เก็บข้อมูล 22 ส.ค. 2569 · AI Engineering ภาคสนาม EP.2
ในตอนที่แล้ว แผนที่ทักษะของ Andrew Ng มีหกข้อย่อย และเขายกข้อเดียวขึ้นมาพูดเป็นบุคคลที่หนึ่ง 12
จากประสบการณ์ของผม คุณสมบัติสำคัญที่สุดที่แยกคนที่เก่งเรื่องการสร้างระบบ AI ออกมา คือความสามารถในการขับ evals และ error analysis อย่างมีวินัย
ตอนนี้คือข้อนั้น แต่ไม่ได้เล่าว่าควรทำอย่างไร เล่าว่าเกิดอะไรขึ้นจริงตอนผมลงมือทำ รวมถึงรอบที่ผมเขียนตัววัดขึ้นมาแล้วมันตอบผิด 3
ตัววัดที่ดีคือตัวที่เปลี่ยนความเห็นเป็นตัวเลขที่เถียงไม่ได้
งานที่ทำคือปกโพสต์ Facebook ที่ต้องเป็นภาพเดียวกว้าง แล้วตัดครึ่งอัปโหลดเป็นสองรูป เพื่อให้ Facebook วางเรียงกันแล้วอ่านเป็นภาพเดียว
คำถามคือ สองรูปนี้ต่อกันเป็นภาพเดียวจริงหรือเปล่า ซึ่งเป็นคำถามที่ตอบด้วยการมองแล้วรู้สึกว่าใช่ ได้ง่ายมาก และผิดได้ง่ายพอกัน
สองการวัดที่ใช้แทนการมอง
| การวัด | คำถามที่มันตอบ | ผลที่ได้ |
|---|---|---|
| เทียบคอลัมน์ที่รอยตัด | มีเนื้อหาคาบรอยตัดจริงไหม | 252 จาก 1,080 แถว = 23.3% |
| เทียบกับภาพที่ไม่ถูกตัด | ยังเป็นภาพเดียวอยู่ไหม | ต่างกัน 0 จาก 2,332,800 พิกเซล |
การวัดที่หนึ่งอ่านพิกเซลคอลัมน์สุดท้ายของรูปซ้ายกับคอลัมน์แรกของรูปขวา แถวไหนที่ทั้งสองฝั่งไม่ใช่สีพื้น คือแถวที่มีเนื้อหาข้ามรอยตัด
การวัดที่สองถอด CSS สองบรรทัดที่ทำหน้าที่ crop ออก แล้ว render ภาพเดิมเต็มความกว้าง จากนั้นเทียบทีละพิกเซลกับสองรูปที่วางต่อกัน
อ่านแบบผู้บริหารองค์กร ความต่างที่สำคัญไม่ได้อยู่ที่ความแม่นยำ แต่อยู่ที่ว่ามันเปลี่ยนบทสนทนา คำว่าดูดีแล้วเป็นความเห็นที่เถียงกันได้ไม่จบ ส่วนคำว่าต่างกันศูนย์พิกเซลจากสองล้านสามแสนพิกเซลไม่ใช่ความเห็น ในทีมที่เถียงกันเรื่องคุณภาพบ่อย ๆ ต้นตอมักไม่ใช่คนไม่เห็นตรงกัน แต่เป็นการที่ยังไม่มีใครแปลงคำถามนั้นเป็นตัวเลข
เครื่องมือที่ต้องเขียนเอง เพราะไม่มีให้ใช้
เครื่องนี้ไม่มี PIL ไม่มี matplotlib การอ่านพิกเซลจึงต้องเขียน PNG decoder เองด้วย zlib กับ struct รวมถึงต้องคลาย filter ห้าแบบของ PNG เอง
อ่านแบบผู้บริหารองค์กร จุดที่ผมคิดว่าน่าสนใจกว่าตัวโค้ดคือการตัดสินใจว่าจะเขียนมันขึ้นมา ต้นทุนคือเวลาไม่กี่สิบนาที ส่วนสิ่งที่ได้กลับมาคือคำตอบที่ไม่ต้องเชื่อใจใคร ในงานที่ผลลัพธ์ทำนายล่วงหน้าไม่ได้ เครื่องมือวัดมักเป็นสิ่งที่คุ้มที่สุดที่จะสร้างเอง และเป็นสิ่งแรกที่คนข้ามเพราะมันไม่ใช่ฟีเจอร์
ตัวตรวจที่ปฏิเสธจะตรวจสิ่งที่มันนิยามไม่ได้
อีกตัวหนึ่งคือ validate-spec.py ยาว 160 บรรทัด รับไฟล์ spec แล้วคืน exit 0 ถ้าส่งต่อได้ และ exit 1 พร้อมรายการปัญหาถ้าไม่ได้ มันแยกสิ่งที่เป็นข้อผิดพลาดออกจากสิ่งที่เป็นเพียงคำเตือน 4
| สิ่งที่มันตรวจ | สิ่งที่มันจงใจไม่ตรวจ |
|---|---|
| ทุกแถวของตารางมีจำนวนช่องเท่าหัวตาราง | หน้าตาของเพจ |
| ชนิดของบล็อกอยู่ในห้าแบบที่รองรับ | ถ้อยคำ |
| สารบัญด้านข้างตรงกับหัวข้อจริง | คุณภาพของเนื้อหา |
เหตุผลที่ไม่ตรวจดีไซน์ เขียนไว้ในหัวไฟล์ของมันเอง คือดีไซน์อยู่ที่เดียวและไม่ถูกคัดลอกมาไว้ที่นี่ ไฟล์นี้จึงไม่มีทางลอยห่างจากหน้าตาจริงของเพจ
อ่านแบบผู้บริหารองค์กร ตัววัดที่พยายามตรวจทุกอย่างจะกลายเป็นสำเนาที่สองของระบบ แล้วต้องแก้สองที่ทุกครั้ง กฎที่ผมได้จากตรงนี้คือ ตรวจเฉพาะสิ่งที่นิยามได้โดยไม่ต้องรู้ว่าปลายทางหน้าตาอย่างไร ส่วนที่เหลือให้คนดู และเขียนไว้ตรง ๆ ว่าไม่ได้ตรวจ
ตัววัดที่ผิด อันตรายกว่าไม่มีตัววัดเลย
นี่คือส่วนที่ผมคิดว่ามีค่าที่สุดในตอนนี้ เพราะมันเกือบพาไปแก้ของที่ไม่ได้พัง
ตัวเลขที่ถูก แต่ตอบคนละคำถาม
รอบแรกของการวัดที่สอง ผมเอาสองรูปที่ตัดแล้วไปเทียบกับปกที่ render แบบไม่ตัด ผลคือ
differing pixels: 575,340 / 2,332,800 (24.66%)
max channel delta: 235
diff bbox: [84, 0, 2117, 1079]
ต่างกันเกือบหนึ่งในสี่ ทั่วทั้งภาพ ถ้าเชื่อตัวเลขนี้ ข้อสรุปคือโค้ดตัดรูปพังหนัก
ที่จริงแล้วไม่มีอะไรพังเลย ปกแบบปกติแบ่งคอลัมน์ 57 ต่อ 43 ส่วนปกแบบตัดครึ่งแบ่ง 50 ต่อ 50 เพื่อให้รอยตัดตกที่ขอบพอดี มันคนละ layout กันตั้งแต่ต้น ตัวเลข 24.66% เป็นตัวเลขจริง แต่มันวัดความต่างระหว่างการจัดวางสองแบบ ไม่ได้วัดว่าการตัดรูปสูญเสียอะไรไปหรือเปล่า
เมื่อเปลี่ยน baseline เป็น HTML ตัวเดียวกันที่ถอดการ crop ออก ผลกลายเป็น 0
อ่านแบบผู้บริหารองค์กร นี่คือ error analysis ในความหมายที่ Ng พูดถึง และมันไม่ได้แปลว่าไปดูว่าโมเดลตอบผิดตรงไหน แต่แปลว่าไปดูว่าตัววัดกำลังวัดอะไรกันแน่ ตัววัดที่ผิดอันตรายกว่าไม่มีตัววัด เพราะมันมาพร้อมความมั่นใจ ไม่มีตัววัดแล้วคนยังระวัง แต่มีตัวเลขผิดแล้วคนจะเลิกระวังและเริ่มแก้ผิดจุด
สิ่งที่ทำให้จับได้
จับได้เพราะตัวเลขมันมากเกินกว่าจะสมเหตุสมผล ถ้าโค้ดตัดรูปพังจริง ความต่างควรกระจุกอยู่ที่รอยต่อ ไม่ใช่กระจายทั่วทั้งภาพตั้งแต่ x=84 ถึง x=2117
อ่านแบบผู้บริหารองค์กร สิ่งที่ช่วยไว้คือการที่ตัววัดคืนค่ามามากกว่าตัวเลขเดียว มันคืนกรอบพื้นที่ที่ต่างกันมาด้วย ถ้ามันคืนมาแค่ 24.66% ผมคงเชื่อ ตอนออกแบบตัววัด การให้มันบอกว่าต่างตรงไหน มีค่าพอ ๆ กับการบอกว่าต่างเท่าไหร่ และมันคือสิ่งเดียวที่ทำให้แยกออกว่าตัววัดเองผิดหรือของจริงพัง
มีบั๊กที่ไม่มีตัวเลขไหนจับได้ ต้องเปิดดูด้วยตาเท่านั้น
ในรอบเดียวกันมีบั๊กสามตัวที่ตัววัดทั้งหมดข้างต้นให้ผ่านหมด
สามตัวนั้น
| อาการที่เห็น | สาเหตุจริง | ทำไมตัวเลขไม่จับ |
|---|---|---|
| พาดหัวยาว 5 บรรทัด ดันตัวเลขสถิติไปทับเลขหน้า | ไม่มีการนับความสูงหลัง render | ไฟล์ออกมาครบ ขนาดถูกต้อง 1080×1080 |
"3 ใน 4" ขึ้นเป็นตัวอักษรสองแบบในสตริงเดียว |
ฟอนต์ Anton ไม่มีตัวอักษรไทย เบราว์เซอร์เลย fallback เฉพาะตัวที่วาดไม่ได้ | ข้อความถูกต้องทุกตัวอักษร |
| การ์ดขึ้นดำสนิททั้งใบ | path ภาพเป็น relative แต่การ์ด render ผ่าน file:// มันเลยไปหาผิดที่ |
ไฟล์ PNG ถูกสร้างจริง ไม่มี error |
ข้อที่แก้ที่ราก ไม่ใช่แก้ที่อาการ
ข้อสามแก้ด้วยการทำให้มันพังเสียงดัง แทนที่จะปล่อยให้ได้การ์ดสีดำที่ดูเหมือนตั้งใจ ตอนนี้มันหยุดทำงานทันทีพร้อมบอกว่าไปหาไฟล์ที่ path ไหนมา
art file not found: art/aieng-cover.png
looked in: /private/tmp/.../scratchpad/art/aieng-cover.png
อ่านแบบผู้บริหารองค์กร ข้อแตกต่างระหว่างระบบที่ดูแลได้กับดูแลไม่ได้ อยู่ตรงนี้มากกว่าอยู่ที่จำนวนเทสต์ ความล้มเหลวที่ส่งเสียงจะถูกแก้ในนาทีนั้น ความล้มเหลวที่เงียบจะถูกส่งต่อไปให้ลูกค้าเจอ และตอนที่มันย้อนกลับมา ไม่มีใครจำได้แล้วว่าเปลี่ยนอะไรไป การลงทุนที่คุ้มที่สุดในระบบ AI มักไม่ใช่การเพิ่มตัววัด แต่เป็นการเปลี่ยนความล้มเหลวเงียบให้ดังขึ้น
ตัววัดที่ถูกที่สุดคือ checklist ที่ยอมรับว่าต้องใช้คน
จากบทเรียนข้างบน สิ่งที่ทำคือเขียนมันลงใน checklist ท้ายคู่มือการทำงานของตัวเอง
fb-carousel-post เวอร์ชัน 1.8.0 มี checklist ปิดงาน 22 ข้อ และข้อที่แพงที่สุดคือข้อที่ยอมรับตรง ๆ ว่าเครื่องช่วยไม่ได้
เปิดดู PNG ทุกไฟล์ — overflow กับ font fallback ไม่ส่งเสียง
ข้อที่เพิ่มเข้ามาหลังเจอบั๊กฟอนต์ ก็เขียนเป็นกฎที่ตรวจได้ทันที
ห้ามมีตัวอักษรไทยในช่องที่ใช้ฟอนต์ Anton —
"3 ใน 4"พัง ส่วน"3 / 4"ไม่พัง
อ่านแบบผู้บริหารองค์กร เวอร์ชันของคู่มือพวกนี้ไม่ได้ขึ้นตามรอบเวลา มันขึ้นตอนมีของพังจริง ซึ่งทำให้เลข version กลายเป็นบันทึกว่าเคยเจ็บกี่ครั้ง ผลที่ตามมาที่ผมชอบคือ ความรู้ไม่ได้อยู่ในหัวคนอีกต่อไป มันอยู่ในไฟล์ที่รอบหน้าจะถูกอ่านอีก ในองค์กรที่คนหมุนเวียนบ่อย นี่คือความต่างระหว่างทีมที่เก่งขึ้นเรื่อย ๆ กับทีมที่เจ็บซ้ำที่เดิม
ภาคผนวก
ศัพท์เฉพาะ
| คำ | ความหมาย |
|---|---|
| Evals | การประเมินคุณภาพผลลัพธ์ของระบบอย่างเป็นระบบ |
| Error analysis | การไล่ดูว่าระบบผิดตรงไหนและเพราะอะไร เพื่อกำหนดว่าจะแก้อะไรต่อ |
| Baseline | ค่าอ้างอิงที่ใช้เทียบว่าผลลัพธ์ดีขึ้นหรือแย่ลง |
| Exit code | ตัวเลขที่โปรแกรมคืนเมื่อจบ 0 คือสำเร็จ ไม่ใช่ 0 คือมีปัญหา |
| Fallback (ฟอนต์) | การที่ระบบเปลี่ยนไปใช้ฟอนต์อื่นเมื่อฟอนต์ที่เลือกไม่มีตัวอักษรนั้น |
| Silent failure | ความล้มเหลวที่ไม่แจ้งเตือน ระบบเดินต่อเหมือนปกติแต่ผลลัพธ์ผิด |
| Definition of done | เกณฑ์ที่ตกลงไว้ล่วงหน้าว่างานแบบไหนถึงเรียกว่าเสร็จ |
สูตรและวิธีคำนวณ
สัดส่วนแถวที่มีเนื้อหาคาบรอยตัด
นับแถว y ที่ทั้ง (คอลัมน์ 1079 ของรูปซ้าย) และ (คอลัมน์ 0 ของรูปขวา)
ต่างจากสีพื้นเกินเกณฑ์ 10 ในทุกช่องสี
252 ÷ 1,080 = 0.2333 → 23.3%
ความต่างระดับพิกเซล
เทียบ RGB ทีละพิกเซลของภาพเต็ม 2160×1080 กับสองรูปที่วางต่อกัน
2,160 × 1,080 = 2,332,800 พิกเซล
ผลที่ยอมรับได้มีค่าเดียวคือ 0
วิธีเก็บข้อมูลและข้อจำกัด
ตัวเลขทั้งหมดมาจากระบบที่ผมสร้างเอง เก็บ ณ 22 ส.ค. 2569 บันทึกภาคสนามฉบับเต็มอยู่ในที่เก็บงานส่วนตัว 3
- นี่คือระบบเดียว ของคนเดียว ไม่ใช่การสำรวจ และไม่ใช่ตัวแทนของอุตสาหกรรม
- ไม่มีกลุ่มควบคุม ผมไม่รู้ว่าถ้าทำอีกแบบผลจะดีกว่าหรือแย่กว่า
- ขนาดของระบบเล็กมากเมื่อเทียบกับงาน production จริง สิ่งที่ได้ผลที่ขนาดนี้อาจไม่ได้ผลที่ขนาดใหญ่กว่า
- ตัววัดที่เล่ามาทั้งหมดเป็นตัววัดเชิงโครงสร้าง ไม่ใช่การประเมินคุณภาพผลลัพธ์ของโมเดล ซึ่งเป็นคนละเรื่องและยากกว่ามาก
- ตัวเลขทุกตัวจะเก่าทันทีที่โค้ดถูกแก้ครั้งถัดไป
