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

[LLM 4/10] DPO: เมื่อโมเดลภาษากลายเป็น reward model ของตัวเอง

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

บทที่แล้วเราทำ RLHF ด้วย PPO และคุณคงเห็นแล้วว่ามันมีชิ้นส่วนเยอะแค่ไหน — ต้องเทรน reward model แยกหนึ่งตัว ต้องโหลดโมเดลพร้อมกัน 4 ตัวใน VRAM ต้องจูน PPO อีกสิบกว่าพารามิเตอร์ และถ้า reward model เพี้ยน โมเดลจะไปเจอทางลัดที่โกงคะแนนได้ บทนี้เราจะทำสิ่งเดียวกันด้วยลูป training ธรรมดาแบบ supervised — ไม่มี reward model ไม่มี RL และที่สำคัญคือ มันไม่ใช่การประมาณ เราจะพิสูจน์ด้วยพีชคณิตว่าทั้งสองชิ้นนั้นตัดกันหายไปจริง ๆ

Open in Colab04_dpo.ipynb

1. ปัญหา (Problem statement)

สมมติคุณอยากให้ผู้ช่วย AI ของคุณ "ตอบเป็นภาษาไทยเสมอ" — ฟังดูง่าย แต่ลองเขียนเป็น loss function ดูสิครับ คุณจะเขียนไม่ออก

นี่คือปัญหาแกนกลางของ alignment: คุณภาพของคำตอบ เขียนเป็นสมการไม่ได้ "สุภาพกว่า" "เป็นธรรมชาติกว่า" "ไม่หลุดไปเป็นภาษาอังกฤษ" — ไม่มีเฉลยเดียวที่ถูกต้อง มีแต่การเปรียบเทียบ ให้คนดูคำตอบสองอันแล้วบอกว่าชอบอันไหนมากกว่า ข้อมูลที่ได้จึงมีหน้าตาเป็นสามสิ่ง: prompt xx, คำตอบที่ชอบ ywy_w (chosen), คำตอบที่ไม่ชอบ yly_l (rejected)

RLHF แบบ PPO แก้ปัญหานี้ด้วยการเดินอ้อมสองขั้น:

  1. เทรน reward model rϕ(x,y)r_\phi(x,y) ให้เลียนแบบความชอบของมนุษย์
  2. ใช้ RL ดัน policy ไปหาคะแนนสูง ๆ ของ reward model นั้น

การเดินอ้อมนี้มีราคา:

ปัญหาของ RLHF/PPOผลที่เกิดขึ้นจริง
ต้องเทรนโมเดลเพิ่ม 1 ตัวเพิ่มขั้นตอน เพิ่มโอกาสพัง เพิ่มเวลา
ต้องโหลด 4 โมเดลพร้อมกันpolicy + ref + reward + value — VRAM บาน
reward hackingโมเดลหาช่องโกงคะแนน โดยที่มนุษย์ไม่ได้ชอบขึ้นเลย
PPO ไวต่อ hyperparameterรันสองรอบด้วย seed ต่างกัน อาจได้ผลคนละเรื่อง

คำถามของบทนี้จึงเป็นคำถามเดียวสั้น ๆ: เราข้ามขั้นที่ 1 กับ 2 ไปเลยได้ไหม

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

คำตอบคือได้ และเหตุผลสวยมาก

จุดเริ่มคือข้อสังเกตว่า objective ของ RLHF ที่มี KL constraint นั้น มีคำตอบในรูปปิด (closed form) เรารู้อยู่แล้วว่า policy ที่ดีที่สุดหน้าตาเป็นอย่างไร โดยไม่ต้องรัน RL เลยแม้แต่ step เดียว เมื่อรู้แบบนั้น เราก็พลิกสมการกลับด้าน — แทนที่จะถามว่า "reward นี้ให้ policy อะไร" เราถามว่า "policy นี้แปลว่า reward เท่าไหร่"

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

เมื่อพลิกสมการ ตัวโมเดลภาษาเองก็คือ reward model อยู่แล้วโดยปริยาย reward model กับ RL loop ไม่ได้ถูก "ประมาณทิ้ง" แต่มันตัดกันหายไปทางพีชคณิต สิ่งที่เหลือคือ loss function แบบ supervised ธรรมดาที่เทรนด้วย Trainer ตัวเดียวจบ

นี่คือ DPO (Direct Preference Optimization) ซึ่งเสนอโดย Rafailov และคณะ (2023) ชื่อ "Direct" มาจากการที่เรา optimize บนข้อมูล preference โดยตรง ไม่ผ่านตัวกลาง

3. สมการ (Equation)

3.1 ตั้งโจทย์: RLHF objective

maxπ ExD,yπ(x)[r(x,y)]βDKL[π(yx)πref(yx)]\max_{\pi}\ \mathbb{E}_{x\sim\mathcal{D},\,y\sim\pi(\cdot|x)}\big[r(x,y)\big] - \beta\,\mathbb{D}_{\text{KL}}\big[\pi(y|x)\,\|\,\pi_{\text{ref}}(y|x)\big]

อ่านเป็นภาษาคน: "ทำคะแนน reward ให้สูงที่สุด แต่ห้ามเดินห่างจากโมเดลตั้งต้นมากเกินไป"

  • π\pi = policy คือโมเดลที่เรากำลังเทรน
  • πref\pi_{\text{ref}} = reference policy คือโมเดลตั้งต้น (ในบทนี้คือโมเดลหลัง SFT จากบทที่ 2)
  • r(x,y)r(x,y) = reward ของคำตอบ yy ต่อ prompt xx
  • β\beta = ความเข้มของสายจูง ยิ่งมากยิ่งดึงกลับหา πref\pi_{\text{ref}} แรง

พจน์ KL ไม่ใช่ของประดับ ถ้าไม่มีมันโมเดลจะวิ่งหนีไปหาจุดที่ reward สูงแต่ภาษาพัง

3.2 ขั้นที่ 1 — คำตอบในรูปปิด

โจทย์ข้างบนนี้แก้ได้ด้วยมือ (เป็นการหา distribution ที่ minimize KL ต่อ distribution เป้าหมาย) ได้ผลว่า

π(yx)=1Z(x)πref(yx)exp(1βr(x,y))\pi^*(y|x) = \frac{1}{Z(x)}\pi_{\text{ref}}(y|x)\exp\left(\frac{1}{\beta}r(x,y)\right)
  • Z(x)=yπref(yx)exp ⁣(r(x,y)/β)Z(x) = \sum_{y}\pi_{\text{ref}}(y|x)\exp\!\big(r(x,y)/\beta\big) คือ partition function ตัวหารที่ทำให้ผลรวมเป็น 1
  • สังเกตว่า Z(x)Z(x) ขึ้นกับ xx เท่านั้น ไม่ขึ้นกับ yy — จำประโยคนี้ไว้ให้ดี เดี๋ยวมันจะกลายเป็นพระเอก

ความหมายเชิงสัญชาตญาณ: policy ที่ดีที่สุดคือ โมเดลเดิม ถ่วงน้ำหนักใหม่ด้วย exp(r/β)\exp(r/\beta) คำตอบที่ reward สูงถูกขยายความน่าจะเป็น คำตอบที่ reward ต่ำถูกกด แต่ตั้งต้นจากรูปร่างเดิมของ πref\pi_{\text{ref}} เสมอ

ในทางปฏิบัติเราคำนวณ Z(x)Z(x) ไม่ได้ เพราะต้องรวมทุกคำตอบที่เป็นไปได้ทั้งจักรวาล นี่คือเหตุผลที่คนใช้ RL — และเป็นเหตุผลที่ DPO ไม่ต้องใช้

3.3 ขั้นที่ 2 — พลิกสมการหา reward

ใส่ log ทั้งสองข้างแล้วย้ายข้าง จะได้

r(x,y)=βlogπ(yx)πref(yx)+βlogZ(x)r(x,y) = \beta\log\frac{\pi^*(y|x)}{\pi_{\text{ref}}(y|x)} + \beta\log Z(x)

บรรทัดนี้คือหัวใจ reward ทุกฟังก์ชันเขียนใหม่ได้ในรูปของ policy ที่ optimal กับ policy ตั้งต้น แปลว่าถ้าเรามีโมเดลสองตัว เราคำนวณ reward โดยปริยายของมันได้ทันที โดยไม่ต้องเทรน reward model ใด ๆ

3.4 ขั้นที่ 3 — แทนใน Bradley-Terry แล้ว Z(x)Z(x) ตัดหาย

โมเดลมาตรฐานของความชอบคือ Bradley-Terry: โอกาสที่คนจะเลือก ywy_w เหนือ yly_l คือ

p(ywylx)=σ(r(x,yw)r(x,yl))p(y_w \succ y_l \mid x) = \sigma\big(r(x,y_w) - r(x,y_l)\big)

โดย σ\sigma คือ sigmoid สังเกตว่าในสมการนี้ reward ปรากฏในรูป ผลต่าง เท่านั้น แทนสมการ 3.3 ลงไป — βlogZ(x)\beta\log Z(x) อยู่ทั้งสองฝั่งเท่ากันเป๊ะเพราะ xx ตัวเดียวกัน — มันจึงตัดกันหายไป

LDPO(θ)=E(x,yw,yl)[logσ(βlogπθ(ywx)πref(ywx)βlogπθ(ylx)πref(ylx))]\mathcal{L}_{\text{DPO}}(\theta) = -\mathbb{E}_{(x,y_w,y_l)}\left[\log\sigma\left(\beta\log\frac{\pi_\theta(y_w|x)}{\pi_{\text{ref}}(y_w|x)} - \beta\log\frac{\pi_\theta(y_l|x)}{\pi_{\text{ref}}(y_l|x)}\right)\right]
นี่คือประโยคที่ทั้งบทความสร้างขึ้นมาเพื่อพูด

สิ่งที่คำนวณไม่ได้ (Z(x)Z(x)) ตัดหายไป เพราะ Bradley-Terry สนใจแค่ผลต่างของ reward ที่เหลือคือ log-probability ของโมเดลสองตัวบนข้อความที่เรามีอยู่แล้ว ซึ่งคำนวณด้วย forward pass ธรรมดา ไม่มีการสุ่มคำตอบ ไม่มี rollout ไม่มี value function — DPO เป็น supervised learning เต็มตัว

3.5 Gradient — ที่ซึ่งสัญชาตญาณอยู่

θLDPO=βE[σ(r^lr^w)(θlogπθ(ywx)θlogπθ(ylx))]\nabla_\theta\mathcal{L}_{\text{DPO}} = -\beta\,\mathbb{E}\left[\sigma(\hat r_l - \hat r_w)\left(\nabla_\theta\log\pi_\theta(y_w|x) - \nabla_\theta\log\pi_\theta(y_l|x)\right)\right]

โดย r^=βlog(πθ/πref)\hat r = \beta\log\big(\pi_\theta/\pi_{\text{ref}}\big) เรียกว่า implicit reward (reward โดยปริยาย)

อ่านทีละชิ้น:

  • วงเล็บขวา = ทิศทาง ดัน log-prob ของ ywy_w ขึ้น และกด log-prob ของ yly_l ลง พร้อมกัน
  • σ(r^lr^w)\sigma(\hat r_l - \hat r_w) = น้ำหนัก คือ "โมเดลจัดอันดับคู่นี้ผิดแค่ไหน"

น้ำหนักตัวนี้คือจุดสอนที่สำคัญที่สุด ถ้าโมเดลจัดอันดับคู่นี้ถูกอยู่แล้ว (r^w\hat r_w มากกว่า r^l\hat r_l ชัดเจน) ค่า σ(r^lr^w)\sigma(\hat r_l - \hat r_w) จะเข้าใกล้ศูนย์ และคู่นั้นแทบไม่ส่ง gradient เลย DPO จึงโฟกัสไปที่ความผิดพลาดของตัวเองโดยอัตโนมัติ ไม่ต้องมีใครมาคัดข้อมูลให้

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

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

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