变量作用域机制主要由两个函数实现:
tf.get_variable(<name>, <shape>, <initializer>)
tf.variable_scope(<scope_name>)
常用的initializer有
tf.constant_initializer(value) # 初始化一个常量值,
tf.random_uniform_initializer(a, b) # 从a到b均匀分布的初始化,
tf.random_normal_initializer(mean, stddev) # 用所给平均值和标准差初始化正态分布.
对如下实例,
with tf.variable_scope(conv1):
# Variables created here will be named "conv1/weights".
weights = tf.get_variable('weights',kernel_shape,
initializer=tf.random_normal_initializer())
# Variables created here will be named "conv1/biases".
biases = tf.get_variable('biases',biases_shape,
initializer=tf.constant_intializer(0.0))
变量作用域的tf.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_intializer(0.0))
conv = tf.nn.conv2d(input, weights,
strides=[1, 1, 1, 1], padding='SAME')
return tf.nn.relu(conv + 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])
如果连续调用两次my_image_filter()将会报出ValueError:
result1 = my_image_filter(image1)
result2 = my_image_filter(image2)
# Raises ValueError(... conv1/weights already exists ...)
若不在网络架构中采用变量作用域则不会报错,但是会产生两组变量,而不是共享变量。
变量作用域是怎么工作的?
理解tf.get_variable()
情况1:当tf.get_variable_scope().reuse == False时,该方法用来创建新变量。
with tf.variable_scope("foo"):
v = tf.get_variable("v", [1])
assert v.name == "foo/v:0"
该情况下方法会生成一个“foo/v”,并检查确保没有其他变量使用该全称。如果该全程已经有其他的变量在使用了,则会抛出ValueError。
情况2:当tf.get_variable_scope().reuse == True时,该方法是为重用变量所设置
with tf.variable_scope("foo"):
v = tf.get_variable("v", [1])
with tf.variable_scope("foo", reuse=True):
v1 = tf.get_variable("v", [1])
assert v1 == v
该情况下会搜索一个已存在的“foo/v”并将该变量的值赋给v1,若找不到“foo/v”变量则会抛出ValueError。
注意reuse标签可以被手动设置为True,但不能手动设置为False。reuse 参数是不可继承的,所以当你设置一个变量作用域为重用作用域时,那么其所有的子作用域也将会被重用。