ปรับปรุงโมเดล 350M ให้สร้างผลลัพธ์แบบมีโครงสร้างได้ดีขึ้น ด้วย GRPO เพียง 100 ขั้นตอน

การสร้างผลลัพธ์ที่มีโครงสร้าง (Structured Output) เป็นหนึ่งในงานที่ใช้กันทั่วไปสำหรับโมเดลภาษาขนาดใหญ่ (LLMs) ในโลกจริง แต่ส่วนใหญ่แล้ว การทดสอบมาตรฐาน (Benchmarks) มักจะรวมเอาการสร้างผลลัพธ์นี้เข้ากับการวัดผลด้านการให้เหตุผล (Reasoning) หรือการดึงข้อมูล (Extraction) มากกว่าที่จะวัดผลโดยตรง

หัวใจสำคัญคือการที่โมเดลสามารถสร้างผลลัพธ์ที่ถูกต้องและสามารถนำไปประมวลผลต่อได้ตามรูปแบบที่กำหนด (Schema Compliance) ซึ่งมักจะเป็นปัจจัยตัดสินว่าโมเดลนั้นจะสามารถนำไปเชื่อมต่อกับระบบอื่น ๆ ได้หรือไม่

บทความนี้จะแสดงให้เห็นว่า การปรับแต่งโมเดลขนาดเล็กให้เหมาะกับงานเฉพาะทาง (Task-specific Fine-tuning) สามารถเพิ่มประสิทธิภาพ และเทียบเท่ากับโมเดลที่มีขนาดใหญ่กว่ามากได้อย่างไร

การเตรียมความพร้อม: การติดตั้งและตั้งค่า

ก่อนเริ่มต้น เราจำเป็นต้องเตรียมเครื่องมือต่าง ๆ เพื่อให้การทำงานราบรื่น:

  • GPU: ส่วนของการ Fine-tuning จะต้องใช้ GPU
  • Colab/Kaggle: โน้ตบุ๊กที่ใช้ในการปรับแต่งโมเดลนี้ ถูกออกแบบมาให้สามารถทำงานบน GPU ฟรีของ Colab หรือ Kaggle ได้
  • MacBook (สำหรับ Evaluation): ส่วนของการประเมินผล (Evaluation) สามารถรันบน MacBook ได้ โดยใช้ llama.cpp ซึ่งจะเปิดใช้งานเซิร์ฟเวอร์ที่รองรับ OpenAI API เพื่อให้เครื่องมือประเมินผล IFStruct สามารถสื่อสารได้

เครื่องมือที่เราต้องใช้คือ uv สำหรับจัดการเครื่องมือ Python และ llama.cpp สำหรับการให้บริการโมเดล

การติดตั้ง llama.cpp

ทำตามเอกสารของ Liquid AI เกี่ยวกับการติดตั้ง llama.cpp โดยใช้ Homebrew และตรวจสอบว่า llama-server พร้อมใช้งาน

การประเมิน IFStruct บน LFM2.5-350M (โมเดลพื้นฐาน)

ก่อนที่เราจะเริ่มปรับแต่งโมเดล ลองมาประเมิน LFM2.5-350M บน IFStruct Benchmark กันก่อน เพื่อดูว่าเราสามารถทำคะแนนได้ใกล้เคียงกับ 21.1% ที่รายงานไว้หรือไม่

IFStruct คือ Benchmark ที่ใช้ทดสอบความถูกต้องของผลลัพธ์ LLM และการปฏิบัติตาม Schema โดย Benchmark นี้เป็น Open-source อยู่ที่ Liquid4All/ifstruct และชุดข้อมูลสาธารณะสามารถเข้าถึงได้ที่ Hugging Face ในชื่อ LiquidAI/ifstruct-v1.0

สำหรับการเปรียบเทียบผลการประเมิน เราจะให้บริการโมเดลผ่าน llama.cpp บน MacBook โดยใช้โมเดล BF16 GGUF (LiquidAI/LFM2.5-350M-GGUF)

การเริ่มเซิร์ฟเวอร์โมเดลพื้นฐาน

เมื่อติดตั้ง llama.cpp เรียบร้อยแล้ว ให้เริ่มเซิร์ฟเวอร์โมเดลพื้นฐานด้วยคำสั่งต่อไปนี้:

./server -m  --alias IFStruct --ngl 99 -np 4 -c 32768
  • --alias: ชื่อโมเดลที่ IFStruct จะส่งไปยัง Endpoint ที่รองรับ OpenAI API
  • -ngl 99: สั่งให้ llama.cpp โหลดทุก Layer ไปยัง GPU (หากมี)
  • -np 4: ให้บริการคำขอ 4 รายการพร้อมกัน
  • -c 32768: ขนาดของ Context Prompt

การรัน Benchmark

เมื่อเซิร์ฟเวอร์พร้อมทำงานแล้ว เราสามารถรัน Benchmark แบบเต็มรูปแบบด้วยตัวอย่าง 2000 รายการ:

python3 -m ifstruct.eval --model-name IFStruct --max-samples 2000

ผลลัพธ์จาก IFStruct Release Blog รายงานคะแนน 21.1% สำหรับ LFM2.5-350M การตั้งค่า llama.cpp/BF16 ของเราวัดผลได้ 22.6% ซึ่งใกล้เคียงกับ 21.1% ที่รายงานใน IFStruct Blog เราจะใช้ผลลัพธ์จากการทดสอบภายในนี้เป็น Baseline สำหรับการเปรียบเทียบภายใต้ Stack การให้บริการเดียวกัน

GRPO Fine-tuning ด้วย TRL บน Structured Outputs

กระบวนการปรับแต่งโมเดลแบบเต็มรูปแบบสามารถดูได้ในโน้ตบุ๊กที่แนบมา ส่วนนี้จะกล่าวถึงเฉพาะส่วนที่สำคัญ

เราใช้ nvidia/Nemotron-RL-instructionfollowing-structuredoutputs ซึ่งจับคู่ Prompt แต่ละอันกับ Target JSON Schema และจำนวน Field ที่คาดหวัง เราใช้ตัวอย่างประมาณ 500 รายการสำหรับการฝึก

เนื่องจากลักษณะการกระจายข้อมูลของ Nemotron แตกต่างจาก IFStruct Evaluation เราจึงทำการเพิ่ม Prompt เพื่อปิดช่องว่างระหว่างทั้งสองส่วน:

  • 40% ของ Prompt จะมีการเพิ่มคำสั่ง "return the output inside a fenced code block" เพื่อให้โมเดลเรียนรู้ที่จะทำตามคำสั่งรูปแบบ แทนที่จะปล่อย JSON ดิบเสมอ
  • อีก 20% ที่แยกออกมา จะถูกแปลงเป็น Task แบบ Top-level Array (Schema จะถูกห่อหุ้มใน Array ที่มีจำนวน Item ที่ต้องการ) ซึ่งเป็นการฝึกให้โมเดลสามารถสร้าง Output แบบ List และปฏิบัติตามจำนวน Item ที่กำหนด

การสร้าง LoRA Adapter

เราโหลด LiquidAI/LFM2.5-350M และแนบ LoRA Adapter เข้าไป เนื่องจาก LFM2.5 ใช้สถาปัตยกรรมแบบ Hybrid Attention/Convolution เราจึงกำหนดเป้าหมายไปที่ Module Name เฉพาะของ LFM:

# ตัวอย่างโค้ด (ย่อ)
from trl import create_reference_model, AutoModelForCausalLMWithValueHead
from peft import LoraConfig

model = AutoModelForCausalLMWithValueHead.from_pretrained(
"LiquidAI/LFM2.5-350M",
load_in_8bit=True,
device_map="auto",
)
lora_config = LoraConfig(
r=16,
lora_alpha=32,
lora_dropout=0.05,
bias="none",
task_type="CAUSAL_LM",
target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "wi", "wo", "fc1", "fc2"],
# ตัวอย่าง target modules
)
model.add_adapter(lora_config)

การฝึกนี้จะปรับปรุงพารามิเตอร์ประมาณ 6 ล้านตัว ซึ่งคิดเป็นประมาณ 1.66% ของโมเดลทั้งหมด

การกำหนด Reward Functions

จากนั้น เรากำหนด Reward Functions 3 ตัว โดยแต่ละตัวจะให้คะแนนบนสเกล [0, 1] เพื่อประเมินว่าโครงสร้างที่ดึงออกมานั้นถูกต้องหรือไม่:

  • jsonformatreward: ผลลัพธ์สามารถ Parse ได้หรือไม่ และอยู่ในรูปแบบที่ต้องการหรือไม่? ได้คะแนนเต็ม (1.0) สำหรับรูปแบบที่ต้องการ (Fenced Code Block vs Raw JSON), 0.2 สำหรับรูปแบบที่ parse ได้แต่ไม่ถูกต้อง, และ 0.0 สำหรับผลลัพธ์ที่ Parse ไม่ได้
  • fieldcountreward: Object มีจำนวน Top-level Fields ตรงตามที่คาดหวังหรือไม่? การตรงกันพอดีจะได้ 1.0 และคะแนนจะลดลงตามความคลาดเคลื่อน
  • schemavalidationreward: ผลลัพธ์สามารถ Validate กับ JSON Schema ของ Row ได้หรือไม่? นับจำนวนข้อจำกัดที่ละเมิด และให้คะแนนบางส่วนโดยพิจารณาจาก Key ที่จำเป็น

เรานำทั้งสามมารวมกันเป็น Weighted Sum ด้วย reward_weights=[1.0, 0.5, 2.0]

การฝึกโมเดล

เราทำการฝึกเป็นเวลา 100 ขั้นตอน โดยมีการสร้างผลลัพธ์ 8 ครั้งต่อกลุ่ม Prompt ซึ่งเหมาะสำหรับ GPU ขนาด 16 GB ฟรี:

# ตัวอย่างโค้ด (ย่อ)
from trl import PPOConfig, PPOTrainer
from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("LiquidAI/LFM2.5-350M")
# ... กำหนด Reward Functions และ Dataset ...

config = PPOConfig(
steps=100,
mini_batch_size=1,
# ปรับตามขนาด GPU
batch_size=8,
# จำนวน generations per prompt group
gradient_accumulation_steps=1,

# ... อื่นๆ ...
)
trainer = PPOTrainer(config, model, ref_model=None, tokenizer=tokenizer, dataset=dataset)

# ... ลูปการฝึก ...

ดังที่เห็นในโน้ตบุ๊ก ระหว่างการฝึก ส่วนประกอบของ Reward ทั้งสามส่วนจะเพิ่มขึ้น KL จากโมเดลอ้างอิงจะยกตัวขึ้นจากศูนย์หลังช่วง Warm-up และสัดส่วนของ Truncated Completion จะคงที่ใกล้ศูนย์

การรวมและบันทึกโมเดล

สุดท้าย เราทำการรวม LoRA Adapter เข้ากับ Base Weights และบันทึกเป็น Checkpoint ที่สมบูรณ์พร้อมสำหรับการแปลงเป็น GGUF เพื่อให้บริการ

IFStruct Evaluation บน GRPO Tuned LFM2.5-350M

หลังจากการ Fine-tuning ด้วย GRPO เราทำการประเมิน IFStruct อีกครั้ง สำหรับขั้นตอนนี้ เราจำเป็นต้องแปลง Checkpoint ของโมเดลที่รวมแล้วให้เป็น BF16 GGUF ตัวแปลง Script นี้มาพร้อมกับ Source Code ของ llama.cpp ดังนั้นเราจะ Clone Repository และติดตั้ง Package gguf ของตัวแปลง

การเริ่มเซิร์ฟเวอร์โมเดลที่ Fine-tuned

จากนั้น เราให้บริการโมเดลที่รวมแล้วด้วยคำสั่งต่อไปนี้:

./server -m  --alias IFStruct-GRPO --ngl 99 -np 4 -c 32768

การรัน Benchmark อีกครั้ง

จากนั้น เราจะรัน IFStruct Evaluation แบบเต็มอีกครั้งด้วยโมเดลที่ Fine-tuned แล้ว:

python3 -m ifstruct.eval --model-name IFStruct-GRPO --max-samples 2000

การเปรียบเทียบผลลัพธ์

เมื่อเปรียบเทียบผลการรันทั้งสองครั้งบน Stack การให้บริการที่เหมือนกัน:

| Metric | Base Model | GRPO Tuned Model | Gain |
| :------------------ | :--------- | :--------------- | :------- |
| IFStruct JSON Pass Rate | 22.6% | 29.7% | +7.1 pts |
| IFStruct YAML Pass Rate | 19.5% | 21.8% | +2.3 pts |

จะเห็นว่า การปรับปรุงนั้นตรงตามเป้าหมายของการฝึก: อัตราการผ่าน JSON เพิ่มขึ้นเกือบ 7 จุด (22.6% → 29.7%) ในขณะที่ YAML ยังคงใกล้เคียงเดิม แม้ว่าคะแนนนี้จะยังต่ำกว่าคะแนนของ Qwen3.5-2B ที่ 33.15% แต่ก็แสดงให้เห็นว่า การ Fine-tuning ที่เน้นงานเฉพาะทาง แม้จะเล็กน้อย ก็สามารถทำให้โมเดลขนาดเล็กเข้าใกล้โมเดลขนาดใหญ่ได้

การรัน GRPO สั้นๆ ด้วยตัวอย่างประมาณ 500 รายการ และ 100 ขั้นตอน สามารถยกระดับโมเดลขนาดเล็ก 350M พารามิเตอร์ จาก 22.6% เป็น 29.7% บน IFStruct ได้ ข้อคิดที่ได้คือ สัญญาณ Reward ที่ราคาไม่แพงและเฉพาะเจาะจงกับงาน สามารถทำให้โมเดลขนาดเล็กมีความน่าเชื่อถือเกี่ยวกับรูปแบบผลลัพธ์ได้อย่างมาก และช่วยลดช่องว่างกับโมเดลที่มีขนาดใหญ่กว่าหลายเท่าตัว

หากต้องการทำซ้ำหรือต่อยอดงานนี้ โปรดดูที่ IFStruct v1.0 Blog Post, Liquid4All/ifstruct benchmark repo, และ LiquidAI/ifstruct-v1.0 dataset

#AI #LLM #FineTuning #GRPO #StructuredOutput

ขอบคุณ แหล่งข้อมูล
https://huggingface.co/blog/grpo-with-trl-ifstruct

ปรับปรุงโมเดล 350M ให้สร้างผลลัพธ์แบบมีโครงสร้างได้ดีขึ้น ด้วย GRPO เพียง 100 ขั้นตอนการสร้างผลลัพธ์ที่มีโครงสร้าง (Structured Output) เป็นหนึ่งในงานที่ใช้กันทั่วไปสำหรับโมเดลภาษาขนาดใหญ่ (LLMs) ในโลกจริง แต่ส่วนใหญ่แล้ว การทดสอบมาตรฐาน (Benchmarks) มักจะรวมเอาการสร้างผลลัพธ์นี้เข้ากับการวัดผลด้านการให้เหตุผล (Reasoning) หรือการดึงข้อมูล (Extraction) มากกว่าที่จะวัดผลโดยตรงหัวใจสำคัญคือการที่โมเดลสามารถสร้างผลลัพธ์ที่ถูกต้องและสามารถนำไปประมวลผลต่อได้ตามรูปแบบที่กำหนด (Schema Compliance) ซึ่งมักจะเป็นปัจจัยตัดสินว่าโมเดลนั้นจะสามารถนำไปเชื่อมต่อกับระบบอื่น ๆ ได้หรือไม่บทความนี้จะแสดงให้เห็นว่า การปรับแต่งโมเดลขนาดเล็กให้เหมาะกับงานเฉพาะทาง (Task-specific Fine-tuning) สามารถเพิ่มประสิทธิภาพ และเทียบเท่ากับโมเดลที่มีขนาดใหญ่กว่ามากได้อย่างไรการเตรียมความพร้อม: การติดตั้งและตั้งค่าก่อนเริ่มต้น เราจำเป็นต้องเตรียมเครื่องมือต่าง ๆ เพื่อให้การทำงานราบรื่น:GPU: ส่วนของการ Fine-tuning จะต้องใช้ GPUColab/Kaggle: โน้ตบุ๊กที่ใช้ในการปรับแต่งโมเดลนี้ ถูกออกแบบมาให้สามารถทำงานบน GPU ฟรีของ Colab หรือ Kaggle ได้MacBook (สำหรับ Evaluation): ส่วนของการประเมินผล (Evaluation) สามารถรันบน MacBook ได้ โดยใช้ llama.cpp ซึ่งจะเปิดใช้งานเซิร์ฟเวอร์ที่รองรับ OpenAI API เพื่อให้เครื่องมือประเมินผล IFStruct สามารถสื่อสารได้เครื่องมือที่เราต้องใช้คือ uv สำหรับจัดการเครื่องมือ Python และ llama.cpp สำหรับการให้บริการโมเดลการติดตั้ง llama.cppทำตามเอกสารของ Liquid AI เกี่ยวกับการติดตั้ง llama.cpp โดยใช้ Homebrew และตรวจสอบว่า llama-server พร้อมใช้งานการประเมิน IFStruct บน LFM2.5-350M (โมเดลพื้นฐาน)ก่อนที่เราจะเริ่มปรับแต่งโมเดล ลองมาประเมิน LFM2.5-350M บน IFStruct Benchmark กันก่อน เพื่อดูว่าเราสามารถทำคะแนนได้ใกล้เคียงกับ 21.1% ที่รายงานไว้หรือไม่IFStruct คือ Benchmark ที่ใช้ทดสอบความถูกต้องของผลลัพธ์ LLM และการปฏิบัติตาม Schema โดย Benchmark นี้เป็น Open-source อยู่ที่ Liquid4All/ifstruct และชุดข้อมูลสาธารณะสามารถเข้าถึงได้ที่ Hugging Face ในชื่อ LiquidAI/ifstruct-v1.0สำหรับการเปรียบเทียบผลการประเมิน เราจะให้บริการโมเดลผ่าน llama.cpp บน MacBook โดยใช้โมเดล BF16 GGUF (LiquidAI/LFM2.5-350M-GGUF)การเริ่มเซิร์ฟเวอร์โมเดลพื้นฐานเมื่อติดตั้ง llama.cpp เรียบร้อยแล้ว ให้เริ่มเซิร์ฟเวอร์โมเดลพื้นฐานด้วยคำสั่งต่อไปนี้:./server -m --alias IFStruct --ngl 99 -np 4 -c 32768--alias: ชื่อโมเดลที่ IFStruct จะส่งไปยัง Endpoint ที่รองรับ OpenAI API-ngl 99: สั่งให้ llama.cpp โหลดทุก Layer ไปยัง GPU (หากมี)-np 4: ให้บริการคำขอ 4 รายการพร้อมกัน-c 32768: ขนาดของ Context Promptการรัน Benchmarkเมื่อเซิร์ฟเวอร์พร้อมทำงานแล้ว เราสามารถรัน Benchmark แบบเต็มรูปแบบด้วยตัวอย่าง 2000 รายการ:python3 -m ifstruct.eval --model-name IFStruct --max-samples 2000ผลลัพธ์จาก IFStruct Release Blog รายงานคะแนน 21.1% สำหรับ LFM2.5-350M การตั้งค่า llama.cpp/BF16 ของเราวัดผลได้ 22.6% ซึ่งใกล้เคียงกับ 21.1% ที่รายงานใน IFStruct Blog เราจะใช้ผลลัพธ์จากการทดสอบภายในนี้เป็น Baseline สำหรับการเปรียบเทียบภายใต้ Stack การให้บริการเดียวกันGRPO Fine-tuning ด้วย TRL บน Structured Outputsกระบวนการปรับแต่งโมเดลแบบเต็มรูปแบบสามารถดูได้ในโน้ตบุ๊กที่แนบมา ส่วนนี้จะกล่าวถึงเฉพาะส่วนที่สำคัญเราใช้ nvidia/Nemotron-RL-instructionfollowing-structuredoutputs ซึ่งจับคู่ Prompt แต่ละอันกับ Target JSON Schema และจำนวน Field ที่คาดหวัง เราใช้ตัวอย่างประมาณ 500 รายการสำหรับการฝึกเนื่องจากลักษณะการกระจายข้อมูลของ Nemotron แตกต่างจาก IFStruct Evaluation เราจึงทำการเพิ่ม Prompt เพื่อปิดช่องว่างระหว่างทั้งสองส่วน:40% ของ Prompt จะมีการเพิ่มคำสั่ง "return the output inside a fenced code block" เพื่อให้โมเดลเรียนรู้ที่จะทำตามคำสั่งรูปแบบ แทนที่จะปล่อย JSON ดิบเสมออีก 20% ที่แยกออกมา จะถูกแปลงเป็น Task แบบ Top-level Array (Schema จะถูกห่อหุ้มใน Array ที่มีจำนวน Item ที่ต้องการ) ซึ่งเป็นการฝึกให้โมเดลสามารถสร้าง Output แบบ List และปฏิบัติตามจำนวน Item ที่กำหนดการสร้าง LoRA Adapterเราโหลด LiquidAI/LFM2.5-350M และแนบ LoRA Adapter เข้าไป เนื่องจาก LFM2.5 ใช้สถาปัตยกรรมแบบ Hybrid Attention/Convolution เราจึงกำหนดเป้าหมายไปที่ Module Name เฉพาะของ LFM:# ตัวอย่างโค้ด (ย่อ) from trl import create_reference_model, AutoModelForCausalLMWithValueHead from peft import LoraConfig model = AutoModelForCausalLMWithValueHead.from_pretrained( "LiquidAI/LFM2.5-350M", load_in_8bit=True, device_map="auto", ) lora_config = LoraConfig( r=16, lora_alpha=32, lora_dropout=0.05, bias="none", task_type="CAUSAL_LM", target_modules=["q_proj", "k_proj", "v_proj", "o_proj", "wi", "wo", "fc1", "fc2"], # ตัวอย่าง target modules ) model.add_adapter(lora_config)การฝึกนี้จะปรับปรุงพารามิเตอร์ประมาณ 6 ล้านตัว ซึ่งคิดเป็นประมาณ 1.66% ของโมเดลทั้งหมดการกำหนด Reward Functionsจากนั้น เรากำหนด Reward Functions 3 ตัว โดยแต่ละตัวจะให้คะแนนบนสเกล [0, 1] เพื่อประเมินว่าโครงสร้างที่ดึงออกมานั้นถูกต้องหรือไม่:jsonformatreward: ผลลัพธ์สามารถ Parse ได้หรือไม่ และอยู่ในรูปแบบที่ต้องการหรือไม่? ได้คะแนนเต็ม (1.0) สำหรับรูปแบบที่ต้องการ (Fenced Code Block vs Raw JSON), 0.2 สำหรับรูปแบบที่ parse ได้แต่ไม่ถูกต้อง, และ 0.0 สำหรับผลลัพธ์ที่ Parse ไม่ได้fieldcountreward: Object มีจำนวน Top-level Fields ตรงตามที่คาดหวังหรือไม่? การตรงกันพอดีจะได้ 1.0 และคะแนนจะลดลงตามความคลาดเคลื่อนschemavalidationreward: ผลลัพธ์สามารถ Validate กับ JSON Schema ของ Row ได้หรือไม่? นับจำนวนข้อจำกัดที่ละเมิด และให้คะแนนบางส่วนโดยพิจารณาจาก Key ที่จำเป็นเรานำทั้งสามมารวมกันเป็น Weighted Sum ด้วย reward_weights=[1.0, 0.5, 2.0]การฝึกโมเดลเราทำการฝึกเป็นเวลา 100 ขั้นตอน โดยมีการสร้างผลลัพธ์ 8 ครั้งต่อกลุ่ม Prompt ซึ่งเหมาะสำหรับ GPU ขนาด 16 GB ฟรี:# ตัวอย่างโค้ด (ย่อ) from trl import PPOConfig, PPOTrainer from transformers import AutoTokenizer tokenizer = AutoTokenizer.from_pretrained("LiquidAI/LFM2.5-350M") # ... กำหนด Reward Functions และ Dataset ... config = PPOConfig( steps=100, mini_batch_size=1, # ปรับตามขนาด GPU batch_size=8, # จำนวน generations per prompt group gradient_accumulation_steps=1, # ... อื่นๆ ... ) trainer = PPOTrainer(config, model, ref_model=None, tokenizer=tokenizer, dataset=dataset) # ... ลูปการฝึก ...ดังที่เห็นในโน้ตบุ๊ก ระหว่างการฝึก ส่วนประกอบของ Reward ทั้งสามส่วนจะเพิ่มขึ้น KL จากโมเดลอ้างอิงจะยกตัวขึ้นจากศูนย์หลังช่วง Warm-up และสัดส่วนของ Truncated Completion จะคงที่ใกล้ศูนย์การรวมและบันทึกโมเดลสุดท้าย เราทำการรวม LoRA Adapter เข้ากับ Base Weights และบันทึกเป็น Checkpoint ที่สมบูรณ์พร้อมสำหรับการแปลงเป็น GGUF เพื่อให้บริการIFStruct Evaluation บน GRPO Tuned LFM2.5-350Mหลังจากการ Fine-tuning ด้วย GRPO เราทำการประเมิน IFStruct อีกครั้ง สำหรับขั้นตอนนี้ เราจำเป็นต้องแปลง Checkpoint ของโมเดลที่รวมแล้วให้เป็น BF16 GGUF ตัวแปลง Script นี้มาพร้อมกับ Source Code ของ llama.cpp ดังนั้นเราจะ Clone Repository และติดตั้ง Package gguf ของตัวแปลงการเริ่มเซิร์ฟเวอร์โมเดลที่ Fine-tunedจากนั้น เราให้บริการโมเดลที่รวมแล้วด้วยคำสั่งต่อไปนี้:./server -m --alias IFStruct-GRPO --ngl 99 -np 4 -c 32768การรัน Benchmark อีกครั้งจากนั้น เราจะรัน IFStruct Evaluation แบบเต็มอีกครั้งด้วยโมเดลที่ Fine-tuned แล้ว:python3 -m ifstruct.eval --model-name IFStruct-GRPO --max-samples 2000การเปรียบเทียบผลลัพธ์เมื่อเปรียบเทียบผลการรันทั้งสองครั้งบน Stack การให้บริการที่เหมือนกัน:| Metric | Base Model | GRPO Tuned Model | Gain || :------------------ | :--------- | :--------------- | :------- || IFStruct JSON Pass Rate | 22.6% | 29.7% | +7.1 pts || IFStruct YAML Pass Rate | 19.5% | 21.8% | +2.3 pts |จะเห็นว่า การปรับปรุงนั้นตรงตามเป้าหมายของการฝึก: อัตราการผ่าน JSON เพิ่มขึ้นเกือบ 7 จุด (22.6% → 29.7%) ในขณะที่ YAML ยังคงใกล้เคียงเดิม แม้ว่าคะแนนนี้จะยังต่ำกว่าคะแนนของ Qwen3.5-2B ที่ 33.15% แต่ก็แสดงให้เห็นว่า การ Fine-tuning ที่เน้นงานเฉพาะทาง แม้จะเล็กน้อย ก็สามารถทำให้โมเดลขนาดเล็กเข้าใกล้โมเดลขนาดใหญ่ได้การรัน GRPO สั้นๆ ด้วยตัวอย่างประมาณ 500 รายการ และ 100 ขั้นตอน สามารถยกระดับโมเดลขนาดเล็ก 350M พารามิเตอร์ จาก 22.6% เป็น 29.7% บน IFStruct ได้ ข้อคิดที่ได้คือ สัญญาณ Reward ที่ราคาไม่แพงและเฉพาะเจาะจงกับงาน สามารถทำให้โมเดลขนาดเล็กมีความน่าเชื่อถือเกี่ยวกับรูปแบบผลลัพธ์ได้อย่างมาก และช่วยลดช่องว่างกับโมเดลที่มีขนาดใหญ่กว่าหลายเท่าตัวหากต้องการทำซ้ำหรือต่อยอดงานนี้ โปรดดูที่ IFStruct v1.0 Blog Post, Liquid4All/ifstruct benchmark repo, และ LiquidAI/ifstruct-v1.0 dataset#AI #LLM #FineTuning #GRPO #StructuredOutputhttps://huggingface.co/blog/grpo-with-trl-ifstruct
Shared content
HUGGINGFACE.CO
Fine-tuning a 350M Model for Better Structured Outputs in 100 GRPO Steps
We’re on a journey to advance and democratize artificial intelligence through open source and open science.
5 التعليقات 0 المشاركات 338 مشاهدة 0 معاينة