[LLM 9/10] Benchmarking: ตัวเลข accuracy ที่ไม่มี confidence interval คือข่าวลือ
ตั้งแต่บทที่ 1 ซีรีส์นี้พูดประโยคเดิมซ้ำทุกครั้งที่รายงานตัวเลข: "accuracy ที่ไม่มี confidence interval ไม่ใช่ผลการทดลอง มันคือข่าวลือ" และสัญญาไว้ว่าจะอธิบายเต็ม ๆ ในบทที่ 9 — บทนี้แหละครับ เราจะไม่เทรนอะไรเลยแม้แต่ step เดียว แต่จะสร้างระบบวัดผลสามโหมดขึ้นจากศูนย์ เอาทุก checkpoint ที่เทรนมาตลอดซีรีส์ขึ้นมาวัดบนข้อสอบไทยจริง แล้วพิสูจน์ว่า การตั้งค่าที่ไม่มีใครเขียนไว้ใน paper เปลี่ยนคะแนนของโมเดลตัวเดิมได้มากกว่าช่องว่างบน leaderboard ที่คนเถียงกัน
Open in Colab09_benchmarking.ipynb
1. ปัญหา (Problem statement)
ลองอ่านประโยคแบบนี้ที่เจอได้ทุกสัปดาห์: "โมเดล X ได้ 71.2% บน ThaiExam แซงโมเดล Y ที่ได้ 69.8%"
คำถามเดียวที่ควรถามคือ วัดจากกี่ข้อ ถ้าชุดทดสอบมี 100 ข้อ ช่วงความเชื่อมั่น 95% ของแต่ละตัวเลขกว้างราว ±8–10 จุด แปลว่า 71.2% กับ 69.8% คือตัวเลขเดียวกันที่บังเอิญสุ่มออกมาไม่เท่ากัน การประกาศผู้ชนะจากช่องว่าง 1.4 จุดบนชุดทดสอบ 100 ข้อ ไม่ต่างจากโยนเหรียญสิบครั้งแล้วสรุปว่าเหรียญเอียง
ปัญหาไม่ได้หยุดที่ขนาดชุดทดสอบ เพราะ "คะแนน benchmark" หนึ่งตัวเลข เกิดจากการตัดสินใจหลายชั้นที่แทบไม่มีใครรายงาน:
| การตัดสินใจที่ซ่อนอยู่ | ผลต่อคะแนน |
|---|---|
| ให้คะแนนแบบ log-likelihood หรือ generative | เปลี่ยนได้หลายจุด |
| normalize ความยาวตัวเลือกหรือไม่ () | สลับอันดับบน leaderboard ได้ |
| 0-shot หรือ 5-shot, template เขียนยังไง | เปลี่ยนได้หลายจุด |
| ใส่ chat template ให้โมเดลไหนบ้าง | ลำเอียงเข้าข้างโมเดลใดโมเดลหนึ่ง |
| ข้อสอบรั่วอยู่ในข้อมูลเทรนหรือไม่ (contamination) | คะแนนสูงปลอมทั้งแท่ง |
ตัวเลขหนึ่งตัวที่ปกปิดการตัดสินใจห้าชั้น บวกกับ error bar ที่ไม่มีใครวาด — นั่นคือสิ่งที่เราเรียกกันว่า leaderboard
2. เราจะทำอะไร (Solution)
บทนี้ไม่มีการเทรนเลย และนั่นคือจุดเด่น ไม่ใช่จุดอ่อน — การวัดผลเป็นงานคนละชนิดกับการเทรน และมันสมควรได้บทของตัวเอง
เราจะทำสี่อย่าง:
- เขียนระบบให้คะแนนสามโหมดจากศูนย์ — log-likelihood multiple-choice, generative exact-match (พร้อม normalization ภาษาไทย), และ LLM-as-judge พร้อม rubric ที่เขียนเป็นลายลักษณ์อักษร แล้วแสดงให้เห็นว่าทั้งสามโหมดให้คะแนนโมเดลตัวเดียวกันไม่เท่ากัน
- เอาทุก checkpoint จากบทที่ 1–8 มาวัดบนแกนเดียวกัน ด้วยข้อสอบไทยจริง
(
scb10x/thai_exam), โจทย์เลขไทย (VISAI-AI/gsm8k-thai) และ KobEval-TH ชุดประจำซีรีส์ - ติด Wilson 95% CI ให้ทุกตัวเลข แล้วดูว่าข้อสรุปไหนของซีรีส์รอดจาก error bar บ้าง
- ลอง reproduce ตัวเลขบน leaderboard สาธารณะ ของ Qwen3-0.6B บน ThaiExam — และถ้าไม่ตรง เราจะไล่หาสาเหตุแทนที่จะเงียบ
คะแนน benchmark ไม่ใช่คุณสมบัติของโมเดล มันคือคุณสมบัติของ (โมเดล × วิธีวัด × ชุดข้อสอบ × จำนวนข้อ) การรายงานตัวเลขโดยไม่รายงานอีกสามอย่างที่เหลือ คือการรายงานแค่เศษหนึ่งส่วนสี่ของความจริง และ confidence interval คือราคาขั้นต่ำของคำว่า "ผลการทดลอง"
3. สมการ (Equation)
3.1 Wilson score interval — CI ประจำซีรีส์
ถ้าตอบถูก จาก ข้อ ได้ ช่วงความเชื่อมั่นแบบ Wilson ที่ระดับ (95% → ) คือ
ทำไมไม่ใช้สูตร normal approximation () ที่จำง่ายกว่า เพราะมันพังตรงที่เราต้องใช้มันบ่อยที่สุด: ขอบ 0 กับ 1 และ เล็ก
ลองกรณีจริงจากบทที่ 8: guardrail ปล่อยคำขออันตรายหลุด 0 ครั้งจากชุดทดสอบ 30 ข้อ
from kobeval import wilson_ci # ฟังก์ชันเดียวกับที่ใช้มาตั้งแต่บทที่ 1
wilson_ci(0, 30) # → (0.000, 0.114)
- Normal approximation: — ช่วงกว้างศูนย์ ราวกับเรามั่นใจ 100% ว่าอัตราหลุดเป็น 0% จากการดูแค่ 30 ตัวอย่าง
- Wilson: — "เท่าที่ดูมา 30 ครั้งยังไม่เคยหลุด แต่ค่าจริงอาจสูงถึง 11%"
ช่วงที่สองคือประโยคที่ซื่อสัตย์ ช่วงแรกคือคำโกหกที่สูตรผลิตให้โดยอัตโนมัติ
สังเกตในสูตรว่า Wilson ดึงจุดกึ่งกลางเข้าหา ด้วยพจน์ (เหมือนเติมข้อมูลเสมือน ข้อ ถูกครึ่งผิดครึ่ง)
และมีพจน์ กันความกว้างไม่ให้ยุบเป็นศูนย์ — นี่คือเหตุผลที่ kobeval ใช้ Wilson มาตลอดซีรีส์
3.2 Length-normalised multiple-choice scoring — ตัวเลขที่ตัดสิน leaderboard เงียบ ๆ
โหมด log-likelihood ให้โมเดลอ่านโจทย์ แล้วเทียบความน่าจะเป็นของตัวเลือก ทั้งประโยค:
- → ใช้ log-prob รวมดิบ ๆ ซึ่งลำเอียงเข้าข้างตัวเลือกสั้น (token น้อย = โดนคูณความน่าจะเป็นน้อยครั้ง)
- → หารด้วยจำนวน token คือใช้ log-prob เฉลี่ยต่อ token
สองบรรทัดนี้คือ acc กับ acc_norm ใน lm-evaluation-harness และบน benchmark จริง
มันให้คะแนนไม่เท่ากันและบางครั้งสลับอันดับโมเดล —
เวลาเห็นตาราง paper สองฉบับรายงาน ThaiExam ไม่เท่ากัน สาเหตุอันดับต้น ๆ คือ คนละค่า
โดยที่ทั้งสองฉบับไม่ได้เขียนไว้เลยว่าใช้ค่าไหน
3.3 pass@k แบบไม่ลำเอียง — สำหรับโจทย์ที่ตรวจอัตโนมัติได้
โจทย์เลขและโจทย์โค้ดยอมให้เราสุ่มหลายคำตอบแล้วถามว่า "มีสักอันไหมที่ถูก" สุ่ม ครั้ง ถูก ครั้ง ตัวประมาณที่ถูกต้องของ pass@ คือ
ตัวประมาณแบบสัญชาตญาณ นั้นลำเอียง: ฟังก์ชัน เป็นฟังก์ชันเว้า (concave) ใน ดังนั้นตาม Jensen's inequality — เสียบค่าประมาณเข้าไปในฟังก์ชันไม่เชิงเส้นแล้วค่าคาดหวังจะไม่ตรงกับของจริง ส่วนสูตรทวินามข้างบนคือ "สัดส่วนของการหยิบ ตัวจาก ตัวที่ผิดยกชุด" ซึ่งพิสูจน์ได้ว่า unbiased พอดีเป๊ะ
3.4 McNemar's test — เทียบสองโมเดลบนข้อสอบชุดเดียวกัน
โมเดล A กับ B ทำข้อสอบชุดเดียวกัน ให้ = จำนวนข้อที่ A ถูกแต่ B ผิด, = จำนวนข้อที่ B ถูกแต่ A ผิด:
เทียบกับ (แบบมี continuity correction) จุดสำคัญคือคำว่า paired: ข้อที่ทั้งคู่ถูกและข้อที่ทั้งคู่ผิดไม่อยู่ในสูตรเลย เพราะมันไม่ได้บอกอะไรว่าใครเก่งกว่า ถ้าคุณใช้ t-test เทียบ accuracy สองตัวเหมือนมาจากคนละชุดข้อสอบ คุณกำลังโยนโครงสร้าง "ข้อเดียวกัน" ทิ้ง แล้วต้องใช้ข้อสอบมากกว่าหลายเท่าเพื่อ power เท่าเดิม
3.5 Contamination check — ข้อสอบรั่วอยู่ในข้อมูลเทรนไหม
สำหรับข้อสอบ และคลังข้อมูลเทรน นิยามอัตราการทับซ้อนของ -gram:
โดย คือเซตของ -gram ทั้งหมด สำหรับภาษาไทยเราใช้ k-gram ระดับตัวอักษร (เช่น 20 ตัวอักษร) เพราะการตัดคำไทยมีความกำกวม ถ้า สูง (เช่นเกิน 0.7) ให้สงสัยว่าโมเดลเคย "เห็นเฉลย" มาแล้ว — คะแนนบนข้อนั้นวัดความจำ ไม่ได้วัดความสามารถ
บทความนี้คือประมาณ 30% แรกของบทเรียน — ส่วนที่เหลือ (การเตรียมสภาพแวดล้อม, การเตรียมข้อมูล, โค้ดหลัก, ผลลัพธ์จริง และบทสรุป) อยู่ในคอร์ส LLM Finetuning ซึ่งเรียนฟรี เพียงเข้าสู่ระบบด้วย Google
อ่านเนื้อหาเต็มในคอร์ส →