MeCab の解析結果をそのまま MeCab の学習(mecab-cost-train)に使おうとして下のようになってしまうという "あるある" の原因と解決法。
上の図だと、
- 解析結果を学習に使うということは CSV に登録されているはずなのに、adding virtual node が大量発生
- 解析結果が未知語(処理の出力)になった行で rewrite.def の記載のパターンとマッチせずにエラー出して終了(↓)
feature_index.cpp(278) [rewrite_.rewrite2(path->rnode->feature, &ufeature2, &lfeature2, &rfeature2)] cannot rewrite pattern: 補助記号,一般,,,,
adding virtual node の説明はこれ(↓)
adding virtual node: 未知語処理を行なっても処理できなかった 形態素で, 学習の際便宜的に追加される形態素です.
adding virtual node 起きても、別に学習は動くのだけど。virtual node 作るたびにメモリガンガン消費して、そこそこ大きいデータで学習しようとしたらすぐメモリ足りなくなるので、ちゃんと辞書に載ってる(未知語でない)なら、起きないのがベスト。
原因は単に MeCab の出力結果と学習時の CSV がマッチしていないだけ、なのだけど、
前回のように、ミニデータ作ってちゃんと確認してみる。
使うデータ
adding virtual node をなくす
ミニデータの final に入ってる辞書は「車で待つ」「くるまで待つ」くらいしか解析できないけれど、まずはそれを実行する。
解析するテキストを用意。
車で待つ
くるまで待つ
前回の作った final はバイナリ化していなかったのでディレクトリに入って mecab-dict-index でバイナリ化。
$ cd final/
final$ mecab-dict-index
./pos-id.def is not found. minimum setting is used
reading ./unk.def ... 35
emitting double-array: 100% |###########################################|
./pos-id.def is not found. minimum setting is used
reading ./mini_lex.csv ... 6
emitting double-array: 100% |###########################################|
reading ./matrix.def ... 15x16
emitting matrix : 100% |###########################################|
done!
final$ cd ../
この final 使って raw_text.txt を解析。
$ mecab -d final raw_text.txt > mecab_output_corpus.mecab
MeCab の -d オプションで final を辞書指定している。
$ cat mecab_output_corpus.mecab
車 名詞,普通名詞,一般,,,,クルマ,車,車,クルマ,車,クルマ,和,"ク濁","基本形","","","","",体,クルマ,クルマ,クルマ,クル マ,"0","C2","",2895297651024384,10533
で 助詞,接続助詞,,,,,テ,て,で,デ,で,デ,和,"","","","","","",接助,デ,デ,デ,デ,"","動詞%F1,形容詞%F2@-1","",6837330270888448,24874
待つ 動詞,一般,,,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,"","","","","","",用,マツ,マツ,マツ,マツ,"1","C1","",9848884062986923,35830
EOS
くるま 名詞,普通名詞,一般,,,,クルマ,車,くるま,クルマ,くるま,クルマ,和,"ク濁","基本形","","","","",体,クルマ,クルマ,クルマ,クルマ,"0","C2","",2895297718133248,10533
で 助詞,接続助詞,,,,,テ,て,で,デ,で,デ,和,"","","","","","",接助,デ,デ,デ,デ,"","動詞%F1,形容詞%F2@-1","",6837330270888448,24874
待つ 動詞,一般,,,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,"","","","","","",用,マツ,マツ,マツ,マツ,"1","C1","",9848884062986923,35830
EOS
解析はできたので、早速この結果を学習に使ってみる。
$ cd seed/
seed$ mecab-cost-train ../mecab_output_corpus.mecab model
reading corpus ...adding virtual node: 名詞,普通名詞,一般,,,,クルマ,車,車,クルマ,車,クルマ,和,"ク濁","基本形","","","","",体,クルマ,クルマ,クルマ,クルマ,"0","C2","",2895297651024384,10533
adding virtual node: 助詞,接続助詞,,,,,テ,て,で,デ,で,デ,和,"","","","","","",接助,デ,デ,デ,デ,"","動詞%F1,形容詞%F2@-1","",6837330270888448,24874
adding virtual node: 動詞,一般,,,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,"","","","","","",用,マツ,マツ, マツ,マツ,"1","C1","",9848884062986923,35830
adding virtual node: 名詞,普通名詞,一般,,,,クルマ,車,くるま,クルマ,くるま,クルマ,和,"ク濁","基本形","","","","",体,クル マ,クルマ,クルマ,クルマ,"0","C2","",2895297718133248,10533
adding virtual node: 助詞,接続助詞,,,,,テ,て,で,デ,で,デ,和,"","","","","","",接助,デ,デ,デ,デ,"","動詞%F1,形容詞%F2@-1","",6837330270888448,24874
adding virtual node: 動詞,一般,,,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,"","","","","","",用,マツ,マツ, マツ,マツ,"1","C1","",9848884062986923,35830
Number of sentences: 2
Number of features: 52
eta: 0.00005
freq: 1
eval-size: 10
unk-eval-size: 4
threads: 1
charset: UTF-8
C(sigma^2): 1.00000
iter=0 err=0.50000 F=0.50000 target=4.38203 diff=1.00000
iter=1 err=0.00000 F=1.00000 target=2.12781 diff=0.51442
iter=2 err=0.00000 F=1.00000 target=1.98969 diff=0.06491
iter=3 err=0.00000 F=1.00000 target=1.97815 diff=0.00580
iter=4 err=0.00000 F=1.00000 target=1.97697 diff=0.00060
iter=5 err=0.00000 F=1.00000 target=1.97687 diff=0.00005
iter=6 err=0.00000 F=1.00000 target=1.97687 diff=0.00000
iter=7 err=0.00000 F=1.00000 target=1.97687 diff=0.00000
Done! writing model file ...
自分の解析結果のくせに adding virtual node しますね。
まずこれは dicrc で指定してる MeCab の解析出力指定の一部が悪くて、
node-format-unidic22 = %m\t%f[0],%f[1],%f[2],%f[3],%f[4],%f[5],%f[6],%f[7],%f[8],%f[9],%f[10],%f[11],%f[12],"%f[13]","%f[14]","%f[15]","%f[16]","%f[17]","%f[18]",%f[19],%f[20],%f[21],%f[22],%f[23],"%f[24]","%f[25]","%f[26]",%f[27],%f[28]\n
この行の
"%f[13]","%f[14]","%f[15]","%f[16]","%f[17]","%f[18]",%f[19],%f[20],%f[21],%f[22],%f[23],"%f[24]","%f[25]","%f[26]",
このあたりのダブルクォーテーション(")でくくってるカラムには、アクセント関係の値が入るのだけど。例えば「"動詞%F1,形容詞%F2@-1"」みたいに 1 カラムにカンマ(,)区切りで複数値が入ってくることがあって。何もしてないと、CSV 的にはまずい。だけど複数値が入る場合だけダブルクォーテーションでくくるとかそういう複雑、dicrc では設定できない。なので苦肉の策で値が 1 個でも空でもとりあえず全部ダブルクォーテーションでくくっている。
空の場合「,"",」みたいになってしまうけれど、CSV のルール的には空要素扱いで特に問題はない。
ただ mini_lex.csv では、アクセント用のカラムに入る値が 1 個の時はダブルクォーテーションではくくっていないし、0 個の時はアスタリスク(*)が入る。
空の時にアスタリスク(*)が入るのは他のカラムでも同様。
くるま,0,0,0,名詞,普通名詞,一般,*,*,*,クルマ,車,くるま,クルマ,くるま,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297718133248,10533
車,0,0,0,名詞,普通名詞,一般,*,*,*,クルマ,車,車,クルマ,車,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297651024384,10533
くる,0,0,0,動詞,非自立可能,*,*,カ行変格,終止形-一般,クル,来る,くる,クル,くる,クル,和,*,*,*,*,*,*,用,クル,クル,クル,クル,1,C1,*,2891174448865963,10518
まで,0,0,0,助詞,副助詞,*,*,*,*,マデ,まで,まで,マデ,まで,マデ,和,*,*,*,*,*,*,副助,マデ,マデ,マデ,マデ,*,"名詞%F2@1,形容詞%F2@1,動詞%F2@1",*,9865651581755904,35891
で,0,0,0,助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ,0,0,0,動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
というわけで、
- 1 カラムに値が 0 or 1 つしか入っていないのにダブルクォーテーションでくくってあるカラムからくくってるダブルクォーテーションを除去
- 空のカラムはアスタリスクで埋める
を実施したのがこちら(↓)。
$ cat mecab_output_corpus_2.mecab
車 名詞,普通名詞,一般,*,*,*,クルマ,車,車,クルマ,車,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297651024384,10533
で 助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ 動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
EOS
くるま 名詞,普通名詞,一般,*,*,*,クルマ,車,くるま,クルマ,くるま,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297718133248,10533
で 助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ 動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
EOS
さっそく、mecab-cost-train
seed$ mecab-cost-train ../mecab_output_corpus_2.mecab model
reading corpus ...
Number of sentences: 2
Number of features: 52
eta: 0.00005
freq: 1
eval-size: 10
unk-eval-size: 4
threads: 1
charset: UTF-8
C(sigma^2): 1.00000
iter=0 err=0.50000 F=0.50000 target=0.69315 diff=1.00000
iter=1 err=0.00000 F=1.00000 target=0.50293 diff=0.27442
iter=2 err=0.00000 F=1.00000 target=0.29234 diff=0.41873
iter=3 err=0.00000 F=1.00000 target=0.29495 diff=0.00894
iter=4 err=0.00000 F=1.00000 target=0.17163 diff=0.41809
iter=5 err=0.00000 F=1.00000 target=0.17105 diff=0.00337
iter=6 err=0.00000 F=1.00000 target=0.17077 diff=0.00164
iter=7 err=0.00000 F=1.00000 target=0.17077 diff=0.00000
iter=8 err=0.00000 F=1.00000 target=0.17077 diff=0.00000
Done! writing model file ...
adding virtual node 回避。
ちなみにこういうふう(↓)に、空のカラムをアスタリスクで埋めなかったり、値が 1 個なのにダブルクォーテーションでくくってたり、ダブルクォーテーションでくくった空要素があると、CSV 側のアスタリスクで埋めてあるカラムと一致せず、もれなく adding virtual node 行き。
車 名詞,普通名詞,一般,,,,クルマ,車,車,クルマ,車,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297651024384,10533
で 助詞,"接続助詞",*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ 動詞,一般,"",*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
EOS
くるま 名詞,普通名詞,一般,*,*,*,クルマ,車,くるま,クルマ,くるま,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297718133248,10533
で 助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ 動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
EOS
seed$ mecab-cost-train ../mecab_output_corpus_3.mecab model
reading corpus ...adding virtual node: 名詞,普通名詞,一般,,,,クルマ,車,車,クルマ,車,クルマ,和,ク濁,基本形,*,*,*,*,体,ク ルマ,クルマ,クルマ,クルマ,0,C2,*,2895297651024384,10533
adding virtual node: 助詞,"接続助詞",*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
adding virtual node: 動詞,一般,"",*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
Number of sentences: 2
Number of features: 52
eta: 0.00005
freq: 1
eval-size: 10
unk-eval-size: 4
threads: 1
charset: UTF-8
C(sigma^2): 1.00000
iter=0 err=0.50000 F=0.50000 target=2.77259 diff=1.00000
iter=1 err=0.00000 F=1.00000 target=1.74502 diff=0.37062
iter=2 err=0.00000 F=1.00000 target=1.54654 diff=0.11374
iter=3 err=0.00000 F=1.00000 target=1.43054 diff=0.07501
iter=4 err=0.00000 F=1.00000 target=1.42481 diff=0.00400
iter=5 err=0.00000 F=1.00000 target=1.42397 diff=0.00059
iter=6 err=0.00000 F=1.00000 target=1.42393 diff=0.00003
iter=7 err=0.00000 F=1.00000 target=1.42393 diff=0.00000
iter=8 err=0.00000 F=1.00000 target=1.42393 diff=0.00000
Done! writing model file ...
同梱の SQL ファイルを読めばわかるけど、UniDic はver. 2.2.0 以降、DB から CSV を export する際に、空のカラムには必ずアスタリスクを入れているし、カラムに値が 2 つ以上入る場合のみ、ダブルクォーテーションでくくっている。
さらに補足だが、今回使っているミニデータでは feature.def でアクセント周りの素性は基の UniDic から削除して使っている。
なので実は、アクセント周りのカラムは空だろうが、ダブルクォーテーションでくくってあろうがなかろうが、問題なく動いたりする。
$ cat mecab_output_corpus_4.mecab
車 名詞,普通名詞,一般,*,*,*,クルマ,車,車,クルマ,車,クルマ,和,ク濁,基本形,*,*,*,*,体,クルマ,クルマ,クルマ,クルマ,0,C2,*,2895297651024384,10533
で 助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,*,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ 動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,C1,*,9848884062986923,35830
EOS
くるま 名詞,普通名詞,一般,*,*,*,クルマ,車,くるま,クルマ,くるま,クルマ,和,ク濁,基本形,*,*,*,"",体,クルマ,クルマ,クルマ, クルマ,0,C2,*,2895297718133248,10533
で 助詞,接続助詞,*,*,*,*,テ,て,で,デ,で,デ,和,*,*,*,*,*,*,接助,デ,デ,デ,デ,,"動詞%F1,形容詞%F2@-1",*,6837330270888448,24874
待つ 動詞,一般,*,*,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,*,*,*,*,*,*,用,マツ,マツ,マツ,マツ,1,"C1",*,9848884062986923,35830
EOS
seed$ mecab-cost-train ../mecab_output_corpus_4.mecab model
reading corpus ...
Number of sentences: 2
Number of features: 52
eta: 0.00005
freq: 1
eval-size: 10
unk-eval-size: 4
threads: 1
charset: UTF-8
C(sigma^2): 1.00000
iter=0 err=0.50000 F=0.50000 target=0.69315 diff=1.00000
iter=1 err=0.00000 F=1.00000 target=0.50293 diff=0.27442
iter=2 err=0.00000 F=1.00000 target=0.29234 diff=0.41873
iter=3 err=0.00000 F=1.00000 target=0.29495 diff=0.00894
iter=4 err=0.00000 F=1.00000 target=0.17163 diff=0.41809
iter=5 err=0.00000 F=1.00000 target=0.17105 diff=0.00337
iter=6 err=0.00000 F=1.00000 target=0.17077 diff=0.00164
iter=7 err=0.00000 F=1.00000 target=0.17077 diff=0.00000
iter=8 err=0.00000 F=1.00000 target=0.17077 diff=0.00000
Done! writing model file ...
ポイントなのは feature.def で使用しているカラムの中身がコーパスと CSV で同じ形で書かれていることだったりする。
未知語処理された行でエラーになるのに対応
ミニデータの CSV にはカタカナ表記の「クルマ」は入っていないので、
クルマで待つ
を作って、
$ mecab -d final raw_text_2.txt > mecab_output_corpus_5.mecab
ク 名詞,普通名詞,一般,,,
ル 名詞,普通名詞,一般,,,
マ 名詞,普通名詞,一般,,,
で 助詞,接続助詞,,,,,テ,て,で,デ,で,デ,和,"","","","","","",接助,デ,デ,デ,デ,"","動詞%F1,形容詞%F2@-1","",6837330270888448,24874
待つ 動詞,一般,,,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,"","","","","","",用,マツ,マツ,マツ,マツ,"1","C1","",9848884062986923,35830
EOS
これを訓練データにする。
seed$ mecab-cost-train ../mecab_output_corpus_5.mecab model
reading corpus ...adding virtual node: 名詞,普通名詞,一般,,,
adding virtual node: 名詞,普通名詞,一般,,,
adding virtual node: 名詞,普通名詞,一般,,,
adding virtual node: 助詞,接続助詞,,,,,テ,て,で,デ,で,デ,和,"","","","","","",接助,デ,デ,デ,デ,"","動詞%F1,形容詞%F2@-1","",6837330270888448,24874
adding virtual node: 動詞,一般,,,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,"","","","","","",用,マツ,マツ, マツ,マツ,"1","C1","",9848884062986923,35830
feature_index.cpp(278) [rewrite_.rewrite2(path->rnode->feature, &ufeature2, &lfeature2, &rfeature2)] cannot rewrite pattern: 名詞,普通名詞,一般,,,
これ実は rewrite.def の書き換えパターンにマッチしない(列数が足りてない)って怒られているだけで。
列数は実際足りているのだけど、カンマ(,)の直後に改行が入ると、カンマ直後のカラムを「ない」と判断しているだけなので。こういうふうに改行直前に値を入れてあげるだけで解決する。
ク 名詞,普通名詞,一般,,,*
ル 名詞,普通名詞,一般,,,*
マ 名詞,普通名詞,一般,,,*
で 助詞,接続助詞,,,,,テ,て,で,デ,で,デ,和,"","","","","","",接助,デ,デ,デ,デ,"","動詞%F1,形容詞%F2@-1","",6837330270888448,24874
待つ 動詞,一般,,,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,"","","","","","",用,マツ,マツ,マツ,マツ,"1","C1","",9848884062986923,35830
EOS
$ /work/oka/bin/mecab0996/libexec/mecab/mecab-cost-train ../mecab_output_corpus_5.mecab model
reading corpus ...adding virtual node: 名詞,普通名詞,一般,,,*
adding virtual node: 名詞,普通名詞,一般,,,*
adding virtual node: 名詞,普通名詞,一般,,,*
adding virtual node: 助詞,接続助詞,,,,,テ,て,で,デ,で,デ,和,"","","","","","",接助,デ,デ,デ,デ,"","動詞%F1,形容詞%F2@-1","",6837330270888448,24874
adding virtual node: 動詞,一般,,,五段-タ行,終止形-一般,マツ,待つ,待つ,マツ,待つ,マツ,和,"","","","","","",用,マツ,マツ, マツ,マツ,"1","C1","",9848884062986923,35830
Number of sentences: 1
Number of features: 32
eta: 0.00005
freq: 1
eval-size: 10
unk-eval-size: 4
threads: 1
charset: UTF-8
C(sigma^2): 1.00000
iter=0 err=1.00000 F=-nan target=7.45703 diff=1.00000
iter=1 err=0.00000 F=1.00000 target=4.06693 diff=0.45462
iter=2 err=0.00000 F=1.00000 target=3.24484 diff=0.20214
iter=3 err=0.00000 F=1.00000 target=3.22770 diff=0.00528
iter=4 err=0.00000 F=1.00000 target=3.22755 diff=0.00004
iter=5 err=0.00000 F=1.00000 target=3.22753 diff=0.00001
iter=6 err=0.00000 F=1.00000 target=3.22753 diff=0.00000
Done! writing model file ...
これで解決。