llm-jp-3.1-1.8bがリリースされたので、以前の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"]))
['<s>', '▁国境', 'の', '長い', 'トンネル', 'を', '抜ける', 'と', '雪', '国', 'であった。', '<s>', '▁夜', 'の', '底', 'が', '白', 'くなった', '。']
文頭のmetaspaceが邪魔だ。しかも「であった。」が、句点を含んだまま1トークンになっていて、かなり使いづらい。仕方ないので、2月25日の記事をまねて、トークナイザを改良することにした。
>>> 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"]))
['<s>', '国境', 'の', '長', 'い', 'トンネル', 'を', '抜', 'け', 'る', 'と', '雪', '国', 'で', 'あ', 'っ', 'た', '。', '<s>', '夜', 'の', '底', 'が', '白', 'く', 'な', 'っ', 'た', '。']
ひらがなが細かすぎる気がしないでもないが、とりあえず、このやり方でトークナイザを改良して、国語研長単位品詞付与・係り受け解析モデルllm-jp-3.1-1.8b-ud-embedsを試作してみた。以前に作った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トークンにしたらしいので、それが見事に効いているということだろう。ただ、これでも、ModernBERTにはあと一歩及んでいないので、少なくとも現時点の係り受け解析には、LLaMAよりはModernBERTということだろう。