私的Chainer入門してみたイキオイで、続きをやってみることにする。
とはいえ、chainerを極める方向に行くよりも、いろいろと食い散らかしておきたい。
まあ、そんなワケで、TensorFlowである。
MNIST For ML Beginnersを参照しつつすすめる。
私的Chainer入門やPythonでKNNを使った手書き文字認識でもMNISTを扱ったワケだけれど、こいつをつかって「数字判別機を作る」というのは、機械学習のチュートリアルの基礎中の基礎だ。言うなれば、Oracleデータベースを初めて触る人がscott/tigerのempデータベースをselectするSQL文から入るようなもんだ。
TensorFlowの準備から
PythonからTensorFlowを使う。AnacondaでPython環境を作っているので、ドキュメントに従い、以下のようにインストールする。
% conda install -c conda-forge tensorflow
以上でインストール完了である。
MNIST For ML Beginnersに戻る
ワケの分からないまま、以下のコードを実行する。
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
とりあえず、ipythonで実行したところ、以下のようになった。
In [1]: from tensorflow.examples.tutorials.mnist import input_data
In [2]: mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting MNIST_data/train-images-idx3-ubyte.gz
Successfully downloaded train-labels-idx1-ubyte.gz 28881 bytes.
Extracting MNIST_data/train-labels-idx1-ubyte.gz
Successfully downloaded t10k-images-idx3-ubyte.gz 1648877 bytes.
Extracting MNIST_data/t10k-images-idx3-ubyte.gz
Successfully downloaded t10k-labels-idx1-ubyte.gz 4542 bytes.
Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
どうやら、データがダウンロードされたようだ。
% % ls -s1 MNIST_data/
total 22672
3224 t10k-images-idx3-ubyte.gz
16 t10k-labels-idx1-ubyte.gz
19368 train-images-idx3-ubyte.gz
64 train-labels-idx1-ubyte.gz
TensorFlowでのMNIST実装
MNIST For ML Beginnersによると、chainerのチュートリアルであったように、28x28ピクセルの手書き数字の画像が0〜9のいずれであるのか?をy = Wx + bの線形の式で評価する。
違いは、chainerのチュートリアルでは、chainer.links.Linear()していたところを、Softmax Regressionを使って評価せよという点か。
このあたりの違いについては、勉強不足過ぎて分からない。
チュートリアルによると、数字1個あたり28x28ピクセルの画像データになっているが、これを1次元の28x28=784の配列データであるとみなして、それが55000個あるという前提で考えるようだ。すなわち全データが784行×55000列の行列であるとみなして、これをmnist.train.xsとしている。それぞれの列のラベル(すなわち、各列が0〜9のいずれであるか?を示す)を10行×55000列の行列として保持していて、ソレをmnist.train.ysとしている。なんで、10行か?というと、0を[1,0,0,0,0,0,0,0,0,0]、3を[0,0,0,1,0,0,0,0,0,0]のように表現しているから、だそうだ。
データの読み込みと式の定義
import tensorflow as tf
x = tf.placeholder(tf.float32, [None, 784])
784列のデータをplaceholderとして、まずは定義する。
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
Variableとして学習の対象となるパラメーターを定義する。
そして、モデルを定義する。
y = tf.nn.softmax(tf.matmul(x, W) + b)
matmul()というのは、行列の掛け算。ここで、softmax regressionによってyを得ることができる。なおyは以下のように示される10行の行列である。
<tf.Tensor 'Softmax_1:0' shape=(?, 10) dtype=float32>
最適化の準備
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))
さて、最適化というと最小二乗化法かなと思うところなんだけれど、どうやらそうではなく−Σy'log(y)というcross_entropy functionというのを用いるらしい。
ということで、このcross_entropyを最小化させるべく、gradient descent algorithmを使う、と。これは、chainerのチュートリアルで呼んでいたSGDとはよく似ているけれど、違う手法だ。
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
では、変数を初期化し、実行の準備をする。
変数初期化の定義であるが、チュートリアルによると、
init = tf.global_variables_initializer()
と書くべきらしいのだが、実際にはこれはエラーになる。
Traceback (most recent call last):
File "./mnist_train_tf.py", line 14, in <module>
init = tf.global_variables_initializer()
AttributeError: module 'tensorflow' has no attribute 'global_variables_initializer'
どうやら、https://github.com/tensorflow/tensorflow/issues/5514#issuecomment-260840208 によると、tensorflowのr0.12からglobal_variables_initializer()
が定義されたようで、r0.11以前はinitialize_all_variables()
を使っていたようだ。チュートリアルはr0.12準拠だけれど、anaconda環境でinstallしたtensorflowはr0.11なので、エラーになっていたらしい。
最適化のための試行
tensorflowでSessionを定義して、そのsessionの中で、テストデータから100個ずつ選択して学習する。
というのを、1000回繰り返す。
sess = tf.Session()
sess.run(init)
for i in range(1000):
batch_xs, batch_ys = mnist.train.next_batch(100)
sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
先に定義したtrain_stepはcross_entropyを最小化するためのものであり、そこにmnistから取得したデータbatch_xsとラベルbatch_ysをfeed_dictという引数を介して入力する。
実行結果
0.9184ということで、数値としては予想外に低いかなと思う。
チュートリアルにも、こんなふうに書いてある。
This should be about 92%.
Is that good? Well, not really. In fact, it's pretty bad. This is because we're using a very simple model. With some small changes, we can get to 97%. The best models can get to over 99.7% accuracy!
まあ、チュートリアル用に簡単なモデルを使ったからだよってことらしい。
本日のまとめ
- TensorFlowを使ってみた
- chainerとはまた違ってた
- release 0.12と0.11で違う名前になっているmethodがあった
ニューラルネットによるアプローチといっても、ツールごとにまったく実装方法が有るということが分かった。
そして、このコードをきちんと理解できるだけのニューラルネット・人工知能周辺の知識が全く足りてないことも分かった。
本日のコード
2017/02/22 の追記
TensorFlow の1.0が出て、インストール方法が変わった。手元のWindows機で試してみる。
Windowsへのインストール
condaではなく、pipでインストールしろと、https://www.tensorflow.org/install/install_windows に書いてある。
あれ?
とりあえず、installできたかどうかの確認のために、サンプルコードを実行してみると、動くんだけど、たくさんのwarningが出る。
>>> import tensorflow as tf
>>> hello = tf.constant('Hello, Tensorflow!')
>>> sess = tf.Session()
>>> print(sess.run(hello))
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "BestSplits" device_type: "CPU"') for unknown op: BestSplits
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "CountExtremelyRandomStats" device_type: "CPU"') for unknown op: Cou
ntExtremelyRandomStats
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "FinishedNodes" device_type: "CPU"') for unknown op: FinishedNodes
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "GrowTree" device_type: "CPU"') for unknown op: GrowTree
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "ReinterpretStringToFloat" device_type: "CPU"') for unknown op: Rein
terpretStringToFloat
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "SampleInputs" device_type: "CPU"') for unknown op: SampleInputs
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "ScatterAddNdim" device_type: "CPU"') for unknown op: ScatterAddNdim
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "TopNInsert" device_type: "CPU"') for unknown op: TopNInsert
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "TopNRemove" device_type: "CPU"') for unknown op: TopNRemove
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "TreePredictions" device_type: "CPU"') for unknown op: TreePredictio
ns
E c:\tf_jenkins\home\workspace\release-win\device\cpu\os\windows\tensorflow\core\framework\op_ke
rnel.cc:943] OpKernel ('op: "UpdateFertileSlots" device_type: "CPU"') for unknown op: UpdateFert
ileSlots
b'Hello, Tensorflow!'
Hello Tensorflow!は最後に表示されてるけれど、途中のこれはなんなんでしょうね。