TENSORFLOW变量作用域(VARIABLE SCOPE)


Posted in Python onJanuary 10, 2020

举例说明

TensorFlow中的变量一般就是模型的参数。当模型复杂的时候共享变量会无比复杂。

官网给了一个case,当创建两层卷积的过滤器时,每输入一次图片就会创建一次过滤器对应的变量,但是我们希望所有图片都共享同一过滤器变量,一共有4个变量:conv1_weights,conv1_biases,conv2_weights, and conv2_biases。

通常的做法是将这些变量设置为全局变量。但是存在的问题是打破封装性,这些变量必须文档化被其他代码文件引用,一旦代码变化,调用方也可能需要变化。

还有一种保证封装性的方式是将模型封装成类。

不过TensorFlow提供了Variable Scope 这种独特的机制来共享变量。这个机制涉及两个主要函数:

tf.get_variable(<name>, <shape>, <initializer>) 创建或返回给定名称的变量
tf.variable_scope(<scope_name>) 管理传给get_variable()的变量名称的作用域

在下面的代码中,通过tf.get_variable()创建了名称分别为weights和biases的两个变量。

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)

但是我们需要两个卷积层,这时可以通过tf.variable_scope()指定作用域进行区分,如with tf.variable_scope("conv1")这行代码指定了第一个卷积层作用域为conv1,

在这个作用域下有两个变量weights和biases。

def my_image_filter(input_images):
  with tf.variable_scope("conv1"):
    # Variables created here will be named "conv1/weights", "conv1/biases".
    relu1 = conv_relu(input_images, [5, 5, 32, 32], [32])
  with tf.variable_scope("conv2"):
    # Variables created here will be named "conv2/weights", "conv2/biases".
    return conv_relu(relu1, [5, 5, 32, 32], [32])

最后在image_filters这个作用域重复使用第一张图片输入时创建的变量,调用函数reuse_variables(),代码如下:

with tf.variable_scope("image_filters") as scope:
  result1 = my_image_filter(image1)
  scope.reuse_variables()
  result2 = my_image_filter(image2)

tf.get_variable()工作机制

tf.get_variable()工作机制是这样的:

当tf.get_variable_scope().reuse == False,调用该函数会创建新的变量

with tf.variable_scope("foo"):
  v = tf.get_variable("v", [1])
assert v.name == "foo/v:0"

当tf.get_variable_scope().reuse == True,调用该函数会重用已经创建的变量

with tf.variable_scope("foo"):
  v = tf.get_variable("v", [1])
with tf.variable_scope("foo", reuse=True):
  v1 = tf.get_variable("v", [1])
assert v1 is v

变量都是通过作用域/变量名来标识,后面会看到作用域可以像文件路径一样嵌套。

tf.variable_scope理解

tf.variable_scope()用来指定变量的作用域,作为变量名的前缀,支持嵌套,如下:

with tf.variable_scope("foo"):
  with tf.variable_scope("bar"):
    v = tf.get_variable("v", [1])
assert v.name == "foo/bar/v:0"

当前环境的作用域可以通过函数tf.get_variable_scope()获取,并且reuse标志可以通过调用reuse_variables()设置为True,这个非常有用,如下

with tf.variable_scope("foo"):
  v = tf.get_variable("v", [1])
  tf.get_variable_scope().reuse_variables()
  v1 = tf.get_variable("v", [1])
assert v1 is v

作用域中的resuse默认是False,调用函数reuse_variables()可设置为True,一旦设置为True,就不能返回到False,并且该作用域的子空间reuse都是True。如果不想重用变量,那么可以退回到上层作用域,相当于exit当前作用域,如

with tf.variable_scope("root"):
  # At start, the scope is not reusing.
  assert tf.get_variable_scope().reuse == False
  with tf.variable_scope("foo"):
    # Opened a sub-scope, still not reusing.
    assert tf.get_variable_scope().reuse == False
  with tf.variable_scope("foo", reuse=True):
    # Explicitly opened a reusing scope.
    assert tf.get_variable_scope().reuse == True
    with tf.variable_scope("bar"):
      # Now sub-scope inherits the reuse flag.
      assert tf.get_variable_scope().reuse == True
  # Exited the reusing scope, back to a non-reusing one.
  assert tf.get_variable_scope().reuse == False

一个作用域可以作为另一个新的作用域的参数,如:

with tf.variable_scope("foo") as foo_scope:
  v = tf.get_variable("v", [1])
with tf.variable_scope(foo_scope):
  w = tf.get_variable("w", [1])
with tf.variable_scope(foo_scope, reuse=True):
  v1 = tf.get_variable("v", [1])
  w1 = tf.get_variable("w", [1])
assert v1 is v
assert w1 is w

不管作用域如何嵌套,当使用with tf.variable_scope()打开一个已经存在的作用域时,就会跳转到这个作用域。

with tf.variable_scope("foo") as foo_scope:
  assert foo_scope.name == "foo"
with tf.variable_scope("bar"):
  with tf.variable_scope("baz") as other_scope:
    assert other_scope.name == "bar/baz"
    with tf.variable_scope(foo_scope) as foo_scope2:
      assert foo_scope2.name == "foo" # Not changed.

variable scope的Initializers可以创递给子空间和tf.get_variable()函数,除非中间有函数改变,否则不变。

with tf.variable_scope("foo", initializer=tf.constant_initializer(0.4)):
  v = tf.get_variable("v", [1])
  assert v.eval() == 0.4 # Default initializer as set above.
  w = tf.get_variable("w", [1], initializer=tf.constant_initializer(0.3)):
  assert w.eval() == 0.3 # Specific initializer overrides the default.
  with tf.variable_scope("bar"):
    v = tf.get_variable("v", [1])
    assert v.eval() == 0.4 # Inherited default initializer.
  with tf.variable_scope("baz", initializer=tf.constant_initializer(0.2)):
    v = tf.get_variable("v", [1])
    assert v.eval() == 0.2 # Changed default initializer.

算子(ops)会受变量作用域(variable scope)影响,相当于隐式地打开了同名的名称作用域(name scope),如+这个算子的名称为foo/add

with tf.variable_scope("foo"):
  x = 1.0 + tf.get_variable("v", [1])
assert x.op.name == "foo/add"

除了变量作用域(variable scope),还可以显式打开名称作用域(name scope),名称作用域仅仅影响算子的名称,不影响变量的名称。另外如果tf.variable_scope()传入字符参数,创建变量作用域的同时会隐式创建同名的名称作用域。如下面的例子,变量v的作用域是foo,而算子x的算子变为foo/bar,因为有隐式创建名称作用域foo

with tf.variable_scope("foo"):
  with tf.name_scope("bar"):
    v = tf.get_variable("v", [1])
    x = 1.0 + v
assert v.name == "foo/v:0"
assert x.op.name == "foo/bar/add"

注意: 如果tf.variable_scope()传入的不是字符串而是scope对象,则不会隐式创建同名的名称作用域。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python3.3教程之模拟百度登陆代码分享
Jan 16 Python
Python实现扫描局域网活动ip(扫描在线电脑)
Apr 28 Python
在Python中用get()方法获取字典键值的教程
May 21 Python
python文本数据相似度的度量
Mar 12 Python
浅析python的优势和不足之处
Nov 20 Python
Python3爬虫学习之将爬取的信息保存到本地的方法详解
Dec 12 Python
使用urllib库的urlretrieve()方法下载网络文件到本地的方法
Dec 19 Python
Python 3.8 新功能全解
Jul 25 Python
python 实现识别图片上的数字
Jul 30 Python
在keras中model.fit_generator()和model.fit()的区别说明
Jun 17 Python
python实现企业微信定时发送文本消息的示例代码
Nov 24 Python
python opencv将多个图放在一个窗口的实例详解
Feb 28 Python
python numpy数组复制使用实例解析
Jan 10 #Python
关于Pytorch的MNIST数据集的预处理详解
Jan 10 #Python
详解pycharm连接不上mysql数据库的解决办法
Jan 10 #Python
pycharm双击无响应(打不开问题解决办法)
Jan 10 #Python
python ubplot使用方法解析
Jan 10 #Python
Pytorch使用MNIST数据集实现基础GAN和DCGAN详解
Jan 10 #Python
Pytorch使用MNIST数据集实现CGAN和生成指定的数字方式
Jan 10 #Python
You might like
教你如何使用php session
2013/10/28 PHP
PHP中将一个字符串部分字符用星号*替代隐藏的实现代码
2019/09/08 PHP
解决在laravel中auth建立时候遇到的问题
2019/10/15 PHP
js实现仿MSN带关闭功能的右下角弹窗代码
2015/09/04 Javascript
分享我的jquery实现下拉菜单心的
2015/11/29 Javascript
深入分析jQuery的ready函数是如何工作的(工作原理)
2015/12/17 Javascript
Angularjs 动态改变title标题(兼容ios)
2016/12/29 Javascript
vue2.0使用Sortable.js实现的拖拽功能示例
2017/02/21 Javascript
细说webpack源码之compile流程-rules参数处理技巧(2)
2017/12/26 Javascript
vue 中引用gojs绘制E-R图的方法示例
2018/08/24 Javascript
微信小程序开发之自定义tabBar的实现
2018/09/06 Javascript
vue项目开发中setTimeout等定时器的管理问题
2018/09/13 Javascript
vue-autoui自匹配webapi的UI控件的实现
2020/03/20 Javascript
浅谈vue websocket nodeJS 进行实时通信踩到的坑
2020/09/22 NodeJs
解决vue数据不实时更新的问题(数据更改了,但数据不实时更新)
2020/10/27 Javascript
基于Python列表解析(列表推导式)
2018/06/23 Python
python运行时强制刷新缓冲区的方法
2019/01/14 Python
python 实现在一张图中绘制一个小的子图方法
2019/07/07 Python
对Django中的权限和分组管理实例讲解
2019/08/16 Python
python用TensorFlow做图像识别的实现
2020/04/21 Python
tensorflow从ckpt和从.pb文件读取变量的值方式
2020/05/26 Python
Python在后台自动解压各种压缩文件的实现方法
2020/11/10 Python
css3制作动态进度条以及附加jQuery百分比数字显示
2012/12/13 HTML / CSS
高级Java程序员面试题
2016/06/23 面试题
生物专业个人自荐信范文
2013/11/29 职场文书
预备党员思想汇报
2014/01/08 职场文书
运动会解说词50字
2014/01/18 职场文书
宾馆总经理岗位职责
2014/02/14 职场文书
《植物妈妈有办法》教学反思
2014/02/25 职场文书
项目投资建议书
2014/05/16 职场文书
个人总结与自我评价
2015/02/14 职场文书
部门优秀员工推荐信
2015/03/24 职场文书
工作推荐信模板
2015/03/25 职场文书
公司员工管理制度
2015/08/04 职场文书
端午节将至,用Python爬取粽子数据并可视化,看看网友喜欢哪种粽子吧!
2021/06/11 Python
golang三种设计模式之简单工厂、方法工厂和抽象工厂
2022/04/10 Golang