TensorflowでMNIST(5)

毎回学習させるのは効率が悪いので、一度学習させそれを保存しておき、判定時には判定のみをさせるように修正します

畳み込みニューラルネットワーク(CNN)のプログラムを修正していきます

学習用

tf_cnn3.py

#!/bin/env python
# -*- coding: utf-8 -*-
# http://qiita.com/ikki8412/items/95bc81a744dc377d9119
import tensorflow as tf
import numpy as np
import random
import time
import math

NUMCLASS=10
NUMPARAM=784
   
### データ処理用
def label_data(lines):
  labels=[]
  for line in lines:
    # ラベルを1-of-k方式で用意する
    tmp = np.zeros(NUMCLASS)
    tmp[int(line)] = 1
    labels.append(tmp)
  return np.asarray(labels)

def image_data(test):
  test_image=map(lambda n: map(lambda k: float(k)/255.0,n),test[:,1:NUMPARAM+1])
  return np.asarray(test_image)


# 開始時刻
start_time = time.time()
print "開始時刻: " + str(start_time)


### データ取得 --->
# ファイルを開く
f = open("train.txt", 'r')
# データを入れる配列
train = []
for line in f:
    # 改行を除いてスペース区切りにする
    line = line.rstrip()
    l = line.split(" ")
    l = map(lambda n: int(n),l)
    #l=map(lambda n: 0 if n=="0" else 1,l)
    train.append(l)


# numpy形式に変換
train = np.asarray(train)
f.close()

f = open("t10k.txt", 'r')
test = []
for line in f:
    line = line.rstrip()
    l = line.split(" ")
    l = map(lambda n: int(n),l)
    #l=map(lambda n: 0 if n=="0" else 1,l)
    test.append(l)

test = np.asarray(test)
f.close()
### データ取得 ---<


# 訓練画像を入れる変数
# 訓練画像は28x28pxであり、これらを1行784列のベクトルに並び替え格納する
# Noneとなっているのは訓練画像がいくつでも入れられるようにするため
x = tf.placeholder(tf.float32, [None, NUMPARAM], name="x-input")

# 交差エントロピー
# y_は正解データのラベル
# 損失とオプティマイザを定義します
y_ = tf.placeholder(tf.float32, [None, NUMCLASS], name="y-input")


# hidden1
with tf.name_scope("hidden_layer1") as scope:
  w_h1 = tf.Variable(tf.truncated_normal([NUMPARAM, 500],
                          stddev=1.0 / math.sqrt(float(NUMPARAM))),name='weights')
  b_h1 = tf.Variable(tf.zeros([500]),name='biases')

  h1 = tf.nn.sigmoid(tf.matmul(x, w_h1) + b_h1)
# hidden2
with tf.name_scope("hidden_layer2") as scope:
  w_h2 = tf.Variable(tf.truncated_normal([500, 300],
                          stddev=1.0 / math.sqrt(float(500))),name='weights')
  b_h2 = tf.Variable(tf.zeros([300]),name='biases')

  h2 = tf.nn.sigmoid(tf.matmul(h1, w_h2) + b_h2)
# softmax layer
with tf.name_scope("softmax_layer") as scope:
  w_o = tf.Variable(tf.truncated_normal([300, NUMCLASS],
                          stddev=1.0 / math.sqrt(float(300))),name='weights')
  b_o = tf.Variable(tf.zeros([NUMCLASS]),name='biases')

  y = tf.nn.softmax((tf.matmul(h2, w_o) + b_o))


# 更なる name scopes はグラフ表現をクリーンアップしま
with tf.name_scope("xent") as scope:
  cross_entropy = -tf.reduce_sum(y_*tf.log(y))
  # TensorBoardで表示するよう指定
  tf.scalar_summary("cross_entropy", cross_entropy)

  # 勾配硬化法を用い交差エントロピーが最小となるようyを最適化する
  train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

# 用意した変数Veriableの初期化を実行する
init = tf.initialize_all_variables()

# Sessionを開始する
# runすることで初めて実行開始される(run(init)しないとinitが実行されない)
sess = tf.Session()
sess.run(init)
# TensorBoardで表示する値の設定
summary_op = tf.merge_all_summaries()
summary_writer = tf.train.SummaryWriter("/tmp/data", sess.graph_def)


# 1000回の訓練(train_step)を実行する
# next_batch(100)で100つのランダムな訓練セット(画像と対応するラベル)を選択する
# 訓練データは60000点あるので全て使いたいところだが費用つまり時間がかかるのでランダムな100つを使う
# 100つでも同じような結果を得ることができる
# feed_dictでplaceholderに値を入力することができる
print "--- 訓練開始 ---"
for i in range(20000):
  train_sample=np.asarray(random.sample(train,100))
  batch_ys=label_data(train_sample[:,0])
  batch_xs=image_data(train_sample)
  train_accuracy=sess.run(train_step, feed_dict={x: batch_xs, y_:batch_ys})

  # 1 step終わるたびにTensorBoardに表示する値を追加する
  summary_str=sess.run(summary_op, feed_dict={x: batch_xs, y_:batch_ys})
  summary_writer.add_summary(summary_str, i)
print "--- 訓練終了 ---"

# 正しいかの予測
# 計算された画像がどの数字であるかの予測yと正解ラベルy_を比較する
# 同じ値であればTrueが返される
# argmaxは配列の中で一番値の大きい箇所のindexが返される
# 一番値が大きいindexということは、それがその数字である確率が一番大きいということ
# Trueが返ってくるということは訓練した結果と回答が同じということ
with tf.name_scope("test") as scope:
  correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

# 精度の計算
# correct_predictionはbooleanなのでfloatにキャストし、平均値を計算する
# Trueならば1、Falseならば0に変換される
  accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))

  tf.scalar_summary("accuracy", accuracy)

# 精度の実行と表示
# テストデータの画像とラベルで精度を確認する
# ソフトマックス回帰によってWとbの値が計算されているので、xを入力することでyが計算できる
test_label=label_data(test[:,0])
test_image=image_data(test)
# http://d.hatena.ne.jp/sugyan/20151124/1448292129
print "精度"
print(sess.run(accuracy, feed_dict={x: test_image, y_: test_label}))

## save 
saver = tf.train.Saver([w_h1,b_h1,w_h2,b_h2,w_o,b_o])
saver.save(sess, "/tmp/tf_cnn.ckpt")

# 終了時刻
end_time = time.time()
print "終了時刻: " + str(end_time)
print "かかった時間: " + str(end_time - start_time)

判定用

tf_cnn3_exec.py

#!/bin/env python
# -*- coding: utf-8 -*-
# http://qiita.com/ikki8412/items/95bc81a744dc377d9119
import tensorflow as tf
import numpy as np
import random
import time
import math

NUMCLASS=10
NUMPARAM=784
   
### データ処理用
def label_data(lines):
  labels=[]
  for line in lines:
    # ラベルを1-of-k方式で用意する
    tmp = np.zeros(NUMCLASS)
    tmp[int(line)] = 1
    labels.append(tmp)
  return np.asarray(labels)

def image_data(test):
  test_image=map(lambda n: map(lambda k: float(k)/255.0,n),test[:,1:NUMPARAM+1])
  return np.asarray(test_image)


# 開始時刻
start_time = time.time()
print "開始時刻: " + str(start_time)


### データ取得 --->
# ファイルを開く

f = open("t10k.txt", 'r')
test = []
for line in f:
    line = line.rstrip()
    l = line.split(" ")
    l = map(lambda n: int(n),l)
    #l=map(lambda n: 0 if n=="0" else 1,l)
    test.append(l)

test = np.asarray(test)
f.close()
### データ取得 ---<


# 訓練画像を入れる変数
# 訓練画像は28x28pxであり、これらを1行784列のベクトルに並び替え格納する
# Noneとなっているのは訓練画像がいくつでも入れられるようにするため
x = tf.placeholder(tf.float32, [None, NUMPARAM], name="x-input")

# 交差エントロピー
# y_は正解データのラベル
# 損失とオプティマイザを定義します
y_ = tf.placeholder(tf.float32, [None, NUMCLASS], name="y-input")


# hidden1
with tf.name_scope("hidden_layer1") as scope:
  w_h1 = tf.Variable(tf.truncated_normal([NUMPARAM, 500],
                          stddev=1.0 / math.sqrt(float(NUMPARAM))),name='weights')
  b_h1 = tf.Variable(tf.zeros([500]),name='biases')

  h1 = tf.nn.sigmoid(tf.matmul(x, w_h1) + b_h1)
# hidden2
with tf.name_scope("hidden_layer2") as scope:
  w_h2 = tf.Variable(tf.truncated_normal([500, 300],
                          stddev=1.0 / math.sqrt(float(500))),name='weights')
  b_h2 = tf.Variable(tf.zeros([300]),name='biases')

  h2 = tf.nn.sigmoid(tf.matmul(h1, w_h2) + b_h2)
# softmax layer
with tf.name_scope("softmax_layer") as scope:
  w_o = tf.Variable(tf.truncated_normal([300, NUMCLASS],
                          stddev=1.0 / math.sqrt(float(300))),name='weights')
  b_o = tf.Variable(tf.zeros([NUMCLASS]),name='biases')

  y = tf.nn.softmax((tf.matmul(h2, w_o) + b_o))



# 用意した変数Veriableの初期化を実行する
init = tf.initialize_all_variables()

# Sessionを開始する
# runすることで初めて実行開始される(run(init)しないとinitが実行されない)
sess = tf.Session()
sess.run(init)



saver = tf.train.Saver([w_h1,b_h1,w_h2,b_h2,w_o,b_o])
saver.restore(sess, "/tmp/tf_cnn.ckpt")


# 精度の実行と表示
# テストデータの画像とラベルで精度を確認する
# ソフトマックス回帰によってWとbの値が計算されているので、xを入力することでyが計算できる
test_label=label_data(test[:,0])
test_image=image_data(test)


# http://d.hatena.ne.jp/sugyan/20151124/1448292129
print "精度"
print(test_image[0])
res=(sess.run(y, feed_dict={x: [test_image[0]]}))
print res[0]


# 終了時刻
end_time = time.time()
print "終了時刻: " + str(end_time)
print "かかった時間: " + str(end_time - start_time)

実行

学習させて、テストデータの先頭の1つを判定します。その際、どの数値をどの確率で判定しているかのリストを表示させています。その数値が最も高いものがこのエンジンでの判定結果となります。

$ python tf_cnn3.py
開始時刻: 1459469907.05
--- 訓練開始 ---
--- 訓練終了 ---
精度
0.9804
終了時刻: 1459470791.98
かかった時間: 884.936733961
ubuntu@ubuntu:~/mnist$ python tf_cnn3_exec.py
開始時刻: 1459471244.43
結果
[	1.49596369e-09	 4.64228158e-08	 5.76857360e-07	 1.40932752e-05
2.07982364e-11	 3.24105409e-10	 2.27739631e-15	 9.99985099e-01
5.93633684e-11	 2.51105405e-07]
終了時刻: 1459471249.84
かかった時間: 5.40709519386

この結果では7が9.99985099e-01で最も数値が高くなっています