自然言語処理の深遠

Deep Dive Into Natural Language Processing

形態素解析を並列化して高速化するTip

自然言語処理ではその第一歩として形態素解析が行われることが多いと思います。 しかし、形態素解析をする際に、解析対象が大量にあると実行時間が結構かかります。 本記事では、Pythonconcurrent.futures モジュールを使った高速化方法を紹介します。

ナイーブな実装

想定している状況は、あるフォルダの中に大量のテキストファイルが存在し、そのファイルを読み込んで形態素解析するというものです。 以下のプログラムは、globを使ってファイルのリストを取得し、それらを読み込んでMeCab形態素解析をしています:

import glob
import MeCab

t = MeCab.Tagger()


def tokenize_parse(text_file):
    with open(text_file) as f:
        text = f.read()
        chunks = t.parse(text).splitlines()
        for chunk in chunks:
            pass  # do something                                                                                                                                                                        


for text_file in glob.glob("data/text/*/*.txt"):
    tokenize_parse(text_file)
    print('{} was processed'.format(text_file))

プログラムの内容はよくあるデータ処理のパターンに従っています:

  1. 処理したいファイルのリストを列挙する
  2. データを処理するhelper関数を書く
  3. ループ内でhelper関数を呼ぶことでデータを1件ずつ処理していく

このプログラムを7000ほどのテキストファイルに対して実行し、実行時間を計測してみましょう:

$ time python tokenizer_1.py
data/text/dokujo-tsushin/dokujo-tsushin-4778030.txt was processed
[... about 7375 more lines of output ...]
real    0m22.641s
user    0m10.134s
sys 0m1.139s

実行結果からこのプログラムの実行に 22.6秒 かかっていることがわかります。 並列に処理することで実行時間をどれくらい削減できるでしょうか?

パラレルな実装

データを並列に処理するためのアプローチとしては以下の方法が考えられます:

  1. テキストファイルのリストを分割する
  2. 分割数分のPythonプロセスを実行する
  3. 各プロセスは1で分割したデータを処理する
  4. 各プロセスの処理結果を統合する

並列処理するためにPython組み込みのモジュールである concurrent.futures を使うことができます。まずはimportしましょう:

import concurrent.futures

モジュールをimportしたら複数のPythonを並列に走らせるための命令を書きます。そのために ProcessPool を使います:

with concurrent.futures.ProcessPoolExecutor() as executor:

あとは executor.map() を使って通常のループを置き換えてしまいます:

text_files = glob.glob("data/text/*/*.txt")
for text_file, _ in zip(text_files, executor.map(tokenize_parse, text_files)):
    print('{} was processed'.format(text_file))

executor.map()関数の引数にはhelper関数と処理したデータを渡します。 そうすることで、リストの分割や分割したリストを子プロセスへ渡す、子プロセスを実行する、実行結果を統合するといった面倒な処理をしてくれます。

以上を踏まえて、ナイーブな実装を並列化してみました:

import concurrent.futures
import glob
import MeCab

t = MeCab.Tagger()


def tokenize_parse(text_file):
    with open(text_file) as f:
        text = f.read()
        chunks = t.parse(text).splitlines()
        for chunk in chunks:
            pass  # do something                                                                                                                                                                        


with concurrent.futures.ProcessPoolExecutor() as executor:
    text_files = glob.glob("data/text/*/*.txt")
    for text_file, _ in zip(text_files, executor.map(tokenize_parse, text_files)):
        print('{} was processed'.format(text_file))

実行時間を計測してみましょう:

$ time python tokenizer_2.py
data/text/dokujo-tsushin/dokujo-tsushin-4778030.txt was processed
[... about 7375 more lines of output ...]
real    0m10.284s
user    0m19.136s
sys 0m2.209s

実行時間は 10.3秒 になりました。ナイーブな場合と比べて約2倍に高速化されています。

まとめ

Python組み込みの concurrent.futures モジュールを使うことで簡単に並列処理を実装することができました。 実行時間を削減したいという方は並列化してみてください。

OpenCVでカメラ画像を取得したときの画像が暗かったのを直した話

機械学習で使うためにPythonからOpenCVを使ってカメラ画像を取得していた。 この際、取得した画像が暗くなってしまう問題に悩まされていた。 以下のような感じだ。 f:id:Hironsan:20170608150131p:plain

これではとても使えない。 結局ちょっとしたことで解決したので解決策をコードとともに載せておく。 f:id:Hironsan:20170608150145p:plain

続きを読む

PyEnchant使ってサクッとスペルチェックをする

Pythonで英語のスペルチェックをしようとしていたら、PyEnchantというライブラリを見つけたので紹介。PyEnchantを使うことで、スペルチェックしたりミススペルした単語に対して訂正語を提示したりできる。イメージ的にはGoogleのもしかしてに近いことをできる。

もともとはEnchantというC++で書かれたスペルチェッカーがあるのだが、PyEnchantはそのPythonバインディングという位置づけ。詳しい情報は以下の公式サイトを当たると良い。

PyEnchant a spellchecking library for Python

パッと見た限りでは日本語の情報もなかったので、この記事では簡単な使い方を紹介しておく。

続きを読む

Word Mover's Distance を使って文の距離を計算する

自然言語処理にとって文や文書間の類似度を計算するのは重要なタスクです。 類似文(書)の計算には、盗作の検知、関連記事の検索、質問応答における質問文の多様性の吸収といった様々な応用があります。

文書間の距離を計算する手法として Word Mover’s Distance があります。 Word Mover’s Distance は2015年に提案された手法です。Twitterのようなショートテキストに対して良い結果を示しているのが特徴です。 具体的には Word2vec や GloVe 等で得られた単語の分散表現を使って文書間の距離を計算します。

本記事では、Word Mover’s Distance を試してみることを目的としています。 具体的には gensim という単語の分散表現や類似文書を計算できるPythonライブラリを用いて Word Mover’s Distance を計算します。

なお、Word Mover’s Distance の理論については以下の記事が非常にわかりやすく解説してくださっているのでそちらを参照してください。 yubessy.hatenablog.com

では早速実装してみましょう。

続きを読む