深入理解TensorFlow變量

本文主要講解以下語法的區(qū)別:

  • tf.Variable
  • tf.get_variable
  • tf.variable_scope(<scope_name>)
  • tf.name_scope(<scope_name>)

創(chuàng)建變量

變量通過tf.Variable類來操縱,可以通過實(shí)例化tf.Variable來創(chuàng)建變量,比如a = tf.Variable([1.0], name='a')。不過官方推薦的最佳創(chuàng)建方式是通過調(diào)用tf.get_variable來隱式的創(chuàng)建,這個函數(shù)要求你指定變量的名稱,這個名稱將作為副本用于訪問相同的變量,以及在檢查點(diǎn)和導(dǎo)出模型時命名次變量的值。tf.get_variable還允許你重復(fù)使用先前創(chuàng)建的同名變量,從而輕松定義復(fù)用層的模型。而直接通過tf.Variable來創(chuàng)建變量的話無論什么時候都會創(chuàng)建新的變量。

下面通過官方文檔中的幾個例子來說明。

創(chuàng)建一個形狀是[1,2,3]名稱為my_variable的變量,默認(rèn)數(shù)據(jù)類型是tf.float32,并且默認(rèn)數(shù)值將通過tf.glorot_uniform_initializer被隨機(jī)初始化。

my_variable = tf.get_variable("my_variable", [1, 2, 3])

我們可以自己指定數(shù)據(jù)的類型和初始化器。TensorFlow提供了很多的初始化器(這個自己看api文檔),還可以直接指定初始值,像這個樣子:

my_int_variable = tf.get_variable("my_int_variable", [1, 2, 3], dtype=tf.int32, 
  initializer=tf.zeros_initializer)
other_variable = tf.get_variable("other_variable", dtype=tf.int32, 
  initializer=tf.constant([23, 42]))

變量集合

默認(rèn)情況下,每個tf.Variable被放置在以下兩個集合中:

tf.GraphKeys.GLOBAL_VARIABLES -- 能在多設(shè)備上共享

tf.GraphKeys.TRAINABLE_VARIABLES -- 會計(jì)算梯度的變量

如果你希望某個變量不要被訓(xùn)練,那可以放在這個集合里:tf.GraphKeys.LOCAL_VARIABLES

比如這樣:

my_local = tf.get_variable("my_local", shape=(), 
collections=[tf.GraphKeys.LOCAL_VARIABLES])

或者這樣,添加trainableFalse

my_non_trainable = tf.get_variable("my_non_trainable", shape=(), trainable=False)

當(dāng)然也可以創(chuàng)建自己的集合,像這樣:

添加my_loacl變量到my_collection_name集合

tf.add_to_collection("my_collection_name", my_local)

取出集合中的變量list:

tf.get_collection("my_collection_name")

共享變量

我們在構(gòu)造一些網(wǎng)絡(luò)的時候,可能會遇到一個層多次利用或多個輸入使用同一個層的情況,這種時候就需要重復(fù)利用同一套權(quán)重變量,不然就無法達(dá)到預(yù)期的效果,這個時候就可以通過變量作用域tf.variable_scope()tf.get_variable配合來實(shí)現(xiàn),下面繼續(xù)拿官方文檔上的例子來做說明。

例如,我們通過便編寫一個函數(shù)來創(chuàng)建卷積層:

def conv_relu(input, kernel_shape, bias_shape):
    # Create variable named "weights".
    weights = tf.get_variable("weights", kernel_shape,
        initializer=tf.random_normal_initializer())
    # Create variable named "biases".
    biases = tf.get_variable("biases", bias_shape,
        initializer=tf.constant_initializer(0.0))
    conv = tf.nn.conv2d(input, weights,
        strides=[1, 1, 1, 1], padding='SAME')
    return tf.nn.relu(conv + biases)

在我們的真實(shí)模型中,有兩個輸入需要使用同一個卷積,于是你可能會想這么做:

input1 = tf.random_normal([1,10,10,32])
input2 = tf.random_normal([1,20,20,32])
x = conv_relu(input1, kernel_shape=[5, 5, 32, 32], bias_shape=[32])
x = conv_relu(x, kernel_shape=[5, 5, 32, 32], bias_shape = [32])  # This fails.

但是你很快就會發(fā)現(xiàn),這是行不通的,第一次調(diào)用函數(shù)的時候就已經(jīng)創(chuàng)建了weightsbiases變量,第二次調(diào)用的時候變量名稱已經(jīng)存在,所以就無法再使用這兩個名稱了,而如果要復(fù)用與第一次想通的變量,就需要使用變量作用域,并且聲明重復(fù)使用變量,像下面這樣操作:(設(shè)置reuse=True

with tf.variable_scope("model"):
  output1 = my_image_filter(input1)
with tf.variable_scope("model", reuse=True):
  output2 = my_image_filter(input2)

或者:(設(shè)置scope.reuse_variables())

with tf.variable_scope("model") as scope:
  output1 = my_image_filter(input1)
  scope.reuse_variables()
  output2 = my_image_filter(input2)

當(dāng)然,我們可能遇到的更多情況是模型中有多次卷積操作,并且使用不同的變量,于是我們可以定義不同的變量作用域來實(shí)現(xiàn):

def my_image_filter(input_images):
    with tf.variable_scope("conv1"):
        # Variables created here will be named "conv1/weights", "conv1/biases".
        relu1 = conv_relu(input_images, [5, 5, 32, 32], [32])
    with tf.variable_scope("conv2"):
        # Variables created here will be named "conv2/weights", "conv2/biases".
        return conv_relu(relu1, [5, 5, 32, 32], [32])

或者使用tf.Variable,這樣每次調(diào)用conv_relu都會創(chuàng)建出不同的變量。

而名稱作用域tf.name_scope并不會對tf.get_variable產(chǎn)生影響,只會對tf.Variable之類的其他的命名操作增加一個名稱范圍前綴。下面做個演示:

with tf.variable_scope("conv1"):
    a = tf.Variable([1.0], name='a')
with tf.variable_scope("conv2"):
    b = tf.Variable([1.0], name='a')
print(a)
print(b)
# 輸出:
# <tf.Variable 'conv1/a:0' shape=(1,) dtype=float32_ref>
# <tf.Variable 'conv2/a:0' shape=(1,) dtype=float32_ref>

with tf.variable_scope("conv1"):
    a = tf.get_variable('a', [1])
with tf.variable_scope("conv2"):
    b = tf.get_variable('a', [1])
print(a)
print(b)
# 輸出
# <tf.Variable 'conv1/a:0' shape=(1,) dtype=float32_ref>
# <tf.Variable 'conv2/a:0' shape=(1,) dtype=float32_ref>

with tf.variable_scope("conv1"):
    a = tf.get_variable('a', [1])
with tf.variable_scope("conv1"):
    b = tf.get_variable('a', [1])
print(a)
print(b)
# 報(bào)錯
# ValueError: Variable conv1/a already exists, disallowed. Did you mean to set reuse=True in 
# VarScope? Originally defined at:

with tf.variable_scope("conv1"):
    a = tf.get_variable('a', [1])
with tf.variable_scope("conv1", reuse=True):
    b = tf.get_variable('a', [1])
print(a)
print(b)
# 輸出
# <tf.Variable 'conv1/a:0' shape=(1,) dtype=float32_ref>
# <tf.Variable 'conv1/a:0' shape=(1,) dtype=float32_ref>

with tf.name_scope("conv1"):
    a = tf.get_variable('a', [1])
with tf.name_scope("conv2"):
    b = tf.get_variable('a', [1])
print(a)
print(b)
# 報(bào)錯
# ValueError: Variable a already exists, disallowed. Did you mean to set reuse=True in VarScope? Originally defined at:

with tf.name_scope("conv1"):
    a = tf.get_variable('a', [1])
print(a)
# 輸出 (可以看出名稱域?qū)λ鼪]有影響)
# <tf.Variable 'a:0' shape=(1,) dtype=float32_ref>

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

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

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