ห่วงโซ่มาร์คอฟและการชั่งน้ำหนักระหว่างสำรวจกับใช้ประโยชน์ใน Python
AI มักต้องตัดสินใจภายใต้ความไม่แน่นอน ห่วงโซ่มาร์คอฟจำลองการที่ระบบเปลี่ยนไปมาระหว่างสถานะด้วยความน่าจะเป็นคงที่ ส่วน multi-armed bandit แสดงทางเลือกหลักของการเรียนรู้แบบเสริมกำลัง: ลองสิ่งใหม่ หรือใช้สิ่งที่ได้ผลดีที่สุดมาจนถึงตอนนี้
แนวคิดแบบเข้าใจง่าย
AI มักต้องตัดสินใจภายใต้ความไม่แน่นอน ห่วงโซ่มาร์คอฟจำลองการที่ระบบเปลี่ยนไปมาระหว่างสถานะด้วยความน่าจะเป็นคงที่ ส่วน multi-armed bandit แสดงทางเลือกหลักของการเรียนรู้แบบเสริมกำลัง: ลองสิ่งใหม่ หรือใช้สิ่งที่ได้ผลดีที่สุดมาจนถึงตอนนี้
ทำนายสถานะในอนาคตด้วยห่วงโซ่มาร์คอฟ และสร้างสมดุลระหว่างการสำรวจกับการใช้ประโยชน์ด้วย bandit แบบ epsilon-greedy
ประเด็นสำคัญ
- ในห่วงโซ่มาร์คอฟ สถานะถัดไปขึ้นกับสถานะปัจจุบันเท่านั้น
- ความน่าจะเป็นในการเปลี่ยนออกจากสถานะหนึ่งรวมกันได้ 1 เสมอ
- การสำรวจช่วยหาตัวเลือกที่ดีกว่า การใช้ประโยชน์ช่วยเก็บรางวัลจากตัวเลือกที่ดีที่สุดที่รู้แล้ว
- epsilon ควบคุมสมดุล ยิ่ง epsilon มากยิ่งสำรวจมาก
ควรใช้เมื่อใด?
- เข้าใจสิ่งที่เกิดขึ้นภายในโครงข่ายประสาทเทียมและไลบรารี AI
- เข้าใจแนวคิดก่อนลงมือเขียนเองในโจทย์ที่เกี่ยวข้อง
- เตรียมตัวสำหรับคอร์สแมชชีนเลิร์นนิง การสัมภาษณ์งาน และโปรเจกต์
ลองดูการทำงานจริง
เปลี่ยนความน่าจะเป็นในการเปลี่ยนสภาพอากาศเพื่อดูว่าห่วงโซ่จะนิ่งที่ใด กด เล่น เพื่อให้ bandit เรียนรู้ว่าเครื่องไหนให้รางวัลมากกว่า
โค้ดตัวอย่าง
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 และทดสอบกรณีขอบก่อนใช้ชุดข้อมูลที่ใหญ่ขึ้น
- เปลี่ยนอินพุตหรือน้ำหนัก แล้วลองทายผลลัพธ์ก่อนรัน
- พิมพ์ค่าระหว่างทางออกมาเพื่อดูการคำนวณทีละขั้น
- แก้โจทย์ที่ลิงก์ไว้ด้านล่างเพื่อเขียนแนวคิดนี้ด้วยตัวเอง
ฝึกด้วยโจทย์
ใช้สิ่งที่เรียนในบทนี้แก้ปัญหาจริง ทุกโจทย์รันในเบราว์เซอร์ พร้อมการทดสอบทันทีและรีวิวจาก AI
- การแจกแจงสถานะของห่วงโซ่มาร์คอฟ ส่งการแจกแจงความน่าจะเป็นผ่านเมทริกซ์การเปลี่ยนสถานะของห่วงโซ่มาร์คอฟตามจำนวนก้าวที่กำหนด ง่าย
- Multi-armed bandit แบบ epsilon-greedy สร้างสมดุลระหว่างการสำรวจและการใช้ประโยชน์ใน multi-armed bandit ด้วยการเลือกการกระทำแบบ epsilon-greedy ง่าย