变量命名空间
tf里面的命名空间和C++的命名空间基本上是同一种东西,能够更好的管理模块的变量(特别是将来会重用到的变量)。最简单的用法就是
with tf.variable_scope("layer1"):
# 这里就创建了一个名叫layer1的变量空间
v = tf.get_variable("vector", [3], initializer=tf.random_normal_initializer(stddev=1.0, mean=0.0)) # 创建了在这个layer1空间中的一个名为vector的向量并且初始化
assert v.name = "layer1/vector:0" # 加上变量空间,变量全称为"layer1/vector:0",具有唯一性
通过这样可以将一层网络的参数放在一起,发生变量重用的时候会很方便。
变量重用
变量重用则是通过get_variable函数 重复创建 同名变量来共享变量值。
举例子,我们要对图片进行特征提取。有两个已有的函数:
'''激活函数为ReLU的卷积层'''
def conv_relu(input, kernel_shape, bias_shape):
weights = tf.get_variable("weights", kernel_shape,
initializer=tf.random_normal_initializer())
biases = tf.get_variable("biases", bias_shape,
conv = tf.nn.conv2d(input, weights,
strides=[1, 1, 1, 1], padding='SAME')
return tf.nn.relu(tf.nn.bias_add(conv, biases))
'''对输入图片进行特征提取/滤波'''
def my_image_filter(input_images):
with tf.variable_scope("conv1"):
relu1 = conv_relu(input_images, [5, 5, 32, 32], [32])
with tf.variable_scope("conv2"):
return conv_relu(relu1, [5, 5, 32, 32], [32])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
如果直接调用两次函数my_image_filter,第二次调用时tf的get_variable函数会检测是否已经存在已经命名的变量,所以就会报错:
result1 = my_image_filter(image1)
result2 = my_image_filter(image2)
如果想要重用变量,则需要将变量打上重用标签。
被重用的变量需要落在同一个变量空间中,有三种方式来设置变量的重用标签reuse。
第一种:
with tf.variable_scope("image_filters") as scope:
result1 = my_image_filter(image1)
scope.reuse_variables() # 用scope来调用reuse_variables函数
result2 = my_image_filter(image2)
第二种:
with tf.variable_scope("image_filters"):
result1 = my_image_filter(image1)
with tf.variable_scope("foo", reuse=True):
result2 = my_image_filter(image2)
第三种:
with tf.variable_scope("image_filters"):
result1 = my_image_filter(image1)
tf.get_variable_scope().reuse_variables() # 用get_variable_scope函数得到当前空间
result2 = my_image_filter(image2)
命名空间独立性
如果之前已经存在一个命名了的命名空间,在嵌套内层如果开启该命名空间,会自动忽略上层嵌套的命名空间,该命名空间里面的变量名字保持原样。
with tf.variable_scope("foo") as foo_scope:
assert foo_scope.name == "foo"
with tf.variable_scope("bar"):
with tf.variable_scope("baz") as other_scope:
assert other_scope.name == "bar/baz"
with tf.variable_scope(foo_scope) as foo_scope2:
assert foo_scope2.name == "foo"
但是如果直接用名字”foo”,则会不一样,会开启一个新的不一样的命名空间:
with tf.variable_scope("foo") as foo_scope:
assert foo_scope.name == "foo"
with tf.variable_scope("bar"):
with tf.variable_scope("baz") as other_scope:
assert other_scope.name == "bar/baz"
with tf.variable_scope("foo") as foo_scope2:
assert foo_scope2.name == "bar/baz/foo"
对ops(操作)命名
第一种:
with tf.variable_scope("foo"):
x = 1.0 + tf.get_variable("v", [1])
assert x.op.name == "foo/add"
第二种(tf.name_scope仅仅对ops有用,不改变变量命名):
with tf.variable_scope("foo"):
with **tf.name_scope("bar")**:
v = tf.get_variable("v", [1])
x = 1.0 + v
assert v.name == "foo/v:0"
assert x.op.name == "foo/bar/add"
Initializer的继承和覆盖
在嵌套命名空间里,Initializer可以继承或覆盖上层嵌套的初始化设置。
点击打开链接