1. 程式人生 > >【TensorFlow學習筆記】5:variable_scope和name_scope,圖的基本操作

【TensorFlow學習筆記】5:variable_scope和name_scope,圖的基本操作

學習《深度學習之TensorFlow》時的一些實踐。


variable_scope

一般的巢狀

上節有學到在巢狀scope中的變數,一般是:

import tensorflow as tf

# with tf.variable_scope("scopeA") as spA:
#     var1 = tf.get_variable("v1", [1])

with tf.variable_scope("scopeB"):
    with tf.variable_scope("scopeA"):
        var3 = tf.get_variable(
"v3", [1]) print(var3.name)
scopeB/scopeA/v3:0

使不受外層影響

如果在其前便定義了內層scope,並將其傳入tf.variable_scope中,即:

import tensorflow as tf

with tf.variable_scope("scopeA") as spA:
    var1 = tf.get_variable("v1", [1])

with tf.variable_scope("scopeB"):
    with tf.variable_scope(spA):
        var3 = tf.get_variable(
"v3", [1]) print(var3.name)
scopeA/v3:0

此時不受外層variable_scope的影響。

name_scope

運算結點既受到name_scope限制,也受到variable_scope限制,而Variable僅受到variable_scope限制。

注意,變數和運算結點雖然都是Tensor,但它們分別是:

<class 'tensorflow.python.ops.variables.Variable'>
<class 'tensorflow.python.framework.ops.Tensor'>

輸出其type就能檢視到,所以它們才會對不同的scope有不同的表現。

一般使用

with tf.variable_scope("v"):
    with tf.name_scope("n1"):
        a = tf.get_variable("a", [1])  # Variable
        x = 1.0 + a  # Op
        with tf.name_scope("n2"):
            y = 1.0 + a  # Op
print(a.name, x.op.name, y.op.name, sep='\n')
v/a:0
v/n1/add:0
v/n1/n2/add:0

返回頂層

當為name_scope指定空字串時,其行為是使其作用域回到頂層,這個比較特殊。

with tf.variable_scope("v"):
    with tf.name_scope("n1"):
        a = tf.get_variable("a", [1])  # Variable
        x = 1.0 + a  # Op
        with tf.name_scope(""):
            y = 1.0 + a  # Op
            b = tf.get_variable("b", [1])  # Variable僅受到variable_scope的限制
print(a.name, x.op.name, y.op.name, b.name, sep='\n')
v/a:0
v/n1/add
add
v/b:0

因為b是一個Variable,僅受到variable_scope的限制,所以這個“回到頂層”對它不奏效。

圖的基本操作

圖即是一個計算任務,每個T程式預設就帶一個計算圖。

建立圖

import tensorflow as tf

# 在TF預設的圖上建立的常量Tensor
c = tf.constant(0.0)
print(c.graph)
<tensorflow.python.framework.ops.Graph object at 0x00000000032B99B0>
# 建立圖g,並在它上面建立個常量Tensor
g = tf.Graph()
with g.as_default():
    c1 = tf.constant(0.0)
print(c1.graph)  # 可以通過變數的graph屬性獲取所在的圖
print(g)
<tensorflow.python.framework.ops.Graph object at 0x000000000A611588>
<tensorflow.python.framework.ops.Graph object at 0x000000000A611588>
# 獲取預設圖,看看預設圖是哪個
g2 = tf.get_default_graph()
print(g2)
<tensorflow.python.framework.ops.Graph object at 0x00000000032B99B0>
# 重置預設圖,相當於重新建立了一個圖
tf.reset_default_graph()  # 使用該函式時必須保證當前圖的資源已經全部釋放
g3 = tf.get_default_graph()
print(g3)
<tensorflow.python.framework.ops.Graph object at 0x000000000A611550>

獲取圖中的Tensor

這裡是獲取其中的常量Tensor,只要根據它的名稱就可以將它取出。

import tensorflow as tf

g = tf.Graph()
with g.as_default():
    c = tf.constant(0.0)

print(c.name)
# 通過名稱得到對應元素:通過Tensor的名稱得到圖中的c
t = g.get_tensor_by_name(name="Const:0")
print(c is t)
Const:0
True

不過我暫時還是不理解這樣做有什麼意義,可能是在某些情形下能訪問到圖卻無法直接得到裡面的變數吧。

獲取圖中的op

注意op是op包下的Tensor的屬性,而不是Tensor本身!

import tensorflow as tf

# 兩個常量Tensor
a = tf.constant([[1.0, 2.0]])
b = tf.constant([[1.0], [3.0]])
# 定義它們做矩陣乘法的操作
mymul = tf.matmul(a, b, name='mymul')
print(mymul.op.name)  # 注意這裡是.op.name
# 因為這個op在預設圖裡,先獲取到預設圖
dft_g = tf.get_default_graph()
# 再從預設圖裡取出來
mymul_op = dft_g.get_operation_by_name(name="mymul")  # 注意這裡沒有':0'
mymul_tensor = dft_g.get_tensor_by_name(name="mymul:0")
print(mymul is mymul_op)
print(mymul_op is mymul_tensor)
print(mymul is mymul_tensor)
mymul
False
False
True

從這個例子中可以看到,前面定義的mymul看似是一個操作,其實它是一個Tensor而不是op,必須要訪問其op屬性得到的才是op,而get_operation_by_name得到的就是op,get_tensor_by_name得到的卻是Tensor,這不一樣,很容易弄混。

獲取元素列表

import tensorflow as tf

g = tf.Graph()
with g.as_default():
    c = tf.constant(0.0)
    d = tf.constant(1.1)

ops = g.get_operations()
print(ops)
[<tf.Operation 'Const' type=Const>, <tf.Operation 'Const_1' type=Const>]

得到的是圖g中的所有元素。

通過物件獲取元素

前面是通過名字獲取元素,這裡是通過傳入物件本身來獲取元素,這就更搞不懂為什麼了。。不過書上說這個函式有驗證和轉換的功能,在多執行緒中有時會用到。

g = tf.Graph()
with g.as_default():
    c1 = tf.constant(0.0)

c1_cpoy = g.as_graph_element(c1)
print(c1 is c1_cpoy)
True

相關學習資源

name_scope 與 variable_scope詳解