TensorBoardでビギナー向けMNISTチュートリアルを可視化する

#概要
TensorFlowの公式チュートリアル[MNIST For ML Beginners](https://www.tensorflow.org/versions/r0.9/tutorials/mnist/beginners/index.html)をTensorBoardで可視化して、TensorFlowとTensorBoardを理解しようとしたので、その記録です。
作成したコードは[GitHub](https://github.com/kozenumezawa/TensorFlow/blob/master/tutorial/MNIST1/mnist1-tensorboard.py)にあります。

# 環境
以下のプログラムは、次の環境で動作確認をしています。

```
Python 2.7.13
tensorflow (1.4.0)
tensorflow-tensorboard (0.4.0rc3)
```

#公式のチュートリアル
[MNIST For ML Beginners](https://www.tensorflow.org/versions/r0.9/tutorials/mnist/beginners/index.html)を和訳しつつ、そのままコードにすると次のようになります。人工知能初心者の私には、このままではわかりにくかったので、TensorBoardを追加したいと考えました。

```python:mnist1.py
# coding:utf-8
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

#   placeholderは、値（テンソル）が入力される場所
#   [None, 784]は2次元のテンソル。Noneは次元の指定なしの意味
x = tf.placeholder(tf.float32, [None, 784])

#   Variableは変更可能なテンソル
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))

#   xW+bを計算。yはNN(ニューラルネットワーク)の出力として使う
#   ソフトマックス関数を用いることで、xW+bの各要素を0~1に変換している
y = tf.nn.softmax(tf.matmul(x, W) + b)

#   y_は、教師データやテストデータの正解が入力されるplaceholder
y_ = tf.placeholder(tf.float32, [None, 10])

#   クロスエントロピーはコスト関数
#   y(教師データの入力からNNを用いて求めた出力)とy_（教師データの正解）のクロスエントロピーを計算して、正解度をチェック
cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))

#   最急降下法を用いてクロスエントロピーの最小化を図る
train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)

#   すべての変数を初期化する準備
init = tf.global_variables_initializer()

#   Sessionを初期化して開始
#   Sessionが、上で定義したNNのグラフ（placeholderとvariableの接続関係）と計算資源（CPU・GPU）をつないでくれる
sess = tf.Session()
sess.run(init)

#   1000回学習させる
for i in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)    #   データを所得
#   feed_dictを用いて、placeholderに渡す入力データを指定する
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})

#   学習させた後のNNが、未知のデータを正しく分類できるかの評価基準を設定
correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1))

#   correct_predictionは、[True, False, True, True,　・・・]といったデータ構造なので、これを0(False),1(True)に対応付けて、その平均値を計算
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels}))
```

ちなみに、実行すると正解率0.91ぐらいが表示されます。

#TensorBoardの導入
TensorBoardで扱うデータを作成するために、上のプログラムのsess.run(init)の後に次の行を追加します。

```python:
summary_writer = tf.summary.FileWriter('mnist1_data', graph=sess.graph) 
```

こうすることで、プログラム実行時にプログラムと同じディレクトリに'mnist1_data'というディレクトリを作り、そこにTensorBoardに必要なデータを保存するようになります。
プログラム実行後、次のようにTensorBoardを実行して、[http://localhost:6006](http://localhost:6006)にアクセスすることでグラフを確認することができます。

```text
$ python mnist1-tensorboard.py
$ tensorboard --logdir=/ディレクトリの絶対パス/mnist1_data
```

この実行結果は次のようになります。
![1.png](https://qiita-image-store.s3.amazonaws.com/0/131125/47089a69-c4d1-5479-bf72-d6fd16a9125b.png)

これだけではわかりにくいので、次のようにplaceholderとvariableに名前をつけていきます。

```python:
x = tf.placeholder(tf.float32, [None, 784], name="x")
W = tf.Variable(tf.zeros([784, 10]), name="W")
b = tf.Variable(tf.zeros([10]), name="b")
y_ = tf.placeholder(tf.float32, [None, 10], name="y_")
```

これを実行すると次のようになり、それぞれに名前がついた状態になります。
![2.png](https://qiita-image-store.s3.amazonaws.com/0/131125/4a8ffa2d-b40a-091d-3255-611a7338982e.png)
こうすることで、一番下から入力xが入り、その後MatMulを用いてxWを計算し、さらにbをaddする・・というように流れが少しわかるようになってきました。
しかし、グラフが細かすぎて見にくいので、次のようにグラフをまとめたい処理の直前にtf.name_scopeを追加して処理をまとめます。

```python:
#   クロスエントロピーの計算をname_scopeでまとめる
with tf.name_scope("cross-entropy"):
    cross_entropy = tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(y), reduction_indices=[1]))

#   最急降下法の計算をname_scopeでまとめる
with tf.name_scope("training"):
    train_step = tf.train.GradientDescentOptimizer(0.5).minimize(cross_entropy)
```

そして実行すると次のようになります。
![3.png](https://qiita-image-store.s3.amazonaws.com/0/131125/71330d03-e79c-c079-5850-ae0d05f5e239.png)

先ほどまでより、非常に見やすくなりました。
この結果のグラフから、[MNIST For ML Beginners](https://www.tensorflow.org/versions/r0.9/tutorials/mnist/beginners/index.html)では、
入力xをy=aW+bとして出力を求め、クロスエントロピーを用いて正解y_との比較を行ってるいることがわかります。
また、trainingでは、クロスエントロピーが最小になるWとbを見つけるために、すべてのデータを所得していることがわかります。

#まとめ
MNISTチュートリアルを少し修正してあげるだけで、簡単にTensorBoardで可視化できることがわかりました。
自分のような初心者の方の理解の助けになれば幸いです。