โมดูล 2/5 · สัปดาห์ 4–6 · 27 ชม.

พื้นฐาน ML

UAT 315 ปัญญาประดิษฐ์ การวิเคราะห์ข้อมูล และการมองเห็นด้วยคอมพิวเตอร์สำหรับระบบอากาศยานไร้คนขับ

เวลาเรียนประมาณ 90 นาทีร่าง รอตรวจปรับปรุงล่าสุด 27 กันยายน 2569

บทเรียน

เมื่อเรียนจบโมดูลนี้ ผู้เรียนจะสามารถ

  1. แยกการเรียนรู้แบบมีผู้สอนกับไม่มีผู้สอน และงานจำแนกประเภทกับงานพยากรณ์ค่า
  2. แบ่งข้อมูลเป็นชุดฝึก ชุดตรวจสอบ และชุดทดสอบ และอธิบายหน้าที่ของแต่ละชุด
  3. ฝึกและเปรียบเทียบ logistic regression กับ decision tree ด้วย scikit-learn
  4. อธิบายการเรียนน้อยไปและการเรียนเกิน และเหตุที่ความแม่นยำอย่างเดียวหลอกได้

ความรู้พื้นฐานที่ควรมี: UAT 315 โมดูล 1 · UAT 106 โมดูล 3

ทำไมต้องรู้

การเรียนรู้ของเครื่อง (machine learning, ML) คือการให้คอมพิวเตอร์หากฎจากตัวอย่าง แทนที่คนจะเขียนกฎเองทุกข้อ งานโดรนหลายอย่างเหมาะกับ ML เช่น ทำนายว่ามอเตอร์ใกล้เสียจาก log การสั่น หรือจำแนกพื้นที่น้ำท่วมจากภาพ แต่แบบจำลองที่ได้คะแนนดีบนข้อมูลที่เคยเห็นอาจใช้ไม่ได้เลยกับข้อมูลใหม่ โมดูลนี้ปูหลักการที่ทำให้ผลของ ML เชื่อถือได้

ชนิดของการเรียนรู้

  • เรียนแบบมีผู้สอน (supervised learning) มีคำตอบที่ถูกต้อง (ป้าย, label) ของตัวอย่างฝึก แบ่งเป็น จำแนกประเภท (classification) เมื่อคำตอบเป็นกลุ่ม เช่น มอเตอร์ปกติหรือผิดปกติ และ พยากรณ์ค่า (regression) เมื่อคำตอบเป็นตัวเลข เช่น เวลาบินที่เหลือ
  • เรียนแบบไม่มีผู้สอน (unsupervised learning) ไม่มีป้าย แบบจำลองหาโครงสร้างเอง เช่น จัดกลุ่มเที่ยวบินที่คล้ายกัน หรือหาเที่ยวบินที่แปลกไปจากกลุ่ม
คุณลักษณะ x คือการสั่นและกระแส เข้าแบบจำลอง f ของ x และ theta ได้คำทำนาย y hat ว่าปกติหรือผิดปกติ นำไปเทียบกับป้ายจริง y ได้ความคลาดเคลื่อน loss แล้วใช้ปรับค่า theta ของแบบจำลอง
ภาพที่ 1 การเรียนรู้แบบมีผู้สอน

การฝึกคือการปรับค่าพารามิเตอร์ ของแบบจำลองให้คำทำนายใกล้ป้ายจริงมากที่สุด โดยวัดความต่างด้วย ฟังก์ชันความสูญเสีย (loss)

แบ่งข้อมูลสามชุด

ตัวอย่างนี้ใช้ข้อมูลสังเคราะห์ 400 เที่ยวบิน คุณลักษณะคือการสั่นเฉลี่ย (g) และกระแสขณะลอยตัว (A) ป้ายคือมอเตอร์ผิดปกติหรือไม่ ข้อมูลแบ่งเป็นสามชุดที่มีหน้าที่ต่างกัน

  • ชุดฝึก (train) ใช้ปรับพารามิเตอร์
  • ชุดตรวจสอบ (validation) ใช้เลือกแบบจำลองและค่าตั้ง เช่น ความลึกของต้นไม้
  • ชุดทดสอบ (test) เก็บไว้ประเมิน ครั้งเดียว หลังเลือกทุกอย่างแล้ว
import numpy as np
from sklearn.model_selection import train_test_split

rng = np.random.default_rng(345)
n = 400
faulty = rng.random(n) < 0.2
vibration = np.where(faulty, rng.normal(0.17, 0.05, n), rng.normal(0.12, 0.04, n))
current = np.where(faulty, rng.normal(20, 2.5, n), rng.normal(18, 2.5, n))
X = np.column_stack([vibration, current])
y = faulty.astype(int)

X_rest, X_test, y_rest, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=345)
X_train, X_val, y_train, y_val = train_test_split(X_rest, y_rest, test_size=0.25, stratify=y_rest, random_state=345)
print(f"train {len(y_train)}  validation {len(y_val)}  test {len(y_test)}   faulty share {y.mean():.1%}")
train 240  validation 80  test 80   faulty share 21.8%

stratify=y รักษาสัดส่วนมอเตอร์ผิดปกติให้ใกล้เคียงกันทุกชุด ซึ่งสำคัญเมื่อกลุ่มหนึ่งมีน้อย

แบบจำลองแรกและกับดักของความแม่นยำ

Logistic regression เป็นแบบจำลองจำแนกประเภทพื้นฐาน รวมคุณลักษณะแบบเส้นตรงแล้วแปลงเป็นความน่าจะเป็นด้วยฟังก์ชันซิกมอยด์ ก่อนดูผล ต้องมี ค่าอ้างอิง (baseline) เสมอ

from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, recall_score
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler

baseline = np.zeros_like(y_val)
print(f"always 'healthy': accuracy {accuracy_score(y_val, baseline):.3f}  recall {recall_score(y_val, baseline):.3f}")

model = make_pipeline(StandardScaler(), LogisticRegression()).fit(X_train, y_train)
pred = model.predict(X_val)
print(f"logistic regression: accuracy {accuracy_score(y_val, pred):.3f}  recall {recall_score(y_val, pred):.3f}")
pred_03 = (model.predict_proba(X_val)[:, 1] >= 0.3).astype(int)
print(f"threshold 0.3:       accuracy {accuracy_score(y_val, pred_03):.3f}  recall {recall_score(y_val, pred_03):.3f}")
always 'healthy': accuracy 0.787  recall 0.000
logistic regression: accuracy 0.950  recall 0.765
threshold 0.3:       accuracy 0.900  recall 0.824

แบบจำลองที่ตอบว่า “ปกติ” ทุกครั้งได้ความแม่นยำเกือบ 79% ทั้งที่ไม่พบมอเตอร์ผิดปกติเลยสักลำ (recall = 0) นี่คือ กับดักของความแม่นยำ เมื่อกลุ่มหนึ่งมีน้อย logistic regression ดีกว่ามาก และถ้าลดจุดตัดความน่าจะเป็นจาก 0.5 เป็น 0.3 จะพบมอเตอร์ผิดปกติมากขึ้น แลกกับการเตือนผิดเพิ่ม ในงานซ่อมบำรุงที่การพลาดมอเตอร์เสียอาจทำให้โดรนตก การเลือก recall สูงมักคุ้มกว่า make_pipeline ช่วยให้ StandardScaler เรียนสถิติจากชุดฝึกเท่านั้นตามที่เรียนในโมดูล 1

เรียนน้อยไปและเรียนเกิน

สามช่องมีจุดข้อมูลชุดเดียวกัน ช่องแรกเส้นตรงแทบแบนไม่ตามข้อมูลคือเรียนน้อยไป ช่องที่สองเส้นโค้งเรียบตามแนวโน้มคือพอดี ช่องที่สามเส้นหยักผ่านทุกจุดคือเรียนเกิน
ภาพที่ 2 เรียนน้อยไป พอดี และเรียนเกิน
  • เรียนน้อยไป (underfitting) แบบจำลองง่ายเกินไป ทำได้ไม่ดีทั้งชุดฝึกและชุดตรวจสอบ
  • เรียนเกิน (overfitting) แบบจำลองจำรายละเอียดและสัญญาณรบกวนของชุดฝึก ทำได้ดีมากบนชุดฝึกแต่แย่ลงบนข้อมูลใหม่

Decision tree แบ่งข้อมูลด้วยคำถามใช่หรือไม่ทีละขั้น ความลึกของต้นไม้คุมความซับซ้อน

from sklearn.tree import DecisionTreeClassifier

for depth in (1, 2, 3, 4, 6, 10, None):
    tree = DecisionTreeClassifier(max_depth=depth, random_state=0).fit(X_train, y_train)
    print(f"max_depth {str(depth):>4}: train {accuracy_score(y_train, tree.predict(X_train)):.3f}"
          f"   validation {accuracy_score(y_val, tree.predict(X_val)):.3f}")
max_depth    1: train 0.867   validation 0.887
max_depth    2: train 0.879   validation 0.863
max_depth    3: train 0.904   validation 0.925
max_depth    4: train 0.929   validation 0.925
max_depth    6: train 0.954   validation 0.912
max_depth   10: train 0.992   validation 0.887
max_depth None: train 1.000   validation 0.887

เมื่อต้นไม้ลึกขึ้น ความแม่นยำบนชุดฝึกเพิ่มจนถึง 1.000 แต่บนชุดตรวจสอบสูงสุดที่ความลึก 3 ถึง 4 แล้วลดลง ความลึกไม่จำกัดคือการเรียนเกินอย่างชัดเจน เราจึงเลือกความลึกจากชุดตรวจสอบ ไม่ใช่จากชุดฝึก

ตัวอย่างที่ 1 ประเมินครั้งสุดท้ายด้วยชุดทดสอบ

หลังเลือกความลึก 3 จากชุดตรวจสอบแล้ว ฝึกใหม่ด้วยชุดฝึกรวมชุดตรวจสอบ และประเมินกับชุดทดสอบเพียงครั้งเดียว

final = DecisionTreeClassifier(max_depth=3, random_state=0).fit(X_rest, y_rest)
test_pred = final.predict(X_test)
print(f"test accuracy {accuracy_score(y_test, test_pred):.3f}   test recall {recall_score(y_test, test_pred):.3f}")
test accuracy 0.800   test recall 0.412

ผลบนชุดทดสอบต่ำกว่าบนชุดตรวจสอบมาก ความแม่นยำลดจาก 0.925 เหลือ 0.800 และพบมอเตอร์ผิดปกติเพียง 41% ผลแบบนี้พบบ่อยในงานจริง สาเหตุหนึ่งคือชุดตรวจสอบมีมอเตอร์ผิดปกติเพียง 17 ลำ ตัวเลขจากชุดเล็กจึงแกว่งมาก และการเลือกค่าที่ดีที่สุดจากชุดตรวจสอบก็ทำให้ผลบนชุดนั้นดูดีเกินจริงเล็กน้อย ผลบนชุดทดสอบคือตัวเลขที่ต้องรายงานตามจริง ถ้าเห็นผลนี้แล้วย้อนกลับไปปรับความลึกเพื่อให้ตัวเลขดีขึ้น ชุดทดสอบจะไม่เป็นอิสระอีกต่อไป ทางที่ถูกคือเก็บข้อมูลเพิ่ม ใช้การตรวจสอบไขว้ (cross-validation) และเตรียมชุดทดสอบใหม่สำหรับรอบถัดไป

กิจกรรมในชั้นเรียน

กิจกรรม: ออกแบบงาน ML สำหรับซ่อมบำรุง

  1. กำหนดปัญหาหนึ่ง เช่น ทำนายว่าแบตเตอรี่ควรปลดระวางหรือไม่ ระบุว่าเป็นงานจำแนกประเภทหรือพยากรณ์ค่า มีผู้สอนหรือไม่ และป้ายมาจากไหน
  2. อภิปรายว่าผลเสียของการพลาดของจริง (FN) กับการเตือนผิด (FP) ในงานนั้นต่างกันอย่างไร แล้วเลือกตัวชี้วัดหลัก
  3. ลองเปลี่ยนจุดตัดในโค้ดตัวอย่างเป็น 0.2 และ 0.5 บันทึก accuracy และ recall แล้วเลือกจุดตัดพร้อมเหตุผล
  4. อธิบายให้เพื่อนฟังว่าทำไมห้ามใช้ชุดทดสอบเลือกความลึกของต้นไม้

ข้อผิดพลาดที่พบบ่อย

ระวัง

  • รายงานความแม่นยำอย่างเดียว กับข้อมูลที่กลุ่มหนึ่งมีน้อย
  • ไม่มีค่าอ้างอิง จึงไม่รู้ว่าแบบจำลองดีกว่าการเดาแบบง่ายหรือไม่
  • เลือกแบบจำลองจากชุดฝึก ซึ่งให้รางวัลแก่การเรียนเกิน
  • ใช้ชุดทดสอบหลายครั้ง จนกลายเป็นชุดตรวจสอบอีกชุด
  • ใช้จุดตัด 0.5 เสมอ โดยไม่ดูผลเสียของความผิดพลาดแต่ละแบบ

สรุป

  • ML แบบมีผู้สอนเรียนจากตัวอย่างที่มีป้าย แบ่งเป็นงานจำแนกประเภทและพยากรณ์ค่า
  • ชุดฝึกใช้ปรับพารามิเตอร์ ชุดตรวจสอบใช้เลือกแบบจำลอง และชุดทดสอบใช้ประเมินครั้งเดียว
  • ต้องเทียบกับค่าอ้างอิงเสมอ และความแม่นยำหลอกได้เมื่อกลุ่มไม่สมดุล
  • ความซับซ้อนที่มากเกินทำให้เรียนเกิน เลือกความซับซ้อนจากผลบนชุดตรวจสอบ

แบบฝึกตรวจความเข้าใจ

  1. ทำนายเวลาบินที่เหลือเป็นนาทีเป็นงานชนิดใด
  2. ข้อมูล 1 000 เที่ยว มีมอเตอร์ผิดปกติ 50 เที่ยว แบบจำลองที่ตอบ “ปกติ” ทุกครั้งได้ความแม่นยำเท่าใด
  3. แบบจำลองได้ความแม่นยำ 1.00 บนชุดฝึก แต่ 0.80 บนชุดตรวจสอบ บอกอะไร
  4. มีมอเตอร์ผิดปกติจริง 20 ลำ แบบจำลองพบ 15 ลำ recall เท่าใด
  5. ทำไมจึงต้องใช้ stratify ตอนแบ่งข้อมูลที่กลุ่มหนึ่งมีน้อย
เฉลย
  1. พยากรณ์ค่า (regression) แบบมีผู้สอน
  2. ทั้งที่ไม่พบมอเตอร์ผิดปกติเลย
  3. แบบจำลองเรียนเกิน จำชุดฝึกได้แต่ใช้กับข้อมูลใหม่ได้ไม่ดี
  4. เพื่อให้สัดส่วนของกลุ่มที่มีน้อยใกล้เคียงกันทุกชุด ไม่เช่นนั้นบางชุดอาจแทบไม่มีตัวอย่างของกลุ่มนั้น

สรุปสูตรสำคัญ

ฟังก์ชันซิกมอยด์ของ logistic regression
ความแม่นยำ (accuracy)
recall

แหล่งอ้างอิงหลัก

  1. Géron, A. (2025). Hands-on machine learning with Scikit-Learn and PyTorch. O'Reilly. link
  2. Géron, A. (2022). Hands-on machine learning with Scikit-Learn, Keras, and TensorFlow (3rd ed.). O'Reilly.
  3. Goodfellow, I., Bengio, Y., & Courville, A. (2016). Deep learning. MIT Press. link
  4. scikit-learn developers. Metrics and scoring: Quantifying the quality of predictions (scikit-learn 1.9). link
  5. scikit-learn developers. Cross-validation: Evaluating estimator performance (scikit-learn 1.9). link
  6. Montgomery, D. C., & Runger, G. C. (2018). Applied statistics and probability for engineers (7th ed.). Wiley. link

อ่านเพิ่มเติม

ศึกษาหน่วยความรู้ที่กำหนดล่วงหน้า ดูสื่อประกอบ และทำ quiz ประจำโมดูล

ในชั้นเรียน / ภาคสนาม

บรรยาย อภิปรายกรณีศึกษา และแก้โจทย์ในชั้นเรียน

หลักฐานการเรียนรู้: ผล quiz และแบบฝึกหัดที่ส่ง

แบบทดสอบประจำโมดูล

แบบทดสอบนี้ใช้ตรวจความเข้าใจ (formative) ไม่ใช่การสอบเก็บคะแนน

โดเมนความรู้: ปัญญาประดิษฐ์และคอมพิวเตอร์วิทัศน์