TensorFlow從0到1 - 17 - Step By Step上手TensorBoard

TensorFlow從0到1系列回顧

上一篇16 L2正則化對抗“過擬合”提到,為了檢測訓(xùn)練過程中發(fā)生的過擬合,需要記錄每次迭代(甚至每次step)模型在訓(xùn)練集和驗證集上的識別精度。其實,為了能更好的調(diào)試和優(yōu)化TensorFlow程序,日志(logging)和監(jiān)測(monitoring)需求遠(yuǎn)不止“識別精度”。在訓(xùn)練過程中不斷變化的“損失”、“更新速率”(step/sec)甚至“概率分布”等信息,都是幫助我們深入理解模型與訓(xùn)練的關(guān)鍵信息。

對此,TensorBoard提供了盡善盡美的支持。它能將所記錄的動/靜態(tài)信息,方便的可視化成直觀的圖形,幫助人們更容易的分析并獲得洞察,讓神經(jīng)網(wǎng)絡(luò)“黑盒”變得透明。

本篇介紹TensorBoard的基本用法:繪制MNIST案例中計算圖、識別精度和損失。

訓(xùn)練集和驗證集識別精度

TensorBoard生成圖形的流程框架,簡單概括起來就兩點:

  • TensorFlow運行并將log信息記錄到文件;
  • TensorBoard讀取文件并繪制圖形。

在代碼實現(xiàn)和組織層面,通常只要在“正常”代碼后集中添加負(fù)責(zé)logging的代碼即可,兩者能夠很好的區(qū)隔,不會發(fā)生嚴(yán)重的耦合。以下示例代碼基于16 L2正則化對抗“過擬合”,修改了logging的部分。

step 1:構(gòu)造summary node

TensorBoard以protocol buffer 的方式記錄信息,它是Google開發(fā)的一種序列化結(jié)構(gòu)數(shù)據(jù)的方法。

我們的目標(biāo)是記錄accuracy和loss,更準(zhǔn)確的說是記錄accuracy node和loss node的輸出值,那么首先需要將數(shù)據(jù)轉(zhuǎn)換成protocol buffer object,而負(fù)責(zé)轉(zhuǎn)換動作的就是TensorFlow提供的summary節(jié)點(summary有匯總和概括的含義,暫不做翻譯)。

accuracy_scalar = tf.summary.scalar('accuracy', accuracy)
loss_scalar = tf.summary.scalar('loss', loss)

上面的tf.summary.scalar方法稱為summary operation。它接受一個要跟蹤的節(jié)點,并返回一個scalar summary節(jié)點,該節(jié)點以protocol buffer的方式表示一個標(biāo)量值。

summary節(jié)點與其他節(jié)點一樣,依靠Session運行才會有輸出。如果跟蹤的節(jié)點非常多,還可以進(jìn)行節(jié)點合并,Session在運行時會自動遍歷運行所有的summary節(jié)點:

merged = tf.summary.merge_all()

step 2:構(gòu)造summary file writer

構(gòu)造好summary node后,就要構(gòu)造summary文件寫入器了,所有跟蹤的信息都依靠它來寫入文件,而TensorBoard繪制的圖形正是基于這些文件的。

train_writer = tf.summary.FileWriter('MNIST/logs/tf17/train')
validation_writer = tf.summary.FileWriter('MNIST/logs/tf17/validation')

tf.summary.FileWriter構(gòu)造summary文件寫入器,接受一個log的目錄作為保存文件的路徑。log目錄如果不存在,會被程序自動創(chuàng)建。通常訓(xùn)練集日志和驗證集日志分開存放,分別構(gòu)造各自的summary文件寫入器即可。

step 3:運行summary節(jié)點

在運行summary節(jié)點時,出于性能考慮(盡可能少的運行計算圖),會與使用相同輸入數(shù)據(jù)的“正常”節(jié)點一起執(zhí)行,下面代碼基于訓(xùn)練數(shù)據(jù),使用了合并的summary節(jié)點:

summary, accuracy_currut_train = sess.run(
    [merged, accuracy],
    feed_dict={x: mnist.train.images, y_: mnist.train.labels})

在summary節(jié)點不多時,當(dāng)然也可以分別運行節(jié)點,下面代碼基于驗證數(shù)據(jù),使用了單獨的summary節(jié)點:

(sum_accuracy_validation,
 sum_loss_validation,
 accuracy_currut_validation) = sess.run(
    [accuracy_scalar, loss_scalar, accuracy],
    feed_dict={x: mnist.validation.images, y_: mnist.validation.labels})

step 4:向記錄器添加

運行summary節(jié)點的輸出,即可通過文件寫入器的add_summary方法進(jìn)行添加,該方法除了接受summary節(jié)點的運行輸出值,還接受一個global_step參數(shù)來作為序列號:

train_writer.add_summary(summary, epoch)
validation_writer.add_summary(sum_accuracy_validation, epoch)
validation_writer.add_summary(sum_loss_validation, epoch)

step 5:啟動TensorBoard Server

啟動TensorBoard Server可以與前面的記錄寫入并行,TensorBoard會自動的掃描日志文件的更新。

重新生成并繪制,只需手工刪除現(xiàn)有數(shù)據(jù)或者目錄即可。

新啟動一個命令行窗口,激活虛擬環(huán)境,鍵入命令tensorboard,其參數(shù)logdir指出log文件的存放目錄,可以只給出其上級目錄,TensorBoard會自動遞歸掃描目錄:

tensorboard --logdir=TF1_1/MNIST
TensorBoard Server

當(dāng)TensorBoard服務(wù)器順利啟動后,即可打開瀏覽器輸入地址:http://127.0.0.1:6006/查看。注意在Windows環(huán)境下輸入http://0.0.0.0:6006/無效。下圖就是TensorBoard繪制出的accuracy和loss的圖形:

TensorBoard

圖形“同框”技巧

上圖中的accuracy和loss圖形中,訓(xùn)練集曲線和驗證集曲線以不同顏色“同框”出現(xiàn),特別便于對比分析。同框需要滿足以下兩點:

  • 要同框的曲線跟蹤的必須是同一個節(jié)點,比如跟蹤accuracy節(jié)點或loss節(jié)點;
  • 各曲線的數(shù)據(jù)記錄在不同的目錄下,可以通過構(gòu)造兩個不同的文件寫入器來達(dá)到;

繪制計算圖

TensorBoard除了繪制動態(tài)數(shù)據(jù),繪制靜態(tài)的graph(計算圖)更是easy,在構(gòu)造“文件寫入器”多添加一個參數(shù)sess.graph即可:

train_writer = tf.summary.FileWriter('MNIST/logs/tf17/train', sess.graph)

重新運行TensorFlow程序后,啟動TensorBoard Server,在瀏覽器打開頁面,點選GRAPHS菜單,即可看到:

Graph

附完整代碼

import argparse
import sys
from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf

FLAGS = None


def main(_):
    # Import data
    mnist = input_data.read_data_sets(FLAGS.data_dir, one_hot=True,
                                      validation_size=10000)

    # Create the model
    x = tf.placeholder(tf.float32, [None, 784])
    W_2 = tf.Variable(tf.random_normal([784, 100]) / tf.sqrt(784.0))
    '''W_2 = tf.get_variable(
        name="W_2",
        regularizer=regularizer,
        initializer=tf.random_normal([784, 30], stddev=1 / tf.sqrt(784.0)))'''
    b_2 = tf.Variable(tf.random_normal([100]))
    z_2 = tf.matmul(x, W_2) + b_2
    a_2 = tf.sigmoid(z_2)

    W_3 = tf.Variable(tf.random_normal([100, 10]) / tf.sqrt(100.0))
    '''W_3 = tf.get_variable(
        name="W_3",
        regularizer=regularizer,
        initializer=tf.random_normal([30, 10], stddev=1 / tf.sqrt(30.0)))'''
    b_3 = tf.Variable(tf.random_normal([10]))
    z_3 = tf.matmul(a_2, W_3) + b_3
    a_3 = tf.sigmoid(z_3)

    # Define loss and optimizer
    y_ = tf.placeholder(tf.float32, [None, 10])

    tf.add_to_collection(tf.GraphKeys.WEIGHTS, W_2)
    tf.add_to_collection(tf.GraphKeys.WEIGHTS, W_3)
    regularizer = tf.contrib.layers.l2_regularizer(scale=5.0 / 50000)
    reg_term = tf.contrib.layers.apply_regularization(regularizer)

    loss = (tf.reduce_mean(
        tf.nn.sigmoid_cross_entropy_with_logits(labels=y_, logits=z_3)) +
        reg_term)

    train_step = tf.train.GradientDescentOptimizer(0.5).minimize(loss)

    sess = tf.InteractiveSession()
    tf.global_variables_initializer().run()

    correct_prediction = tf.equal(tf.argmax(a_3, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

    accuracy_scalar = tf.summary.scalar('accuracy', accuracy)
    loss_scalar = tf.summary.scalar('loss', loss)
    merged = tf.summary.merge_all()
    train_writer = tf.summary.FileWriter(
        'MNIST/logs/tf17/train', sess.graph)
    validation_writer = tf.summary.FileWriter(
        'MNIST/logs/tf17/validation')

    # Train
    best = 0
    for epoch in range(30):
        for _ in range(5000):
            batch_xs, batch_ys = mnist.train.next_batch(10)
            sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys})
        # Test trained model
        summary, accuracy_currut_train = sess.run(
            [merged, accuracy],
            feed_dict={x: mnist.train.images,
                       y_: mnist.train.labels})

        (sum_accuracy_validation,
         sum_loss_validation,
         accuracy_currut_validation) = sess.run(
            [accuracy_scalar, loss_scalar, accuracy],
            feed_dict={x: mnist.validation.images,
                       y_: mnist.validation.labels})

        train_writer.add_summary(summary, epoch)
        validation_writer.add_summary(sum_accuracy_validation, epoch)
        validation_writer.add_summary(sum_loss_validation, epoch)

        print("Epoch %s: train: %s validation: %s"
              % (epoch, accuracy_currut_train, accuracy_currut_validation))
        best = (best, accuracy_currut_validation)[
            best <= accuracy_currut_validation]

    # Test trained model
    print("best: %s" % best)
    train_writer.close()
    validation_writer.close()


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--data_dir', type=str, default='../MNIST/',
                        help='Directory for storing input data')
    FLAGS, unparsed = parser.parse_known_args()
    tf.app.run(main=main, argv=[sys.argv[0]] + unparsed)

下載 tf_17_tensorboard.py

上一篇 16 L2正則化對抗“過擬合”
下一篇 18 升級手記:TensorFlow 1.3.0


共享協(xié)議:署名-非商業(yè)性使用-禁止演繹(CC BY-NC-ND 3.0 CN)
轉(zhuǎn)載請注明:作者黑猿大叔(簡書)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容