この記事の内容
- Juman++をサーバーモードで利用すると、はかどる話
- 形態素解析を簡単に実行するPythonパッケージでJuman++を利用可能にした話
Juman++とは?
Juman++とは京大・黒橋研究室で開発された形態素解析器です。
「それ、Mecabと何が違うん?」と言う点ですが、Juman++では「RNN(いわゆるディープラーニング系のやつ)言語モデルを利用している」点が異なります。
Qiitaでも紹介記事が徐々に増えつつあり、今後の普及が楽しみです。
Juman++のちょっと気になる点
- 依存ライブラリを新しくしないといけない。特にgcc周り
- 遅い
依存ライブラリ問題は、gccを更新して、他のコード郡が動かなくなるかもしれない・・・という懸念はあります。
そういう場合はDocker環境を用意するというクールな解決法を使いましょう。
さて、問題は2の速度面です。
こちらの記事では、
Mecabは10秒ほどで終わったのに対し、JUMAN++は 10時間以上 かかってしまい
とのことで、速度面に懸念があるのは確かです。
私の環境でも計測比較をしてみました。
time echo "外国人参政権が認可された。私もあさって日曜最終日。" | mecab
echo 0.00s user 0.00s system 26% cpu 0.005 total
mecab 0.00s user 0.00s system 49% cpu 0.007 total
time echo "外国人参政権が認可された。私もあさって日曜最終日。" | jumanpp
echo 0.00s user 0.00s system 31% cpu 0.004 total
jumanpp 0.14s user 0.35s system 53% cpu 0.931 total
Mecabと比較して3桁も違う数値が出てしまいました。
この要因は設計云々ではなく、モデル読み込みに時間がかかっているため(らしいです。某所よりの話)
つまり、RNN言語モデルを利用する上で、仕方がないことではあります。
では、どうすればいいのでしょうか?
サーバーモードを利用しよう!
解決策は簡単で、「サーバースクリプトを使う」以上!です。
実はこれ、ver.1.0.1 マニュアルにきちんと書いてあります。
5ページを参照してください。
Juman++のtarに同封のRubyスクリプトを利用して、サーバーモードとして起動しっぱなしにしておきます。
マニュアルによると、
$ ruby script/server.rb --cmd "jumanpp -B 5" --host host.name --port 1234
でサーバー起動。クライアントして呼び出すには
echo "ケーキを食べる" | ruby script/client.rb --host host.name --port 1234
です。
では、サーバーモードを利用すると時間はどれくらいの短縮になるのでしょうか?
time echo "外国人参政権が認可された。私もあさって日曜最終日。" | ruby client.rb --host localhost
echo 0.00s user 0.00s system 21% cpu 0.006 total
ruby client.rb --host localhost 0.04s user 0.01s system 47% cpu 0.092 total
約10分の1の時間になりました!スゴイですね!
ちなみに、ネットワーク越しのJuman++だと、どうなるのでしょうか?
ローカルネットワーク内に存在するサーバーマシンにJuman++サーバーを起動し、計測してみました。
time echo "外国人参政権が認可された。私もあさって日曜最終日。" | ruby client.rb --host sever.hogehoge
echo 0.00s user 0.00s system 22% cpu 0.005 total
ruby client.rb --host sever.hogehoge 0.03s user 0.01s system 26% cpu 0.167 total
。。。。まあ、ネットワークレスポンスの考慮すると、こんなものでしょうか。
とにかく、サーバーモードを利用すると、ボトルネックは解決できることがわかったわけです。
みなさん、Juman++はサーバーモードで利用しましょう
PythonからJuman++のサーバーモードを利用する
先のクライアントスクリプトはRubyで記述されています。
なので、Rubyの人はそのまま使えばいいんじゃないっすかねー(鼻くそほじほじ)
ただ、私はPythonを常用する人なので、やっぱりPythonから呼び出ししたいわけです。
(client.rb
をPythonにして使いたい場合は、下の方にコードをはっつけておくので、そっちを見てください)
公式でpyknpというPythonパッケージが公開されていますが、実はjuman++用にはsubprocess呼び出ししか用意されていません。(pyknp-0.3での話)
これでは、サーバーモードの恩恵を受けることができないわけです。
私はJapaneseTokenizersというPythonパッケージを公開しています。
このPythonパッケージに組み込んじゃいました。
Python2xとPython3xの両方で利用可能です。
できること
- 1行で形態素分割結果をリスト取得
- 1行で形態素分割 -> 品詞フィルタリング -> ストップワード除去 -> リスト化
- Mecab, Juman, Juman++, Kyteaを同じ記法で呼び出し可能
インストール方法
- Mecab, Juman, Juman++をインストールする。このREADMEを見てください。
- Juman++をサーバーモードで起動する。Juman++同封の
server.rb
を使ってください。 pip install JapaneseTokenizer
でおしまいです。
使い方
Juman++をサーバーモードで呼び出すには1行で済みます。
>>> from JapaneseTokenizer import JumanppWrapper
>>> sentence = 'テヘラン(ペルシア語: تهران ; Tehrān Tehran.ogg 発音[ヘルプ/ファイル]/teɦˈrɔːn/、英語:Tehran)は、西アジア、イランの首都でありかつテヘラン州の州都。人口12,223,598人。都市圏人口は13,413,348人に達する。'
>>> list_result = JumanppWrapper(server='localhost', port=12000).tokenize(sentence, return_list=True)
>>> print(list_result)
['テヘラン', 'ペルシア', '語', '発音', 'ヘルプ', 'ファイル', '英語', 'Tehran', '西', 'アジア', 'イラン', '首都', 'テヘラン', '州都', '人口', '12,223,598', '都市', '圏', '人口', '13,413,348']
品詞で形態素選択をするには、選択したい品詞を List[Tuple[str]]
で渡してやります。
Juman++の品詞体系はこのページを見てください。
>>> from JapaneseTokenizer import JumanppWrapper
>>> sentence = 'テヘラン(ペルシア語: تهران ; Tehrān Tehran.ogg 発音[ヘルプ/ファイル]/teɦˈrɔːn/、英語:Tehran)は、西アジア、イランの首都でありかつテヘラン 州の州都。人口12,223,598人。都市圏人口は13,413,348人に達する。'
>>> pos_condition = [('名詞', '地名')]
>>> JumanppWrapper(server='localhost', port=12000).tokenize(sentence, return_list=False).filter(pos_condition=pos_condition).convert_list_object()
['テヘラン', 'アジア', 'イラン', 'テヘラン']
他にも品詞情報、表層系、その他、Juman++が出力する情報をまとめて獲得もできます。
詳しくはexamples.pyを参照ください。
前回の記事からの改良点
- Juman++を利用できるようにした
- Juman serverモードで発生するバグを解消
- 1行で品詞フィルタリングまでを完結させるシンタックスシュガーの導入