前言:整理name_scope与variable_scope是因为自己在学习的过程中碰到的一些疑惑,后来看书和网上的一些解释。故这里做一些学习记录。
1、大体的认识
tf.name_scope()和tf.variable_scope()是两个作用域,一般与两个创建/调用变量的函数tf.variable() 和tf.get_variable()搭配使用。它们搭配在一起的两个常见用途:
- 变量共享
- tensorboard画流程图时为了可视化封装变量
这两种用途有特定的搭配方式,掌握好就可以用了。
- name_scope:为了更好地管理变量的命名空间而提出的。比如在 tensorboard 中,因为引入了 name_scope, 我们的 Graph 看起来才井然有序。
- variable_scope:大部分情况下,跟 tf.get_variable() 配合使用,实现变量共享的功能。
2、name_scope与variable_scope的区别
先直接给出结论,然后再进行说明,是其他博主整理的结论,这只是借鉴一下,原文是这个。
- name_scope 对 get_variable新建变量的name属性无影响;对variable新建变量的name属性增加了“范围”标识。
- variable_scope对get_variable新建变量的name属性和variable新建变量的name属性都增加了“范围”标识。
- get_variable新建变量如果遇见重复的name则会因为重复而报错。
- variable新建的变量如果遇见重复的name则会自动修改前缀,以避免重复出现。
2.1 tf.name_scope
tf.name_scope 主要结合 tf.Variable() 来使用,方便参数命名管理。
2.1.1 name_scope()对variable的影响
'''
Signature: tf.name_scope(*args, **kwds)
Docstring:
Returns a context manager for use when defining a Python op.
'''
# 也就是说,它的主要目的是为了更加方便地管理参数命名。
# 与 tf.Variable() 结合使用。简化了命名
with tf.name_scope('conv1') as scope:
weights1 = tf.Variable([1.0, 2.0], name='weights')
bias1 = tf.Variable([0.3], name='bias')
# 下面是在另外一个命名空间来定义变量的
with tf.name_scope('conv2') as scope:
weights2 = tf.Variable([4.0, 2.0], name='weights')
bias2 = tf.Variable([0.33], name='bias')
# 所以,实际上weights1 和 weights2 这两个引用名指向了不同的空间,不会冲突
print weights1.name
print weights2.name
conv1/weights:0
conv2/weights:0
从上面的例子可以看出name_scope()对variable的变量名自动添上命名空间的名称,形式为/
2.1.2 tf.name_scope对tf.get_variable()的影响
with tf.name_scope("a_name_scope") as myscope:
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
print(var1.name)
var1:0
可见并没有在变量名前添加命名空间的名称。
2.2 tf.variable_scope
tf.variable_scope() 主要结合 tf.get_variable() 来使用,实现变量共享
2.2.1 variable_scope()对tf.get_variable() 的影响
with tf.variable_scope('v_scope') as scope1:
Weights1 = tf.get_variable('Weights', shape=[2,3])
bias1 = tf.get_variable('bias', shape=[3])
# 下面来共享上面已经定义好的变量
# note: 在下面的 scope 中的变量必须已经定义过了,才能设置 reuse=True,否则会报错
with tf.variable_scope('v_scope', reuse=True) as scope2:
Weights2 = tf.get_variable('Weights')
print Weights1.name
print Weights2.name
v_scope/Weights:0
v_scope/Weights:0
对variable的影响这里就不展示了,这里只提醒一下,当需要共用变量的时候,设置的reuse=True必须是要已经创建过的变量,否则则会报错。
也许目前还不知道这会有什么用,但给个例子就会发现这样的好处。这里借鉴一下这篇博客的内容。(也可以参考下这篇文章,讲的还算清楚,对变量的共享,因为在卷积神经网络中,卷积层的参数就是共享的呢)
TensorFlow中的变量一般就是模型的参数。当模型复杂的时候共享变量会无比复杂。
官网给了一个case,当创建两层卷积的过滤器时,每输入一次图片就会创建一次过滤器对应的变量,但是我们希望所有图片都共享同一过滤器变量,一共有4个变量:conv1_weights,conv1_biases,conv2_weights, and conv2_biases。
通常的做法是将这些变量设置为全局变量。但是存在的问题是打破封装性,这些变量必须文档化被其他代码文件引用,一旦代码变化,调用方也可能需要变化。
还有一种保证封装性的方式是将模型封装成类。
不过TensorFlow提供了Variable Scope 这种独特的机制来共享变量。这个机制涉及两个主要函数:
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)
但是我们需要两个卷积层,这时可以通过tf.variable_scope()指定作用域进行区分,
如with tf.variable_scope("conv1")这行代码指定了第一个卷积层作用域为conv1,
在这个作用域下有两个变量weights和biases。
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])
最后在image_filters这个作用域重复使用第一张图片输入时创建的变量,调用函数reuse_variables(),代码如下:
with tf.variable_scope("image_filters") as scope:
result1 = my_image_filter(image1)
scope.reuse_variables()
result2 = my_image_filter(image2)
总之,当神经网络结构更加复杂、参数更多时,使用这种变量的管理方式将大大提高程序的可读性。
参考资料:
https://blog.csdn.net/jerr__y/article/details/60877873