บทเรียน 6.1 — หกโมเดลกับ edge_ai API: แอปที่โฟกัสโมเดลเดียว

สร้าง "แอปโฟกัสโมเดลเดียว" ของคุณเอง

โมดูล 6 — แอป Edge AI

เปิด โมดูล 6 (Apps, Pillar 5)

คาถาประจำบทเรียน: "เมนูให้เลือกทุกอย่าง คือเดโม — แอปที่ทำงานจริงมักโฟกัสโมเดลเดียว แล้วเอา verdict ไปทำอะไรสักอย่าง"

MicroPython บนบอร์ด BENTO (PSoC Edge · Cortex-M55 + Ethos-U55 NPU)

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

เปิดบทเรียนด้วยของจริงก่อน

เหมือนทุกบทเรียน เราเริ่มแบบ กลับด้าน — รันของที่ทำงานได้ก่อน แล้วค่อยแกะ วันนี้เปิดตัวอย่าง 16_edge_ai_sound_events.py มันคือเมนูรวมสามโมเดลเสียง (ไอ / เสียงเตือน / ไซเรน) ในหน้าเดียว

รันเดโมเสียง ตัวอย่าง 16 แกะดูข้างใน find_model + result โฟกัสโมเดลเดียว + นับเมื่อเจอ รีทาร์เก็ต cough/alarm/siren

บทเรียน 1.1–1.3 เราทำ "เมนู 6 โมเดล" ให้เลือกได้ทุกตัว — สนุกดีสำหรับเดโม แต่วันนี้เราจะถอยไปอีกก้าว: เอาโมเดลเดียวมาทำเป็น แอป ที่มีหน้าจอเฉพาะตัว แล้วต่อ verdict เข้ากับการกระทำจริง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

เป้าหมายของชุดบทเรียนนี้

จบชุดบทเรียนนี้เราจะเปลี่ยนจาก "รันโมเดล" เป็น "สร้างแอป" ครบ 4 เรื่อง แล้วปิดท้ายด้วยแอปที่คุณสร้างเอง:

  1. เมนู กับ แอปโฟกัส ต่างกันตรงไหน และทำไมงานจริงมักเลือกอย่างหลัง
  2. find_model() — เล็งโมเดลด้วยคีย์เวิร์ด แทนที่จะ hard-code เลข index
  3. อ่าน scores ทุกคลาส + latency_ms ให้เป็น ไม่ใช่แค่คลาสที่ชนะ
  4. จาก verdict สู่ action — นับเมื่อคลาสเป้าหมายข้ามเกณฑ์ CONF_FLOOR (ก้าวแรกของ Apps)
  5. ลงมือ: เติม s15_apps.py ให้เป็น แอป Cough ที่นับจำนวนครั้งที่ไอบนจอ

ปลายทางวันนี้: แอปโฟกัสหน้าตาสะอาด รันโมเดลเดียว โชว์คลาสที่ชนะ + แถบทุกคลาส และตัวนับที่เพิ่มขึ้นจริงเมื่อเจอเสียงเป้าหมาย

วันนี้เรายังไม่แตะ RGB/เสียง/WiFi (นั่นคือ บทเรียน 6.3–6.6) เราโฟกัสที่ "โครงของแอปต่อโมเดล" กับการกระทำเบาที่สุดหนึ่งอย่าง คือการนับ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ชุดบทเรียนนี้อยู่ตรงไหนของวงจร

เราเดินมาครบสี่ Pillar แรกแล้ว (DAQ → Processing → Analysis → Training) ชุดบทเรียนนี้เข้าสู่ Pillar 5 · Apps — ขั้นที่เอาโมเดลไป "ใช้งาน" จริง

1 · DAQ โมดูล 2 2 · Processing โมดูล 3 3 · Analysis โมดูล 4 4 · Training โมดูล 5 5 · Apps ชุดบทเรียนนี้ (6.1–6.2) Apps คือปลายทางของทั้งวงจร — เอาทุกอย่างที่สร้างมา มาทำเป็นของที่ใช้ได้จริง
  • บทเรียน 1.1–1.3 เราเคยแตะ Apps มาแล้วสั้นๆ (เมนู 6 โมเดล) และ บทเรียน 1.6–1.7 เราแกะ path จาก verdict สู่ action
  • ชุดบทเรียนนี้เอาทั้งสองมาต่อยอด: สร้าง แอปที่โฟกัสและใช้ได้จริง ไม่ใช่แค่เดโมเมนู
  • บทเรียน 6.3–6.4 (ชุดบทเรียนถัดไป) จะต่อ action ให้แรงขึ้น (RGB/เสียง/log + debounce เต็มรูปแบบ) · บทเรียน 6.5–6.6 ต่อ IoT

เราปิดวงกลับมาที่จุดเริ่ม — แต่รอบนี้คุณเข้าใจทุกขั้นที่อยู่เบื้องหลังโมเดลแล้ว การสร้างแอปจึงไม่ใช่กล่องดำอีกต่อไป

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ทบทวนจากบทเรียน 1.6–1.7 — verdict สู่ action

บทเรียน 1.6–1.7 เราแกะแอป Edge AI จนเห็น "เส้นทางของผล" — จากเซนเซอร์ไปจนถึงการกระทำ วันนี้เราต่อจากปลายเส้นนั้น

เซนเซอร์ ไมค์ / IMU / เรดาร์ โมเดล (NPU) อนุมาน verdict label · conf · scores action นับ / เตือน / log โฟกัสของชุดบทเรียนนี้: จาก verdict → action ที่เบาที่สุด
  • โมดูล 1 หยุดที่ช่อง verdict เป็นหลัก — เอา label + conf ขึ้นจอ
  • ชุดบทเรียนนี้เราขยับไปช่อง action ช่องแรก: "นับ" เมื่อคลาสเป้าหมายมาแบบมั่นใจ
  • การนับดูเล็กน้อย แต่มันสอนหลักการเดียวกับ action ที่ใหญ่กว่า: ตัดสินใจว่าจะเชื่อ verdict เมื่อไร แล้วค่อยลงมือ

"นับ" คือ action ที่ปลอดภัยที่สุดสำหรับเรียนรู้ — ไม่มีอะไรพัง แต่คุณจะได้เจอปัญหาจริงของ Apps ทันที: นับเฟ้อเพราะเสียงกระพริบ, false positive จาก conf ต่ำ เดี๋ยวเราแก้ทีละอย่าง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

เมนู กับ แอปโฟกัส ต่างกันตรงไหน

ทั้งคู่ใช้ edge_ai ตัวเดียวกัน ต่างกันที่ เจตนาของการออกแบบ — และงานจริงเกือบทั้งหมดเป็นแบบขวา

เมนู (1.1–1.3 · ตัวอย่าง 12/16) dropdown เลือกได้ทุกโมเดล UI กลางๆ ใช้ได้กับทุกตัว ผู้ใช้ต้องรู้ว่าจะเลือกอะไร ดีสำหรับ: สำรวจ · เดโม · ทดสอบ ไม่ดีสำหรับ: สินค้าจริง (เครื่องตรวจเสียงไอ ไม่ควรให้เลือกโมเดลเอง) แอปโฟกัส (6.1–6.2 · ตัวอย่าง 13/14/15) เล็งโมเดลเดียวตอนเปิดแอป UI ออกแบบเฉพาะงานนั้น ผู้ใช้แค่ "ใช้" ไม่ต้องเลือก verdict ต่อกับ action ได้เต็มที่ ดีสำหรับ: สินค้า · งานเฉพาะทาง คือรูปแบบที่เราจะสร้างวันนี้

คิดง่ายๆ: เมนูคือ "รีโมตรวม" ที่คุมทีวีได้ทุกยี่ห้อ ส่วนแอปโฟกัสคือ "ปุ่มเดียว" บนเครื่องที่ทำงานหนึ่งอย่างให้ดีที่สุด งานวิศวกรรมจริงต้องการอย่างหลังมากกว่า

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ตระกูลแอปอ้างอิง — ตัวอย่าง 13 ถึง 16

ก่อนสร้างเอง มาดูของที่มีอยู่ ทั้งสี่ตัวคือ "แอปต่อโมเดล" ที่โครงเกือบเหมือนกันเป๊ะ ต่างแค่โมเดลกับ UI นิดหน่อย

# ไฟล์ โมเดล/เซนเซอร์ จุดเด่นที่เพิ่มจากเมนู
13 13_edge_ai_motion.py Motion (IMU) โฟกัสตัวเดียว + find_model + latency
14 14_edge_ai_babycry.py Baby Cry (MIC) การ์ดผลลัพธ์ + แถบความมั่นใจต่อคลาส
15 15_edge_ai_radar_push.py Push (RADAR) โมเดล float32 + คำใบ้ระยะยืน
16 16_edge_ai_sound_events.py Cough/Alarm/Siren (MIC) คัดเฉพาะโมเดลไมค์เข้ามาในเมนูย่อย
  • สังเกตว่าทั้งสี่ตัวมีก้อนเดียวกัน: find_model() → select() → ลูป result() → วาด verdict + แถบ → finally: stop()
  • ตัวอย่าง 13/14/15 คือ แอปโฟกัสโมเดลเดียว (แม่แบบของเรา) · ตัวอย่าง 16 เป็นเมนูย่อยของสามโมเดลเสียง
  • งานชุดบทเรียนนี้: เอาโครงเดียวกันนี้ บวก action หนึ่งอย่าง (การนับ) แล้วทำให้รีทาร์เก็ตง่ายด้วยตัวแปรบนหัวไฟล์

จำ pattern นี้ไว้ให้ขึ้นใจ เพราะแอป Edge AI 90% ที่คุณจะเขียนต่อจากนี้ ล้วนเป็นโครงนี้ทั้งนั้น เปลี่ยนแค่ "โมเดลอะไร" กับ "ทำอะไรกับผล"

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

6 โมเดล — ตัวไหนเอามาทำแอปโฟกัสได้บ้าง

ทะเบียนโมเดลยังเป็น 6 ตัวเดิมจากบทเรียน 1.1–1.3 ชุดบทเรียนนี้เราจะหยิบ โมเดลเสียง มาทำแอป เพราะทดสอบง่าย (ส่งเสียงเอง) และเป็นสนามใหญ่ของ Edge AI จริง

# ชื่อโมเดล เซนเซอร์ คลาส (labels) เหมาะทำแอป
0 Motion Detection IMU idle, circle, shaking ตัวอย่าง 13
1 Baby Cry Detection MIC unlabelled, baby_cry ตัวอย่าง 14
2 Push Detection RADAR unlabelled, Push ตัวอย่าง 15
3 Cough Detection MIC unlabelled, cough ชุดบทเรียนนี้ (ค่าตั้งต้น)
4 Alarm Detection MIC unlabelled, alarm รีทาร์เก็ต
5 Siren Detection MIC unlabelled, sirens รีทาร์เก็ต
  • ค่าตั้งต้นของ s15_apps.py เล็งที่ Cough Detection — เราสร้างแอป "เครื่องนับเสียงไอ"
  • โมเดล Cough/Alarm/Siren มาจาก DEEPCRAFT Ready-Model แต่ละตัวมีสองคลาส: unlabelled กับคลาสเป้าหมาย
  • การบ้าน: เปลี่ยนสองบรรทัดบนหัวไฟล์ให้เป็น Alarm และ Siren แล้วเซฟเป็นไฟล์แยก

เราเลือก Cough เป็นตัวตั้งต้นเพราะ "ไอ" เป็นเสียงสั้นชัด นับง่าย เห็นตัวเลขขยับทันที — เหมาะกับการเรียนเรื่อง "ขอบขาขึ้น" กับ debounce ที่จะเจอต่อไป

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ทวนคำสั่งหลักของ edge_ai

แอปโฟกัสยืนอยู่บนคำสั่งเดิมจาก บทเรียน 1.1–1.3 แต่ชุดบทเรียนนี้เราตัด count()/models() ออกจากลูปหลัก เหลือแค่สามตัวที่ทำงานจริงตอนรัน

คำสั่ง ชุดบทเรียนนี้ใช้ทำอะไร
edge_ai.models() เรียกครั้งเดียวตอนเปิด — ให้ find_model() ค้นทะเบียน
edge_ai.select(n) เริ่มโมเดลเป้าหมายตัวเดียว (ครั้งเดียว ไม่มีปุ่ม Load)
edge_ai.result() ดึง verdict ล่าสุดในลูป — หัวใจของแอป
edge_ai.stop() ปิดเครื่องยนต์ตอนออก (finally)
edge_ai.CONF_FLOOR เส้นแบ่ง 0.50 — ใช้ตัดสินว่าจะ "นับ" ไหม
edge_ai.SENSOR_MIC ค่าคงที่ = 2 — เซนเซอร์สำรองให้ find_model()
  • ต่างจาก บทเรียน 1.1–1.3 ตรงที่ select() เรียก ครั้งเดียวตอนเปิดแอป ไม่ต้องรอผู้ใช้กด Load — แอปโฟกัสรู้อยู่แล้วว่าจะรันอะไร
  • CONF_FLOOR คราวนี้ไม่ใช่แค่เปลี่ยนสี แต่เป็น เงื่อนไขของ action จริง (นับหรือไม่นับ)

น้อยลงแต่คมขึ้น — เมื่อคุณรู้ว่าจะรันโมเดลไหน โค้ดก็สั้นลง เหลือแต่แก่น: อ่านผล แล้วตัดสินใจ

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

result() เจาะลึก — คราวนี้เราใช้ scores กับ latency

result() คืน dict เดิมจาก บทเรียน 1.1–1.3 แต่ชุดบทเรียนนี้เราจะใช้ฟิลด์ให้ครบขึ้น โดยเฉพาะ scores (ทุกคลาส) และ latency_ms

r = edge_ai.result()
# {'index': 3, 'label': 'cough', 'top': 1, 'conf': 0.88,
#  'scores': [0.12, 0.88], 'latency_ms': 6.4, 'seq': 210, 'running': True}
ฟิลด์ ชุดบทเรียนนี้ใช้ยังไง
label + conf คำตอบสั้น + ใช้เทียบ CONF_FLOOR เพื่อตัดสินใจนับ
top index คลาสที่ชนะ — ระบายแถบตัวชนะเป็นเขียว
scores คะแนน ทุกคลาส — วาดแถบครบทุกแถว เห็น "ความสูสี"
latency_ms เวลาอนุมานจริง — โชว์บนการ์ด เทียบข้ามเซนเซอร์ได้
seq เลขลำดับผล — กันวาดจอซ้ำ (วาดเฉพาะตอน seq เปลี่ยน)

ใน บทเรียน 1.1–1.3 เราสนใจแค่ label/conf — ชุดบทเรียนนี้ scores กับ latency_ms เลื่อนมาเป็นพระเอก เพราะแอปที่ดีต้องบอกผู้ใช้ได้ว่า "มั่นใจแค่ไหน" และ "เร็วแค่ไหน" ไม่ใช่แค่ "คืออะไร"

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

find_model() — เล็งด้วยคีย์เวิร์ด ไม่ hard-code index

หัวใจที่ทำให้แอปโฟกัส "ทน" คือไม่ผูกกับเลข index ตายตัว เราค้นทะเบียนจากชื่อแทน แบบเดียวกับตัวอย่าง 13–16

def find_model(keywords, sensor):
    ms = edge_ai.models()
    for m in ms:                       # 1) ลองจับชื่อก่อน
        for k in keywords:
            if k.lower() in m['name'].lower():
                return m
    for m in ms:                       # 2) ไม่เจอชื่อ -> ใช้เซนเซอร์ที่ตรงกันตัวแรก
        if m['sensor'] == sensor:
            return m
    return ms[0]                       # 3) กันเหนียว -> ตัวแรกสุด
  • ส่ง ("cough",) เข้าไป มันจะคืน dict ของโมเดล Cough ไม่ว่ามันจะอยู่ index เท่าไร
  • ถ้าเฟิร์มแวร์สลับลำดับโมเดล หรือเพิ่ม/ลดโมเดล โค้ดนี้ยังหาถูกตัว — ต่างจาก select(3) ที่จะพังทันที
  • มีสามชั้นถอยหลัง (ชื่อ → เซนเซอร์ → ตัวแรก) เพื่อให้แอป ไม่ crash แม้หาไม่เจอเป๊ะ

นี่คือนิสัยเดียวกับ บทเรียน 1.1–1.3 — "ถามฮาร์ดแวร์ อย่าเดา" แค่คราวนี้เราถามแบบเจาะจง "ขอโมเดลที่ชื่อมีคำว่า cough" แล้วปล่อยให้เฟิร์มแวร์ตอบว่ามันอยู่ตรงไหน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

โครงของแอปโฟกัส

จับโครงให้ได้ก่อนดูโค้ดจริง แอปโฟกัสทุกตัวเดินตามห้าจังหวะนี้ — เป็นญาติสนิทของ "โครงร่วม" จาก บทเรียน 1.4–1.5 แต่ select ขยับมาอยู่ต้นเรื่อง

1 · find_model เล็งตัวเป้าหมาย 2 · สร้าง widget การ์ด + แถบคลาส 3 · select เริ่มครั้งเดียว 4 · ลูป result verdict + action(นับ) 5 · finally stop เก็บกวาด วนอ่านผลทุก ~150 ms

ต่างจากเมนู บทเรียน 1.1–1.3 ตรงที่ ไม่มีปุ่ม Load — select() อยู่ก่อนลูปเลย เพราะแอปโฟกัส "รู้ตั้งแต่เปิด" ว่าจะรันโมเดลอะไร ผู้ใช้ไม่ต้องเลือก

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

อ่าน scores ทุกคลาส — แถบต่อคลาส

scores คือหัวใจที่ทำให้ผู้ใช้ "เห็นความมั่นใจ" ไม่ใช่แค่คลาสเดียว เราวาดหนึ่งแถบต่อหนึ่งคลาส ตัวที่ชนะระบายเขียว

top = r['top']
for i, (lb, br) in enumerate(rows):
    if i < len(r['scores']):
        br.value(int(r['scores'][i] * 100))   # ความสูงของแถบ = คะแนนคลาสนั้น
        br.color(GREEN if i == top else DIM)   # คลาสที่ชนะ = เขียว, ที่เหลือ = จาง
  • โมเดล Cough มีสองคลาส ['unlabelled', 'cough'] เราจึงเห็นสองแถบ ขยับสวนทางกัน
  • เวลาไอชัดๆ แถบ cough จะพุ่งเข้าใกล้ 100% แถบ unlabelled จะยุบลง
  • เวลาเงียบ/เสียงอื่น แถบสองอันจะ สูสี — นี่แหละคือตอนที่ conf ต่ำกว่า CONF_FLOOR

แถบทุกคลาสไม่ได้มีไว้สวยงามเฉยๆ มันบอกคุณว่าโมเดล "ลังเล" หรือ "ชัวร์" ด้วยตาเปล่า — ก่อนจะเชื่อคำตอบ ให้ดูว่าตัวชนะทิ้งห่างตัวอื่นแค่ไหน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

latency — เวลาอนุมานต่างกันตามเซนเซอร์

latency_ms คือเวลาที่ NPU ใช้อนุมานหนึ่งครั้ง แอปที่ดีควรโชว์ให้เห็น เพราะมันบอก "ความสด" ของคำตอบ

lat.text("latency: %.1f ms" % r['latency_ms'])
  • โมเดลเสียง (Cough/Alarm/Siren) มักใช้เวลาต่างจากโมเดล IMU (Motion) เพราะขนาดอินพุตและสถาปัตยกรรมต่างกัน
  • ตัวเลขนี้เล็ก (ไม่กี่ ms) เพราะมี Ethos-U55 ช่วยคูณเมทริกซ์ — ถ้าให้ CPU ทำเองจะช้ากว่าหลายเท่า
  • ในงานจริง latency สำคัญมากกับงานที่ต้องตอบทันที (ตรวจการล้ม เสียงเตือน) — ช้าไปคือพลาดจังหวะ

ลองสังเกตในแล็บ: สลับระหว่างแอป Cough (ไมค์) กับตัวอย่าง 13 (IMU) แล้วเทียบ latency_ms คุณจะเห็นด้วยตาว่า "โมเดลคนละแบบ กินเวลาคนละอย่าง" — นี่คือข้อมูลที่วิศวกรใช้เลือกโมเดล

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

จาก verdict สู่ action — นับเมื่อข้าม CONF_FLOOR

นี่คือของใหม่จริงๆ ของชุดบทเรียนนี้ เราไม่หยุดที่การโชว์ผล แต่ "ทำอะไรสักอย่าง" เมื่อเจอคลาสเป้าหมายแบบมั่นใจ

is_target = (r['label'] == TARGET_CLASS
             and r['conf'] >= edge_ai.CONF_FLOOR)   # เชื่อก็ต่อเมื่อมั่นใจถึงเกณฑ์
if is_target and not was_target:                    # นับเฉพาะ "ขอบขาขึ้น"
    hits += 1
    hits_lbl.text(str(hits))
was_target = is_target
  • เงื่อนไขมีสองส่วน: คลาสต้องเป็นเป้าหมาย และ conf ต้องถึง CONF_FLOOR — ถ้าปล่อยเงื่อนไข conf ทิ้ง ตัวนับจะเก็บ false positive เต็มไปหมด
  • CONF_FLOOR เลื่อนสถานะจาก "ตัวเปลี่ยนสี" (บทเรียน 1.1–1.3) มาเป็น "ประตูของ action" จริง
  • นี่คือหลักการเดียวกับทุก action ในโลก Edge AI: ตัดสินใจว่าจะเชื่อ verdict ไหม ก่อนลงมือ

action แรกของคุณคือการนับ — เล็กแต่จริง ในบทเรียน 6.3–6.4 เราจะเปลี่ยน hits += 1 เป็น "จุด RGB / เล่นเสียง / เขียน log" ด้วยโครงตัดสินใจอันเดียวกันนี้

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

คณิตเบื้องหลัง (1) — argmax เลือกคลาสที่ชนะ

โมเดลไม่ได้คืนแค่ "คลาสเดียว" แต่คืน scores เป็นคะแนนของทุกคลาส เราต้องเลือก "ตัวที่ชนะ" ออกมาหนึ่งตัว วิธีคิดคือหาตำแหน่งที่คะแนนสูงสุด:

y^  =  arg⁡max⁡i  si\hat{y} \;=\; \arg\max_{i}\; s_i

โดยที่ s=(s0,s1,…,sK−1)s = (s_0, s_1, \dots, s_{K-1}) คือเวกเตอร์คะแนนของ KK คลาส และ y^\hat{y} คือ index ของคลาสที่ชนะ (ในโค้ดคือ r['top'])

  • sis_i — คะแนน (คล้ายความน่าจะเป็น) ของคลาสที่ ii รวมกันทุกคลาสได้ประมาณ 1
  • arg⁡max⁡\arg\max — แปลว่า "เอา index ที่ทำให้ค่ามากที่สุด" ไม่ใช่ตัวเลขค่ามากที่สุด
  • y^\hat{y} — คลาสที่โมเดลเชียร์ที่สุด เราจึงระบายแถบของคลาสนี้เป็นสีเขียว

ตัวอย่างโมเดล Cough ที่มีสองคลาส ['unlabelled', 'cough']: ได้ s=(0.12, 0.88)s = (0.12,\ 0.88) → y^=1\hat{y}=1 → คลาส cough ชนะ, และ conf ของผลนี้คือ 0.880.88

argmax บอกแค่ "ใครชนะ" มันไม่เคยบอกว่า "ชนะขาดหรือชนะเฉียด" — เพราะแม้คะแนน 0.510.51 ต่อ 0.490.49 ก็ยังมีผู้ชนะ นั่นคือเหตุผลที่เราต้องดู conf ต่ออีกชั้นในสไลด์ถัดไป ก่อนจะเชื่อผล

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

คณิตเบื้องหลัง (2) — CONF_FLOOR ประตูของ action

เพราะ argmax เลือกผู้ชนะเสมอ แม้ตอนคะแนนสูสี เราจึงตั้ง "เส้นแบ่งความมั่นใจ" ไว้อีกชั้น ก่อนจะยอมนับ ความมั่นใจของผลก็คือคะแนนของตัวที่ชนะ:

conf  =  sy^  =  max⁡i si\text{conf} \;=\; s_{\hat{y}} \;=\; \max_i\, s_i

count  ⟸  ( label=TARGET ) ∧ ( conf≥τ ),τ=0.50\text{count} \;\Longleftarrow\; \big(\,\text{label} = \text{TARGET}\,\big)\ \wedge\ \big(\,\text{conf} \ge \tau\,\big), \qquad \tau = 0.50

  • conf\text{conf} — คะแนนของคลาสที่ชนะ (ตัวสูงสุด) ใช้เป็นค่าความมั่นใจ
  • τ\tau (อ่านว่า "เทา") — เกณฑ์ขั้นต่ำ คือ edge_ai.CONF_FLOOR = 0.500.50 ในชุดบทเรียนนี้
  • ∧\wedge — เครื่องหมาย "และ" ทั้งสองเงื่อนไขต้องจริง พร้อมกัน จึงจะนับ

ทำไมมันสำคัญกับชุดบทเรียนนี้: ถ้าไม่มี τ\tau ทุกครั้งที่ cough แค่ชนะแบบ 0.510.51 ต่อ 0.490.49 ก็จะถูกนับ ตัวนับจะเฟ้อไปด้วย false positive การใส่ τ\tau คือการเขียนกฎว่า "เชื่อก็ต่อเมื่อมั่นใจถึงเกณฑ์" ซึ่งเป็นหัวใจของการเปลี่ยน verdict ให้เป็น action

เลข 0.500.50 ไม่ใช่ของศักดิ์สิทธิ์ — ตั้งสูง (τ=0.7\tau=0.7) ได้ความชัวร์แต่พลาดเสียงเบาๆ ตั้งต่ำ (τ=0.3\tau=0.3) จับได้ไวแต่ false positive เยอะ การเลือก τ\tau คือการชั่งน้ำหนักสองอย่างนี้ให้เข้ากับงาน

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ขอบขาขึ้น — ทำไมต้อง "not was_target"

ถ้านับทุกผลที่เข้าคลาสเป้าหมาย จะได้ตัวเลขเฟ้อมหาศาล เพราะไอหนึ่งครั้งกินเวลาหลายผลอนุมาน เราจึงนับเฉพาะ จังหวะที่เพิ่งเข้า

conf ของคลาส cough ตามเวลา (เส้นประ = CONF_FLOOR) นับ +1 นับ +1 ค้างเหนือเกณฑ์ = ไม่นับซ้ำ ค้างเหนือเกณฑ์ = ไม่นับซ้ำ
  • was_target จำสถานะรอบก่อน เรานับเฉพาะตอน "รอบนี้เข้าเป้า แต่รอบก่อนยังไม่เข้า" (ขอบขาขึ้น false → true)
  • ตราบใดที่เสียงยังดังค้างเหนือเกณฑ์ จะไม่นับซ้ำ ต้องตกลงต่ำกว่าเกณฑ์ก่อน แล้วขึ้นใหม่ถึงนับอีกครั้ง
  • ในฉบับเต็ม (examples/) เราเสริม debounce เบาๆ อีกชั้น: ต้องเจอติดกันสองผลถึงนับ กันเสียงกระพริบชั่วขณะ

เทคนิค "ขอบขาขึ้น" นี้เหมือนกับการอ่านปุ่มกดในคอร์สอื่นเป๊ะ — เรานับ "การกด" หนึ่งครั้ง ไม่ใช่นับทุกมิลลิวินาทีที่นิ้วยังกดค้างอยู่

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0

ข้อควรรู้ — Ready-Model แบบ eval มีขีดจำกัด

โมเดล Cough/Alarm/Siren เป็น DEEPCRAFT Ready-Model แบบ eval มีเงื่อนไขที่ต้องรู้ก่อนทดสอบ ไม่งั้นจะงงว่าทำไมผลหยุดนิ่ง

  • Ready-Model แบบ eval จำกัดจำนวนครั้งการอนุมาน (inference count) ต่อการบูตหนึ่งครั้ง
  • ถ้ารันนานๆ แล้วผลค้างนิ่ง (ตัวเลข seq ไม่ขยับ) นั่นแปลว่าถึงขีดจำกัดแล้ว — รีบูตบอร์ด จะรีเซ็ต
  • นี่ไม่ใช่บั๊กในโค้ดเรา เป็นลักษณะของโมเดล eval ซึ่งเป็นของ Imagimob AB (บริษัทในเครือ Infineon) ใช้ได้เพื่อประเมินผลเท่านั้น ห้ามใช้เชิงพาณิชย์หรือแจกจ่ายต่อ
ผลหยุดนิ่ง + seq ไม่ขยับ = ถึงขีด eval แล้ว → รีบูตบอร์ด ไม่ใช่แก้โค้ด

จุดนี้สำคัญเชิงวิศวกรรม: โมเดลที่ "ให้ลองฟรี" มักมีเงื่อนไขซ่อนอยู่ พอเราฝึกโมเดลเองได้ (โมดูล 5 (Training) ที่เพิ่งผ่านมา) เราก็หลุดจากข้อจำกัดนี้ — นี่คือเหตุผลหนึ่งที่คอร์สพาไปถึงการเทรนเอง

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · ดัดแปลงจาก Edge AI Developer (รศ.วิรุฬห์ ศรีบริรักษ์, BUU) · CC BY-NC 4.0