Tensorflow变量及共享变量

Posted 我家大宝最可爱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tensorflow变量及共享变量相关的知识,希望对你有一定的参考价值。

1. TF为什么使用静态图

首先要说的是这里的tensorflow版本是1.x,2.x的我还没有仔细研究过
静态图意味着计算图的构建和实际计算是分开的,静态图会事先定义好整个运算流,这样之后再次运行的时候就不需要重新构建计算图了,因此速度会比动态图更快,从性能上来说会更加高效。但这也意味着程序和编译器执行期间存在着gap,代码的错误很难发现。无法向动态图一样随时可以获取中间结果。tensorflow就是先定义好整个计算流,然后再对数据进行计算。

a. 静态图

静态图其实就是两个部分,

  1. 把神经网络整个计算流图给搭建出来,从输入,到隐含层,到输出层
  2. 输入数据,数据在计算图中流转计算,输出最终结果

b.动态图

动态可以分为三个个部分

  1. 构建这一层的计算图
  2. 输入上一层获取的数据,计算这一层的数据,输出数据
  3. 循环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变量及共享变量的主要内容,如果未能解决你的问题,请参考以下文章

无法在TensorFlow中共享/重命名变量

TensorFlow学习笔记:共享变量

TensorFlow 变量作用域 变量管理 共享变量

TensorFlow——共享变量的使用方法

tensorflow中的共享变量(sharing variables)

tensorflow里面共享变量name_scope, variable_scope等如何理解