/*無料版Wordpress.comの制限でフォントが大きいです.最近のWordpress.comはfont-size指定を無視するみたいなので適宜縮小して読まれることをおすすめします.*/
前回のエントリでTensorFlowの導入を行いました.今回はMNISTチュートリアルを実際にやってみたのでコードを解読していこうと思います.
MNIST
MNISTは画像認識分野でよくトレーニングに使われる手書き文字データ集です.それぞれが28×28の画像で訓練集合が6万,テスト集合が1万存在します.TensorFlowのページでは画像認識機械学習のHello Worldと言われています.このデータを使って行う学習の目標としてはソフトマックス関数で入力画像が表す数値の確率を出力し,テスト集合で高スコアを出すことです.
準備
前回のエントリの手順でAnacondaとTensorFlowを導入し,Jupyter(IPython Notebook)を起動しましょう.JupyterはインタラクティブなPython実行環境で,ブラウザ上で実行されます.起動方法は端末上で
ipython notebook
です.ブラウザが起動するのでhttp://localhost:8888に移動するとJupyterを利用することができます.使い方の詳細は
IPython Notebookを使ってみる – たけぞう瀕死ブログ
が参考になります.端末上で行いたい場合は単に
ipython
と入力するとipythonが実行できます.
解読
初期化
from tensorflow.examples.tutorials.mnist import input_data mnist = input_data.read_data_sets('MNIST_data', one_hot=True) import tensorflow as tf
上のコードでMNISTのデータをなければダウンロードし,mnistという変数を介してアクセスできるようにします.三行目はユーザーが基本的に利用する名前空間のインポートです.
セッションの作成
sess = tf.InteractiveSession()
TensorFlowはバックエンドにC++を使用していてPython側から計算手順(グラフ)を構築します.一旦構築した計算手順はセッションを走らせることでC++側で実行されます.こうすることでPythonとのやり取りをできるだけ減らし,高速化を図ります.ただし,今回はインタラクティブな環境で実行するため,InteractiveSessionを使用してセッション開始後に計算手順を構築します(多分こちらの方法は遅い)
ノードの作成
x = tf.placeholder(tf.float32, shape=[None, 784]) y_ = tf.placeholder(tf.float32, shape=[None, 10])
入力ノードと出力ノードはplaceholderという名前の関数で構築されます.第一引数は型,第二引数は配列の形状です.xが入力ノードなので次元は28×28=784,出力は0~9までの10ラベルなので次元は10となっています.ここで,出力ノードがy_となっているのはこのノードには訓練データの正解ラベルが入力されるため,最終的な分類器の出力とは異なることを示しています.ここで宣言したノードは以下で見ていくようにあたかもPythonインタプリタ上の変数であるかのように扱うことができます.
ノード重みの作成
W = tf.Variable(tf.zeros([784,10])) b = tf.Variable(tf.zeros([10])) sess.run(tf.initialize_all_variables())
ノードの間をつなぐ重みはVariablesと呼ばれており,上のように宣言します.ここでWは入力ノードから各出力ノードにつながる次元784の重みベクトル10個分を合わせた行列,bはそれぞれの出力ノードへの活性化関数の引数に加算されるバイアス項です.三行目でVariablesをセッションによって初期化しています.
予測器の作成
y = tf.nn.softmax(tf.matmul(x,W) + b)
チュートリアルの最初では単純なソフトマックス回帰で分類するので予測関数はこのように宣言します.tf.matmulで入力ベクトルと重みの積をとることで10次元のベクトルに変換し,バイアス項を加えたあと10個の要素を用いてソフトマックス変換します.yは各クラスに分類される確率を表す10次元ベクトルになります.
損失関数の作成
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
損失関数は分類問題なのでクロスエントロピーを使います.tf.reduce_sumは全ミニバッチに対して引数の和を計算するものです.ミニバッチは確率的勾配降下で用いられる何個かの教師データをまとめたものです.
誤差関数の最小化方法を決める
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
ソフトマックス回帰なので最適化手法は確率的勾配降下ではなく最急降下法を用い,クロスエントロピーを最小化します.0.01は学習パラメータです.たったこれだけ指定すると誤差逆伝播から実際の目的関数の最小化まで自動でやってくれるので大変便利です.ただし他のライブラリも同じことをできるようです.
誤差関数を最小化する
for i in range(1000): batch = mnist.train.next_batch(50) train_step.run(feed_dict={x: batch[0], y_: batch[1]})
ここでforループを回して損失関数を最小化するようVariablesを調整します.train_step.runはfeed_dictからplaceholderに代入すべき値を持ってきて最適化を行います.そのためにbatchにmnist.train.next_batchで訓練データを取ってきています.
分類器の評価
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1)) accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) print(accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
訓練した分類器の性能を評価します.tf.argmaxはテンソル,テンソルの階数を引数にとって最大の要素のインデックスを返します.予測ベクトルの最大確率を与えるインデックスと正解インデックスをtf.equalで比較し,tf.reduce_meanで平均のcorrect_prediction,すなわち正答率を計算します.実際の計算は三行目のevalメソッドで行い,feed_dictからテスト用データを供給します.注意しないといけないのは二行目のtf.castで,そのままだとcorrect_predictionはboolean型なのでキャストしないといけないということです.以上のようにJupyterに入力していくとテストデータで91%くらいの正答率が得られるはずです.
雑感
今回は全然ディープラーニングに関係ないTensorFlowの使い方になってしまいましたが次回は後半の畳み込みニューラルネットワーク(CNN)のデモを実践します.APIなどが気になったら
API Documentation
をご覧になると良いかと思います.