版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。


[参考文献]:

1.scope 命名方法

2.name&variable scope

3.tf.variable_scope和tf.name_scope的用法


1.scope是干什么的

顾名思义“scope”的意思是“范围”,那么name_scope和variable_scope就是针对name所做的范围定义。典型的 TensorFlow 可以有数以千计的节点,在构建各op的过程中,命名要做到不重复,那么在编写程序的时候就要特别注意,例如“x”、“y”、”W”、”B”甚至“weight”等经常使用的变量/常量命名就很可能会重复,否则就要增加一个字符串来表示不同的op所属,例如在x前加train成为train_x,在x前加scan成为scan_x等等,一方面表明此变量、常量所属“范围”的标识,这个name_scope和variable_scope就是干这个事情的,另一方面是从name上保证此变量命名的唯一性。有了这个scope的存在,其中描述的变量和常量就会在机器当中自动给添加前缀描述,作为对各个变量、常量的区分。在这里的编程和以前使用C、C++不同之处就是,C/C++当中的变量名实际相当于我们这里的XXX.name()而不是XXX,计算机区分的是XXX.name()。简单说,有了scope,那么在tensorflow当中就是用op/tensor名来划定范围,实现对变量或者常量名的唯一性定义,避免冲突。

2.scope是怎么干的

接下来我们要分析的问题是:究竟name_scope()和variable_scope()对可以产生变量的tf.get_variable()和tf.Variable()会有什么不同?为了一探究竟,接下来做一些测试:

2.1 tf.name_scope对tf.get_variable()的影响

import tensorflow as tf

with tf.name_scope("a_name_scope") as myscope:
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
 
var1:0
[ 1.]

[结论]:

name_scope()没有对 tf.get_variable()产生的变量增加“范围”。于是,如果再有相同的变量名生成,即便name_scope使用了新的名字“a_name_scope_new”,仍旧会破坏“唯一性”,从而导致出错“该变量已经定义过了!”,试验一下:

with tf.name_scope("a_name_scope_new") as myscope:
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
 
---------------------------------------------------------------------------

ValueError: Variable var1 already exists, disallowed. Did you mean to set reuse=True in VarScope?

【结论】:

果然出错了!“Variable var1 already exists, disallowed.”,说明name_scope没有对get_variable()增加“范围”。那我现在还想生成一个新的变量var2而且要让其内容与var1相同怎么办?

with tf.name_scope("a_name_scope") as myscope:
#initializer = tf.constant_initializer(value=1)
var2 = tf.get_variable(name='var2', dtype=tf.float32, initializer=var1)
#var2=var1
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # var2:0
print(sess.run(var2)) # [ 1.]
 
var1:0
[ 1.]
var2:0
[ 1.]
 

【结论】:

看结果,的确生成了新的变量var2。如果我不想生成新的变量var2,而只想做个变量的名称更改怎么办?注意,这里就和C、C++有不同了。
 
  • 1
with tf.name_scope("a_name_scope") as myscope:
var3=var1
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var3.name) # var1:0
print(sess.run(var3)) # [ 1.]
 
var1:0
[ 1.]
var1:0
[ 1.]
 

【结论】:

虽然有一个变量var3,但是其name和值都是与var1相同的,计算机认的是name,认为这两个是完全一样的,并不是新建,只是引用,我们可以理解为是C语言中的指针,指针的名字可以千奇百怪,但是其指向的地址内容才是其真正的归属。所以,这个变量var3你可以随时设置,不会引起重复性、唯一性的错误——“Variable var1 already exists, disallowed.”。
 
  • 1

变量的名称只是指针名,变量的name是地址

with tf.name_scope("a_name_scope") as myscope:
var3=var1
 

【结论】:

的确没有引起错误提示。
 

2.2 variable_scope对get_variable的影响

那么接着分析,既然name_scope对get_variable没有增加“范围”,那variable_scope呢?
 
with tf.variable_scope("a_variable_scope") as myscope:
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
 
a_variable_scope/var1:0
[ 1.]
 

【结论】:variable_scope对get_variable有命名的影响

看到var1指向的内容被新建了,其name变成了“a_variable_scope/var1:0”,也就是说对计算机而言这已经是一个新的内容了,需要一个新的内存来存储,这个和之前的var1.name = var1:0已经不是一个东西了.同时,我们想要找到之前的var1的name已经是不能够了,这个完全就是C/C++指针的意思,指针指向了一个新的内存,如果不使用一个新的指针指向旧的地址,那么就会导致旧地址的内容无法检索了。验证一下:
 
  • 1
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
print(var3.name) # var1:0
print(sess.run(var3)) # [ 1.]
 
a_variable_scope/var1:0
[ 1.]
var1:0
[ 1.]
 

【结论】: 变量名就是指针,变量的name属性是地址

var3是前面对旧的var1的内容的指针,虽然在前面var1指向了新建的内容(a_variable_scope/var1:0),但是原有内容的指针给了var3,所以现在仍旧可以通过指针找到旧地址内容。前面看到了,使用variable_scope能够产生新的变量,即增加了“范围”标识的变量,那么这个能否再次执行产生新的变量呢?也就是说,新产生的name为(a_variable_scope/var1:0)的地址能否再次被新建?
 
with tf.variable_scope("a_variable_scope") as myscope:
initializer = tf.constant_initializer(value=1)
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
 
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)
ValueError: Variable a_variable_scope/var1 already exists, disallowed. Did you mean to set reuse=True in VarScope?
 

【结论】:get_variable取值的唯一性仍旧需要保证

可见虽然variable_scope可以增加name“范围”,但是get_variable取值的唯一性仍旧需要维护,否则就会出错,你是不可以任性新建的。那我现在就是想重用此变量,我就是想更改一个变量名而已,行吗?当然行,之前我们就采用了直接变量名赋值就行了“var3=var1”,这样变量名改为了var3,但是其name仍旧是var1的name,从c理解就是,指针随便建,地址唯一不变,街道名你随便改,可是街道你不能随便拆改。那还有一种材料中介绍的方法,就是使用reuse_variables(),但是一旦重用的对象本身不存在就会报错。这里说的对象不是“指针”,而是指针地址,而且是带有variable_scope指定的“范围”的指针地址。
 
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # var2:0
print(sess.run(var2)) # [ 1.]
print(var3.name) # var1:0
print(sess.run(var3)) # [ 1.]
 
a_variable_scope/var1:0
[ 1.]
var2:0
[ 1.]
var1:0
[ 1.]
 

【分析】:

看看上面三个变量,如果在 tf.variable_scope(“a_variable_scope”)下则会增加“范围”——(a_variable_scope),显然,var1是已存在的对象,而var2虽然也是有已有的地址,但是如果在 tf.variable_scope当中使用get_variable来获取则会新建一个name为:(a_variable_scope/var2:0),所以var2不能当做是已有地址的变量来被重用,否则会出错。var1是可以被重用的,因为他的确是一个已有的范围内的地址。

with tf.variable_scope("a_variable_scope") as myscope:
initializer = tf.constant_initializer(value=1)
myscope.reuse_variables()
var2 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_variable_scope/var1:0
print(sess.run(var2)) # [ 1.]
 
a_variable_scope/var1:0
[ 1.]
a_variable_scope/var1:0
[ 1.]
 

**【结论】:**var1被var2重用了

with tf.variable_scope("a_variable_scope") as myscope:
initializer = tf.constant_initializer(value=1)
myscope.reuse_variables()
var2 = tf.get_variable(name='var2', shape=[1], dtype=tf.float32, initializer=initializer)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # a_variable_scope/var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_variable_scope/var1:0
print(sess.run(var2)) # [ 1.]
 
---------------------------------------------------------------------------

ValueError                                Traceback (most recent call last)

ValueError: Variable a_variable_scope/var7 does not exist, or was not created with tf.get_variable(). Did you mean to set reuse=None in VarScope?
 

【结论】:

在上面var1被var2重用,这个是正确的,但是紧接着想重新新建一个就会立马报错的,说明这个重用操作“myscope.reuse_variables()”在with范围内都是生效的。如果name_scope下使用reuse_variables()则会报错。
 
with tf.name_scope("a_name_scope") as myscope:
initializer = tf.constant_initializer(value=1)
myscope.reuse_variables()
var1 = tf.get_variable(name='var1', shape=[1], dtype=tf.float32, initializer=initializer) with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
 
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)
AttributeError: 'str' object has no attribute 'reuse_variables'
 

2.3 name_scope()对variable的影响

with tf.name_scope("a_name_scope") as myscope:
var2 = tf.Variable(name='var2', initial_value=[2], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_name_scope/var2:0
print(sess.run(var2)) # [ 2.]
 
a_variable_scope/var1:0
[ 1.]
a_name_scope_5/var2:0
[ 2.]
 

【结论】:

很棒!name_scope对variable有效,新增了“范围”名。那这个范围名是否与get_variable一样有唯一性?
 
with tf.name_scope("a_name_scope") as myscope:
var2 = tf.Variable(name='var2', initial_value=[2], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_name_scope/var2:0
print(sess.run(var2)) # [ 2.]
 
a_variable_scope/var1:0
[ 1.]
a_name_scope_6/var2:0
[ 2.]
 

【结论】:

从上面结果看,唯一性仍旧保证了,原因是自动的将var2.name从(a_name_scope_1/var2:0)变为了(a_name_scope_2/var2:0).这里使用了“变为”这个词实际是错误的,因为根本不是变为,而是新建了一个name 为(a_name_scope_2/var2:0)的变量,这个变量和前面的那个变量的名都为var2但是name属性却是不同的。
 

2.4 variable_scope对variable的影响

with tf.variable_scope("my_variable_scope") as myscope:
var2 = tf.Variable(name='var2', initial_value=[initializer.value], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_name_scope/var2:0
print(sess.run(var2)) # [ 2.]
a_variable_scope/var1:0
[ 1.]
my_variable_scope/var2:0
[ 1.]
 

【结论】:

variable_scope对variable有效,而且从下面的运行结果看,唯一性可以得到保证,新建了一个新的变量,这点和name_scope一致。
 
  • 1
with tf.variable_scope("my_variable_scope") as myscope:
var2 = tf.Variable(name='var2', initial_value=[initializer.value], dtype=tf.float32)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print(var1.name) # var1:0
print(sess.run(var1)) # [ 1.]
print(var2.name) # a_name_scope/var2:0
print(sess.run(var2)) # [ 2.]
 
a_variable_scope/var1:0
[ 1.]
my_variable_scope_1/var2:0
[ 1.]
 

总结:

[1]. name_scope 对 get_variable新建变量的name属性无影响;对variable新建变量的name属性增加了“范围”标识。

[2]. variable_scope对get_variable新建变量的name属性和variable新建变量的name属性都增加了“范围”标识。

[3]. get_variable新建变量如果遇见重复的name则会因为重复而报错。

[4]. variable新建的变量如果遇见重复的name则会自动修改前缀,以避免重复出现。

name_scope与variable_scope 详解的更多相关文章

  1. 基础 | batchnorm原理及代码详解

    https://blog.csdn.net/qq_25737169/article/details/79048516 https://www.cnblogs.com/bonelee/p/8528722 ...

  2. TextCNN 代码详解(附测试数据集以及GitHub 地址)

    前言:本篇是TextCNN系列的第三篇,分享TextCNN的优化经验 前两篇可见: 文本分类算法TextCNN原理详解(一) 一.textCNN 整体框架 1. 模型架构 图一:textCNN 模型结 ...

  3. Batchnorm原理详解

    Batchnorm原理详解 前言:Batchnorm是深度网络中经常用到的加速神经网络训练,加速收敛速度及稳定性的算法,可以说是目前深度网络必不可少的一部分. 本文旨在用通俗易懂的语言,对深度学习的常 ...

  4. 深度学习基础(CNN详解以及训练过程1)

    深度学习是一个框架,包含多个重要算法: Convolutional Neural Networks(CNN)卷积神经网络 AutoEncoder自动编码器 Sparse Coding稀疏编码 Rest ...

  5. 超详细的Tensorflow模型的保存和加载(理论与实战详解)

    1.Tensorflow的模型到底是什么样的? Tensorflow模型主要包含网络的设计(图)和训练好的各参数的值等.所以,Tensorflow模型有两个主要的文件: a) Meta graph: ...

  6. 无所不能的Embedding6 - 跨入Transformer时代~模型详解&代码实现

    上一章我们聊了聊quick-thought通过干掉decoder加快训练, CNN-LSTM用CNN作为Encoder并行计算来提速等方法,这一章看看抛开CNN和RNN,transformer是如何只 ...

  7. 中文NER的那些事儿2. 多任务,对抗迁移学习详解&代码实现

    第一章我们简单了解了NER任务和基线模型Bert-Bilstm-CRF基线模型详解&代码实现,这一章按解决问题的方法来划分,我们聊聊多任务学习,和对抗迁移学习是如何优化实体识别中边界模糊,垂直 ...

  8. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  9. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

随机推荐

  1. 【亲测有效】安装npm慢的解决方案

    使用淘宝的NPM库:npm install -gd express --registry=http://registry.npm.taobao.org

  2. DBA面对新mysql环境

    来源:http://blog.csdn.net/wyzxg/article/details/8491152 author:skatetime:2013/01/10 DBA面对新MySQL环境感悟 1. ...

  3. c# Directory类的常用方法

  4. Linux在丢失的情况下重置密码

    1.开机菜单是 移动光标到第一行 --敲击e 2.找到UTF-8,加上空格rd.break,敲击ctrl+x 3.输入以下命令 mount -o remount,rw /sysroot chroot ...

  5. Linux命令——rsync

    参考:Rsync (Remote Sync): 10 Practical Examples of Rsync Command in Linux How to Sync Files/Directorie ...

  6. 云计算/云存储---Ceph和Openstack的cinder模块对接方法

    1.创建存储池 在ceph节点中执行如下语句. #ceph osd pool create volumes 2.配置 OPENSTACK 的 CEPH 客户端 在ceph节点两次执行如下语句,两次{y ...

  7. maven报错找不到依赖

    遇到一个巨坑 跑公司的一个项目,拉下来代码,跑不起来.发现maven一直报这个错 was cached in the local repository,resolution will not be r ...

  8. SQL中 count(*)和count(1)的对比,区别

    执行效果: 1.  count(1) and count(*) 当表的数据量大些时,对表作分析之后,使用count(1)还要比使用count(*)用时多了! 从执行计划来看,count(1)和coun ...

  9. 《The One!团队》第八次作业:ALPHA冲刺(四)

    项目 内容 作业所属课程 所属课程 作业要求 作业要求 团队名称 < The One !> 作业学习目标 (1)掌握软件测试基础技术.(2)学习迭代式增量软件开发过程(Scrum) 第四天 ...

  10. CF600E Lomsat gelral 和 CF741D Dokhtar-kosh paths

    Lomsat gelral 一棵以\(1\)为根的树有\(n\)个结点,每个结点都有一种颜色,每个颜色有一个编号,求树中每个子树的最多的颜色编号(若有数量一样的,则求编号和). \(n \le 10^ ...