私(安岡孝一)の「camembert-thai-base」のトークナイザを使って、JonusNattapongが「Hanuman」というタイ語生成モデルを公開した。ただ、タイ語生成モデルのトークナイザとしては、ちょっとマズイことになっている。Google Colaboratoryで「Hanuman」を動かしてみよう。
!pip install transformers triton
from transformers import pipeline
nlp=pipeline("text-generation","JonusNattapong/Hanuman",trust_remote_code=True,revision="d9d931b69eae6f336cb5ee6e097990af812fe16e")
print(nlp("เมืองที่ใหญ่เป็นอันดับ 3 ของประเทศไทยคือเมืองใด",max_new_tokens=128))
「เมืองที่ใหญ่เป็นอันดับ 3 ของประเทศไทยคือเมืองใด」の続きを生成させたところ、私の手元では以下の結果が得られた。
[{'generated_text': 'เมืองที่ใหญ่เป็นอันดับ 3 ของประเทศไทยคือเมืองใดในที่าของในกับคําในที่คําการการศาสตร์การโดยในการได้าประเทศในและเป็นการคความในปีในในและความและการสและเป็นของเป็นในสปีจากพศาได้พศการคือและเป็นในการทางมีในาเป็นเป็นมีเป็นลของนคือยของของมีของการการคโดยที่จากการการในภาษาภาษาซึ่งการการที่เป็น'}]
空白も改行も全く生成されない。それもそのはず、「camembert-thai-base」のpre_tokenizerはWhitespace()
であり、空白も改行も剝ぎ取られてしまって、言語モデルには渡されない。トークナイザの中身をちょっとみてみよう。
print(nlp.tokenizer.backend_tokenizer)
print(nlp.tokenizer.convert_ids_to_tokens(nlp.tokenizer.convert_tokens_to_ids([" ","\n","▁"])))
トークナイザの中身は、こんな感じ。
Tokenizer(version="1.0", truncation=None, padding=None, added_tokens=[{"id":0, "content":"<s>NOTUSED", "single_word":False, "lstrip":False, "rstrip":False, ...}, {"id":1, "content":"<pad>", "single_word":False, "lstrip":False, "rstrip":False, ...}, {"id":2, "content":"</s>NOTUSED", "single_word":False, "lstrip":False, "rstrip":False, ...}, {"id":3, "content":"<unk>", "single_word":False, "lstrip":False, "rstrip":False, ...}, {"id":5, "content":"<s>", "single_word":False, "lstrip":False, "rstrip":False, ...}, ...], normalizer=Sequence(normalizers=[Nmt(), NFKC(), Lowercase()]), pre_tokenizer=Whitespace(), post_processor=TemplateProcessing(single=[SpecialToken(id="<s>", type_id=0), Sequence(id=A, type_id=0), SpecialToken(id="</s>", type_id=0)], pair=[SpecialToken(id="<s>", type_id=0), Sequence(id=A, type_id=0), SpecialToken(id="</s>", type_id=0), SpecialToken(id="</s>", type_id=0), Sequence(id=B, type_id=0), ...], special_tokens={"</s>":SpecialToken(id="</s>", ids=[6], tokens=["</s>"]), "<s>":SpecialToken(id="<s>", ids=[5], tokens=["<s>"])}), decoder=WordPiece(prefix="", cleanup=True), model=Unigram(unk_id=3, vocab=[("<s>NOTUSED", 0), ("", 0), ("</s>NOTUSED", 0), ("<unk>", 0), ("<unk>NOTUSED", -1200), ...], byte_fallback=False))
['<unk>', '<unk>', '▁']
全体にBERT系トークナイザで、空白も改行もvocabに含まれてないので、無理に渡しても<unk>になってしまう。ただ、metaspace (U+2581)はvocabに含まれているので、pre_tokenizerをMetaspace(prepend_scheme="never")
に、decoderをMetaspace()
に置き換える手はアリだと思う。でも、その方法でも、改行は空白に化けてしまうので、やはり、もう少しタイ語生成モデル向けにトークナイザを改造した上で、モデルを再トレーニングした方がいいと思う。
from tokenizers import pre_tokenizers,decoders
nlp.tokenizer.backend_tokenizer.pre_tokenizer=pre_tokenizers.Metaspace(prepend_scheme="never")
nlp.tokenizer.backend_tokenizer.decoder=decoders.Metaspace()
nlp.tokenizer.save_pretrained("modified_tokenizer")