TensorFlowでCNN実装(TensorBoardでの可視化有り)
初めてCNNを実装したので備忘録として。
目標
- TensorFlowではじめるDeepLearning実装入門の第3章に従い、TensorFlowでMNISTを分類するCNNを実装してみる。
- ついでに、TensorBoardに正解率等を表示する。
※ CNNの理論的詳細については定番のConvolutional Neural Networkをゼロから理解するを御覧ください。
方針
- ネットワークはおおまかに畳み込み層1、畳み込み層2、全結合層、出力層に分かれる
- 畳み込み層では畳込みとプーリングを行い、画像から特徴量を抽出
- 全結合層では、畳み込み層で生成された特徴量の次元を落とす
- 出力層で、10の数値のいずれかに分類
- TensorBoardに下記を表示する
- 各層の重みのヒストグラム
- 学習途中のaccuracyとlossの推移
- ネットワークのグラフ構造
コード
import tensorflow as tf import tensorflow.examples.tutorials.mnist as mnist # MNISTを保存 mnist_data = mnist.input_data.read_data_sets("../data/mnist/", one_hot=True) def train_cnn(): # TensorBoardに載せるsummaryのリスト summaries = [] # 入力 with tf.name_scope("data"): # 入力画像 x = tf.placeholder(tf.float32, [None, 784], name="x") # 正解ラベル y = tf.placeholder(tf.float32, [None, 10], name="y") # 畳み込み層1 with tf.name_scope("conv_1"): # 畳み込み可能なshapeに変換 img = tf.reshape(x, [-1, 28, 28, 1]) # 畳み込みフィルタ f_1 = tf.Variable(tf.truncated_normal([5, 5, 1, 32], stddev=0.1), name="f_1") # ログにf_1のヒストグラムを出力 summaries.append(tf.summary.histogram("f_1", f_1)) # 畳み込み演算 conv_1 = tf.nn.conv2d(img, f_1, strides=[1, 1, 1, 1], padding="SAME", name="conv_1") # バイアス b_1 = tf.Variable(tf.constant(0.1, shape=[32])) # 活性化関数 h_conv_1 = tf.nn.relu(conv_1 + b_1) # プーリング演算 h_pool_1 = tf.nn.max_pool(h_conv_1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME") # 畳み込み層2 with tf.name_scope("conv_2"): # 畳み込みフィルタ f_2 = tf.Variable(tf.truncated_normal([5, 5, 32, 64], stddev=0.1), name="f_2") # ログにf_2のヒストグラムを出力 summaries.append(tf.summary.histogram("f_2", f_2)) # 畳み込み演算 conv_2 = tf.nn.conv2d(h_pool_1, f_2, strides=[1, 1, 1, 1], padding="SAME", name="conv_2") # バイアス b_2 = tf.Variable(tf.constant(0.1, shape=[64])) # 活性化関数 h_conv_2 = tf.nn.relu(conv_2 + b_2) # プーリング演算 h_pool_2 = tf.nn.max_pool(h_conv_2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME") # 全結合層 with tf.name_scope("fc"): # フラットな形に変換 h_pool_2_flat = tf.reshape(h_pool_2, [-1, 7*7*64]) # 全結合層の重み w_fc = tf.Variable(tf.truncated_normal([7*7*64, 1024], stddev=0.1), name="w_fc") # ログにw_fcのヒストグラムを出力 summaries.append(tf.summary.histogram("w_fc", w_fc)) # バイアス b_fc = tf.Variable(tf.constant(0.1, shape=[1024])) # 活性化関数 h_fc = tf.nn.relu(tf.matmul(h_pool_2_flat, w_fc) + b_fc) # 出力層 with tf.name_scope("out"): # 全結合層の重み w_out = tf.Variable(tf.truncated_normal([1024, 10], stddev=0.1)) # ログにw_outのヒストグラムを出力 summaries.append(tf.summary.histogram("w_out", w_out)) # バイアス b_out = tf.Variable(tf.constant(0.1, shape=[10])) # 活性化関数 out = tf.nn.softmax(tf.matmul(h_fc, w_out) + b_out) # 誤差 with tf.name_scope("loss"): # 誤差 loss = tf.reduce_mean(-tf.reduce_sum(y * tf.log(out + 1e-5), axis=[1])) # 誤差をログに出力 summaries.append(tf.summary.scalar("loss", loss)) # 訓練 with tf.name_scope("train"): train_step = tf.train.GradientDescentOptimizer(0.01).minimize(loss) # 評価 with tf.name_scope("accuracy"): # 正解率 correct = tf.equal(tf.argmax(out, 1), tf.argmax(y, 1)) accuracy = tf.reduce_mean(tf.cast(correct, tf.float32)) # 正解率をログに出力 summaries.append(tf.summary.scalar("accuracy", accuracy)) # 初期化 init = tf.global_variables_initializer() # 実行 with tf.Session() as sess: # ログをひとまとめにする設定 summary_op = tf.summary.merge(summaries) # ログの保管場所 summary_writer = tf.summary.FileWriter("../logs", sess.graph) # 初期化 sess.run(init) # テストデータ test_images, test_labels = mnist_data.test.images, mnist_data.test.labels # 学習 for i in range(1000): # 訓練データ train_images, train_labels = mnist_data.train.next_batch(50) # ミニバッチ学習 sess.run(train_step, feed_dict={x: train_images, y: train_labels}) # 定期的にログ書き出し step = i + 1 if step % 100 == 0: pass # ログのテキスト取得 summary_text, acc_val = sess.run([summary_op, accuracy], feed_dict={x: test_images, y: test_labels}) # ログに書き出し summary_writer.add_summary(summary_text, step) print("step: {} acc: {: .3}".format(step, acc_val)) train_cnn()
出力
tensorboard --logdir logs/mnist
を実行し、ブラウザからlocalhost:6006
にアクセスすると、可視化結果が見られる。
Accuracy
Loss
出力層の活性化関数を間違えてSoftmaxではなくReluにしてしまっていたため、最初全く精度が出ずに焦った。。。
TensorBoardでMNIST分類器の見える化
TensorBoardを初めて触ったので備忘録として。
TensorBoardは、TensorFlowのモデルの構造や精度等を可視化してくれる活かしたツールです。
目標
TensorFlowではじめるDeepLearning実装入門の第3章に従い、TensorboardでMNIST分類器の精度や重み等を表示してみる。
方針
- モデルは前回の記事と同じ、隠れ層1つのシンプルなもの
- TensorBoardに下記を表示する
- 入力画像
- 入力層から隠れ層への重みのヒストグラム
- 学習途中のaccuracyとlossの推移
- ネットワークのグラフ構造
ポイント
- TensorBoardはTensorFlowの吐き出したログを元に可視化を行うため、まずログの設定をする必要がある
tf.summary
モジュールに、ログとして吐き出したいものを指定するメソッドがあるので、それらを各所に埋め込むtf.summary.merge
メソッドで、埋め込んだ各種ログを1つのテキストとして取得tf.summary.FileWriter
オブジェクトで、ファイルの書き出し- TensorFlowの実行後、TensorBoardをコマンドラインから実行
コード
import tensorflow as tf import tensorflow.examples.tutorials.mnist as mnist # MNISTを保存 mnist_data = mnist.input_data.read_data_sets("mnist/", one_hot=True) # 入力 with tf.name_scope("input"): # 入力の定義 x = tf.placeholder(tf.float32, [None, 784], name="x") # ログに10枚ずつ入力画像を出力 img = tf.reshape(x, [-1, 28, 28, 1]) summary_input_data = tf.summary.image("input_data", img, 10) # 隠れ層 with tf.name_scope("hidden"): # 隠れ層の計算 w_1 = tf.Variable(tf.truncated_normal([784, 64], stddev=0.1), name="w1") b_1 = tf.Variable(tf.zeros([64]), name="b1") h_1 = tf.nn.relu(tf.matmul(x, w_1) + b_1) # ログにw_1のヒストグラムを出力 summary_w_1 = tf.summary.histogram("w1", w_1) # 出力層 with tf.name_scope("output"): # 出力層の計算 w_2 = tf.Variable(tf.truncated_normal([64, 10], stddev=0.1), name="w2") b_2 = tf.Variable(tf.zeros([10]), name="b2") out = tf.nn.softmax(tf.matmul(h_1, w_2) + b_2) # 正解ラベル with tf.name_scope("label"): # 正解ラベルの定義 y = tf.placeholder(tf.float32, [None, 10], name="y") # 誤差 with tf.name_scope("loss"): # 誤差の計算 loss = tf.reduce_mean(tf.square(y - out)) # 誤差をログに出力 summary_loss = tf.summary.scalar("loss", loss) # 訓練 with tf.name_scope("train"): # 訓練の設定 train_step = tf.train.GradientDescentOptimizer(0.5).minimize(loss) # 正解率 with tf.name_scope("accuracy"): # 正解率の計算 correct = tf.equal(tf.argmax(out, 1), tf.argmax(y, 1)) accuracy = tf.reduce_mean(tf.cast(correct, tf.float32)) # 正解率をログに出力 summary_accuracy = tf.summary.scalar("accuracy", accuracy) # 初期化 init = tf.global_variables_initializer() # 実行 with tf.Session() as sess: # ログをひとまとめにする設定 summary_op = tf.summary.merge([summary_input_data, summary_w_1, summary_accuracy, summary_loss]) # ログの保管場所 summary_writer = tf.summary.FileWriter("logs/mnist", sess.graph) # 初期化 sess.run(init) # テストデータ test_images, test_labels = mnist_data.test.images, mnist_data.test.labels # 学習 for i in range(1000): # 訓練データ train_images, train_labels = mnist_data.train.next_batch(50) # ミニバッチ学習 sess.run(train_step, feed_dict={x: train_images, y: train_labels}) # 定期的にログ書き出し step = i + 1 if step % 10 == 0: # ログのテキスト取得 summary_text = sess.run(summary_op, feed_dict={x: test_images, y: test_labels}) # ログに書き出し summary_writer.add_summary(summary_text, step)
出力
tensorboard --logdir logs/mnist
を実行し、ブラウザからlocalhost:6006
にアクセスすると、可視化結果が見られる。
入力画像
入力層から隠れ層への重みのヒストグラム
だいたい0の周りに分布していることがわかる。
学習途中のaccuracyとlossの推移
こういうグラフを見ると、深層学習やってる感が凄く出る。
ネットワークのグラフ構造
上記は画像のほんの一部で、実際にはこの何十倍もの巨大な画像に。。。
おそらく何かを盛大に間違っている気がするのだが、詳しい方教えてください。
TensorFlowでMNIST
TensorFlowでMNISTの分類器を実装した記事はいくらでもあるのだが、備忘録として。
目標
TensorFlowではじめるDeepLearning実装入門の第2章に従い、MNISTデータの分類器を構築する。
方針
- 隠れ層1つの単純なモデル
- 隠れ層の活性化関数はRelu、出力層の活性化関数はSoftmax
- 損失関数は平均二乗誤差
- 100回ミニバッチを学習するたびに、正解率を表示
コード
import tensorflow.examples.tutorials.mnist as mnist # MNISTを保存 mnist_data = mnist.input_data.read_data_sets("mnist/", one_hot=True) # 入力 x = tf.placeholder(tf.float32, [None, 784]) # 隠れ層 w_1 = tf.Variable(tf.truncated_normal([784, 64], stddev=0.1), name="w1") b_1 = tf.Variable(tf.zeros([64]), name="b1") h_1 = tf.nn.relu(tf.matmul(x, w_1) + b_1) # 出力層 w_2 = tf.Variable(tf.truncated_normal([64, 10], stddev=0.1), name="w2") b_2 = tf.Variable(tf.zeros([10]), name="b2") out = tf.nn.softmax(tf.matmul(h_1, w_2) + b_2) # 正解 y = tf.placeholder(tf.float32, [None, 10]) # 最適化 loss = tf.reduce_mean(tf.square(y - out)) train_step = tf.train.GradientDescentOptimizer(0.5).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) # テストデータ test_images, test_labels = mnist_data.test.images, mnist_data.test.labels # 学習 for i in range(1000): # 訓練データ train_images, train_labels = mnist_data.train.next_batch(50) # ミニバッチ学習 sess.run(train_step, feed_dict={x: train_images, y: train_labels}) # 定期的に評価 if (i + 1) % 100 == 0: # 正解率表示 acc_val = sess.run(accuracy, feed_dict={x: test_images, y: test_labels}) print(f"acc_val: {acc_val: .3}")
出力
Extracting mnist/train-images-idx3-ubyte.gz Extracting mnist/train-labels-idx1-ubyte.gz Extracting mnist/t10k-images-idx3-ubyte.gz Extracting mnist/t10k-labels-idx1-ubyte.gz acc_val: 0.419 acc_val: 0.653 acc_val: 0.797 acc_val: 0.834 acc_val: 0.85 acc_val: 0.865 acc_val: 0.875 acc_val: 0.882 acc_val: 0.889 acc_val: 0.887
深層学習の教科書で読んだ各部品(重みや活性化関数等)を、レゴブロックのような感覚で組み合わせられるのは面白い。