from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
Extracting MNIST_data/train-images-idx3-ubyte.gz Extracting MNIST_data/train-labels-idx1-ubyte.gz Extracting MNIST_data/t10k-images-idx3-ubyte.gz Extracting MNIST_data/t10k-labels-idx1-ubyte.gz
# 表示してみる
import matplotlib.pyplot as plt
%matplotlib inline
fig = plt.figure(figsize=(12,6))
for i, img in enumerate(mnist.train.images[:25]):
ax = fig.add_subplot(5,5,i+1)
ax.imshow(img.reshape(28, 28), interpolation="none")
# import
import tensorflow as tf
# ログ保存用のディレクトリがあれば一度削除し、新たに作りなおす
LOG_DIR = "/tmp/softmax"
if tf.gfile.Exists(LOG_DIR):
tf.gfile.DeleteRecursively(LOG_DIR)
tf.gfile.MakeDirs(LOG_DIR)
# TensorBoardのための準備
def variable_summaries(var):
""" テンソルに様々なsummaryを付加する(TensorBoardでの可視化に利用)
Args:
var: summaryを付加したいテンソル
Returns:
なし(summary opの付加を行うだけの関数)
"""
with tf.name_scope('summaries'):
mean = tf.reduce_mean(var)
tf.summary.scalar('mean', mean)
with tf.name_scope('stddev'):
stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
tf.summary.scalar('stddev', stddev)
tf.summary.scalar('max', tf.reduce_max(var))
tf.summary.scalar('min', tf.reduce_min(var))
tf.summary.histogram('histogram', var)
with tf.name_scope("input"):
# データを与えるためのplaceholder
x = tf.placeholder(tf.float32, [None, 784], name = "image") # input image
y_ = tf.placeholder(tf.float32, [None, 10], name = "label") # label
with tf.name_scope("variables"):
# 学習可能なパラメータ
with tf.name_scope("Weight"):
W = tf.Variable(tf.zeros([784, 10]))
variable_summaries(W)
with tf.name_scope("Bias"):
b = tf.Variable(tf.zeros([10]))
variable_summaries(b)
def inference(images, weights, biases):
""" 画像からそのクラスを予想する
Args:
images: 画像のplaceholder
weights: 重みのVariable
biases: バイアスのVariable
Returns:
logits: 計算されたlogit
"""
with tf.name_scope("logits"):
logits = tf.matmul(images, weights) + biases
tf.summary.histogram("logits_histogram", logits)
return logits
def loss(logits, labels):
""" logitとlabelから誤差関数(交差エントロピー)を計算する
Args:
logits:識別器の予測
labels:正しいラベル
Returns:
cross_entropy: 交差エントロピー
"""
with tf.name_scope("loss"):
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits), name="cross_entropy_mean")
tf.summary.scalar('cross_entropy', cross_entropy) # ログをとる
return cross_entropy
def train(loss, learning_rate):
""" 訓練用のopを生成する
Args:
loss
learning_rate
Returns:
The op for training
"""
with tf.name_scope("train"):
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
train_op = optimizer.minimize(loss)
return train_op
def evaluation(logits, labels):
""" logitsがlabelsを予測する精度を評価する
Args:
logits
labels
Returns:
正解率
"""
with tf.name_scope("evaluation"):
correct = tf.equal(tf.argmax(logits, 1), tf.argmax(labels, 1))
accuracy = tf.reduce_mean(tf.cast(correct, tf.float32), name="accuracy")
tf.summary.scalar("accuracy", accuracy) # ログをとる
return accuracy
# グラフを構築
logits = inference(x, W, b)
loss = loss(logits, y_)
train_op = train(loss, 0.1)
accuracy = evaluation(logits, y_)
summary = tf.summary.merge_all() # すべてのsummaryをひとまとめにするop
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())
# summaryをファイルに出力するためのwriter
train_writer = tf.summary.FileWriter(LOG_DIR+"/train", sess.graph) # sess.graphを渡すことでComputational GraphをTensorBoardに可視化
test_writer = tf.summary.FileWriter(LOG_DIR+"/test")
MAX_STEP = 2000
BATCH_SIZE = 100
for step in range(MAX_STEP):
batch_xs, batch_ys = mnist.train.next_batch(BATCH_SIZE)
sess.run(train_op, feed_dict={x: batch_xs, y_: batch_ys}) # trainを実行
# 100stepごとにテスト結果を表示
if step % 100 == 0:
test_loss, test_accuracy = sess.run([loss, accuracy], feed_dict={x: mnist.test.images, y_: mnist.test.labels})
print("step: {}, test_accuracy: {}, test_loss: {}".format(step, test_accuracy, test_loss))
# ログの実行
train_summary_str = sess.run(summary, feed_dict={x: batch_xs, y_: batch_ys})
test_summary_str = sess.run(summary, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
train_writer.add_summary(train_summary_str, step)
test_writer.add_summary(test_summary_str, step)
train_writer.close()
test_writer.close()
step: 0, test_accuracy: 0.407499879599, test_loss: 2.19526791573 step: 100, test_accuracy: 0.870700120926, test_loss: 0.589205980301 step: 200, test_accuracy: 0.885000109673, test_loss: 0.469472557306 step: 300, test_accuracy: 0.892900049686, test_loss: 0.418157845736 step: 400, test_accuracy: 0.89660012722, test_loss: 0.394196510315 step: 500, test_accuracy: 0.89970010519, test_loss: 0.374979138374 step: 600, test_accuracy: 0.902900099754, test_loss: 0.361071527004 step: 700, test_accuracy: 0.904900074005, test_loss: 0.353250801563 step: 800, test_accuracy: 0.907600164413, test_loss: 0.343760222197 step: 900, test_accuracy: 0.909000098705, test_loss: 0.337838679552 step: 1000, test_accuracy: 0.909600138664, test_loss: 0.33370706439 step: 1100, test_accuracy: 0.911600112915, test_loss: 0.325382322073 step: 1200, test_accuracy: 0.910800099373, test_loss: 0.324246108532 step: 1300, test_accuracy: 0.912300109863, test_loss: 0.318959236145 step: 1400, test_accuracy: 0.911800086498, test_loss: 0.317459285259 step: 1500, test_accuracy: 0.914300084114, test_loss: 0.315505206585 step: 1600, test_accuracy: 0.91520011425, test_loss: 0.310797214508 step: 1700, test_accuracy: 0.915200173855, test_loss: 0.308820784092 step: 1800, test_accuracy: 0.916200101376, test_loss: 0.308186322451 step: 1900, test_accuracy: 0.916100084782, test_loss: 0.30688893795
print("Accuracy: {}".format(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})))
Accuracy: 0.91680008173
Softmax Regressionは、
という計算によって事後確率を求めている。したがって、「最もiと認識されやすい画像」は重みのi番目のベクトル(i=0, 1, ..., 9)によって得ることができる。
fig = plt.figure(figsize=(12,6))
for i in range(W.eval().shape[1]):
ax = fig.add_subplot(2,5,i+1)
ax.imshow(W.eval()[:, i].reshape(28, 28), interpolation="none")
様々な文字画像に先述の重み画像を混ぜあわせることを考える。
人間の目には依然として容易に識別できるにもかかわらず、識別器は誤って識別するようになる。例えば"7"に対応する重みを混ぜあわせると、多くの画像を"7"と予想するようになる。
# "7"に対応する重みをテスト用画像に足し合わせて表示する
import numpy as np
fake_x = np.array([img + W.eval()[:, 7] for img in mnist.test.images[:25]])
fig = plt.figure(figsize=(12,6))
for i, img in enumerate(fake_x):
ax = fig.add_subplot(5,5,i+1)
ax.imshow(img.reshape(28, 28), interpolation="none")
# 上の画像の多くを"7"と予想するようになる
print(sess.run(tf.argmax(logits, 1), feed_dict={x: fake_x}))
[7 2 7 7 7 7 7 7 7 7 0 7 7 0 7 7 7 7 7 7 7 6 7 7 7]
Softmax Regressionでは各クラスの事後確率を推定し、事後確率が最大となるクラスをモデルの予想としている。事後確率の最大値が90%となる入力画像と50%となる入力画像では、前者の方が正答率が高いはず。それを確かめてみる。
posteriors = sess.run(tf.nn.softmax(logits), feed_dict={x: mnist.test.images})# テストデータに対してモデルが出力した事後確率
print(posteriors.shape)
is_true = np.argmax(posteriors, 1) == np.argmax(mnist.test.labels, 1) # 正解したデータにのみTrueが入ったarray
print(is_true.shape)
(10000, 10) (10000,)
plt.hist(np.max(posteriors[is_true], 1))
(array([ 17., 50., 112., 216., 238., 311., 401., 691., 1285., 5847.]), array([ 0.25194693, 0.32675163, 0.40155632, 0.47636102, 0.55116572, 0.62597042, 0.70077512, 0.77557982, 0.85038452, 0.92518922, 0.99999392]), <a list of 10 Patch objects>)
plt.hist(np.max(posteriors[~is_true], 1))
(array([ 6., 47., 112., 142., 143., 125., 89., 68., 60., 40.]), array([ 0.18450125, 0.26577138, 0.34704152, 0.42831166, 0.5095818 , 0.59085194, 0.67212208, 0.75339222, 0.83466236, 0.9159325 , 0.99720263]), <a list of 10 Patch objects>)
# 事後確率のクラス間の最大値を0.1刻みにしたもの
floor_posteriors = np.array(map(lambda x: int(x*10)/10., np.max(posteriors, 1)))
# モデルの予想した事後確率と、正解(1)不正解(0)をたばねたもの
count = np.concatenate((np.vstack(floor_posteriors), np.vstack(is_true.astype(int))), axis=1)
print(count)
[[ 0.9 1. ] [ 0.9 1. ] [ 0.9 1. ] ..., [ 0.9 1. ] [ 0.7 1. ] [ 0.9 1. ]]
# 事後確率が最大となるクラスにおける事後確率ごとに、正答率を記録する
h = []
for i in range(1, 10):
a = np.array(filter(lambda x: x[0]==i/10., count))
if a.any():
h.append([i/10., np.sum(a[:, 1])/a.shape[0] ])
h = np.array(h)
print(h)
[[ 0.1 0. ] [ 0.2 0.32 ] [ 0.3 0.37254902] [ 0.4 0.5184136 ] [ 0.5 0.63168724] [ 0.6 0.71828358] [ 0.7 0.86892489] [ 0.8 0.93868282] [ 0.9 0.99255352]]
plt.xlabel("Max posterior")
plt.ylabel("Accuracy")
plt.plot(h[:, 0], h[:, 1])
[<matplotlib.lines.Line2D at 0x7f0c342c7650>]