今回はMNIST For ML Beginnersの解説です。何人かの方々がわかりやすい解説を既にされていますので、それらには言及されていない箇所に重きをおいて記述します。まず、TensorFlow.orgの当該ページで五月雨式に書かれているPythonのコードをまとめて書きますと下記です。
2018/01/30 追記: TensorFlow ver 1.5のSyntaxに対応してコードをアップデートしました。
python:MNIST_For_ML_Beginners.py
# -*- coding: utf-8 -*-
# Implementing the Regression
import tensorflow as tf
# このコードと同じ階層にinput_data.pyがあるとして
import input_data
# このコードと同じフォルダ階層にMNIST_dataというフォルダがあり、そこに学習・テストデータが存在するものとして
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
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)
# Training
y_ = tf.placeholder(tf.float32, [None, 10])
cross_entropy = -tf.reduce_sum(y_*tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
init = tf.global_variables_initializer()
# Optional: 私のマシン(Macbook Pro)でGPUではなくCPU使用で実行すると出ることがある警告メッセージを表示しないようにする(処理は止まらず進みますが煩わしいので)
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
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})
# Evaluating Our Model
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
上記で難しそうに感じる箇所は下記の3箇所かと思います。おのおのにつき一般論ではなくTensorFlowを前提として述べます。
1) y = tf.nn.softmax(tf.matmul(x, W) + b) の matmul()
第3回目の情報共有では割愛しましたが、数値の掛け合わせと行列の掛け合わせは計算のルールが異なります。高校数学で習う「内積」や「外積」です。ニューラルネットワークの構造の定義としてxとWの掛け合わせをしますが、行列同士なので行列の「内積」の形をとります。行列の内積の計算、左は横方向に右は縦方向に掛け合わせて足していくという面倒な計算です。なので、TensorFlowにはライブラリにこの「内積」を計算する関数が用意されているので、それを使ってtf.matmul(x, W)として内積の計算を行います。matmulは「mathematical multiplication(数学的掛け合わせ)」の略だと思われます。なお、この定義から考えるとmatmulを使って掛け合わせるものは普通にスカラー量でもいいのだと推測されます。
2) y = tf.nn.softmax(tf.matmul(x, W) + b) の softmax()
「ソフトマックス」と聞くと、バケツで作ったプリンのような何か柔らかくてでっかいものが想像されますが、この「ソフトマックス」は「無制限の実数範囲の入力xに対して0から1までの値であるyに変換して出力する関数」です。なお、このように0から1に収めることを「正規化する」といいます。式とグラフの記載は控えますが、上記のこのソフトマックス関数は自然対数の底であるe(実際の値は2.7182818....)を使った特殊な性質を持った数式で、ニューラルネットの学習最適化を行う際(最も誤差が大きい方向に修正する)に必要となる「微分計算」が容易に出来るという性質があります。この理由から、「正規化」を行える関数は他にも「ステップ関数」などがあるのですが、その微分に関する便利な性質から、ソフトマックス関数が多用されます。
では、なぜ出力を正規化(0から1に収める)をするのでしょうか?その方が、後述する「クロスエントロピー」を用いて学習の出来具合を計算するうえで都合が良いのです。また、出力を正規化しても問題が無いことを、少し的がずれるかもしれませんが我々の実生活に置き換えて考えてみます。仮に「リンゴ」や「ミカン」といわれたら『くだもの』と答え、「キャベツ」や「にんじん」といわれたら『野菜』と答えるパターン認識ゲームをしたとします。このゲーム、小声で「リンゴ」といわれたら小声で「くだもの」と答え、大声で「リンゴ」といわれたら大声で「くだものぉぉ!」と大声で答えることに意味はあるでしょうか?このゲームの本質は入力である言葉と出力である言葉の関係性のパターンを当てることであって、声のボリュームには意味はありません。もし、仮に、小声の「リンゴ」が「果物」で、大声の「リンゴ」が「野菜」という場合があるのであれば、入力変数xに「声のボリューム」を変数として追加して学習すれば出力を正規化しても問題ないはずです。
*その3) cross_entropy = -tf.reduce_sum(y_tf.log(y))
「クロスエントロピー」または「交差エントロピー」。ものすごくざっくりと述べますと、「ある数値の軍団Aと、ある数値の軍団Bがどれくらい異なるか」を表す概念です。エントロピーとは、これもざっくり述べますと「乱雑さの度合い」です。この「エントロピー」という概念は様々な理工学分野で用いられまして、上下に分離したドレッシングの瓶をシャカシャカ振ってよく混ざった状態にすると「エントロピーが増えた」となります。ということで、機械学習でいうと「学習データの出力と、実際のニューラルネットワークの学習結果としての出力がどれくらい異なるか」を表します。このクロスエントロピーを用いる際に比較対象となる「数値の軍団」は正規化されている必要があり、前項のソフトマックス関数で正規化しています。私はお決まりの呪文だとして機械的に使っています。
以上、ご指摘やアドバイス、喜んで伺いたく宜しくお願い致します。
続編はこちらへ http://qiita.com/MATS_ElectricBlueIndustries/items/a0ef52be42b0c4e6cfb5