国語研長単位品詞付与・係り受け解析モデルllm-jp-3.1-1.8b-ud-embedsリリース

[llm-jp-3.1-1.8b](https://huggingface.co/llm-jp/llm-jp-3.1-1.8b)が[リリースされた](https://llmc.nii.ac.jp/topics/llm-jp-3-1_instruct4/)ので、以前の[llm-jp-3-1.8b](https://huggingface.co/llm-jp/llm-jp-3-1.8b)と比較してみることにした。入出力幅4096トークンの日本語LLaMAという点は同様なので、まずはトークナイザを見てみよう。

```
>>> from transformers import AutoTokenizer
>>> tkz=AutoTokenizer.from_pretrained("llm-jp/llm-jp-3.1-1.8b")
>>> print(tkz.convert_ids_to_tokens(tkz("国境の長いトンネルを抜けると雪国であった。","夜の底が白くなった。")["input_ids"]))
['
', '▁国境', 'の', '長い', 'トンネル', 'を', '抜ける', 'と', '雪', '国', 'であった。', '
', '▁夜', 'の', '底', 'が', '白', 'くなった', '。']
```

文頭のmetaspaceが邪魔だ。しかも「であった。」が、句点を含んだまま1トークンになっていて、かなり使いづらい。仕方ないので、[2月25日の記事](https://qiita.com/KoichiYasuoka/items/5b9d1670363756de2a33)をまねて、トークナイザを改良することにした。

```
>>> from transformers import AutoTokenizer
>>> from tokenizers import Regex
>>> from tokenizers.pre_tokenizers import Sequence,Split,Whitespace,Punctuation
>>> tkz=AutoTokenizer.from_pretrained("llm-jp/llm-jp-3.1-1.8b")
>>> tkz.backend_tokenizer.normalizer=None
>>> tkz.backend_tokenizer.pre_tokenizer=Sequence([Split(Regex("[ぁ-ん]"),"isolated"),Whitespace(),Punctuation()])
>>> print(tkz.convert_ids_to_tokens(tkz("国境の長いトンネルを抜けると雪国であった。","夜の底が白くなった。")["input_ids"]))
['
', '国境', 'の', '長', 'い', 'トンネル', 'を', '抜', 'け', 'る', 'と', '雪', '国', 'で', 'あ', 'っ', 'た', '。', '
', '夜', 'の', '底', 'が', '白', 'く', 'な', 'っ', 'た', '。']
```

ひらがなが細かすぎる気がしないでもないが、とりあえず、このやり方でトークナイザを改良して、国語研長単位品詞付与・係り受け解析モデル[llm-jp-3.1-1.8b-ud-embeds](https://huggingface.co/KoichiYasuoka/llm-jp-3.1-1.8b-ud-embeds)を[試作してみた](https://huggingface.co/KoichiYasuoka/llm-jp-3.1-1.8b-ud-embeds/blob/main/maker.py)。以前に作った[llm-jp-3-1.8b-ud-embeds](https://huggingface.co/KoichiYasuoka/llm-jp-3-1.8b-ud-embeds)との間で、係り受け解析の精度を比較してみよう。Google Colaboratoryだと、こんな感じ。

```
!pip install transformers
mdl="KoichiYasuoka/llm-jp-{}-1.8b-ud-embeds"
org="llm-jp/llm-jp-{}-1.8b"
import os,sys,subprocess
from transformers import pipeline
url="https://github.com/UniversalDependencies/UD_Japanese-GSDLUW"
f=os.path.join(os.path.basename(url),"ja_gsdluw-ud-test.conllu")
os.system(f"test -f {f} || git clone --depth=1 {url}")
url="https://universaldependencies.org/conll18/conll18_ud_eval.py"
c=os.path.basename(url)
os.system(f"test -f {c} || curl -LO {url}")
with open(f,"r",encoding="utf-8") as r:
  s=[t[8:].strip() for t in r if t.startswith("# text =")]
rst=[]
for z in ["3.1","3"]:
  for tkz in ["original","refined"]:
    nlp=pipeline("universal-dependencies",mdl.format(z),trust_remote_code=True)
    if tkz=="original":
      from transformers import AutoTokenizer
      from tokenizers.normalizers import Replace
      nlp.tokenizer=AutoTokenizer.from_pretrained(org.format(z))
      nlp.tokenizer.backend_tokenizer.normalizer=Replace(" ","▁")
      nlp.tokenizer.model_input_names=["input_ids","attention_mask"]
    with open("result.conllu","w",encoding="utf-8") as w:
      for t in s:
        w.write(nlp(t))
    p=subprocess.run([sys.executable,c,"-v",f,"result.conllu"],
      encoding="utf-8",stdout=subprocess.PIPE,stderr=subprocess.STDOUT)
    os.system("mkdir -p "+os.path.join("result",mdl.format(z)))
    rst.append(os.path.join("result",mdl.format(z),tkz+".txt"))
    with open(rst[-1],"w",encoding="utf-8") as w:
      print(f"\n*** {mdl.format(z)} ({tkz} tokenizer)",p.stdout,sep="\n",file=w)
!cat {" ".join(rst)}
```

私(安岡孝一)の手元では、以下の結果が出力された。

```
*** KoichiYasuoka/llm-jp-3.1-1.8b-ud-embeds (original tokenizer)
Metric     | Precision |    Recall |  F1 Score | AligndAcc
-----------+-----------+-----------+-----------+-----------
Tokens     |     71.77 |     55.34 |     62.49 |
Sentences  |    100.00 |    100.00 |    100.00 |
Words      |     71.77 |     55.34 |     62.49 |
UPOS       |     70.61 |     54.45 |     61.49 |     98.39
XPOS       |      0.00 |      0.00 |      0.00 |      0.00
UFeats     |     71.77 |     55.34 |     62.49 |    100.00
AllTags    |      0.00 |      0.00 |      0.00 |      0.00
Lemmas     |      0.00 |      0.00 |      0.00 |      0.00
UAS        |     48.86 |     37.68 |     42.55 |     68.08
LAS        |     48.29 |     37.24 |     42.05 |     67.28
CLAS       |     38.23 |     34.72 |     36.39 |     51.33
MLAS       |     32.06 |     29.12 |     30.52 |     43.05
BLEX       |      0.00 |      0.00 |      0.00 |      0.00

*** KoichiYasuoka/llm-jp-3.1-1.8b-ud-embeds (refined tokenizer)
Metric     | Precision |    Recall |  F1 Score | AligndAcc
-----------+-----------+-----------+-----------+-----------
Tokens     |     96.01 |     96.48 |     96.25 |
Sentences  |    100.00 |    100.00 |    100.00 |
Words      |     96.01 |     96.48 |     96.25 |
UPOS       |     94.96 |     95.43 |     95.19 |     98.91
XPOS       |      0.00 |      0.00 |      0.00 |      0.00
UFeats     |     95.97 |     96.44 |     96.21 |     99.96
AllTags    |      0.00 |      0.00 |      0.00 |      0.00
Lemmas     |      0.00 |      0.00 |      0.00 |      0.00
UAS        |     88.24 |     88.67 |     88.46 |     91.91
LAS        |     87.56 |     87.98 |     87.77 |     91.19
CLAS       |     81.32 |     82.54 |     81.93 |     86.43
MLAS       |     79.10 |     80.28 |     79.68 |     84.06
BLEX       |      0.00 |      0.00 |      0.00 |      0.00

*** KoichiYasuoka/llm-jp-3-1.8b-ud-embeds (original tokenizer)
Metric     | Precision |    Recall |  F1 Score | AligndAcc
-----------+-----------+-----------+-----------+-----------
Tokens     |     72.85 |     54.10 |     62.09 |
Sentences  |    100.00 |    100.00 |    100.00 |
Words      |     72.85 |     54.10 |     62.09 |
UPOS       |     71.00 |     52.73 |     60.52 |     97.47
XPOS       |      0.00 |      0.00 |      0.00 |      0.00
UFeats     |     72.83 |     54.09 |     62.08 |     99.98
AllTags    |      0.00 |      0.00 |      0.00 |      0.00
Lemmas     |      0.00 |      0.00 |      0.00 |      0.00
UAS        |     47.60 |     35.36 |     40.58 |     65.35
LAS        |     46.89 |     34.83 |     39.97 |     64.37
CLAS       |     35.28 |     31.06 |     33.03 |     47.83
MLAS       |     29.92 |     26.33 |     28.01 |     40.56
BLEX       |      0.00 |      0.00 |      0.00 |      0.00

*** KoichiYasuoka/llm-jp-3-1.8b-ud-embeds (refined tokenizer)
Metric     | Precision |    Recall |  F1 Score | AligndAcc
-----------+-----------+-----------+-----------+-----------
Tokens     |     95.74 |     96.14 |     95.94 |
Sentences  |    100.00 |    100.00 |    100.00 |
Words      |     95.74 |     96.14 |     95.94 |
UPOS       |     94.28 |     94.68 |     94.48 |     98.47
XPOS       |      0.00 |      0.00 |      0.00 |      0.00
UFeats     |     95.72 |     96.13 |     95.92 |     99.98
AllTags    |      0.00 |      0.00 |      0.00 |      0.00
Lemmas     |      0.00 |      0.00 |      0.00 |      0.00
UAS        |     86.74 |     87.10 |     86.92 |     90.59
LAS        |     85.96 |     86.33 |     86.14 |     89.79
CLAS       |     79.07 |     79.73 |     79.40 |     84.05
MLAS       |     76.39 |     77.03 |     76.71 |     81.20
BLEX       |      0.00 |      0.00 |      0.00 |      0.00
```

UPOS/LAS/MLASを表にしてみよう。

| |トークナイザ改良前|トークナイザ改良後|
|:-:|:-:|:-:|
|llm-jp-3.1-1.8b-ud-embeds|61.49/42.05/30.52|95.19/87.77/79.68|
|llm-jp-3-1.8b-ud-embeds|60.52/39.97/28.01|94.48/86.14/76.71|

LLM-jp-3.1の方が明らかに精度が高い。LLM-jp-3では2.1Tトークンの事前学習だったのに対し、LLM-jp-3.1では[0.4T増やして2.5Tトークンにした](https://llm-jp.nii.ac.jp/ja/blog/blog-887/)らしいので、それが見事に効いているということだろう。ただ、これでも、ModernBERTには[あと一歩及んでいない](https://qiita.com/KoichiYasuoka/items/457f983b9988f2820460)ので、少なくとも現時点の係り受け解析には、LLaMAよりはModernBERTということだろう。