ทำ NER ภาษาไทย โดยใช้ Transformers Model จาก Hugging Face

Isada Sukprapa
Super AI Engineer
Published in
4 min readMar 27, 2021

Hi, วันนี้ผมจะมาสอนทำ supervised learning คือ NER tagging โดยใช้ Transformers model จาก Library ใน HuggingFace ว่าด้วยเหตุผลที่ผมต้องการเขียนเรื่องนี้ขึ้นมา เพราะว่าเห็นตอนนี้บทความใน medium ที่สอนการทำ NER tagging ที่เป็น ภาษาไทยล่าสุดยังคงใช้ตัว CRF-BiLSTM อยู่ อย่างที่ทุกคนทราบดีว่าตอนนี้เทรนด์ในการนำโมเดล Transformers มาประยุกต์ในงาน NLP ถือว่าเป็นเรื่องปกติมาก จึงคิดบทความนี้น่าจะเป็นประโยชน์ต่อผู้สนใจครับ

NER tagging. Source

NER คืออะไร

ผมเชื่อว่าหลายท่านที่อยู่ในแวดวง NLP คงรู้จัก NER กันดีครับ NER มากจาก Named Entity Recognition หรือการรู้จำคำเฉพาะ ตัวอย่าง NE ก็คืออย่างจำพวกชื่อ หน่วยงาน ชื่อคน วันที่ สถานที่ หรือชื่อกระทรวง เชื่อว่าหลายท่านคงมีคำถามตามมาว่า

แล้วเราสกัด NEไปเพื่ออะไร ?

จริงๆการกำกับ NE มีประโยชน์มากในแง่ของการวิเคราห์ข้อมูล ที่เป็นจำพวกบทความหรือ text ยกตัวอย่างในงานด้าน biomedical ก็มีรายงานใช้ NER เพื่อตรวจจับชื่อของ Gene หรือ DNA หรืออย่างในการทำ Information Retrieval การกำกับ NE สามารถช่วย search engine ให้มีประสิทธิภาพมากขึ้น ทั้งนี้ในงานที่ผมกำลังทำในส่วนของ Machine Translation การtag NE ก็เพื่อแก้ปัญหา rare-word เนื่องจาก machine ไม่สามารถแปลคำที่ไม่เคยถูกเทรนมาก่อนได้

ในเมื่อเกริ่นมาสักพักแล้วก็ได้เวลาลงมือครับ โดยบทความนี้จะใช้ Google Colab ในการ implement เพื่อให้สามารถทำตามได้ง่าย ทั้งนี้ Google Colab ยังมี GPU ด้วย สำคัญมากๆในการเทรน Transformers ครับ

โดยโค้ดส่วนใหญ่จะเอามากจาก Token Classificaion Example สามารถไปอ่านเพิ่มเติมได้ครับ

0. Preparing Colab

  1. เข้าไปที่ https://colab.research.google.com/ > create a new notebook
  2. ทำการเปลี่ยนไปใช้ GPU โดย Runtime > Change Runtime Type > เลือก GPU
  3. (อันนี้เป็นทางเลือกนะครับ) ทำการ mount drive ด้วยเพื่อเราอยาก save model หรือ dataset ไว้
ภาพตัวอย่าง Change Runtime Type

1. Loading Dataset

ในส่วนของ dataset ที่เราจะใช้กันคือ LST20 จากแลป LST ใน NECTEC โดยdatsetตัวนี้มี format เป็น CONLL-2003

  1. เข้าไปที่ website AI for Thai
  2. ทำการ login / sign-in
  3. สามารถไปโหลด ได้ที่ Corpus
lst20 บน AIforThai

4. เมื่อโหลดเสร็จแล้วให้โยนทั้งก้อนไปที่ colab ครับ

ให้คลิ๊กที่ปุ่มอัปโหลด

2. Preprocessing

  1. ทำการ unzip lst20 และ pip install สิ่งที่ต้องใช้

2. import library ทั้งหมด

จากที่เรา import มา คือ เราจะใช้ AutoModel กับ AutoTokenizer โดยทั้งสองตัวนี้จะช่วย auto deploy model บน huggingface โดยเราไม่จำเป็นต้องไปหา class ของ โมเดลเอง สมมุติว่า ถ้าเราใช้ โมเดล pretrained เป็น RoBERTa ตัว AutoModel ก็จะไปหา class RoBERTa มา return ให้เอง โดยหลักการหลังจากนี้คือเราก็จะ fine-tune model ต่อ

3. ทำการ declare โมเดล และ โหลด lst20

ก่อนจะไปข้อต่อไป อยากให้ลองเล่นกับ DatasetDict ก่อน

จะเห็นว่าเรามี train set = 63310, validate set = 5620, test set = 5250 ค่อนข้างเยอะทีเดียว ไหนลองมาดูข้างในแต่ล่ะอันหน่อยสิ

โอเค พวก ner_tags ก็จะเป็นตัวเลข ถ้าอยากรู้ว่ามันคืออะไร ให้เราปริ้น feature name ดู

สรุปเรามี 31 NE tags ถ้าใครอยากรู้ว่าแต่ล่ะ tag มีความหมายอย่างไง ให้ไปตำต่อที่ LST20_guideline ครับ

ก่อนไปต่อ กำหนด variable feature names สักนิด สำหรับเอาไปใช้ในการเทรน

3. Tokenizer

ในการ fine-tuning เราจำเป็นต้องมี tokenizer ตัว tokenizer จะช่วยในการตัด sequence ตั้งแต่ระดับวลี ไปถึงระดับตัวอักษร ขึ้นกับว่า pretrained ตัวนี้เทรนมาแบบไหน จากเท่าที่ดู เหมือนว่า “Geotrend/bert-base-th-cased” จะถูกเทรนมาแบบ multi-language ทำให้ tokenizer อาจมีระดับย่อยถึง 1 character งั้นมาลองดูกัน

อันนี้ลองเปรียบเทียบ input ids ของสองประโยค ประโยคล่างมีการตัดคำ ส่วนประโยคบนไม่ได้ตัด (id 11, 12 หมายถึงเริ่มต้นและจบของประโยค) ถึงแม้ว่าจัดตัดคำต่างกัน แต่สองประโยชน์เป็นประโยคเดียวกัน ทว่ามี input ids ไม่เหมือนกัน ไหนเราลองดูสิความหมายมันต่างกันอย่างไร

เครื่องหมาย ## หมายถึง subword การที่ [‘ผ’ , ‘##ม’] หมายความว่า ‘ผ’ กับ ‘ม’ ควรจะติดกันเป็นคำเดียวกัน

4. Aligning Labels

ตอนนี้ text ที่ถูก tokenized ด้วย Tokenizer มี lengthไม่เท่ากับ length ของ NE tags หมายความว่า ตัวอย่าง ประโยค ก. ว่าด้วย “นายกคือประยุทธ์” ซึ่งมีเฉลยแท็กคือ [11, 0, 0, 8, 12] (11,12 = Begin, End ของ text) เมื่อ Tokenizer ตัดประโยค ก. แล้ว จะได้ [‘นา’, ‘##ยก’, ‘คือ’, ‘ประ’, ‘##ยุทธ์’] ดังนั้นเราต้อง align เฉลยแท๊กใหม่ ก็คือ [11, 0, 0, 0, 8, 8, 12] เป็นต้น

เราเลยจำเป็นต้อง align label ใหม่

อันนี้คือ simple version ของการ align labels แต่จะเห็นได้ว่า ตอนนี้ length ของ label และ tokenized_input มีขนาดเท่ากันแล้ว เราสามารถใช้ประโยชน์จาก word_ids() ได้โดยเอาไป map กับ label ที่ควรจะเป็น

โอเคมาเขียน function สำหรับ pre-process กัน

หลักการทำงานของ function นี้คือ align label โดยทำให้ input ที่ถูก tokenize มี ner tags เหมือนก่อนที่จะถูก tokenize และมี label เริ่มต้นกับสุดท้ายให้เป็น -100 (ไม่ถูกนำมาคิด loss)

ต่อไปนำมา map กับ dataset

5. Fine-tuning Model

ก่อนอื่นเราต้อง load model มาก่อน โดยโมเดลที่เราใช้คือ “Geotrend/bert-base-th-cased” หรือ BERT model นั้นเอง ความง่ายของ AutoModel ของ huggingface คือเราสามารถ deploy ได้เลยไม่ยุ่งยาก

ของที่เราต้องใช้ ในการ fine-tuning model หลักๆเราต้องมี 3 functions ได้แก่ TrainingArguments, DataCollator, ComputationMetrics

เริ่มจาก TrainingArguments ก่อน TrainingArguments คือ การกำหนด parameters สำหรับ fine-tuning model เราสามารถกำหนด TrainingArguments ได้ดังต่อไปนี้

TrainingArguments สำคัญมากครับ โมเดลเราจะ converge เร็ว converge ช้าขึ้นอยู่ parameters และ มันสามารถปรับเพิ่มอะไรได้อีกเยอะ แน่ะนำให้ไปตำต่อที่นี้ครับ

Data Collator

Data Collator เป็น function ที่ทำให้ covert dataset จาก list ให้เป็น batch tensors ครับ สามารถเรียกใช้ได้ง่ายๆต่อไปนี้

Computation Metrics

อันนี้เอามาวัดผลของการ fine-tuning เราใช้ seqeval ซึ่งเป็น libary หนึ่งที่นิยมนำมาใช้กับการวัดผล งานพวก sequence tagging ครับ

ก่อนอื่นทำการโหลด seqeval ก่อน

เราลองมาทดลอง function compute จาก seqeval กันก่อน (เนื่องจาก format ทำให้ seqeval จะแจ้งเตือน ถ้าเราใช้ ‘_’ แทน ‘-’ เพราะงั้นเลยต้อง replace ขจัดความรกหูรกตา)

ทีนี้เราต้องมาเขียน function compute_metics เอง โดยรับ predictions มาจาก model เพื่อทำการ evaluate

หลังจากเรามี functions ทั้งหมดแล้วก็พร้อมที่จะ fine-tuning model แล้วครับ โดย function ที่เราจะใช้คือ Trainerครับ

เราสามารถเริ่มเทรนได้ด้วยการ call trainer.train() ในการ train ค่อนข้างใช้เวลานานมากๆ 1 epoch ประมาณ 30–40 นาทีครับ

โดยทุกๆ epoch เราจะได้ผลประมาณนี้

เราสามารถ evaluate model ได้ด้วยคำสั่ง

ตัวอย่างผลลัพธ์

นอกนั้น เราสามารถทดลอง ให้ model ทำการ predict testset จากการ modify ฟังชั่น compute_mertics ได้เหมือนกัน

โดยผลลัพธ์ก็จะออกมามี format เหมือนกับผล evaluate ครับ ทีนี้ในการเทรน Transformers ให้ออกมาเก่งจำเป็นต้อง train เยอะๆ epoch อย่างน้อยก็ต้องมี 20–30 epochs ถึงจะให้ผลดี ซึ้งใช้เวลาค่อนข้างนาน อยากให้ไปลองดูกัน

สุดท้ายนี้ถ้ารู้สึกว่าเทรนพอแล้ว หรืออยากเก็บไว้มาเทรนต่อวันอื่น ผมแน่ะนำให้ทำการ save pretrained สามารถอ่านต่อได้ ตรงนี้ครับ

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

--

--