Juman++をサーバーモードで利用しよう

  • 18
    いいね
  • 0
    コメント

この記事の内容

Juman++とは?

Juman++とは京大・黒橋研究室で開発された形態素解析器です。
「それ、Mecabと何が違うん?」と言う点ですが、Juman++では「RNN(いわゆるディープラーニング系のやつ)言語モデルを利用している」点が異なります。

Qiitaでも紹介記事が徐々に増えつつあり、今後の普及が楽しみです。

Juman++のちょっと気になる点

  1. 依存ライブラリを新しくしないといけない。特にgcc周り
  2. 遅い

依存ライブラリ問題は、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を同じ記法で呼び出し可能

インストール方法

  1. Mecab, Juman, Juman++をインストールする。このREADMEを見てください。
  2. Juman++をサーバーモードで起動する。Juman++同封のserver.rbを使ってください。
  3. 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行で品詞フィルタリングまでを完結させるシンタックスシュガーの導入