Tensorflow变量及共享变量
Posted 我家大宝最可爱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tensorflow变量及共享变量相关的知识,希望对你有一定的参考价值。
1. TF为什么使用静态图
首先要说的是这里的tensorflow版本是1.x,2.x的我还没有仔细研究过
静态图意味着计算图的构建和实际计算是分开的,静态图会事先定义好整个运算流,这样之后再次运行的时候就不需要重新构建计算图了,因此速度会比动态图更快,从性能上来说会更加高效。但这也意味着程序和编译器执行期间存在着gap,代码的错误很难发现。无法向动态图一样随时可以获取中间结果。tensorflow就是先定义好整个计算流,然后再对数据进行计算。
a. 静态图
静态图其实就是两个部分,
- 把神经网络整个计算流图给搭建出来,从输入,到隐含层,到输出层
- 输入数据,数据在计算图中流转计算,输出最终结果
b.动态图
动态可以分为三个个部分
- 构建这一层的计算图
- 输入上一层获取的数据,计算这一层的数据,输出数据
- 循环1,2,3步,直到输出层
动态不是一次性搭建初计算图,一次性计算数据的,而是每搭建一层,计算着一层的输出,我们可以随时获取计算过的每一层的数据,这是跟
2. 为什么会产生variable_scope
首先看一下tensorflow变量产生的过程,我们定义了两个变量,他们的name都是weights
import tensorflow as tf
w1 = tf.Variable(tf.random_normal([784,200], stddev = 0.35), name="weights")
w2 = tf.Variable(tf.random_normal([784,200], stddev = 0.35), name="weights") # 名称相同
print(w1.name,w2.name)
weights:0 weights_1:0
可以看到,tensorflow会自动相同名字的变量进行修改,默认在后面添加数字进行区分,其实这也说明tf.Variable每次产生的都是新的变量。即使用户定义了相同的名字,tf也会在内部进行修改,重新创建变量。
这就会产生一个问题,我们没有办法使用同一个变量。考虑这样一个网络,输入两幅图片,判断两个图片的相似性。基于这个问题,我们可以搭建如下网络,两个图像共享同一个编码层,然后编码后的数据通过mse进行打分,mse差值越小说明两个图片越相似。
然后我们使用tf来实现这个网络
import warnings
warnings.filterwarnings("ignore", message=r"Passing", category=FutureWarning)
import tensorflow as tf
import numpy as np
def conv_relu(input, kernel_shape, bias_shape):
weights = tf.Variable(tf.random_normal(kernel_shape),name="weights")
biases = tf.Variable(tf.zeros(bias_shape), name="biases")
conv = tf.nn.conv2d(input, weights, strides=[1, 1, 1, 1], padding='SAME')
relu = tf.nn.relu(conv + biases)
return relu
input_image1 = tf.placeholder(tf.float32,shape=(None,None,None,3))
input_image2 = tf.placeholder(tf.float32,shape=(None,None,None,3))
relu1 = conv_relu(input_image1,[5, 5, 3, 32], [32])
relu2 = conv_relu(input_image2,[5, 5, 3, 32], [32])
loss = tf.reduce_mean(tf.squared_difference(relu1, relu2))
init_g = tf.global_variables_initializer()
init_l = tf.local_variables_initializer()
with tf.Session() as sess:
sess.run(init_g)
sess.run(init_l)
image1 = np.random.rand(1,100, 100, 3)
image2 = np.random.rand(1,100, 100, 3)
print(sess.run(loss,feed_dict = {input_image1 : image1,input_image2 : image2}))
print(tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES))
16.021566
[
<tf.Variable ‘weights:0’ shape=(5, 5, 3, 32) dtype=float32_ref>,
<tf.Variable ‘biases:0’ shape=(32,) dtype=float32_ref>,
<tf.Variable ‘weights_1:0’ shape=(5, 5, 3, 32) dtype=float32_ref>,
<tf.Variable ‘biases_1:0’ shape=(32,) dtype=float32_ref>
]
看到什么问题没有,总共有4个变量,一个CNN明明只有两个变量,为什么现在变成了4个,这相当于我们创建了并行的两个CNN层了,并没有共享同一层
多么的可怕啊,程序完全没有按照我们的想法去运行。造成这个的原因就是因为每次调用tf.Variable时会创建一个新的变量。要解决这个问题我们得使用tf.get_variable。tf.get_variable创建变量时,如果指定的变量名已经存在(即先前已经用同一个变量名通过get_variable()函数实例化了变量),那么get_variable()只会返回之前的变量,否则才创造新的变量。
import warnings
warnings.filterwarnings("ignore", message=r"Passing", category=FutureWarning)
import tensorflow as tf
import numpy as np
# 使用tf.get_variable创建变量
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)
input_image1 = tf.placeholder(tf.float32,shape=(None,None,None,3))
input_image2 = tf.placeholder(tf.float32,shape=(None,None,None,3))
relu1 = conv_relu(input_image1,[5, 5, 3, 32], [32])
relu2 = conv_relu(input_image2,[5, 5, 3, 32], [32])
loss = tf.reduce_mean(tf.squared_difference(relu1, relu2))
init_g = tf.global_variables_initializer()
init_l = tf.local_variables_initializer()
with tf.Session() as sess:
sess.run(init_g)
sess.run(init_l)
image1 = np.random.rand(1,100, 100, 3)
image2 = np.random.rand(1,100, 100, 3)
print(sess.run(loss,feed_dict = {input_image1 : image1,input_image2 : image2}))
print(tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES))
最后报了一个错误sad
ValueError: Variable weights already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope? Originally defined at:
意思是这个变量已经存在了,再次创建的时候就会报错。
get_variable()创建两个相同名字的变量是会报错的,默认上它只是检查变量名,防止重复,如果要变量共享,就需要指定在哪个域名内可以共享变量。
看到没有,如果要共享变量,那么就需要指定共享域,那么该如何来指定呢?
3. tf.variable_scope使用
当参数reuse=False,函数tf.get_variable()表示创建变量,如果之前创建了这个变量,则会报错
import tensorflow as tf
with tf.variable_scope("foo", reuse=False):
v = tf.get_variable("v", [1], initializer=tf.constant_initializer(1.0))
v1 = tf.get_variable("v", [1])
# 输出结果:
# ValueError: Variable foo/v already exists, disallowed.
# Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope?
当参数reuse=True,函数tf.get_variable()表示获取变量,如果之前没有创建这个变量,则会报错
import tensorflow as tf
with tf.variable_scope("foo"):
v = tf.get_variable("v", [1], initializer=tf.constant_initializer(1.0))
with tf.variable_scope("foo", reuse=True):
v1 = tf.get_variable("v", [1])
print(v1 == v)
# 输出结果:True
如果直接手动控制tf.variable_scope会非常的麻烦。每次都需要在第一次创建的时候指定reuse=Fasle,之后再指定reuse=True。tf提供了tf.AUTO_REUSE参数,让我们只设置一次即可
with tf.variable_scope('foo', reuse=tf.AUTO_REUSE):
v = tf.get_variable('v', [1])
v1 = tf.get_variable('v')
重写一下之前的代码,是的,只需要添加一行代码就行
def conv_relu(input, kernel_shape, bias_shape):
with tf.variable_scope('share_cnn', reuse=tf.AUTO_REUSE):
# 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)
4.2909775
[
<tf.Variable ‘share_cnn/weights:0’ shape=(5, 5, 3, 32) dtype=float32_ref>,
<tf.Variable ‘share_cnn/biases:0’ shape=(32,) dtype=float32_ref>
]
可以看到这次就只有两个变量了,说明两个图像共享了同一个CNN编码层了。
以上是关于Tensorflow变量及共享变量的主要内容,如果未能解决你的问题,请参考以下文章