2.2 TensorFlow变量管理

1. 变量的使用

相对于c语言,python语言简化了对于变量的声明以及初始化的过程,是因为python会自动根据变量初始值来选择变量类型。但是在TensorFlow中我们需要注意,变量声明和使用和c语言类似,在声明的过程中需要指明变量类型以及初始值等。
TensorFlow中的变量特指深度学习过程中,控制输入到输出映射的可以变化的数据,这些变化数据随着训练迭代的进行,不断地改变数值,不断优化,使输出的结果越来越接近于正确的结果。

1.1 变量的声明

tensorflow提供了两个变量声明的函数:tf.Variable() 和 tf.get_variable().在功能上两个都是等价的,都是声明一个变量。两者在形式上的区别是:前者只需要指明初始值,其他参数为可选参数;而后者必须指明name,shape,和初始值。前者比较简单,但是不能很好的与命名空间配合使用,后者能很方便的与命名空间配合使用。所以一般而言,推荐使用后者。
具体说说两者的区别:
tf.get_variable(“vname”)方法,在创建变量时,如果这个变量vname已经存在,直接使用这个变量,如果不存在,则重新创建;
tf.Variable()在创建变量时,一律创建新的变量,如果这个变量已存在,则后缀会增加0、1、2等数字编号予以区别。
也就是tf.Variable()不适用于变量共享,每次都会创建新的变量
典型例子:

a = tf.Variable(2.0)

weights = tf.get_variable('weights', [2,5], initializer=tf.truncated_normal_initializer(stddev=0.1))

1.2 变量的初始值

在声明变量的时候必须指明初始化该变量的方法,tensorflow提供了以下几种指明初始值的函数:
在这里插入图片描述

例如:

import tensorflow as tf

a = tf.get_variable('a', [2,5], initializer=tf.truncated_normal_initializer(stddev=0.1))
sess = tf.InteractiveSession()

init = tf.initialize_all_variables()
init.run()

b = sess.run(a)
print(b)

需要注意的是这里的指明初始值和后面的变量初始化函数有区别。tensorflow是符号式编程,变量的的声明只是指明了变量符号,在会话中的初始化函数才会真正的占用内存,分配数值。

1.3 变量的初始化

注意1.2中说过,前面所有在计算图中的操作都是定义计算图,并没有真正的运行。只有在会话中运行后才会真正的计算。同样,在会话中需要显式的初始化所有函数,一般采用一个函数初始化所有变量。

init = tf.initialize_all_variables()
init.run()

或者:
tf.initialize_all_variables().run()

或者:
sess.run( tf.initialize_all_variables())

当然,也可以根据需要合理的初始化变量, 例如只初始化a,b,c:

init_new = tf.initialize_variables([a,b,c])
sess.run(init_new)

1.4 变量值的引用

前面说过,tensorflow中的变量的数据结构是一个tensor,它反映的是计算,并不能直接得到计算的结果。如果要引用计算的结果,有两种方式:

sess.run(a)
或者:
a.run()    or   a.eval()

这两种方式的区别见上一节,一句话说就是没有显示指明默认图用前者,显示指明默认图后都可以使用。

2. 变量命名空间

tensorflow是深度学习框架,神经网络的一个特点是每一层之间的变量名都是重复的,比如都是:权重,偏置。每一层网络结构也都一样:cnn,fcn等,这个时候变量的命名就有很大的问题,比如30层网络的权重变量命名,总不能:

weight_1 = 
weight_2 = 
weight_3 =
...

weight_30 =  

这样管理起来很不方便。tensorflow中采用命名空间来管理变量。常用的两个函数为: tf.variable_scope(), tf.name_scope().
编写代码就是这种形式:

    with tf.variable_scope('cnn_layer1',reuse=reuse):
        weights, biases = init_variable([5,5,1,32],[32])
        cnn1_res = conv2d(x_img,weights,biases,1.0)

    # layer_2
    with tf.variable_scope('cnn_layer2',reuse=reuse):
        weights, biases = init_variable([3,3,32,64],[64])
        cnn2_res = conv2d(cnn1_res,weights, biases,1.0)

    # layer_3
    with tf.variable_scope('cnn_layer3',reuse=reuse):
        weights, biases = init_variable([3, 3, 64, 128], [128])
        cnn3_res = conv2d(cnn2_res, weights, biases, 1.0)
        cnn3_shape = cnn3_res.shape.as_list()[1:]
        h3_s = reduce(lambda x, y: x * y, cnn3_shape)
        cnn3_reshape = tf.reshape(cnn3_res,[-1,h3_s])

    # layer_4
    with tf.variable_scope('fcn1',reuse=reuse):
        weights, biases = init_variable([h3_s,5000],[5000],regularizer)
        fcn1_res = tf.nn.relu(tf.matmul(cnn3_reshape,weights)+biases)
        fcn1_dropout = tf.nn.dropout(fcn1_res,dropout)

这样不同层的时候一直可以使用weights作为2权重的变量名,因为受到tf.variable_scope()函数的约束。

tf.name_scope()和tf.variable_scope()是两个作用域,一般与两个创建/调用变量的函数tf.variable() 和tf.get_variable()搭配使用。它们搭配在一起的两个常见用途:1)变量共享,2)tensorboard画流程图时为了可视化封装变量[1]

2.1 变量共享

在测试网络的时候实际上是采用训练网络的结果,那么这个时候的参数必须使用训练网络的参数,这时候就涉及了变量共享的问题。一般采用这种形式:

def inference(x,reuse):
	#这里定义网络
def  train():
	#调用inference(x,False)
	inference(x,False)

def test():
	inference(x,True)

在训练的时候不共享变量,在测试的使用共享变量。
关于为什么要这么搭配使用参考文献:https://www.cnblogs.com/weizhen/p/6751792.html

2.2 tf.name_scope()和tf.variable_scope()的区别

命名域 (name scope),通过tf.name_scope 或 tf.op_scope创建;
变量域 (variable scope),通过tf.variable_scope 或 tf.variable_op_scope创建;
这两种作用域,对于使用tf.Variable()方式创建的变量,具有相同的效果,都会在变量名称前面,加上域名称。
对于通过tf.get_variable()方式创建的变量,只有variable scope名称会加到变量名称前面,而name scope不会作为前缀。

综上:tf.variable_scope()搭配tf.get_variable(“vname”)能达到变量共享,这也是推荐使用的一种方式。

3. 占位符和常量

3.1 占位符

tf.placeholder()函数定义:

def placeholder(dtype, shape=None, name=None)

dtype:表示tensorflow中的数据类型,如常用的tf.float32,tf.float64等数值类型;
shape:表示数据类型,默认的None是一个一维的数值,shape=[None,5],表示行不定,列是5;
name:张量名称;

placeholder()又叫占位符,用于声明一个张量的数据格式,告诉系统这里会有一个这种格式的张量,但是还没有给定具体数值,具体的数值要在正式运行的时候给到。占位变量是一种TensorFlow用来解决读取大量训练数据问题的机制,它允许你现在不用给它赋值,随着训练的开始,再把训练数据传送给训练网络学习[2]。
常用于网络的输入层输出定义,这两层是没有网络参数的更新:

X = tf.placeholder(tf.float32, shape = [None,32*32,3])

None表示该维度的大小不确定,因为我们会修改batch_size的大小,一帮我们定义为None,tensorflow会根据运行时候具体情况调整。

3.2 常量

TF中定义的常量一般为不可更改的张量,tf.constant()函数定义:

def constant(value, dtype=None, shape=None, name="Const", verify_shape=False)

value: 符合tf中定义的数据类型的常数值或者常数列表;
dtype:数据类型,可选;
shape:常量的形状,可选;
name:常量的名字,可选;
verify_shape:常量的形状是否可以被更改,默认不可更改;

例如:

a = tf.constant([1.9,3.0])

当然也还有tf.ones()、tf.zeros()等初始化张量的方法。

4. 总结

一句话总结前面提到的4个函数的关系:tf.variable_scope可以让变量有相同的命名,包括tf.get_variable得到的变量,还有tf.Variable的变量;tf.name_scope可以让变量有相同的命名,只是限于tf.Variable的变量

参考文献

[1] https://blog.csdn.net/gqixf/article/details/80191918
[2] https://blog.csdn.net/dcrmg/article/details/79016107

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值