变量的命名空间是为了更好的管理和重用变量,因为神经网络的节点和参数非常多,我们需要scope来清楚的知道变量是那一层的。
- name_scope: 为了更好地管理变量的命名空间而提出的。比如在 tensorboard 中,因为引入了 name_scope, 我们的 Graph 看起来才井然有序。
-
variable_scope:绝大部分情况下,根
tf.get_variable()
配合使用,实现变量共享的功能。
三种方式创建变量
tf.placeholder
,tf.Variable
,tf.get_variable
上面三种方式定义的变量具有相同的类型,而且只有 tf.get_variable() 创建的变量之间会发生命名冲突。在实际使用中,三种创建变量方式的用途也是分工非常明确的。
tf.placeholder
-
tf.placeholder(dtype, shape=None, name=None)
占位符。trainable==False,类似于函数的传递参数,在图运行前必须先传入值。
import tensorflow as tf
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
output = input1 * input2
with tf.Session() as sess:
print sess.run(output, feed_dict = {input1:[3.], input2: [4.]})
tf.Variable
-
tf.Variable([1,2,3], initializer = init , name = 'va')
,先创建形状,在创建初始化,再创建name的方式。 -
tf.Variable(tf.truncated_normal([1,2,3], stddev =0.1))
:直接创建初始化:应该是最为方便的方式。 -
tf.Variable(tf.constant(0.1 , shape =[1,2,3]))
:也是直接创建初始化的一种形式,只不过是直接使用常数进行初始化。 -
global_step = tf.Variable(0 , trainable = False)
:创建一个用于记录的不可训练的变量。 - 下面这两个定义是等价的,常数初始化函数
tf.constant_initializer
和常数生成函数tf.constant
在功能上是一致的。
v = tf.get_variable('v', shape =[1], initializer = tf.constant_initializer(1.0))
v = tf.Variable(tf.constant(1.0 , shape =[1], name = 'v')
tf.get_variable 不仅可以创建变量,也可以用来获取变量。
tf.get_variable中变量名称是一个必填的参数,这个函数会根据这个名字常见或获取变量,如果创建失败(有同名的参数),那么程序就会报错,这是为了避免无意识的变量复用造成的错误。
-
tf.get_variable('conv_1',initializer = tf.random_normal(shape=[1,2,3],minval=0.4,maxval=1.4))
一般都是和tf.variable_scope()
配合使用,从而实现变量共享的功能。 -
tf.name_scope()
并不会对tf.get_variable()
创建的变量有任何影响。 即在name_scope('hello')内部使用 get_variable() 中定义的 variable ,这个variable的 name 并没有 “hello/”前缀。 -
tf.name_scope()
主要是用来管理命名空间的,这样子让我们的整个模型更加有条理。而tf.variable_scope()
的作用是为了实现变量共享,它和tf.get_variable()
来完成变量共享的功能,tf.name_scope()
可以和with tf.variable_scope():
联合使用,用于给非get_variable
创建的变量加上联合命名空间。
with tf.name_scope("name1"):
with tf.variable_scope("var1"):
w = tf.get_variable("w",shape=[2])
res = tf.add(w,[3])
>>var1/w:0
name1/var1/Add:0
-
tf.trainable_variables()
获取所有的可训练的变量,默认的是tf.variable
和tf.get_variable()
创建的。
vs = tf.trainable_variables()
print 'There are %d train_able_variables in the Graph: ' % len(vs)
for v in vs:
with tf.name_scope('nsc1'):
v1 = tf.Variable([1], name='v1')
with tf.variable_scope('vsc1'):
v2 = tf.Variable([1], name='v2')
v3 = tf.get_variable(name='v3', shape=[])
print ('v1.name: ', v1.name)
print ('v2.name: ', v2.name)
print ('v3.name: ', v3.name)
>>v1.name: nsc1/v1:0
v2.name: nsc1/vsc1/v2:0
v3.name: vsc1/v3:0
一个例子比较variable()和get_ variable()
- variable可以看到 重复命名的,后面使用标号_1进行区分。
import tensorflow as tf
# 设置GPU按需增长
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
# 拿官方的例子改动一下
def my_image_filter():
conv1_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),
name="conv1_weights")
conv1_biases = tf.Variable(tf.zeros([32]), name="conv1_biases")
conv2_weights = tf.Variable(tf.random_normal([5, 5, 32, 32]),
name="conv2_weights")
conv2_biases = tf.Variable(tf.zeros([32]), name="conv2_biases")
return None
# First call creates one set of 4 variables.
result1 = my_image_filter()
# Another set of 4 variables is created in the second call.
result2 = my_image_filter()
# 获取所有的可训练变量
vs = tf.trainable_variables()
print 'There are %d train_able_variables in the Graph: ' % len(vs)
for v in vs:
print v
>>There are 8 train_able_variables in the Graph:
Tensor("conv1_weights/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("conv1_biases/read:0", shape=(32,), dtype=float32)
Tensor("conv2_weights/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("conv2_biases/read:0", shape=(32,), dtype=float32)
Tensor("conv1_weights_1/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("conv1_biases_1/read:0", shape=(32,), dtype=float32)
Tensor("conv2_weights_1/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("conv2_biases_1/read:0", shape=(32,), dtype=float32)
-
tf.get_variable() 可以使用scope.reuse_variables()来重用变量,除了使用这个函数还可以在
with tf.variable_scope("image_filters",reuse=True) as scope:
中直接变量重用。
import tensorflow as tf
# 设置GPU按需增长
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
sess = tf.Session(config=config)
# 下面是定义一个卷积层的通用方式
def conv_relu(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))
return None
def my_image_filter():
# 按照下面的方式定义卷积层,非常直观,而且富有层次感
with tf.variable_scope("conv1"):
# Variables created here will be named "conv1/weights", "conv1/biases".
relu1 = conv_relu([5, 5, 32, 32], [32])
with tf.variable_scope("conv2"):
# Variables created here will be named "conv2/weights", "conv2/biases".
return conv_relu( [5, 5, 32, 32], [32])
with tf.variable_scope("image_filters") as scope:
# 下面我们两次调用 my_image_filter 函数,但是由于引入了 变量共享机制
# 可以看到我们只是创建了一遍网络结构。
result1 = my_image_filter()
scope.reuse_variables()
result2 = my_image_filter()
# 看看下面,完美地实现了变量共享!!!
vs = tf.trainable_variables()
print 'There are %d train_able_variables in the Graph: ' % len(vs)
for v in vs:
print v
>>There are 4 train_able_variables in the Graph:
Tensor("image_filters/conv1/weights/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("image_filters/conv1/biases/read:0", shape=(32,), dtype=float32)
Tensor("image_filters/conv2/weights/read:0", shape=(5, 5, 32, 32), dtype=float32)
Tensor("image_filters/conv2/biases/read:0", shape=(32,), dtype=float32)
一个变量重用的例子
import tensorflow as tf
#在名字为foo的命名空间内创建名字为v的变量
with tf.variable_scope("foo"):
#创建一个常量为1的v
v= tf.get_variable('v',[1],initializer = tf.constant_initializer(1.0))
#因为在foo空间已经创建v的变量,所以下面的代码会报错
#with tf.variable_scope("foo"):
# v= tf.get_variable('v',[1])
#在生成上下文管理器时,将参数reuse设置为True。这样tf.get_variable的函数将直接获取已声明的变量
#且调用with tf.variable_scope("foo")必须是定义的foo空间,而不能是with tf.variable_scope("")未命名或者其他空间。
with tf.variable_scope("foo",reuse =True):
v1= tf.get_variable('v',[1])# 不写[1]也可以
print(v1==v) #输出为True,代表v1与v是相同的变量