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

ลงมือทำ: แอปโฟกัสของเราเอง

โมดูล 6 — แอป Edge AI · สไลด์: slides.md · ภาพรวมโมดูล · หน้าหลักสูตร

เติมสี่จุดใน s15_apps.py ให้เป็นแอปโฟกัสที่นับเสียงไอ ได้แก่ select โมเดลเป้าหมายก่อนลูป อ่าน result โชว์คลาสที่ชนะ และเงื่อนไขตรวจเจอที่ผ่าน CONF_FLOOR แล้วรีทาร์เก็ตเป็น Alarm หรือ Siren ด้วยการแก้แค่สองบรรทัดบนหัวไฟล์ จนได้ตระกูลแอปต่อโมเดลของเราเอง

เมื่อจบบทเรียนนี้ คุณจะ:

  1. เติมสี่จุดใน practice/s15_apps.py จนแอปขึ้นคลาสที่ชนะ แถบทุกคลาส latency และตัวนับที่เพิ่มหนึ่งครั้งต่อเหตุการณ์เป้าหมายหนึ่งครั้ง
  2. รีทาร์เก็ตแอปเป็นโมเดลอื่นอย่างน้อยหนึ่งตัวโดยแก้แค่ TARGET_KEYWORDS กับ TARGET_CLASS และตรวจชื่อคลาสจาก edge_ai.models() ก่อน (เช่น Siren ใช้คลาส sirens)
  3. ทดลองตัดเงื่อนไข conf ≥ CONF_FLOOR ออกชั่วคราว แล้วอธิบายจากผลที่เห็นว่าทำไมตัวนับจึงเก็บ false positive

ผ่านบทเรียน 6.1 มาแล้ว เข้าใจ find_model, CONF_FLOOR และการนับขอบขาขึ้น เตรียมคลิปเสียงไอ เสียงเตือน หรือไซเรนไว้เปิดใกล้บอร์ด

  • อุปกรณ์: บอร์ด TESAIoT Dev Kit ที่ลงเฟิร์มแวร์ MicroPython ของ BENTO แล้ว หรือ BENTO Emulator ใน BENTO IDE — บน Emulator โมเดลเสียงเป็นค่าจำลองที่คลาสเหตุการณ์ยังไม่ชนะ unlabelled ตัวนับจึงไม่ขยับ ทดสอบตรรกะการนับบน Emulator ได้ด้วยโมเดล Motion กับปุ่ม Shake ส่วนการนับเสียงไอจริงต้องใช้บอร์ด
  • เรียนมาก่อน: บทเรียน 6.1 — หกโมเดลกับ edge_ai API: แอปที่โฟกัสโมเดลเดียว

ทั้งไฟล์อ่านเป็นประโยคเดียว: เล็งโมเดล cough → สร้างการ์ด → เริ่มรัน → วนอ่านผล เอาคลาสขึ้นจอ นับเมื่อเจอ → ออกก็หยุด แผงตั้งค่าบนหัวไฟล์คือ TARGET_KEYWORDS = ("cough",), TARGET_CLASS = "cough" และ TARGET_SENSOR = edge_ai.SENSOR_MIC แยกชื่อโมเดลกับชื่อคลาสออกจากกัน เพราะไม่เหมือนกันเสมอ สี่จุดที่เติมคือ (1) edge_ai.select(model['index']) ก่อนลูปใน try เพราะ select() โยน OSError ได้ถ้าการสลับไม่ได้รับการยืนยัน (2) r = edge_ai.result() (3) verdict.text(r['label'] or '-') เมื่อ seq เปลี่ยน และ (4) is_target = r['label'] == TARGET_CLASS and r['conf'] >= edge_ai.CONF_FLOOR ซึ่งเป็นของใหม่จริงของบทเรียนนี้

ตัวนับเพิ่มเมื่อ is_target and not was_target คือหนึ่งต่อการไอหนึ่งครั้ง ถ้าเห็นเลขพรวดหลายทีต่อเสียงเดียว แปลว่าเงื่อนไขขอบขาขึ้นหายไป ถ้าผลค้างนิ่งและ seq ไม่ขยับ นั่นคือเพดานของ Ready-Model แบบประเมินผล ไม่ใช่โค้ดพัง รีทาร์เก็ตใช้เวลาไม่ถึงนาที: ("alarm",) กับ "alarm" หรือ ("siren",) กับ "sirens" (มี s) แล้วเซฟเป็นไฟล์ใหม่ โครงทั้งไฟล์ไม่ต้องแตะ เพราะ find_model() หาโมเดลให้ และแถบปรับตาม labels ที่ได้มา ความสำเร็จคือบอกได้ว่า action ของคุณเชื่อ verdict เมื่อไร และกันนับเฟ้ออย่างไร

s15_apps_full.py เพิ่มสีตาม CONF_FLOOR debounce เบา ๆ (นับเมื่อเจอติดกันสองผล) ป้ายเวลาที่เจอครั้งล่าสุด และปุ่ม Reset ล้างตัวนับ

ไฟล์ ไฟล์นี้สอน
examples/s15_apps_full.py แอป Edge AI แบบ “โฟกัสโมเดลเดียว” (ฉบับเต็ม)

สไลด์ของบทเรียนนี้อ้างถึงไฟล์ที่อยู่ในบทเรียนอื่นหรือใน shared/ ด้วย:

คอมเมนต์ # เติม: อยู่ที่บรรทัด 87 (select), 96 (result), 101 (verdict.text) และ 112 (is_target) ถ้าการ์ดขึ้นครบแต่ไม่มีผลเลย ตรวจจุดที่ 87 ก่อน ถ้าแถบขยับแต่ตัวใหญ่ไม่เปลี่ยน ตรวจจุดที่ 101

ไฟล์ฝึก เรื่อง
practice/s15_apps.py แอป Edge AI แบบ “โฟกัสโมเดลเดียว” (ฉบับฝึกเติมโค้ด)

เปิดเฉลยหลังจากลองเองแล้วอย่างน้อยหนึ่งรอบ และอ่าน วิธีใช้เฉลย ก่อน

เฉลย คู่กับ
solution/s15_apps.py practice/s15_apps.py

คำถามชุดเดียวกันอยู่ใน quiz.yaml สำหรับระบบที่ตรวจอัตโนมัติ

  1. แอปขึ้นการ์ดครบแต่ไม่มีผลใด ๆ เลยและตัวนับไม่ขยับ จุดใดยังว่างมากที่สุด (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)

    • ก) จุดที่ 1 edge_ai.select(model[‘index’])
    • ข) จุดที่ 3 verdict.text(…)
    • ค) จุดที่ 4 is_target
    • ง) ไม่มีจุดใดผิด
    เฉลย

    ก — ถ้าไม่ select โมเดลเป้าหมาย ก็ไม่มีโมเดลรัน จึงไม่มีผลให้ result() คืน

  2. ไอหนึ่งครั้งแต่ตัวนับเพิ่มสามถึงสี่ครั้ง ส่วนใดของเงื่อนไขหายไป (เลือกหนึ่งข้อ · เป้าหมายข้อ 1)

    • ก) r[“conf”] >= edge_ai.CONF_FLOOR
    • ข) not was_target (การนับเฉพาะขอบขาขึ้น)
    • ค) r[“label”] == TARGET_CLASS
    • ง) edge_ai.stop()
    เฉลย

    ข — ไอหนึ่งครั้งกินหลายผลอนุมาน ถ้าไม่จำสถานะรอบก่อน ทุกผลที่เข้าเป้าจะถูกนับหมด

  3. รีทาร์เก็ตเป็นไซเรนด้วย TARGET_KEYWORDS = (“siren”,) และ TARGET_CLASS = “siren” แล้วตัวนับไม่เคยขยับ เพราะอะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 2)

    • ก) โมเดล Siren ไม่มีบนบอร์ด
    • ข) ชื่อคลาสจริงคือ sirens (มี s) เงื่อนไข label == TARGET_CLASS จึงไม่เคยจริง
    • ค) CONF_FLOOR สูงเกินไป
    • ง) find_model หาไม่เจอ
    เฉลย

    ข — ชื่อโมเดลกับชื่อคลาสไม่เหมือนกันเสมอ ให้ตรวจ labels จาก edge_ai.models() ใน REPL ก่อนรีทาร์เก็ต

  4. ตัดเงื่อนไข conf ออกแล้ว ตัวนับเพิ่มแม้ไม่มีใครไอ เพราะอะไร (เลือกหนึ่งข้อ · เป้าหมายข้อ 3)

    • ก) ไมค์เสีย
    • ข) argmax ให้ผู้ชนะเสมอ แม้ cough ชนะแบบเฉียด 0.51 ต่อ 0.49 ก็ถูกนับ กลายเป็น false positive
    • ค) seq ไม่เปลี่ยน
    • ง) โมเดลเปลี่ยนเป็น Motion
    เฉลย

    ข — CONF_FLOOR คือประตูที่บอกว่าเชื่อผลก็ต่อเมื่อมั่นใจถึงเกณฑ์ ถ้าไม่มีประตู ทุกครั้งที่ชนะเฉียดก็กลายเป็นการกระทำ

MVP ของชุดบทเรียน 6.1–6.2: แอปโฟกัสต่อโมเดลที่ UI สะอาด เล็งโมเดลด้วย find_model() โชว์ verdict แถบทุกคลาสและ latency และมีตัวนับที่ทำงานจริงเมื่อคลาสเป้าหมายข้าม CONF_FLOOR รีทาร์เก็ตได้อย่างน้อยสองโมเดล

  • เติมไฟล์ฝึกครบสี่จุด ซ้อมบน Emulator แล้วนับเสียงไอจริงบนบอร์ด
  • รีทาร์เก็ตเป็น Alarm หรือ Siren เซฟเป็นไฟล์ใหม่ แล้วยืนยันว่าตัวนับทำงาน
  • ตัด and r['conf'] >= edge_ai.CONF_FLOOR ออกชั่วคราว ส่งเสียงอื่น ๆ แล้วจดลงบันทึกการเรียนว่าตัวนับต่างจากเดิมอย่างไร แล้วใส่กลับ
  • อธิบายได้ว่าทำไมต้องเช็ก CONF_FLOOR ก่อนนับ และทำไมต้องนับเฉพาะขอบขาขึ้น

ชุดบทเรียนถัดไป (บทเรียน 6.3–6.4) เราจะเปลี่ยนการนับเป็น action ที่แรงขึ้น เช่นไฟ RGB เสียง และ log พร้อม debounce และ cooldown เต็มรูปแบบ

บทเรียนถัดไป: บทเรียน 6.3 — ท่อสั่งการ: CONF_FLOOR, debounce, cooldown และ on_result

  • ถ้าแอปนับเสียงไอนับเกินจริงในห้องที่มีคนคุยกัน คุณจะปรับอะไรก่อน ระหว่าง CONF_FLOOR กับ debounce
  • การแยก TARGET_KEYWORDS ออกจาก TARGET_CLASS ช่วยคนที่ต้องดูแลโค้ดต่อจากคุณอย่างไร

คำถามทบทวน

ลองตอบเองก่อน แล้วค่อยเปิดดูเฉลย

  1. แอปขึ้นการ์ดครบแต่ไม่มีผลใด ๆ เลยและตัวนับไม่ขยับ จุดใดยังว่างมากที่สุด (เป้าหมายข้อ 1)

    1. จุดที่ 1 edge_ai.select(model['index'])
    2. จุดที่ 3 verdict.text(...)
    3. จุดที่ 4 is_target
    4. ไม่มีจุดใดผิด
    ดูเฉลย

    คำตอบ: A. จุดที่ 1 edge_ai.select(model['index'])

    ถ้าไม่ select โมเดลเป้าหมาย ก็ไม่มีโมเดลรัน จึงไม่มีผลให้ result() คืน

  2. ไอหนึ่งครั้งแต่ตัวนับเพิ่มสามถึงสี่ครั้ง ส่วนใดของเงื่อนไขหายไป (เป้าหมายข้อ 1)

    1. r["conf"] >= edge_ai.CONF_FLOOR
    2. not was_target (การนับเฉพาะขอบขาขึ้น)
    3. r["label"] == TARGET_CLASS
    4. edge_ai.stop()
    ดูเฉลย

    คำตอบ: B. not was_target (การนับเฉพาะขอบขาขึ้น)

    ไอหนึ่งครั้งกินหลายผลอนุมาน ถ้าไม่จำสถานะรอบก่อน ทุกผลที่เข้าเป้าจะถูกนับหมด

  3. รีทาร์เก็ตเป็นไซเรนด้วย TARGET_KEYWORDS = ("siren",) และ TARGET_CLASS = "siren" แล้วตัวนับไม่เคยขยับ เพราะอะไร (เป้าหมายข้อ 2)

    1. โมเดล Siren ไม่มีบนบอร์ด
    2. ชื่อคลาสจริงคือ sirens (มี s) เงื่อนไข label == TARGET_CLASS จึงไม่เคยจริง
    3. CONF_FLOOR สูงเกินไป
    4. find_model หาไม่เจอ
    ดูเฉลย

    คำตอบ: B. ชื่อคลาสจริงคือ sirens (มี s) เงื่อนไข label == TARGET_CLASS จึงไม่เคยจริง

    ชื่อโมเดลกับชื่อคลาสไม่เหมือนกันเสมอ ให้ตรวจ labels จาก edge_ai.models() ใน REPL ก่อนรีทาร์เก็ต

  4. ตัดเงื่อนไข conf ออกแล้ว ตัวนับเพิ่มแม้ไม่มีใครไอ เพราะอะไร (เป้าหมายข้อ 3)

    1. ไมค์เสีย
    2. argmax ให้ผู้ชนะเสมอ แม้ cough ชนะแบบเฉียด 0.51 ต่อ 0.49 ก็ถูกนับ กลายเป็น false positive
    3. seq ไม่เปลี่ยน
    4. โมเดลเปลี่ยนเป็น Motion
    ดูเฉลย

    คำตอบ: B. argmax ให้ผู้ชนะเสมอ แม้ cough ชนะแบบเฉียด 0.51 ต่อ 0.49 ก็ถูกนับ กลายเป็น false positive

    CONF_FLOOR คือประตูที่บอกว่าเชื่อผลก็ต่อเมื่อมั่นใจถึงเกณฑ์ ถ้าไม่มีประตู ทุกครั้งที่ชนะเฉียดก็กลายเป็นการกระทำ

อ้างอิงบทเรียนนี้

ถ้านำบทเรียนนี้ไปสอน ทำสไลด์ หรือทำเอกสารต่อ ให้อ้างอิงด้วยข้อความนี้ ถ้าดัดแปลงเนื้อหา ให้เติม (ดัดแปลง)ต่อท้ายชื่อบทเรียน

"ลงมือทำ: แอปโฟกัสของเราเอง" จาก TESA Open Knowledge โดยสมาคมสมองกลฝังตัวไทย (Thai Embedded Systems Association: TESA) https://github.com/tesaiot/tesa-qualification-program สัญญาอนุญาต CC BY-NC 4.0

ข้อความอ้างอิงภาษาอังกฤษ: "Hands-on: your own focused app" 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/m06-apps/l02-focused-app-lab/

วิธีอ้างอิง TESA ฉบับเต็ม

TESA Open Knowledge · © 2026 สมาคมสมองกลฝังตัวไทย (TESA) · CC BY-NC 4.0

เนื้อหาเผยแพร่ภายใต้ CC BY-NC 4.0 นำไปใช้ต่อในงานที่ไม่ใช่เพื่อการค้าได้ โปรดอ้างอิงสมาคมสมองกลฝังตัวไทย (TESA) ทุกครั้ง · วิธีอ้างอิง TESA