うずまき2017 powered by Jun-Systems

耳管開放症, SAS, 統計解析, 人工知能, プログラミングそれに思考

*

TensorFlowについて書くよ pt.1: 単回帰の解読

      2016/06/28

自分自身TensorFlow自体については全く詳しくないので自学と備忘録を兼ねて書き連ねてゆく.ただし,ちょっとでもTensorFlow触ったことある人には無用の産物ですが,全く触ったことのない人にはちょっと説明不足かもしれないです.

今回はTensorFlowの使用例としてネットに上がっていた単回帰モデルの解読をやります.

1 つかTensorFlowって何

テンサーフロー/テンソルフロー
細かいことは他で読んでほしいんですが,Googleが提供するオープンソースのPython用ライブラリぐらいに思っとけばいいんじゃないでしょうか.機械学習向けのライブラリとか云われているものの,本来はテンソル(多次元配列)全般の計算のためのライブラリ(のはず).ちなみに,多次元配列というのは「2次元配列としての行列(マトリクス)」のもっと多次元版でMATLABとかが強いやつです.テンサーフローと呼びたいがテンソルの手前微妙な感じですね.

インストールの仕方などはQiitaに無限に記事があがってるのでその辺を読めばいいんですが,もし細かい依存ライブラリのdependenciesがうまく咬み合わないとprotobufの最適なバージョンがないとか怒られて動かなかったりします.その場合にはTensorflowとprotobufを一旦pipでアンインストールした後に

pip install https://storage.googleapis.com/tensorflow/自分にあう最新版.whl

みたいな感じにすればたぶん動くようになります.自分の環境に合う最新版を必ずここから拾ってきて差し替えてください.とりあえず動けばいいかなと思って最初version 0.9.0が出てる時に適当に0.5ぐらいのやつ入れたら調子悪くてまともに動きませんでした.

2 習得のために

Python自体についてはなんとなく書けることが前提にはなると思いますが,とりあえずaymericdamien/TensorFlow-Examples: TensorFlow tutorials and code examples for beginnersとかを適当になぞって内部でどういう処理を書いているのかをひとつずつ解明していけばいいと思います.

2.1 Basic Models: Linear Regressionを解読する

今回は例として[Example 2-1] Basic Models: Linear Regressionで何やってんのかを解読します.(これやる前にIntroductionのHello, World!Basic Operationは一通りやってみた方がいいです.プログラムが読めなくても英語と数学がわかれば10分で終わります.)

import tensorflow as tf
import numpy
import matplotlib.pyplot as plt
rng = numpy.random

必要なライブラリだけインポートします.これでtensorflowの各関数をtf.fooみたいな感じで呼び出せるようになりました.あとは下段でnumpyのランダムサンプリング用の関数群をrngで呼び出せるようにしています.

learning_rate = 0.01
training_epochs = 1000
display_step = 50
learning_rate

損失関数の最適化にあたって今回はGradient Descent(日本語だと勾配法とか勾配降下法とか呼ぶらしい)を使うわけですが,そこで使うパラメータですね.簡単に後述します.

training_epochs

いわゆる「何周まわすか」ですね.機械学習は学習データについて入力データと出力データが合うようにパラメータを更新していきます.パラメータの更新の回数はモデルの予測性能を見るにあたって重要なファクターになります.(この辺: An epoch is a measure of the number of times all of the training vectors are used once to update the weights – what is EPOCH in neural network)

display_step

あとで出てきますが,学習過程の表示数ですね.

train_X = numpy.asarray([3.3,4.4,5.5,6.71,6.93,4.168,9.779,6.182,7.59,2.167,
                         7.042,10.791,5.313,7.997,5.654,9.27,3.1])
train_Y = numpy.asarray([1.7,2.76,2.09,3.19,1.694,1.573,3.366,2.596,2.53,1.221,
                         2.827,3.465,1.65,2.904,2.42,2.94,1.3])
n_samples = train_X.shape[0]

train_X / train_Yではそれぞれ学習用の入出力データ(説明変数と目的変数)を用意しています.asarrayで配列(というかベクトル)として定義した説明変数train_Xはshapeで行列のサイズを取得できるので,train_X.shape[0]で行数(=オブザベーション数)を取得してn_sampleに格納します.

説明が下手ですが

mat1 = numpy.asmatrix([[1,1,1],[1,1,1]])
print mat1.shape

とかやれば意味わかると思います.

X = tf.placeholder("float")
Y = tf.placeholder("float")

TensorFlowではまず変数の型を定義します.今回はX,Yともにfloat型で,値の受け渡しはあとです.

W = tf.Variable(rng.randn(), name="weight")
b = tf.Variable(rng.randn(), name="bias")

今回は Y = W * X + bの形の単回帰なのでパラメータとしてのbとW(InterceptとCoeffientみたいな)を定義します.変数(Variable)として,最初に定義したrng(numpy.random)からrandn()関数をあてて,標準正規分布に従って初期値を設定しています.

pred = tf.add(tf.mul(X, W), b)

先に書きましたがモデル設定です. 予測値prediction = (W * X) + bの形でモデルを定義します.addとmulについては先述のBasic Operationのところで出てきますが,引数に入れた値について足したり掛けたりする関数です.

cost = tf.reduce_sum(tf.pow(pred-Y, 2))/(2*n_samples)
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(cost)

まず上段中身の関数から見ていきますが,pow(a,b)でa^bの計算,reduce_sumでは引数にテンソルを指定すると,返り値としてテンソルの全要素の和をとった0階のスカラーが返ってきます.この辺がわかりやすい.n_samplesはオブザベーション数なので,要は損失関数として,先の予測値predと実測値Yの差の二乗の平均値(MSE, Mean Squared Error)を定義しています.

回帰はこの損失関数の最小化をもって達成されるので,次にこの関数を最適化します.今回はGradient Descent(勾配法)を使います.一階微分してひたすらにより小さな値を模索する,健気でありながら堅実な方法ですね.その際に引数として最初に定義したlearning_rate(学習率)を指定しています.予測値と真値との差についてどの程度勾配を動かすかって話ですね.そして最後にGradientDescentを用いてのタスクとしてminimize(cost)で損失関数の最小化を指定します.

init = tf.initialize_all_variables()
with tf.Session() as sess:
    sess.run(init)

各変数の初期化してGraphの立ち上げ.この辺はIntroductionから出てきますね.

for epoch in range(training_epochs):
    for (x, y) in zip(train_X, train_Y):
        sess.run(optimizer, feed_dict={X: x, Y: y})

はじめに定義したtraining_epochsから1000epoch分のループを回します.
さらに各epochで,train_X,train_Yの各要素についてのループを回します.

最初にfloat型として指定した変数としてのX,Yにここで初めて値が流し込まれます.それがfeed_dict内で定義されます.
この辺はpythonのループの話になるので詳述はしませんが,要はtrain_X/Yそれぞれから取ってきた各要素x,yをfeed_dictに従って変数X,Yに流し込んだ上で,先のpotimizerを用いて最適化に向けて模索されるわけです.

if (epoch+1) % display_step == 0:
    c = sess.run(cost, feed_dict={X: train_X, Y:train_Y})
    print "Epoch:", '%04d' % (epoch+1), "cost=", "{:.9f}".format(c), \
        "W=", sess.run(W), "b=", sess.run(b)

ここでは,初めに指定したdisplay_stepの値(今回は50epoch毎)に,各epochでのMSEとWightとbiasの値を吐きます.
学習がちゃんと進んでるのかをその目で確かめてください.

print "Optimization Finished!"
training_cost = sess.run(cost, feed_dict={X: train_X, Y: train_Y})
print "Training cost=", training_cost, "W=", sess.run(W), "b=", sess.run(b), '\n'

終わったらそれっぽいメッセージと,最終的なMSE,W,bの値を吐きます.

plt.plot(train_X, train_Y, 'ro', label='Original data')
plt.plot(train_X, sess.run(W) * train_X + sess.run(b), label='Fitted line')
plt.legend()
plt.show()

最後にmatplotlibを使って学習結果をグラフにプロットします.初めの1行で元データのX,Yを散布図でプロット,その上からXに対する予測値(W*X+b)の回帰直線を引いて,凡例を加えたら表示させます.

そんな感じです.
途中から面倒くさくなって文章がどんどん減っていくのが目に見えてわかりますね.細かい最適化のアルゴリズムとかPython自体の話とか諸々だいぶ端折ってますが,まあ全体の流れとしては大体こんな感じじゃないでしょうか.

次号: TensorFlowについて書くよ pt.2: 重回帰への拡張


 - TensorFlow , , , , , ,

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

  関連記事