Tensorflow 之 name/variable_scope 的使用
-
name/variable_scope 的作用
-
充分理解 name / variable_scope
-
TensorFlow 入門筆記
-
* name_scope: * 為了更好地管理變量的命名空間而提出的。比如在 tensorboard 中,因為引入了 name_scope, 我們的 Graph 看起來才井然有序。
-
* variable_scope: * 大大大部分情況下,跟 tf.get_variable() 配合使用,實現變量共享的功能。
2.三種方式創建變量: tf.placeholder, tf.Variable, tf.get_variable
從上面的實驗結果來看,這三種方式所定義的變量具有相同的類型。而且只有 tf.get_variable() 創建的變量之間會發生命名沖突。在實際使用中,三種創建變量方式的用途也是分工非常明確的。其中
- tf.placeholder() 占位符。* trainable==False *
- tf.Variable() 一般變量用這種方式定義。 * 可以選擇 trainable 類型 *
- tf.get_variable() 一般都是和 tf.variable_scope() 配合使用,從而實現變量共享的功能。 * 可以選擇 trainable 類型 *
3. 探索 name_scope 和 variable_scope
tf.name_scope() 並不會對 tf.get_variable() 創建的變量有任何影響。
tf.name_scope() 主要是用來管理命名空間的,這樣子讓我們的整個模型更加有條理。而 tf.variable_scope() 的作用是為了實現變量共享,它和 tf.get_variable() 來完成變量共享的功能。
- 首先我們要確立一種 Graph 的思想。在 TensorFlow 中,我們定義一個變量,相當於往 Graph 中添加了一個節點。和普通的 python 函數不一樣,在一般的函數中,我們對輸入進行處理,然後返回一個結果,而函數裏邊定義的一些局部變量我們就不管了。但是在 TensorFlow 中,我們在函數裏邊創建了一個變量,就是往 Graph 中添加了一個節點。出了這個函數後,這個節點還是存在於 Graph 中的。
共享變量
TensorFlow 支持兩種共享變量的方式:
- 顯式傳遞
tf.Variable
對象。 - 在
tf.variable_scope
對象內隱式包裝tf.Variable
對象。
雖然顯式傳遞變量的代碼非常清晰,但有時編寫 TensorFlow 函數(在實現中隱式使用變量)非常方便。tf.layer
中的大多數功能層以及所有 tf.metrics
和部分其他庫工具都使用這種方法。
變量作用域允許您在調用隱式創建和使用變量的函數時控制變量重用。作用域還允許您以分層和可理解的方式命名變量。
例如,假設我們編寫一個函數來創建一個卷積/relu 層:
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)
此函數使用短名稱 weights
和 biases
,這有利於清晰區分二者。然而,在真實模型中,我們需要很多此類卷積層,而且重復調用此函數將不起作用:
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.
由於期望的操作不清楚(創建新變量還是重新使用現有變量?),因此 TensorFlow 將會失敗。不過,在不同作用域內調用 conv_relu
可表明我們想要創建新變量:
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])
如果您想要共享變量,有兩種方法可供選擇。首先,您可以使用 reuse=True
創建具有相同名稱的作用域:
with tf.variable_scope("model"):
output1 = my_image_filter(input1)
with tf.variable_scope("model", reuse=True):
output2 = my_image_filter(input2)
您也可以調用 scope.reuse_variables()
以觸發重用:
with tf.variable_scope("model") as scope:
output1 = my_image_filter(input1)
scope.reuse_variables()
output2 = my_image_filter(input2)
由於根據作用域的具體字符串名稱初始化變量作用域可能比較危險,因此也可以根據另一作用域進行初始化:
with tf.variable_scope("model") as scope:
output1 = my_image_filter(input1)
with tf.variable_scope(scope, reuse=True):
output2 = my_image_filter(input2)
Tensorflow 之 name/variable_scope 的使用