0
1

gpt2-large-japanese-charは『雪国』の冒頭をどうトークナイズするのか

Last updated at Posted at 2024-01-09

昨年12月27日に京都大学言語メディア研究室から、日本語GPT-2モデルgpt2-large-japanese-charが発表された。モデル名の末尾がcharなので、たぶん単文字トークナイザを使っているようだ。ちょっと試してみよう。

>>> from transformers import AutoTokenizer
>>> tkz=AutoTokenizer.from_pretrained("ku-nlp/gpt2-large-japanese-char")
>>> print(tkz.convert_ids_to_tokens(tkz("国境の長いトンネルを抜けると雪国であった。","夜の底が白くなった。")["input_ids"]))
['åĽ½', 'å¢ĥ', 'ãģ®', 'éķ·', 'ãģĦ', 'ãĥĪ', 'ãĥ³', 'ãĥį', 'ãĥ«', 'ãĤĴ', 'æĬľ', 'ãģij', 'ãĤĭ', 'ãģ¨', 'éĽª', 'åĽ½', 'ãģ§', 'ãģĤ', 'ãģ£', 'ãģŁ', 'ãĢĤ', 'å¤ľ', 'ãģ®', 'åºķ', 'ãģĮ', 'çĻ½', 'ãģı', 'ãģª', 'ãģ£', 'ãģŁ', 'ãĢĤ']

う、「国」が「åĽ½」ということは、もしや

>>> text="国境の長いトンネルを抜けると雪国であった。夜の底が白くなった。"
>>> x=tkz(text,return_offsets_mapping=True)
>>> for i,(s,e) in zip(x["input_ids"],x["offset_mapping"]):
...   print(text[s:e],text[s:e].encode("utf-8"),ascii(tkz.convert_ids_to_tokens(i)))
... 
国 b'\xe5\x9b\xbd' '\xe5\u013d\xbd'
境 b'\xe5\xa2\x83' '\xe5\xa2\u0125'
の b'\xe3\x81\xae' '\xe3\u0123\xae'
長 b'\xe9\x95\xb7' '\xe9\u0137\xb7'
い b'\xe3\x81\x84' '\xe3\u0123\u0126'
ト b'\xe3\x83\x88' '\xe3\u0125\u012a'
ン b'\xe3\x83\xb3' '\xe3\u0125\xb3'
ネ b'\xe3\x83\x8d' '\xe3\u0125\u012f'
ル b'\xe3\x83\xab' '\xe3\u0125\xab'
を b'\xe3\x82\x92' '\xe3\u0124\u0134'
抜 b'\xe6\x8a\x9c' '\xe6\u012c\u013e'
け b'\xe3\x81\x91' '\xe3\u0123\u0133'
る b'\xe3\x82\x8b' '\xe3\u0124\u012d'
と b'\xe3\x81\xa8' '\xe3\u0123\xa8'
雪 b'\xe9\x9b\xaa' '\xe9\u013d\xaa'
国 b'\xe5\x9b\xbd' '\xe5\u013d\xbd'
で b'\xe3\x81\xa7' '\xe3\u0123\xa7'
あ b'\xe3\x81\x82' '\xe3\u0123\u0124'
っ b'\xe3\x81\xa3' '\xe3\u0123\xa3'
た b'\xe3\x81\x9f' '\xe3\u0123\u0141'
。 b'\xe3\x80\x82' '\xe3\u0122\u0124'
夜 b'\xe5\xa4\x9c' '\xe5\xa4\u013e'
の b'\xe3\x81\xae' '\xe3\u0123\xae'
底 b'\xe5\xba\x95' '\xe5\xba\u0137'
が b'\xe3\x81\x8c' '\xe3\u0123\u012e'
白 b'\xe7\x99\xbd' '\xe7\u013b\xbd'
く b'\xe3\x81\x8f' '\xe3\u0123\u0131'
な b'\xe3\x81\xaa' '\xe3\u0123\xaa'
っ b'\xe3\x81\xa3' '\xe3\u0123\xa3'
た b'\xe3\x81\x9f' '\xe3\u0123\u0141'
。 b'\xe3\x80\x82' '\xe3\u0122\u0124'

ううう、UTF-8のByte-Pair Encodingがナマで使われてる(ただし0x00~0x20・0x7f~0x9fはU+0100~U+0120・U+0121~U+0141へマッピング)。decodeは実装されてるかしら。

>>> print([tkz.decode(t) for t in x["input_ids"]])
['国', '境', 'の', '長', 'い', 'ト', 'ン', 'ネ', 'ル', 'を', '抜', 'け', 'る', 'と', '雪', '国', 'で', 'あ', 'っ', 'た', '。', '夜', 'の', '底', 'が', '白', 'く', 'な', 'っ', 'た', '。']

decodeが準備されてるので、とりあえず何とかなりそうだ。ただ、常用漢字表2136字は、どの程度サポートしているのだろう。

>>> import urllib.request
>>> with urllib.request.urlopen("https://www.unicode.org/wg2/iso10646/edition6/data/JapaneseCoreKanji.txt") as r:
...   k=[chr(int(t,16)) for t in r.read().decode().strip().split("\n") if not t.startswith("#")]
...
>>> for i,j in zip(k,tkz(k)["input_ids"]):
...   if len(j)>1:
...     print(i,tkz.convert_ids_to_tokens(j))
...
剝 ['åī', 'Ŀ']
塡 ['å¡', '¡']
頰 ['éł', '°']
𠮟 ['ð', 'ł', '®', 'Ł']

「剝」「塡」「頰」「𠮟」の4字がサポートされておらず、いずれも複数のトークンに泣き別れとなっている。うーん、「剝」「塡」「頰」は2トークンなので、mergesを追加すれば何とかなりそうだけど、「𠮟」を救うのは無理かなあ。それともReplace("𠮟","叱")normalizerに入れるべきかなあ。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1