TECHSTEP

ITインフラ関連の記事を公開してます。

TensorFlow再入門 ~単層パーセプトロン~

初めに

TensorFlow再入門シリーズ第3回です。今回は世界で最も有名なデータセットであるMNISTを使い、単層パーセプトロンで画像認識を実行します。

TensorFlowで単層パーセプトロンをする際の要素

これまで利用した関数などを用いることでほぼ実装可能ですが、一部新しい関数も利用しています。

ミニバッチ学習

大規模なデータを扱って学習をする場合、訓練データからランダムにデータを取り出して計算し、その平均誤差を利用することで、効率的に学習を進めることができます。その際の取り出すデータサイズをミニバッチサイズと言います。

今回はtensorflow.examples.tutorials.mnist.input_dataに組み込まれたread_data_sets関数を利用します。

read_data_sets(train_dir,
                   fake_data=False,
                   one_hot=False,
                   dtype=dtypes.float32,
                   reshape=True,
                   validation_size=5000
)

ソースコードはこちらになります

評価関数

今回はMNISTのデータセットに含まれる0~9の10種類の数字から、同じ数字を推測できているかどうかで評価を行っています。

推測の出力結果は0~9のどの数字に近いかが確率として表示されています。 まずtf.argmaxを用いて、そのリストの中で最も大きな値となるラベル(=正解と予測されたラベル)を取り出し、実際のラベルと比較します。比較の際にはtf.equalという関数を利用します。2つの引数を比べ、True/Falseのboolで返します。

次に返ってきたboolを数値に変換し、評価に利用します。 その際にtf.castという関数を利用します。これはデータの型(dtype)を別のものに変更する関数です。

# 使い方
tf.math.argmax(
    input,
    axis=None,
    name=None,
    dimension=None,
    output_type=tf.dtypes.int64
)

tf.math.equal(
    x,
    y,
    name=None
)

tf.cast(
    x,
    dtype,
    name=None
)

公式ページは以下になります。

tf.argmax

tf.equal

tf.cast

実装

実際のコード

まずは実際のコードを載せます。

# ライブラリのインポート
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

# データセット
mnist = input_data.read_data_sets("data", one_hot=True)

train_x, train_y = mnist.train.next_batch(100)
test_x = mnist.test.images
test_y = mnist.test.labels

# ハイパーパラメータ
num_epochs = 10000
learning_rate = 0.01

# 計算グラフ
X = tf.placeholder(tf.float32, [None, 784])
Y = tf.placeholder(tf.float32, [None, 10])
 
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

out = tf.nn.softmax(tf.matmul(X, W) + b)

## 損失関数
loss = tf.losses.softmax_cross_entropy(Y, out)

## 最適化関数
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_step = optimizer.minimize(loss)

## 評価
correct = tf.equal(tf.argmax(out, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))

# 変数の初期化
init = tf.global_variables_initializer()

# 計算処理
with tf.Session() as sess:
  sess.run(init)

  for epoch in range(num_epochs):
    sess.run(train_step, feed_dict={X: train_x, Y: train_y})
    if epoch != 0 and epoch % 1000 == 0:
      train_loss, accuracy_value = sess.run(loss, feed_dict={X: train_x, Y: train_y}), \
                                   accuracy.eval(feed_dict={X: train_x, Y: train_y})
      print("epoch: ", epoch, " train_loss: ", train_loss, " accuracy_value: ", accuracy_value)
      
tf.reset_default_graph()

0. ライブラリのインポート

TensorFlowに組み込まれたMNISTデータセットを呼び出します。

# ライブラリのインポート
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

ソースコードはこちらです

1. データセットの読み込み

データセットをミニバッチ化し、訓練データとテストデータに分けますensorFlowの提供するMNISTデータセットでは、初めからtrain、testに分かれているので、それぞれ別の変数に入れます。

# データセット
mnist = input_data.read_data_sets("data", one_hot=True)

train_x, train_y = mnist.train.next_batch(100)
test_x = mnist.test.images
test_y = mnist.test.labels

2. データフローグラフの構築

データセットの入れ物となるX Y、変数となるW b、出力結果を格納するoutなどを指定します。

また損失関数・最適化関数に加え、上述した評価関数も指定します。

# 計算グラフ
X = tf.placeholder(tf.float32, [None, 784])
Y = tf.placeholder(tf.float32, [None, 10])
 
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

out = tf.nn.softmax(tf.matmul(X, W) + b)

## 損失関数
loss = tf.losses.softmax_cross_entropy(Y, out)

## 最適化関数
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_step = optimizer.minimize(loss)

## 評価
correct = tf.equal(tf.argmax(out, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32))

3. 各変数の初期化

変数を含むので初期化をします。

# 変数の初期化
init = tf.global_variables_initializer()

4. 各関数の実行(実行フェーズ)

これまでと同様、セッションを開始してtf.Session.runで計算を実行します。

# 計算処理
with tf.Session() as sess:
  sess.run(init)

  for epoch in range(num_epochs):
    sess.run(train_step, feed_dict={X: train_x, Y: train_y})

5. 計算結果の確認・評価

実行結果を確認します。ここでは損失関数の値と評価関数の値を見ています。

    if epoch != 0 and epoch % 1000 == 0:
      train_loss, accuracy_value = sess.run(loss, feed_dict={X: train_x, Y: train_y}), \
                                   accuracy.eval(feed_dict={X: train_x, Y: train_y})
      print("epoch: ", epoch, " train_loss: ", train_loss, " accuracy_value: ", accuracy_value)

6. 計算グラフのリセット

最後に計算グラフのリセットを行います。

tf.reset_default_graph()

計算結果

実行結果を載せます。ハイパーパラメーターを変更すれば、より精度は向上します。

epoch:  1000  train_loss:  1.8928964  accuracy_value:  0.72
epoch:  2000  train_loss:  1.7550746  accuracy_value:  0.8
epoch:  3000  train_loss:  1.6716672  accuracy_value:  0.89
epoch:  4000  train_loss:  1.6261232  accuracy_value:  0.91
epoch:  5000  train_loss:  1.6011841  accuracy_value:  0.92
epoch:  6000  train_loss:  1.5857533  accuracy_value:  0.92
epoch:  7000  train_loss:  1.5758034  accuracy_value:  0.92
epoch:  8000  train_loss:  1.5691535  accuracy_value:  0.92
epoch:  9000  train_loss:  1.5644498  accuracy_value:  0.92

その他

ミニバッチを使わない場合

ミニバッチ化せずに実行した場合も載せます。実行時間はミニバッチと比べてかなりかかります(30~40分程度)。

# コード変更箇所

#train_x, train_y = mnist.train.next_batch(100)
train_x = mnist.train.images
train_y = mnist.train.labels
test_x = mnist.test.images
test_y = mnist.test.labels

# 実行結果

epoch:  1000  train_loss:  2.03642  accuracy_value:  0.59145457
epoch:  2000  train_loss:  1.8735378  accuracy_value:  0.73687273
epoch:  3000  train_loss:  1.8022996  accuracy_value:  0.78023636
epoch:  4000  train_loss:  1.7664666  accuracy_value:  0.7906909
epoch:  5000  train_loss:  1.7446582  accuracy_value:  0.7978909
epoch:  6000  train_loss:  1.7297618  accuracy_value:  0.8022182
epoch:  7000  train_loss:  1.7188071  accuracy_value:  0.80572724
epoch:  8000  train_loss:  1.7103248  accuracy_value:  0.8087636
epoch:  9000  train_loss:  1.7034981  accuracy_value:  0.8113091

公式ページにあるチュートリアルコード

TensorFlowはバージョンが上がるにつれ、TensorFlow単体での利用からKerasの利用を推奨しているようです。チュートリアルの初めのページでは、kerasを用いてとてもコンパクトにMNISTの学習を実行しています。

# チュートリアルのコード
import tensorflow as tf
mnist = tf.keras.datasets.mnist

(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

model = tf.keras.models.Sequential([
  tf.keras.layers.Flatten(input_shape=(28, 28)),
  tf.keras.layers.Dense(512, activation=tf.nn.relu),
  tf.keras.layers.Dropout(0.2),
  tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

model.fit(x_train, y_train, epochs=5)
model.evaluate(x_test, y_test)

# 結果
Epoch 1/5
60000/60000 [==============================] - 14s 234us/sample - loss: 0.2200 - acc: 0.9348
Epoch 2/5
60000/60000 [==============================] - 14s 230us/sample - loss: 0.0972 - acc: 0.9699
Epoch 3/5
60000/60000 [==============================] - 13s 224us/sample - loss: 0.0692 - acc: 0.9782
Epoch 4/5
60000/60000 [==============================] - 13s 220us/sample - loss: 0.0537 - acc: 0.9832
Epoch 5/5
60000/60000 [==============================] - 13s 224us/sample - loss: 0.0418 - acc: 0.9862
10000/10000 [==============================] - 1s 57us/sample - loss: 0.0634 - acc: 0.9818
[0.06343337026094087, 0.9818]

参考リンク

Tensorflow run() vs eval() と InteractiveSession() vs Session()

TensorFlowのMNISTはどうなってるのか?