ลงมือทำ: verdict บนเว็บให้ตรงกับ PC และเรื่องราว Cortex-A
โมดูล 5 — ฝึกโมเดลและนำไปใช้หลายเป้าหมาย · สไลด์: slides.md · ภาพรวมโมดูล · หน้าหลักสูตร
เติมห้าจุดใน s13_web.py ให้ทำสี่ขั้นเดียวกับที่เบราว์เซอร์ทำ คือ normalize, quantize, invoke และ dequantize จนได้ verdict ฝั่ง PC เป็น ground truth แล้ววัด parity กับไฟล์ web ด้วย max-abs-diff ปิดด้วยเรื่องราว Cortex-A ที่รัน eval_pc.py ตัวเดิมได้เลย และการเลือกเป้าหมายอย่างมีเหตุผล
เป้าหมาย
หัวข้อที่มีชื่อว่า “เป้าหมาย”เมื่อจบบทเรียนนี้ คุณจะ:
- เติมห้าจุดใน practice/s13_web.py จนพิมพ์ verdict ฝั่ง PC ที่ conf เท่ากับคะแนนสูงสุดใน scores และ scores รวมกันได้ราว 1
- วัด parity อย่างน้อยหนึ่ง window (ด้วย s13_web_full.py บน PC หรือหน้าเว็บที่โหลด LiteRT.js) จดค่า max-abs-diff กับคลาสที่ชนะ แล้วตัดสินผ่านหรือไม่ผ่านตาม TOL = 0.02
- เลือกเป้าหมาย (MCU, Web, Cortex-A หรือ PC) ให้โจทย์ที่กำหนดพร้อมข้อแลกเปลี่ยนอย่างน้อยสองข้อ และอธิบายว่าทำไม eval_pc.py รันบน Cortex-A ได้โดยไม่แก้
ก่อนเริ่ม
หัวข้อที่มีชื่อว่า “ก่อนเริ่ม”ผ่านบทเรียน 5.6 มาแล้ว เข้าใจ quantize, dequantize และนิยาม parity
คัดลอก practice/s13_web.py ไปวางใน shared/training ที่มี dataset_tools.py, model_int8.tflite และ .norm.npz
- อุปกรณ์: คอมพิวเตอร์ของคุณ ไม่ต้องใช้บอร์ด (หรือใช้ BENTO Emulator ใน BENTO IDE ประกอบ) — ใช้ PC (Python กับ ai-edge-litert หรือ Docker image เดิม) การเทียบในเบราว์เซอร์ต้องทำหน้าเว็บของคุณเองที่โหลด LiteRT.js เพราะ BENTO Emulator โหลดไฟล์ของเราเองไม่ได้
- เรียนมาก่อน: บทเรียน 5.6 — รันโมเดลบนเว็บ: LiteRT.js, int8 I/O และ parity
web_verdict() เดินสี่ขั้นเดียวกับที่หน้าเว็บต้องทำ ห้าจุดที่เติมคือ (1) x = (window - z["mean"]) / z["std"] normalize ด้วยชุดเดียวกับตอนฝึก
(2) q = np.clip(np.round(x / in_scale + in_zero), -128, 127).astype(np.int8) โดยอ่าน scale/zero จาก inp["quantization"]
(3) it.set_tensor(inp["index"], q) แล้ว it.invoke() (4) o = (o - out_zero) * out_scale ให้ softmax กลับเป็นความน่าจะเป็น และ
(5) conf = float(o[top]) ผลคืน dict {label, top, conf, scores} หน้าตาเดียวกับที่ฝั่ง JS (webVerdict) คืน ฝั่ง JS ใช้ไฟล์ web ที่ I/O เป็น float
จึงข้ามขั้น quantize และ dequantize ส่วนขั้น normalize ต้องเป็นสูตรเดียวกันทุกตัวอักษร
ground truth ฝั่ง PC คือ python s13_web.py จากนั้นวัด parity: s13_web_full.py --export-web สร้าง model_web.tflite จาก model.keras
แล้ว python s13_web_full.py รันไฟล์ int8 กับไฟล์ web บนชุดทดสอบ 12 window พิมพ์ max-abs-diff และคลาสที่ชนะ นี่คือด่านแรกบน PC
ขั้นถัดไปคือหน้าเว็บของคุณที่โหลด LiteRT.js ด้วยโค้ดจาก --show-js ถ้าไม่ผ่าน ไล่ตามลำดับ: normalize → quantize → invoke ก่อนโทษ kernel
วิธีดีบักที่เร็วที่สุดคือป้อน input ชุดเดียวกันเป๊ะแล้วเทียบผลทีละขั้น จุดที่เริ่มต่างคือจุดที่ front-end ไม่ตรง
Cortex-A ง่ายที่สุด: pip install ai-edge-litert บน Raspberry Pi หรือ Jetson แล้วรัน eval_pc.py กับไฟล์ .tflite เดิมได้เลย เพราะมี Linux และ Python จริง
ไม่มีข้อจำกัด int8 แบบ NPU และเร่งต่อได้ด้วย delegate (XNNPACK บน CPU, GPU delegate บน Jetson) การเลือกเป้าหมายคือการแลก:
MCU เล็กและประหยัดไฟที่สุดแต่แปลงยากสุด Web แชร์ได้ทันทีแต่ต้องทำ front-end ใน JS Cortex-A แรงและยืดหยุ่น PC คือโต๊ะฝึกและ ground truth
ตัวอย่างสมบูรณ์
หัวข้อที่มีชื่อว่า “ตัวอย่างสมบูรณ์”s13_web_full.py คือแล็บ parity ครบวงบน PC: --export-web สร้างไฟล์ web จาก model.keras (ได้จาก train.py --save-keras), รันเฉย ๆ
เทียบไฟล์ int8 กับไฟล์ web 12 window แล้วสรุปผ่านหรือไม่ผ่าน และ --show-js พิมพ์โค้ด LiteRT.js ไปวางในหน้าเว็บ
ข้อควรรู้: ตัวเลือก --index ของไฟล์ฝึกยังไม่ได้ถูกใช้ สคริปต์หยิบ window ทดสอบตัวแรกเสมอ
| ไฟล์ | ไฟล์นี้สอน |
|---|---|
| examples/s13_web_full.py | แล็บ parity ครบวง: PC vs Web จากโมเดล .tflite ไฟล์เดียว (ฉบับเต็ม) |
สไลด์ของบทเรียนนี้อ้างถึงไฟล์ที่อยู่ในบทเรียนอื่นหรือใน shared/ ด้วย:
- shared/training
- shared/training/convert_web.py — Prepare the trained model for the browser (BENTO Edge AI Emulator / any web page).
- shared/training/dataset_tools.py — Dataset tools for the IMU gesture classifier (Pillar 4 / Training).
- shared/training/eval_pc.py — Run the exported int8 .tflite on the PC and report accuracy + confusion.
- shared/training/model_int8.tflite
- shared/training/train.py — Train a tiny IMU gesture classifier and export it as int8 TFLite.
ฝึกเติม
หัวข้อที่มีชื่อว่า “ฝึกเติม”คอมเมนต์ # เติม อยู่ที่บรรทัด 38 (normalize), 50 (quantize), 55 (invoke), 60 (dequantize) และ 65 (conf)
ถ้า conf เป็น 0.0000 จุดที่ 65 ยังว่าง ถ้า scores เป็นเลขจำนวนเต็มอย่าง −128 หรือ 127 จุดที่ 60 ยังว่าง
| ไฟล์ฝึก | เรื่อง |
|---|---|
| practice/s13_web.py | เอาโมเดลของเราลง Web แล้วทวนผลให้ตรงกับ PC (ฉบับฝึกเติมโค้ด) |
เปิดเฉลยหลังจากลองเองแล้วอย่างน้อยหนึ่งรอบ และอ่าน วิธีใช้เฉลย ก่อน
| เฉลย | คู่กับ |
|---|---|
| solution/s13_web.py | practice/s13_web.py |
เช็กความเข้าใจ
หัวข้อที่มีชื่อว่า “เช็กความเข้าใจ”คำถามชุดเดียวกันอยู่ใน quiz.yaml สำหรับระบบที่ตรวจอัตโนมัติ
-
รันแล้ว scores ดูถูกต้องแต่ conf = 0.0000 ทุกครั้ง จุดใดยังว่าง (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)
- ก) เติม 1 normalize
- ข) เติม 3 invoke
- ค) เติม 4 dequantize
- ง) เติม 5 conf = float(o[top])
เฉลย
ง — placeholder conf = 0.0 ค้างอยู่ ต้องดึงคะแนนของคลาสที่ชนะออกมาด้วย float(o[top])
-
scores ออกมาเป็น [‘-128.0000’, ‘127.0000’, ‘-128.0000’] จุดใดยังว่าง (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)
- ก) เติม 2 quantize
- ข) เติม 4 dequantize ค่ายังเป็น int8 ดิบ ไม่ใช่ความน่าจะเป็น
- ค) เติม 1 normalize
- ง) ไม่มีจุดใดผิด
เฉลย
ข — ต้องแปลงกลับด้วย (o − out_zero) × out_scale ค่าจึงอยู่ในช่วง 0..1 และรวมกันได้ราว 1
-
s13_web_full.py รายงานคลาสที่ชนะตรงกัน 12/12 window และ max-abs-diff สูงสุด 0.0117 ที่ TOL 0.02 สรุปอย่างไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 2)
- ก) ผ่านบน PC แล้ว ขั้นต่อไปคือยืนยันในเบราว์เซอร์จริง
- ข) ไม่ผ่าน เพราะ diff ไม่เป็นศูนย์
- ค) ผ่าน และไม่ต้องทดสอบที่ไหนอีก
- ง) ไม่ผ่าน เพราะต้องได้ 100%
เฉลย
ก — ครบทั้งสองเงื่อนไข แต่ s13_web_full.py รันไฟล์ web ด้วย interpreter บน PC จึงเป็นด่านแรก เบราว์เซอร์จริงอาจใช้ kernel ต่างกันจึงควรยืนยันซ้ำ
-
ต้องส่งเดโมให้ลูกค้าเปิดดูทันทีโดยไม่ติดตั้งอะไรและไม่มีบอร์ด ควรเลือกเป้าหมายใด (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)
- ก) MCU + Ethos-U55
- ข) Web ในเบราว์เซอร์
- ค) Cortex-A
- ง) PC ใน Docker
เฉลย
ข — เว็บแชร์ด้วยลิงก์ได้ทันทีและข้อมูลอยู่ในเครื่องผู้ใช้ แลกกับการต้องทำ front-end ใน JS และวัด parity เอง
-
ทำไม eval_pc.py จึงรันบน Raspberry Pi ได้โดยไม่แก้แม้แต่บรรทัดเดียว (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)
- ก) เพราะ Raspberry Pi มี Ethos-U55
- ข) เพราะ Cortex-A มี Linux กับ Python จริง ติดตั้ง ai-edge-litert ได้ และใช้ไฟล์ .tflite เดิมโดยไม่บังคับ int8
- ค) เพราะ eval_pc.py ถูกคอมไพล์เป็นภาษา C
- ง) เพราะใช้ Vela
เฉลย
ข — Cortex-A คือ PC ตัวเล็กที่มีระบบปฏิบัติการเต็ม สคริปต์และไฟล์โมเดลชุดเดียวกับบน PC จึงย้ายไปได้ทันที
MVP ของชุดบทเรียน 5.6–5.7: verdict ของไฟล์ web ตรงกับฝั่ง PC ภายในเกณฑ์ (max|score_pc − score_web| ≤ TOL และคลาสที่ชนะตรงกัน) พร้อมอธิบายได้ว่าทำไมไม่จำเป็นต้องเท่ากันทุกบิต
- เติมไฟล์ฝึกครบห้าจุด รัน
python s13_web.pyแล้วจด label, conf และ scores ลงบันทึกการเรียน - รัน
s13_web_full.py --export-webแล้วs13_web_full.pyจด max-abs-diff สูงสุดและจำนวน window ที่คลาสตรงกัน - ปิด normalize ฝั่งใดฝั่งหนึ่งชั่วคราว แล้วดูว่า max-abs-diff พุ่งขึ้นแค่ไหน
- ถ้าทำได้ ยืนยันอย่างน้อยหนึ่ง window ในหน้าเว็บที่โหลด LiteRT.js ด้วยโค้ดจาก
--show-js
ชุดบทเรียนถัดไป (บทเรียน 5.8–5.9) เราจะพาโมเดลเดียวกันไป MCU ผ่าน Vela แล้วเทียบสามเป้าหมายด้าน latency, accuracy และพลังงาน
บทเรียนถัดไป: บทเรียน 5.8 — quantize และ Vela: เอาโมเดลของเราขึ้น Ethos-U55
สะท้อนคิด
หัวข้อที่มีชื่อว่า “สะท้อนคิด”- ถ้าคุณต้องทำเดโมเสียงแทน IMU front-end ฝั่ง JS จะยากขึ้นตรงไหน
- ในงานของคุณ TOL เท่าไรจึงยอมรับได้ และใครควรเป็นคนตัดสินเกณฑ์นั้น
คำถามทบทวน
ลองตอบเองก่อน แล้วค่อยเปิดดูเฉลย
-
รันแล้ว scores ดูถูกต้องแต่ conf = 0.0000 ทุกครั้ง จุดใดยังว่าง (เป้าหมายข้อ 1)
- เติม 1 normalize
- เติม 3 invoke
- เติม 4 dequantize
- เติม 5 conf = float(o[top])
ดูเฉลย
คำตอบ: D. เติม 5 conf = float(o[top])
placeholder conf = 0.0 ค้างอยู่ ต้องดึงคะแนนของคลาสที่ชนะออกมาด้วย float(o[top])
-
scores ออกมาเป็น ['-128.0000', '127.0000', '-128.0000'] จุดใดยังว่าง (เป้าหมายข้อ 1)
- เติม 2 quantize
- เติม 4 dequantize ค่ายังเป็น int8 ดิบ ไม่ใช่ความน่าจะเป็น
- เติม 1 normalize
- ไม่มีจุดใดผิด
ดูเฉลย
คำตอบ: B. เติม 4 dequantize ค่ายังเป็น int8 ดิบ ไม่ใช่ความน่าจะเป็น
ต้องแปลงกลับด้วย (o − out_zero) × out_scale ค่าจึงอยู่ในช่วง 0..1 และรวมกันได้ราว 1
-
s13_web_full.py รายงานคลาสที่ชนะตรงกัน 12/12 window และ max-abs-diff สูงสุด 0.0117 ที่ TOL 0.02 สรุปอย่างไร (เป้าหมายข้อ 2)
- ผ่านบน PC แล้ว ขั้นต่อไปคือยืนยันในเบราว์เซอร์จริง
- ไม่ผ่าน เพราะ diff ไม่เป็นศูนย์
- ผ่าน และไม่ต้องทดสอบที่ไหนอีก
- ไม่ผ่าน เพราะต้องได้ 100%
ดูเฉลย
คำตอบ: A. ผ่านบน PC แล้ว ขั้นต่อไปคือยืนยันในเบราว์เซอร์จริง
ครบทั้งสองเงื่อนไข แต่ s13_web_full.py รันไฟล์ web ด้วย interpreter บน PC จึงเป็นด่านแรก เบราว์เซอร์จริงอาจใช้ kernel ต่างกันจึงควรยืนยันซ้ำ
-
ต้องส่งเดโมให้ลูกค้าเปิดดูทันทีโดยไม่ติดตั้งอะไรและไม่มีบอร์ด ควรเลือกเป้าหมายใด (เป้าหมายข้อ 3)
- MCU + Ethos-U55
- Web ในเบราว์เซอร์
- Cortex-A
- PC ใน Docker
ดูเฉลย
คำตอบ: B. Web ในเบราว์เซอร์
เว็บแชร์ด้วยลิงก์ได้ทันทีและข้อมูลอยู่ในเครื่องผู้ใช้ แลกกับการต้องทำ front-end ใน JS และวัด parity เอง
-
ทำไม eval_pc.py จึงรันบน Raspberry Pi ได้โดยไม่แก้แม้แต่บรรทัดเดียว (เป้าหมายข้อ 3)
- เพราะ Raspberry Pi มี Ethos-U55
- เพราะ Cortex-A มี Linux กับ Python จริง ติดตั้ง ai-edge-litert ได้ และใช้ไฟล์ .tflite เดิมโดยไม่บังคับ int8
- เพราะ eval_pc.py ถูกคอมไพล์เป็นภาษา C
- เพราะใช้ Vela
ดูเฉลย
คำตอบ: B. เพราะ Cortex-A มี Linux กับ Python จริง ติดตั้ง ai-edge-litert ได้ และใช้ไฟล์ .tflite เดิมโดยไม่บังคับ int8
Cortex-A คือ PC ตัวเล็กที่มีระบบปฏิบัติการเต็ม สคริปต์และไฟล์โมเดลชุดเดียวกับบน PC จึงย้ายไปได้ทันที
อ้างอิงบทเรียนนี้
ถ้านำบทเรียนนี้ไปสอน ทำสไลด์ หรือทำเอกสารต่อ ให้อ้างอิงด้วยข้อความนี้ ถ้าดัดแปลงเนื้อหา ให้เติม (ดัดแปลง)ต่อท้ายชื่อบทเรียน
"ลงมือทำ: verdict บนเว็บให้ตรงกับ PC และเรื่องราว Cortex-A" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0
ข้อความอ้างอิงภาษาอังกฤษ: "Hands-on: a web verdict that matches the PC, and the Cortex-A story" from TESA Open Knowledge by the Thai Embedded Systems Association (TESA), https://github.com/tesaiot/tesa-qualification-program, licensed under CC BY-NC 4.0
ลิงก์บทเรียน: https://tesaiot.github.io/tesa-qualification-program/courses/edge-ai-developer/m05-training/l07-web-parity-lab/
TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0
เนื้อหาเผยแพร่ภายใต้ CC BY-NC 4.0 นำไปใช้ต่อในงานที่ไม่ใช่เพื่อการค้าได้ โปรดอ้างอิงสมาคมสมองกลฝังตัวไทย (TESA) ทุกครั้ง · วิธีอ้างอิง TESA