1. 程式人生 > >tensorflow中的“tf.name_scope()”有什麼用?

tensorflow中的“tf.name_scope()”有什麼用?

1. tf.name_scope()名稱空間的實際作用

(1)在某個tf.name_scope()指定的區域中定義的所有物件及各種操作,他們的“name”屬性上會增加該命名區的區域名,用以區別物件屬於哪個區域;
(2)將不同的物件及操作放在由tf.name_scope()指定的區域中,便於在tensorboard中展示清晰的邏輯關係圖,這點在複雜關係圖中特別重要。

見下例:

import tensorflow as tf;  
tf.reset_default_graph()

# 無tf.name_scope()
a = tf.constant(1,name='my_a') #定義常量
b = tf.Variable(2,name='my_b') #定義變數
c = tf.add(a,b,name='my_add') #二者相加(操作)
print("a.name = "+a.name)
print("b.name = "+b.name)
print("c.name = "+c.name)

# 有tf.name_scope()
# with tf.name_scope('cgx_name_scope'): #定義一塊名為cgx_name_scope的區域,並在其中工作
#     a = tf.constant(1,name='my_a')
#     b = tf.Variable(2,name='my_b')
#     c = tf.add(a,b,name='my_add')
# print("a.name = "+a.name)
# print("b.name = "+b.name)
# print("c.name = "+c.name)

# 儲存graph用於tensorboard繪圖
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    writer = tf.summary.FileWriter("./test",sess.graph)
    print(sess.run(c))
writer.close()
# 輸出結果
# 無tf.name_scope()
a.name = my_a:0
b.name = my_b:0
c.name = my_add:0

# 有tf.name_scope()
a.name = cgx_name_scope/my_a:0
b.name = cgx_name_scope/my_b:0
c.name = cgx_name_scope/my_add:0

從輸出結果可以看出,在tf.name_scope()下的所有物件和操作,其name屬性前都加了cgx_name_scope,用以表示這些內容全在其範圍下。
下圖展示了兩種情況的tensorboard差異,差別一目瞭然。

2. name_scope()只決定“物件”屬於哪個範圍,並不會對“物件”的“作用域”產生任何影響。

tf.name_scope()只是規定了物件和操作屬於哪個區域,但這並不意味著他們的作用域也只限於該區域(with的這種寫法很容易讓人產生這種誤會),不要將其和“全域性變數、區域性變數”的概念搞混淆,兩者完全不是一回事。在name_scope中定義的物件,從被定義的位置開始,直到後來某個地方對該物件重新定義,中間任何地方都可以使用該物件。本質上name_scope只對物件的name屬性進行圈定,並不會對其作用域產生任何影響。這就好比甲、乙、丙、丁屬於陳家,這裡“陳家”就是一個name_scope劃定的區域,雖然他們只屬於陳家,但他們依然可以去全世界的任何地方,並不會只將他們限制在陳家範圍。


見下例:
(1)程式首先指定了命名區域cgx_1,並在其中定義了變數a,緊接著case1直接在cgx_1中輸出a.name = cgx_1/my_a:0,這很好理解,跟想象的一樣;
(2)case2在cgx_1之外的公共區域也輸出了相同的a.name,這就說明a的作用範圍並沒有被限制在cgx_1中
(3)接著程式又新指定了命名區域cgx_2,並在其中執行case3,輸出a.name,結果還是和case1和case2完全相同,實際上還是最前面定義的那個a,這更進一步說明name_scope不會對物件的作用域產生影響
(4)★★接著在cgx_2中重新定義了變數“a”,緊接著就執行case4,輸出a.name = cgx_2/my_a:0,可見此時的結果與前面三個case就不同了,說明這裡新定義的a覆蓋了前面的a,即使他們在兩個完全獨立的name_scope中
(5)case5輸出的結果與case4結果相同,這已經無須解釋了。

#name_scope 的影響範圍
with tf.name_scope('cgx_1'): #指定cgx_1區域
    a = tf.Variable(tf.constant(4),name='my_a') #定義變數a
    print("case1: a.name="+a.name) #cgx_1區域內輸出
print("case2: a.name="+a.name) #cgx_1區域外輸出

# 儲存graph用於tensorboard繪圖
with tf.name_scope('cgx_2'): #新指定cgx_2區域
    print("case3: a.name="+a.name) #在cgx_2內輸出cgx_1中定義a.name
    a = tf.Variable(tf.constant(4),name='my_a') #★★重新定義a這個變數
    print("case4: a.name="+a.name)
print("case5: a.name="+a.name)
# 輸出結果:
case1: a.name = cgx_1/my_a:0
case2: a.name = cgx_1/my_a:0
case3: a.name = cgx_1/my_a:0
case4: a.name = cgx_2/my_a:0
case5: a.name = cgx_2/my_a:0

3. tf.name_scope('cgx_scope')語句重複執行幾次,就會生成幾個獨立的名稱空間,儘管表面上看起來都是“cgx_scope”,實際上tensorflow在每一次執行相同語句都會在後面加上“_序數”,加以區別。

見下例:
(1)指定了“cgx_scope”命名區域,並在其中定義變數a;
(2)又指定了相同名稱的“cgx_scope”命名區域,並在其中定義變數b;
(3)輸出a.name = cgx_scope/my_a:0和b.name = cgx_scope_1/my_b:0,可見b.name已經自動加了“_1”,這是tensorflow的特點,自動檢測是否重複,有重複就自動增加數字作為標記

with tf.name_scope('cgx_scope'):
    a = tf.Variable(1,name='my_a')

with tf.name_scope('cgx_scope'):
    b = tf.Variable(2,name='my_b')

c = tf.add(a,b,name='my_add')

print("a.name = "+a.name)
print("b.name = "+b.name)

# 儲存graph用於tensorboard繪圖程式(同上)
# 輸出結果
a.name = cgx_scope/my_a:0
b.name = cgx_scope_1/my_b:0 #自動增加了“_1”

下圖進一步說明a和b不在同一個name_scope中

 

4. 如何在不同的地方將物件指定到相同的name_scope中?

方法:
with tf.name_scope('cgx_scope') as cgxscope:
……
with tf.name_scope(cgxscope) :
……
見下例:
將前一例程式做簡單修改,輸出結果a和b都在cgx_scope的命名範圍內,後面的tensorboard也說明了這點。

with tf.name_scope('cgx_scope') as cgxscope:
    a = tf.Variable(1,name='my_a')

with tf.name_scope(cgxscope):
    b = tf.Variable(2,name='my_b')

c = tf.add(a,b,name='my_add')

print("a.name = "+a.name)
print("b.name = "+b.name)
# 輸出結果
a.name = cgx_scope/my_a:0
b.name = cgx_scope/my_b:0

下圖說明此例中a和b位於相同的name_scope中。

5. 多重name_scope名稱空間

多個with tf.name_scope()重疊使用,如下例。

with tf.name_scope('cgx_scope_1'): #第一重新命名空間
    with tf.name_scope('cgx_scope_2'): #第二重新命名空間
        a = tf.Variable(1,name='my_a')

with tf.name_scope('cgx_scope_3'):
    b = tf.Variable(2,name='my_b')

c = tf.add(a,b,name='my_add')

print("a.name = "+a.name)
print("b.name = "+b.name)
# 輸出結果
a.name = cgx_scope_1/cgx_scope_2/my_a:0
b.name = cgx_scope_3/my_b:0

6. 常量tf.constant()即使在某個name_scope下被定義,在tensorboard中也不會被繪製到該name_scope下,主要考慮到影象的結構問題。

如下例:
常量a和變數b都定義在cgx_scope下,操作c定義在公共區域。從輸出結果看,一切正常。但後面的tensorboard圖跟想象的有點區別,按規律my_a和my_b都應該在cgx_scope內,但圖中顯然沒有。猜測,tensorboard中常量通常在水平左側,形式比較固定,而變數通常在下側,形式也比較隨意,因此把常量和變數畫在同一name_scope下對圖的邏輯有較大影響。

該例中如果把c = tf.add(a,b,name='my_add')同樣寫入cgx_scope下,那麼在tensorboard中整個過程都會被放入cgx_scope下。

with tf.name_scope('cgx_scope'):
    a = tf.constant(1,name='my_a')
    b = tf.Variable(2,name='my_b')

c = tf.add(a,b,name='my_add')

print("a.name = "+a.name)
print("b.name = "+b.name)
print("c.name = "+c.name)
# 輸出結果
a.name = cgx_scope/my_a:0
b.name = cgx_scope/my_b:0
c.name = my_add:0

7. tf.name_scope()對由tf.get_variable()產生的變數沒有影響

如下例:
在cgx_scope名稱空間下,a是由tf.get_variable()生成的變數,b是由tf.Variable()生成的變數,按規律a.name和b.name的字首都是cgx_scope,但從輸出結果可看出,a.name的字首沒出現,說明a不在該名稱空間。後面的tensorboard圖也說明了這點。出現這種情況是由tf.get_variable()的特性決定的,詳見其他文章。

with tf.name_scope('cgx_scope'):
    a = tf.get_variable('my_a',initializer=4)
    b = tf.Variable(2,name='my_b')

c = tf.add(a,b,name='my_add')

print("a.name = "+a.name)
print("b.name = "+b.name)
# 輸出結果
a.name = my_a:0
b.name = cgx_scope/my_b:0

 

get_valuable()不受name_scope影響

作者:馬爾地夫Maldives
連結:https://www.jianshu.com/p/635d95b34e14
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授