ข้ามไปยังเนื้อหาหลัก

[LLM 5/10] GRPO: ลบ value network ทิ้ง แล้วให้กลุ่มคำตอบเป็น baseline ของกันเอง

· อ่าน 9 นาที
Kobkrit Viriyayudhakorn
CEO, iApp Technology

บทที่แล้วเราปิดท้ายด้วยช่องว่างของ DPO: มันจัดอันดับได้เฉพาะคำตอบที่มีคนเตรียมไว้ในไฟล์ ส่วนบทที่ 3 เราจ่ายราคาเต็มของ PPO: โมเดล 4 ตัวใน VRAM และ value network ทั้งตัวที่ต้องเทรนเพิ่ม บทนี้เราจะเอาข้อดีของทั้งสองมารวมกัน — ให้โมเดลสุ่มคำตอบของตัวเองมาเรียนแบบ RL จริง ๆ แต่ลบ value network ทิ้งทั้งก้อน ด้วยข้อสังเกตทางสถิติที่เรียบง่ายจนน่าหงุดหงิดว่าทำไมไม่มีใครคิดก่อน: ถ้าสุ่มคำตอบหลายอันต่อโจทย์เดียวกัน ค่าเฉลี่ย reward ของกลุ่มก็คือ baseline ที่ value network พยายามประมาณอยู่แล้ว และถ้าโจทย์ตรวจคำตอบได้ด้วยโค้ด เราไม่ต้องใช้ข้อมูล preference จากมนุษย์เลย — ศูนย์คู่ ศูนย์บาท

Open in Colab05_grpo.ipynb

1. ปัญหา (Problem statement)

ลองตั้งโจทย์แบบนี้: สอน Qwen3-0.6B ให้แก้โจทย์คณิตศาสตร์ภาษาไทย คำตอบสุดท้ายเป็นตัวเลขหนึ่งตัว ตรวจถูกผิดได้ด้วยเครื่องหมาย == บรรทัดเดียว

เอาเครื่องมือจากสามบทที่ผ่านมามาไล่ดูทีละตัว จะพบว่าไม่มีตัวไหนพอดีกับงานนี้เลย:

วิธีโมเดลสุ่มคำตอบเองแล้วเรียนจากมันได้ไหมต้องมี label จากมนุษย์โมเดลใน VRAM
SFT (บทที่ 2)ไม่ได้ — เลียนแบบเฉลยอย่างเดียวเฉลยที่คนเขียน1
PPO (บทที่ 3)ได้คู่ preference สำหรับเทรน reward model4
DPO (บทที่ 4)ไม่ได้ — offline ล้วนคู่ preference2 (LoRA เหลือ 1)
  • SFT สอนให้เลียนแบบวิธีทำของเฉลย แต่ไม่เคยให้โมเดลลองผิดลองถูกเอง โมเดลไม่เคยเห็นว่า "วิธีคิดของตัวเอง" แบบไหนพาไปคำตอบถูก
  • PPO ให้โมเดลลองเองได้ แต่แลกด้วยการเทรน reward model จากคู่ preference บวก value network อีกทั้งตัว — ทั้งที่งานนี้ reward เขียนเป็นฟังก์ชัน Python ได้ตรง ๆ
  • DPO ตัด RL ทิ้งได้สวยงาม แต่มันจัดอันดับได้แค่คำตอบที่มีอยู่แล้วในชุดข้อมูล โจทย์เลขต้องการให้โมเดลลองหลาย ๆ ทางแล้วเสริมทางที่ไปถึงคำตอบถูก

คำถามของบทนี้จึงแคบและคม: ใน PPO มีชิ้นส่วนไหนที่จำเป็นจริง และชิ้นไหนลบทิ้งได้ เมื่อ reward ของเราตรวจได้ด้วยโค้ด

2. เราจะทำอะไร (Solution)

ย้อนกลับไปที่หน้าที่ของ value network ในบทที่ 3: มันมีไว้ตอบคำถามเดียวคือ "โดยเฉลี่ยแล้ว prompt นี้ควรได้ reward ประมาณเท่าไหร่" เพื่อใช้เป็น baseline เอาไปหักออกจาก reward จริง — คำตอบที่ "ดีกว่าค่าเฉลี่ย" ได้ gradient บวก ที่ "แย่กว่าค่าเฉลี่ย" ได้ลบ ถ้าไม่มี baseline ตัวนี้ policy gradient จะ noise สูงจนเทรนแทบไม่ได้

PPO ตอบคำถามนั้นด้วยการเทรนโมเดลอีกตัวทั้งตัวขึ้นมาทำนายค่าเฉลี่ยนี้ GRPO ตอบด้วยการสุ่มให้เห็นกับตา:

แนวคิดหลักของบทนี้

สุ่มคำตอบ GG อันจาก prompt เดียวกัน แล้วเฉลี่ย reward ของกลุ่ม — ค่าเฉลี่ยนั้นคือ unbiased estimate ของ "reward ที่คาดหวังจาก prompt นี้" อยู่แล้วโดยนิยาม มันคือสิ่งเดียวกับที่ value network พยายามประมาณ แต่ไม่ต้องเทรน ไม่ต้องโหลด ไม่มีวันประมาณเพี้ยน value network ทั้งตัวจึงลบทิ้งได้ และเมื่อ reward ตรวจด้วยโค้ด (คำตอบเลขถูกหรือผิด) reward model กับข้อมูล preference จากมนุษย์ก็หายตามไปด้วย — เหลือศูนย์ label

นี่คือ GRPO (Group Relative Policy Optimization) เสนอโดย Shao และคณะ (2024) ใน DeepSeekMath และเป็นเครื่องยนต์ตัวเดียวกับที่เทรน DeepSeek-R1 แนวทางนี้มีชื่อเรียกรวม ๆ ว่า RLVR (RL with Verifiable Rewards) — RL ที่ reward มาจากตัวตรวจ ไม่ใช่จากรสนิยมมนุษย์

และขอวางความคาดหวังให้ตรงตั้งแต่ต้นบท: หลักฐานปัจจุบันชี้ว่า RL แบบนี้ส่วนใหญ่ทำหน้าที่ "เหลา" ความสามารถที่โมเดลฐานมีอยู่แล้วที่ pass@8 ให้ย้ายมาโผล่ที่ pass@1 มากกว่าจะสร้างความสามารถใหม่จากศูนย์ เราจะกลับมาเรื่องนี้พร้อมเครื่องมือวัดในหัวข้อ 9

3. สมการ (Equation)

3.1 Group-relative advantage — หัวใจทั้งหมดอยู่บรรทัดเดียว

A^i=rimean(r1,,rG)std(r1,,rG)\hat A_i = \frac{r_i - \operatorname{mean}(r_1,\dots,r_G)}{\operatorname{std}(r_1,\dots,r_G)}
  • GG = จำนวนคำตอบที่สุ่มจาก prompt เดียวกัน (ในบทนี้คือ 8)
  • rir_i = reward ของคำตอบที่ ii
  • ทุก token ของคำตอบที่ ii ใช้ A^i\hat A_i ตัวเดียวกันทั้งประโยค — ต่างจาก PPO ที่พยายามให้ advantage ละเอียดราย token ผ่าน value network และ GAE

อ่านเป็นภาษาคน: "คำตอบนี้ดีกว่าหรือแย่กว่าความพยายามครั้งอื่น ๆ ของฉันเอง ต่อโจทย์ข้อเดียวกัน" ไม่มีการเปรียบเทียบข้ามโจทย์ ไม่มีการทำนายอนาคต มีแค่การแข่งกันเองในกลุ่ม

สมการสั้น ๆ นี้มีผลตามมาที่สำคัญมาก: ถ้าทั้งกลุ่มได้ reward เท่ากันหมด (ถูกหมดหรือผิดหมด) ทุก A^i\hat A_i เป็นศูนย์ และ batch นั้นไม่สอนอะไรเลย จำประโยคนี้ไว้ มันจะกลายเป็นทั้งกับดักอันดับหนึ่งและตัวชี้วัดที่สำคัญที่สุดของบท

3.2 GRPO objective ฉบับเต็ม

JGRPO(θ)=E[1Gi=1G1oit=1oi{min ⁣(ρi,tA^i, clip(ρi,t,1ϵ,1+ϵ)A^i)βDKL[πθπref]}]\mathcal{J}_{\text{GRPO}}(\theta) = \mathbb{E}\left[\frac{1}{G}\sum_{i=1}^{G}\frac{1}{|o_i|}\sum_{t=1}^{|o_i|}\Big\{\min\!\big(\rho_{i,t}\,\hat A_i,\ \operatorname{clip}(\rho_{i,t},\,1-\epsilon,\,1+\epsilon)\,\hat A_i\big) - \beta\,\mathbb{D}_{\text{KL}}\big[\pi_\theta \,\|\, \pi_{\text{ref}}\big]\Big\}\right]

โดย ρi,t=πθ(oi,tq,oi,<t)πθold(oi,tq,oi,<t)\rho_{i,t} = \dfrac{\pi_\theta(o_{i,t} \mid q, o_{i,<t})}{\pi_{\theta_{\text{old}}}(o_{i,t} \mid q, o_{i,<t})} คืออัตราส่วนความน่าจะเป็นของ token เทียบกับ policy ตอนสุ่ม

อ่านทีละชิ้น เพราะทุกชิ้นเคยผ่านตามาแล้วในซีรีส์นี้:

  • min(, clip())\min(\cdot,\ \operatorname{clip}(\cdot)) = PPO clip เดิมจากบทที่ 3 ไม่มีอะไรใหม่ — กันไม่ให้ก้าวไกลเกินไปจากจุดที่สุ่ม rollout มา
  • 1oi\frac{1}{|o_i|} = เฉลี่ยต่อ token กันคำตอบยาวได้อิทธิพลเกินตัว (นึกถึง length bias จากบทที่ 4)
  • βDKL\beta\,\mathbb{D}_{\text{KL}} = สายจูงเส้นเดิมที่ผูกกับ πref\pi_{\text{ref}} ตัวเดียวกับบทที่ 3 และ 4

สิ่งที่ควรอ่านคือสิ่งที่ไม่อยู่ในสมการ: ไม่มี V(s)V(s) ไม่มี GAE ไม่มี critic loss ทั้งบรรทัดใช้แค่โมเดลสองตัว (πθ\pi_\theta กับ πref\pi_{\text{ref}}) และเลข reward จากตัวตรวจ

3.3 พจน์ KL ไม่ได้คำนวณตรง ๆ — รู้จัก k3 estimator

KL divergence จริง ๆ ต้อง sum ทั้ง vocabulary ของทุกตำแหน่ง ซึ่งแพงและไม่จำเป็น GRPO ประมาณมันจาก token ที่สุ่มออกมาแล้ว ด้วย estimator ชื่อเล่นว่า k3:

D^k3=πref(oi,t)πθ(oi,t)logπref(oi,t)πθ(oi,t)1\hat{\mathbb{D}}_{k3} = \frac{\pi_{\text{ref}}(o_{i,t})}{\pi_\theta(o_{i,t})} - \log\frac{\pi_{\text{ref}}(o_{i,t})}{\pi_\theta(o_{i,t})} - 1

คำถามที่นักเรียนถามเสมอ (และควรถาม): ทำไมไม่ใช้ log(πθ/πref)\log(\pi_\theta/\pi_{\text{ref}}) ตรง ๆ ในเมื่อค่าคาดหวังของมันก็คือ KL อยู่แล้ว?

คำตอบ: ตัว naive (เรียกว่า k1) unbiased ก็จริง แต่ราย sample มันติดลบได้ — ประมาณ 40% ของ sample ให้ค่าติดลบ ทั้งที่ KL เป็นลบไม่ได้โดยนิยาม — และ variance สูงมาก ที่ batch ขนาดจริง ค่าประมาณจะแกว่งจน penalty เดี๋ยวผลักเดี๋ยวดึง

k3 แก้ทั้งสองข้อพร้อมกัน ให้ x=πref/πθx = \pi_{\text{ref}}/\pi_\theta แล้วสังเกตสองข้อเท็จจริง:

  1. อสมการ x1logxx - 1 \geq \log x เป็นจริงเสมอ ดังนั้น k3 =(x1)logx0= (x-1) - \log x \geq 0 ทุก sample
  2. Eπθ[x]=πθπrefπθ=1\mathbb{E}_{\pi_\theta}[x] = \sum \pi_\theta \cdot \frac{\pi_{\text{ref}}}{\pi_\theta} = 1 ดังนั้นพจน์ (x1)(x-1) มีค่าคาดหวังเป็นศูนย์ — มันคือ control variate ที่หักล้าง noise ของ logx-\log x โดยไม่แตะค่าคาดหวัง

ผลคือ estimator ที่ unbiased เท่าเดิม แต่ variance ต่ำกว่ากันเป็นระดับ และไม่มีวันติดลบ รูปที่ 5.3 จะให้เห็นความต่างนี้กับตา

3.4 หมายเหตุขั้นสูง: การหารด้วย std ไม่ได้บริสุทธิ์อย่างที่เห็น (Dr.GRPO)

การหารด้วย std(r1..rG)\operatorname{std}(r_1..r_G) ในสมการ 3.1 แอบใส่ bias เข้ามาหนึ่งอย่าง: กลุ่มที่ reward เกือบเท่ากันหมด (std เล็ก เช่น ถูก 7 ใน 8) จะถูกขยาย advantage ด้วยตัวคูณมหาศาล ขณะที่กลุ่มที่เสียงแตกจริง ๆ (std ใหญ่ — ซึ่งมี information มากที่สุด) กลับถูกกดให้เบาลงโดยเปรียบเทียบ ผลรวมคือ gradient เอนเอียงไปหาโจทย์ที่โมเดลเกือบจะเห็นพ้องกับตัวเองอยู่แล้ว งาน Dr.GRPO (Liu และคณะ, 2025) เสนอให้ตัดการหาร std ทิ้ง เหลือแค่การลบ mean ซึ่งยังเป็น baseline ที่ถูกต้องทุกประการ วิดเจ็ตในหัวข้อ 4 มีปุ่มสลับให้ลองทั้งสองแบบ

3.5 pass@k แบบ unbiased — เครื่องมือที่หัวข้อ 9 ต้องใช้

สุ่มคำตอบ nn ครั้งต่อโจทย์ ถูก cc ครั้ง แล้วอยากรู้ว่า "ถ้าให้โควตา kk ครั้ง จะมีสักครั้งที่ถูกไหม":

pass@k^=1(nck)(nk)\widehat{\text{pass@}k} = 1 - \frac{\binom{n-c}{k}}{\binom{n}{k}}

เศษส่วนข้างหลังคือความน่าจะเป็นที่หยิบ kk อันจาก nn แล้วเจอแต่คำตอบผิดล้วน ๆ สูตรที่คนมักใช้ผิดคือ 1(1c/n)k1-(1-c/n)^k ซึ่ง bias เข้าข้างตัวเองอย่างเป็นระบบเมื่อ nn เล็ก (นี่คือเหตุผลที่กระดาษ HumanEval ของ Chen และคณะ 2021 ต้องมี appendix แยกเรื่องนี้) จำสูตรนี้ไว้ — มันคือมาตรวัดที่ใช้ตัดสินว่า GRPO "สร้าง" ความสามารถใหม่ หรือแค่ "เหลา" ของเดิม

เนื้อหาเต็มอยู่ในคอร์ส

บทความนี้คือประมาณ 30% แรกของบทเรียน — ส่วนที่เหลือ (การเตรียมสภาพแวดล้อม, การเตรียมข้อมูล, โค้ดหลัก, ผลลัพธ์จริง และบทสรุป) อยู่ในคอร์ส LLM Finetuning ซึ่งเรียนฟรี เพียงเข้าสู่ระบบด้วย Google

อ่านเนื้อหาเต็มในคอร์ส →