ใน ep นี้เราจะมาศึกษาอีก Concept นึงที่สำคัญของ NLP คือ Language Model หรือ โมเดลของภาษา ซึ่งถ้าโมเดลของเรามีความสามารถที่จะเข้าใจภาษาโดยภาพรวมได้ดีระดับหนึ่งแล้ว ก็จะส่งผลให้โมเดลนั้นทำงานเฉพาะทาง เช่น ClassificationSentiment Analysis, Machine Translation, Question-Answer ได้ดีขึ้นไปด้วยในตัว

Language Model คืออะไร

Parse tree of the English phrase "John loves Mary" using the Grammatical Framework (GF) shell command 'vp'. Credit https://commons.wikimedia.org/wiki/File:Parse_tree_-_English.png
Parse tree of the English phrase “John loves Mary” using the Grammatical Framework (GF) shell command ‘vp’. Credit https://commons.wikimedia.org/wiki/File:Parse_tree_-_English.png

Language Model คือ โมเดลว่าภาษานั้นเป็นอย่างไร ในทางสถิติคือ Probability Distribution ของลำดับของคำต่าง ๆ ว่าน่าจะเป็นคำอะไร เช่น ถ้าเราเข้าใจภาษาอังกฤษบ้าง เราก็จะพอเดาได้ว่าคำอะไรน่าจะอยู่ในช่องว่าง Somsak is a tall ______. และคำอะไรไม่น่าจะอยู่

ในทางปฏิบัติ เราสามารถใช้วิธี Bag-of-word ดูทีละคำ (Uni-Gram) ทีละหลาย ๆ คำ N-Gram ดูคำที่มาก่อน ดูคำที่มาทีหลัง หรือทั้งสองทิศทาง Bi-direction และใช้โมเดลคณิตศาสตร์ได้หลากหลาย

แต่ในเคสนี้ เราจะใช้ Neural Network แบบ Recurrent Neural Network – RNN แบบหนึ่ง เรียกว่า AWD_LSTM ที่ถูกเทรนด้วย Corpus ข้อความจาก Dumps Wikipedia ภาษาไทย โดยให้โมเดลเดาคำต่อไปเรื่อย ๆ (เป็น Label แบบ Self-supervised Learning)

เมื่อเราได้ Language Model จาก Wikipedia ภาษาไทย มาแล้ว เราสามารถใส่ข้อความภาษาไทยเริ่มต้นเข้าไปให้ Language Model เดาคำที่น่าจะเป็นคำต่อไป หรือก็คือ Generate Text สร้างข้อความใหม่ต่อ ๆ ไปได้

AWD_LSTM Model Architecture

DropConnect sets a randomly selected subset of weights within the network to zero. Credit https://arxiv.org/abs/1906.04569
DropConnect sets a randomly selected subset of weights within the network to zero. Credit https://arxiv.org/abs/1906.04569

AWD_LSTM เป็น LSTM / Recurrent Neural Network (RNN) แบบหนึ่ง ที่มีการใช้ DropOut / DropConnect หลากหลายแบบภายในส่วนต่าง ๆ ของโมเดล อย่างชาญฉลาด จะอธิบายต่อไป

An example model layout for a single DropConnect layer. Credit http://proceedings.mlr.press/v28/wan13.html
An example model layout for a single DropConnect layer. Credit http://proceedings.mlr.press/v28/wan13.html

เรามาเริ่มกันเลยดีกว่า

Open In Colab

ใน ep นี้เราจะมาศึกษาอีก Concept นึงที่สำคัญของ NLP คือ Language Model หรือ โมเดลของภาษา ซึ่งถ้าโมเดลของเรามีความสามารถที่จะเข้าใจภาษาโดยภาพรวมได้ดีระดับหนึ่งแล้ว ก็จะส่งผลให้โมเดลนั้นทำงานเฉพาะทาง เช่น Classification, Sentiment Analysis, Machine Translation, Question-Answer ได้ดีขึ้นไปด้วยในตัว

Language Model คืออะไร

Language Model คือ โมเดลว่าภาษานั้นเป็นอย่างไร ในทางสถิติคือ Probability Distribution ของลำดับของคำต่าง ๆ ว่าน่าจะเป็นคำอะไร เช่น ถ้าเราเข้าใจภาษาอังกฤษบ้าง เราก็จะพอเดาได้ว่าคำอะไรน่าจะอยู่ในช่องว่าง Somsak is a tall _. และคำอะไรไม่น่าจะอยู่

ในทางปฏิบัติ เราสามารถใช้วิธี Bag-of-word ดูทีละคำ (Uni-Gram) ทีละหลาย ๆ คำ N-Gram ดูคำที่มาก่อน ดูคำที่มาทีหลัง หรือทั้งสองทิศทาง Bi-direction และใช้โมเดลคณิตศาสตร์ได้หลากหลาย

แต่ในเคสนี้ เราจะใช้ Neural Network แบบ Recurrent Neural Network - RNN แบบหนึ่ง เรียกว่า AWD_LSTM ที่ถูกเทรนด้วย Corpus ข้อความจาก Dumps Wikipedia ภาษาไทย โดยให้โมเดลเดาคำต่อไปเรื่อย ๆ

เมื่อเราได้ Language Model จาก Wikipedia ภาษาไทย มาแล้ว เราสามารถใส่ข้อความภาษาไทยเริ่มต้นเข้าไปให้ Language Model เดาคำที่น่าจะเป็นคำต่อไป หรือก็คือ Generate Text สร้างข้อความใหม่ต่อ ๆ ไปได้

0. Install

In [1]:
! nvidia-smi
Wed May 27 15:23:24 2020       
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.82       Driver Version: 418.67       CUDA Version: 10.1     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  Tesla K80           Off  | 00000000:00:04.0 Off |                    0 |
| N/A   35C    P8    28W / 149W |      0MiB / 11441MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
                                                                               
+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

ติดตั้ง Library ที่จำเป็น

In [2]:
! pip install sklearn_crfsuite -q
! pip install https://github.com/PyThaiNLP/pythainlp/archive/dev.zip -q
! pip install fastai2 -q
! pip install emoji -q
     |████████████████████████████████| 747kB 4.2MB/s 
     - 22.8MB 138kB/s
  Building wheel for pythainlp (setup.py) ... done
     |████████████████████████████████| 194kB 2.8MB/s 
     |████████████████████████████████| 51kB 1.7MB/s 
  Building wheel for emoji (setup.py) ... done

1. Import

Import ในที่นี้เราจะใช้ PyThaiNLP และ fastai2 text

In [3]:
from fastai2.basics import *
from fastai2.text.all import *

from pythainlp.ulmfit import *
from pythainlp.tokenize import THAI2FIT_TOKENIZER
Corpus: wiki_lm_lstm
- Downloading: wiki_lm_lstm 0.32
100%|██████████| 1050919089/1050919089 [05:17<00:00, 3307292.88it/s]
Corpus: wiki_itos_lstm
- Downloading: wiki_itos_lstm 0.32
100%|██████████| 1530484/1530484 [00:07<00:00, 194956.20it/s]

2. Dummy Dataset

สั่ง Download Dummy Dataset ขนาดเล็ก มาสำหรับใช้สร้าง Model แต่เราจะไม่ได้ใช้ Dataset ส่วนนี้มาทำงานอะไร เพราะเป็นภาษาอังกฤษ

In [4]:
imdb = untar_data(URLs.IMDB_SAMPLE)
dummy_df = pd.read_csv(imdb/'texts.csv')

# dummy_df.head()

3. Data pipeline

เราจะกำหนด Tokenizer ตัวตัดคำภาษาไทย สำหรับใช้ใน Data pipeline ของ fastai2 ด้วยตัวตัดคำจาก pythainlp

In [0]:
class XThaiTokenizer():
    def __init__(self, lang: str = "th", split_char=' ', **kwargs): 
        self.split_char=split_char
        self.lang = lang

    def __call__(self, items): return (THAI2FIT_TOKENIZER.word_tokenize(t) for t in items)

    def add_special_cases(self, toks):
        pass

โหลด Vocab Dictionary ของ Wikipedia ภาษาไทย เตรียมเอาไว้ใส่ใน Data Pipeline เนื่องจากเราจะใช้ Pre-train Model เราจึงต้องใช้ Vocab เดียวกันกับโมเดลนั้น ๆ

In [6]:
thwiki_vocab = pickle.load(open(THWIKI_LSTM['itos_fname'],'rb'))

len(thwiki_vocab), thwiki_vocab[:20]
Out[6]:
(60005,
 ['xxunk',
  'xxpad',
  'xxbos',
  'xxfld',
  'xxmaj',
  'xxup',
  'xxrep',
  'xxwrep',
  ' ',
  '\n',
  'ใน',
  'ที่',
  'และ',
  'ของ',
  'เป็น',
  'มี',
  'ได้',
  'การ',
  '"',
  '('])

สร้าง Data Pipeline ด้วย fastai2 DataBlock API โดยใส่ tokenizer และ vocab จากด้านบน

In [0]:
imdb_lm = DataBlock(blocks=TextBlock.from_df('text', is_lm=True, tok_func=XThaiTokenizer, vocab=thwiki_vocab, sep=''),
                    get_x=ColReader('text'),    
                    splitter=ColSplitter())
In [0]:
# imdb_lm.summary(dummy_df, bs=64, seq_len=72)

สร้าง DataLoader จาก DataBlock

In [9]:
dls = imdb_lm.dataloaders(dummy_df, bs=64, seq_len=72)

เช็คขนาด Vocab ของ DataLoader อีกที จะเห็นว่าเท่ากันกับ Vocab จาก Wikipedia ภาษาไทย ที่เราโหลดมา

In [10]:
len(dls.vocab)
Out[10]:
60005

เราสามารถเรียก show_batch ดูข้อมูลได้ แต่เนื่องจาก Dataset ภาษาอังกฤษ แต่ตัดคำไทย Vocab Dictionary เป็นภาษาไทย อาจจะมีคำภาษาอังกฤษน้อย คำที่ไม่อยู่ใน Vocab ก็จะกลายเป็น UNK ไปหมด

In [0]:
# dls.show_batch(max_n=5)

4. Model

สร้าง Language Model Learning ด้วยโมเดล AWD_LSTM โดยกำหนด Hyperparameter ให้ตรงตาม Pre-trained คือ emb_sz=400, n_hid=1550, n_layers=4, pad_token=1 แต่ไม่ต้องโหลด Weight มาด้วย pretrained=False

In [0]:
# language_model_learner??
# AWD_LSTM??
In [0]:
config = dict(emb_sz=400, n_hid=1550, n_layers=4, pad_token=1, tie_weights=True, out_bias=True,
             output_p=0.25, hidden_p=0.1, input_p=0.2, embed_p=0.02, weight_p=0.15)

trn_args = dict(drop_mult=0.9, clip=0.12, alpha=2, beta=1)

learn = language_model_learner(dls, AWD_LSTM, config=config, pretrained=False, **trn_args)

ดูสถิติโมเดล

In [14]:
learn.summary()
Out[14]:
SequentialRNN (Input shape: ['64 x 72'])
================================================================
Layer (type)         Output Shape         Param #    Trainable 
================================================================
RNNDropout           64 x 72 x 400        0          False     
________________________________________________________________
RNNDropout           64 x 72 x 1550       0          False     
________________________________________________________________
RNNDropout           64 x 72 x 1550       0          False     
________________________________________________________________
RNNDropout           64 x 72 x 1550       0          False     
________________________________________________________________
Linear               64 x 72 x 60005      24,062,005 True      
________________________________________________________________
RNNDropout           64 x 72 x 400        0          False     
________________________________________________________________

Total params: 24,062,005
Total trainable params: 24,062,005
Total non-trainable params: 0

Optimizer used: <function Adam at 0x7f79745136a8>
Loss function: FlattenedLoss of CrossEntropyLoss()

Callbacks:
  - TrainEvalCallback
  - Recorder
  - ProgressCallback
  - ModelReseter
  - RNNRegularizer

5. Load Pretrained Model

โหลด Weight และ Vocab ของ Pre-trained Model จากใน pythainlp.ulmfit เราจะได้โมเดลที่เข้าใจ ภาษาไทยใน Wikipedia มาเรียบร้อย

In [0]:
# THWIKI_LSTM??
In [16]:
learn.load_pretrained(THWIKI_LSTM['wgts_fname'], THWIKI_LSTM['itos_fname'])
Out[16]:
<fastai2.text.learner.LMLearner at 0x7f790e8e6dd8>

6. Generate Text

เมื่อเราได้โมเดลที่โหลดทุกอย่างเรียบร้อย พร้อมทำงาน เราจะมาลอง Generate Text กัน

ตัวอย่าง 1

In [29]:
print(learn.predict('ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ', 200, temperature=0.8))
 ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อพุทธศตวรรษที่ 24 เมื่อสมัยกรุงศรีอยุธยาเป็นราชธานี โดยมีพระเจ้าปราสาททองเป็นครองราชย์ ส่วนสมเด็จพระเจ้ากรุงธนบุรีเป็นกษัตริย์แห่งกรุงศรีอยุธยา คือ พระเจ้าอู่ทอง พระราชโอรสของสมเด็จพระนารายณ์มหาราช 
 
  สมัยอยุธยา. 
 สมัยกรุงศรีอยุธยา หลังคริสต์ศตวรรษที่ 17 เมืองอยุธยาได้ถูกทำลายเสียหมดแล้ว โดยกรุงศรีอยุธยาถูกยกให้เป็นเมืองประเทศราชของกรุงศรีอยุธยาเมืองลพบุรี มีการสร้างกำแพงเมือง ตลอดจนป้อมปราการ จนกระทั่งถึงสมัยกรุงรัตนโกสินทร์ เมื่อ พ.ศ. 1956 สมัยที่พระเจ้ากรุงธนบุรีทรงสถาปนากรุงศรีอยุธยาขึ้น พระเจ้าติโลกราชทรงพยายามทำทั้ง 2 ด้านให้ทันสมัย พระองค์ทรงออกแบบเมืองไทยให้มีขนาดใหญ่กว่าเดิม มีตัวอาคารกว้าง 15 เมตร ยาว 75 เมตร และมีการสร้างซุ้มประตูล้อมรอบ ได้มีการสร้างบันไดเรือ (phantom หินย้อย) สำหรับสร้างสะพาน 
 
 ต่อมาในรัชสมัยของสมเด็จพระรามาธิบดีที่ 1 แห่งสยาม พระองค์ทรงถูกยกทัพเข้ามา

ตัวอย่าง 2

Generate 5 ครั้ง เพื่อเปรียบเทียบ

In [30]:
TEXT = "ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ"
N_WORDS = 50
N_SENTENCES = 5

preds = [learn.predict(TEXT, N_WORDS, temperature=0.6) 
         for _ in range(N_SENTENCES)]

preds
Out[30]:
[' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ พ.ศ. 2511 โดย พระยาพหลพลพยุหเสนา (พจน์ พหลโยธิน) ซึ่งเป็นผู้ที่ได้เป็นผู้นำในการสร้างทางรถไฟสายใต้ และการสร้างทางรถไฟสายใต้ (สาย สระบุรี-บางขุนเทียน) \n',
 ' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ พ.ศ. 2534 ระหว่าง ไทยกับฝรั่งเศส (พ.ศ. 2533-2532) โดยการส่งกำลังทหารไปโจมตีญี่ปุ่น \n \n การยึดครองประเทศไทย. \n หลังจากญี่ปุ่นพ่ายแพ้สงคราม ญี่ปุ่นก็ออกปฏิบัติการในด้าน',
 ' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ พ.ศ. 2446 โดย จอมพล ป.พิบูลสงคราม และ จอมพลสฤษดิ์ ธนะรัชต์ ได้เดินทางมายังกรุงเทพมหานคร เพื่อร่วมรบในสงครามอินโดจีนครั้งที่หนึ่ง ซึ่งในช่วงนั้น ทหารญี่ปุ่นได้ทำสงคราม กับกองทัพญี่ปุ่น และ กองทัพญี่ปุ่น',
 ' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ พ.ศ. 2477 โดยจอมพล ป. เป็นนายกรัฐมนตรี และได้มีการจัดตั้ง "สภาพัฒนาการเศรษฐกิจแห่งชาติ" ขึ้น โดยองค์กรที่มีหน้าที่รับผิดชอบในการจัดตั้ง "สภาพัฒนาการเศรษฐกิจแห่งชาติ" ขึ้น โดยมี ',
 ' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ พ.ศ. 2473 โดย พระยาบรมราชภักดี (หม่อมหลวงเฟื้อ พึ่งบุญ) และ พระยาทรงสุรเดช (บุญรอด โกมารกุล ณ นคร) ได้ร่วมกันสร้าง "อนุสาวรีย์พระบาทสมเด็จ']

ตัวอย่าง 3

เราสามารถปรับ temperature เพื่อให้ได้คำที่หลากหลายยิ่งขึ้น

In [31]:
TEXT = "ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ"
N_WORDS = 50
N_SENTENCES = 5

preds = [learn.predict(TEXT, N_WORDS, temperature=0.9) 
         for _ in range(N_SENTENCES)]

preds
Out[31]:
[' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อกรุงเทพฯ ได้ส่งเรือลงไปสำรวจป่า และเยี่ยมชมเกาะโบราณแห่งหนึ่งที่ยังมีนกที่เพิ่งดั้งเดิมมาร่วม 10 ตัว จึงคิดเลือกว่าจะตั้งชื่อประเทศว่า "ประเทศไทย" ครั้งหนึ่ง old s.s',
 ' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ \n \n พ.ศ. 2515  ทหารเขมรแดงได้เคลื่อนขบวนไปยังบ้านหลวงพระบาง และได้รู้จักข้าราชการ และวีรบุรุษในรัฐบาลไทย ที่จับมาแต่ต้น โดยไม่สนใจความวุ่นวายใดๆ แต่ไม่ยอมจำนนขึ้นไปยังประเทศ',
 ' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อปี 2531 นับตั้งแต่ พล.ต.ท.หริส" เทพหัสดิน ณ อยุธยา ผู้บัญชาการตำรวจแห่งชาติ เป็นต้นมา และ ดร. รื่น สุวรรณนะ หัวหน้าคณะในพันธ์ไทยรัฐบาลได้จัดตั้ง "กองทุนร่วมกู้วัฒนธรรมไทย" ที่',
 ' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ พ.ศ. 2458 เมื่อ ปรีดี พนมยงค์ ได้รับเชิญจากหนังสือพิมพ์สยามรัฐให้เดินทางไปสำรวจสถานที่ ณ เมืองบัควิลล์ รัฐควิเบก สหรัฐอเมริกา โดยได้ส่งตัวอย่าง มะนิลา ',
 ' ประวัติศาสตร์ไทย เริ่มต้นขึ้นเมื่อ เขามิชชันนารีdi อภัยวงศ์ ได้พัฒนาพระพุทธศาสนาเป็นศาสนสถานที่สำคัญและมีจำนวนประชากรมากที่สุดในโลก เมื่อ พ.ศ. 2528 การสร้างวัดไทยต่อจากพุทธศาสนา ในทางการเมือง เป็นส่วนหนึ่งของการเผยแพร่พระพุทธศาสนาในประเทศไทย ']

Credit

In [0]:
 

แชร์ให้เพื่อน:

Keng Surapong on FacebookKeng Surapong on GithubKeng Surapong on Linkedin
Keng Surapong
Project Manager at Bua Labs
The ultimate test of your knowledge is your capacity to convey it to another.

Published by Keng Surapong

The ultimate test of your knowledge is your capacity to convey it to another.

Enable Notifications    Ok No thanks