Variables變量用于共享、持久化狀態管理。
tf.Variable
表示此數值在計算過程中可能會變化,它獨立于sess.run
上下文存在。因此我們可以在sessionA中利用ops操作改變這個變量,進而在sessionB中使用這個變量,以此達到傳遞共享數值的目的。
創建變量
使用tf.get_variable(name,shape,dtype,initializer)
創建變量。
如果設定了初initializer初始化函數返回明確的值,那么不能同時使用shape參數,否則必須指定shape。
import tensorflow as tf
sess=tf.Session()
v1 = tf.get_variable("v1", [1, 2, 3]) #隨機0~1之間
v2 = tf.get_variable("v2", [1, 2, 3],initializer=tf.zeros_initializer) #全0
v3 = tf.get_variable("v3", dtype=tf.int32,initializer=tf.constant([23, 42])) #不能同時設定shape!
init=tf.global_variables_initializer()
sess.run(init)
print(sess.run(v1))
print(sess.run(v2))
print(sess.run(v3))
打印結果
[[[-0.8628024 0.6660923 0.8403772 ]
[-0.5985474 -0.073349 0.23826087]]]
[[[0. 0. 0.]
[0. 0. 0.]]]
[23 42]
變量集合Variable collections
將一組變量放入集合進行管理
import tensorflow as tf
sess=tf.Session()
v1 = tf.get_variable("v1", [1, 2, 3])
tf.add_to_collection("mycollection", v1) #將v1放入名稱為mycollection的集合
mycollection=tf.get_collection("mycollection")
print(mycollection) #一個列表
init=tf.global_variables_initializer()
sess.run(init)
print(sess.run(mycollection[0])) #獲取v1
打印結果
[<tf.Variable 'v1:0' shape=(1, 2, 3) dtype=float32_ref>]
[[[-0.28881794 0.46018004 -0.83893764]
[-0.93932706 0.84757173 0.78609943]]]
默認情況tf.Variable
都會被放入兩個默認的集:
-
tf.GraphKeys.GLOBAL_VARIABLES
可用于多設備共享變量 -
tf.GraphKeys.TRAINABLE_VARIABLES
會被計算梯度下降
也可以在創建變量的時候立即放入集合,語法:
my_local = tf.get_variable(name="my_local",
shape=(),
collections=[tf.GraphKeys.LOCAL_VARIABLES])
或者直接設定變量可被訓練:
my_non_trainable = tf.get_variable("my_non_trainable",
shape=(),
trainable=False)
Device placement設備放置
可以把變量限定在特定設備,例如下面代碼把v變量放置在GPU1下面:
with tf.device("/device:GPU:1"):
v = tf.get_variable("v", [1])
分布式計算中變量的設備非常重要,放置不當可能導致運算緩慢甚至出錯。tf.train.replica_device_setter
方法可以自動化處理。
cluster_spec = {
"ps": ["ps0:2222", "ps1:2222"],
"worker": ["worker0:2222", "worker1:2222", "worker2:2222"]}
with tf.device(tf.train.replica_device_setter(cluster=cluster_spec)):
v = tf.get_variable("v", shape=[20, 20])
初始化變量
變量在使用前必須被初始化。使用low level api的時候必須手工明確初始化,hight level api中的tf.contrib.slim, tf.estimator.Estimator and Keras
會自動在訓練前完成初始化。
- 一次性初始化所有變量
tf.global_variables_initializer()
- 初始化單個變量
session.run(my_variable.initializer)
- 查看哪些變量沒被初始化
session.run(tf.report_uninitialized_variables())
注意,tf.global_variables_initializer()
初始化時候并沒有固定順序,如果某個變量依賴于其他變量的求值,那將遇到錯誤。當所有變量沒被初始化完成的時候,用variable.initialized_value()
來獲取計算值,而不要直接使用變量。
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
w = tf.get_variable("w", initializer=v.initialized_value() + 1)
使用變量
在計算圖中,變量可以當作tf.tensor
張量對象使用。例如
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
w = v + 1
設定變量的值,可以直接使用變量自帶的方法assign, assign_add,assign_sub
等。
import tensorflow as tf
sess=tf.Session()
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
assignment = v.assign_add(1)
init=tf.global_variables_initializer()
sess.run(init)
print(sess.run(assignment)) #或者assignment.op.run(), 或assignment.eval()
輸出
1.0
由于類似梯度下降算法這樣的優化器會在運算時候不斷修改變量,所以變量是不穩定的。我們可以用tf.Variable.read_value
方法讀取變化之后的值。
import tensorflow as tf
sess=tf.Session()
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())
assignment = v.assign_add(1)
init=tf.global_variables_initializer()
sess.run(init)
print(sess.run(v.read_value()))
with tf.control_dependencies([assignment]):
w = v.read_value()
print(sess.run(w))
打印結果
0.0
1.0
共享變量Sharing variables
Tensorflow有兩種方法共享變量:
- 顯式的傳遞
tf.Variable
對象 - 隱式的使用
tf.variable_scope
包裹tf.variable
對象
比如下面的示意代碼中,我們創建了一個卷積層(線性整流單元):
def conv_relu(input, kernel_shape, bias_shape):
# 創建變量 "weights".
weights = tf.get_variable("weights", kernel_shape,
initializer=tf.random_normal_initializer())
# 創建變量"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)
上面的代碼定義了conv_relu方法,其中有兩個變量weight和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]) # 失?。?
我們試圖鏈接兩個卷積層,但計算機在計算的時候無法清楚是重新創建weight和biases還是繼續使用已經存在的。
下面的代碼正確的創建兩個卷積層,使用新的變量:
def my_image_filter(input_images):
with tf.variable_scope("conv1"):
# 這里創建的變量被重新命名為 "conv1/weights", "conv1/biases".
relu1 = conv_relu(input_images, [5, 5, 32, 32], [32])
with tf.variable_scope("conv2"):
# 這里創建的變量被重新命名為 "conv2/weights", "conv2/biases".
return conv_relu(relu1, [5, 5, 32, 32], [32])
如果你需要共享變量而不是重新創建,以下兩種語法都可以實現:
with tf.variable_scope("model"):
output1 = my_image_filter(input1)
with tf.variable_scope("model", reuse=True): #注意這里reuse=True
output2 = my_image_filter(input2)
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: # 注意這里的as scope
output1 = my_image_filter(input1)
with tf.variable_scope(scope, reuse=True): #注意這里傳入的scope
output2 = my_image_filter(input2)
本篇小結
- 創建變量
tf.get_variable(name,shape,dtype,initializer)
- 變量集合
tf.add_to_collection("mycollection", v1)
- 置入不同的設備
- 變量初始化方法
tf.global_variables_initializer()
和session.run(my_variable.initializer)
- 使用變量
- 修改變量
assign, assign_add,assign_sub
- 共享變量
tf.variable_scope
探索人工智能的新邊界
如果您發現文章錯誤,請不吝留言指正;
如果您覺得有用,請點喜歡;
如果您覺得很有用,感謝轉發~
END