ระดับ : Beginner / Intermediate / Advanced
เชิง : Concept / Mathematics / Implementation / Creativity / Others
แท็ก : Deep Learning, Natural Language Processing, Language Modeling
เกริ่นนำ
Karpathy
ผู้ที่อยู่ในแวดวง machine learning คงจะคุ้นเคยกับชื่อนี้กันเป็นอย่างดี เพราะเมื่อไม่กี่ปีก่อน Karpathy นับเป็นดาวรุ่งพุ่งแรงที่สุดคนนึง ซึ่งสรรค์สร้างผลงานต่างๆ ไว้มากมาย ไม่ว่าจะเป็นการสอนคอร์ส CS231n ที่เปรียบเสมือนจุดเริ่มต้นของคอร์ส deep learning สมัยใหม่ รวมทั้งยังเขียนเปเปอร์ เขียนโปรแกรม และเขียนบทความหลายชิ้น อันล้วนแล้วแต่น่าตื่นตาตื่นใจและเป็นหมุดหมายสำคัญของวงการ ในที่นี้เราจะกล่าวถึงบทความนึงของ Karpathy ที่มีชื่อว่า “The Unreasonable Effectiveness of Recurrent Neural Networks” ซึ่งเป็นการตั้งชื่อล้อกับบทความอันโด่งดังของ Eugene Wigner นักฟิสิกส์รางวัลโนเบล ที่รู้สึกฉงนใจเป็นอย่างมากว่าทำไมคณิตศาสตร์ถึงสามารถนำมาใช้กับวิทยาศาสตร์ได้ดียิ่งนัก และในบทความของ Karpathy ก็มีความน่าพิศวงปรากฏอยู่เช่นเดียวกัน ว่าทำไมเมื่อใช้ RNN มาเรียนรู้แบบจำลองภาษาระดับอักขระ (character-level language model) แล้วจึงสามารถสร้างลำดับของตัวอักษรขึ้นมาจนคล้ายกับภาษาของจริงได้ถึงเพียงนี้
ในบทความนี้ Karpathy ได้ทดลองใช้ RNN แบบ LSTM มาเรียนรู้แบบจำลองภาษากับ 5 ชุดข้อมูล อันได้แก่
- Paul Graham
- Shakespeare
- Wikipedia
- Algebraic Geometry
- Linux Source Code
ซึ่งหลังจากที่ได้เรียนรู้แล้ว แบบจำลองสามารถผลิตลำดับของตัวอักษรออกมาได้ละม้ายคล้ายจริงมาก ยกตัวอย่างเช่น Latex เกี่ยวกับ algebraic geometry ที่ RNN สร้างมาดังรูปด้านล่าง สำหรับผู้เขียนที่ไม่มีความรู้ทางด้านนี้ ดูเผินๆ แล้วนึกว่าเป็นของจริงเลยทีเดียว (คล้ายของจริงถึงขนาดมีคำว่า Proof. Omitted. อีกต่างหาก!)
สำหรับชุดข้อมูล Wikipedia ชุดข้อมูล Algebraic Geometry และชุดข้อมูล Linux Source Code พบว่าข้อความที่แบบจำลองสร้างออกมามี syntax ที่เป๊ะมาก เช่นมีวงเล็บเปิดวงเล็บปิดและการเว้นวรรคเว้นบรรทัดที่ถูกต้อง มี tag ต่างๆ เหมือนจริง ส่วนชุดข้อมูล Paul Graham และ Shakespeare ถ้าดูเผินๆ ก็จะเหมือนกับผลงานที่สองท่านนี้ได้เขียนไว้เอง
นอกจากนี้ Karpathy ยังได้วิเคราะห์ลึกถึงระดับเซลล์ของ LSTM ซึ่งเปรียบเสมือนหน่วยความจำที่ส่งผ่านข้อมูลเข้าประมวลผลในช่วงเวลาต่างๆ และพบว่าบางเซลล์เก็บข้อมูลที่มีความหมาย สามารถแปลผลได้โดยตรง เช่น มีเซลล์ที่บ่งบอกสถานะว่าตอนนี้อยู่ที่ตำแหน่งไหนของบรรทัด หรือบางเซลล์ก็บ่งชี้ว่ากำลังอยู่ในอัญประกาศ ตัวอย่างเช่นในรูปด้านล่าง ที่เป็นสีอ่อนคือเซลล์นี้มีค่าใกล้ๆ 0 และที่เป็นสีแก่แสดงว่าเซลล์นี้มีค่าสูง ซึ่งหมายความว่าเซลล์นี้กำลังตื่นตัวอยู่ ส่วนสีน้ำเงินกับสีแดงคือการแสดงค่าของเซลล์ที่เป็นบวกและลบครับ ซึ่งนับว่าเป็นการวิเคราะห์และการทำ visualization ที่เหนือชั้นมากเลย
จากผลลัพธ์ของการเรียนรู้แบบจำลองภาษาและผลการวิเคราะห์ข้างต้นนี้แสดงให้เห็นพลังความสามารถของ deep learning เป็นอย่างยิ่ง ซึ่ง Karpathy ได้บรรยายถึงสิ่งที่สวยงามเกี่ยวกับ LSTM ไว้ดังนี้ครับ
Again, what is beautiful about this is that we didn’t have to hardcode at any point that if you’re trying to predict the next character it might, for example, be useful to keep track of whether or not you are currently inside or outside of quote. We just trained the LSTM on raw data and it decided that this is a useful quantity to keep track of. In other words, one of its cells gradually tuned itself during training to become a quote detection cell, since this helps it better perform the final task. This is one of the cleanest and most compelling examples of where the power in Deep Learning models (and more generally end-to-end training) is coming from.
สุนทรภู่
บทประพันธ์ของ Shakespeare คือชุดข้อมูลชุดนึงที่ Karpathy ได้เลือกใช้มาสอนแบบจำลองภาษา ทำให้ผู้เขียนมีความสนใจอยากจะทดลองว่า ถ้าเป็นบทร้อยกรองของไทย อันมีฉันทลักษณ์ที่เคร่งครัดกว่า แบบจำลองภาษาจะยังสามารถเรียนรู้สิ่งเหล่านี้ได้หรือไม่ โดยในที่นี้จะขอเลือกรูปแบบร้อยกรองที่แพร่หลายและเป็นที่นิยมมากที่สุด นั่นคือกลอนสุภาพของสุนทรภู่มาครับ
อย่างหม่อมฉันอันที่ดีและชั่ว ถึงลับตัวแต่ก็ชื่อเขาลือฉาว เป็นอาลักษณ์นักเลงทำเพลงยาว เขมรลาวลือเลื่องถึงเมืองนคร
ถ้าในต่างประเทศมี Shakespeare ผู้เป็นเลิศด้านการใช้ภาษาอังกฤษ รังสรรค์บทละครและบทกวีที่ทรงคุณค่าไว้มากมาย ฝั่งเมืองไทยก็เห็นจะมีสุนทรภู่ ผู้แต่งกลอนโดยใช้ภาษาไทยได้อย่างวิจิตรแพรวพราว สามารถสถาปนากลอนแปดให้ยิ่งใหญ่ในโลกของคำประพันธ์และวรรณคดีไทยได้ตั้งแต่สมัยต้นกรุงรัตนโกสินทร์จวบจนกระทั่งถึงปัจจุบัน โดยฉันทลักษณ์ของกลอนสุนทรภู่จะเป็นดังนี้ครับ
ในกลอนแปดบทนึงประกอบด้วย ๒ บาท บาทละ ๒ วรรค วรรคละ ๘ คำ (แต่อาจเป็น ๗ หรือ ๙ คำได้) สัมผัสนอกจะเป็นไปตามภาพ ส่วนสัมผัสในแม้จะไม่บังคับ แต่ถ้ามีด้วยก็จะทำให้บทกลอนของเราสละสลวยยิ่งขึ้น และในหัวข้อต่อๆ ไป เราจะ … มารู้จักอักขราอาร์เอ็นเอ็น โดยลองเล่นแต่งเป็นกลอนสุนทรภู่ แบบจำลองภาษาคงน่าดู ได้เรียนรู้เอไอไปพร้อมกัน
แบบจำลองภาษาและอักขราอาร์เอ็นเอ็น
แบบจำลองภาษา
แบบจำลองภาษา (language model) ในที่นี้ คือ probabilistic model ที่รับเป็น sequence เข้ามา แล้วดูว่ามีความน่าจะเป็นที่ sequence นี้จะอยู่ในภาษาที่แบบจำลองเรียนรู้มามากน้อยแค่ไหน หรืออาจเขียนได้ว่าแบบจำลองภาษาจะให้ค่าของ
ออกมา เมื่อ u คือหน่วยทางภาษาที่เราสนใจ ซึ่งโดยส่วนใหญ่อยู่ในระดับคำ แต่ที่จะใช้ในบทความนี้จะเป็นระดับอักขระครับ
ถ้าเรามองว่า u เข้ามาเรียงกัน โดยตัวที่ 1 เข้ามาก่อน ต่อด้วยตัวที่ 2 ไปจนจบตัวที่ T จากค่า P ข้างต้น เมื่อใช้ product rule ของ probability จะได้ว่าค่านี้เท่ากับ ความน่าจะเป็นในการเกิด u ตัวที่ 1 คูณด้วยความน่าจะเป็นในการเกิด u ตัวที่ 2 เมื่อก่อนหน้านี้คือ u ตัวที่ 1 แล้วคูณไปเรื่อยๆ ด้วยความน่าจะเป็นในการเกิด u ตัวต่อไป เมื่อเกิด u ตัวก่อนๆ หน้าขึ้นมาแล้ว ซึ่งจะเขียนเป็นสมการได้ว่า
แทบทุกงานทางด้าน machine learning ที่มีภาษาเข้ามาเกี่ยวข้อง แบบจำลองภาษาจะเข้ามาช่วยได้ ไม่ว่าจะเป็นงานเช่น machine translation เรื่อยไปจนถึง speech recognition และ OCR โดยในสมัยก่อนงานเหล่านี้จะมีหลาย module ประกอบกัน และส่วนใหญ่แบบจำลองภาษาจะถูกปลั๊กเข้าไปข้างหลัง เป็น module ตัวสุดท้ายเพื่อแก้ไขผลลัพธ์ที่ออกมาให้มีความถูกต้องมากยิ่งขึ้น แต่ในปัจจุบันงานเหล่านี้จะใช้ deep learning ที่เป็น end-to-end ซึ่งแบบจำลองภาษาจะถูกเรียนรู้ขึ้นมาเสร็จสรรพโดยอัตโนมัติใน neural network ขนาดใหญ่นี้เลย และนอกจากจะนำไปใช้ช่วยเหลือในงานอื่นแล้ว แบบจำลองภาษาด้วยตัวของมันเองก็อาจเอามาใช้ผลิต sequence ออกมาเล่นๆ เหมือนอย่างในบทความนี้ก็ได้ครับ
Statistical Language Model
การสร้างแบบจำลองภาษาแบบดั้งเดิม จะใช้วิธีการทางสถิติ นั่นคือค่า P ของ sequence ต่างๆ จะคำนวณมาจากการนับคำที่ปรากฏอยู่ใน corpus โดยตรง ค่า P ข้างต้นมักประมาณโดยใช้ข้อมูลแค่ n ตัว หรือที่เรียกว่า n-gram ดังนี้
ถึงแม้ n จะมีค่าไม่มากแล้ว แต่ sequence ของ n-gram ที่มีโอกาสเกิดขึ้นได้ในภาษาจริงนั้นก็มีมากมายเกินกว่าที่จะอยู่ใน corpus ใดๆ การให้ค่า count เป็น 0 สนิทเลยจึงไม่ใช่เรื่องที่ดี ทำให้ต้องมีเทคนิคเช่น smoothing หรือ back-off เข้ามาช่วยด้วยครับ
Neural Language Model
ในปี ค.ศ. 2003 Bengio et al. ได้นำ feedforward neural network มาใช้สร้างแบบจำลองภาษา เปเปอร์นี้มีเรื่อง word embedding มาก่อน word2vec และมาก่อนการใช้ RNN สำหรับ neural language model นับสิบปี ต่อมา Sutskever et al. และ Graves ได้ใช้ RNN และ LSTM สำหรับสร้างแบบจำลองภาษา ซึ่งเป็นรากฐานก่อนที่จะมาถึง Karpathy นี่เองครับ
ใน neural language model นี้ ค่า P จะออกมาจาก softmax นั่นคือ
เมื่อ V เป็นเซ็ตของหน่วยทางภาษา เช่นคำทั้งหมดที่ใช้ ส่วน h จะเป็นค่าที่ออกจาก hidden state ชั้นสุดท้าย และ v คือ output embedding ที่แม็พจาก h มาสู่ output ซึ่งเป็นหน่วยทางภาษาที่เราสนใจ
neural language model จะได้เปรียบตรงที่ information ทั้งหลายถูกเก็บอยู่ใน hidden state ซึ่งเป็น distributed representation ขณะที่ statistical language model จะทำการนับ discrete term ต่างๆ โดยตรง จึงเจอปัญหาการระเบิดแบบ exponential เพียงแค่เพิ่มค่าของ n จำนวนพจน์ต่างๆ ที่ต้องคำนวณจะมีเพิ่มขึ้นอย่างมหาศาล ทำให้เสมือนว่า neural language model สามารถใช้ information ย้อนไปได้ไกลกว่า
การวัดผล
ค่ามาตรฐานสำหรับการวัดผลของแบบจำลองภาษาคือ cross entropy ซึ่งเป็นการวัดความเคลื่อนคลาด ระหว่าง probability distribution ที่แบบจำลองทำนาย (P) กับสิ่งที่เกิดขึ้นจริง (Q) และเนื่องจากสิ่งที่เกิดขึ้นจริงคือหน่วยทางภาษาหน่วยเดียว เช่นเป็นคำๆ นึง จากคำที่เป็นไปได้ทั้งหมด ค่า Q ของคำๆ นั้นจึงเป็น 1 และค่าที่เหลือเป็น 0 หมด ทำให้ลดรูปได้เป็นบรรทัดสุดท้าย ในสมการด้านล่างนี้
สำหรับแบบจำลองระดับอักขระ ในตอนทดสอบจะเรียกค่า cross entropy นี้ว่า bit per character (bpc) ส่วนในตอนเรียนรู้ ค่านี้ก็คือ loss ที่ใช้กับ softmax layer ครับ
อักขราอาร์เอ็นเอ็น
(คำนี้เป็นคำที่ผู้เขียนประดิษฐ์ขึ้นเองเพื่อใช้ในบทความนี้นะครับ โดยจะหมายถึง RNN ที่ใช้สำหรับสร้าง character-level language model เนื่องจากคำว่า character มีศัพท์บัญญัติภาษาไทยว่า อักขระ จึงจับมาสนธิกับคำว่า อาร์เอ็นเอ็น ที่เป็นคำทับศัพท์เสียเลย)
ตัวอย่างอย่างง่าย
ตัวอย่างอย่างง่ายเพื่ออธิบายการทำงานของอักขราอาร์เอ็นเอ็นจะเป็นดังรูปนี้ครับ
ในตัวอย่างนี้จะมีตัวอักษรแค่ 4 ตัว คือ ‘h’ ‘e’ ‘l’ และ ‘o’ ด้าน input vector และ output vector จึงมี 4 มิติ โดยที่ค่าในแต่ละมิติจะสัมพันธ์กับตัวอักษรแต่ละตัว ซึ่ง input vector ในที่นี้จะเป็น one-hot encoding ส่วน output vector ในแต่ละตำแหน่งจะแสดงถึงความมั่นใจในการตอบ ‘h’ ‘e’ ‘l’ และ ‘o’ ออกมา ซึ่งในการเรียนรู้ จะต้องทำให้ค่าในตำแหน่งสีเขียวมีค่ามาก และค่าในตำแหน่งสีแดงมีค่าน้อย เพื่อให้คำตอบออกมาถูกต้องตามข้อมูลที่สอนเข้าไป
RNN จะทำงานทีละ time step โดยรับ input เป็นตัวอักษรที่เวลานั้นเข้ามา แล้ว hidden state จะคำนวณค่าจาก input vector ที่เข้ามาเวลานั้นและจาก hidden state ก่อนหน้า จากนั้นจะให้ output เป็นการทำนายตัวอักษรตัวถัดไป หรือเขียนเป็นสมการได้ว่า
ของที่ใช้จริง
ถ้านำ RNN ข้างต้นไปใช้จริงจะพบว่าทำการเรียนรู้ได้ไม่ดี เนื่องจากมีปรากฏการณ์ vanishing/exploding gradient เป็นปัญหาใหญ่อยู่ ในการทดลองนี้จึงได้ใช้ RNN แบบ LSTM และการตั้งค่าเกือบทั้งหมดจะเหมือนกับที่ Karpathy ทำ แต่ก็ไม่ได้นำโค้ดของ Karpathy มาใช้โดยตรงครับ เนื่องจากผู้เขียนไม่รู้ภาษา Lua จึงได้ใช้โค้ด Keras ของคุณ Yu Xuan Tay มาแทน โดยทำการเพิ่มเติมแก้ไขในจุดสำคัญๆ สองส่วน คือทำให้สามารถรับภาษาไทยได้ กับเพิ่มในส่วนของการทำ validation และ testing
สำหรับ RNN architecture ที่ใช้ในการทดลอง สามารถอธิบายได้ดังนี้
- input ที่เข้ามาจะผ่าน embedding layer ก่อน เพื่อแปลงจาก one-hot encoding ตรงๆ ให้อยู่ใน embedding space ที่สื่อความหมายได้ดีขึ้น
- กล่องของ recurrent layer จะเหมือนกับ hidden layer ในรูปก่อนหน้า เพียงแต่เปลี่ยนจาก RNN ธรรมดาเป็น LSTM และมีหลายชั้น
- ใน Keras เมื่อระบุให้ return_sequences=True ที่ชั้น LSTM ในแต่ละเวลาจะคาย output ออกมาด้วย ถ้ามี LSTM ซ้อนกันหลายชั้น ก็จะใช้ output ของ LSTM ชั้นล่าง มาเป็น input ของ LSTM ที่ชั้นถัดไป ในเวลาเดียวกัน
- ใน Keras จะมี TimeDistributed layer สำหรับครอบ output ที่ออกมาจาก LSTM ชั้นสุดท้ายในแต่ละเวลา โดยในที่นี้จะครอบเป็น fully connected layer หรือเรียกอีกชื่อว่า dense layer ที่มี output ขนาดเท่ากับจำนวนตัวอักษรที่ใช้ และให้ softmax เป็น activation function
- ใน Keras ถ้า stateful=True จะให้ค่าของ hidden state มีความต่อเนื่องไประหว่าง minibatch ด้วย ซึ่งจำเป็นต้องใช้ในงานนี้เพราะว่าข้อมูลที่ใช้สอนแบบจำลองภาษามีความต่อเนื่องกันไปโดยตลอด ค่าของ hidden state จึงควรจะต่อเนื่องตามไปด้วย มิใช่เริ่มจาก 0 ใหม่ในทุกๆ minibatch และเมื่อเซ็ตให้ใช้ stateful แล้ว กระบวนการเตรียมข้อมูลก่อนนำเข้าไปเทรนจะซับซ้อนกว่าแบบทั่วไปที่เป็น stateless อยู่เล็กน้อยครับ
ในส่วนของ source code ที่ใช้ ได้เปิดเป็น open source ไว้ที่นี่ครับ
การทดลองสร้างแบบจำลองภาษา
ชุดข้อมูล
ชุดข้อมูลภาษาไทยในที่นี้มาจากวรรณคดีเรื่องพระอภัยมณี โดยผู้เขียนได้ใช้เฟรมเวิร์ค Scrapy ดึงข้อมูลมาจากห้องสมุดดิจิทัลวชิรญาณ ซึ่งต้องขอขอบคุณทางห้องสมุดมาไว้ ณ ที่นี้ครับ เพราะการจัดทำวรรณกรรมของไทยให้อยู่ในรูปแบบหนังสืออิเล็กทรอนิกส์นอกจากจะมีคุณูปการอย่างมหาศาลในด้านการอนุรักษ์แล้ว ยังมีประโยชน์ต่อวงการ NLP ภาษาไทยอีกด้วย
ข้อมูลชุดนี้จะใช้ชื่อว่า phra_aphai สิริแล้วมี 2,612,950 ตัวอักษร บันทึกไฟล์โดยใช้ encoding เป็น UTF-8 โดยบรรทัดนึงจะมีสองวรรค แต่ละวรรคคั่นด้วยตัวอักษรช่องว่าง ตัวอย่างบทกลอนที่อยู่ในข้อมูลฝึกสอนเป็นดังนี้ครับ
ชุดข้อมูล phra_aphai มีขนาดประมาณ 2M การทดลองนี้จึงได้นำชุดข้อมูล tinyshakespeare ที่มีขนาดประมาณ 1M และชุดข้อมูล shakespeare ที่มีประมาณ 4M มาใช้ทดลองเพื่อทำการเปรียบเทียบกันด้วย โดยมีการแบ่งข้อมูลสำหรับฝึกสอนและทดสอบดังตารางด้านล่างนี้ครับ
โดยชุดข้อมูล tinyshakespeare และ shakespeare จะตัดตัวอักษรตำแหน่งที่ 1M และ 4M จนถึงตัวสุดท้ายไปเป็น test data ตามลำดับ และที่เหลือจะแบ่งข้อมูล 10% ข้างท้ายมาเป็น validation data ส่วนนอกนั้นจะเป็น training data สำหรับชุดข้อมูล phra_aphai จะตัดตอนที่ ๑๑๖ ไปจนจบ เป็น test data และตอนที่ ๑๐๔ ถึง ๑๑๕ เป็น validation data
เซ็ตอัพ
ในการทดลองมีการตั้งค่า hyperparameter ต่างๆ เป็นดังนี้
network parameters
num_layer = 3
rnn_size = 512
ในที่นี้จะใช้ LSTM ซ้อนกันสามชั้น และ hidden state เป็น vector ขนาด 512 จากการทดลองพบว่าค่า rnn_size มีความสำคัญมากทีเดียว ในช่วงแรกผู้เขียนเซ็ตเป็นขนาด 128 แล้วผลลัพธ์ที่ออกมาไม่ค่อยดีเท่าไหร่ จึงได้รู้ว่าเป็นค่าที่น้อยไป
input parameters
batch_size = 64
seq_len = 256
embedding_size = 32
ผู้เขียนสันนิษฐานว่าเมื่อเป็น stateful แล้ว ค่า seq_len อาจไม่สำคัญเท่าไหร่ แต่ก็เลือกใช้ seq_len เป็น 256 ซึ่งจากการสุ่มตัวอย่างดูพบว่าค่านี้ครอบคลุมกลอนสองบทได้ สำหรับ parameter อื่น จะให้ minibatch นึงมีข้อมูล 64 ท่อน และขนาด vector ที่ออกมาจาก embedding layer เท่ากับ 32
optimization
Adam optimizer
lr = 0.001
beta_1 = 0.9
beta_2 = 0.999
decay = 0
ในที่นี้จะทำ optimization โดยใช้วิธี Adam optimizer ส่วน parameter อื่นๆ ก็ใช้ค่าที่เป็น default ของการทำ optimization วิธีนี้ครับ
regularization
drop_rate = 0.5
clip_norm = 5
ในที่นี้จะใช้ค่า dropout rate เท่ากับ 50% ซึ่งเป็นค่ามาตรฐานที่ส่วนใหญ่นิยมใช้กัน และเพื่อป้องกันปัญหา exploding gradient ของ RNN จะมีการขริบ gradient ไม่ให้มีขนาดที่เกิน 5
สรุป
โครงสร้างของ neural network และจำนวน parameter ทั้งหมดสามารถสรุปได้ดังตารางนี้
Karpathy ได้ให้เคล็ดลับในการสร้าง neural network ไว้นิดนึงว่าจำนวน parameter ที่มีทั้งหมด กับจำนวนข้อมูลควรจะอยู่ใน order เดียวกัน ในที่นี้จะเห็นว่าทั้ง parameter และชุดข้อมูลของเราอยู่ที่สเกลระดับ 10⁶ เหมือนกัน จึงน่าจะโอเคระดับนึง ปัญหา underfitting คงจะไม่มี แต่อาจต้องคอยจับตาปัญหา overfitting อยู่บ้างครับ
ผลการทดลอง
ในที่นี้จะนำเสนอผลการทดลองทั้งแบบที่เป็นตัวเลข (quantity) และตัวอักษร (quality) นะครับ
ตัวเลข
ในการทดลองนี้ได้ทำการเทรนทั้งหมด 1000 รอบ โดยใช้ Tesla K80 GPU แล้วทดสอบกับ validation data ทุกๆ 10 รอบ เมื่อเทรนเสร็จแล้วจะนำแบบจำลองของรอบที่ให้ค่า bpc ใน validation data ต่ำสุด มาใช้ทดสอบกับ test data ซึ่งให้ผลดังตาราง
พบว่าค่า bpc ของ test data ขึ้นอยู่กับขนาดของข้อมูลโดยตรง โดยชุดข้อมูลที่มีข้อมูลมากกว่า จะให้ค่า bpc ที่ดีกว่า สำหรับค่า bpc ของชุดข้อมูล phra_aphai ที่ประมาณ 2 ในเชิง information theory อาจตีความได้ว่า ถ้าเราต้องการจะบีบอัดข้อมูลหนังสือพระอภัยมณีทั้งเล่ม ในทางปฏิบัติอาจสามารถทำได้เพียงใช้แค่ 2 บิต ต่อจำนวนตัวอักษรหนึ่งตัว ก็จะลดขนาดไฟล์หนังสือพระอภัยมณีลงได้ราวๆ 4 เท่า เมื่อเทียบกับการ encoding ทั่วไปที่ใช้ 8 บิต ค่า bpc นี้จะเป็น upper bound ของ optimal code จริงๆ ซึ่ง optimal code นี้ก็คือ lower bound ของ data compression ที่เป็นไปได้นั่นเองครับ
ส่วน learning curve ของชุดข้อมูลต่างๆ จะเป็นดังรูปด้านล่างนี้
และเมื่อเอาเฉพาะ validation data ของสามชุดข้อมูลมาเทียบกัน จะเป็นดังนี้
จะเห็นว่าชุดข้อมูล phra_aphai ลู่เข้าช้ากว่าชุดข้อมูล shakespeare ทั้งสองอยู่เล็กน้อย โดยค่า bpc ที่ดีที่สุดใน validation data มาช้ากว่าอยู่ประมาณร้อยรอบ เมื่อดูกราฟแล้วพบว่าค่า bpc ของ validation data มีอาการหวั่นไหวในรอบหลังๆ โดยเฉพาะชุดข้อมูล tinyshakespeare ที่สั่นค่อนข้างแรง อาจจะเป็นเพราะผู้เขียนไม่ได้ปรับ learning rate ให้มี decay และจากการที่ค่า bpc ของ validation data กับ test data ในชุดข้อมูล tinyshakespeare มีค่าค่อนข้างต่างกัน ทำให้เห็นว่าชุดข้อมูลนี้มีข้อมูลจำนวนน้อยเกินไป และเกิดปัญหา overfitting อาจจะต้องปรับเรื่อง regularization สำหรับชุดข้อมูลนี้ให้มีมากขึ้น
สำหรับผลของการเปลี่ยน hyperparameter ต่างๆ จะมีบล็อกนี้ที่ได้ทำการทดลองไว้ครับ
ตัวอักษร
สุดท้ายนี้เราจะให้ RNN ที่เรียนรู้แบบจำลองภาษามาแล้ว สร้างลำดับของตัวอักษรต่อๆ กันไปเรื่อยๆ โดยตัวอักษรที่ถูกสร้างขึ้นในเวลาก่อนหน้า จะถูกนำไปใช้เป็น input สำหรับสร้างตัวอักษรในเวลาถัดไป และจะสุ่มตัวอักษรจาก 3 ตัวที่มีค่า probability สูงสุด เป็น output ออกมา โดยใช้ seed string หรือ string เริ่มต้นเป็น “๏ ก” กลอนที่ได้ 5 บทแรกเป็นดังนี้ครับ
- ในด้านฉันทลักษณ์ส่วนใหญ่ทำได้ค่อนข้างดี ถ้ามองเพียงผิวเผินอาจนึกว่าสุนทรภู่มาเอง
- แบบจำลองนี้สามารถเรียนรู้ข้อจำกัดด้านจำนวนพยางค์ การเว้นวรรค และการเว้นบรรทัด แล้วแต่งกลอนออกมาตามข้อกำหนดนี้ได้เป๊ะมาก
- สัมผัสในไม่ด่างพร้อย ถ้าดูแค่แต่ละวรรคจะเห็นว่าค่อนข้างสมบูรณ์ในตัว
- แต่สัมผัสนอกบางครั้งยังไม่ค่อยจะได้
- มีศัพท์ใหม่บางคำที่แบบจำลองสร้างขึ้นมาเอง เช่นคำว่า “สำอาญ” ซึ่งดูจะคล้ายๆ คำว่า สำราญ ผสมกับ สำอาง (วรรคที่ว่า “แม้นมารดรอดอ่านสำอาญตา” ผู้เขียนอ่านครั้งแรกแล้วรู้สึกว่าตัดคำได้ยากมากครับ)
- วรรคแรกสุดในหนังสือพระอภัยมณีเป็นวรรครับ (วรรคที่ ๒ ในกลอน ๑ บท) ซึ่งแบบจำลองก็เรียนรู้ได้ และแต่งออกมาแบบนี้เหมือนกัน
- เมื่อขึ้นต้นบทกลอนหัวข้อใหม่ จะใช้เครื่องหมายตาไก่หรือฟองมัน (๏) และจบท้ายหัวข้อนั้นด้วยไปยาลน้อย (ฯ) ซึ่งแบบจำลองก็ใช้สองเครื่องหมายนี้มาต่อกันได้ไม่พลาดเลย ตัวอย่างเช่นกลอนอีกช่วงนึงที่แบบจำลองแต่งออกมาดังนี้
- จะเห็นว่าในส่วนสัมผัสนอกของบาทเดียวกัน แบบจำลองนี้พยายามจะทำให้ได้อยู่ เช่นในบทที่ ๔ ของกลอนด้านบน มีการเลือกใช้คำว่า “ตับ” เพื่อให้สัมผัสกับคำว่า “รับ” และพยายามเติม ม.ม้า ให้เป็นคำว่า “ว่าม” เพื่อให้สัมผัสกับคำว่า “งาม” แต่สัมผัสนอกที่อยู่คนละบาทนั้นยังทำได้ไม่ค่อยดี
- ส่วนในด้านความหมาย หรือการจะให้แต่งอะไรออกมาเป็นเรื่องเป็นราวนั้น แน่นอนว่ายังเกินความสามารถของแบบจำลองภาษาลักษณะนี้อยู่ครับ
- การที่แบบจำลองยังทำสัมผัสนอกและสืบทอดความหมายระหว่างวรรคได้ไม่ดี แสดงให้เห็นว่าเรื่อง long-range dependency ยังเป็นปัญหาที่สำคัญ และรอคอยการแก้ไขต่อไป
ท่านผู้อ่านสามารถดูข้อมูลที่แบบจำลองผลิตมาจำนวนหนึ่งล้านตัวอักษรได้ที่นี่ และลองเทียบกับวรรณคดีเรื่องพระอภัยมณีของจริงได้ที่นี่ครับ
มีทฤษฎีลิงอนันต์ได้กล่าวไว้ว่า ถ้าเราจับลิงมาตัวนึง ให้นั่งเคาะแป้นพิมพ์ไปเรื่อยๆ ซักวันก็คงได้บทประพันธ์ของ Shakespeare ออกมา แต่คงต้องรอนาน (มากๆ) แต่ถ้าหากเราให้ deep learning แทนลิงตัวนั้น ก็จะสามารถแต่งอะไรที่คล้ายกับ Shakespeare หรือสุนทรภู่ออกมาได้ โดยที่ไม่ต้องใช้เวลาถึงอสงไขยอย่างในทฤษฎีลิงอนันต์ครับ
ปิดท้าย
Karpathy
ถ้าคนธรรมดาจะแต่งกลอนซักบทให้ได้สละสลวยอาจต้องใช้เวลาเป็นวัน ว่ากันว่าสุนทรภู่ช่วงพีคพูดกลอนออกมาแล้วใช้เสมียนสองคนนั่งจดยังจดแทบไม่ทัน แต่ถึงกระนั้น วรรณคดีเรื่องพระอภัยมณีกว่าจะแต่งเสร็จก็ใช้เวลามากกว่า 20 ปี ในปัจจุบันนี้ก็ยังมีปัญหาว่านักอ่านรอเสพผลงานของนักเขียนที่ตนเองชื่นชอบอย่างกระวนกระวาย หลายคนถึงกับภาวนาว่าขออย่าให้ตนเองและนักเขียนตายไปก่อนที่นิยายหรือมังงะที่ติดตามอยู่จะถึงตอนจบเลย เพราะฉะนั้น จะดีแค่ไหนถ้าความฝันใฝ่ของ Karpathy เป็นจริง จะดีแค่ไหนถ้า AI สามารถแต่งนิยายชุด A Song of Ice and Fire เล่มใหม่ หรือวาดมังงะ Hunter x Hunter ตอนใหม่ได้เพียงในเวลาไม่กี่วัน แทนที่จะต้องรอคอยกันนานหลายๆ ปี อย่างที่เป็นอยู่
Karpathy มีความเชื่อว่าซักวันนึง แม้แต่หนังทั้งเรื่องก็สามารถใช้ AI สร้างขึ้นมาได้ ใจนึงผู้เขียนคิดว่าถ้า extrapolation จากความก้าวหน้าแบบก้าวกระโดดของโลก AI ในปัจจุบัน เวลานั้นคงจะมาถึงในอีกไม่ช้า แต่อีกใจนึงผู้เขียนก็คิดว่ายังมีช่องว่างอันกว้างใหญ่ที่จำเป็นต้องข้ามไปอยู่
ผู้เขียนเชื่อว่าในสมองของคนเรานี้มีแบบจำลองภาษาอยู่อย่างแน่นอน แต่เรื่องความคิดสร้างสรรค์นั้นเป็นอะไรที่มากกว่าแบบจำลองภาษา กว่าจะกลั่นถ้อยคำออกมาเป็นหนังสือซักเล่ม บทความซักบท หรือเรื่องราวซักเรื่อง มนุษย์เราใช่ว่าสักแต่จะนำตัวอักษรหรือคำที่น่าจะเป็นมาเรียงร้อยต่อกัน แต่ยังมีเรื่องของการวางแผน การใช้เหตุผล การใช้ภาษา อารมณ์ศิลปะ รวมทั้งจะต้องประมวลความรู้ทางโลก ความรู้สึกนึกคิด และประสบการณ์ชีวิตที่มีทั้งหมดเข้าด้วยกัน ซึ่งสิ่งเหล่านี้ยังเกินกว่าความสามารถของ AI ในปัจจุบัน แม้แต่ในงานบางอย่างที่ AI ทำได้ดีแล้ว เราก็ยังไม่เข้าใจกลไกข้างในนัก อย่างที่ Karpathy ใช้คำว่า unreasonable effectiveness นั่นเองครับ
สุนทรภู่
ย้อนกลับไปเมื่อสมัยต้นกรุงรัตนโกสินทร์ เราจะได้เห็นภาพชีวิตกวีเอกของไทยที่ได้ดีและตกอับสลับกัน แต่ไม่ว่าจะเป็นช่วงไหน สุนทรภู่ก็ยังคงเขียนกลอนอยู่อย่างต่อเนื่อง เฉพาะเรื่องพระอภัยมณีก็นับว่ามีความยาวสูงเพียงพอที่จะให้ผู้เขียนนำมาใช้ทดลองสร้าง language model เทียบกับงานของ Shakespeare ได้
เนื่องในโอกาสวันสุนทรภู่ปีนี้ ผู้เขียนขอน้อมรำลึกถึงท่านด้วยครับ
หนึ่งขอฝากปากคำทำหนังสือ ให้สืบชื่อชั่วฟ้าสุธาสถาน สุนทราอาลักษณ์เจ้าจักรพาฬ พระทรงสารศรีเศวตเกศกุญชร