แนวคิด AI ด้วย Python

ห่วงโซ่มาร์คอฟและการชั่งน้ำหนักระหว่างสำรวจกับใช้ประโยชน์ใน Python

AI มักต้องตัดสินใจภายใต้ความไม่แน่นอน ห่วงโซ่มาร์คอฟจำลองการที่ระบบเปลี่ยนไปมาระหว่างสถานะด้วยความน่าจะเป็นคงที่ ส่วน multi-armed bandit แสดงทางเลือกหลักของการเรียนรู้แบบเสริมกำลัง: ลองสิ่งใหม่ หรือใช้สิ่งที่ได้ผลดีที่สุดมาจนถึงตอนนี้

แนวคิดแบบเข้าใจง่าย

AI มักต้องตัดสินใจภายใต้ความไม่แน่นอน ห่วงโซ่มาร์คอฟจำลองการที่ระบบเปลี่ยนไปมาระหว่างสถานะด้วยความน่าจะเป็นคงที่ ส่วน multi-armed bandit แสดงทางเลือกหลักของการเรียนรู้แบบเสริมกำลัง: ลองสิ่งใหม่ หรือใช้สิ่งที่ได้ผลดีที่สุดมาจนถึงตอนนี้

ทำนายสถานะในอนาคตด้วยห่วงโซ่มาร์คอฟ และสร้างสมดุลระหว่างการสำรวจกับการใช้ประโยชน์ด้วย bandit แบบ epsilon-greedy

ประเด็นสำคัญ

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

ควรใช้เมื่อใด?

  • เข้าใจสิ่งที่เกิดขึ้นภายในโครงข่ายประสาทเทียมและไลบรารี AI
  • เข้าใจแนวคิดก่อนลงมือเขียนเองในโจทย์ที่เกี่ยวข้อง
  • เตรียมตัวสำหรับคอร์สแมชชีนเลิร์นนิง การสัมภาษณ์งาน และโปรเจกต์

ลองดูการทำงานจริง

เปลี่ยนความน่าจะเป็นในการเปลี่ยนสภาพอากาศเพื่อดูว่าห่วงโซ่จะนิ่งที่ใด กด เล่น เพื่อให้ bandit เรียนรู้ว่าเครื่องไหนให้รางวัลมากกว่า

โค้ดตัวอย่าง

รันโค้ด →
main.py
import random

# Markov chain: tomorrow's weather depends only on today's.
transitions = {"sunny": {"sunny": 0.8, "rainy": 0.2}, "rainy": {"sunny": 0.4, "rainy": 0.6}}
dist = {"sunny": 1.0, "rainy": 0.0}
for day in range(1, 4):
    dist = {s: sum(dist[p] * transitions[p][s] for p in dist) for s in dist}
    print(f"day {day}:", {s: round(v, 3) for s, v in dist.items()})

# Epsilon-greedy bandit: usually pick the best arm so far, sometimes explore.
random.seed(1)
true_payouts = [0.3, 0.7]
counts, totals = [0, 0], [0.0, 0.0]
epsilon = 0.1
for _ in range(500):
    if random.random() < epsilon or 0 in counts:
        arm = random.randrange(2)                                  # explore
    else:
        arm = max(range(2), key=lambda a: totals[a] / counts[a])  # exploit
    reward = 1 if random.random() < true_payouts[arm] else 0
    counts[arm] += 1
    totals[arm] += reward
print("pulls per arm:", counts)
print("estimated payouts:", [round(t / c, 2) for t, c in zip(totals, counts)])

ผลลัพธ์ที่คาดหวัง

day 1: {'sunny': 0.8, 'rainy': 0.2}
day 2: {'sunny': 0.72, 'rainy': 0.28}
day 3: {'sunny': 0.688, 'rainy': 0.312}
pulls per arm: [25, 475]
estimated payouts: [0.16, 0.7]

หลักการทำงาน

ในแต่ละวัน ความน่าจะเป็นใหม่คือความน่าจะเป็นเดิมคูณกับความน่าจะเป็นในการเปลี่ยนสถานะ โอกาสที่แดดออกจึงลดจาก 1.0 เหลือ 0.688 ในสามวัน ส่วน bandit จะสุ่มเลือกคันโยก 10% ของครั้ง และนอกนั้นดึงคันโยกที่มีค่าเฉลี่ยดีที่สุดจนถึงตอนนั้น ไม่นานมันก็ใช้การดึงส่วนใหญ่กับคันโยกที่ดีกว่า และประเมินรางวัลของคันนั้นได้ราว 0.7

เปลี่ยนค่าและรันโปรแกรมด้วย คอมไพเลอร์ Python ออนไลน์ของ CodeUtility โดยไม่ต้องติดตั้ง Python

แบบฝึกหัด

ลองเปลี่ยน input และทดสอบกรณีขอบก่อนใช้ชุดข้อมูลที่ใหญ่ขึ้น

  1. เปลี่ยนอินพุตหรือน้ำหนัก แล้วลองทายผลลัพธ์ก่อนรัน
  2. พิมพ์ค่าระหว่างทางออกมาเพื่อดูการคำนวณทีละขั้น
  3. แก้โจทย์ที่ลิงก์ไว้ด้านล่างเพื่อเขียนแนวคิดนี้ด้วยตัวเอง
รันใน Python IDE →

ฝึกด้วยโจทย์

ใช้สิ่งที่เรียนในบทนี้แก้ปัญหาจริง ทุกโจทย์รันในเบราว์เซอร์ พร้อมการทดสอบทันทีและรีวิวจาก AI

โจทย์ทั้งหมด