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