🤗

日本語事前学習済みALBERTモデルを公開します

に公開
4

Discussion

安岡孝一安岡孝一

トークナイザの「_」なのですが

>>> from transformers import AutoTokenizer,AutoModelForMaskedLM
>>> tokenizer=AutoTokenizer.from_pretrained("ken11/albert-base-japanese-v1")
>>> tokenizer.tokenize("大学で[MASK]の研究をしています")
['▁', '大学で', '[MASK]', '▁', 'の研究', 'を', 'しています']
>>> tokenizer.backend_tokenizer.pre_tokenizer.add_prefix_space=False
>>> tokenizer.tokenize("大学で[MASK]の研究をしています")
['大学で', '[MASK]', 'の研究', 'を', 'しています']

というオマジナイで何とかなると思うのです。このまま保存も効きますので、続けて

>>> tokenizer.save_pretrained("new.model")
>>> model=AutoModelForMaskedLM.from_pretrained("ken11/albert-base-japanese-v1")
>>> model.save_pretrained("new.model")

とすれば、新しいモデルが作れると思います。よければお試しあれ。

kenken

なるほど!
コメントありがとうございます!

RoBERTaトークナイザーには教えていただいたadd_prefix_space の説明がありました

機能的にはSentencepieceでいうところの --add_dummy_prefix オプションをFalseにするようなものかな?と理解しました。

今回は学習時に--add_dummy_prefix をデフォルトのTrueのままにしていたので、このモデル的には 文頭にはmeta symbolが存在する 状態が正なのです。

['▁', '大学で', '[MASK]', 'の研究', 'を', 'しています']

試しに文頭のmeta symbolもない状態で推論すると以下のようになります

>>> tokenizer.backend_tokenizer.pre_tokenizer.add_prefix_space=False
>>> tokenizer.tokenize("大学で[MASK]の研究をしています")
['大学で', '[MASK]', 'の研究', 'を', 'しています']
>>> p = pipeline("fill-mask", model=model, tokenizer=tokenizer)
>>> p("大学で[MASK]の研究をしています")
[{'sequence': '大学でからの研究をしています', 'score': 0.016584541648626328, 'token': 27, 'token_str': 'から'}, {'sequence': '大学で最近の研究をしています', 'score': 0.009435724467
039108, 'token': 9517, 'token_str': '最近'}, {'sequence': '大学で年の研究をしています', 'score': 0.008557639084756374, 'token': 14, 'token_str': '年'}, {'sequence': '大学で論文の研
究をしています', 'score': 0.008555536158382893, 'token': 2331, 'token_str': '論文'}, {'sequence': '大学で日本語の研究をしています', 'score': 0.008385793305933475, 'token': 2261, 't
oken_str': '日本語'}]

文頭のmeta symbolも消すとそれはそれで推論結果が悪くなるので、 add_prefix_space=Falseでは対応しきれない問題と思われます。。

いや、単純に学習時に add_prefix_space=False しておけばよかったんだと思いました…
とても勉強になりました、ありがとうございます。

安岡孝一安岡孝一

ふーむ、[MASK]の後の「▁」は削るが、文頭の「▁」は残す、ということですね。だとすると、こんな感じかな。

>>> from transformers import AutoTokenizer,AutoModelForMaskedLM,pipeline
>>> from tokenizers import processors
>>> tokenizer=AutoTokenizer.from_pretrained("ken11/albert-base-japanese-v1")
>>> tokenizer.backend_tokenizer.pre_tokenizer.add_prefix_space=False
>>> tokenizer.backend_tokenizer.post_processor=processors.TemplateProcessing(single="[CLS]:0 ▁:0 $A:0 [SEP]:0",pair="[CLS]:0 ▁:0 $A:0 [SEP]:0 ▁:1 $B:1 [SEP]:1",special_tokens=[(t,tokenizer.convert_tokens_to_ids(t)) for t in ["[CLS]","[SEP]","▁"]])
>>> model=AutoModelForMaskedLM.from_pretrained("ken11/albert-base-japanese-v1")
>>> p=pipeline("fill-mask",model=model,tokenizer=tokenizer)
>>> p("大学で[MASK]の研究をしています")
[{'sequence': '大学で英語の研究をしています', 'score': 0.03434569388628006, 'token': 1181, 'token_str': '英語'}, {'sequence': '大学で心理学の研究をしています', 'score': 0.03220712020993233, 'token': 8310, 'token_str': '心理学'}, {'sequence': '大学で数学の研究をしています', 'score': 0.02853451296687126, 'token': 4577, 'token_str': '数学'}, {'sequence': '大学で医学の研究をしています', 'score': 0.023687569424510002, 'token': 2829, 'token_str': '医学'}, {'sequence': '大学で日本語の研究をしています', 'score': 0.01937411166727543, 'token': 2261, 'token_str': '日本語'}]

post_processorいじるのは、さすがにトリッキーなのですけど、続けて

>>> tokenizer.save_pretrained("new.model")
>>> model.save_pretrained("new.model")

とすれば保存もできます。よければどうぞ。

kenken

ありがとうございます 🙇
すごいですね、これなら確かにうまく動きました。

post_processorいじるのは、さすがにトリッキー

post_processorここまでいじれるの全然知らなかったです
このカスタムしたTokenizerを公開しようかと思ったんですが、post_processで操作が入ってると利用者にとって想定外の挙動になると思ったのでやめました
(思わぬところでmeta symbolが追加されていて利用者を混乱させるかなと)

いろいろ教えていただきありがとうございます!🙇