Tensorflow代码学习:变量及共享变量

1. TF中变量的定义

在tf中定义变量有两种方式,一种是 tf.Variable()和tf.get_variable(),首先看一下 tf.Variable()
我们定义了两个变量,他们的name都是weights

import tensorflow as tf

def NN(x_input,n_input,n_output):
    weight = tf.Variable(tf.random_normal([n_input, n_output]),name="weight") # n_input x n_output
    bias = tf.Variable(tf.random_normal([n_output]),name="bias") # n_output
    out = tf.add(tf.matmul(x_input, weight), bias) # batch_size x n_output
    return out

x_input = tf.constant([[1.0,2.0,3.0],[4.0,5.0,6.0]]) # shape = batch_size x n_input

output = NN(x_input,3,2) # 2 x 2
output1 = NN(output,2,1) # 2 x 1

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(output1))
    print(tf.trainable_variables())
    # <tf.Variable 'weight:0' shape=(3, 2) dtype=float32_ref>,
    # <tf.Variable 'bias:0' shape=(2,) dtype=float32_ref>, 
    # <tf.Variable 'weight_1:0' shape=(2, 1) dtype=float32_ref>, 
    # <tf.Variable 'bias_1:0' shape=(1,) dtype=float32_ref>

weights:0 weights_1:0

可以看到,tensorflow会自动相同名字的变量进行修改,默认在后面添加数字进行区分,其实这也说明tf.Variable每次产生的都是新的变量。即使用户定义了相同的名字,tf也会在内部进行修改,重新创建变量。我们创建简单的神经网络的时候只使用tf.Variable也是没有问题的,因为每一层网络的变量都是不同的,都需要创建新的变量。但是当我们明确要使用同一个变量的时候,就会出现问题。

2. 为什么会产生variable_scope

考虑这样一个网络,输入两幅图片,判断两个图片的相似性。基于这个问题,我们可以搭建如下网络,两个图像共享同一个编码层,然后编码后的数据通过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编码层了。

training参数

当进行神经网络训练时,有些变量是机器学习训练的参数如 weight 和 bias ,它们的值会在训练过程中在梯度更新的时候发生改变,而有些值不属于机器学习训练的参数如训练步数 step ,学习率等我们不希望这些值在梯度更新的时候改变。
指定参数trainable是True还是False决定训练过程中定义变量的值是否被更新。若参数trainable的值是True,变量的值在训练过程中可以被修改,变量会被添加到GraphKeys.TRAINABLE_VARIABLES中,我们可以通过trainable_variables()函数来获取所有的trainable为True的变量。如果参数trainable的值是False,则训练过程中变量的值不能被改编。在使用Tensorflow的优化方法的优化器来对神经网络的参数进行优化的时候,只会优化那些trainable为True的变量。
变量的trainable默认为True。一般权重weight、偏置bias在训练过程中是可优化的,而如果我们要记录训练的步数step,一般设置其trainable为False,表示该变量在训练过程中不会被优化器改变。

1. TF为什么使用静态图

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

Tensorflow学习笔记(2): 变量及共享变量
TensorFlow——共享变量的使用方法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值