LoginSignup
3
5

More than 5 years have passed since last update.

Cloud9でTensorFlowのチュートリアル(初心者のためのMNIST)をやってみた~手書き画像の分類~

Last updated at Posted at 2016-10-29

はじめに

TensorFlowのチュートリアルで機械学習の初心者のためと書いてある「MNIST For ML Beginners」をやってみました。そこで機械学習のHelloWorldと書いてある、MNISTの数字認識を実装してみました。MNISTとは手書き画像のデータセットの事で、ここでは0~9の手書きの数字の画像を読み込んで、機会学習で分類をします。
TensorFlowのGithubに置いてあるサンプルコードは難しいそうに見えるのですが、必要な実装だけしてみると本当にシンプルで20行で実装できました。

環境

Cloud9
Python 2.7.6
Sample Codes : GitHub
環境構築は「クラウド統合開発環境Cloud9でTensorFlowを使う~GetStarted~
TesorFlowの基本的な使い方は「クラウド統合開発環境Cloud9でTensorFlowを使う〜使い方の基本〜
を参照

学習処理のコード

Githubに置いてありますが、以下が実装したコードになります。

mnist_softmax_train.py
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf

# Download gz files to MNIST_data directory
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

# Initializing
sess = tf.InteractiveSession()

x = tf.placeholder(tf.float32, shape=[None, 28*28])
y_ = tf.placeholder(tf.float32, shape=[None, 10])

W = tf.Variable(tf.zeros([28*28, 10]), name="W")
b = tf.Variable(tf.zeros([10]), name="b")

sess.run(tf.initialize_all_variables())

# Making model
y = tf.matmul(x, W) + b
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y, y_))

# Training
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
for i in range(1000):
  batch = mnist.train.next_batch(100)
  train_step.run(feed_dict={x: batch[0], y_: batch[1]})

# Evaluating
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}))

# Save train data
saver = tf.train.Saver()
saver.save(sess, 'param/softmax.param')

実行してみるとチュートリアルにも書いてあるように、92%ほどの精度が出ているようです。

コードの中身

mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

データを取得しているところです。MNIST_dataというディレクトリを作成して、そこに4ファイルダウンロードしています。中身はブラックボックスなので調べてみる必要があります。

sess = tf.InteractiveSession()

x = tf.placeholder(tf.float32, shape=[None, 28*28])
y_ = tf.placeholder(tf.float32, shape=[None, 10])

W = tf.Variable(tf.zeros([28*28, 10]), name="W")
b = tf.Variable(tf.zeros([10]), name="b")

sess.run(tf.initialize_all_variables())

初期化処理です。xが画像データ(28ピクセル×28ピクセル)、y_がその画像のラベル(0~9)を保持します。placeholderなので、後で代入しています。
Wとbはパラメータで、Wが画像の各ピクセルの重みづけとbが切片と言った形でしょう。

y = tf.matmul(x, W) + b
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(y, y_))

yはパラメータとxから予測値を算出している式。次の式がソフトマックス回帰。
ロジスティック回帰は0と1を予測するモデルですが、それを拡張して複数のラベル(今回だと0~9)を予測できるようにしたもの。
チュートリアルには詳しい式も記載されていたので、それも勉強する必要があると思います。

train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
for i in range(1000):
  batch = mnist.train.next_batch(100)
  train_step.run(feed_dict={x: batch[0], y_: batch[1]})

GradientDescentOptimizerが確率的勾配降下法。mnist.train.next_batchで最初にダウンロードしたデータを順に取得して、feed_dict={x: batch[0], y_: batch[1]}で、変数に代入しています。繰り返し実行することで最適解を求めているところです。

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}))

テストデータを使用して、y(予測値)とy_(実際の値)の精度を確認しているところです。

saver = tf.train.Saver()
saver.save(sess, 'param/softmax.param')

学習したパラメータを保存している処理です。これで後からパラメータのみを使用して画像の分類を行えます。

自分の手書きデータの予測

上記で手書きの数値データを学習しました。そのパラメータを使って、自分で書いた手書きデータの分類を行ってみました。
自分の手書きデータは、同じようにGithubに置いてありますが、白黒のbmpです。parsebmp.py で読み込んでいます。MNISTのデータは、0~1の数値で学習しているのですが、この処理は簡単に0, 1のデータのみです。
実際に動かしてみると、60%の精度でした。92%には程遠いのですが、ある程度は判定できていると言ってよいでしょう。
⇒ 手書きデータの予測には前処理が必要でした。詳細については自分の手書きデータをTensorFlowで予測するの記事を参考にして下さい。

mnist_softmax.py
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
import sys
import numpy as np
import parsebmp as pb

def whatisit(file, sess):
  print("File name is %s" % file)
  data = pb.parse_bmp(file)

  # Show bmp data
  for i in range(len(data)):
    sys.stdout.write(str(int(data[i])))
    if (i+1) % 28 == 0:
      print("")

  # Predicting
  d = np.array([data])
  result = sess.run(y, feed_dict={x: d})

  # Show result
  print(result)
  print(np.argmax(result, 1))


if __name__ == "__main__":
  # Restore parameters
  x = tf.placeholder(tf.float32, shape=[None, 28*28])
  y_ = tf.placeholder(tf.float32, shape=[None, 10])
  W = tf.Variable(tf.zeros([28*28, 10]), name="W")
  b = tf.Variable(tf.zeros([10]), name="b")
  y = tf.matmul(x, W) + b

  sess = tf.InteractiveSession()
  saver = tf.train.Saver()
  saver.restore(sess, 'param/softmax.param')

  # My data
  whatisit("My_data/0.bmp", sess)
  whatisit("My_data/1.bmp", sess)
  whatisit("My_data/2.bmp", sess)
  whatisit("My_data/3.bmp", sess)
  whatisit("My_data/4.bmp", sess)
  whatisit("My_data/5.bmp", sess)
  whatisit("My_data/6.bmp", sess)
  whatisit("My_data/7.bmp", sess)
  whatisit("My_data/8.bmp", sess)
  whatisit("My_data/9.bmp", sess)

おわりに

まずはコードをチュートリアルを見ながら実装してみました。本当に簡単に実装できてしまうのですが、以下の点を理解していく必要があると思います。

  • 使用データの中身
  • ソフトマックス回帰の詳細な計算式

また本当に理解するために、自分の手書きのデータなどをとりこんで予測させることができたらよいと思います。それが実用にも繋がると思います。
⇒ 2017/03/27に自分の手書きデータの予測をやってみました。

更新履歴

  • 2018/06/12: 手書きデータの予測について追記
  • 2017/03/27: パラメータの保存方法、自分の手書きデータの予測内容を追記
  • 2016/10/30: 新規投稿
3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5