[程序員指南3]變量
變量
TensorFlow 變量是表示程序處理的共享,持久狀態的最佳方法。
變量通過tf.Variable
類進行操作。A tf.Variable
表示可以通過運行op來更改其值的張量。與tf.Tensor
對象不同 ,a tf.Variable
存在於單個session.run
調用的上下文之外 。
在內部,tf.Variable
存儲一個持續張量。具體操作允許您讀取和修改此張量的值。這些修改在多個tf.Session
s 中可見,因此多個工作人員可以看到相同的值 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]
。默認情況下,該變量將具有dtype
tf.float32
該初始值並通過其隨機化 tf.glorot_uniform_initializer
。
您可以選擇指定dtype
和初始化程序tf.get_variable
。例如
my_int_variable = tf.get_variable("my_int_variable", [1, 2, 3], dtype=tf.int32, initializer=tf.zeros_initializer)
TensorFlow提供了許多方便的初始化器。或者,您可以初始化a tf.Variable
以具有值a tf.Tensor
。例如:
other_variable = tf.get_variable("other_variable", dtype=tf.int32, initializer=tf.constant([23, 42]))
請註意,當初始化程序為a時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("/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)
使用變量
要使用tf.Variable
TensorFlow圖中的a 值,只需將其視為正常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() assignment.run()
大多數TensorFlow優化器具有專門的操作,可以根據一些梯度下降算法有效地更新變量的值。請參閱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.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, 1, 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)
[程序員指南3]變量