การใช้งาน NLP_LIB เพื่อ train semi-supervised model ด้านภาษาศาสตร์
NLP_LIB เป็น python library ที่ผมเขียนขึ้นมาเพื่อช่วยในการทำงานวิจัยด้านภาษาศาสตร์ โดยตัว library นี้มุ่งเน้นไปที่การ train model แบบ semi-supervised learning ซึ่งจะนำไปใช้ในกรณีที่เราต้องการ train model เพื่อทำ supervised task อะไรบางอย่าง แต่ดันมีจำนวน training data น้อยเกินไป หรืออีกกรณีคือการที่เราต้องการจะ train model ที่สามารถนำไปใช้ได้หลายๆงานในภาษาเดียวกัน โดยไม่ต้องเริ่ม train ใหม่ตั้งแต่ต้น… กล่าวคือ การใช้เทคนิค semi-supervised learning นี้จะสามารถ
- ลดจำนวน training data ที่ต้องใช้ในการ train supervised model
- ลดระยะเวลาที่ต้องใช้ในการ train supervised model หลายๆงานในภาษาเดียวกัน
ใน Blog นี้จะอธิบายหลักการเบื้องต้นของการทำ semi-supervised learning ในงานภาษาศาสตร์ และอธิบายการใช้งาน NLP_LIB เพื่อ train model ดังกล่าว ตั้งแต่การ set up, train, inference และจะมีอธิบายเกี่ยวกับตัว NLP_LIB ระดับหนึ่งแต่ไม่ลงลึกมาก การอธิบายโครงสร้างของ NLP_LIB อย่างละเอียดจะอยู่ใน Blog ถัดๆไป
Semi-Supervised Learning ในงานภาษาศาสตร์
ในการ train supervised model นั้น โดนปกติเราจะใช้ training data ที่มีการ label เพื่อ train model ดังรูปด้านล่างนี้
ตัวแปรหนึ่งที่สำคัญต่อแม่นยำของ model คือคุณภาพและปริมาณของ training data ที่เรามี
ในโลกความเป็นจริงนั้น เรามักจะเริ่มต้นจากจุดที่เรามี training data ที่มี label น้อยมาก ทำให้การ train model ตรงๆแบบนี้ไม่ค่อยได้ผลดีนักเท่าไหร่
หลักการ semi-supervised learning ในงานด้านภาษาศาสตร์นั้นตั้งอยู่บนพื้นฐานที่ว่า ข้อมูล text ที่ไม่ได้มีการ label นั้น จริงๆมีอยู่เยอะมาก (เช่น wikipedia) หากเทียบกับข้อมูล labeled training data สำหรับงาน supervised task หนึ่งๆ ดังนั้นถ้าเราสามารถหาวิธีทำให้ model สามารถ train บนข้อมูลที่ไม่ต้องมี label ได้ด้วย จะทำให้เราสามารถมีข้อมูลปริมาณมหาศาลให้เราใช้ train model ให้ได้ผลดีขึ้นได้
โดยการทำ semi-supervised learning นั้น จะเริ่มจากการ train model บน data ที่ไม่ได้มีการ label ที่มีปริมาณเยอะๆก่อน เราเรียก step นี้ว่า language modeling แล้วหลังจากนั้นค่อยเอา model ที่ได้ไป train ต่อบน data ที่มีการ label ใน task ที่เราต้องการ เราเรียก step นี้ว่า fine tuning ดังรูปข้างล่าง
วิธีนี้จะทำให้เราเอา data ที่มีอยู่ทั่วไปมาใช้ประโยชน์ได้ และมักจะได้ผลดีกว่าการ train model บน labeled training data ที่มีอยู่น้อยนิด นอกจากนี้ จะเห็นว่าเราสามารถนำ model ที่ผ่านการ train แบบ language model มาใช้ซ้ำๆ คือนำมา fine tune เข้ากับ supervised task หลายๆอย่างได้โดยไม่ต้องเริ่มต้น train language model ใหม่… ขอแค่งาน downstream task เหล่านั้นทำงานบนภาษาเดียวกันก็จะสามารถใช้ได้ ทำให้สามารถร่นระยะเวลาในการสร้าง supervised model หลายๆ task ได้ด้วย
จะเห็นได้ว่าการ train แบบ semi-supervised learning นั้น เราจะต้องมีข้อมูลอยู่ 2 ชุด คือชุดที่เป็น text data เปล่าๆไม่มี label ขนาดใหญ่ กับอีกชุดที่เล็กกว่าที่มีการ label data ตาม task ที่เราต้องการ
ในส่วนถัดไปจะเป็นการใช้งาน NLP_LIB เพื่อทำการ train semi-supervised learning
หลักการที่กล่าวมาด้านบนนี้เป็นหลักการทั่วไปในการทำ semi-supervised learning ในงานภาษาศาสตร์… ในแง่ของ model architecture นั้น model ที่จะเอาทำเป็น language model รวมถึง objective function ในการ train นั้นจะต้องสามารถ train บน data ที่ไม่มี label ได้ ซึ่งในปัจจุบัน (2019) มีงานวิจัยเสนอรูปแบบ model ที่สามารถนำมา train เป็น language model ไว้หลายตัว OpenAI GPT หรือ Google BERT ซึ่งแต่ละตัวก็จะมี objective function แตกต่างกันในการ train เราจะยังไม่ลงรายละเอียดในที่นี้ แต่จะขอ list training method ที่มีความเป็นไปได้ในการทำงานบน text data แบบไม่มี label ได้ (ซึ่งแปลว่ามีความเป็นไปได้ที่จะเอามาใช้สร้าง langauge model) ไว้ด้านล่างนี้
Auto-Encoder : Train ให้ model predict output = input ได้โดยลด dimension ของข้อมูลใน hidden layer แล้วมองว่าข้อมูลใน hidden layer จะ represent abstract idea ของ data
Skip Gram / CBOW : Train ให้ model สามารถ predict คำที่ตำแหน่งหนึ่งๆได้ถูกต้องโดยดูจากคำรอบๆตัวมัน มักใช้ในการ train word embedding
Next Token Prediction : Train ให้ model สามารถ predict คำถัดไปโดย condition on คำก่อนหน้าทั้งหมดใน document
Mask Tokens Prediction : ทำการ mask บางคำใน document ออกแล้วให้ model predict คำเหล่านั้นให้ถูกต้องได้โดย condition on คำที่เหลือทั้งหมด
NLP_LIB Installation and Setup
ระบบจะต้องมี python3 (3.6.8 ขึ้นไป) และ pip3 ลงอยู่เป็น Prerequisite…
จากนั้นทำการ install NLP_LIB ด้วย
pip3 install NLP_LIB_cpu
กรณีที่เครื่องที่ใช้งานมี GPU สามารถลง library version ที่ใช้งาน CUDA ได้ดังนี้
pip3 install NLP_LIB
ตอนนี้เราพร้อมจะใช้งาน NLP_LIB แล้ว
Prepare Training Data
เราต้องเตรียม training data ทั้งหมดสองชุดด้วยกัน ชุดหนึ่งจะเป็น text data เปล่าๆ ส่วนอีกชุดจะเป็น text data ที่มี label สำหรับงาน supervise task ที่เราต้องการ
training data ทั้งสองชุดจะอยู่ในรูปแบบ .txt file ดังนี้ (ชื่อ file สามารถตั้งได้อิสระ แต่ขอแนะนำว่าตั้งตามแหล่งที่มาของ data จะได้เข้าใจง่าย)
language_model_data.txt
sentence 1
sentence 2
...
sentence N
supervised_data.txt ( [TAB] แทน tab character)
sentence 1[TAB]label
sentence 2[TAB]label
...
sentence N[TAB]label
ด้านล่างนี้เป็นตัวอย่างของ training data files ทั้งสองสำหรับงาน Sentiment Analysis
language_model_data.txt
นี่คือประโยคแรก
นี่คือประโยคที่สอง
...
นี่คือประโยคสุดท้าย
supervised_data.txt ( ช่องว่างตรงกลางเกิดจากการใช้ tab character)
ผลงานดีมากๆ positive
ส่งของมาแต่ใช้งานไม่ได้ negative
...
วันนี้อากาศเย็น neutral
เพื่อความสะดวกในการเรียกใช้งาน ให้เอา training data ทั้ง 2 file ไปไว้ใน folder ext_dataset โดย language model training data ควรมีจำนวนไม่น้อยกว่า 1,000 บรรทัด และ supervised training data ควรมีจำนวนบรรทัดไม่น้อยกว่า 320 บรรทัด
NLP_LIB จะทำการแบ่งข้อมูลเป็น training data set และ validation data set ให้เอง จริงๆเราสามารถ specify ข้อมูลแต่ละชุดแยกเป็น 2 file เพื่อให้ใช้ file นึงเพื่อ train กับใช้อีก file เพื่อการ evaluate model ได้ แต่จะยังไม่พูดถึงใน Blog นี้
Train Language Model
หลังจากที่เราเตรียม training data ไว้ใน folder ext_dataset แล้ว เราสามารถ train language model ได้โดยใช้คำสั่งดังนี้
python3 -m NLP_LIB tf2-dec-sp:ext_dataset/language_model_data.txt
tf2-dec-sp คือ language model architecture ที่เราเลือกใช้ ซึ่ง NLP_LIB มี implementation ของหลาย architecture ให้เลือกใช้ แต่จะยังไม่พูดถึงใน Blog นี้
ในค่า setting แบบ default นั้น NLP_LIB จะ train language model จำนวน 60 epoches แต่เราสามารถกด Ctrl-C เพื่อหยุดการ train กลางทางได่้ โดย NLP_LIB จะเก็บ model ที่ดีที่สุดไว้ให้ใน folder
_outputs_/tf2-dec-sp_ext_dataset_language_model_data.txt/checkpoint
NLP_LIB จะเริ่ม save model file หลัง train จบอย่างน้อย 1 epoch เท่านั้น
Finetune Downstream Task
เมื่อเราได้ language model ออกมาแล้ว เราสามารถใช้มันเพื่อ finetune เข้ากับ supervised training data ได้ โดยที่เวลาเราจะสั่ง finetune นั้น เราจำเป็นต้องบอกว่าเราใช้ language model ไหน (ทั้ง model architecture และ language model data set) เพื่อให้ NLP_LIB สามารถสร้าง model และเลือกวิธี encode input data ที่ถูกต้องได้ นอกจากนี้ เราจำเป็นจะต้องระบุด้วยว่า finetune model นั้นเป็นลักษณะไหน (เช่นใน case Sentiment Analysis ของเราคือเป็น multiclass classifier ที่ label มีได้ 3 ค่า — Positive, Negative, Neutral) และใช้ supervised data set ไหนด้วย ดังตัวอย่างด้านล่างนี้
python3 -m NLP_LIB tf2-dec-sp:ext_dataset/language_model_data.txt:sa3:ext_dataset/supervised_data.txt
จะเห็นว่าส่วนแรกของ arguments จะเหมือนกับตอน train language model เลยคือ tf2-dec-sp:ext_dataset/language_model_data.txt ซึ่งจะทำให้ NLP_LIB สามารถไป load pretrained language model ได้ถูกที่ ส่วน arguments ที่เหลือนั้น sa3 เป็นการบอกว่า supervised data set นั้นเป็น task ที่เป็น single answer (multiclass label) ที่มีจำนวนค่าของ label 3 แบบ และ argument สุดท้ายคือ supervised training data file ซึ่งก็คือ ext_dataset/supervised_data.txt
ในค่า setting แบบ default นั้น NLP_LIB จะ train language model จำนวน 30 epoches แต่เราสามารถกด Ctrl-C เพื่อหยุดการ train กลางทางได่้ โดย NLP_LIB จะเก็บ model ที่ดีที่สุดไว้ให้ใน folder
_outputs_/tf2-dec-sp_sa3_ext_dataset_language_model_data.txt_ext_dataset_supervised_data.txt/checkpoint
NLP_LIB จะเริ่ม save model file หลัง train จบอย่างน้อย 1 epoch เท่านั้น
Perform Prediction
หลังจากที่ทำการ finetune model เข้ากับ supervised task แล้ว เราสามารถนำ model ที่ได้มาใช้ในการ predict ผลลัพธ์กับ data ใหม่ได้ โดยการใช้คำสั่งที่เหมือนกับตอน finetune data แต่เพิ่ม parameter ว่าเราต้องการ predict บน data file หรือ string ไหนเช่น
Predict บน input string
python3 -m NLP_LIB tf2-dec-sp:ext_dataset/language_model_data.txt:sa3:ext_dataset/supervised_data.txt predict str:เศรษกิจดีขึ้นมาก
Predict บน data file
python3 -m NLP_LIB tf2-dec-sp:ext_dataset/language_model_data.txt:sa3:ext_dataset/supervised_data.txt predict file:ext_dataset/supervised_test_data.txt
ext_dataset/supervised_test_data.txt เก็บข้อมูลที่ต้องการ predict ได้หลาย entry โดยแต่ละ entry คือหนึ่งบรรทัดใน file
ตัวอย่าง output จากการ predict บน file
input = ['เศรษกิจดีขึ้นมาก', 'วันนี้อากาศแย่', 'รถติดมากๆ', 'วันนี้อากาศเย็น', 'วันนี้อากาศร้อน']
Predicted output = ['positive', 'negative', 'negative', 'neutral', 'negative']
Finished predicting.
==== PREDICTION OUTPUT ====
['positive', 'negative', 'negative', 'neutral', 'negative']
ภาคผนวก: การวิเคราะห์คุณภาพของ model
ในระหว่างการ train ทั้งในส่วนของ language model และ supervised finetune นั้น NLP_LIB จะทำการสร้าง tensorboard log เพื่อให้เราสามารถวิเคราะห์คุณภาพของ model ที่กำลัง train อยู่แบบ realtime ได้ ซึ่งจะทำให้เราสามารถ
- หยุดการ train เนื่องจาก model ดูแล้วไม่แม่นขึ้นเลย ซึ่งทำให้เราต้องไปวิเคราะห์ต่อว่าจะแก้ที่ model architecture หรือจะแก้ที่ training data (ใน Blog ถัดๆไปจะลงลึกเรื่องการวิเคราะห์เวลา model train ออกมาได้ไม่ดี)
- หยุดการ train เนื่องจากเห็นว่า model เริ่มจะ overfit แล้ว
NLP_LIB จะทำการ save weight ของ model ที่ดีที่สุด (best_weight.h5) แล้ว weight ของ model ที่ training epoch ล่าสุด (last_weight.h5) ในกรณีที่ทำการ train จน model overfit ตัว best_weight.h5 จะเป็น weight ของ model ใน epoch ที่ความแม่นยำบน validation data สูงที่สุด (กล่าวคือตอนที่ยังไม่ overfit นั่นเอง)
จากตัวอย่างด้านบน directory ของ tensorboard log สำหรับ language model จะอยู่ที่
_outputs_/tf2-dec-sp_ext_dataset_language_model_data.txt/tboard_log
ส่วน tensorboard log สำหรับ supervised finetune จะอยู่ที่
_outputs_/tf2-dec-sp_sa3_ext_dataset_language_model_data.txt_ext_dataset_supervised_data.txt/tboard_log
เราสามารถดู tensorboard log ได้ตั้งแต่ขณะที่ train model จบไป 1 epoch ได้โดยให้เปิด terminal window ใหม่แล้ว จากนั้นใช้คำสั่งด้านล่างนี้เพื่อ run tensorboard บน log directory ของ model
สำหรับ language model
tensorboard --logdir=_outputs_/tf2-dec-sp_ext_dataset_language_model_data.txt/tboard_log/
สำหรับ supervised finetune
tensorboard --logdir=_outputs_/tf2-dec-sp_sa3_ext_dataset_language_model_data.txt_ext_dataset_supervised_data.txt/tboard_log/
จากนั้นเปิด web browser เข้าไปยัง URL: http://localhost:6006
ในการวิเคราะห์คุณภาพ language model เราจะดูที่ val_ppl (Perplexity value บน validation data) ส่วนสำหรับ supervised finetune เราจะดูที่ val_loss (Loss value บน validation data) ซึ่งจะบอกเราได้ว่า model กำลัง overfit แล้ว หรือ train ไม่ลู่เข้าเลยแต่แรก (การวิเคราะห์อย่างละเอียดจะขอพูดถึงใน Blog ถัดๆไป)
ตัวอย่างในรูปด้านล่างนี้แสดง val_loss ที่เริ่มจะอิ่มตัวแต่ยังไม่ overfit
ใน Blog นี้ เราได้ทดลองใช้ NLP_LIB ทำการ train model ภาษาศาสตร์แบบ semi-supervised learning เบื้องต้นแล้ว ใน Blog ถัดๆไปจะเป็นการลงลึกในตัว NLP_LIB เพื่อใช้งาน feature ต่างๆ และทำการ extend library โดยลองเขียน model ใหม่ๆ หรือ data transformation ใหม่ๆ ถ้าใครมี GPU มากกว่า 1 ตัวก็จะสามารถใช้งาน multi-GPUs training ได้อีกด้วย