TensorFlow 變量是表示程序處理的共享持久狀態的最佳方法。
我們使用 tf.Variable 類操作變量。tf.Variable 表示可通過對其運行操作來改變其值的張量。與 tf.Tensor 對象不同,tf.Variable 存在于單個 session.run 調用的上下文之外。
在 TensorFlow 內部,tf.Variable 會存儲持久性張量。具體 op 允許您讀取和修改此張量的值。這些修改在多個 tf.Session 之間是可見的,因此對于一個 tf.Variable,多個工作器可以看到相同的值。
創建變量
創建變量的最佳方式是調用 tf.get_variable 函數。此函數要求您指定變量的名稱。其他副本將使用此名稱訪問同一變量,以及在對模型設置檢查點和導出模型時指定此變量的值。tf.get_variable 還允許您重復使用先前創建的同名變量,從而輕松定義重復利用層的模型。
要使用tf.get_variable創建變量,只需提供名稱和形狀即可
my_variable = tf.get_variable("my_variable", [1, 2, 3])
這將創建一個名為 “my_variable” 的變量,該變量是形狀為 [1, 2, 3] 的三維張量。默認情況下,此變量將具有 dtypetf.float32,其初始值將通過 tf.glorot_uniform_initializer 隨機設置。
您可以選擇為 tf.get_variable 指定 dtype 和初始化器。例如:
my_int_variable = tf.get_variable("my_int_variable", [1, 2, 3], dtype=tf.int32, initializer=tf.zeros_initializer)
TensorFlow 提供了許多方便的初始化器。或者,您也可以將 tf.Variable 初始化為 tf.Tensor 的值。例如:
other_variable = tf.get_variable("other_variable", dtype=tf.int32, initializer=tf.constant([23, 42]))
請注意,當初始化器是 tf.Tensor 時,您不應指定變量的形狀,因為將使用初始化器張量的形狀。
變量集合
由于 TensorFlow 程序的未連接部分可能需要創建變量,因此能有一種方式訪問所有變量有時十分受用。為此,TensorFlow 提供了集合,它們是張量或其他對象(如 tf.Variable 實例)的命名列表。
默認情況下,每個 tf.Variable 都放置在以下兩個集合中:
tf.GraphKeys.GLOBAL_VARIABLES- 可以在多臺設備間共享的變量
tf.GraphKeys.TRAINABLE_VARIABLES- TensorFlow 將計算其梯度的變量
如果您不希望變量可訓練,可以將其添加到 tf.GraphKeys.LOCAL_VARIABLES 集合中。例如,以下代碼段展示了如何將名為 my_local 的變量添加到此集合中:
my_local = tf.get_variable("my_local", shape=(),collections=[tf.GraphKeys.LOCAL_VARIABLES])
或者,您可以指定 trainable=False(作為 tf.get_variable 的參數):
my_non_trainable = tf.get_variable("my_non_trainable", shape=(), trainable=False)
您也可以使用自己的集合。集合名稱可為任何字符串,且您無需顯式創建集合。創建變量(或任何其他對象)后,要將其添加到集合中,請調用 tf.add_to_collection。例如,以下代碼將名為 my_local 的現有變量添加到名為 my_collection_name 的集合中:
tf.add_to_collection("my_collection_name", my_local)
要檢索您放置在某個集合中的所有變量(或其他對象)的列表,您可以使用:
tf.get_collection("my_collection_name")
設備放置方式
與任何其他 TensorFlow 指令一樣,您可以將變量放置在特定設備上。例如,以下代碼段創建了名為 v 的變量并將其放置在第二個 GPU 設備上:
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]) # this variable is placed # in the parameter server # by the replica_device_setter
初始化變量
變量必須先初始化后才可使用。如果您在低級別 TensorFlow API 中進行編程(即您在顯式創建自己的圖和會話),則必須明確初始化變量。tf.contrib.slim、tf.estimator.Estimator 和 Keras 等大多數高級框架在訓練模型前會自動為您初始化變量。
顯式初始化在其他方面很有用。它允許您在從檢查點重新加載模型時不用重新運行潛在資源消耗大的初始化器,并允許在分布式設置中共享隨機初始化的變量時具有確定性。
要在訓練開始前一次性初始化所有可訓練變量,請調用 tf.global_variables_initializer()。此函數會返回一個操作,負責初始化 tf.GraphKeys.GLOBAL_VARIABLES 集合中的所有變量。運行此操作會初始化所有變量。例如:
session.run(tf.global_variables_initializer())# Now all variables are initialized.
如果您確實需要自行初始化變量,則可以運行變量的初始化器操作。例如:
session.run(my_variable.initializer)
您可以查詢哪些變量尚未初始化。例如,以下代碼會打印所有尚未初始化的變量名稱:
print(session.run(tf.report_uninitialized_variables()))
請注意,默認情況下,tf.global_variables_initializer 不會指定變量的初始化順序。因此,如果變量的初始值取決于另一變量的值,那么很有可能會出現錯誤。任何時候,如果您在并非所有變量都已初始化的上下文中使用某個變量值(例如在初始化某個變量時使用另一變量的值),最好使用 variable.initialized_value(),而非 variable:
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())w = tf.get_variable("w", initializer=v.initialized_value() + 1)
使用變量
要在 TensorFlow 圖中使用 tf.Variable 的值,只需將其視為普通 tf.Tensor 即可:
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())w = v + 1 # w is a tf.Tensor which is computed based on the value of v. # Any time a variable is used in an expression it gets automatically # converted to a tf.Tensor representing its value.
要為變量賦值,請使用 assign、assign_add 方法以及 tf.Variable 類中的友元。例如,以下就是調用這些方法的方式:
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())assignment = v.assign_add(1)tf.global_variables_initializer().run()sess.run(assignment) # or assignment.op.run(), or assignment.eval()
大多數 TensorFlow 優化器都有專門的 op,會根據某種梯度下降算法有效地更新變量的值。請參閱 tf.train.Optimizer,了解如何使用優化器。
由于變量是可變的,因此及時了解任意時間點所使用的變量值版本有時十分有用。要在事件發生后強制重新讀取變量的值,可以使用 tf.Variable.read_value。例如:
v = tf.get_variable("v", shape=(), initializer=tf.zeros_initializer())assignment = v.assign_add(1)with tf.control_dependencies([assignment]): w = v.read_value() # w is guaranteed to reflect v's value after the # assign_add operation.
共享變量
TensorFlow 支持兩種共享變量的方式:
顯式傳遞tf.Variable對象
將tf.Variable對象隱式封裝在tf.variable_scope對象內
雖然顯式傳遞變量的代碼非常清晰,但有時編寫在其實現中隱式使用變量的 TensorFlow 函數非常方便。tf.layers 中的大多數功能層以及所有 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)
-
變量
+關注
關注
0文章
613瀏覽量
28412 -
tensorflow
+關注
關注
13文章
329瀏覽量
60544
原文標題:TensorFlow 變量:表示程序處理的共享持久狀態的最佳方法
文章出處:【微信號:tensorflowers,微信公眾號:Tensorflowers】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論