SEチャンネル

大学生プログラマができるかぎりIT系のことを書く備忘録メモ

TensorFlow入門 2

f:id:tkmtys:20160531223829j:plain

Python初心者がTensorFlowに入門してみるの続き。今回はMNISTの手書き数字の認識をやってみる。

MNISTとは

機械学習Hello World的なものらしいです。

60,000の教師あり学習用のデータと、学習結果を試験する10,000のデータの手書き数字で、すでにsize-normalizedとcenteredとfixed-sizeがなされている。

MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges

ページを見ると、学習用データと試験用データが確かにダウンロードできるが、すでにバイナリに圧縮されているので人が見れるデータではなくなっている。

sponsor

資材のダウンロード

チュートリアルのサンプルコードが実はTensorFlowをインストールした時点で既に一緒にインストールされている。以下のようにチュートリアルフォルダまで移動する。

$ cd ./tensorflow/ # 元のフォルダ
(tensorflow) $ source bin/activate
(tensorflow) $ cd ./lib/python2.7/site-packages/tensorflow/examples/tutorials/mnist/
(tensorflow) $ ls
__init__.py __init__.pyc    input_data.py   input_data.pyc  mnist.py    mnist.pyc

全部あるはず、、、と思ったが、実際にはGithubに公開されているものから幾つか不足している。git cloneでコピーしても良いが、ファイル1つなのでコピーで作成する。

tensorflow/tensorflow/examples/tutorials/mnist at r0.8 · tensorflow/tensorflow · GitHub

ここのmnist_softmax.pyをコピーして同じフォルダに同じ名前で作成する。

実行

とりあえずコードを見る前に実行してみる。

(tensorflow) $ python mnist_softmax.py 

Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting /tmp/data/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting /tmp/data/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting /tmp/data/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting /tmp/data/t10k-labels-idx1-ubyte.gz
0.915

先ほどのMNISTからデータを/tmp/data配下にダウンロードして、学習を行い、10,000の試験データに対する精度が最後に出力されている。この数値は実行する度に変わるようだ。概ね0.92前後で、100個のデータに対して8個は誤っていることになる。

sponsor

コードの中身

早速、実行したmnist_softmax.pyの中を見てみる。

インポート

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

from tensorflow.examples.tutorials.mnist import input_data

import tensorflow as tf

ここらへんはモジュールのインポートで同じディレクトリのinput_data.pyをインポートしている。またtensorflowモジュールをtfとしてインポートしている。

mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True)

input_dataでダウンロードした画像データ群をmnist変数に代入している。

変数の定義

x = tf.placeholder(tf.float32, [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, W) + b)

ここは単なる変数の定義で、上から、

  1. xはfloat32の[None, 784]の行列
  2. Wはzeroで埋めた[784,10]の行列
  3. bは[10]のベクトル
  4. yはW*x + bにsoftmax関数を当てたもの(=[None,10]のベクトル)

という定義をしている。ちなみに784の理由はMNISTの元画像が28×28=784のサイズで、それを1次元ベクトルにしているからだ。 Noneは画像の枚数が入るが、後でわかるようにバルクで処理するために不定となっている。

bとかyが10なのは、画像の数字が0~9のどのクラスに分類されるかのブール値を埋めるから。 式の意味としては、 xという入力ベクトル(=28×28の画像)があったときにW*x+bという線形な計算で0~9のどれかを予測するyが得られるという、かなり無理やりな予測だ。(だから最初の予測精度は0.915とかなり悪い結果になっている)

ここまでは単なる変数で、tensorflow的には、MNISTの60,000のデータからWとbを決定する学習フェーズが後にある。

学習モデルの設定

y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

学習するための下準備。 y_という実際の正解値(教師ありなので)を入れる変数を1行目で用意している。

2行目は、正解値と予測したyとの差、クロスエントロピーという量を計算している。(実際にはこの時点でyには何も入ってないので 計算モデルのみ定義している)

3行目は学習の進め方を選択している。最急降下法(GradientDescentOptimizer)で、クロスエントロピーを最小化する設定としている。

ここらへんは機械学習のモデルにクリティカルに関わってくるので、 今度また別エントリで書きたい。

学習フェーズ

tf.initialize_all_variables().run()
for i in range(1000):
  batch_xs, batch_ys = mnist.train.next_batch(100)
  train_step.run({x: batch_xs, y_: batch_ys})

学習の実行。 100枚の画像単位で1000回学習を繰り返している。

結果出力

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({x: mnist.test.images, y_: mnist.test.labels}))

1000回の学習が終了した時点で、精度を出力している。

1行目は予測が正しいか正しくないかの変数をcorrect_predictionとしている。(例によってyとかに依存せずに計算モデルのみ定義している) tf.argmax(y,1)はyの中で値が最も大きいindexを返す関数。なので、tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))は型的にはブール値(予測があっていたか間違っていたか)のリストとなる。 正解してれば1に、間違っていれば0にキャストして全体の平均をとることで、精度を出している。

まとめ

ここまでは単にチュートリアルのコードを実行して中身を見ただけなので、 次回は学習するモデルを変更してみる。