相信大家在学习和使用tensorflow的过程中肯定会遇到过关于scope的一些问题,scope是一种给变量命名的方法,它会让变量命名变得简单,同时也常用于reusing variable 代码中,下面将会给大家讲解一下tensorflow中两种定义scope的方法,来帮助大家更好的理解和使用scope。
首先我们先展示一段代码:
import tensorflow as tf
with tf.name_scope("a_name_scope"):
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
var2 = tf.Variable(name='var2', initial_value=[2], dtype=tf.float32)
var21 = tf.Variable(name='var2', initial_value=[2.1], dtype=tf.float32)
var22 = tf.Variable(name='var2', initial_value=[2.2], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_name_scope/var2:0
print(sess.run(var2)) # [ 2.]
print(var21.name) # a_name_scope/var2_1:0
print(sess.run(var21)) # [ 2.0999999]
print(var22.name) # a_name_scope/var2_2:0
print(sess.run(var22)) # [ 2.20000005]
在session下我们分别打印出各个变量的名字和值,打印出来的结果显示在每一句代码后面的#注释部分。仔细观察上面的结果我们不难看出,在tf.name_scope( )这种框架下,如果使用tf.get_variable( )这种途径创建的变量,其名字是不受scope的名字所影响的。接下来用tf.Variable( )这种方式创建的变量,输出时会将scope的名字一起输出(即在scope这个变量下创建的变量),而且他们都有自己的变量名字并且相同,程序没有报错但也没数输出三个相同名字的,那是因为在创建变量时,会检测是否该变量的名字已经存在,如果存在则改变其名字,因此才会输出2_1和2_2。
with tf.variable_scope("a_variable_scope") as scope:
initializer = tf.constant_initializer(value=3)
var3 = tf.get_variable(name='var3', shape=[1], dtype=tf.float32, initializer=initializer)
var4 = tf.Variable(name='var4', initial_value=[4], dtype=tf.float32)
var5 = tf.Variable(name='var4', initial_value=[5], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var3.name) # a_variable_scope/var3:0
print(sess.run(var3)) # [ 3.]
print(var4.name) # a_variable_scope/var4:0
print(sess.run(var4)) # [ 4.]
可以看出,在tf.variable_scope( )这种框架下,两种产生变量的途径创建的变量在输出时都会把scope变量的名字一起输出。
在有的时候程序中需要我们重复使用之前定义过的变量,那我们应该怎么办呢,那么我们就可以使用tensorflow中的scope.reuse_variables()。
with tf.variable_scope("a_variable_scope") as scope:
initializer = tf.constant_initializer(value=3)
var3 = tf.get_variable(name='var3', shape=[1], dtype=tf.float32, initializer=initializer)
scope.reuse_variables()
var3_reuse = tf.get_variable(name='var3',)
var4 = tf.Variable(name='var4', initial_value=[4], dtype=tf.float32)
var4_reuse = tf.Variable(name='var4', initial_value=[4], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var3.name) # a_variable_scope/var3:0
print(sess.run(var3)) # [ 3.]
print(var3_reuse.name) # a_variable_scope/var3:0
print(sess.run(var3_reuse)) # [ 3.]
print(var4.name) # a_variable_scope/var4:0
print(sess.run(var4)) # [ 4.]
print(var4_reuse.name) # a_variable_scope/var4_1:0
print(sess.run(var4_reuse)) # [ 4.]
从上面可以看到,如果想要达到重复利用变量的效果, 我们就要使用 tf.variable_scope(), 并搭配 tf.get_variable() 这种方式产生和提取变量. 不像 tf.Variable() 每次都会产生新的变量, tf.get_variable() 如果遇到了同样名字的变量时, 它会单纯的提取这个同样名字的变量(避免产生新变量). 而在重复使用的时候, 一定要在代码中强调 scope.reuse_variables(), 否则系统将会报错, 以为你只是单纯的不小心重复使用到了一个变量。
简单来看:
个人觉得name_scope的作用在于封装一大堆操作让生成的数据流图具有层次化,方便navigate。variable_scope则是一个更加值得注意的东西。它控制着变量的分级命名。变量命名很重要如果变量名冲突是要报错的,还有就是它控制变量共享,你可以指定控制在某一个scope下所有的变量共享。name_scope是作用在操作上的,操作如果命名冲突没关系,tf会自动帮你加一个后缀,无关紧要。如果你希望好调试,那就为操作命个名。
通过上面的学习,相信各位同学能够很好的理解scope的命名方法了吧,那么就赶紧去实战吧!!!