Tensorflow是一个编程模型,几乎成为了一种编程语言(里面有变量、有操作......)。

Tensorflow编程分为两个阶段:构图阶段+运行时。

Tensorflow构图阶段其实就是在对图进行一些描述性语言,跟html很像,很适合用标记性语言来描述。

Tensorflow是有向图,是一个有向无环图。张量为边,操作为点,数据在图中流动。

Tensorflow为每个结点都起了唯一的一个名字。

import tensorflow as tf

a = tf.constant(3)  # name=Const:0
b = tf.Variable(4) # name=Variable:0
print(a.name, b.name)

如上所示,即便你没有指明变量的name属性,tensorflow也会给它起个默认名字。

在C++中有namespace的概念,命名空间的好处就是减少了命名冲突,我们可以在命名空间中使用较简易的标识符。为了便于用户定义变量的name,tensorflow也提出了name_scope

with tf.name_scope("my"):
a = tf.constant(3) # my/Const:0
b = tf.add(a, b) # my/Add:0
print(a.name, b.name)
# 使用get_variable却不管用
c = tf.get_variable("c", shape=1, dtype=tf.int32, initializer=tf.constant_initializer(2)) # c:0
print(c.name)

如上所示,在name_scope中的属性,会用类似文件路径的方式来定义变量的name属性

但是关于name_scope需要明白两点:

  • 使用tf.get_variable函数创建的变量不会受name_scope的影响
  • 只有新创建的变量,如tf.constant,tf.Variable等新建结点的操作才会受到name_scope的影响

总而言之,name_scope作用比较单一,仅仅是为了更改变量的name属性,便于命名变量。而variable_scope作用就很丰富了,它不仅能够改变变量的name属性,还能够实现变量管理功能。

with tf.variable_scope("ha"):
a = tf.constant(2, name="myconstant") # ha/myconstant:0
b = tf.get_variable("b", shape=1, dtype=tf.int32, initializer=tf.constant_initializer(2)) # ha/b:0
print(a.name, b.name)

在改变变量name属性这方面,variable_scope和name_scope基本没有差别,唯一的区别就是get_variable不会受到name_scope的影响,却会受到variable_scope的影响。

variable_scope更加重要的功能是实现变量管理,其中最突出的一点就是变量共享

# 下面我们来验证一下变量共享机制
def get_share_variable(reuse):
with tf.variable_scope("share", reuse=reuse):
a = tf.get_variable("a", shape=(1), dtype=tf.int32)
return a one = get_share_variable(False)
two = get_share_variable(True)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(sess.run([one, two, tf.assign(one, [2])]))

再上面的例子中,通过reuse属性可以控制variable_scope中的变量是否需要重新创建,如果指定reuse=false,则必然会执行新建变量的操作。

上面代码one和two输出值都变成了2,这说明它俩引用的是同一个对象。

使用variable_scope实现变量共享需要注意以下几点:

  • 重用之前必须保证已经创建过,否则报错
  • 使用时必须指明shape和dtype,否则无法复用已创建的变量

变量共享机制非常重要。一个非常常用的场景就是:训练完成之后保存模型,加载模型之后整个图已经建立好了,这时就需要通过variable_scope机制复用已经建好的图,然后测试。

为了验证以上两点,请看下例:

复用未曾创建过的变量会报错

with tf.variable_scope("ha", default_name="what", reuse=True):
try:
m = tf.get_variable("m")
except Exception as ex:
print(ex) # Variable ha/m does not exist, or was not created with tf.get_variable(). Did you mean to set reuse=tf.AUTO_REUSE in VarScope?

它建议我们使用reuse=tf.AUTO_REUSE,这个属性值的含义表示:如果变量存在则复用,不存在则创建之。

以前,reuse属性的取值为True和False,没有tf.AUTO_REUSE。但是在tensorflow未来的版本中,有可能会把reuse的取值弄成枚举类型。这就略微有点小坑了,不知AUTO_REUSE的使用场景是否对得起这么不优雅的设计。

  • AUTO_REUSE=1
  • REUSE_FALSE = 2
  • REUSE_TRUE = 3

下面验证第二点,必须指明变量的形状和类型才可以复用

with tf.variable_scope("ha", default_name="what", reuse=tf.AUTO_REUSE):
try:
m = tf.get_variable("m")
print(m.name)
except Exception as ex:
print(ex) # ValueError: Shape of a new variable (ha/m) must be fully defined, but instead was <unknown>. 这个错误是在说:创建变量必须指明变量的类型

variable_scope的主要作用是变量共享。

说到变量共享,不得不说tf.get_variable()函数。tf.Variable()是构造函数,一定会创建新的变量。tf.get_variable则可以直接访问已经创建的变量(只能在variable_scope中且reuse=True或者AUTO_REUSE的情况下),也可以创建新的变量(在variable_scope内部或者外面都可以,若是内部,则必须reuse=FALSE或者AUTO_REUSE)。

通过以上过程可以发现,get_variable跟variable_scope非常合得来。get_variable不一定非在variable_scope中使用,但是不在variable_scope中使用,它就只能用来创建变量而无法复用变量了,因为只有variable_scope才拥有reuse属性。

# reuse变量的唯一方式就是使用name_scope
x = tf.Variable(3, False, name='x')
print(x.name, x.shape) # x:0 ()
y = tf.get_variable("x", shape=x.shape)
print(y.name, y.shape) # x_1:0 ()

使用get_variable时也有一些微操作,比如指定trainable属性指明该变量是否可以训练。

with tf.variable_scope("ha", default_name="what", reuse=tf.AUTO_REUSE):
# 当variable_scope reuse变量时,依旧可以对变量进行一些微操作:设置trainable=False,表示这个节点不可训练
# 当获取变量时,dtype类型必须对应正确
a = tf.get_variable("b", trainable=False, dtype=tf.int32)
print(tf.trainable_variables("ha"))

相比name_scope功能的单一,tensorflow对variable_scope玩了很多花样:

  • tf.get_trainable_variables() 获取全部可训练的变量
  • tf.get_variable_scope()获取当前的变量作用域

为了对比说明问题,下面用嵌套的方式来实现作用域。

with tf.variable_scope("one"):
"""
使用name_scope只会影响变量的名字,它要解决的问题是变量重名问题
"""
with tf.name_scope("two"):
x = tf.constant(3) # one/two/Const:0
print(x.name)
# variable_scope.name是根目录的名字
print(tf.get_variable_scope().name, tf.get_variable_scope().original_name_scope) # 输出为:one one/
with tf.variable_scope("three"):
x = tf.constant(3) # one/three/Const:0
print(x.name)
print(tf.get_variable_scope().name, tf.get_variable_scope().original_name_scope) # 输出为one/three one/three/

可见,name_scope对于tf.get_variable_scope()来说几乎是不可见的,但却会对变量的命名产生影响,但却仅仅对变量名产生影响。

函数不会阻隔with作用域

# 使用函数依旧不会影响作用域
def ha():
x = tf.Variable(3) # ha_3/Variable:0
print(x.name) with tf.variable_scope("ha"): # 这个变量作用域已经定义过好几次了,它的实际名字变成了ha_3
ha()

Tensorflow中每个结点的name都不会重复,如果重复了怎么办?


# 如果重复定义变量
a = tf.constant(2, name='a') # a:0
b = tf.constant(2, name='a') # a_1:0
print(a.name, b.name) # 如果重复定义name_scope
with tf.name_scope("my"):
a = tf.constant(2) # my_1/Const:0
print(a.name)
"""
可见tensorflow对于一切重名的东西都会在末尾加上下划线+数字
"""
with tf.name_scope("my_4"):
a = tf.constant(2)
print(a.name) # my_4/Const:0
with tf.name_scope("my"):
a = tf.constant(2)
print(a.name) # my_2/Const:0
with tf.name_scope("my_4"):
a = tf.constant(2) # my_4_1/Const:0
print(a.name)

通过以上例子可以发现,tensorflow对于命名重复问题使用以下规则解决:

1、要使用的name不存在,可以直接使用

2、要使用的name已经存在,执行下列循环:

i=1
while 1:
now_name="%s_%d"%(name,i)
if exists(now_name):
i+=1
else:
return now_name

Tensorflow中的name_scope和variable_scope的更多相关文章

  1. tensorflow中的name_scope, variable_scope

    在训练深度网络时,为了减少需要训练参数的个数(比如LSTM模型),或者是多机多卡并行化训练大数据.大模型等情况时,往往就需要共享变量.另外一方面是当一个深度学习模型变得非常复杂的时候,往往存在大量的变 ...

  2. tensorflow 中 name_scope 及 variable_scope 的异同

    Let's begin by a short introduction to variable sharing. It is a mechanism in TensorFlow that allows ...

  3. TensorFlow学习笔记(1):variable与get_variable, name_scope()和variable_scope()

    Variable tensorflow中有两个关于variable的op,tf.Variable()与tf.get_variable()下面介绍这两个的区别 使用tf.Variable时,如果检测到命 ...

  4. TensorFlow基础笔记(13) tf.name_scope tf.variable_scope学习

    转载http://blog.csdn.net/jerr__y/article/details/60877873 1. 首先看看比较简单的 tf.name_scope(‘scope_name’). tf ...

  5. tensorflow中使用tf.variable_scope和tf.get_variable的ValueError

    ValueError: Variable conv1/weights1 already exists, disallowed. Did you mean to set reuse=True in Va ...

  6. [翻译] Tensorflow中name scope和variable scope的区别是什么

    翻译自:https://stackoverflow.com/questions/35919020/whats-the-difference-of-name-scope-and-a-variable-s ...

  7. 【TensorFlow学习笔记 】name_socpe variable_scope

    [引言]TensorFlow中的命名域是非常重要的概念,涉及到参数共享,方便命名参数管理,定义图结构 本文主要介绍name_scope 和 variable_scope,slim包中的arg_scop ...

  8. TensorFlow中的变量命名以及命名空间.

    What: 在Tensorflow中, 为了区别不同的变量(例如TensorBoard显示中), 会需要命名空间对不同的变量进行命名. 其中常用的两个函数为: tf.variable_scope, t ...

  9. tensorflow中slim模块api介绍

    tensorflow中slim模块api介绍 翻译 2017年08月29日 20:13:35   http://blog.csdn.net/guvcolie/article/details/77686 ...

随机推荐

  1. 构建配置 Enable multidex

    官方文档 配置方法数超过 64K 的应用 随着 Android 平台的持续成长,Android 应用的大小也在增加.当您的应用及其引用的库达到特定大小时,您会遇到构建错误,指明您的应用已达到 Andr ...

  2. RV ItemDecoration 分割线 简介 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  3. ODBC更新记录集提示”记录集为只读“

    创建的ODBC应用程序默认的记录集不具有只读属性,但是再更新记录表时会提示”记录集为只读“,这是为什么呢? 今天看书找到了答案: 因为MFC中的数据库类不支持需要连接两个或者多个表的记录集更新,如果选 ...

  4. 转:fastText原理及实践(达观数据王江)

    http://www.52nlp.cn/fasttext 1条回复 本文首先会介绍一些预备知识,比如softmax.ngram等,然后简单介绍word2vec原理,之后来讲解fastText的原理,并 ...

  5. wifidog 源码初分析(4)-转

    在上一篇<wifidog 源码处分析(3)>的流程结束后,接入设备的浏览器重定向至 路由器 上 wifidog 的 http 服务(端口 2060) /wifidog/auth 上(且携带 ...

  6. VS2008中MFC对话框界面编程Caption中文乱码的解决办法

    文章转载自http://blog.csdn.net/ajioy/article/details/6877646 最近在使用VS2008编写一个基于对话框的程序时,在对话框中添加Static控件,编写其 ...

  7. OpenGL ES 3.0之Texturing纹理详解(一)

    本文流程 1.Texturing基础 2.装载Texturing和mipmapping 3.纹理过滤和包装 4.Texture level-of-detail, swizzles, and depth ...

  8. 教育单元测试mock框架优化之路(下)

    转载:https://sq.163yun.com/blog/article/169563599967031296 四.循环依赖的解决 果然! 当我将@SpyBean应用到存在有循环依赖的Bean上时, ...

  9. Android studio 导入 github 工程

    最近从 github 下载两个开源项目,导入 Android Studio 都以 Studio 卡死结束.第一次以为是项目问题,第二次查询资料发现导入方式不正确,在此整理. 原目录结构如下: Andr ...

  10. RPi Desktop盒子安装与服务配置

    批量安装配置盒子时候,可以先安装一个,其余的从这台copy过去. 之前的部分shell记录在本地,记录如下,以免忘记.下次可直接cp执行即可: Step1, 创建用户/组 sudo groupadd ...