1. 程式人生 > >Tensorflow 變數機制

Tensorflow 變數機制

最近一直在跟著《TensorFlow:實戰google深度學習框架》學習Tensorflow,學到第5.3節變數管理以及5.4節模型持久化的時候忽然發現基礎好像學的還是不夠紮實,被變數的使用搞得一臉懵逼。書中講的還是很詳細的,我針對一些有疑問的定義進行了實驗,這裡總結一下。

問題1:tf.Variable中不指定name引數會怎樣?

執行以下程式

a=tf.Variable(tf.constant(1.0,shape=[1]))
b=tf.Variable(tf.constant(1.0,shape=[1]))
print(a)
print(b)

輸出

<tf.Variable 'Variable:0' shape=(1,) dtype=float32_ref>
<tf.Variable 'Variable_1:0' shape=(1,) dtype=float32_ref>

可見程式中a定義的第一個變數被自動命名為Variable,由於重名而把b定義的第二個變數自動命名為Variable_1

補充:tf.get_variable的name引數是不能重名的

執行以下程式

a = tf.get_variable(name='a1',shape=[1,2])
b = tf.get_variable(name='a1',shape=[3,4])
print(a)
print(b)

報瞭如下錯

ValueError: Variable a1 already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope?

因此在使用tf.get_variable要注意name引數是不能相同的

問題2:變數名指的究竟是什麼?

a = tf.get_variable( 'b' , [1] , initializer = tf.constant_initializer(1.0) ) 

該語句定義了一個名為“b”的節點,並且書中的變數名指的也應該是‘b’(即tf.Variable中的name引數)

print(a)後輸出Tensor("b:0", shape=(2,), dtype=float32),其中“b:0”表示該張量計算節點“b”輸出的第一個結果

print(a.name)後輸出b:0

注:tf.get_variable與tf.Variable最大不同就是tf.get_variable中name引數是一個必填的引數,而在tf.Variable中是可選的。tf.get_variable就是根據這一引數來建立和命名變數

那麼該語句中的a是指什麼呢?

執行下面兩個程式

code1

a = tf.get_variable(name='a1',shape=[1,2])
a = tf.get_variable(name='a1',shape=[1,2])
print(a)

code2

a=tf.Variable(tf.constant(1.0,shape=[1]))
a=tf.Variable(tf.constant(1.0,shape=[1]))
print(a)

code1的執行結果為

ValueError: Variable a1 already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope?

code2的執行結果為

<tf.Variable 'Variable_1:0' shape=(1,) dtype=float32_ref>

通過上述兩個程式比較,可以看出,每個程式中相同語句執行了兩次,因此可以將這個‘a’理解為用來指代程式中操作的結果的標識(也就是python中的變數名指向了一個新的記憶體地址)(此處有問題可能是混淆了C與python變數名的意義,可以參考https://www.jianshu.com/p/3289be65c76d

問題3:tf.variable_scope的作用範圍?

一開始我對tf.variable_scope的理解有問題,所有對以下程式碼有個疑惑,就是為什麼在scope('layer2')中也可以直接用在scope('layer1')中定義的layer1

#訓練時會建立變數,測試時會通過儲存的模型載入變數v          
def get_weight_variable(shape,regularizer):                           
weights=tf.get_variable("weights",shape,initializer=tf.truncated_normal_initializer(stddev=0.1))
    if regularizer !=None :
        #將張量加入自定義集合losses中
        tf.add_to_collection('losses',regularizer(weights))
    return weights

#dnn前向傳播
def inference(input_tensor,regularizer):
    #第一層變數
    with tf.variable_scope('layer1'):
        weights=get_weight_variable([INPUT_NODE,LAYER1_NODE],regularizer)
        biases=tf.get_variable("biases",[LAYER1_NODE],initializer=tf.constant_initializer(0.0))
        layer1=tf.nn.relu(tf.matmul(input_tensor,weights)+biases)

    #第二層變數
    with tf.variable_scope('layer2'):
        weights=get_weight_variable([LAYER1_NODE,OUTPUT_NODE],regularizer)
        biases=tf.get_variable("biases",[OUTPUT_NODE],initializer=tf.constant_initializer(0.0))
        layer2=tf.nn.relu(tf.matmul(layer1,weights)+biases)

因為scope只對name引數中的變數名起作用而不對程式中定義的變數名起作用,程式中定義的變數名仍是起到一個指示的作用。這裡tf.variable_scope('XXX')語句是用來在name引數指定的變數名前新增名稱空間的,可以將每次執行 with tf.variable_scope('XXX'):理解為打開了一個名為XXX的資料夾(variable_scope的名稱空間也可以巢狀,類似絕對地址)

下列兩個程式碼執行結果是一樣的

with tf.variable_scope('layer1'):
    biases=tf.get_variable("biases1",[1],initializer=tf.constant_initializer(0.0))

with tf.variable_scope('layer2'):
    biases=tf.get_variable("biases2",[1],initializer=tf.constant_initializer(0.0))

print(biases.name)
with tf.variable_scope('layer1'):
    biases=tf.get_variable("biases1",[1],initializer=tf.constant_initializer(0.0))

with tf.variable_scope('layer2'):
    biases=tf.get_variable("biases2",[1],initializer=tf.constant_initializer(0.0))
    print(biases.name)

均為

layer2/biases2:0

(還是對python中變數名理解的問題T T)

問題4:儲存或載入指定變數時,tf.train.saver列表中提供的變數是哪一個?

如在載入模型時只加載一個變數則應該使用如下程式碼定義一個Saver類

saver=tf.train.Saver([v1])

那麼這個v1到底是name引數還是程式中定義的變數名呢

分別執行以下兩段程式碼(只聲明瞭一個Saver類,沒有執行具體操作的程式碼)

code1

v=tf.Variable(tf.constant(1.0,shape=[1]),name='v1')
saver=tf.train.Saver([v1])

code2

v1=tf.Variable(tf.constant(1.0,shape=[1]),name='v')
saver=tf.train.Saver([v1])

code1報錯如下錯,而code2可以執行

NameError: name 'v1' is not defined

因此列表中指定的變數應該是在程式中定義的變數,此時可以將它當做普通python程式理解,畢竟只有程式中定義了的變數才能被列表使用

問題5:tf.train.Saver在儲存或者載入變數時給變數重新命名,字典中的key-value分別對應什麼?

如在儲存模型時為v1,v2重新命名,則應該使用如下程式碼定義一個Saver類

那這個字典中key,value是什麼含義呢?繼續做一個實驗。

首先執行了

a=tf.Variable(tf.constant(1.0,shape=[1]),name='a1')
saver=tf.train.Saver({"a":a2})

報錯

NameError: name 'a2' is not defined

這說明key應該是這個變數被重新命名的名稱,value應該是a或者a1,根據問題4我們可以推測value應該是a(在程式中定義了的變數)

接著執行

a=tf.Variable(tf.constant(1.0,shape=[1]),name='a1')
saver=tf.train.Saver({"a2":a})

程式沒有報錯,說明value應該對應程式中定義了的變數,為了證明使用name引數作為value是錯誤的,再執行以下程式

a=tf.Variable(tf.constant(1.0,shape=[1]),name='a1')
saver=tf.train.Saver({"a2":a1})

程式報錯

NameError: name 'a1' is not defined

綜上所述,定義用來重新命名的Saver類時,使用的字典的key應該是希望重新命名成什麼名,value是程式中定義的變數