今日重點
閱讀一篇關于RNN網(wǎng)絡可視化的代碼,作者寫的比較清晰易懂,可以用來借鑒。我找了好久震蒋,在博客園找到的這篇,強烈推薦博客園(https://www.cnblogs.com/cloud-ken/p/9327746.html)躲庄。
Tensorboard是一個神經(jīng)網(wǎng)絡可視化工具查剖,通過使用本地服務器在瀏覽器上查看神經(jīng)網(wǎng)絡訓練日志,生成相應的可是畫圖噪窘,幫助煉丹師優(yōu)化神經(jīng)網(wǎng)絡笋庄。
油管上有單迪倫·馬內在2017年做的匯報,很驚艷倔监。主要包括了以下主要功能
- 可視化網(wǎng)絡
- 可視化訓練過程
- 多模型效果可視化對比
0. 引入必要庫
tqdm庫用來顯示運行進度條直砂。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import tqdm
1. 生成變量監(jiān)控信息并定義生成監(jiān)控信息日志的操作。
var給出了需要記錄的張量,name給出了在可視化結果中顯示的圖表名稱浩习,這個名稱一般和變量名一致静暂。使用name_scope將生成監(jiān)控信息的操作放在同一個命名空間下。
這個操作值得借鑒谱秽,我看tensorboard的指引代碼的時候感覺很難理解洽蛀,應該是我閱讀能力的問題。
通過tf.histogram_summary函數(shù)記錄張量中元素的取值分布
tf.summary.histogram函數(shù)會生成一個Summary protocol buffer疟赊。將Summary 寫入TensorBoard 日志文件后辱士,在HISTOGRAMS 欄,和DISTRIBUTION 欄下都會出現(xiàn)對應名稱的圖表听绳。和TensorFlow 中其他操作類似颂碘,
tf.summary.histogram 函數(shù)不會立刻被執(zhí)行,只有當sess.run 函數(shù)明確調用這個操作時椅挣, TensorFlow才會具正生成并輸出Summary protocol buffer头岔。
SUMMARY_DIR = "./logs/rnn4"
BATCH_SIZE = 100
TRAIN_STEPS = 3000
# var給出了需要記錄的張量,name給出了在可視化結果中顯示的圖表名稱,這個名稱一般和變量名一致
def variable_summaries(var, name):
# 將生成監(jiān)控信息的操作放在同一個命名空間下
with tf.name_scope('summaries'):
tf.summary.histogram(name, var)
# 計算變量的平均值鼠证,并定義生成平均值信息日志的操作峡竣,記錄變量平均值信息的日志標簽名為'mean/'+name,其中mean為命名空間,/是命名空間的分隔符在相同命名空間中的監(jiān)控指標會被整合到同一欄中量九,name則給出了當前監(jiān)控指標屬于哪一個變量
mean = tf.reduce_mean(var)
tf.summary.scalar('mean/' + name, mean)
# 計算變量的標準差适掰,并定義生成其日志文件的操作
stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
tf.summary.scalar('stddev/' + name, stddev)
2. 生成一層全鏈接的神經(jīng)網(wǎng)絡颂碧。
在這個神經(jīng)網(wǎng)絡層中,定義了權重weights类浪,偏置biases载城,算法Wx_plus_b,其實也是一個很簡單的神經(jīng)網(wǎng)絡费就。
def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu):
# 將同一層神經(jīng)網(wǎng)絡放在一個統(tǒng)一的命名空間下
with tf.name_scope(layer_name):
# 聲明神經(jīng)網(wǎng)絡邊上的權值诉瓦,并調用權重監(jiān)控信息日志的函數(shù)
with tf.name_scope('weights'):
weights = tf.Variable(tf.truncated_normal([input_dim, output_dim], stddev=0.1))
variable_summaries(weights, layer_name + '/weights')
# 聲明神經(jīng)網(wǎng)絡邊上的偏置,并調用偏置監(jiān)控信息日志的函數(shù)
with tf.name_scope('biases'):
biases = tf.Variable(tf.constant(0.0, shape=[output_dim]))
variable_summaries(biases, layer_name + '/biases')
with tf.name_scope('Wx_plus_b'):
preactivate = tf.matmul(input_tensor, weights) + biases
# 記錄神經(jīng)網(wǎng)絡節(jié)點輸出在經(jīng)過激活函數(shù)之前的分布
tf.summary.histogram(layer_name + '/pre_activations', preactivate)
activations = act(preactivate, name='activation')
# 記錄神經(jīng)網(wǎng)絡節(jié)點輸出在經(jīng)過激活函數(shù)之后的分布力细。
對于layer1 确买,因為使用了ReLU函數(shù)作為激活函數(shù)固该,所以所有小于0的值部被設為了0狐蜕。于是在激活后的layer1 / activations圖上所有的值都是大于0的雾棺。
對于layer2 ,因為沒有使用激活函數(shù)逝慧,所以layer2 / activations和layer2 / pre_activations一樣米绕。
tf.summary.histogram(layer_name + '/activations', activations)
return activations
3.設定主函數(shù)
主函數(shù)里面包括數(shù)據(jù)、網(wǎng)絡設置馋艺、反向傳播栅干、正確率計算等。
def main():
mnist = input_data.read_data_sets(".\MNIST_data/", one_hot=True)
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)
# 將輸入變量還原成圖片的像素矩陣捐祠,并通過tf.iamge_summary函數(shù)定義將當前的圖片信息寫入日志的操作
hidden1 = nn_layer(x, 784, 500, 'layer1')
y = nn_layer(hidden1, 500, 10, 'layer2', act=tf.identity)
# 計算交叉熵并定義生成交叉熵監(jiān)控日志的操作碱鳞。
with tf.name_scope('cross_entropy'):
cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=y, labels=y_))
tf.summary.scalar('cross_entropy', cross_entropy)
with tf.name_scope('train'):
train_step = tf.train.AdamOptimizer(0.001).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)
# tf.scalar_summary,tf.histogram_summary,tf.image_summary函數(shù)都不會立即執(zhí)行,需要通過sess.run來調用這些函數(shù),因為程序重定義的寫日志的操作非常多踱蛀,一一調用非常麻煩窿给,所以Tensorflow提供了tf.summary.merged_all()函數(shù)來整理所有的日志生成操作。在Tensorflow程序執(zhí)行的過程中只需要運行這個操作就可以將代碼中定義的所有日志生成操作全部執(zhí)行一次率拒,從而將所有日志文件寫入文件崩泡。
merged = tf.summary.merge_all()
with tf.Session() as sess:
# 初始化寫日志的writer,并將當前的Tensorflow計算圖寫入日志
summary_writer = tf.summary.FileWriter(SUMMARY_DIR, sess.graph)
tf.global_variables_initializer().run()
for i in tqdm.tqdm(range(TRAIN_STEPS)):
xs, ys = mnist.train.next_batch(BATCH_SIZE)
# 運行訓練步驟以及所有的日志生成操作,得到這次運行的日志猬膨。
summary, _ = sess.run([merged, train_step], feed_dict={x: xs, y_: ys})
# 將得到的所有日志寫入日志文件角撞,這樣TensorBoard程序就可以拿到這次運行所對應的
# 運行信息。
summary_writer.add_summary(summary, i)
summary_writer.close()
if __name__ =='__main__':
main()
運行后可以在操作界面查看運行的情況勃痴。效果其實不錯谒所。