Hatena::ブログ(Diary)

自然言語処理 on Mac

2016-06-26

Julia言語で実装された深層学習フレームワークMerlin

Recurrent Neural Networksなどの深層学習に基づく手法が近年の自然言語研究を席巻していて、画像認識のような圧倒的な性能差ではないですが、伝統的な構文解析タスクでもベンチマーク精度を叩き出していたりします:
Recurrent Neural Network Grammars

公開されている深層学習のフレームワークはまさに百花繚乱の状態で、多数のマシンに分散して計算が可能なGoogleTensorFlowや、TensorFlowやTheanoをベースにして直観的にプログラミングができるKeras、日本のPreferred NetworksのChainer、高性能なアンサンブル機械学習ライブラリXGBoostでも有名なdmlc (Distributed (Deep) Machine Learning Community)MXNetなど枚挙にいとまがありません。その中でもMerlinJulia言語で実装された異色のフレームワークです。

Julia言語のウェブページには、Pythonのような書きやすさでありながらCやFortranに迫る実行速度を示す衝撃的なベンチマーク結果が載っています。しかし例えばPythonの場合でも、NumpyやCythonなどを使ってさらに高速化していくことはできます。Juliaの良い点は、あまり速度面を気にしなくてもそこそこ高速なプログラムが書けて、さらに変数に型情報を与えたり配列のメモリ割当を減らすなど言語仕様の枠内のことをすることで比較的簡単に性能改善できる余地があることだと思います。このときマニュアルにあるような点に気をつけることが必要で、FAQにあるように、配列演算処理で余計なメモリ割当が起きてしまうことがあるので、原始的なループ処理で記述した方が高速になることがあります。

Juliaは2012年に公開されてからまだ日が浅く、言語仕様もまだまだ未成熟で、RやPythonMATLABなどと比べてライブラリが十分ではないなどの欠点はありますが、魅力的な特徴が色々ある言語なので、広まっていってほしいと切に願います。

2015-03-15

新語が追加されたmecab-ipadic-neologd辞書

日本語形態素解析エンジンMeCabで標準的に使われているIPA辞書に新語を追加したmecab-ipadic-neologdが公開されました:
[O] MeCab 用の新語辞書 mecab-ipadic-neologd を公開しました

これまでもWikipediaはてなキーワードからとりだした単語をMeCabの辞書に登録する取り組みはいろいろとありました:
livedoor Techブログ : wikipediaのデータや顔文字辞書からmecabのユーザ辞書を作成するフレームワーク
MeCabの辞書にはてなキーワードを追加しよう - 不可視点

最近のJUMANの辞書にもWikipediaやWebからとられた単語が登録されています:
JUMAN - KUROHASHI-KAWAHARA LAB

mecab-ipadic-neologdは新語データを定期的に更新して改善を続ける予定ということで、今後が楽しみです。

MacPortsにこのmecab-ipadic-neologdを追加しました。MeCabのシステム辞書として使う場合は次のコマンドを実行します:

$ sudo port selfupdate
$ sudo port install mecab-utf8 +neologd

解析対象の文字コードはUTF−8です。MeCabはもともとEUC文字コードベースだったため、ポート名には-utf8がついています。辞書データは、/opt/local/lib/mecab/dic/neologd-utf8にインストールされます。

ただし、すでにIPA辞書版などのmecab-utf8がインストールされている場合は上のコマンドがエラーを起こしてしまうので、いったんmecab-utf8を取り除いてから、オプションを指定して入れ直します:

$ sudo port -f uninstall mecab-utf8
$ sudo port install mecab-utf8 +neologd

なお、上のコマンドは単にシステム辞書のシンボリックリンク/opt/local/lib/mecab/dic/sysを張り替えるだけなので、これまでにインストールした辞書データやエンジン自体は消えずにそのまま残ります。

システム辞書を変えずに辞書データだけをインストールする場合は:

$ sudo port install mecab-ipadic-neologd

試しにサンプルの文を解析してみます:

$ echo '「人工知能」という名前は1956年にダートマス会議でジョン・マッカーシーにより命名された。' | mecab
「	記号,括弧開,*,*,*,*,「,「,「
人工知能	名詞,固有名詞,一般,*,*,*,人工知能,ジンコウチノウ,ジンコウチノウ
」	記号,括弧閉,*,*,*,*,」,」,」
という	助詞,格助詞,連語,*,*,*,という,トイウ,トユウ
名前	名詞,一般,*,*,*,*,名前,ナマエ,ナマエ
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
1956年	名詞,固有名詞,一般,*,*,*,1956年,センキュウヒャクゴジュウロクネン,センキュウヒャクゴジュウロクネン
に	助詞,格助詞,一般,*,*,*,に,ニ,ニ
ダートマス会議	名詞,固有名詞,一般,*,*,*,ダートマス会議,ダートマスカイギ,ダートマスカイギ
で	助詞,格助詞,一般,*,*,*,で,デ,デ
ジョン・マッカーシー	名詞,固有名詞,人名,*,*,*,ジョン・マッカーシー,ジョンマッカーシー,ジョンマッカーシー
により	助詞,格助詞,連語,*,*,*,により,ニヨリ,ニヨリ
命名	名詞,サ変接続,*,*,*,*,命名,メイメイ,メイメイ
さ	動詞,自立,*,*,サ変・スル,未然レル接続,する,サ,サ
れ	動詞,接尾,*,*,一段,連用形,れる,レ,レ
た	助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
。	記号,句点,*,*,*,*,。,。,。
EOS

人工知能」「1956年」「ダートマス会議」「ジョン・マッカーシー」が固有名詞としてかたまりでとれています。実際には解析の前に正規化処理をしておく必要があります。

ちなみにMacPortsではソースのスクリプトパッチをあてています。一つは、辞書をビルドするときに使われるxargsに制限によるもので、MacPortsビルド作業をするディレクトリ絶対パス名が、xargsが扱える引数のバイト数を超えて長くなってしまうので、相対パス名を使うようにしています。もう一つは、/tmpに一時ファイルを作らないようにして、MacPortsが管理していない場所にファイルが作られるのを防ぎます。ビルドのときはmacportsユーザで作業するため、/tmpに残ったファイルは一般ユーザが上書きできなくなってしまいます。

ところで現在MeCabソースコードGoogle Codeで管理されていますが、来年閉鎖されることが発表されました:
Google Open Source Blog: Bidding farewell to Google Code

MeCabのページにも、Export to GitHubのボタンがありますね。いろいろなコードやページのリンク先を書き換える必要がありそうです。

2015-02-15

MacPortsでCaffe

2012年の国際的な画像認識技術評価タスクで、多段の畳み込みニューラルネットワークを使った手法が圧倒的な性能を達成してから、画像認識研究は深層学習中心に一変しました:
[1409.0575] ImageNet Large Scale Visual Recognition Challenge

自然言語処理研究の分野でも、畳み込みニューラルネットワークを使う手法は、タスクごとの知識を利用しないで最高性能に迫る解析を行うSENNAが現れ、word2vec分散表現やアルファベットや読みを入力としてテキスト分類タスクベンチマークのbag-of-wordsモデルを超える性能を示したりと大変注目を集めています:
[1103.0398] Natural Language Processing (almost) from Scratch
[1408.5882] Convolutional Neural Networks for Sentence Classification
[1502.01710] Text Understanding from Scratch

深層学習を実装するフレームワークとして、Theano/Pylearn2TorchCaffeなど様々公開されていますが、Caffeは画像認識研究の最新成果が反映されていて、高速な上に使いやすく人気があります。

Caffeのインストール手順を見ると、Mavericks(10.9)以降のMacの場合、NVIDIAGPUを利用するために必要なCUDAのバージョン6までがgccベースのlibstdc++にリンクされているため、homebrewを使った少々面倒な手順が記述されていますが、CPUだけ、もしくは次期CUDAのバージョン7を利用する場合はもっと単純です。

Caffeは効率的なデータ処理を行うprotobufなどいくつかの依存パッケージが必要で、Pythonインタフェースも用意されていますが、MacPortsCaffeポートを使うと、CPUでの処理限定になりますが、簡単にMacインストールできます。Mac標準のベクトル数値演算ライブラリは、十分にチューニングされているためか結構高速ですが、複数のCPUコアでは同時に動作しません。Caffeポートはデフォルトの指定でOpenBLAS対応になって、CPUコアが最大限利用されるようになります。ただし、残念ながら全体の処理速度は思ったほどあがらないですが。。

Caffeをインストールして、手書き数字認識テストセットMNISTを標準的な畳み込みニューラルネットワークのLeNetで学習するサンプルを試してみます:

$ sudo port selfupdate
$ sudo port install caffe
$ cp -r /opt/local/libexec/caffe .
$ cd caffe
$ ./data/mnist/get_mnist.sh
Downloading...
...
Unzipping...
Done.
$ ./examples/mnist/create_mnist.sh
Creating lmdb...
Done.
$ vi examples/mnist/lenet_solver.prototxt
(最終行のGPUをCPUに変更します)
$ ./examples/mnist/train_lenet.sh
I0215 22:35:43.757207 2073379584 caffe.cpp:103] Use CPU.
I0215 22:35:43.758378 2073379584 caffe.cpp:107] Starting Optimization
I0215 22:35:43.759407 2073379584 solver.cpp:32] Initializing solver from parameters:
...
I0215 22:43:08.604959 2073379584 solver.cpp:246] Iteration 10000, loss = 0.00372661
I0215 22:43:08.604992 2073379584 solver.cpp:264] Iteration 10000, Testing net (#0)
I0215 22:43:11.086513 2073379584 solver.cpp:315]     Test net output #0: accuracy = 0.9902
I0215 22:43:11.087237 2073379584 solver.cpp:315]     Test net output #1: loss = 0.0292476 (* 1 = 0.0292476 loss)
I0215 22:43:11.087249 2073379584 solver.cpp:251] Optimization Done.
I0215 22:43:11.087255 2073379584 caffe.cpp:121] Optimization Done.
$ 

2.7 GHz Intel Core i5のマシンで動かして、8分弱の学習時間でテスト精度が99%を超えました! CUDAを有効にしてGPUを使ったり、NVIDIAが公開している深層学習用のcuDNNライブラリを利用するとさらに高速になります。ちなみにTheanoで同様のことを行うとCPU処理で6時間程度かかるようです。。

ちなみに、CaffeのPythonインタフェースは/opt/local/bin/python2.7から利用できます。NumPyやmatplotlib、scikit-learn、pandas、ipythonなど、機械学習統計処理などに適したAnacondaのように各種Pythonライブラリも同時にインストールされるので、デフォルトPythonとして普段から利用するのも良いと思います:

$ sudo port select --set python python27
$ sudo port select --set ipython ipython27

[2015-02-22追記]
CaffeポートにGPUとcuDNNを利用するオプションを追加しました。CUDA7(+cuDNN)が/usr/local/cudaにインストールされていることが前提です。ポートを+gpuや+cudnnオプションつきでインストールしようとすると、ソースからコンパイルが始まります:

$ port variants caffe
caffe has the variants:
[+]cpu: Use CPU only
     * conflicts with gpu
   cudnn: Use cuDNN
   gpu: Use GPU and CUDA in /usr/local/cuda
     * conflicts with cpu
[+]openblas: Use OpenBLAS
[+]python27: Install Python 2.7 interface
   universal: Build for multiple architectures
$ sudo port install caffe +gpu
または
$ sudo port install caffe +cudnn
...

また、まもなくCaffeのバージョン1.0が公開されるようです:
https://github.com/BVLC/caffe/pull/1849

2014-10-22

Emacs 24.4リリース

Emacsの最新版24.4がリリースされました。素のままのEmacsでは、日本語入力のときにキーに割り当てられた機能を使おうとすると、日本語がわたってしまってうまくいかないことなどがあって不便なので、インラインパッチが欠かせませんでした:
no title

上のパッチは現時点で24.3版用ですが、24.4版に対応したパッチが公開されています:
Emacs 24.4 for Mac OS X (2014/8/20 版) - Plamo Linux 日記

MacPortsのApplication版Emacsを最新版に更新してインラインパッチを適用しました。MacPortsインストールされていれば次のようにインストールできます:

$ sudo port selfupdate
$ sudo port install emacs-app

ちなみに、デフォルトで+inlineの指定が有効になってインラインパッチが適用されていて、これまで使えていた +patchesなどは無効です。最新版のOS X Yosemite (10.10)ではMacPortsのBuildbotが動いていませんが、Mavericks (10.9)、Mountain Lion (10.8)、Lion (10.7) ではバイナリができていて、インストールは短時間で終わります。Yosemite用のBuildbotの準備も進んでいるようなので楽しみです。
Index of /emacs-app

EmacsテキストエディタとしてVimとよく比較されますが、相互に類似のパッケージが実装されています。EmacsVimの操作性を実現したEvilや、ファイル名やモード名などを表示するモードラインを美しく描画するPowerlineなど、Vimに触発されたパッケージが様々あります:
Evil: EmacsをVimのごとく使う - 導入編 - 貳佰伍拾陸夜日記
emacsにpowerlineを導入 - $shibayu36->blog;

Powerlineですが、Emacs 24.4で表示されなくなる不具合が報告されています:
powerline is not saved properly under Emacs 24.4 ? Issue #58 ? milkypostman/powerline ? GitHub

とりあえずの解決方法としては、設定ファイル ~/emacs.d/init.el に次の行を加えれば良いようです:

(powerline-reset)

2014-08-11

機械学習に適した大規模分散計算環境Apache Spark

大規模分散計算環境のApache Sparkは、HadoopのMacReduceに比べてメモリ内で効率的に処理を行うことが特長で、機械学習ストリーム処理グラフ解析SQLデータ分析などの機能ライブラリがあります。Spark自体はScala言語で実装されていますが、Scalaの他にPython用のAPI対話的なシェルも用意されていて、どちらの言語でもプログラミングや動作確認が可能です。

動作確認は簡単にできて、Java6以上がインストールされていれば、Downloadsページから適当なビルド済みパッケージをダウンロードして解凍すると、ScalaまたはPython対話シェルが起動できます:

$ curl -O http://d3kbcqa49mib13.cloudfront.net/spark-1.0.2-bin-hadoop1.tgz
$ tar zxf spark-1.0.2-bin-hadoop1.tgz
$ cd spark-1.0.2-bin-hadoop1
$ bin/pyspark
..(中略)..
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_,_/_/ /_/\_\   version 1.0.2
      /_/

Using Python version 2.7.8 (default, Jul 13 2014 17:11:32)
SparkContext available as sc.
>>> 

ここではPython対話シェルを起動しています。

Sparkは、処理対象のデータをResilient Distributed Dataset (RDD)とよばれる並列処理用のデータ形式に変換します。RDDの内容そのものではなく適用する処理手順を記録しておき、どこかの計算機ノードで処理が失敗しても、直前のRDDの内容を復元して別のノードで処理を継続します。対話シェルで動作を確認すると、値が必要になるまで実際の処理を行っていないことが分かります。

たとえば、README.mdファイルを読み込んで各行の文字数を合計してみます:

>>> lines = sc.textFile("README.md")
14/08/11 18:54:09 INFO MemoryStore: ensureFreeSpace(32856) called with curMem=0, maxMem=309225062
14/08/11 18:54:09 INFO MemoryStore: Block broadcast_0 stored as values to memory (estimated size 32.1 KB, free 294.9 MB)
>>> lengths = lines.map(lambda s: len(s))
>>> lengths.reduce(lambda a, b: a + b)
14/08/11 18:55:03 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
14/08/11 18:55:03 WARN LoadSnappy: Snappy native library not loaded
14/08/11 18:55:03 INFO FileInputFormat: Total input paths to process : 1
14/08/11 18:55:03 INFO SparkContext: Starting job: reduce at <stdin>:1
14/08/11 18:55:03 INFO DAGScheduler: Got job 0 (reduce at <stdin>:1) with 2 output partitions (allowLocal=false)
14/08/11 18:55:03 INFO DAGScheduler: Final stage: Stage 0(reduce at <stdin>:1)
14/08/11 18:55:03 INFO DAGScheduler: Parents of final stage: List()
14/08/11 18:55:03 INFO DAGScheduler: Missing parents: List()
14/08/11 18:55:03 INFO DAGScheduler: Submitting Stage 0 (PythonRDD[2] at RDD at PythonRDD.scala:37), which has no missing parents
14/08/11 18:55:03 INFO DAGScheduler: Submitting 2 missing tasks from Stage 0 (PythonRDD[2] at RDD at PythonRDD.scala:37)
14/08/11 18:55:03 INFO TaskSchedulerImpl: Adding task set 0.0 with 2 tasks
14/08/11 18:55:03 INFO TaskSetManager: Starting task 0.0:0 as TID 0 on executor localhost: localhost (PROCESS_LOCAL)
14/08/11 18:55:03 INFO TaskSetManager: Serialized task 0.0:0 as 2999 bytes in 3 ms
14/08/11 18:55:03 INFO TaskSetManager: Starting task 0.0:1 as TID 1 on executor localhost: localhost (PROCESS_LOCAL)
14/08/11 18:55:03 INFO TaskSetManager: Serialized task 0.0:1 as 2999 bytes in 1 ms
14/08/11 18:55:03 INFO Executor: Running task ID 0
14/08/11 18:55:03 INFO Executor: Running task ID 1
14/08/11 18:55:03 INFO BlockManager: Found block broadcast_0 locally
14/08/11 18:55:03 INFO BlockManager: Found block broadcast_0 locally
14/08/11 18:55:04 INFO HadoopRDD: Input split: file:/.../spark-1.0.2-bin-hadoop1/README.md:2110+2111
14/08/11 18:55:04 INFO HadoopRDD: Input split: file:/.../spark-1.0.2-bin-hadoop1/README.md:0+2110
14/08/11 18:55:04 INFO PythonRDD: Times: total = 1345, boot = 1314, init = 30, finish = 1
14/08/11 18:55:04 INFO PythonRDD: Times: total = 1352, boot = 1310, init = 38, finish = 4
14/08/11 18:55:04 INFO Executor: Serialized size of result for 1 is 638
14/08/11 18:55:04 INFO Executor: Sending result for 1 directly to driver
14/08/11 18:55:04 INFO Executor: Finished task ID 1
14/08/11 18:55:04 INFO Executor: Serialized size of result for 0 is 638
14/08/11 18:55:04 INFO Executor: Sending result for 0 directly to driver
14/08/11 18:55:04 INFO Executor: Finished task ID 0
14/08/11 18:55:04 INFO TaskSetManager: Finished TID 1 in 1427 ms on localhost (progress: 1/2)
14/08/11 18:55:04 INFO DAGScheduler: Completed ResultTask(0, 1)
14/08/11 18:55:04 INFO TaskSetManager: Finished TID 0 in 1456 ms on localhost (progress: 2/2)
14/08/11 18:55:04 INFO TaskSchedulerImpl: Removed TaskSet 0.0, whose tasks have all completed, from pool 
14/08/11 18:55:04 INFO DAGScheduler: Completed ResultTask(0, 0)
14/08/11 18:55:04 INFO DAGScheduler: Stage 0 (reduce at <stdin>:1) finished in 1.475 s
14/08/11 18:55:04 INFO SparkContext: Job finished: reduce at <stdin>:1, took 1.656086 s
4094

Sparkに同梱されている機械学習ライブラリMLlibとよばれていますが、現時点で、線形SVMロジスティック回帰、決定木、ナイーブベイズ協調フィルタリング、k-meansクラスタリングなどの機能が提供されています。SparkのGithubにはサンプルのスクリプトとデータが登録されているので、動作確認をする場合はこちらをチェックアウトするとよいでしょう。

なお、Hadoopとの連携など大規模並列処理向け機械学習ライブラリMahoutは、今後MapReduceアルゴリズムを新規に実装することはやめて、Sparkに対応することになっています。