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

yasuokaの日記: Transformersとbert-base-japanese-char-extendedとUD_Japanese-GSDで作る日本語「長単位」形態素解析器

日記 by yasuoka

今日のNINJALサロンで話題になったので、日本語「長単位」形態素解析器を試作してみることにした。方法としてはUD_Japanese-GSDのLUWPOSを、Transformersのrun_ner.pybert-base-japanese-char-extendedで、何とか「長単位」の系列ラベリングに落とし込む。Google Colaboratory (GPU版)だと、こんな感じ。

!pip install transformers datasets seqeval
!test -d UD_Japanese-GSD || git clone https://github.com/universaldependencies/UD_Japanese-GSD
!test -f run_ner.py || curl -LO https://raw.githubusercontent.com/huggingface/transformers/v`pip list | sed -n 's/^transformers *\([^ ]*\) *$/\1/p'`/examples/pytorch/token-classification/run_ner.py

for d in ["train","dev","test"]:
  with open("UD_Japanese-GSD/ja_gsd-ud-"+d+".conllu","r",encoding="utf-8") as f:
    r=f.read()
  with open(d+".json","w",encoding="utf-8") as f:
    tokens=[]
    tags=[]
    i=0
    for s in r.split("\n"):
      t=s.split("\t")
      if len(t)==10 and not s.startswith("#"):
        for c in t[1]:
          tokens.append(c)
        b=t[9][t[9].index("LUWBILabel=")+11]
        p=[u[7:] for u in t[9].split("|") if u.startswith("LUWPOS=")][0]
        if p=="名詞-普通名詞-副詞可能":
          p="名詞-普通名詞-一般"
        p=p.replace("-","/")
        tags.extend([b+"-"+p]+["I-"+p]*(len(t[1])-1))
      else:
        if len(tokens)>0:
          print("{\"tokens\":[\""+"\",\"".join(tokens)+"\"],\"tags\":[\""+"\",\"".join(tags)+"\"]}",file=f)
          tokens=[]
          tags=[]
    if len(tokens)>0:
      print("{\"tokens\":[\""+"\",\"".join(tokens)+"\"],\"tags\":[\""+"\",\"".join(tags)+"\"]}",file=f)

!python run_ner.py --model_name_or_path KoichiYasuoka/bert-base-japanese-char-extended --train_file train.json --validation_file dev.json --test_file test.json --output_dir ja_luw.pos --do_train --do_eval --do_predict

ただ「名詞-普通名詞-副詞可能」というLUWPOSが、一ヶ所だけ現れて気持ち悪かったので、そこは「名詞-普通名詞-一般」に直している。私(安岡孝一)の手元では、15分程度でja_luw.posが出来上がり、以下のmetricsとなった。

***** train metrics *****
  epoch                    =        3.0
  train_loss               =     0.2678
  train_runtime            = 0:13:01.48
  train_samples            =       7050
  train_samples_per_second =     27.064
  train_steps_per_second   =      3.386

***** eval metrics *****
  epoch                   =        3.0
  eval_accuracy           =     0.9637
  eval_f1                 =     0.9705
  eval_loss               =     0.1588
  eval_precision          =     0.9678
  eval_recall             =     0.9734
  eval_runtime            = 0:00:06.57
  eval_samples            =        507
  eval_samples_per_second =     77.053
  eval_steps_per_second   =      9.727

***** predict metrics *****
  predict_accuracy           =     0.9669
  predict_f1                 =     0.9672
  predict_loss               =     0.1594
  predict_precision          =     0.9624
  predict_recall             =     0.9721
  predict_runtime            = 0:00:06.92
  predict_samples_per_second =     78.466
  predict_steps_per_second   =      9.826

96%程度なので、まあ悪くない感じだ。出来上がったja_luw.posで、「全学年にわたって小学校の国語の教科書に大量の挿し絵が用いられている」を形態素解析してみよう。

from transformers import AutoModelForTokenClassification,AutoTokenizer,TokenClassificationPipeline
mdl=AutoModelForTokenClassification.from_pretrained("ja_luw.pos")
tkz=AutoTokenizer.from_pretrained("ja_luw.pos")
nlp=TokenClassificationPipeline(model=mdl,tokenizer=tkz,aggregation_strategy="simple")
d=nlp(inputs="全学年にわたって小学校の国語の教科書に大量の挿し絵が用いられている")
print(d)

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

[{'entity_group': '名詞/普通名詞/一般', 'score': 0.99953014, 'word': '全学年', 'start': 0, 'end': 3}, {'entity_group': '助詞/格助詞', 'score': 0.99852294, 'word': 'にわたって', 'start': 3, 'end': 8}, {'entity_group': '名詞/普通名詞/一般', 'score': 0.9992971, 'word': '小学校', 'start': 8, 'end': 11}, {'entity_group': '助詞/格助詞', 'score': 0.99976945, 'word': 'の', 'start': 11, 'end': 12}, {'entity_group': '名詞/普通名詞/一般', 'score': 0.99958575, 'word': '国語', 'start': 12, 'end': 14}, {'entity_group': '助詞/格助詞', 'score': 0.99973565, 'word': 'の', 'start': 14, 'end': 15}, {'entity_group': '名詞/普通名詞/一般', 'score': 0.99962956, 'word': '教科書', 'start': 15, 'end': 18}, {'entity_group': '助詞/格助詞', 'score': 0.99977046, 'word': 'に', 'start': 18, 'end': 19}, {'entity_group': '形状詞/一般', 'score': 0.98628527, 'word': '大量', 'start': 19, 'end': 21}, {'entity_group': '助詞/格助詞', 'score': 0.99945784, 'word': 'の', 'start': 21, 'end': 22}, {'entity_group': '名詞/普通名詞/一般', 'score': 0.9996125, 'word': '挿し絵', 'start': 22, 'end': 25}, {'entity_group': '助詞/格助詞', 'score': 0.99980253, 'word': 'が', 'start': 25, 'end': 26}, {'entity_group': '動詞/一般/上一段/ア行', 'score': 0.9828689, 'word': '用い', 'start': 26, 'end': 28}, {'entity_group': '助動詞/助動詞/レル', 'score': 0.99877167, 'word': 'られ', 'start': 28, 'end': 30}, {'entity_group': '助動詞/上一段/ア行', 'score': 0.99854565, 'word': 'ている', 'start': 30, 'end': 33}]

「全学年」「にわたって」「小学校」「の」「国語」「の」「教科書」「に」「大量」「の」「挿し絵」「が」「用い」「られ」「ている」となっており、私の見る限り、正しく解析できているようだ。さて、UD_Japanese-GSDLUWがリリースされたら、このあたり、もっとうまくいくかな。

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

192.168.0.1は、私が使っている IPアドレスですので勝手に使わないでください --- ある通りすがり

読み込み中...