TensorBoard是TensorFlow官方推出的可視化工具尺栖,它可以將模型訓練過程中的各種匯總數(shù)據(jù)展示出來决瞳。我們在使用TensorFlow訓練大型深度學習神經(jīng)網(wǎng)絡時皮胡,中間的計算過程可能非常復雜赏迟,可以使用TensorBoard觀察訓練過程中的各種可視化數(shù)據(jù)锌杀。它的流程是糕再,在執(zhí)行TensorFlow計算圖的過程中突想,將各種類型的數(shù)據(jù)匯總并記錄到日志文件中。然后使用TensorBoard讀取這些日志文件袭灯,解析數(shù)據(jù)并生成數(shù)據(jù)可視化Web頁面稽荧。
用一個MNIST數(shù)據(jù)集的手寫字體識別姨丈,看一下各種類型數(shù)據(jù)的匯總和展示构挤。
先說一下我的環(huán)境筋现,我用的是Cuda9.0+Ubuntu16.04+Tensorflow-gpu1.12+Python3.6矾飞。
訓練過程
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
max_steps=1000
learning_rate=0.001
dropout=0.9
data_dir='/tmp/tensorflow/mnist/input_data'
#匯總數(shù)據(jù)的日志存放地址
log_dir='/tmp/tensorflow/mnist/logs/mnist_with_summaries'
? # Import data
mnist = input_data.read_data_sets(data_dir,one_hot=True)
sess = tf.InteractiveSession()
? # Create a multilayer model.
? # Input placeholders
with tf.name_scope('input'):
? x = tf.placeholder(tf.float32, [None, 784], name='x-input')
? y_ = tf.placeholder(tf.float32, [None, 10], name='y-input')
with tf.name_scope('input_reshape'):
? image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
? tf.summary.image('input', image_shaped_input, 10)
? # We can't initialize these variables to 0 - the network will get stuck.
def weight_variable(shape):
? """Create a weight variable with appropriate initialization."""
? initial = tf.truncated_normal(shape, stddev=0.1)
? return tf.Variable(initial)
def bias_variable(shape):
? """Create a bias variable with appropriate initialization."""
? initial = tf.constant(0.1, shape=shape)
? return tf.Variable(initial)
def variable_summaries(var):
? """Attach a lot of summaries to a Tensor (for TensorBoard visualization)."""
? 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))
#直接記錄變量var的直方圖數(shù)據(jù)
? ? tf.summary.histogram('histogram', var)
def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu):
? """Reusable code for making a simple neural net layer.
? It does a matrix multiply, bias add, and then uses relu to nonlinearize.
? It also sets up name scoping so that the resultant graph is easy to read,
? and adds a number of summary ops.
? """
? # Adding a name scope ensures logical grouping of the layers in the graph.
? with tf.name_scope(layer_name):
? ? # This Variable will hold the state of the weights for the layer
? ? with tf.name_scope('weights'):
? ? ? weights = weight_variable([input_dim, output_dim])
? ? ? variable_summaries(weights)
? ? with tf.name_scope('biases'):
? ? ? biases = bias_variable([output_dim])
? ? ? variable_summaries(biases)
? ? with tf.name_scope('Wx_plus_b'):
? ? ? preactivate = tf.matmul(input_tensor, weights) + biases
? ? ? tf.summary.histogram('pre_activations', preactivate)
? ? activations = act(preactivate, name='activation')
? ? tf.summary.histogram('activations', activations)
? ? return activations
hidden1 = nn_layer(x, 784, 500, 'layer1')
with tf.name_scope('dropout'):
? keep_prob = tf.placeholder(tf.float32)
? tf.summary.scalar('dropout_keep_probability', keep_prob)
? dropped = tf.nn.dropout(hidden1, keep_prob)
? # Do not apply softmax activation yet, see below.
y = nn_layer(dropped, 500, 10, 'layer2', act=tf.identity)
with tf.name_scope('cross_entropy'):
? ? # The raw formulation of cross-entropy,
? ? #
? ? # tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(tf.softmax(y)),
? ? #? ? ? ? ? ? ? ? ? ? ? ? ? ? ? reduction_indices=[1]))
? ? #
? ? # can be numerically unstable.
? ? #
? ? # So here we use tf.nn.softmax_cross_entropy_with_logits on the
? ? # raw outputs of the nn_layer above, and then average across
? ? # the batch.
? diff = tf.nn.softmax_cross_entropy_with_logits(logits=y, labels=y_)
? with tf.name_scope('total'):
? ? cross_entropy = tf.reduce_mean(diff)
tf.summary.scalar('cross_entropy', cross_entropy)
with tf.name_scope('train'):
? train_step = tf.train.AdamOptimizer(learning_rate).minimize(
? ? ? cross_entropy)
with tf.name_scope('accuracy'):
? with tf.name_scope('correct_prediction'):
? ? correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
? with tf.name_scope('accuracy'):
? ? accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.summary.scalar('accuracy', accuracy)
? # Merge all the summaries and write them out to /tmp/mnist_logs (by default)
merged = tf.summary.merge_all()
train_writer = tf.summary.FileWriter(log_dir + '/train', sess.graph)
test_writer = tf.summary.FileWriter(log_dir + '/test')
tf.global_variables_initializer().run()
? # Train the model, and also write summaries.
? # Every 10th step, measure test-set accuracy, and write test summaries
? # All other steps, run train_step on training data, & add training summaries
def feed_dict(train):
? """Make a TensorFlow feed_dict: maps data onto Tensor placeholders."""
? if train:
? ? xs, ys = mnist.train.next_batch(100)
? ? k = dropout
? else:
? ? xs, ys = mnist.test.images, mnist.test.labels
? ? k = 1.0
? return {x: xs, y_: ys, keep_prob: k}
saver = tf.train.Saver()
for i in range(max_steps):
? if i % 10 == 0:? # Record summaries and test-set accuracy
? ? summary, acc = sess.run([merged, accuracy], feed_dict=feed_dict(False))
? ? test_writer.add_summary(summary, i)
? ? print('Accuracy at step %s: %s' % (i, acc))
? else:? # Record train set summaries, and train
? ? if i % 100 == 99:? # Record execution stats
? ? ? run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
? ? ? run_metadata = tf.RunMetadata()
? ? ? summary, _ = sess.run([merged, train_step],
? ? ? ? ? ? ? ? ? ? ? ? ? ? feed_dict=feed_dict(True),
? ? ? ? ? ? ? ? ? ? ? ? ? ? options=run_options,
? ? ? ? ? ? ? ? ? ? ? ? ? ? run_metadata=run_metadata)
? ? ? train_writer.add_run_metadata(run_metadata, 'step%03d' % i)
? ? ? train_writer.add_summary(summary, i)
? ? ? saver.save(sess, log_dir+"/model.ckpt", i)
? ? ? print('Adding run metadata for', i)
? ? else:? # Record a summary
? ? ? summary, _ = sess.run([merged, train_step], feed_dict=feed_dict(True))
? ? ? train_writer.add_summary(summary, i)
train_writer.close()
test_writer.close()
可視化效果
切換到Linux命令行下,執(zhí)行TensorBoard程序括尸,并通過--logdir指定TensorFlow日志路徑濒翻,然后就可以自動生成所有匯總數(shù)據(jù)可視化的結果了有送。
tensorboard --logdir=/tmp/tensorflow/mnist/logs/mnist_with_summaries
執(zhí)行上面的命令后雀摘,出現(xiàn)一條提示信息,復制其中的網(wǎng)址到瀏覽器烁落,就能看到數(shù)據(jù)可視化的圖標了。
首先打開標量SCALARS的窗口轧铁,并單擊打開accuracy的圖表旦棉,其中可以看到兩條曲線齿风,分別是train和test中accuracy隨訓練步數(shù)變化的趨勢药薯。可以調整Smoothing參數(shù)救斑,控制對曲線的平滑處理童本。如下圖所示
打開IMAGES窗口,可以看到MNIST數(shù)據(jù)集中的圖片脸候,不只是原始數(shù)據(jù)穷娱,所有在tf.summary.image()中匯總的圖片數(shù)據(jù)都可以在這里看到。
進入GRAPHS窗口运沦,可以看到整個TensorFlow計算圖的結構,這里展示了網(wǎng)絡forward的inference的流程携添,以及backward訓練更新參數(shù)的流程
切換到DISTRIBUTIONS窗口嫁盲,可以看到之前記錄的各個神經(jīng)網(wǎng)絡層輸出的分布,包括在激活函數(shù)前的結果及在激活函數(shù)后的結果烈掠。這樣能觀察到神經(jīng)網(wǎng)絡節(jié)點的輸出是否有效
點擊HISTOGRAMS窗口羞秤,將DISTRIBUTIONS的圖示結構轉換為直方圖的形式,將每一步訓練后的神經(jīng)網(wǎng)絡層的輸出的分布以直方圖的形式展示出來
單擊PROJECTOR左敌,可以看到降維后的嵌入向量的可視化效果