Tensorflow命名空間與計算圖可視化


Tensorflow命名空間與計算圖可視化

覺得有用的話,歡迎一起討論相互學習~

我的微博我的github我的B站

參考文獻
強烈推薦Tensorflow實戰Google深度學習框架
實驗平台:
Tensorflow1.4.0
python3.5.0

  • Tensorflow可視化得到的圖並不僅是將Tensorflow計算圖中的節點和邊直接可視化,它會根據每個Tensorflow計算節點的命名空間來整理可視化得到效果圖,使得神經網絡的整體結構不會被過多的細節所淹沒。除了顯示Tensorflow計算圖的結構,Tensorflow還可以展示Tensorflow計算節點上的信息進行描述統計,包括頻數統計和分布統計。
  • 為了更好的組織可視化效果圖中的計算節點,Tensorboard支持通過Tensorflow命名空間來整理可視化效果圖上的節點。在Tensorboard的默認視圖中,Tensorflow計算圖中同一個命名空間下的所有節點會被縮略為一個節點,而頂層命名空間的節點才會被顯示在Tensorboard可視化效果圖中。

tf.variable_scope和tf.name_scope函數區別

  • tf.variable_scope和tf.name_scope函數都提供了命名變量管理的功能,這兩個函數在大部分情況下是等價的,唯一的區別在於使用tf.get_variable函數時:
import tensorflow as tf
# 不同的命名空間
with tf.variable_scope("foo"):
    # 在命名空間foo下獲取變量"bar",於是得到的變量名稱為"foo/bar"
    a = tf.get_variable("bar", [1])
    print(a.name)
    # foo/bar:0
with tf.variable_scope("bar"):
    # 在命名空間bar下獲取變量"bar",於是得到的變量名稱為"bar/bar".此時變量在"bar/bar"和變量"foo/bar"並不沖突,於是可以正常運行
    b = tf.get_variable("bar", [1])
    print(b.name)
    # bar/bar:0
#  tf.Variable和tf.get_variable的區別。

with tf.name_scope("a"):
    # 使用tf.Variable函數生成變量時會受到tf.name_scope影響,於是這個變量的名稱為"a/Variable"
    a = tf.Variable([1])
    print(a.name)
    # a/Variable: 0

    # tf.get_variable函數不受頭tf.name_scope函數的影響,於是變量並不在a這個命名空間中
    a = tf.get_variable("b", [1])
    print(a.name)
    # b:0

# with tf.name_scope("b"):
    # 因為tf.get_variable不受tf.name_scope影響,所以這里將試圖獲取名稱為"a"的變量。然而這個變量已經被聲明了,於是這里會報重復聲明的錯誤。
    # tf.get_variable("b",[1])
  • 通過對變量命名空間進行管理,使用Tensorboard查看模型的結構時更加清晰
import tensorflow as tf
with tf.name_scope("input1"):
    input1 = tf.constant([1.0, 2.0, 3.0], name="input2")
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("log/simple_example.log", tf.get_default_graph())
writer.close()
  • 這樣程序中定義的加法運算都被清晰的展示出來,並且變量初始化等基本操作都被折疊起來。

Tensorboard展示圖片

  • 點擊input2上的加號按鈕,能夠看到關於input2變量初始化的全過程。

input2節點操作

可視化MNIST程序

MNIST基本程序

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
# mnist_inference中定義的常量和前向傳播的函數不需要改變,因為前向傳播已經通過
# tf.variable_scope實現了計算節點按照網絡結構的划分
import mnist_inference

# #### 1. 定義神經網絡的參數。
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


# #### 2. 定義訓練的過程並保存TensorBoard的log文件。
def train(mnist):
    #  將處理輸入數據的計算都放在名字為"input"的命名空間中
    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)

    # 將處理滑動平均相關的計算都放在名為moving average 的命名空間下。
    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())  # 對可訓練變量集合使用滑動平均

    # 將計算損失函數相關的計算都放在名為loss function 的命名空間下。
    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'))

    # 將定義學習率、優化方法以及每一輪訓練需要執行的操作都放在名字為"train_step"的命名空間下。
    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')
    # 將結果記錄進log文件夾中
    writer = tf.summary.FileWriter("log", tf.get_default_graph())

    # 訓練模型。
    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:
                # 配置運行時需要記錄的信息。
                run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)
                # 運行時記錄運行信息的proto。
                run_metadata = tf.RunMetadata()
                # 將配置信息和記錄運行信息的proto傳入運行的過程,從而記錄運行時每一個節點的時間空間開銷信息
                _, 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()


# #### 3. 主函數。
def main(argv=None):
    mnist = input_data.read_data_sets("../../datasets/MNIST_data", one_hot=True)
    train(mnist)


if __name__ == '__main__':
    main()

可視化效果圖

  • input節點代表了訓練神經網絡需要的輸入數據,這些輸入數據會提供給神經網絡的第一層layer1.然后神經網絡第一層layerl的結果會被傳到第二層layer2,經過layer2的計算得到前向傳播的結果.loss function節點表示計算損失函數的過程,這個過程既依賴於前向傳播的結果來計算交叉熵(layer2到loss_function的邊,又依賴於每一層中所定義的變量來計算L2 正則化損失(layer1和layer2到loss_function的邊).loss_function 的計算結果會提供給神經網絡的優化過程,也就是圖中位train_step 所代表的節點。

  • 發現節點之間有兩種不同的邊。一種邊是通過實線表示的,這種邊刻畫了數據傳輸,邊上箭頭方向表達了數據傳輸的方向。比如layerl和layer2之間的邊表示了layer1的輸出將會作為layer2的輸入。TensorBoard 可視化效果圖的邊上還標注了張量的維度信息。

  • 從圖中可以看出,節點input和layer1之間傳輸的張量的維度為*784。這說明了訓練時提供的batch大小不是固定的(也就是定義的時候是None),輸入層節點的個數為784。當兩個節點之間傳輸的張量多於1時,可視化效果圖上將只顯示張量的個數。效果圖上邊的粗細表示的是兩個節點之間傳輸的標量維度的總大小,而不是傳輸的標量個數。比如layer2和train_step之間雖然傳輸了6個張量,但其維度都比較小,所以這條邊比layerl和moving_average之間的邊(只傳輸了4個張量〉還要細。當張量的維度無法確定時,TensorBoard會使用最細的邊來表示。比如layer1與layer2之間的邊。

  • Tensor Board可視化效果圖上另外一種邊是通過虛線表示的,比如圖中所示的moving_ average 和train_step 之間的邊.虛邊表達了計算之間的依賴關系,比如在程序中,通過tf.control_dependencies函數指定了更新參數滑動平均值的操作和通過反向傳播更新變量的操作需要同時進行,於是moving_average 與train_step 之間存在一條虛邊.

  • 除了手動的通過TensorFlow中的命名空間來調整TensorBoard的可視化效果圖,TensorBoard也會智能地調整可視化效果圖上的節點.TensorFlow中部分計算節點會有比較多的依賴關系,如果全部畫在一張圖上會便可視化得到的效果圖非常擁擠.於是TensorBoard將TensorFlow計算圖分成了主圖(Main Graph)和輔助圖(Auxiliary nodes)兩個部分來呈現。TensorBoard 會自動將連接比較多的節點放在輔助圖中,使得主圖的結構更加清晰。

  • 除了自動的方式,TensorBoard也支持手工的方式來調整可視化結果。右鍵單擊可視化效果圖上的節點會彈出一個選項,這個選項可以將節點加入主圖或者從主圖中刪除。左鍵選擇一個節點並點擊信息框下部的選項也可以完成類似的功能。注意TensorBoard 不會保存用戶對計算圖可視化結果的手工修改,頁面刷新之后計算圖可視化結果又會回到最初的樣子。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM