尽管tensorflow支持 name_scope 和 Variable,但更推荐使用 variable_scope 和 get_variable,这么做方便进行变量名称管理和实现权值变量共享
1 tf.name_scope()
with tf.name_scope('ns1') as ns:
ns_v1 = tf.Variable(initial_value=[1.0], name='v')
ns_gv1 = tf.get_variable(name='v', shape=[2,3])
ns_v2 = tf.Variable(initial_value=[1.0], name='v')
print('ns_v1', ns_v1)
print('ns_gv1', ns_gv1)
print('ns_v2', ns_v2)
ns_v1 <tf.Variable 'ns1/v:0' shape=(1,) dtype=float32_ref> ns_gv1 <tf.Variable 'v:0' shape=(2, 3) dtype=float32_ref> ns_v2 <tf.Variable 'ns1/v_1:0' shape=(1,) dtype=float32_ref>
结果:在 tf.name_scope() 里边:
- 使用 tf.Variable() 创建的变量,会自动地在 name 前面加上 scope name
- 使用 tf.get_variable() 创建的变量,并不受 name_scope 的影响
2 tf.variable_scope()
with tf.variable_scope('vs1') as vs:
vs_v1 = tf.Variable(initial_value=[1.0], name='v')
vs_gv1 = tf.get_variable(name='v', shape=[2,3])
print('vs_v1', vs_v1)
print('vs_gv1', vs_gv1)
vs_v1 <tf.Variable 'vs1/v:0' shape=(1,) dtype=float32_ref> vs_gv1 <tf.Variable 'vs1/v_1:0' shape=(2, 3) dtype=float32_ref>
可以看到 tf.variable_scope 和 tf.name_scope 的区别:
使用 tf.Variable() 和使用 tf.get_variable() 创建的变量,都会自动地在 name 前面加上 variable scope name
3 reuse 实现变量共享
在开始之前,先来看看 python 中怎么判断两个变量指向的对象是不是一样的。我们直接使用 is 关键字来判断就行了,注意不能使用 == 来判断,和 java, C++ 中不同,python 中的 == 只是判断左右两边的内容是否一致,而不是判断左右两边是不是同一个对象。
a = [1,2,3]
b = [1,2,3]
c = a
print('a is b: ', a is b)
print('a is c: ', a is c)
c[0] = 555 # 修改 c,a也会变化:因为 a 和 c 指向同一个对象
b[1] = 666 # 修改 b, a不受影响:因为 a 和 b 指向两个不同的对象
print('a:', a)
print('b:', b)
print('c:', c)
a is b: False
a is c: True
a: [555, 2, 3]
b: [1, 666, 3]
c: [555, 2, 3]
上面的结果显示,a 和 c 是指向内存中的同一个对象的,如果修改c的内容,a 也会一起变。而 b 虽然和 a 的内容一模一样,但是他们并不是一个对象,如果修改 b 的内容,并不会影响到 a。
在 TensorFlow 中,我们是通过变量的 name 来区别不同的对象。 tf.variable_scope() 中的 reuse 就是是我们为了实现变量的共享。
在上面,我们已经创建了一个 variable_scope 它的 name='vs1';在 'vs1' 里边,我们创建了一个变量:name='v'.
with tf.variable_scope('vs1') as vs:
vs_gv2 = tf.get_variable(name='v2', shape=[2,3])
print('vs_gv2', vs_gv2)
with tf.variable_scope('vs1', reuse=True) as vs:
vs_gv3 = tf.get_variable(name='v', shape=[2,3])
print('vs_gv3', vs_gv3)
print('vs_gv3 is vs_gv1: ', vs_gv3 is vs_gv1)
vs_gv2 <tf.Variable 'vs1/v2:0' shape=(2, 3) dtype=float32_ref> vs_gv3 <tf.Variable 'vs1/v_1:0' shape=(2, 3) dtype=float32_ref> vs_gv3 is vs_gv1: True
上面发现了没有,当我们要在同一个 variable_scope 下面‘定义’一个已经存在的变量 name='v' 的时候,需要设置 reuse=True,实际上两次‘定义’指向同一个内存对象。
4 实例
def fc(X, out_size):
in_size = X.shape[1]
W = tf.get_variable('weight', shape=[in_size, out_size], initializer=tf.truncated_normal_initializer())
b = tf.get_variable('bias', shape=[out_size],initializer=tf.zeros_initializer())
h_fc = tf.nn.relu(tf.nn.xw_plus_b(X,W,b), name='relu')
return h_fc
batch_size = 128
feature_size = 50
fc1_size = 64
fc2_size = 32
X_input = tf.placeholder(dtype=tf.float32, shape=[batch_size, feature_size], name='X_input')
with tf.variable_scope('fc1') as vs:
h_fc1 = fc(X_input, out_size=fc1_size)
with tf.variable_scope('fc2') as vs:
h_fc2 = fc(h_fc1, out_size=fc2_size)
all_vars = tf.global_variables()
for i in range(len(all_vars)):
print('var {}:'. format(i), all_vars[i])
var 0: <tf.Variable 'fc1/weight:0' shape=(50, 64) dtype=float32_ref> var 1: <tf.Variable 'fc1/bias:0' shape=(64,) dtype=float32_ref> var 2: <tf.Variable 'fc2/weight:0' shape=(64, 32) dtype=float32_ref> var 3: <tf.Variable 'fc2/bias:0' shape=(32,) dtype=float32_ref>
在神经网络的结构定义的时候,我们应该养成比较好的习惯,在定义每个层的时候都放在一个 tf.variable_scope() 里边。
在定义整个模型的时候,也应该把整个模型放在一个 tf.variable_scope('your_model_name') 里边,这样做有个好处就是后期你想要微调某些层或者把多个小模型联合成一个大模型的时候都可以很轻松地实现。