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.Graphtf.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.Variabletf.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)