numpy.ndarray
作為資料或是 C/C++ 版本的 tensorflow::Tensor
instance)tf.Tensor
或 tf.placeholder
。除了 tf.constant
持有不可更改的資料外,tf.placeholder
如它的以下 tf
為 import tensorflow as tf
的執行結果,也是 tensorflow
的簡稱。
tf.Graph
: 代表計算圖的物件,通常包括了三個元件: tf.constant
, tf.Variable
和 tf.Operation
。tf.Variable
: 具有狀態的變數。該類別下的物件的內在狀態,或所持有的資料是允許被修改的(透過 tf.Variable().assign()
),甚至不在 Session 物件的 context 內。tf.constant
是一個內在狀態不得被更改的 tf.Tensor
。tf.Operation
: 代表計算圖的運算元,有以下四大類運算
tf.Variable.assign()
tf.Variable
或局部域的初始化運算元(local initializer)tf.Graph
tf.Graph
有下列兩個主要的元素:
1.圖形結構(Graph Structure):Tensorflow 中使用的計算圖是一個數據流計算圖,其節點為 tf.Operation
(相對於 PyTorch 的 Function 物件),而圖的連結(edges)代表的是數據流動的方向,如被某一 tf.Operation
當做輸入而消耗,或當作輸出而產生。使用者可以檢查 Graph 結構(透過視覺化工具 tensorboard)以了解如何計算值。但是,它缺少運行時資料的訊息,如包含 NaN 的值。
tf.Variable
(或 tf.Tensor
)都可以放入任何現有或新創建的集合(透過呼叫 tf.add_to_collection
)。可以使用 tf.GraphKeys
中定義的鍵查找當前存在的集合(透過呼叫 tf.get_collection
)。使用集合的好處是可以為 tf.Saver
或 tf.Optimizer
等操作量(見下)。tf.Graph
可以應用命名空間於子圖,為它們提供有意義的名稱。這可以通過呼叫 module function tf.name_scope
來完成。
因為 tf.Graph
有上述集合的概念,所以可以直接提取集合中多個 tf.Variable
物件。這個設計可以反映在 tf.Optimizer
在實例化物件時,不須像 PyTorch torch.nn.optim
在實例化 Optimizer 的時候需要傳遞訓練變數。
相對地,一個 tf.Optimizer
可以直接提取 Graph collection 中的 ops.GraphKeys.TRAINABLE_VARIABLES
(想像靜態計算圖,是個無所不知的天神),而只需要將正向傳播完成的損失傳入 tf.Optimizer().minimize()
函式中。
但,有些變數本身並沒有計算關係,在靜態計算圖中沒有可以到達的路徑,我們可以將他們的聚集起來,並使用 tf.control_dependencies(control_inputs)
context 來將 context 內所執行的運算元與 tf.control_dependencies
輸入相關。
tf.Variable
tf.Variable()
在實體化時,可以透過給予初始值(initial_value)或給予變數定義(variable_def)。若要以變數定義來實體化,則需要遵循 protobuf 的規則來撰寫定義的部分。另外,tf.Variable
還有一個常用參數,那就是 trainable。trainable 參數接受布林值,若為 True
則會將該變數放置在 tf.GraphKeys.TRAINABLE_VARIABLES
的集合裏,反之(為False
),則不會。預設的 tf.Variable()
通常放置於 global 和 trainable 的 collections 中。
如果要讓兩個變數要共享其中一個變數的值,在實作上通常讓另一個 tf.Variable
物件的參考指向共享的tf.Variable
上。 共享參數在需要實踐 tie weight 的需求,如 autoencoder 讓 decoder 的權重變數為 encoder 權重的 transpose。
f.Variable
的參考。tf.variable_score
作 implicit 分享以下的原始碼出自於 tensorflow variable guide。主要目的是使用一個如 factory 的函式,能夠重複呼叫建立不同的卷積層。 在下列的程式碼中,使用 tf.get_variable
來建立 tf.Variable
物件,該方法會在現有的 scope 或 tf.variable_scope
指定的 scope 尋找同名的變數,若沒有尋得則建立一個新的變數。
由下面的原始碼,可以看到若不使用 tf.variable_scope
,則會出現ValueError
(完整的錯誤訊息原始碼底下)
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)
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.
"""
ValueError: Variable weights already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope?
"""
如果要解決以上 name conflict 問題,就要利用 tf.variable_scope
在每一次呼叫都建立新的命名空間。
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])
倘若我們想要 re-using 同樣的 tf.Variable
,如,我們之前所說的 implicitly sharing 或 tie weight case。我們仍舊可以運用 tf.variable_scope
函後將 reuse 參數設為 True
。這個參數也可以在 tf.get_variable
找到,但一旦將該參數設為 True
,若在指定或所在的命名空間找不到該名稱的變數,就不會再建立新的 tf.Variable
而丟出錯誤訊息。
# passing true to enforce reuse at
# constructing time
with tf.variable_scope("model"):
output1 = my_image_filter(input1)
with tf.variable_scope("model", reuse=True):
output2 = my_image_filter(input2)
# using variable_scope to enforce reuse
with tf.variable_scope("model") as scope:
output1 = my_image_filter(input1)
# below is equivalent to ```
# with tf.variable_scope(scope, reuse=True):
scope.reuse_variables()
output2 = my_image_filter(input2)