Theanoに限らず機械学習の分野では 人工知能に関する断創録 の素晴らしさがが突出しています。
ここでは、 人工知能に関する断創録 のTheanoに関連する記事をSageのノートブックで実装し、Thenoの修得を試みます。
最近では、誰でも簡単にDeeepLearningを体験できるtensorflowが注目されていますが、 「人工知能に関する断創録」の作者が言われているように 「TheanoはDeep Learning Tutorialをはじめ、実装例が豊富にあり、絶妙な粒度で小回りもきくので手法の勉強にちょうどよいんだよね。」 というのがとても納得できます。
今回は、 深層学習 (機械学習プロフェッショナルシリーズ) をベースに以下の内容をSageのノートブックで試します。
Sageでtheanoを使うには、以下の手順でtheanoのインストールが必要です。
$ sage -sh (sage-sh) $ easy_install theano Searching for theano Reading https://pypi.python.org/simple/theano/ Best match: Theano 0.8.2 途中省略 Installed /Users/take/local/sage-6.9/local/lib/python2.7/site-packages/Theano-0.8.2-py2.7.egg Processing dependencies for theano Finished processing dependencies for theano (sage-sh) $ exit
最初に、theanoを使うのに必要なライブラリをインポートします。
|
Sageと同様にTheanoも関数を定義するために、 変数(Theanoではシンボル: TensorVariableと呼ぶらしい)を宣言します。
Theanoの変数宣言は以下の様なルールになっています。
変数 = T.型タイプ()型には、d: Double、f: Float、l: Longが指定され、 タイプには、scalar: 値、vector: ベクトル、matrix: 行列が指定されます。
Theanoでは、シンボルで定義した関数を実行時にコンパイルします。
それでは、人工知能に関する断創録の例題に沿って、変数の宣言、関数の定義、関数のコンパイルを実行してみましょう。
<class 'theano.tensor.var.TensorVariable'> <class 'theano.tensor.var.TensorVariable'> |
<class 'theano.tensor.var.TensorVariable'> <class 'theano.tensor.var.TensorVariable'> |
<class 'theano.compile.function_module.Function'> <class 'theano.compile.function_module.Function'> |
1.0 4.0 9.0 16.0 1.0 4.0 9.0 16.0 |
Theanoでは、スカラー、ベクトル、行列などを抽象化した概念テンソル(Tensor)を導入し、 theano.tensorで定義されており、インポート部でこれをTと宣言し、同じ関数定義を ベクトルや行列に簡単に拡張することができます。
[ 1. 4. 9.] [ 1. 4. 9.] |
[[ 1. 4. 9.] [ 16. 25. 36.]] [[ 1. 4. 9.] [ 16. 25. 36.]] |
ニューラルネットの活性化関数で使われているシグモイド関数、 $$ s(x) = \frac{1}{1 - e^{-x}} $$ をTheanoで実装します。
その前に、Sageのplot関数を使ってシグモイド関数の形を見てみましょう。
|
Theanoでの実装は以下の様になります。
入力を行列の形式で与えているので、結果も各入力値に対するシグモイド関数の値が行列として返されます。
[[ 0.5 0.73105858] [ 0.26894142 0.11920292]] [[ 0.5 0.73105858] [ 0.26894142 0.11920292]] |
Theanoの共有変数がGPUのメモリと密接に関係しているという説明を読んで、GPUのメモリに合わせてfloat型 (theano.config.floatX)にしたり、値の取得にget_value()というメソッドを使っていることが納得できました。
私の環境ではGPUが使えないため、type(X)の型は、theano.tensor.sharedvar.TensorSharedVariableでした。
<class 'theano.tensor.sharedvar.TensorSharedVariable'> [[ 1. 2. 3.] [ 4. 5. 6.]] <class 'theano.tensor.sharedvar.TensorSharedVariable'> [[ 1. 2. 3.] [ 4. 5. 6.]] |
共有変数の例として、線形回帰のモデル式が使われています。 回帰モデルは以下の式で、Wとbが共有変数としてyを求めてみます。 $$ y = W x + b $$
共有変数は値を取得するときにはget_valueが必要ですが、関数を表す式を定義するときにはシンボルと同様に 使えるのは良く出来ているとなぁと思いました。
|
[[ 1. 2. 3.] [ 4. 5. 6.]] [ 1. 1.] [[ 1. 2. 3.] [ 4. 5. 6.]] [ 1. 1.] |
<class 'theano.tensor.var.TensorVariable'> <class 'theano.tensor.var.TensorVariable'> |
[ 7. 16.] [ 7. 16.] |
Theanoの特徴の一つに自動微分があります。ニューラルネットの計算で、入力値から予測値を計算するフィードフォワードに対し、 予測結果と正解のずれを誤差関数Eとして表し、重みWの値を更新するバックプロパゲーションでは、誤差関数Eの微分が必要になります。 $$ w^{\tau+1)} = w^{(\tau)} - \mu \Delta E(w^{\tau}) $$
PRMLの第5章にある多層パーセプトロン関数近似をSageで試した sage/PRML- 多層パーセプトロン関数近似 では、PRMLの式の変換を手でお復習いして、確認しました。 この作業はとても手間が掛かり、ミスも多くなります。
(注 特にニューラルネットの計算はとても時間が掛かるため、実務でニューラルネットを使った場合、式のミスをリカバリすのはとても大変です。)
以下のような2次関数の微分をTheanoの自動微分を使って計算してみましょう。 $$ y = x^2 $$ 高校で習った微分の公式から、以下の様になりますね。 $$ \frac{dy}{dx} = 2 x $$
これをTheanoの自動微分を使って解いてみましょう。
微分は、T.grad()のcostに微分される式のシンボル(y)、wrtに微分する変数のシンボルを与えて計算します。
|
微分結果のシンボル(gy)は、そのままでは使えないので、function()で関数かしてから使用します。
微分の結果を表示するには、theano.pp()を使って表示します。
(TensorConstant{2.0} * x) (TensorConstant{2.0} * x) |
4.0 6.0 8.0 4.0 6.0 8.0 |
どんな時も代替手段を持っておくことが大切です。ある方法で上手く行かないとき、 なぜ正しく動かないのかを別の方法の結果と比較することで修正することができます。
Sageの計算は、numpyやTheanoのように速くありませんが、比較的数式に近い形式で計算することができます。
Sageの数式処理を使って上記の2次関数の微分を試してみましょう。diffが数式の微分を行う関数です。
2*x 2*x |
4 6 8 4 6 8 |
例2の指数関数を省略して、例3のsin(x)を計算します。 $$ y = sin(x) $$ $$ \frac{dy}{dx} = cos(x) $$ を計算します。
cos(x) cos(x) |
1.0 6.12323399574e-17 -1.0 1.0 6.12323399574e-17 -1.0 |
今度は、例4の多項式です。 $$ y = (x - 4)(x^2 + 6) $$ $$ \frac{dy}{dx} = 3 x^2 - 8x + 6 $$
Elemwise{Composite{(i0 + sqr(i1) + (i2 * (i3 + i1) * i1))}}(TensorConstant{6.0}, x, TensorConstant{2.0}, TensorConstant{-4.0}) Elemwise{Composite{(i0 + sqr(i1) + (i2 * (i3 + i1) * i1))}}(TensorConstant{6.0}, x, TensorConstant{2.0}, TensorConstant{-4.0}) |
6.0 1.0 2.0 6.0 1.0 2.0 |
結果の式のi0, i1, i2, i3は、次の括弧のTensorConstant{6.0}, x, TensorConstant{2.0}, TensorConstant{-4.0}に対応します。 これをxの式に書き直すと以下の様になります。
6 + x**2 + (2*(-4+x)*x)
この式を手計算で整理する代わりにSageで確認してみましょう。dyに上記の式を代入し、expand()関数で展開してshow()で表示するだけです。 このように簡単に結果を確認できますよ。
|
例5を省略して、例6の偏微分を試してみます。
以下の式zをx, yでそれぞれ偏微分します。 $$ z = (x + 2y)^2 $$ $$ \frac{\partial{z}}{\partial{x}} = 2(x + 2y) $$ $$ \frac{\partial{z}}{\partial{y}} = 4(x + 2y) $$
Elemwise{Composite{(i0 * (i1 + (i2 * i3)))}}(TensorConstant{2.0}, x, TensorConstant{2.0}, y) Elemwise{Composite{(i0 * (i1 + (i2 * i3)))}}(TensorConstant{4.0}, x, TensorConstant{2.0}, y) Elemwise{Composite{(i0 * (i1 + (i2 * i3)))}}(TensorConstant{2.0}, x, TensorConstant{2.0}, y) Elemwise{Composite{(i0 * (i1 + (i2 * i3)))}}(TensorConstant{4.0}, x, TensorConstant{2.0}, y) |
10.0 12.0 20.0 24.0 10.0 12.0 20.0 24.0 |
最後にSageで偏微分を試してみましょう。
x, yの変数をvar関数で定義し、zの数式を定義します。偏微分はdiff関数の微分変数を変えるだけです。
非常に簡単にfgx, fgyを計算できるのがお分かり頂けると思います。
(x, y) |--> 2*x + 4*y (x, y) |--> 4*x + 8*y (x, y) |--> 2*x + 4*y (x, y) |--> 4*x + 8*y |
10 12 20 24 10 12 20 24 |
|