Thodsaporn Chay-intr, Hidetaka Kamigaito, Manabu Okumura『Character-Based Thai Word Segmentation with Multiple Attentions』を読んでいて、Character-Basedの意味するところに多少悩んでしまった。というのも、この論文では、いわゆる単文字トークナイザを想定していて、母音や声調記号すら1文字とみなして切ってしまうようなのだ。Figure 1の例文「มี ๓ ความหมาย」をpython3で見てみよう。
>>> sample="มี ๓ ความหมาย"
>>> print([c for c in sample if not c.isspace()])
['ม', 'ี', '๓', 'ค', 'ว', 'า', 'ม', 'ห', 'ม', 'า', 'ย']
「มี」が2文字に別れていて、非常に気持ちが悪い。このあたりに対してUnicode Standard Annex #29では、書記素クラスター(grapheme cluster)というのが規定されていて、もう少し普通に切ってくれる。pyuegcの助けを借りてみよう。
>>> import pyuegc
>>> print([c for c in pyuegc.EGC(sample) if not c.isspace()])
['มี', '๓', 'ค', 'ว', 'า', 'ม', 'ห', 'ม', 'า', 'ย']
あるいは、タイ語固有のアイデアとしては、タイ文字クラスター(คลัสเตอร์อักษรไทย)というのが30年以上前に提案されていて、Hugging Face / tokenizersだと、pre_tokenizersで簡単に実装できる。ちょっと見てみよう。
>>> from tokenizers import pre_tokenizers as pre,Regex
>>> tcc=pre.Sequence([pre.Whitespace(),pre.Split(Regex("[\u0e40-\u0e44]?[\u0e01-\u0e2e][\u0e30-\u0e3a\u0e45\u0e47-\u0e4e]*|."),"isolated")])
>>> print(tcc.pre_tokenize_str(sample))
[('มี', (0, 2)), ('๓', (3, 4)), ('ค', (5, 6)), ('วา', (6, 8)), ('ม', (8, 9)), ('ห', (9, 10)), ('มา', (10, 12)), ('ย', (12, 13))]
この論文『Character-Based Thai Word Segmentation with Multiple Attentions』は、タイ文字クラスターには言及しているが、書記素クラスターには言及がない。結果として、タイ文字クラスターの要約ベクトルを、単文字トークナイザから頑張ってアテンション機構で組む、という大技になっている。まあ、それはそれで面白いのだけど、1文あたりのトークン数が長くなっちゃうので大変だなぁ。