【TF-2-2】Tensorflow-变量作用域

目录

  1. 背景
  2. 简介
  3. name_scope
  4. variable_scope
  5. 实例

一、背景

通过tf.Variable我们可以创建变量,但是当模型复杂的时候,需要构建大量的变量集,这样会导致我们对于变量管理的复杂性,而且没法共享变量(存在多个相似的变量)。针对这个问题,可以通过TensorFlow提供的变量作用域机制来解决,在构建一个图的时候,就可以非常容易的使用共享命名的变量

二、简介

Tensorflow中有两个作用域,一个是name_scope,另一个是variable_scope

name_score的主要作用是为op_name前加前缀,variable_score是为get_variable创建的变量的名字前缀。简单来讲:使用tf.Variable创建的变量受name_score和variable_score的效果,会给变量添加前缀,但是使用tf.get_variable创建变量只受variable_score的效果。

注意:variable_score内部会创建一个同名的name_score

三、name_scope

用于为变量划分范围。在TensorFlow 中常常会有数以千计的节点,在可视化的过程中很难一下子展示出来,因此用 name_scope 为变量划分范围,在可视化中,这表示在计算图中的一个层级。name_scope会影响 op_name,不会影响用 get_variable()创建的变量,而会影响通过 Variable()创建的变量以及操作的名称,给他们添加一个前缀。

四、variable_scope

变量作用域机制在TensorFlow中主要通过两部分组成:tf.get_variable和tf.variable_scope

v = tf.get_variable(name, shape, dtype, initializer) # 通过所给的名字创建或是返回一个变量

tf.variable_scope(<scope_name>) # 为变量指定命名空间

4.1 tf.get_variable

通过所给定的名字创建或者返回一个对应的变量,这个方法在建立新的变量时与tf.Variable()完全相同。

  • tf.Variable()在定义的时候必须初始化,而tf.get_variable()定义的时候可以先不进行初始化操作。
  • 想要进行变量共享,必须使用tf.get_variable()实现,搭配命名空间,以及reuse关键字的使用,就可以实现变量的共享;而tf.Variable()每次都会生成一个新的变量。

tf.get_variable方法在调用的时候,主要需要给定参数名称name,形状shape,数据类型dtype以及初始化方式initializer四个参数,前两个参数是必须的。

  • tf.get_variable常用的initializer初始化器:

初始化器

描述

tf.constant_initializer(value)

初始化为给定的常数值value

tf.random_uniform_initializer(a, b)

初始化为从a到b的均匀分布的随机值

tf.random_normal_initializer(mean, stddev)

初始化为均值为mean、 方差为stddev的服从高斯分布的随机值

tf.orthogonal_initializer(gini=1.0)

初始化一个正交矩阵, gini参数作用是最终返回的矩阵是随机矩阵乘以gini的结果

tf.identity_initializer(gini=1.0)

初始化一个单位矩阵, gini参数作用是最终返回的矩阵是随机矩阵乘以gini的结果

简单代码:

import tensorflow as tf
with tf.variable_scope("foo"):
v = tf.get_variable("v",[1],initializer=tf.constant_initializer(1.0))
print(v.name)

with tf.variable_scope("la"):
with tf.variable_scope("bar"):
v1 = tf.get_variable("v",[1])
print(v1.name);
with tf.variable_scope("b"):
v2=tf.get_variable("c",[1])
print(v2.name)
with tf.variable_scope(""):
v2 = tf.get_variable("foo/c", [1])
print(v2.name)

结果:

foo/v:0

la/bar/v:0

la/bar/b/c:0

foo/c:0

4.2 tf.variable_scope

为通过创建的变量或者操作指定命名空间。它会管理在名为scope_name的域(scope)下传递给tf.get_variable的所有变量名(组成了一个变量空间),根据规则确定这些变量是否进行复用。这个方法最重要的参数是reuse,有None,tf.AUTO_REUSE与True三个选项。

当reuse值为False(不允许设置):作用域就是创建新变量设置的,此时要求对应的变量不存在,否则报错;

with tf.variable_scope("foo"):

v = tf.get_variable("v", [1])

v2 = tf.get_variable("v", [1])#这里v变量已经定义过了,所以会报错

assert v.name == "foo/v:0"

当reuse值为True:作用域就是为重用变量所设置的,此时要求对应的变量必须存在,否则报错。

当reuse的值为tf.AUTO_REUSE的时候,表示如果变量存在就重用变量,如果变量不存在,就创建新变量返回。(备注:reuse一般设置在variable score对象上)

  • tf.variable_score方法的作用就是定义一个作用域,定义在variable_score作用域中的变量和操作,会将variable score的名称作为前缀添加到变量/操作名称前,支持嵌套的作用域,添加前缀规则和文件目录路径的规则类似。
  • tf.variable_score参数如果给定的是一个已经存在的作用域对象的时候,那么构建变量的时候表示直接跳过当前作用域前缀,直接成为一个完全不同与现在的作用域(直接创建给定作用域下的变量)。但是构建操作的时候,还是和嵌套的方式一样,直接添加子作用域。
  • tf.variable_score参数中,可以给定当前作用域中默认的初始化器initializer,并且子作用域会直接继承父作用域的相关参数(是否重用、默认初始化器等)

五、实例

推荐方式二,代码如下:

    1 	def my_func(x):
    2 	    # initializer:初始化器
    3 	    # w = tf.Variable(tf.random_normal([1]), name='w')[0]
    4 	    # b = tf.Variable(tf.random_normal([1]), name='b')[0]
    5 	    w = tf.get_variable(name='w', shape=[1], initializer=tf.random_normal_initializer())[0]
    6 	    b = tf.get_variable(name='b', shape=[1], initializer=tf.random_normal_initializer())[0]
    7 	    r = w * x + b
    8 	    return r, w, b
    9 	def func(x):
   10 	    with tf.variable_scope('op1', reuse=tf.AUTO_REUSE):
   11 	        r1 = my_func(x)
   12 	    return r1
   13 	# 下面两行代码还是属于图的构建
   14 	x1 = tf.constant(3, dtype=tf.float32, name='x1')
   15 	with tf.variable_scope('func1'):
   16 	    r1 = func(x1)
   17 	with tf.Session(config=tf.ConfigProto(log_device_placement=True, allow_soft_placement=True)) as sess:
   18 	    tf.global_variables_initializer().run()  # 初始化
   19 	    print(sess.run(r1))      # 执行结果
   20 

  

posted @ 2020-03-16 23:14  忆凡人生  阅读(812)  评论(0编辑  收藏  举报