TensorFlow9:TensorBoard可視化

前面的章節(jié)已經(jīng)介紹了如何使用TensorFlow實(shí)現(xiàn)常用的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)帘腹。在將這些神經(jīng)網(wǎng)絡(luò)用于實(shí)際問題之前,需要先優(yōu)化網(wǎng)絡(luò)中的參數(shù)许饿。這就是訓(xùn)練神經(jīng)網(wǎng)絡(luò)的過程阳欲。訓(xùn)練神經(jīng)網(wǎng)絡(luò)十分復(fù)雜,有時需要幾天甚至幾周的時間陋率。為了更好地管理球化、調(diào)試和優(yōu)化神經(jīng)網(wǎng)絡(luò)的訓(xùn)練過程,TensorFlow提供了一個可視化工具TensorBoard瓦糟。TensorBoard可以有效地展示TensorFlow在運(yùn)行過程中的計(jì)算圖筒愚、各種指標(biāo)隨著時間的變化趨勢以及訓(xùn)練中使用到的圖像等信息。
本章將詳細(xì)介紹TensorBoard的使用方法菩浙。
1.將介紹TensorBoard的基礎(chǔ)知識巢掺,并通過TensorBoard來可視化一個簡單的TensorFlow樣例程序。在這一節(jié)中將介紹如何啟動TensorBoard劲蜻,并大致講解TensorBoard提供的幾類可視化信息陆淀。
2.介紹通過TensorBoard得到的TensorFlow計(jì)算圖的可視化結(jié)果。TensorFlow計(jì)算圖保存了TensorFlow程序計(jì)算過程的所有信息先嬉。因?yàn)門ensorFlow計(jì)算圖中的信息含量較多轧苫,所以TensorBoard設(shè)計(jì)了一套交互過程來更加清晰地呈現(xiàn)這些信息。
3.最后將詳細(xì)講解如何使用在這一節(jié)中將詳細(xì)講解如何使用TensorBoard對訓(xùn)練過程進(jìn)行監(jiān)控疫蔓,以及如何通過TensorFlow指定對訓(xùn)練過程進(jìn)行監(jiān)控含懊,以及如何通過TensorFlow指定需要可視化的指標(biāo)。并給出完整的樣例程序介紹如何得到可視化結(jié)果衅胀。

1.TensorBoard簡介

TensorBoard是TensorFlow的可視化工具绢要,它可以通過TensorFlow程序運(yùn)行過程中輸出的日志文件可視化TensorFlow程序的運(yùn)行狀態(tài)。TensorBoard和TensorFlow程序跑在不同的進(jìn)程中拗小,TensorBoard會自動讀取最新的TensorFlow日志文件重罪,并呈現(xiàn)當(dāng)前TensorFlow程序運(yùn)行的最新狀態(tài)。以下代碼展示了一個簡單的TensorFlow程序哀九,這個程序中完成了TensorBoard日志輸出的功能:

import tensorflow as tf

input1 = tf.constant([1.0, 2.0, 3.0], name="input1")
input2 = tf.Variable(tf.random_uniform([3]), name="input2")
output = tf.add_n([input1, input2], name="add")
writer = tf.summary.FileWriter("C:\\log", tf.get_default_graph())
writer.close()

以上程序輸出了TensorFlow計(jì)算圖的信息剿配,所以運(yùn)行Tensorboard時,可以看到這個向量相加程序計(jì)算圖可視化之后的結(jié)果阅束。TensorBoard不需要額外的安裝過程呼胚,在TensorFlow安裝完成時,TensorBoard會被自動安裝息裸。運(yùn)行下面的命令可以啟動TensorBoard:
運(yùn)行TensorBoard蝇更,并將日志的地址指向上面程序日志輸出的地址
tensorboard --logdir=C:\\log
運(yùn)行上面的命令會啟動一個服務(wù)沪编,這個服務(wù)的端口默認(rèn)為6006.通過瀏覽器打開localhost:6006,可以看到下圖所示的界面:

TensorBoard默認(rèn)欄界面

如上圖,可以看到上面程序TensorFlow計(jì)算圖的可視化結(jié)果年扩。
在界面右上方蚁廓,點(diǎn)擊下拉菜單可以看到有12欄,每一欄都對應(yīng)了一類信息的可視化結(jié)果厨幻,在下面的章節(jié)中將具體介紹每一欄的功能相嵌。如圖,打開tensorboard界面會默認(rèn)進(jìn)入SCALARS欄况脆。因?yàn)樯厦娴某绦驔]有輸出任何由EVENTS欄可視化的信息饭宾,所以這個界面顯示的是“NO scalar data was found”(沒有發(fā)現(xiàn)標(biāo)量數(shù)據(jù))。

2.TensorFlow計(jì)算圖可視化

在上圖中給出了一個TensorFlow計(jì)算圖的可視化效果圖格了。然而看铆,從TensorBoard可視化結(jié)果中可以獲取的信息遠(yuǎn)不止上圖所示的這些。這一節(jié)將詳細(xì)介紹如何更好地利用TensorFlow計(jì)算圖的可視化結(jié)果盛末。
1.首先將介紹通過TensorFlow節(jié)點(diǎn)的命名空間整理Tensorboard可視化得到的TensorFlow計(jì)算圖性湿。在前面介紹過,TensorFlow會將所有的計(jì)算以圖的形式組織起來满败。TensorBoard可視化得到的圖并不僅是將TensorFlow計(jì)算圖中的節(jié)點(diǎn)和邊直接可視化,它會根據(jù)每個TensorFlow計(jì)算節(jié)點(diǎn)的命名空間來整理可視化得到的效果叹括,使得神經(jīng)網(wǎng)絡(luò)的整體結(jié)構(gòu)不會被過多的細(xì)節(jié)所淹沒算墨。除了顯示TensorFlow計(jì)算圖的結(jié)構(gòu),TensorBoard還可以展示TensorFlow計(jì)算節(jié)點(diǎn)上的其他信息汁雷。
2.第二小節(jié)將介紹如何從可視化結(jié)果中獲取TensorFlow計(jì)算圖中的這些信息净嘀。

2.1命名空間與TensorBoard圖上節(jié)點(diǎn)

在上一節(jié)給出的樣例程序中只定義了一個加法操作,然而從圖中可以看到侠讯,將這個TensorFlow計(jì)算圖可視化得到的效果圖上卻有
多個節(jié)點(diǎn)挖藏,可以想象,一個復(fù)雜的神經(jīng)網(wǎng)絡(luò)模型所對應(yīng)的TensorFlow計(jì)算圖會比上圖中簡單的向量加法樣例程序的計(jì)算圖復(fù)雜很多厢漩,那么沒有經(jīng)過整理得到的可視化效果圖并不能幫助很好地理解神經(jīng)網(wǎng)絡(luò)模型的結(jié)構(gòu)膜眠。
為了更好地組織可視化效果圖中的計(jì)算節(jié)點(diǎn),TensorBoard支持通過TensorFlow命名空間來整理可視化效果圖上的節(jié)點(diǎn)溜嗜。在TensorBoard的默認(rèn)視圖中宵膨,TensorFlow計(jì)算圖中同一個命名空間下的所有節(jié)點(diǎn)會被縮略成一個節(jié)點(diǎn),只有頂層命名空間中的節(jié)點(diǎn)才會被顯示在TensorBoard可視化效果圖上炸宵。在前面介紹過變量的命名空間辟躏,以及如何通過tf.variable_scope函數(shù)管理變量的命名空間。除了tf.variable_scope函數(shù)土全,tf.name_scope函數(shù)也提供了命名空間管理的功能捎琐。這兩個函數(shù)在大部分情況下是等價(jià)的会涎,唯一的區(qū)別是在使用tf.get_variable函數(shù)時,以下代碼簡單地說明了這兩個函數(shù)的區(qū)別:
1.不同的命名空間

import tensorflow as tf
with tf.variable_scope("foo"):
    a = tf.get_variable("bar", [1])
    print a.name

with tf.variable_scope("bar"):
    b = tf.get_variable("bar", [1])
    print b.name

輸出:


不同命名空間的輸出
  1. tf.Variable和tf.get_variable的區(qū)別瑞凑。
with tf.name_scope("a"):
    a = tf.Variable([1])
    print a.name
    
    a = tf.get_variable("b", [1])
    print a.name

輸出:


tf.Variable和tf.get_variable的輸出

結(jié)果分析:
使用tf.Variable函數(shù)生成變量會受到tf.name_scope影響末秃,于是這個變量的名稱為“a/Variable”
而使用tf.get_variable函數(shù)不受tf.name_scope函數(shù)的影響,于是變量并不在b這個命名空間中拨黔。所以這個變量名稱為b

通過對命名空間管理蛔溃,可以改進(jìn)上一節(jié)中向量加法的樣例代碼,使得可視化得到的效果圖更加清晰篱蝇。以下代碼展示了改進(jìn)的方法:

    with tf.name_scope("input1"):
        input1 = tf.constant([1.0, 2.0, 3.0], name="input1")
    with tf.name_scope("input2"):
        input2 = tf.Variable(tf.random_uniform([3]), name="input2")
    output = tf.add_n([input1, input2], name="add")
    writer = tf.summary.FileWriter("C:\\log", tf.get_default_graph())
    writer.close()

下圖顯示了改進(jìn)后的可視化效果圖:


改進(jìn)后向量加法程序TensorFlow計(jì)算圖的可視化效果圖

從圖中可以看到贺待,上圖中很多的節(jié)點(diǎn)都被縮略到了圖中input2節(jié)點(diǎn)。這樣TensorFlow程序中定義的加法運(yùn)算被清晰地展示了出來零截。需要查看input2節(jié)點(diǎn)中具體包含了哪些運(yùn)算時麸塞,可以將鼠標(biāo)移動到input2節(jié)點(diǎn),并點(diǎn)開右上角加好“+”涧衙。下圖展示了input2節(jié)點(diǎn)之后的視圖:


展開input2節(jié)點(diǎn)的可視化效果圖

在input2的展開圖中可以看到數(shù)據(jù)初始化相關(guān)的操作都被整理到了一起哪工。下面將給出一個樣例程序來展示如何很好地可視化一個真實(shí)的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)圖。本節(jié)將繼續(xù)采用之前的MNIST數(shù)字識別問題哪一章的架構(gòu)弧哎,以下代碼給出了改造后的mnist_train.py程序:
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_inference
  1. 定義神經(jīng)網(wǎng)絡(luò)的參數(shù)雁比。
BATCH_SIZE = 100
LEARNING_RATE_BASE = 0.8
LEARNING_RATE_DECAY = 0.99
REGULARIZATION_RATE = 0.0001
TRAINING_STEPS = 3000
MOVING_AVERAGE_DECAY = 0.99
  1. 定義訓(xùn)練的過程并保存TensorBoard的log文件。
def train(mnist):
    #  輸入數(shù)據(jù)的命名空間撤嫩。
    with tf.name_scope('input'):
        x = tf.placeholder(tf.float32, [None, mnist_inference.INPUT_NODE], name='x-input')
        y_ = tf.placeholder(tf.float32, [None, mnist_inference.OUTPUT_NODE], name='y-input')
    regularizer = tf.contrib.layers.l2_regularizer(REGULARIZATION_RATE)
    y = mnist_inference.inference(x, regularizer)
    global_step = tf.Variable(0, trainable=False)
    
    # 處理滑動平均的命名空間偎捎。
    with tf.name_scope("moving_average"):
        variable_averages = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
        variables_averages_op = variable_averages.apply(tf.trainable_variables())
   
    # 計(jì)算損失函數(shù)的命名空間。
    with tf.name_scope("loss_function"):
        cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
        cross_entropy_mean = tf.reduce_mean(cross_entropy)
        loss = cross_entropy_mean + tf.add_n(tf.get_collection('losses'))
    
    # 定義學(xué)習(xí)率序攘、優(yōu)化方法及每一輪執(zhí)行訓(xùn)練的操作的命名空間茴她。
    with tf.name_scope("train_step"):
        learning_rate = tf.train.exponential_decay(
            LEARNING_RATE_BASE,
            global_step,
            mnist.train.num_examples / BATCH_SIZE, LEARNING_RATE_DECAY,
            staircase=True)

        train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)

        with tf.control_dependencies([train_step, variables_averages_op]):
            train_op = tf.no_op(name='train')
    
    writer = tf.summary.FileWriter("log", tf.get_default_graph())
    
    # 訓(xùn)練模型。
    with tf.Session() as sess:
        tf.global_variables_initializer().run()
        for i in range(TRAINING_STEPS):
            xs, ys = mnist.train.next_batch(BATCH_SIZE)

            if i % 1000 == 0:
                # 配置運(yùn)行時需要記錄的信息程奠。
                run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
                # 運(yùn)行時記錄運(yùn)行信息的proto丈牢。
                run_metadata = tf.RunMetadata()
                _, loss_value, step = sess.run(
                    [train_op, loss, global_step], feed_dict={x: xs, y_: ys},
                    options=run_options, run_metadata=run_metadata)
                writer.add_run_metadata(run_metadata=run_metadata, tag=("tag%d" % i), global_step=i)
                print("After %d training step(s), loss on training batch is %g." % (step, loss_value))
            else:
                _, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs, y_: ys})
                
    writer.close()
  1. 主函數(shù)。
def main(argv=None): 
    mnist = input_data.read_data_sets("../../datasets/MNIST_data", one_hot=True)
    train(mnist)

if __name__ == '__main__':
    main()

4.運(yùn)行結(jié)果如下圖:


改造后的mnist訓(xùn)練模型輸出

相比前面給出的mnist_train.py程序瞄沙,上面程序最大的改變就是將完成類似功能的計(jì)算放到了由tf.name_scope函數(shù)生成的上下文管理器中己沛。這樣TensorBoard可以將這些節(jié)點(diǎn)有效地合并,從而突出神經(jīng)網(wǎng)絡(luò)的整體結(jié)構(gòu)距境。因?yàn)樵趍nist_inference.py程序中已經(jīng)使用了tf.variable_scope來管理變量的命名空間泛粹,所以這里不需要再做調(diào)整。下圖展示了新的MNIST程序的TensorFlow計(jì)算圖可視化得到的效果圖:


改進(jìn)后的MNIST樣例程序TensorFlow計(jì)算圖可視化效果圖

從圖中可以看到肮疗,TensorBoard可視化效果圖很好地展示了整個神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)晶姊,在圖中,input節(jié)點(diǎn)代表了訓(xùn)練神經(jīng)網(wǎng)絡(luò)需要的輸入數(shù)據(jù)伪货,這些輸入數(shù)據(jù)會提供給神經(jīng)網(wǎng)絡(luò)的第一層layer1.然后神經(jīng)網(wǎng)絡(luò)第一層layer1的結(jié)果會被傳到第二層layer2们衙,經(jīng)過layer2的計(jì)算得到前向傳播的結(jié)果钾怔。loss_function節(jié)點(diǎn)表示計(jì)算損失函數(shù)的過程,這個過程既依賴于前向傳播的結(jié)果來計(jì)算交叉熵(layer2到loss_function的邊)蒙挑,又依賴于每一層中所定義的變量來計(jì)算L2正則化損失(layer1和layer2到loss_function的邊)宗侦。loss_function的計(jì)算結(jié)果會提供給神經(jīng)網(wǎng)絡(luò)的優(yōu)化過程,也就是圖中train_step所代表的節(jié)點(diǎn)忆蚀。綜上所述矾利,通過TensorBoard可視化得到的效果圖可以對整個神經(jīng)網(wǎng)絡(luò)的網(wǎng)絡(luò)結(jié)構(gòu)有一個大致了解。
在圖中可以發(fā)現(xiàn)節(jié)點(diǎn)之間有兩種不同的邊馋袜。一種邊是通過實(shí)線表示的男旗,這種邊刻畫了數(shù)據(jù)傳輸,邊上的箭頭方向表達(dá)了數(shù)據(jù)傳輸?shù)姆较蛐辣睢1热鏻ayer1和layer2之間的邊表示了layer1的輸出將會作為layer2的輸入察皇。有些邊上的箭頭是雙向的,比如節(jié)點(diǎn)Variable和train_step之間的邊泽台。這表明train_step會修改Variable的狀態(tài)什荣,在這里也就是表明訓(xùn)練過程會修改記錄訓(xùn)練迭代輪數(shù)的變量。
TensorBoard可視化效果圖的邊上還標(biāo)注了張量的維度信息怀酷。下圖放大了可視化得到的效果圖:


TensorBoard可視化效果圖中邊上信息

從圖中可以看出稻爬,節(jié)點(diǎn)input和layer1之間傳輸?shù)膹埩康木S度為100*784.這說明了訓(xùn)練時提供的batch大小為100,輸入層節(jié)點(diǎn)的個數(shù)為784.當(dāng)兩個節(jié)點(diǎn)之間傳輸?shù)膹埩慷嘤?個時蜕依,可視化效果圖上將只顯示張量的個數(shù)桅锄。效果圖上邊的粗細(xì)表示的是兩個節(jié)點(diǎn)之間傳輸?shù)臉?biāo)量維度的總大小,而不是傳輸?shù)臉?biāo)量個數(shù)笔横。比如layer2和loss_function之間雖然傳輸了兩個張量,但其維度都比較小咐吼,所以這條邊比layer1和layer2之間的邊還要細(xì)吹缔。
TensorBoard可視化效果圖上另外一種邊是通過虛線表示的,比如圖中所示moving_average和train_step之間的邊锯茄。虛邊表達(dá)了計(jì)算之間的依賴關(guān)系厢塘,比如在程序中,通過tf.control_dependencies函數(shù)指定了更新參數(shù)滑動平均值的操作和通過反方向傳播更新變量的操作需要同時進(jìn)行肌幽,于是moving_average與train_step之間存在一條虛邊晚碾。
除了手動的通過TensorFlow中的命名空間來調(diào)整TensorBoard的可視化效果圖,TensorBoard也會智能地調(diào)整可視化效果圖上的節(jié)點(diǎn)喂急。TensorFlow中部分計(jì)算節(jié)點(diǎn)會有比較多的依賴關(guān)系格嘁,如果全部畫在一張圖上會使可視化得到的效果圖非常擁擠。于是TensorBoard將TensorFlow計(jì)算圖分成了主圖(Main Graph)和輔助圖(Auxiliary nodes)兩個部分來呈現(xiàn)廊移。上面第一個圖中糕簿,左側(cè)展示的是計(jì)算圖的主要部分探入,也就是主圖;右側(cè)展示的是一些單獨(dú)列出來的節(jié)點(diǎn)懂诗,也就是輔助圖蜂嗽。TensorBoard會自動將連接比較多的節(jié)點(diǎn)放在輔助圖中,使得主圖的結(jié)構(gòu)更加清晰殃恒。
除了自動的方式走哺,TensorBoard也支持手工的方式來調(diào)整可視化效果挤茄,如下圖所示:


(a)手工將TensorFlow計(jì)算圖可視化效果圖中節(jié)點(diǎn)移出主圖
(b)手工將TensorFlow計(jì)算圖可視化效果圖中節(jié)點(diǎn)加入主圖

如圖,右鍵單擊可視化效果圖上的節(jié)點(diǎn)會彈出一個選項(xiàng),這個選項(xiàng)可以將節(jié)點(diǎn)加入主圖或者從主圖中刪除谈秫。左鍵選擇一個節(jié)點(diǎn)并點(diǎn)擊信息框下部的選項(xiàng)也可以完成類似的功能。

2.2節(jié)點(diǎn)信息

除了展示TensorFlow計(jì)算圖的結(jié)構(gòu)膝昆,TensorBoard還可以展示TensorFlow計(jì)算圖上每個節(jié)點(diǎn)的基本信息以及運(yùn)行時消耗的時間和空間以清。本小節(jié)將進(jìn)一步講解如何通過TensorBoard展現(xiàn)TensorFlow計(jì)算圖節(jié)點(diǎn)上的這些信息。TensorFlow計(jì)算節(jié)點(diǎn)的運(yùn)行時間都是非常有用的信息贮竟,它可以幫助更加有針對性地優(yōu)化TensorFlow程序丽焊,使得整個程序的運(yùn)行速度更快。使用TensorBoard可以非常直觀地展現(xiàn)所有TensorFlow計(jì)算節(jié)點(diǎn)在某一次運(yùn)行時所消耗的時間和內(nèi)存咕别。將以下代碼加入上一小節(jié)中修改后的mnist_train.py神經(jīng)網(wǎng)絡(luò)訓(xùn)練部分技健,就可以將不同迭代輪數(shù)時每一個TensorFlow計(jì)算節(jié)點(diǎn)的運(yùn)行時間和消耗的內(nèi)存寫入TensorBoard的日志文件中:

# 訓(xùn)練模型惰拱。
    with tf.Session() as sess:
        tf.global_variables_initializer().run()
        for i in range(TRAINING_STEPS):
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            # 每1000輪記錄一次運(yùn)行狀態(tài)
            if i % 1000 == 0:
                # 配置運(yùn)行時需要記錄的信息雌贱。
                run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
                # 運(yùn)行時記錄運(yùn)行信息的proto。
                run_metadata = tf.RunMetadata()
                # 將配置信息和記錄運(yùn)行信息的proto傳入運(yùn)行的過程,從而記錄運(yùn)行時每一個節(jié)點(diǎn)的時間、空間開銷信息
                _, loss_value, step = sess.run(
                    [train_op, loss, global_step], feed_dict={x: xs, y_: ys},
                    options=run_options, run_metadata=run_metadata)
                # 將節(jié)點(diǎn)在運(yùn)行時的信息寫入日志文件
                writer.add_run_metadata(run_metadata=run_metadata, tag=("tag%d" % i), global_step=i)
                print("After %d training step(s), loss on training batch is %g." % (step, loss_value))
            else:
                _, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs, y_: ys})

運(yùn)行以上程序,并使用這個程序輸出的日志啟動TensorBoard,就可以可視化每個TensorFlow計(jì)算節(jié)點(diǎn)在某一次運(yùn)行時所消耗的時間和空間了孝治。進(jìn)入GRAPHS欄后瘩蚪,需要先選擇一次運(yùn)行來查看呢灶。
如下圖所示:


選擇運(yùn)行記錄的頁面

如圖所示奖年,點(diǎn)擊頁面左側(cè)的Session.runs選項(xiàng)會出現(xiàn)一個下拉單,在這個下拉單中會出現(xiàn)所有通過train_writer.add_run_metadata函數(shù)記錄的運(yùn)行數(shù)據(jù)。選擇一次運(yùn)行后祭往,TensorBoard左側(cè)的Color欄中將會新出現(xiàn)Computetime和Memory這兩個選項(xiàng)伦意。
在Color欄中選擇Compute time可以看到在這次運(yùn)行中每個TensorFlow計(jì)算節(jié)點(diǎn)的運(yùn)行時間。類似的硼补,選擇Memory可以看到這次運(yùn)行中每個TensorFlow計(jì)算節(jié)點(diǎn)所消耗的內(nèi)存驮肉。下圖展示了在第2000輪迭代時,不同TensorFlow計(jì)算節(jié)點(diǎn)時間消耗的可視化效果圖:


第2000輪迭代時不同TensorFlow計(jì)算節(jié)點(diǎn)時間消耗的可視化效果圖

上圖中顏色越深的節(jié)點(diǎn)表示時間消耗越大已骇。從圖中可以看出离钝,代表訓(xùn)練神經(jīng)網(wǎng)絡(luò)的train_step節(jié)點(diǎn)消耗的時間是最多的。通過對每一個計(jì)算節(jié)點(diǎn)消耗時間的可視化褪储,可以很容易地找到TensorFlow計(jì)算圖上的性能瓶頸卵渴,這大大方便了算法優(yōu)化的工作。在性能調(diào)優(yōu)時鲤竹,一般會選擇迭代輪數(shù)較大時的數(shù)據(jù)(比如上圖中第2000輪迭代時的數(shù)據(jù))作為不同計(jì)算節(jié)點(diǎn)時間/空間消耗的標(biāo)準(zhǔn)浪读,因?yàn)檫@樣可以減少TensorFlow初始化對性能的影響。
在TensorBoard界面左側(cè)的Color欄中,除了Compute time和Memory碘橘,還有Structure和Device兩個選項(xiàng)互订。除了上一圖,在上面幾個圖中痘拆,展示的可視化效果圖都是使用默認(rèn)的Structure選項(xiàng)仰禽。在這個視圖中,灰色的節(jié)點(diǎn)表示沒有其他節(jié)點(diǎn)和它擁有相同結(jié)構(gòu)纺蛆。如果有兩個節(jié)點(diǎn)的結(jié)構(gòu)相同坟瓢,那么它們會被涂上相同的顏色。下圖展示了一個擁有相同結(jié)構(gòu)節(jié)點(diǎn)的卷積神經(jīng)網(wǎng)絡(luò)可視化得到的效果圖:
有相同結(jié)構(gòu)節(jié)點(diǎn)的卷積神經(jīng)網(wǎng)絡(luò)計(jì)算圖在Structure選項(xiàng)下的可視化效果圖

在上圖中犹撒,兩個卷積層的結(jié)構(gòu)是一樣的折联,所以他們都被涂上了相同的顏色。最后识颊,Color欄還可以選擇Device選項(xiàng)诚镰,這個選項(xiàng)可以根據(jù)TensorFlow計(jì)算節(jié)點(diǎn)運(yùn)行的機(jī)器給可視化效果圖上的節(jié)點(diǎn)染色。在使用GPU時祥款,可以通過這種方式直觀地看到哪些計(jì)算節(jié)點(diǎn)被放到了GPU上清笨。下圖給出了一個使用了GPU的TensorFlow計(jì)算圖的可視化效果:


使用了GPU的TensorFlow計(jì)算圖的可視化結(jié)果

上圖中深灰色的節(jié)點(diǎn)表示對應(yīng)的計(jì)算放在了GPU上,淺灰色的節(jié)點(diǎn)表示對應(yīng)的計(jì)算放在了CPU上刃跛。具體如何使用GPU將在下一章介紹抠艾。
當(dāng)點(diǎn)擊TensorBoard可視化效果圖中的節(jié)點(diǎn)時,界面的右上角會彈出一個信息卡片顯示這個節(jié)點(diǎn)的基本信息桨昙,如下圖:
TensorFlow命名空間在TensorBoard可視化效果圖上的信息卡片

當(dāng)點(diǎn)擊的節(jié)點(diǎn)為一個命名空間時检号,TensorBoard展示的信息有這個命名空間內(nèi)所有計(jì)算節(jié)點(diǎn)的輸入、輸出以及依賴關(guān)系蛙酪。雖然屬性(Attribute)也會展示在卡片中齐苛,但是在代表命名空間的屬性下不會有任何內(nèi)容。當(dāng)Session.runs選擇了某一次運(yùn)行時桂塞,節(jié)點(diǎn)的信息卡片上會出現(xiàn)這個節(jié)點(diǎn)運(yùn)行所消耗的時間和內(nèi)存等信息凹蜂。
當(dāng)點(diǎn)擊的TensorBoard可視化效果圖上的節(jié)點(diǎn)對應(yīng)一個TensorFlow計(jì)算節(jié)點(diǎn)時,TensorBoard也會展示類似的信息阁危。下圖展示了一個TensorFlow計(jì)算節(jié)點(diǎn)所對應(yīng)的信息卡片:
TensorFlow計(jì)算節(jié)點(diǎn)在TensorBoard可視化效果圖上的信息卡片

3.監(jiān)控指標(biāo)可視化

在上一節(jié)中著重介紹了通過TensorBoard的GRAPHS欄可視化TensorFlow計(jì)算圖的結(jié)構(gòu)以及在計(jì)算圖上的信息玛痊。TensorBoard除了可以可視化TensorFlow的計(jì)算圖,還可以可視化TensorFlow程序運(yùn)行過程中各種有助于了解程序運(yùn)行狀態(tài)的監(jiān)控指標(biāo)狂打。在本節(jié)中將介紹如何利用TensorBoard中其他欄目可視化這些監(jiān)控指標(biāo)擂煞。除了Graphs欄,TensorBoard界面中還提供了EVENTS/IMAGES/AUDIO和HISTOGRAMS四個欄目來可視化其他的監(jiān)控指標(biāo)菱父。下面的程序展示了如何將TensorFlow程序運(yùn)行時的信息輸出到TensorBoard日志文件中:
1.定義變量

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

2.生成變量監(jiān)控信息并定義生成監(jiān)控信息日志的操作颈娜。

SUMMARY_DIR = "C:/log/supervisor.log"
BATCH_SIZE = 100
TRAIN_STEPS = 3000

# var:需要記錄的張量
# name:可視化結(jié)果中顯示的圖表名稱,這個名稱一般與變量名一致
def variable_summaries(var, name):
    # 將生成監(jiān)控信息的操作放到同一個命名空間下
    with tf.name_scope('summaries'):
        # tf.summary.histogram:記錄張量中元素的取值分布
        tf.summary.histogram(name, var)
        # 計(jì)算變量的平均值
        mean = tf.reduce_mean(var)
        tf.summary.scalar('mean/' + name, mean)
        # 計(jì)算變量的標(biāo)準(zhǔn)差
        stddev = tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
        tf.summary.scalar('stddev/' + name, stddev) 

3.生成一層全鏈接的神經(jīng)網(wǎng)絡(luò)

def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu):
    # 將同一層神經(jīng)網(wǎng)絡(luò)放在一個統(tǒng)一的命名空間下
    with tf.name_scope(layer_name):
        # 聲明神經(jīng)網(wǎng)絡(luò)邊上的權(quán)重浙宜,并調(diào)用生成權(quán)重監(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)絡(luò)的偏置項(xiàng)官辽,并調(diào)用生成偏置項(xià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)絡(luò)輸出節(jié)點(diǎn)在經(jīng)過激活函數(shù)之前的分布
            tf.summary.histogram(layer_name + '/pre_activations', preactivate)
        activations = act(preactivate, name='activation')        
        
        # 記錄神經(jīng)網(wǎng)絡(luò)節(jié)點(diǎn)輸出在經(jīng)過激活函數(shù)之后的分布。
        tf.summary.histogram(layer_name + '/activations', activations)
        return activations

def main():
    mnist = input_data.read_data_sets("../../datasets/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')
    # 將輸入向量還原成圖片的像素矩陣粟瞬,并通過tf.summary.image將當(dāng)前的圖片信息寫入日志的操作
    with tf.name_scope('input_reshape'):
        image_shaped_input = tf.reshape(x, [-1, 28, 28, 1])
        tf.summary.image('input', image_shaped_input, 10)

    hidden1 = nn_layer(x, 784, 500, 'layer1')
    y = nn_layer(hidden1, 500, 10, 'layer2', act=tf.identity)
    # 計(jì)算交叉熵并定義生成交叉熵監(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)
    # 計(jì)算模型在當(dāng)前給定數(shù)據(jù)上的正確率
    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.summary.merge_all:整理所有的日志生成操作
    merged = tf.summary.merge_all()

    with tf.Session() as sess:
        # 初始化寫日志的writer同仆,并將當(dāng)前TensorFlow計(jì)算圖寫入日志
        summary_writer = tf.summary.FileWriter(SUMMARY_DIR, sess.graph)
        tf.global_variables_initializer().run()

        for i in range(TRAIN_STEPS):
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            # 運(yùn)行訓(xùn)練步驟以及所有的日志生成操作,得到這次運(yùn)行的日志裙品。
            summary, _ = sess.run([merged, train_step], feed_dict={x: xs, y_: ys})
            # 將得到的所有日志寫入日志文件俗批,這樣TensorBoard程序就可以拿到這次運(yùn)行所對應(yīng)的
            # 運(yùn)行信息。
            summary_writer.add_summary(summary, i)

    summary_writer.close()

if __name__ == '__main__':
    main()

運(yùn)行代碼市怎,如下圖所示:

程序運(yùn)行過程

運(yùn)行完之后岁忘,在C:/log/supervisor.log目錄,會發(fā)現(xiàn)有個文件events.out.tfevents.1567588311.1002330QL区匠,在命令行執(zhí)行命令:
tensorboard --logdir=C:/log/supervisor.log
再到瀏覽器訪問:http://localhost:6006
可以得到如下圖所示的結(jié)果:
監(jiān)控指標(biāo)可視化的程序運(yùn)行的日志可視化

從程序中可以看出干像,除了GRSPHS之外,TensorBoard中的每一欄對應(yīng)了TensorFlow中一種日志生成函數(shù)驰弄,下表總結(jié)了這個對應(yīng)關(guān)系:
TensorFlow日志生成函數(shù)與TensorBoard界面欄對應(yīng)關(guān)系

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麻汰,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子戚篙,更是在濱河造成了極大的恐慌五鲫,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件岔擂,死亡現(xiàn)場離奇詭異位喂,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)乱灵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門忆某,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人阔蛉,你說我怎么就攤上這事弃舒。” “怎么了状原?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵聋呢,是天一觀的道長。 經(jīng)常有香客問我颠区,道長削锰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任毕莱,我火速辦了婚禮器贩,結(jié)果婚禮上颅夺,老公的妹妹穿的比我還像新娘。我一直安慰自己蛹稍,他們只是感情好吧黄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著唆姐,像睡著了一般拗慨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上奉芦,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天赵抢,我揣著相機(jī)與錄音,去河邊找鬼声功。 笑死烦却,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的先巴。 我是一名探鬼主播短绸,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼筹裕!你這毒婦竟也來了醋闭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤朝卒,失蹤者是張志新(化名)和其女友劉穎证逻,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抗斤,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡囚企,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了瑞眼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片龙宏。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖伤疙,靈堂內(nèi)的尸體忽然破棺而出银酗,到底是詐尸還是另有隱情,我是刑警寧澤徒像,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布黍特,位于F島的核電站,受9級特大地震影響锯蛀,放射性物質(zhì)發(fā)生泄漏灭衷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一旁涤、第九天 我趴在偏房一處隱蔽的房頂上張望翔曲。 院中可真熱鬧迫像,春花似錦、人聲如沸瞳遍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽傅蹂。三九已至,卻和暖如春算凿,著一層夾襖步出監(jiān)牢的瞬間份蝴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工氓轰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留婚夫,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓署鸡,卻偏偏與公主長得像案糙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子靴庆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容