1. 程式人生 > >TensorFlow修煉之道(2)——變數(Variable)

TensorFlow修煉之道(2)——變數(Variable)

變數
變數(Variable)是 TensorFlow 中程式處理的共享持久狀態的最佳方法。與常量不同的時,常量建立後,值便無法更改,但是變數建立後 可以修改。並且修改後的值在多個Session中都是可以看見的。
訓練模型時,需要使用變數(Variable)儲存和更新引數。變數是包含張量(tensor)的記憶體緩衝。變數必須要先被初始化(initialize) ,而且可以在訓練時和訓練後儲存(save)到磁碟中。之後可以再恢復(restore)儲存的變數值來訓練和測試模型。

建立變數
建立變數有兩種方式,一種是使用 tf.Variable 來建立一個新的變數,另一種是使用 tf.get_variable 來獲取一個已經存在的變數或者建立一個新的變數。
tf.Variable 需要接收一個 Tensor 給建構函式,也可以自定義結點名稱和資料型別。這裡使用 tf.random_normal 來生成一個均值為1,標準差0.2,形狀為(2, 5)的張量。使用 tf.Variable 時,如果檢測到命名衝突,系統會自動處理。

import tensorflow as tf
w1 = tf.Variable(tf.random_normal((2, 5), mean=1, stddev=0.2), name="w1")
w2 = tf.Variable(tf.random_normal((2, 5), mean=1, stddev=0.2), name="w1")
print("w1.name: %s, w2.name: %s" % (w1.name, w2.name))
w1.name: w1:0, w2.name: w1_1:0

可以看出,當已經存在一個相同結點的名稱後,tf.Variable 會自動新增“_1”等字尾來做區分。使用 tf.get_variable來建立變數時,結合 tf.variable_scope 可以實現共享變數。

with tf.variable_scope("scope"):
   # 這裡建立的變數名將命名為 "scope/b"
   b1 = tf.get_variable(name="b", shape=[2, 5], initializer=tf.constant_initializer(1.0))
   print(b1)
<tf.Variable 'scope/b:0' shape=(2, 5) dtype=float32_ref>

接下來使用 with 和 tf.variable_scope 來生成一個上下文管理器,需要注意的是,在 tf.variable_scope 中,需要指定 reuse=True ,否則會出錯。

with tf.variable_scope("scope", reuse=True):
   b2 = tf.get_variable(name="b", shape=[2, 5])
   print(b2)
print(b1 is b2)
<tf.Variable 'scope/b:0' shape=(2, 5) dtype=float32_ref>
True
可以看到,b1 和 b2 是同一個變數。

裝置放置


像任何其它TensorFlow操作一樣,你可以將變數放置到特定的裝置上。
語法結構為:with tf.device(…): block,下面建立一個名為v的變數,並將其放在第一個GPU裝置上
with tf.device("/gpu:0"):
   v = tf.get_variable("v", [1])

變數集合
TensorFlow 支援將變數存放在集合(collection)中,以便於在不同地方使用。TensorFlow 中每個集合都是一個列表,並且有一個名稱(可以是任何字串)。可以通過 tf.get_collection 方法來獲取不同名稱的集合。
預設情況下,每個變數會被存放在 tf.GraphKeys.GLOBAL_VARIABLES 和 tf.GraphKeys.TRAINABLE_VARIABLES 這兩個集合中。此外,也可以通過 tf.add_to_collection 手動新增變數到集合中。
print("%s: \n%s\n" % (tf.GraphKeys.GLOBAL_VARIABLES, tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES)))
print("%s: \n%s\n" % (tf.GraphKeys.TRAINABLE_VARIABLES, tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES)))
# 手動新增變數 w1/b1 到集合 my_col 中
tf.add_to_collection("my_col", w1)
tf.add_to_collection("my_col", b1)
print("my_col: \n%s" % tf.get_collection("my_col"))
variables: 
[<tf.Variable 'w1:0' shape=(2, 5) dtype=float32_ref>, <tf.Variable 'w1_1:0' shape=(2, 5) dtype=float32_ref>, <tf.Variable 'scope/b:0' shape=(2, 5) dtype=float32_ref>, <tf.Variable 'v:0' shape=(1,) dtype=float32_ref>]
trainable_variables: 
[<tf.Variable 'w1:0' shape=(2, 5) dtype=float32_ref>, <tf.Variable 'w1_1:0' shape=(2, 5) dtype=float32_ref>, <tf.Variable 'scope/b:0' shape=(2, 5) dtype=float32_ref>, <tf.Variable 'v:0' shape=(1,) dtype=float32_ref>]
my_col: 
[<tf.Variable 'w1:0' shape=(2, 5) dtype=float32_ref>, <tf.Variable 'scope/b:0' shape=(2, 5) dtype=float32_ref>]

初始化變數

在使用變數之前,它必須被初始化。在低階TensorFlow API中程式設計(需要自己明確地建立圖和會話),必須顯式初始化變數。大多數高階框架,如tf.contrib.slim、tf.estimator.Estimator和Keras在訓練模型之前自動初始化變數。
要在訓練開始前一次初始化所有可訓練的變數,可以呼叫 tf.global_variables_initializer() 來完成。如果只想初始化某個變數,可以呼叫變數的 .initializer屬性。在初始化變數之前,可以使用 tf.report_uninitialized_variables() 來檢視尚未被初始化的變數的名稱。
with tf.Session() as sess:
   # 檢視當前未初始化的變數名稱
   print(sess.run(tf.report_uninitialized_variables()))
   # 初始化變數 w1
   sess.run(w1.initializer)
   print(sess.run(tf.report_uninitialized_variables()))
   # 初始化所有變數
   sess.run(tf.global_variables_initializer())
   print(sess.run(tf.report_uninitialized_variables()))
[b'w1' b'w1_1' b'scope/b' b'v']
[b'w1_1' b'scope/b' b'v']
可以看到,呼叫變數的 initializer 屬性只會初始化該變數,呼叫 tf.global_variables_initializer() 會初始化所有變數。

使用變數

在 TensorFlow 使用變數時,只需要像對待普通的張量(Tensor)來對待它就可以了。對變數進行操作後,生成的結果會是一個張量。o1 = w1 + b1
with tf.Session() as sess:
   # 使用變數前需要進行初始化,這裡可以不用進行初始化,
   # 因為在上一節的 "初始化變數" 時已經初始過了,這裡只是為了保證流程完整,所以加上了。
   sess.run(tf.global_variables_initializer())
   print(sess.run(o1))
[[1.9957633 2.0741634 1.6809903 1.7901803 2.1854873]
[1.8982319 2.2382631 1.7602906 1.9434371 2.0995731]]

腦洞科技棧  一個有用的IT公眾號
瞭解更多幹貨文章,可以關注小程式八斗問答