สอน Model ให้บวกเลขเป็นด้วย Reinforcement Learning จะทำได้ไหม? ทำได้รึป่าว?

知高x金知
9 min readNov 6, 2023

--

คำนำ

สวัสดีครับนี้เป็นบทความแรกของผมเลย เขียนถูกๆ ผิดๆ ยังไงก็หยวนๆ กันหน่อยนะครับ อาจจะเขียนมายาวและเวิ้นเว้อไปหน่อยแต่สัญญาว่า อ่านได้เพลินๆ ครับ (มั่งนะ?)

พอดีว่าผมได้มีโอกาส(หลง)ไปเข้าร่วมค่าย Brain Code Camp แล้วได้ลองเล่นกับโปรเจคที่ใช้ Reinforcement Learning (RL) มาครับ (ครั้งแรกเลย)ในบทความนี้ผมเลยจะมาเล่าและแบ่งปันความรู้ร่วมถึงสิ่งที่ได้จากโปรเจคนี้ครับ โดยโจทย์ที่ผมได้ลองทำมามีชื่อว่า…

“การประยุกต์การเรียนรู้แบบเสริมกำลังเพื่อทอนรูปนิพจน์พีชคณิตให้อยู่ในรูปอย่างง่าย”

ใครอ่านชื่อละงงมารวมกันตรงนี้ครับ (ผมด้วย คิดเองแท้ๆ 😅) อธิบายง่ายๆ โจทย์ก็คือเราจะให้คอมพิวเตอร์ใช้วิธีการเรียนรู้แบบเสริมกำลัง (ชื่อไทย of Reinforcement Learning) เพื่อที่จะให้มันลดรูปนิพจน์ทางคณิตศาสตร์ให้อยู่ในรูปที่สั้นที่สุดเป็นครับ อย่างเช่น สมมติว่าเรามีนิพจน์ (นิพจน์ไม่จำเป็นต้องมี ‘=’ นะครับ อันนั้นเรียก “สมการ”)

4x — 2x + 3–1

เราก็สามารถลดรูปให้มันสั้นลง โดยมีขั้นตอนดังนี้

4x-2x + 3–1

(4–2)x + (3–1)

2x + 2

ประมาณนี้แหละครับที่ผมอยากจะให้คอมพ์หรือ model มันทำได้ ก็ดูไม่ยากนะ แค่แยกตัวประกอบกับบวกๆ ลบๆ เลข ใช่ครับ ตอนแรกผมก็คิดแบบนั้น 😆

ที่มาและความอยากทำ (ไม่มีหรอกสำคัญ มีแต่อยากทำ)

*คำแนะนำ: สามารถข้ามหัวข้อนี้ไปได้เลยครับ ไม่ค่อยสำคัญเท่าไหร่ เหมือนชื่อหัวข้อและเหมือนกับที่เธอคิดกับเราอะ 😢

ก่อนอื่นก็ขอเล่าที่มาที่ไปที่ทำให้ผมได้มาทำโจทย์นี้นะครับ จุดเริ่มต้นมาจากความมุ่งที่จะลอง RL ให้ได้ คิดว่าใครหลายๆ คนที่เคยได้เรียน Machine Learning มา หลายคนน่าจะเคยได้ลอง Supervised Learning และ Unsupervised Learning กัน แต่กับ Reinforcement Learning เนี่ยไม่เคยได้ลองเลย และน่าจะสงสัยแบบเดียวกับผมว่ามันคืออะไรวะ?

แล้วจะทำโจทย์อะไรดีละ? ส่วนตัวผมอยากได้โจทย์ที่ทำให้ตัวเองรู้สึกว่าน่าสนใจ ทำแล้วรู้สึกสนุก แต่ก็ต้องไม่ยากเกินที่มือใหม่จะทำไม่ได้ อืม… หายากอยู่นะ มีอยู่วันนึ่งครับ พี่ TA ในกลุ่มผมเขาพูดขึ้นมาประมาณว่า “ปกติ RL เขาใช้ในปัญหาที่เป็น sequence ของการตัดสินใจ” ซึ่งประโยคนี้แหละคำที่มันติดอยู่ในหัวผมในตอนที่กำลังหาโจทย์ จนมีวันนึ่ง ระหว่างที่ผมกำลังนั่งดูยูทูปสอนแก้สมการแก้เซ็งอยู่ ผมก็นึกขึ้นมาได้ว่า “เวลาเราแก้โจทย์คณิตเนี่ย มันก็เหมือนเป็น sequence ของการตัดสินใจนี่หว่า” พอนึกได้แบบนั้นผมก็สงสัยขึ้นมาทันทีเลยว่า “มีใครทำยังวะ หาแป๊ป” ละก็ไปเจอ Mathy ซึ่งเป็น open source ที่มี code ของ Environment หลายๆ โจทย์สำหรับนำไปใช้ทำ RL เพื่อแก้โจทย์ปัญหาทางคณิตศาสตร์แบบต่างๆ (ใครที่งง ว่า Environment คือไรวะ? เดี๋ยวมีอธิบายในหัวข้อถัดไปให้นะครับ)

ด้วยความที่ผมเป็นคนที่ชอบคณิตศาสตร์เป็นทุนเดิมอยู่แล้ว (ไม่งั้นคงไม่ไปนั่งดูคริปแก้สมการแก้เซ็งหรอก) อีกทั้ง code ของ Mathy ยังอ่านค่อนข้างง่ายมี docstring ให้ค่อนข้างละเอียด น่าจะเอาไปทำตามไม่ยาก แบบนี้ก็เสร็จโจรสิครับ เอา Mathy นี่แหละมาเป็น base ของโจทย์ที่จะทำละกัน โจทย์ที่เป้าหมายในช่วงแรกๆ ผมตั้งใจว่าอยากจะทำให้ตัว model มันสามารถแก้สมการตัวแปรเดียวได้ โดยเริ่มจากสอนให้มันรู้จักการลดรูปนิพจน์ให้ได้ก่อนครับ แต่เหมือนผมอาจจะมองด้วยมุมมองของมนุษย์ที่ผ่านการศึกษาขั้นพื้นฐานมาแล้วเกินไป เลยทำให้คิดว่า “แค่การสอนให้ model มันลดรูปนิพจน์เป็นเนี่ย ไม่น่ายากนะ” ด้วยระยะเวลาที่ทางค่ายให้มาน่าจะพอทำให้มันแก้สมการง่ายๆ เป็นได้ และใช่ครับ ผมคิดผิด ยากกว่าที่คิดเยอะเลยครับ ในท้ายที่สุดโจทย์เลยเหลือแค่ทำให้มันลดรูปนิพจน์ง่ายๆ ให้เป็นก็พอครับ 😅

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

เรื่องที่ควรรู้(และอยากให้รู้)ก่อนไปต่อ

ในหัวข้อนี้ผมจะขอปูพื้นสิ่งที่ควรรู้และสิ่งที่ผมอยากให้รู้ ก่อนที่จะไปในหัวข้อถัดๆ ไปนะครับ เริ่มจาก…

Reinforcement Learning คืออะไรหว่า? เคยได้ยินแต่ชื่อ ไม่เคยเห็นตัว

ภาพแสดง basic concept ของ Reinforcement Learning

Reinforcement Learning เป็นวิธีการในการสร้าง model แบบหนึ่งด้วยการให้มันได้ลองผิดลองถูกไปเรื่อยๆ แล้วก็ให้รางวัลกับมันหากมันตามเงื่อนไขที่กำหนดไว้ คล้ายๆ กับเวลาเราฝึกสัตว์นั่นแหละครับ เป้าหมายของตัว model ก็คือ การทำให้ได้รับรางวัลสะสมในตอนจบให้มากที่สุดครับ

  • เราจะเรียกสิ่งที่เราต้องการจะให้มันเป็นตัวแทนของสิ่งที่เราจะฝึกว่า Agent ครับ
  • Agent จะเรียนรู้โดยการลองตอบโต้กับสภาพแวดล้อมหรือ Environment ตามสถานะหรือ State ที่มันได้รับมาครับ
  • การตอบโต้หรือสิ่งที่ Agent ทำเราจะเรียกว่า Action ครับ
  • Agent จะใช้ Policy เป็นสิ่งที่ประเมินว่าควรจะทำ Action แบบใด
  • Environment ก็จะมอบรางวัลหรือ Reward ให้ตามเงื่อนไขที่กำหนดไว้พร้อมทั้งส่ง State ถัดไปให้กับ Agent ครับ

ในระหว่างการเรียนรู้ Agent ก็จะลองผิดลองถูกไปเรื่อยๆ โดยที่ Policy ก็จะถูกปรับไปด้วยครับ ซึ่ง Agent ก็จะลองผิดๆ ถูกๆ เป็นร้อย เป็นพัน เป็นหมื่นหรืออาจจะเป็นแสนครั้งเลยครับกว่าที่มันจะเริ่มเข้าที่

อ่านเท่านี้อาจจะยังนึกภาพไม่ออก ดังนั้นผมจะขอยกตัวอย่างโดยเปรียบเทียบกับโจทย์ที่จะทำนะครับ

  • สมมติให้ Agent คือนักเรียนครับ
  • Environment คือคาบวิชาคณิตศาตร์ระดับประถมปลายที่กำลังเรียนบทการทอนรูปนิพจน์แล้วกันนะครับ (ให้ถือว่าครูเป็นส่วนนึ่งของ Environment นะครับ)
  • ส่วน Action ที่ Agent ทำได้ก็เช่น การแยกตัวประกอบ การบวกเลข การสลับที่หรือการสลับกลุ่มการบวก อะไรประมาณนี้ครับ

โดยที่ในคาบนั้นหรือ Environment ก็จะมอบโจทย์หรือนิพจน์ข้อหนึ่งมาให้ Agent ลองแก้ เช่น

“x + 2x + 3” ตัวโจทย์หรือนิพจน์ข้อนี้ก็คือ State เริ่มต้น

ให้เรามองว่า Agent รู้อยู่แล้วว่ามี Action อะไรบ้าง

  • หน้าที่ของ Agent ก็คือการตัดสินใจครับว่าจะทำ Action ไหน
  • ซึ่งวิธีที่ Agent ใช้ตัดสินใจเลือกว่าจะทำอะไรก็คือ Policy ครับ

แล้วสมมติว่า Agent เลือกที่จะ “แยกตัวประกอบของ x + 2x”

  • มาถึงตรงนี้ Environment ก็จะประเมินครับว่าควรจะได้คะแนนหรือ Reward เท่าไหร่สำหรับ Action นี้
  • ในขณะขณะเดียวกัน State ถัดไป (S₁) ก็จะเกิดขึ้นให้ Agent คิดต่อครับว่าจะทำ Action อะไรต่อครับ

ทั้งหมดนี้ก็เป็นความหมายและ concept ของ RL ในแบบที่ผมเข้าใจ พร้อมตัวอย่างเปรียบเทียบกับโจทย์ที่จะทำครับ

Agent มันเป็นคอมพ์นิแล้วมันจะเข้าใจนิพจน์ได้ยังไงนะ? 🤔

ไม่แน่ใจว่าคุณผู้อ่านจะสงสัยเหมือนชื่อหัวข้อรึป่าว แต่ในหัวข้อนี้ผมอยากมาอธิบายว่าในมุมมองของ Agent หรือนักเรียนของเราเนี่ย เขาเห็น “นิพจน์” เป็นแบบไหนกันครับ

สำหรับมนุษย์โตแล้วอย่างพวกเราคงจะเข้าใจนิพจน์ที่อยู่ในรูปของ text ได้ง่ายๆ ใช่ไหมละครับ เช่น “2x + 4*2–3” เราดูก็รู้ว่าส่วนไหนคือตัวแปร ตัวไหนคือค่าคงที่ ต้องคูณก่อน ต้องคิดจากซ้ายไปขวา ใช่ไหมละครับ แต่การทำให้คอมพ์มันเข้าใจ text ได้แบบเราเนี่ยไม่ง่ายเลย (มันทำได้นะครับแค่ไม่ง่ายเฉยๆ) ดังนั้นเราจึงต้องแปลงนิพจน์ที่อยู่เป็น text format เนี่ยให้กลายเป็น format ที่ช่วยให้คอมพ์มันเข้าใจได้ง่ายขึ้นครับ

วิธีที่พื้นฐานที่สุดอย่างนึ่งก็คือการแบ่งมันเป็น binary tree ครับ ซึ่งแต่ละ node ก็จะแทนองค์ประกอบย่อยในนิพจน์นั้นครับ เช่น `+` (ตัวปฏิบัตการบวก), `-` (ตัวปฏิบัตการลบ), `2` (ค่าคงที่), หรือ `x` (ตัวแปร) เป็นต้นครับ ส่วนเส้นหรือ edge ก็จะเชื่อมกับ node ที่เกี่ยวข้องกันครับ เช่น นิพจน์ “5x — 3x+9–1” พอแปลงเป็น binary tree แล้วก็จะเป็นดังรูปนี้เลยครับ

ภาพนิพจน์ “5x-3x+9–1” เมื่อถูกแปลงเป็น binary tree

สังเกตว่าพจน์ที่ต้องคำนวนก่อนก็จะอยู่ซ้ายกว่าและลึกกว่า พออยู่ใน format นี้ก็จะช่วยให้คอมพ์รู้ได้ครับว่าต้องคำนวนอะไรก่อนหลังง่ายขึ้นครับ ในส่วนของรายละเอียดการ Implement ต่างๆ ไปอ่านเองใน source code ของ Mathy นะครับ (อยู่ใน package ที่ชื่อว่า mathy_core) และเวลาเราจะแปลงมันเป็น input สำหรับ agent เราก็มักจะแปลงเป็น array หรือ list ครับ order ของสมาชิกก็แล้วแต่ design เลยครับ แต่สำหรับ Mathy เขาจะแปลงเป็น list ที่สมาชิกเรียงตามลำดับการ visit แบบ Depth First Search ครับ เช่น ถ้าเราแปลง tree ในภาพตัวอย่างก็จะได้ list ดังนี้ครับ

['-', '+', '-', '*', '5', 'x', '*', '-3', 'x', '+', '9', '1']

(ใน code จริงสมาชิกของ list ที่ได้จะเป็น object นะครับ แต่ในตัวอย่างแสดงเป็น text เพื่อให้ผู้อ่านเข้าใจง่าย)

แต่ยังไม่แค่นี้จบครับ (เยอะจังวะ 😫) โดยปกติแล้วเราคงไม่ส่ง list ของ text หรือ object ไปเป็น input สำหรับ model แต่มักจะเป็น list ของตัวเลขใช่ไหมละครับ จากนี้ผมของเรียกไอ้ list ที่จะใช้เป็น input นี้ว่า feature นะครับ สำหรับโปรเจคนี้ feature ที่เราจะใช้มี 2 feature ด้วยกัน คือ nodes และ values ครับ

  • nodes — คือ list ที่มีสมาชิกเป็นจำนวนเต็มที่ id ของประเภท node นั้นๆ ครับ เช่น root node ในตัวอย่างก่อนหน้านี้เป็น “ตัวปฏิบัติการลบ” ก็แทนด้วย “4” เป็นต้น
  • values — คือ list ที่มีสมาชิกเป็นค่าของค่าคงที่หาก node นั้นเป็นประเภท “ค่าคงที่” ครับ หากเป็น node ประเภทอื่นก็จะแทนด้วย “0” เช่น สมาชิกตัวที่ 5 ของตัวอย่างเป็น “ค่าคงที่” สมาชิกตัวที่ 5 ของ feature นี้ก็จะมีค่าเท่ากับ 5 เป็นต้น

*เพิ่มเติม: ในโปรเจคนี้ feature ทั้ง 2 ตัวจะถูก normalize ให้มีค่าเป็นจำนวนจริงในช่วง 0 ถึง 1 นะครับ (ส่วนเหตุผลก็ default ของ Mathy เขาให้มาแบบนี้ครับ ยังไม่มีไอเดียว่าจะแก้เป็นแบบไหนเลยใช้ๆ ไปก่อนครับ 😅)

โจทย์หน้าตาเป็นยังไงนะ? ใส่โม่ง ถือปืนรึป่าวนะ? (อันนั้นโจร 😑)

ก่อนจะไปหัวข้อถัดๆ ไป ในหัวข้อนี้ผมข้อพูดถึงการกำหนดโจทย์ หรือมองว่าเป็นขอบเขตของโปรเจคก็ได้ครับเพื่อไม่ให้ฟุ้งไปไกล (ไม่ให้ยากเกินไปด้วย ปวดหัว 😵) ซึ่งตัวโจทย์ที่ Agent จะได้รับก็จะอยู่ภายใต้เงื่อนไขต่อไปนี้ครับ

  • จำนวนของ Node ต้องไม่เกิน 12 node เช่น “2x + 2x + 2x + 2x” มี 15 node เยอะไป ❌ NO! ❌
  • ต้องไม่มีการยกกำลัง เช่น “x²” หรือ “2¹” มีการยกกำลัง ไม่ได้ ❌ NO! ❌
  • ต้องไม่มีวงเล็บ เช่น “1 + (2 + x)” มีวงเล็บ ห้าม ❌ NO! ❌
  • ต้องไม่มีการติดลบซ้อน เช่น “--1” ติดลบซ้อนกัน ไม่เอา ❌ NO! ❌
  • ต้องไม่ใช้ “ตัวปฏิบัติการคูณ” และ “ตัวปฏิบัติการหาร” เช่น “1*2” หรือ “1/x” ยุ่งยาก ❌ NO! ❌
  • ยกเว้นกรณีเป็นการคูณกันระหว่างค่าคงที่กับตัวแปร เช่น “2x” ได้ ✅ YES! ✅
  • ต้องเป็นนิพจน์ตัวแปรเดียวหรือไม่มีเลย คือจะมี “x” กี่ตัวก็ได้แต่ต้องมีแค่ “x” (ห้ามนอกใจไปมี “y” หรือ “z” … ไม่ใช่ละ) เช่น “x + y” ไม่ได้ ❌ NO! ❌
  • ค่าคงที่ในนิพจน์จะต้องมีค่าอยู่ในช่วงตั้งแต่ -10 ถึง 10 ไม่ centralized อะไรวะ “ไม่ centralized” ไม่รวมศูนย์ (0) ไง… ไม่ตลก ❌ NO! ❌

โดยเงื่อนไขเหล่านี้เกิดมาจากระหว่างการทดลองครับที่ผมค่อยๆ ลดความยากและตีขอบเขตให้เล็กลง เพื่อให้มันง่ายขึ้น (เพราะขนาดแค่ใน scope เท่านี้ยังทำให้ agent มันเก่งเท่าเด็กประถมไม่ได้เลย)

และเงื่อนไขเหล่านี้จะใช้เฉพาะตอนกำหนดโจทย์ให้มันนะครับ ถ้าระหว่างการแก้โจทย์นิพจน์ใหม่ที่เกิดมาไม่ได้เป็นตามเงื่อนไขพวกนี้ก็ไม่เป็นไรครับ เช่น “x + 10 + 1” แล้ว state ถัดไปเป็น “x + 11” ก็ถือว่าโอเคครับ

น้อง Agent ทำอะไรเป็นบ้าง? Action ได้แล้ว Actingได้รึป่าว?

จากตัวอย่างก่อนหน้านี้ผู้อ่านบางคนคงจะพอนึกภาพของ Action หรือความสามารถพื้นฐานที่ Agent สามารถทำได้แล้ว ดังนั้นหัวข้อนี้ผมของข้ามนะครับ…

หยอกๆ ครับ หยอกเล่นเฉยๆ กลัวอ่านยาวแล้วจะเบื่อ อย่าโกรธนะ 😘

สำหรับ Action ประกอบด้วยสองอย่างที่ Agent ต้องตัดสินใจครับ คือ

  • Rule — Agent ต้องเลือกกฎหรือการกระทำบางอย่างที่ต้องอยู่ภายใต้เงื่อนไขบางอย่าง
  • Applied Node — Agent ต้องเลือกหนึ่ง node ที่จะ apply กับ rule ที่เลือก

ถ้ายังงงอยู่เดี๋ยวจะมีอธิบายพร้อมตัวอย่างในตอนที่อธิบายว่ามี rule อะไรบ้างนะครับ โดย rule ที่เราจะใช้มี 6 ข้อ ดังนี้ครับ

  • Constants Simplify— คือ การบวกคงที่ครับ สำหรับกฎข้อนี้จะ apply ได้กับ node ที่เป็น “ตัวปฏิบัติการบวก” เท่านั้นครับ ตัวอย่างการ apply เช่น
ภาพตัวอย่างการ apply “Constants Simplify” กับ node “ตัวปฏิบัติการบวก”
  • Restate Subtraction — คือ การเปลี่ยนลบเป็นบวกลบครับ (รวมถึงการแปลงบวกลบกลับเป็นลบด้วยเช่นกัน) จากกฎข้อก่อนที่ผมบอกว่า “apply ได้กับ node ที่เป็น “ตัวปฏิบัติการบวก” เท่านั้น” ผู้อ่านอาจจะสงสัยว่าแล้วถ้าเป็นลบละ ซึ่งกฎข้อนี้แหละครับที่จะมาแก้ปัญหาที่จุดนั้น ดังนั้นกฎข้อนี้จึงจะ apply ได้เฉพาะกับ “ตัวปฏิบัติการลบ” และ “ตัวปฏิบัติการบวก” ที่ right child node เป็น “ค่าคงที่” ที่ติดลบ เท่านั้นครับ ตัวอย่างการ apply เช่น
ภาพตัวอย่างการ apply “Constants Simplify” กับ node “ตัวปฏิบัติการบวก”
  • Distributive Factor-Out — คือ การแยกตัวประกอบจากตัวแปรครับ สำหรับกฎข้อนี้จะ apply ได้กับ node ที่เป็น “ตัวปฏิบัติการบวก” และ “ตัวปฏิบัติการลบ” ครับ ตัวอย่างการ apply เช่น
ภาพตัวอย่างการ apply “Distributive Factor-Out” กับ node “ตัวปฏิบัติการบวก”
  • Associative Swap — คือ การสลับกลุ่มการบวก เช่นเดียวกับ “Constants Simplify” ครับ กฎข้อนี้ก็ apply ได้กับ node ที่เป็น “ตัวปฏิบัติการบวก” เท่านั้นครับ ตัวอย่างการ apply เช่น
ภาพตัวอย่างการ apply “Associative Swap” กับ node “ตัวปฏิบัติการบวก”
  • Commutative Swap — คือ การสลับที่การบวก เช่นเดียวกับ “Constants Simplify” ครับ กฎข้อนี้ก็ apply ได้กับ node ที่เป็น “ตัวปฏิบัติการบวก” เท่านั้นครับ ตัวอย่างการ apply เช่น
ภาพตัวอย่างการ apply “Commutative Swap” กับ node “ตัวปฏิบัติการบวก”
  • Distributive Multiply — คือ การคูณเข้า สำหรับกฎข้อนี้เปรียมเหมือนเป็น inverse rule ของ “Distributive Factor-out” ครับ ดังนั้นการ apply จึงทำได้กับ node ที่เป็น “ตัวปฏิบัติการคูณ” เท่านั้นครับ ตัวอย่างการ apply เช่น
ภาพตัวอย่างการ apply “Distributive Multiply” กับ node “ตัวปฏิบัติการคูณ”

จากตัวอย่างที่ยกมาผมคิดว่าทุกคนน่าจะพอเห็นภาพของ Rule และ Applied Node มากขึ้นนะครับ แน่นอนครับว่า Agent ก็สามารถเลือก apply rule กับ node ที่ไม่สอดคล้องกับเงื่อนไขการ apply ได้ครับ ในกรณีนั้นเราจะเรียกว่าเป็น Invalid Move ครับ ดังนั้นสำหรับนิพจน์ที่มี 12 node และมี Rule ที่ใช้ได้อยู่ทั้งหมด 6 ข้อ จะได้ Action Space หรือเซตของ Action ที่เป็นไปได้ทั้งหมดขนาด 12×6 นั่นเองครับ

*เพิ่มเติม: คำอธิบายและตัวอย่างที่ยกมานั้นเป็นคำอธิบายที่ถูกสรุปและตัดทอนเนื้อหามาให้สอดคล้องกับขอบเขตในการกำหนดโจทย์แล้ว (เดี๋ยวจะยาว) ความจริงเงื่อนไขการ apply ของกฎบางข้อมีรายละเอียดที่เยอะและซับซ้อนกว่านี้มาก แนะนำให้ลองไปอ่านเองใน code ดูนะครับ (ถามอยากรู้)

คลาสหรือคุก Environment แบบใดทำไมโหดร้ายแบบนี้

ในคลาสเรียนที่ครูไม่บอกว่าอะไรคือถูก แบบไหนคือผิด ไม่แม้แต่จะแสดงตัวอย่างหรือทำให้ดู บอกเพียงว่าทำอะไรได้บ้าง ทำแล้วได้อะไร นักเรียนต้องลองทำมั่วๆ เอง ถ้าเลือกดีก็ให้ขนม 😋 แต่ถ้าเลือกไม่ดีต้องโดนเฆียน 😱 ต่อให้ทำเสร็จก็ยังไม่ได้กลับบ้าน ต้องทำต่อไปเรื่อยๆ คลาสเรียนแบบใดกัน ทำไมจึงโหดร้ายได้ขนาดนี้ ในหัวข้อนี้เราจะสำรวจ Environment ที่เปรียบเหมือนนรกนี้กันครับ

เกริ่นซะน่ากลัว แต่มันก็คล้ายๆ แบบนั้นแหละครับ 😅

ขอเริ่มจากรางวัล (Reward) และการลงโทษ (Penalty) นะครับ โดยใน Environment นี้เราจะแบ่งการให้รางวัลและการลงโทษออกเป็น 8 แบบได้แก่

  • 🥳 Win— เมื่อ Agent สามารถทำให้นิพจน์อยู่ในรูปอย่างง่าย เราจะถือว่า Agent ชนะครับ แล้วจะให้ รางวัล (+Reward) สำหรับชัยชนะครับ ถึงจุดนี้เราจะถือว่าจบรอบหรือจบ Episode ครับ (ลำดับของพจน์จะเรียงแบบไหนก็ได้ครับ เช่น “x + 1” หรือ “1 + x” จะแบบไหนก็ได้ครับถือว่าชนะทั้งคู่)
  • 😎 Bonus — เมื่อ Agent สามารถชนะโดยใช้จำนวน Action หรือ Step ไม่เกินครึ่งหนึ่งของจำนวน Step สูงสุดหรือ Max Step ที่กำหนดไว้ได้ Agent จะได้รับรางวัลพร้อมโบนัส(+Reward+Bonus)ครับ
  • 😭 Lose — เมื่อ Agent ใช้จำนวน Step ไปจนหมดหรือก็คือมากกว่า Max Step หรือเมื่อ Agent ทำ Action ซ้ำๆ ที่ทำให้เกิด State เดิมซ้ำไปมาเกิน 3 ครั้ง ทั้งสองกรณีจะถือว่า Agent แพ้ครับ เราจะลงโทษ (-Reward) น้องเขาครับ ถึงจุดนี้เราจะถือว่าจบรอบหรือจบ Episode ครับ
  • 🙄 Repeat Move — เมื่อ Agent ทำ Action ใดๆ แล้วทำให้เกิด State ที่เคยเกิดขึ้นมาแล้วใน Episode นั้น เราจะถือว่านั้นเป็นการทำ Action ซ้ำครับ Agent จะถูกลงโทษ (-Reward) ครับ
  • 😱 Invalid Move — เมื่อ Agent เลือก Rule และ Node ที่ไม่สามารถ apply กับ Rule ที่เลือกได้ จะถือว่าเป็นการทำผิดกฏ Agent จะถูกลงโทษ (-Reward) ครับ
  • 😄 Helpful Move — เมื่อ Agent เลือก Rule ที่เป็นประโยชน์หรือช่วยให้เข้าใกล้ชัยชนะมากขึ้น ก็จะได้รับรางวัล (+Reward) สำหรับ Move นั้นครับ (แล้วต้องไม่เป็น Invalid Move ด้วยนะครับ) โดย Rule ที่ถือว่าเป็น ประโยชน์ ได้แก่
    Constants Simplify — ช่วยให้จำนวน Node ใน tree ลดลง
    Distributive Factor-Out — ช่วยให้จำนวน Node ใน tree ลดลง
    Restate Subtraction — ช่วยให้เปลี่ยน “-” ให้เป็น “+ -” ทำให้สามารถทำ “Constants Simplify” ได้
    Associative Swap — ช่วยย้าย “ค่าคงที่” มาอยู่ด้วยกัน ทำให้สามารถทำ “Constants Simplify” ได้ง่ายขึ้น
  • 😐️ Timestep Decay — เมื่อ Agent เลือก Rule ที่ไม่ส่งผลดีหรือผลเสียกับการแก้โจทย์ Agent จะถูกลงโทษ (-Reward) เนื่องจากการใช้ step ที่ไม่เกิดประโยชน โดย Rule ที่ถือว่าทำแล้วไม่สร้างประโยชน์นี้มีแค่ข้อเดียว คือ
    Commutative Swap — การสลับที่ซ้ายขวาไม่ได้ช่วยให้จำนวน Node ลดลง อีกทั้งยังไม่ได้ช่วยให้ สามารถทำ “Constants Simplify” ได้
  • 😩 Unhelpful Move — เมื่อ Agent เลือก Rule ที่ส่งผลเสียหรือทำให้ชัยชนะห่างออกไปไกลขึ้น ก็จะถูกลงโทษ (-Reward) สำหรับ Move นั้นครับ โดย Rule ที่สร้างผลเสียนี้มีแค่ข้อเดียวเช่นกัน คือ
    Distributive Multiply — เนื่องจากทำให้จำนวน Node เพิ่มขึ้น

ทั้งหมดนี้ก็เป็นการให้รางวัลและการลงโทษทั้ง 8 แบบสำหรับ Environment นี้ครับ และการให้รางวัลและการลงโทษจะเป็นตามรายการนี้เลยครับ

  • 🥳 Win = +1
  • 😎 Bonus = +1+2×(1/จำนวน step ที่ใช้) โดยจะมีค่ามากที่สุดได้ไม่เกิน 2
  • 😭 Lose = -1
  • 🙄 Repeat Move = -0.1 × จำนวนครั้งที่ทำ state นั้นซ้ำ
  • 😱 Invalid Move = -0.5
  • 😄 Helpful Move = +0.1
  • 😐️ Timestep Decay = -0.01
  • 😩 Unhelpful Move = -0.01

โดยในการเรียนรู้ของ Agent เราก็จะให้โจทย์กับ Agent ไปหนึ่งข้อครับ คือ

5x - -3x + 9 - 1

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

จากการสังเกตผลการทดลองเหล่านั้น โจทย์ข้อนี้เป็นโจทย์ที่ Agent แก้ไม่ค่อยได้ครับ และยังเป็นโจทย์ที่พอให้ Agent เรียนรู้แล้วมันสามารถแก้โจทย์ข้อที่ง่ายกว่าได้หลายข้อครับด้วย แต่ผลการทดลองพวกนั้นจะไม่ขอเล่าในบทความนี้นะครับ เดี๋ยวยาว (ขี้เกียดเล่าแหละ) แต่แค่อยากบอกให้รับรู้ไว้ก่อนครับ

ในหัวข้อถัดไปเราจะไปรู้จักกับวิธีการที่น้อง Agent ใช้เรียนรู้เพื่อปรับปรุง policy กันนะครับ

ทำ Policy ยังไงให้ที่ทำได้จริง ไม่ตระบัดสัตย์ แต่จะ work ไหมนะ?

สำหรับวิธีการเรียนรู้ที่ผมเลือกใช้มีชื่อเรียกว่า Deep Q-Learning (DQN) ครับ คิดว่าหลายๆ คนน่าจะเคยได้ยินชื่อมันผ่านๆ มาบ้างนะครับ เพราะมันเป็นวิธีพื้นฐานแรกๆ ที่ใครศึกษาเกี่ยวกับ RL ก็น่าเคยได้รู้มาบ้าง ส่วนใครที่ไม่คุ้น ไม่รู้จักว่ามันคืออะไร

ไม่ครับผมไม่เล่าในบทความนี้ 😃 แต่ผมอยากแนะนำให้ลองไปอ่านเองดูครับมันไม่ยากมาก เข้าใจง่ายกว่าที่คิด ลิงค์ด้านล่างนี้เป็นบทความที่ผมใช้อ้างอิงตอน Implement DQN ครับ คิดว่าเขาน่าจะอธิบายได้ดีกว่าผมเยอะเลย ลองไปอ่านดูนะครับ

และเพราะความง่ายที่จะทำความเข้าใจ + Implement ตามไม่ยาก นี้เลยเป็นสาเหตุหลักครับที่ทำให้ผมเลือกใช้วิธีการนี้ครับ (ก็บอกแล้วว่าพึ่งเคยทำ RL มือใหม่ก็ต้องเริ่มจากง่าย ๆ ดิ) ดังนั้นประเด็นในเรื่องของความเหมาะกับโจทย์ไหมก็เป็นเรื่องรองไปครับ แฮะๆ

หลังจากนี้ผมจะถือว่าพวกคุณเข้าใจ DQN แล้วนะครับ

ถ้าคุณรู้จัก DQN แล้วก็น่าจะรู้ว่าสิ่งที่เป็น Policy ของมันก็คือ Deep Neural Network (DNN) นั่นเอง โดยมันจะใช้ DNN เพื่อประมาณรางวัลสะสมที่จะได้เมื่อ Agent ทำแต่ละ Action กับ State ปัจจุบัน โดย Agent จะเลือกทำ Action ที่ DNN มันประมาณมาว่าจะได้รางวัลสะสมมากที่สุด (Cumurative Reward) ครับ

ดังนั้นผมจะมาเล่าว่าจะประยุกต์ DQN เข้ากับโจทย์ของเรายังไงกันครับ อย่างแรกเลยก็คือ Input สำหรับ Policy model ครับ จากหัวข้อก่อนๆ ผมได้บอกไปแล้วครับว่าเราจะใช้ feature 2 ตัว คือ node และ value ครับ

ดังนั้น Input ของ Policy model ก็จะเป็น Matrix ขนาด 2×12 ครับ (สำหรับนิพจน์ที่มีจำนวน node ไม่ถึง 12 node ผมจะทำ zero padding ไปเพื่อให้สมาชิกครบ 12 ตัวครับ)

ส่วน Output ของ Policy model ก็ต้องสามารถ represent Action Space ได้ใช่ไหมละครับ เพราะมันต้องประมาณ Cumulative Reward สำหรับทุกๆ Action ใน Action Space

ในโปรเจคนี้ผม represent Action Space ด้วย Matrix ขนาด 12×6 ครับ สมาชิกตัวใน row ที่ i และ column ที่ j ของ Action Space Matrix จึงแทน Cumulative Reward ของ node ตัวที่ i เมื่อ apply ด้วย rule ข้อที่ j ครับ ที่นี้ถ้าเราหา argmax ของ Action Space Matrix ก็จะได้ Action ที่ Agent จะทำแล้วครับ

โดยภาพต่อไปนี้จะแสดง architecture สำหรับ policy model ที่ทำผลลัพธ์ได้ดีที่สุดในการทดลองนะครับ โดยมันจะเป็น Recurrent Neural Network (RNN) ผสมกันกับ Convolutional Neural Network (CNN) ที่มีจำนวนพารามิเตอร์ประมาณ 3.5 ล้านพารามิเตอร์ครับ

ภาพแสดง architecture ของ policy model ที่ทำผลลัทธ์ได้ดีที่สุดในการทดลอง

สำหรับ policy model ที่ใช้ในการทดลองอื่นๆ ขอไม่ยกมานะครับ เหตุผลเดิมครับ “เดี๋ยวยาว”

เนื่องจากผมมองว่า นิพจน์ มันมีลักษณะที่เป็น sequence ที่ไม่ยาวมาก ก็เลยเลือกใช้ RNN มาเป็น Encoder เพื่อแปลง Input เป็น Action Space Matrix

และเพื่อไม่ให้ Agent มันทำ Repeat Move ดังนั้นมันก็ต้องรู้ว่า state ก่อนๆ เป็นแบบไหนใช่ไหมละครับ ผมก็เลยนำ Action Space Matrix ของ state ก่อนหน้ามาคิดด้วย

อีกทั้งผมมองว่าตำแหน่งใน Action Space Matrix มันมีความหมายหรือก็คือมันมี spatial information เห็นแบบนี้ผมก็เลยนึกถึง CNN เลยครับ สุดท้ายเลยออกมาเป็น architecture ดังที่เห็นเลยครับ

ส่วนตัวผมไม่ได้เป็นคนที่เชี่ยวชาญในการออกแบบ architecture สำหรับ DNN ก็เลยออกแบบมั่วๆ ด้วยแนวคิดแบบง่ายๆ แบบนี้แหละครับ 😅

Are U Winning, Son?

โอเคมาถึงผลลัพธ์แล้วครับ ในบทนี้เราจะมาดูผลลัพธ์ของน้อง Agent ที่ใช้ไอ้ architecture แบบข้างบนกันครับ (ไหนดูซิที่ว่าผลดีสุดหน่ะ จะดีได้แค่ไหนเชียว) และเช่นเดิมครับไม่พูดถึงผลลัพธ์อื่น ๆ นะครับ

สำหรับ parameter ต่าง ๆ ที่ใช้ในให้ Agent ตัวนี้เรียนรู้จะเป็นดังนี้

  • Max Moves = 24 moves
  • Reward Discount = 0.99
  • Max Seq Lenght หรือ Max Nodes = 12
  • Max Timestep = 4
  • Initial Epsilon = 1.
  • Epsilon Decay = 1-1e-4
  • Replay Memory Size = 450
  • Batchsize = 64
  • Max Episode = 300
  • Update Target Model Period = 12

ก่อนไปดูผล ผมขอพูดถึงตัวชี้วัดที่จะใช้คร่าวๆ นะครับ โดยสิ่งที่เราจะพิจารณาว่า Agent มันเก่งหรือป่าวมีดังนี้ครับ

  • Agent สามารถแก้โจทย์ที่ให้เรียนรู้ได้หรือไม่ และมีขั้นตอนอย่างไร (ไอ้ข้อข้างบนนั้นแหละครับ)
  • Agent ใช้กี่ step ในการแก้โจทย์ที่ให้เรียนรู้ และได้รางวัลสะสมเท่าไหร่
  • Agent สามารถแก้โจทย์ที่ไม่เคยได้เรียนรู้ได้กี่ข้อ (โจทย์พวกนี้จะเรียกว่า validation problems นะครับ เป็นนิพจน์ที่สุ่มขึ้นทั้งหมด 30 ข้อครับ)
  • Agent มีรางวัลสะสมเฉลี่ยจากการแก้ validation problems เท่าไหร่

โดยผลที่ได้จะเป็นตามนี้ครับ

สำหรับ โจทย์ที่ให้เรียนรู้ Agent แก้ออกมาได้โดยมีขั้นตอนดังนี้ครับ

5x - -3x + 9–1 , Initial State

5x + 3x + 9–1 , Restate Subtraction

5x + 3x + 9 + -1 , Restate Subtraction

5x + 3x + (9 + -1), Associative Group

5x + 3x + 8 , Constant Simplify

(5 + 3) * x + 8 , Distributive Factoring

8x + 8 , Constant Simplify

โดยใช้ไปทั้งสิ้น 6 moves ได้รางวัลสะสม = 1.83 ครับ จากผลที่ได้ผมค่อนข้างโอเคเลย ใช้ moves ไม่เยอะ ไม่มี Repeat Move หรือ Action ที่สิ้นเปลือง สำหรับตัวชี้วัด 2 ข้อแรกถือว่าผ่านครับ

ส่วนผลลัพธ์เมื่อลองทำโจทย์ที่ไม่เคยเรียน พบว่าสามารถแก้ได้ไป 22 จาก 30 ข้อครับ ถ้าเป็นการสอบก็ถือว่าผ่านนะครับ โดยรางวัลเฉลี่ยที่ได้คือ 0.6432 ครับ ค่อนข้างโอเคครับไม่ต่ำไป โดยภาพต่อไปนี้จะเป็นกระดาษคำตอบของน้อง Agent ครับ

ผลการประเมินด้วยโจทย์ที่ไม่เคยให้ Agent เรียนรู้ 30 ข้อ

สรุปแล้วมันยังไง?

โดยสรุปแล้วน้อง Agent สามารถแก้โจทย์ได้ค่อนข้างโอเคเลยครับ ผลอยู่ในระดับที่รู้สึกรับได้ แต่ว่าก็จะเห็นนะครับว่าถึงมันจะแก้โจทย์ได้ดี แต่ก็ยังไม่อยู่ในระดับที่เท่าคน อย่างโจทย์ทั้ง 30 ข้อ ถ้าให้คนลองแก้ก็คงทำได้ 30/30 ใช่ไหมละครับ

แต่ส่วนหนึ่งผมก็มองว่าอาจจะเป็นเพราะวิธีที่ใช้ในการเรียนรู้ที่ใช้มันไม่เหมาะกับโจทย์ด้วนรึป่าว คิดว่าบางคนระหว่างอ่านอาจจะเอะใจว่า ตอนเราเรียนคณิตศาสตร์เราใช้วิธีลองผิดๆ ถูกๆ แบบนี้เหรอ ซึ่งใช่ครับ ถ้าคิดๆ ดูเราใช้วิธีเรียนรู้จากการทำตามครูมากกว่า ที่จะลองผิดๆ ถูกๆ เองโดยที่รู้แค่กฎที่ทำได้แบบที่น้อง Agent คนนี้ใช้ครับ ดังนั้นในแง่ความเหมาะของวิธีอาจจะต้องค้นหาแนวทางต่อไปครับถ้าอยากไปต่อในโจทย์ที่ซับซ้อนขึ้น

สำหรับตัว code ที่ใช้ ขอดูก่อนนะครับว่าผมพอมีเวลาไป re-factor กับเพิ่ม comment ให้มันอ่านง่ายขึ้นรึป่าว แต่ถ้ามีเวลาเดี๋ยวจะมาแก้ไข blog แล้วแทรกลิงค์ของ colab ไว้ให้นะครับ

ถ้ามีอะไรผิดพลาดหรือตกหลนไปก็ขออภัยมา ณ ที่นี้ด้วยนะครับ รบกวนคอมเม้นท์บอกหน่อยนะครับถ้าสังเกตเห็นอะไรแปลกๆ ขอบคุณที่อ่านมาถึงตรงนี้ครับ

--

--