12月21日の記事の続きだが、Swallowのトークナイザは常用漢字2136字のうち51字をサポートしておらず、これら51字はバイトフォールバックしてしまう。ただ、第3水準漢字の「𠮟」「塡」「剝」「頰」については、代わりに「叱」「填」「剥」「頬」で事前学習されているようだ。Swallow-7b-hfで確かめてみよう。
>>> from transformers import LlamaTokenizerFast
>>> tkz=LlamaTokenizerFast.from_pretrained("tokyotech-llm/Swallow-7b-hf")
>>> print(tkz.convert_ids_to_tokens(sum(tkz(["𠮟責","頰","剝離","装塡"])["input_ids"],[])))
['<s>', '▁', '<0xF0>', '<0xA0>', '<0xAE>', '<0x9F>', '責', '<s>', '▁', '<0xE9>', '<0xA0>', '<0xB0>', '<s>', '▁', '<0xE5>', '<0x89>', '<0x9D>', '離', '<s>', '▁', '装', '<0xE5>', '<0xA1>', '<0xA1>']
>>> print(tkz.convert_ids_to_tokens(sum(tkz(["叱責","頬","剥離","装填"])["input_ids"],[])))
['<s>', '▁', '叱', '責', '<s>', '▁', '頬', '<s>', '▁', '剥', '離', '<s>', '▁', '装', '填']
それならば、入力中の「𠮟」「塡」「剝」「頰」を、それぞれ「叱」「填」「剥」「頬」にReplace
するよう、トークナイザを書き換えてしまった方がうれしい気がする。とりあえず、現状のnormalizer
がどうなっているか見てみよう。
>>> import json
>>> d=json.loads(tkz.backend_tokenizer.to_str())
>>> print(d["normalizer"])
{'type': 'Sequence', 'normalizers': [{'type': 'Prepend', 'prepend': '▁'}, {'type': 'Replace', 'pattern': {'String': ' '}, 'content': '▁'}]}
Sequence
の中身は、メタスペースのPrepend
と、空白からメタスペースへのReplace
なので、「𠮟」「塡」「剝」「頰」のReplace
をSequence
に追加すればよさそうだ。
>>> from tokenizers.normalizers import Sequence,Prepend,Replace
>>> tkz.backend_tokenizer.normalizer=Sequence([Prepend("\u2581"),Replace(" ","\u2581"),Replace("𠮟","叱"),Replace("頰","頬"),Replace("剝","剥"),Replace("塡","填")])
>>> print(tkz.convert_ids_to_tokens(sum(tkz(["𠮟責","頰","剝離","装塡"])["input_ids"],[])))
['<s>', '▁', '叱', '責', '<s>', '▁', '頬', '<s>', '▁', '剥', '離', '<s>', '▁', '装', '填']
よし、うまくいった。mySwallow-7b-hfに保存しよう。
>>> tkz.save_pretrained("mySwallow-7b-hf")
('mySwallow-7b-hf/tokenizer_config.json', 'mySwallow-7b-hf/special_tokens_map.json', 'mySwallow-7b-hf/tokenizer.model', 'mySwallow-7b-hf/added_tokens.json', 'mySwallow-7b-hf/tokenizer.json')
ちなみに、モデル自体も同じディレクトリに保存しておくと、pipeline
とかの読み込みで便利だったりするが、27GBもあるのでハードディスクと相談してほしい。
>>> from transformers import LlamaForCausalLM
>>> mdl=LlamaForCausalLM.from_pretrained("tokyotech-llm/Swallow-7b-hf")
>>> mdl.save_pretrained("mySwallow-7b-hf")
ただし、このReplace
をやってしまうと、たとえば「頬と頰はどちらが子供の名づけに使えますか?」という質問には、絶対に答えられなくなってしまう。その点に注意してReplace
してほしい。