Swallow-MSは『雪国』の冒頭をどうトークナイズするのか

Mistralベースの日本語モデル「[Swallow-MS](https://huggingface.co/tokyotech-llm/Swallow-MS-7b-v0.1)」が、[3月11日にリリースされた](https://zenn.dev/tokyotech_lm/articles/3f71df3cd2e589)。ざっと見てみたところ、モデルそのものはMistralForCausalLMなのだが、トークナイザはLlamaTokenizerを借りているようだ。ちょっと試してみよう。

```
>>> from transformers import AutoTokenizer
>>> tkz=AutoTokenizer.from_pretrained("tokyotech-llm/Swallow-MS-7b-v0.1")
>>> print(tkz)
LlamaTokenizerFast(name_or_path='tokyotech-llm/Swallow-MS-7b-v0.1', vocab_size=42800, model_max_length=1000000000000000019884624838656, is_fast=True, padding_side='left', truncation_side='right', special_tokens={'bos_token': '
', 'eos_token': '
', 'unk_token': '<unk>'}, clean_up_tokenization_spaces=False),  added_tokens_decoder={
        0: AddedToken("<unk>", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
        1: AddedToken("
", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
        2: AddedToken("
", rstrip=False, lstrip=False, single_word=False, normalized=False, special=True),
}
>>> print(tkz.convert_ids_to_tokens(tkz("国境の長いトンネルを抜けると雪国であった。","夜の底が白くなった。")["input_ids"]))
['
', '▁', '国境', 'の', '長い', 'トンネル', 'を', '抜ける', 'と', '雪', '国', 'で', 'あっ', 'た', '。', '
', '▁', '夜', 'の', '底', 'が', '白く', 'なっ', 'た', '。']
```

「Swallow」より`vocab_size`が小さくなっているものの、トークナイズ結果は[「Swallow」と同様](https://qiita.com/KoichiYasuoka/items/60c44df1740efb38e04e)、いいセンだ。では、[常用漢字表2136字](https://www.bunka.go.jp/kokugo_nihongo/sisaku/joho/joho/kijun/naikaku/kanji/)は、どの程度サポートしているのだろう。

```
>>> 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)>3:
...     print(i,tkz.convert_ids_to_tokens(j))
...
丙 ['
', '▁', '<0xE4>', '<0xB8>', '<0x99>']
倹 ['
', '▁', '<0xE5>', '<0x80>', '<0xB9>']
儒 ['
', '▁', '<0xE5>', '<0x84>', '<0x92>']
剝 ['
', '▁', '<0xE5>', '<0x89>', '<0x9D>']
劾 ['
', '▁', '<0xE5>', '<0x8A>', '<0xBE>']
厘 ['
', '▁', '<0xE5>', '<0x8E>', '<0x98>']
吏 ['
', '▁', '<0xE5>', '<0x90>', '<0x8F>']
嘲 ['
', '▁', '<0xE5>', '<0x98>', '<0xB2>']
塡 ['
', '▁', '<0xE5>', '<0xA1>', '<0xA1>']
墾 ['
', '▁', '<0xE5>', '<0xA2>', '<0xBE>']
嫡 ['
', '▁', '<0xE5>', '<0xAB>', '<0xA1>']
帥 ['
', '▁', '<0xE5>', '<0xB8>', '<0xA5>']
庸 ['
', '▁', '<0xE5>', '<0xBA>', '<0xB8>']
弐 ['
', '▁', '<0xE5>', '<0xBC>', '<0x90>']
恣 ['
', '▁', '<0xE6>', '<0x81>', '<0xA3>']
慄 ['
', '▁', '<0xE6>', '<0x85>', '<0x84>']
憬 ['
', '▁', '<0xE6>', '<0x86>', '<0xAC>']
憾 ['
', '▁', '<0xE6>', '<0x86>', '<0xBE>']
斤 ['
', '▁', '<0xE6>', '<0x96>', '<0xA4>']
斥 ['
', '▁', '<0xE6>', '<0x96>', '<0xA5>']
朕 ['
', '▁', '<0xE6>', '<0x9C>', '<0x95>']
楷 ['
', '▁', '<0xE6>', '<0xA5>', '<0xB7>']
殉 ['
', '▁', '<0xE6>', '<0xAE>', '<0x89>']
沃 ['
', '▁', '<0xE6>', '<0xB2>', '<0x83>']
淫 ['
', '▁', '<0xE6>', '<0xB7>', '<0xAB>']
漸 ['
', '▁', '<0xE6>', '<0xBC>', '<0xB8>']
璽 ['
', '▁', '<0xE7>', '<0x92>', '<0xBD>']
畏 ['
', '▁', '<0xE7>', '<0x95>', '<0x8F>']
痘 ['
', '▁', '<0xE7>', '<0x97>', '<0x98>']
糾 ['
', '▁', '<0xE7>', '<0xB3>', '<0xBE>']
繭 ['
', '▁', '<0xE7>', '<0xB9>', '<0xAD>']
罷 ['
', '▁', '<0xE7>', '<0xBD>', '<0xB7>']
羞 ['
', '▁', '<0xE7>', '<0xBE>', '<0x9E>']
舷 ['
', '▁', '<0xE8>', '<0x88>', '<0xB7>']
虞 ['
', '▁', '<0xE8>', '<0x99>', '<0x9E>']
衷 ['
', '▁', '<0xE8>', '<0xA1>', '<0xB7>']
詔 ['
', '▁', '<0xE8>', '<0xA9>', '<0x94>']
諧 ['
', '▁', '<0xE8>', '<0xAB>', '<0xA7>']
諮 ['
', '▁', '<0xE8>', '<0xAB>', '<0xAE>']
謁 ['
', '▁', '<0xE8>', '<0xAC>', '<0x81>']
賂 ['
', '▁', '<0xE8>', '<0xB3>', '<0x82>']
逓 ['
', '▁', '<0xE9>', '<0x80>', '<0x93>']
錮 ['
', '▁', '<0xE9>', '<0x8C>', '<0xAE>']
陪 ['
', '▁', '<0xE9>', '<0x99>', '<0xAA>']
頒 ['
', '▁', '<0xE9>', '<0xA0>', '<0x92>']
頰 ['
', '▁', '<0xE9>', '<0xA0>', '<0xB0>']
𠮟 ['
', '▁', '<0xF0>', '<0xA0>', '<0xAE>', '<0x9F>']
```

2136字のうち47字が、バイトフォールバックしてしまう。「Swallow」と較べて「勅」「婿」「拷」「迭」の4字は使えるようになったものの、残り47字が必要なタスクだと精度が下がる可能性があるので、注意が必要だろう。