係り受け解析器の学習機能
もう少し自然言語処理の意味理解よりのことをちゃんと勉強してみようと思う今日この頃。のやったことメモ_φ(・_・
今回は、係り受け解析器のうち、CaboChaとJ.DepP の学習機能を動かしてみたのでその辺の備忘メモ
準備
CaboChaは既にインストール済み。
モデルは今回、KNBコーパスから学習させるので品詞体系をJUMANにしておく。モデル(係り受け、チャンキング、固有表現)もとりあえずJUMANに変更。
$ cat /usr/local/etc/cabocharc : posset = JUMAN : # Parser model file name parser-model = /usr/local/lib/cabocha/model/dep.juman.model : # Chunker model file name chunker-model = /usr/local/lib/cabocha/model/chunk.juman.model : # NE model file name ne-model = /usr/local/lib/cabocha/model/ne.juman.model :
MeCabのデフォルト辞書もJUMANに変更(辞書のインストールは既に済み)
$ cat /usr/local/etc/mecabrc : dicdir = /usr/local/lib/mecab/dic/jumandic :
動作確認
$ echo "クロールで泳いでいる少女を見た" | cabocha -f 2 -n 1 dep.cpp(90) [decode_posset(p) == posset()] model posset and dependency parser's posset are different: JUMAN != IPA
なぜか品詞体系がIPAのまま?実行時オプションは利いたので、とりあえず今はスルー
$ echo "クロールで泳いでいる少女を見た" | cabocha -P JUMAN -f 2 -n 1 クロールで-D 泳いでいる-D 少女を-D 見た EOS * 0 1D 0/1 1.421559 クロール 名詞,普通名詞,*,*,クロール,くろーる,代表表記:クロール/くろーる カテゴリ:抽象物 ドメイン:スポーツ O で 助詞,格助詞,*,*,で,で,* O * 1 2D 0/1 1.458612 泳いで 動詞,*,子音動詞ガ行,タ系連用テ形,泳ぐ,およいで,代表表記:泳ぐ/およぐ O いる 接尾辞,動詞性接尾辞,母音動詞,基本形,いる,いる,連語 O * 2 3D 0/1 1.458612 少女 名詞,普通名詞,*,*,少女,しょうじょ,代表表記:少女/しょうじょ カテゴリ:人 O を 助詞,格助詞,*,*,を,を,* O * 3 -1D 0/0 0.000000 見た 動詞,*,母音動詞,タ形,見る,みた,代表表記:見る/みる 補文ト 自他動詞:自:見える/みえる O EOS
続いてJ.DepP。 聞いたことなかったけど、CaboCha同様にコーパスから学習させることができるようなので入れてみた。学習、解析速度が速く、学習したモデルの精度もSVMに匹敵するらしい。
こちらは、デフォルトでMeCab、JUMAN辞書、モデルの学習にKNBコーパスを使うようになってる。
$ wget http://www.tkl.iis.u-tokyo.ac.jp/~ynaga/jdepp/jdepp-latest.tar.gz $ tar xzf jdepp-latest.tar.gz $ cd jdepp-2015-10-05/ $ ./configure $ make model $ sudo make install $ echo "クロールで泳いでいる少女を見た" | mecab | jdepp (input: STDIN [-I 0]) # S-ID: 1; J.DepP * 0 1D クロール 名詞,普通名詞,*,*,クロール,くろーる,代表表記:クロール/くろーる カテゴリ:抽象物 ドメイン:スポーツ で 助詞,格助詞,*,*,で,で,* * 1 2D 泳いで 動詞,*,子音動詞ガ行,タ系連用テ形,泳ぐ,およいで,代表表記:泳ぐ/およぐ いる 接尾辞,動詞性接尾辞,母音動詞,基本形,いる,いる,連語 * 2 3D 少女 名詞,普通名詞,*,*,少女,しょうじょ,代表表記:少女/しょうじょ カテゴリ:人 を 助詞,格助詞,*,*,を,を,* * 3 -1D 見た 動詞,*,母音動詞,タ形,見る,みた,代表表記:見る/みる 補文ト 自他動詞:自:見える/みえる EOS J.DepP profiler: io : 0.0166 ms./trial (0.06638521/4) dict : 0.3317 ms. preproc : 0.0194 ms. chunk : 0.0536 ms. depnd : 0.0250 ms.
ついでに、KNPも入れた。解析速度とか今のところ大規模なテキスト処理は厳しいけど、70億分のWebテキストから自動構築した格フレームとかいろいろ興味深いところもあるので、また別途時間をとっていろいろ確認したい。
$ tar xjf juman-7.01.tar.bz2 $ cd juman-7.01 $ ./configure --prefix=/usr/local $ make $ sudo make install $ echo "クロールで泳いでいる少女を見た" | juman クロール くろーる クロール 名詞 6 普通名詞 1 * 0 * 0 "代表表記:クロール/くろーる カテゴリ:抽象物 ドメイン:スポーツ" で で で 助詞 9 格助詞 1 * 0 * 0 NIL 泳いで およいで 泳ぐ 動詞 2 * 0 子音動詞ガ行 4 タ系連用テ形 14 "代表表記:泳ぐ/およぐ" いる いる いる 接尾辞 14 動詞性接尾辞 7 母音動詞 1 基本形 2 "代表表記:いる/いる" 少女 しょうじょ 少女 名詞 6 普通名詞 1 * 0 * 0 "代表表記:少女/しょうじょ カテゴリ:人" を を を 助詞 9 格助詞 1 * 0 * 0 NIL 見た みた 見る 動詞 2 * 0 母音動詞 1 タ形 10 "代表表記:見る/みる 補文ト 自他動詞:自:見える/みえる" EOS $ tar xjf knp-4.15.tar.bz2 $ cd knp-4.15 $ ./configure --prefix=/usr/local --with-juman-prefix=/usr/local/ $ make $ sudo make install $ echo "クロールで泳いでいる少女を見た" | juman | knp # S-ID:1 KNP:4.15-CF1.1 DATE:2015/11/26 SCORE:-19.12316 クロールで──┐ 泳いでいる──┐ 少女を──┐ 見た EOS
CaboChaのモデルをKNBコーパスから作る
CaboChaの学習/評価手順の確認。今回は手軽につかえるKNBコーパスを使ってチャンキングと係り受けモデルを作成する。
4ジャンルに分かれているので、単純に1つを評価用、残りの3つを学習用として作業する。
入力フォーマットは、CaboCha形式に変換する必要があるが、後述のJ.DepP付属のスクリプトがほぼそのまま使えるのでそちらを調整(ヘッダを消しただけ)して使わせてもらう。
評価用のスクリプト(eval.py)とかもJ.DepP付属のものを使用している。
最後に、各ジャンルの評価結果を↓でガッちゃんこしただけ
以下、コーパスの作成からモデルの作成、テスト、評価までの作業メモ
# KNBコーパスの変換 $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Keitai*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2cabocha.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc1.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Kyoto*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2cabocha.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc2.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Gourmet*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2cabocha.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc3.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Sports*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2cabocha.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc4.euc $ for i in `seq 1 1 4`; > do > iconv -f EUC-JP -t UTF-8 knbc$i.euc > knbc$i.utf8; > done # 学習用と評価用に分ける $ cat knbc2.utf8 knbc3.utf8 knbc4.utf8> corpus1 $ cat knbc1.utf8 > gold1 $ cat knbc3.utf8 knbc4.utf8 knbc1.utf8> corpus2 $ cat knbc2.utf8 > gold2 $ cat knbc4.utf8 knbc1.utf8 knbc2.utf8> corpus3 $ cat knbc3.utf8 > gold3 $ cat knbc1.utf8 knbc2.utf8 knbc3.utf8> corpus4 $ cat knbc4.utf8 > gold4 # 文節と係り受けを学習させてそのまま評価 $ for i in `seq 1 1 4`; > do > /usr/local/libexec/cabocha/cabocha-learn -e chunk -P JUMAN -t utf-8 corpus$i chunk$i.model; > /usr/local/libexec/cabocha/cabocha-learn -e dep -P JUMAN -t utf-8 corpus$i dep$i.model > cat gold$i | python ../tools/to_sent.py | mecab -d /usr/local/lib/mecab/dic/jumandic | cabocha -m dep$i.model -M chunk$i.model -P JUMAN -I1 -f1 > result$i > done $ for i in `seq 1 1 4`; > do > python ../tools/eval.py result$i gold$i 2> eval$i; > done # 評価結果をガッちゃんこ $ cat eval[1-4] | python ../tools/eval_all.py chunk: precision: 0.8221 (22713/27628) recall: 0.8189 (22713/27737) f1: 0.8205 sent acc.: 0.4853 (2031/4185) depnd: precision: 0.6288 (14742/23443) recall: 0.6259 (14742/23552) f1: 0.6274 sent acc.: 0.3642 (1524/4185)
あんまりよくない気が、、、そもそもMeCabを学習させてないからこんなもんか??
J.DepPのモデルをKNBコーパスから作る
同じことをJ.DepPでもやってみる。
$ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Keitai*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2kyoto.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc1.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Kyoto*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2kyoto.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc2.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Gourmet*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2kyoto.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc3.euc $ find ../KNBC_v1.0_090925/corpus1 -type f -name "KN*Sports*" | LC_ALL=C sort | xargs cat | python ../tools/knbc2kyoto.py KNP | python ../tools/replace_pos.py mecab -d /usr/local/lib/mecab/dic/jumandic > knbc4.euc $ for i in `seq 1 1 4`; > do > iconv -f EUC-JP -t UTF-8 knbc$i.euc > knbc$i.utf8; > done $ cat knbc2.utf8 knbc3.utf8 knbc4.utf8> corpus1 $ cat knbc1.utf8 > gold1 $ cat knbc3.utf8 knbc4.utf8 knbc1.utf8> corpus2 $ cat knbc2.utf8 > gold2 $ cat knbc4.utf8 knbc1.utf8 knbc2.utf8> corpus3 $ cat knbc3.utf8 > gold3 $ cat knbc1.utf8 knbc2.utf8 knbc3.utf8> corpus4 $ cat knbc4.utf8 > gold4 $ for i in `seq 1 1 4`; > do > mkdir -p model/knbc$i && rm -rf model/knbc$i/* > jdepp -t 0 -I 1 -c corpus$i -m model/knbc$i -- -t 1 -d 2 -c 0.0008 -i 40 -p > jdepp -t 3 -I 1 -c corpus$i -m model/knbc$i -- -t 1 -d 2 -c 0.0008 -i 40 -p -- -s 0.02 -i 5 -t 1; > jdepp -t 0 -I 2 -c corpus$i -m model/knbc$i -- -t 1 -d 2 -c 0.00005 -i 40 -p > jdepp -t 3 -I 2 -c corpus$i -m model/knbc$i -- -t 1 -d 2 -c 0.00005 -i 40 -p -- -- -s 0.005 -i 5 -t 1; > cat gold$i | python ../tools/to_sent.py | mecab -d /usr/local/lib/mecab/dic/jumandic | jdepp -m model/knbc$i > result$i > done $ for i in `seq 1 1 4`; > do > python ../tools/eval.py result$i gold$i 2> eval$i; > done $ cat eval[1-4] | python ../tools/eval_all.py chunk: precision: 0.9304 (25918/27856) recall: 0.9344 (25918/27737) f1: 0.9324 sent acc.: 0.7510 (3143/4185) depnd: precision: 0.7843 (18564/23671) recall: 0.7882 (18564/23552) f1: 0.7862 sent acc.: 0.4937 (2066/4185)
これを見るとやはりCaboChaの結果が怪しい、、、なにかやらかしてる感じか:-)
念のため、J.DepPをCaboChaと同じSVMで学習させたらどうなるか見てみる。
#そして、ちゃんと計測してないけどJ.DepPの学習明らかに速いな。学習/解析速度ももう少しデータ用意して比べてみたい。
TinySVMをインストール。
$ brew install tinysvm
以下、学習部分のみ。
SVM(-l 1)を使うときのオプションがよくわかってないが、とりあえずモデルディレクトリにSVMLight形式の学習データができてたからTinySVMにそいつを学習させた。結構時間がかかる。。。
: [省略] : $ for i in `seq 1 1 4`; > do > mkdir -p model/knbc$i && rm -rf model/knbc$i/* > jdepp -t 0 -I 1 -c corpus$i -m model/knbc$i -- -t 0 > svm_learn -t 1 -d 2 -c 1 model/knbc$i/chunk.train model/knbc$i/chunk > jdepp -t 3 -I 1 -c corpus$i -m model/knbc$i -- -t 0 -- -s 0.02 -i 5 -t 1; > jdepp -t 0 -I 2 -c corpus$i -m model/knbc$i -- -t 0 > svm_learn -t 1 -d 2 -c 1 model/knbc$i/depnd.p0.train model/knbc$i/depnd.p0 > jdepp -t 3 -I 2 -c corpus$i -m model/knbc$i -- -t 0 -- -- -s 0.005 -i 5 -t 1; > cat gold$i | python ../tools/to_sent.py | mecab -d /usr/local/lib/mecab/dic/jumandic | jdepp -m model/knbc$i > result$i > done $ for i in `seq 1 1 4`; > do > python ../tools/eval.py result$i gold$i 2> eval$i; > done $ cat eval[1-4] | python ../tools/eval_all.py chunk: precision: 0.9308 (25893/27818) recall: 0.9335 (25893/27737) f1: 0.9322 sent acc.: 0.7513 (3144/4185) depnd: precision: 0.7809 (18455/23633) recall: 0.7836 (18455/23552) f1: 0.7822 sent acc.: 0.4875 (2040/4185)
やはり、こっちはそれっぽい精度がでてる。。。にゃぜだ
ん〜、気になって眠れないけど眠いのでねる。
つづく(かも)