パスワードを忘れた? アカウント作成
15243832 journal
人工知能

yasuokaの日記: fugashiとunidic-liteが不要な日本語BERTモデルの作成

日記 by yasuoka

昨日の日記で作ったbert-large-japanese-char-extendedだが、これにfugashiunidic-liteが必要となるのは、私(安岡孝一)個人としては、どうにも解せない。そこで、昨日のプログラムをグッと睨んで、fugashiとunidic-liteを不要にすべく、トークナイザに改良を施してみた。

from google.colab import drive
drive.mount("/content/drive")
output_dir="/content/drive/My Drive/bert-large-japanese-char-extended"
variants={"𠮟":"叱","塡":"填","剝":"剥","頰":"頬"}
special_tokens=["[PAD]","[UNK]","[CLS]","[SEP]","[MASK]"]
!pip install transformers sentencepiece
import torch,os
from transformers import BertJapaneseTokenizer,AutoModelForMaskedLM
tokenizer=BertJapaneseTokenizer.from_pretrained("cl-tohoku/bert-large-japanese-char",never_split=special_tokens,do_lower_case=False,do_word_tokenize=True,do_subword_tokenize=True,word_tokenizer_type="basic",subword_tokenizer_type="character",mecab_kwargs=None)
model=AutoModelForMaskedLM.from_pretrained("cl-tohoku/bert-large-japanese-char")
c=[]
for k,v in variants.items():
  if tokenizer.add_tokens([k,v])==1:
    t=tokenizer.convert_tokens_to_ids([k,v])
    c.append((max(t[0],t[1]),min(t[0],t[1])))
e=model.resize_token_embeddings(len(tokenizer))
with torch.no_grad():
  for k,v in c:
    e.weight[k,:]=e.weight[v,:]
model.set_input_embeddings(e)
tokenizer.save_pretrained(output_dir)
model.save_pretrained(output_dir)
t=tokenizer.convert_ids_to_tokens([i for i in range(tokenizer.vocab_size,len(tokenizer))])
with open(os.path.join(output_dir,"vocab.txt"),"a",encoding="utf-8") as f:
  print("\n".join(t),file=f)
os.remove(os.path.join(output_dir,"added_tokens.json"))

結局のところ、パラメータを少しいじっただけなのだが、これで、fugashiとunidic-liteは不要となるはずだ。昨日と同様、「酸素ボンベを充[MASK]する。」で試してみよう。

from google.colab import drive
drive.mount("/content/drive")
!pip install transformers sentencepiece
import torch
from transformers import AutoTokenizer,AutoModelForMaskedLM
tokenizer=AutoTokenizer.from_pretrained("/content/drive/My Drive/bert-large-japanese-char-extended")
model=AutoModelForMaskedLM.from_pretrained("/content/drive/My Drive/bert-large-japanese-char-extended")
tokens=tokenizer.tokenize("酸素ボンベを充[MASK]する。")
print(tokens)
mask=tokens.index("[MASK]")
ids=torch.tensor([tokenizer.convert_tokens_to_ids(tokens)])
with torch.no_grad():
  outputs=model(ids)
  pred=outputs[0][0,mask].topk(5)
for i,t in enumerate(tokenizer.convert_ids_to_tokens(pred.indices)):
  tokens[mask]=t
  print(i+1,tokens)

私の手元では、以下の結果になった。

['酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '[MASK]', 'す', 'る', '。']
1 ['酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '塡', 'す', 'る', '。']
2 ['酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '填', 'す', 'る', '。']
3 ['酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '杯', 'す', 'る', '。']
4 ['酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '給', 'す', 'る', '。']
5 ['酸', '素', 'ボ', 'ン', 'ベ', 'を', '充', '蓄', 'す', 'る', '。']

ちゃんと1文字ずつトークナイズされていて、「充塡」と「充填」が両方とも穴埋めされている。これで、形態素解析が不要になったわけだが、まあ、それがいいのかどうかはわからない。sentencepieceも不要にしたいところだけど、それにはtransformers自体の改造が必要かなぁ。

この議論は、yasuoka (21275)によって ログインユーザだけとして作成されたが、今となっては 新たにコメントを付けることはできません。
typodupeerror

人生の大半の問題はスルー力で解決する -- スルー力研究専門家

読み込み中...