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

yasuokaの日記: 日本語形態素解析エンジンnagisaは古典中国語(漢文)を学習できるのか 2

日記 by yasuoka

ネットサーフィンしていたところ、nagisaという日本語形態素解析エンジンを見つけた。端的には、python3のdynetで、日本語の単語切りと品詞付与をおこなうエンジンなのだが、自前でUniversal Dependenciesから機械学習する方法も示されている。だとすると、UD_Classical_Chinese-Kyotoから古典中国語(漢文)を学習する、というのもアリなのではないかと思い、ちょっと試してみることにした。

% pip3 install nagisa
% git clone https://github.com/UniversalDependencies/UD_Classical_Chinese-Kyoto.git
% awk '{if(NF==10&&$1~/^[1-9][0-9]*$/)printf("%s\t%s\n",$2,$5);else if($0=="")printf("EOS\n")}' UD_Classical_Chinese-Kyoto/lzh_kyoto-ud-train.conllu > lzh_kyoto-ud-train.txt
% awk '{if(NF==10&&$1~/^[1-9][0-9]*$/)printf("%s\t%s\n",$2,$5);else if($0=="")printf("EOS\n")}' UD_Classical_Chinese-Kyoto/lzh_kyoto-ud-dev.conllu > lzh_kyoto-ud-dev.txt
% awk '{if(NF==10&&$1~/^[1-9][0-9]*$/)printf("%s\t%s\n",$2,$5);else if($0=="")printf("EOS\n")}' UD_Classical_Chinese-Kyoto/lzh_kyoto-ud-test.conllu > lzh_kyoto-ud-test.txt
% python3
>>> import nagisa
>>> nagisa.fit(train_file="lzh_kyoto-ud-train.txt",dev_file="lzh_kyoto-ud-dev.txt",test_file="lzh_kyoto-ud-test.txt",model_name="lzh_kyoto-nagisa")

Epoch   LR      Loss    Time_m  DevWS_f1        DevPOS_f1       TestWS_f1       TestPOS_f1
1       0.100   8.880   0.391   98.56           79.15           99.54           81.40
2       0.100   3.602   0.388   98.60           83.63           99.59           84.91
3       0.100   2.705   0.388   98.79           85.25           99.67           86.37
4       0.050   2.304   0.351   98.73           85.76           99.67           86.37
5       0.050   1.771   0.389   98.87           86.62           99.61           87.40
6       0.050   1.593   0.389   98.94           86.78           99.48           87.91
7       0.025   1.472   0.354   98.81           86.55           99.48           87.91
8       0.025   1.285   0.391   98.94           86.87           99.54           87.97
9       0.012   1.207   0.354   98.87           87.04           99.54           87.97
10      0.006   1.128   0.354   98.83           87.08           99.54           87.97

XPOS(第5フィールド)の機械学習でF1値が87.97だとすると、UDPipeの87.8%と比べても、まあ、遜色ない値だ。とりあえず「不入虎穴不得虎子」を、形態素解析してみよう。

>>> lzh=nagisa.Tagger(vocabs="lzh_kyoto-nagisa.vocabs",params="lzh_kyoto-nagisa.params",hp="lzh_kyoto-nagisa.hp").tagging
>>> s=lzh("不入虎穴不得虎子")
>>> print(s)
不/v,副詞,否定,無界 入/v,動詞,行為,移動 虎/n,名詞,主体,動物 穴/n,名詞,固定物,地形 不/v,副詞,否定,無界 得/v,動詞,行為,得失 虎/n,名詞,主体,動物 子/n,名詞,人,関係

一字ずつ全てが切られていて、品詞も妥当なようだ。次に「有兄子曰甫」を、形態素解析してみよう。

>>> s=lzh("有兄子曰甫")
>>> print(s)
有/v,動詞,存在,存在 兄子/n,名詞,主体,書物 曰/v,動詞,行為,伝達 甫/v,動詞,描写,態度

うーん、「甫」という人名を知らないのは、まあ仕方ないとしても、「兄」の「子」をひとまとめにして「n,名詞,主体,書物」だと思ってるのは、どういう勘違いなのだろう。ならば「若之何子之不言也」を、形態素解析してみよう。

>>> s=lzh("若之何子之不言也")
>>> print(s)
若/v,動詞,行為,分類 之/n,代名詞,人称,止格 何/n,代名詞,疑問,* 子/n,代名詞,人称,他 之/p,助詞,接続,属格 不/v,副詞,否定,無界 言/v,動詞,行為,伝達 也/p,助詞,句末,*

さすがに「何」と「子」がちゃんと分かれていて、しかも「之」の品詞も見分けている。どうやら、品詞を階層処理していない(コンマに意味がない)ようなので、品詞の末尾にLEMMAやGlossを付けておく、といった小技は無理そうだ。とりあえずは「甫」を何とかすべく、外部辞書で人名を大量に教えこみたいところなのだが、 nagisa.fit dict_fileのフォーマットって、train_fileとかと同じなのかしら?

この議論は、yasuoka (21275)によって ログインユーザだけとして作成されたが、今となっては 新たにコメントを付けることはできません。
  • by yasuoka (21275) on 2019年08月31日 13時08分 (#3678164) 日記

    udkanbunのMeCab辞書をdict_fileに追加してみたところ、F1値が88.05になって、解析結果が改善されました。

    % pip3 install udkanbun
    % awk -F, '{printf("%s\t%s,%s,%s,%s\n",$1,$5,$6,$7,$8)}' $HOME/.local/lib/python3*/site-packages/udkanbun/mecab-kanbun/*.csv > lzh_udkanbun-dict.txt
    % python3
    >>> import nagisa
    >>> nagisa.fit(train_file="lzh_kyoto-ud-train.txt",dev_file="lzh_kyoto-ud-dev.txt",test_file="lzh_kyoto-ud-test.txt",dict_file="lzh_udkanbun-dict.txt",model_name="lzh_kyoto-nagisa")

    Epoch    LR    Loss    Time_m    DevWS_f1    DevPOS_f1    TestWS_f1    TestPOS_f1
    1    0.100    5.756    0.369    97.76        84.43        98.22        85.19
    2    0.100    2.685    0.369    97.80        87.57        98.47        88.05
    3    0.050    2.213    0.335    97.72        87.64        98.47        88.05
    4    0.025    1.720    0.333    97.42        88.30        98.47        88.05
    5    0.012    1.441    0.334    97.68        88.64        98.47        88.05
    6    0.006    1.312    0.335    97.66        88.85        98.47        88.05
    7    0.003    1.242    0.336    97.72        88.90        98.47        88.05
    8    0.001    1.226    0.334    97.69        88.89        98.47        88.05
    9    0.000    1.187    0.334    97.75        89.02        98.47        88.05
    10    0.000    1.177    0.337    97.75        89.07        98.47        88.05
    >>> lzh=nagisa.Tagger(vocabs="lzh_kyoto-nagisa.vocabs",params="lzh_kyoto-nagisa.params",hp="lzh_kyoto-nagisa.hp").tagging
    >>> s=lzh("有兄子曰甫")
    >>> print(s)
    有/v,動詞,存在,存在 兄/n,名詞,人,関係 子/n,名詞,人,人 曰/v,動詞,行為,伝達 甫/n,名詞,人,名

    でも、学習がうまくいってないのか、Epoch 2以降でF1値が変化してないのです。うーむ。

    • dim_tagembdecayというパラメータを教えていただいた [github.com]ので、とりあえず試してみました。

      >>> import nagisa
      >>> nagisa.fit(train_file="lzh_kyoto-ud-train.txt",dev_file="lzh_kyoto-ud-dev.txt",test_file="lzh_kyoto-ud-test.txt",dict_file="lzh_udkanbun-dict.txt",model_name="lzh_kyoto-nagisa",dim_tagemb=32,decay=3)

      Epoch    LR    Loss    Time_m    DevWS_f1    DevPOS_f1    TestWS_f1    TestPOS_f1
      1    0.100    4.944    0.378    97.43        85.24        97.93        86.73
      2    0.100    2.251    0.379    97.78        87.54        98.78        88.99
      3    0.100    1.890    0.341    97.37        87.90        98.78        88.99
      4    0.100    1.693    0.379    97.79        88.44        98.50        89.09
      5    0.100    1.544    0.379    97.85        88.09        98.76        89.75
      6    0.100    1.464    0.341    96.63        87.72        98.76        89.75
      7    0.100    1.367    0.377    97.87        88.94        98.56        90.07
      8    0.100    1.309    0.342    97.64        89.27        98.56        90.07
      9    0.100    1.271    0.343    97.81        88.81        98.56        90.07
      10    0.050    1.187    0.342    97.79        88.99        98.56        90.07
      >>> lzh=nagisa.Tagger(vocabs="lzh_kyoto-nagisa.vocabs",params="lzh_kyoto-nagisa.params",hp="lzh_kyoto-nagisa.hp").tagging
      >>> s=lzh("有兄子曰甫")
      >>> print(s)
      有/v,動詞,存在,存在 兄子/n,名詞,人,名 曰/v,動詞,行為,伝達 甫/p,接尾辞,*,*

      F1値は90.07に改善されてるのですけど、「有兄子曰甫」については、むしろ悪化してしまいました。うーん、どこかミスったのかな…。

      親コメント
typodupeerror

私は悩みをリストアップし始めたが、そのあまりの長さにいやけがさし、何も考えないことにした。-- Robert C. Pike

読み込み中...