Theano 解説

Deep Learning Implementation」でググるとトップに出てくることで, たまに話題になるライブラリ Theano について簡単に調べたので紹介する. 間違いがあったら是非教えて欲しい. なお, Deep Learningに関する解説は今回は行わない.

TheanoとはPythonにおける数値計算用のライブラリである. 行列演算などを行う関数を提供しており, numpy/scipyの代替パッケージと思えばいいだろう.

大きな特徴は

  • 実行時におけるC++コードの生成とコンパイル
  • GPUサポート
  • 解析的な微分のサポート (x^2の微分=2xという操作を自動でやってくれる)

の3つである. 一部は後に詳細を説明する.

これによってMultilayer Perceptronを実行するベンチマークでは, Theanoがnumpyより1.8倍, Matlabより1.6倍速いという結果がこちらの資料で示されている. (もちろん速度差はケースバイケースである)

同じベンチマークでTheano on GPUだとNumpy on CPUより11倍速いと主張しているが, Numpy側が1コアで動作していたり, Core 2 DuoとGTX285の比較ってフェアなの? という疑問から数字自体にあまり意味を感じない. ただし, Matlab on GPUより6倍程度速いというのは参考になるかもしれない. (実装次第だが)

これらの高速に動作することに加え, 解析的に微分を計算してくれるのが便利である. TheanoはMaximaのように数式をシンボル上で操作できるため,
\frac{d}{dx} x^2 = 2x
みたいなことが出来る. このことはニューラルネットワークのように微分を自分でやるのが面倒で, かつ勾配法を行う際に非常に便利である.

ここまでのまとめ

少し触ってみた感触では, ニューラルネットワークを構築する際には, 確率勾配法で必要な勾配をライブラリ側で求めてくれるため, 中間層をたくさん用いたり, ニューラルネットワーク内で用いる非線形関数を変更したくなった際に非常に便利である.

しかし, ニューラルネットワーク系の研究室が作っているせいか, ニューラルネットワーク関係以外の実装があまり充実していない. 一番大きな問題としては, 固有値の計算などが含まれていないし, 逆行列の計算もexperimentalのようだ(これを見る限り進んではいるようだが). また, 凸最適化などの機能も含まれていないためcvxoptなどと連携する必要がある(もっともこれはscipyにもないが).

欠点はあるが速度は悪くてもscipy程度であることが期待でき, 自分の考えた多層ニューラルネットワークを高速に実装できることは間違いない. また, 少しの変更でGPUも利用できる. scipyとインターフェイスが近く学習コストは高くないため, 自分の実装したいアルゴリズムがTheanoの枠内に収まるなら試しに使ってみてもいいかもしれない.

ここから先は詳細とメモ

実行時におけるC++コードの生成とコンパイル

実行時におけるコンパイルをコードを用いて説明しよう.
以下のコードは与えられた行列を2倍して返すものである.

#!/usr/bin/python

import theano
import theano.tensor as T

A = T.matrix()
B = A*2

f = theano.function([A], B)

print f([[1,2],[3,4]])

最初の

A = T.matrix()

C++における型の宣言のようなもので, Aがmatrixであると指定する.
そして,

B = A*2

という風に行列に対する演算を行う. そして関数を宣言する.

f = theano.function([A], B)

これは引数としてAを取り, 返り値としてBを返す関数の宣言である. ここまでで具体的なAの値は与えられていない. ここでC++コードが生成されコンパイルが行われる.

print f( [ [1,2],[3,4] ] )

最後に, 関数を呼び出して結果を得る. これがTheanoの一連の流れである.

型情報を明示的に与えることから, 裏にC++の存在が透けて見えるだろう. コンパイル時に様々な最適化を行なっており,

  • 無駄な演算の削除 (a*b / a => b)
  • 無駄なメモリコピーの削除 (A = B + C + DとしたときB+Cで中間オブジェクトを作成しない. たぶん)
  • 繰り返し演算の統合 (c=a+b , d=2*(a+b)とあったときa+bは一度だけ計算される)
  • Python側で受け取るオブジェクト以外はPythonオブジェクトを作成しない?(未確認)

などの特徴がある. 大体は, 自分で管理できると思ってしまいそうだが, 勾配を自動で求めさせたりすると効果を発揮しそう.

データ量に対して小さい演算が多発するような状況では, 無駄な中間オブジェクトを作成しない分, scipyなどに比べて優位性が出てくると予想している.

メモ

forループのサポートとかはたぶん弱い. 一応, scan関数というforループをサポートしてるっぽいものが出てくるけど, Pythonのforループよりちょっと速い程度と書かれているので, たぶん凄く遅い(未確認). 行列演算に落とし込めないアルゴリズム(Dynamic Time Warpingの計算みたいな)はあまりうまく機能しないだろう.

コンパイラとかコンパイルオプションとかは自由に指定できるので, ATLAS使ったりMKL使ったりはやり放題. また, コンパイル結果はキャッシュされるので2回目の実行は速い.

マルチスレッドサポートは弱い. 畳み込みの計算(ex.画像へのフィルタ)を複数スレッドでしてくれるぐらい. ちゃんとマルチスレッドをやりたいなら, multiprocessを自分で使う必要がある.

Deep Learningチュートリアルがわかりやすい使用例になってる感じなので興味があったら読んでみたらいいかもしれない.