4、TensorFlow基础(二)常用API与变量作用域

1、图、操作和张量

  TensorFlow 的计算表现为数据流图,所以 tf.Graph 类中包含一系列表示计算的操作对象(tf.Operation),以及在操作之间流动的数据 — 张量对象(tf.Tensor)。与图相关的 API 均位于tf.Graph 类中:

  

  tf.Operation 类代表图中的一个节点,用于计算张量数据。该类型由节点构造器(如 tf.matmul()或者 Graph.create_op())产生。例如,c = tf.matmul(a, b)创建一个 Operation 类,其类型为 MatMul的操作类。与操作相关的 API 均位于 tf.Operation 类中,

  

  

  tf.Tensor 类是操作输出的符号句柄,它不包含操作输出的值,而是提供了一种在 tf.Session中计算这些值的方法。这样就可以在操作之间构建一个数据流连接,使 TensorFlow 能够执行一个表示大量多步计算的图形。与张量相关的 API 均位于 tf.Tensor 类中

  

2、可视化

  可视化时,需要在程序中给必要的节点添加摘要(summary),摘要会收集该节点的数据,并标记上第几步、时间戳等标识,写入事件文件(event file)中。tf.summary.FileWriter 类用于在目录中创建事件文件,并且向文件中添加摘要和事件,用来在 TensorBoard 中展示。

  

  

3、变量作用域

  在 TensorFlow 中有两个作用域(scope),一个是 name_scope,另一个是 variable_scope。它们究竟有什么区别呢?简而言之,name_scope主要是给variable_name加前缀,也可以op_name加前缀;name_scope 是给 op_name 加前缀

  变量名字由两部分组成:scope/变量name。

name 参数才是对象的唯一标识。

  3.1、tf.name_scope()

Graph中保存着一个属性_name_stack(string类型),_name_stack的值保存着当前的name_scope的名字,在这个图中创建的对象Variable、Operation、Tensor的名字之前都加上了这个前缀。

#它的主要目的是为了更加方便地管理参数命名。
# 与 tf.Variable() 结合使用。简化了命名


1

2

3

with tf.name_scope(‘conv1‘) as scope:

      weights1 = tf.Variable([1.02.0], name=‘weights‘)

      bias1 = tf.Variable([0.3], name=‘bias‘)

# 下面是在另外一个命名空间来定义变量的


1

2

3

with tf.name_scope(‘conv2‘) as scope:

      weights2 = tf.Variable([4.02.0], name=‘weights‘)

      bias2 = tf.Variable([0.33], name=‘bias‘)

# 所以,实际上weights1 和 weights2 这两个引用名指向了不同的空间,不会冲突


1

2

3

4

5

print (weights1.name)

print (weights2.name)

输出:<br>conv1/weights:0

conv2/weights:0

# 注意,这里的 with 和 python 中其他的 with 是不一样的
# 执行完 with 里边的语句之后,这个 conv1/ 和 conv2/ 空间还是在内存中的。这时候如果再次执行上面的代码
# 就会再生成其他命名空间(执行完上面的代码,接着执行这里的,上面的空间还在内存中)


1

2

3

4

5

6

7

8

9

10

11

12

with tf.name_scope(‘conv1‘) as scope:

    weights1 = tf.Variable([1.02.0], name=‘weights‘)

    bias1 = tf.Variable([0.3], name=‘bias‘)

with tf.name_scope(‘conv2‘) as scope:

    weights2 = tf.Variable([4.02.0], name=‘weights‘)

    bias2 = tf.Variable([0.33], name=‘bias‘)

print (weights1.name)

print (weights2.name)

输出: 

conv1_1/weights:0

conv2_1/weights:0

注意,tf.Variable再次命名相同变量时(本来又要产生 conv1/weights:0  conv2/weights:0),结果这里产生了(conv1_1/weights:0 conv2_1/weights:0),所以这就是tf.Variable()的一个特性,遇到同名时,产生一个新的,并不共享。

  3.2、 tf.variable_scope

Graph中维护一个collection,这个collection中的 键_VARSCOPE_KEY对应一个 [current_variable_scope_obj],保存着当前的variable_scope。使用 get_variable() 创建变量的时候,就从这个collection 取出 current_variable_scope_obj,通过这个 variable_scope创建变量。

tf.variable_scope() 主要结合 tf.get_variable() 来使用,实现变量共享。

如果tf.variable_scope函数使用参数reuse=None或者reuse=False创建上下文管理器,则tf.get_variable函数可以创建新的变量。但不可以创建已经存在的变量即为同名的变量。

如果tf.variable_scope函数使用参数reuse=True创建上下文管理器,则tf.get_variable函数可以使用已在当前空间定义的变量赋值来创建变量。但不可以使用不存在的变量来创建。

# 这里是正确的打开方式~~~可以看出,name 参数才是对象的唯一标识


1

2

3

with tf.variable_scope(‘v_scope‘) as scope1:

   Weights1 = tf.get_variable(‘Weights‘, shape=[23])

   bias1 = tf.get_variable(‘bias‘, shape=[3])

# 下面来共享上面已经定义好的变量
# note: 在下面的 scope 中的变量必须已经定义过了,才能设置 reuse=True,否则会报错


1

2

3

4

5

6

7

8

9

with tf.variable_scope(‘v_scope‘, reuse=True) as scope2:

   Weights2 = tf.get_variable(‘Weights‘)

   Weights3 = tf.get_variable(‘Weights‘, [2,3]) #shape如果不同会报错

print (Weights2.name)

print (Weights3.name)

输出

v_scope/Weights:0

v_scope/Weights:0

# 可以看到这两个引用名称指向的是同一个内存对象


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

# 注意, bias1 的定义方式

with tf.variable_scope(‘v_scope‘) as scope1:

   Weights1 = tf.get_variable(‘Weights‘, shape=[23])

   bias1 = tf.Variable([0.52], name=‘bias‘)

# 下面来共享上面已经定义好的变量

# note: 在下面的 scope 中的get_variable()变量必须已经定义过了,才能设置 reuse=True,否则会报错

with tf.variable_scope(‘v_scope‘, reuse=True) as scope2:

   Weights2 = tf.get_variable(‘Weights‘)

   bias2 = tf.Variable([0.53], name=‘bias‘)

print (Weights1.name)

print (Weights2.name)

print (bias1.name)

print (bias2.name)

输出:

v_scope / Weights:0

v_scope / Weights:0

v_scope / bias:0

v_scope_1 / bias:0

使用tf.get_variable发现之前有定义好的的该变量,则进行权值共享。

而bias1 = tf.Variable([0.52], name=‘bias‘)发现之前定义好的名字,则重新定一个新的,并没有共享权值。

tf.get_variable_scope() :获取当前scope

tf.get_variable_scope().reuse_variables() 共享变量

  3.3、对比

简单来说name_scope是给Op_name加前缀的,variable_scope是给变量variable_name和Op_name加前缀的.作用域在使用Tensorboard对Graph对象进行可视化的时候很有帮助,作用域会把一些Op划分到较大的语句块当中.使用tensorboard可视化数据流图的时候,每个作用域都对自己的Op进行封装,从而获得更好的可视化效果.

  • 如果在 tf.name_scope() 环境下分别使用 tf.get_variable() 和 tf.Variable(),两者的主要区别在于
    • tf.get_variable() 创建的变量名不受 name_scope 的影响;
    • tf.get_variable() 创建的变量,name 属性值不可以相同;tf.Variable() 创建变量时,name 属性值允许重复(底层实现时,会自动引入别名机制)
  • 此外 tf.get_variable() 与 tf.Variable() 相比,多了一个 initilizer (初始化子)可选参数;
    • tf.Variable() 对应地多了一个 initial_value 关键字参数,也即对于 tf.Variable 创建变量的方式,必须显式初始化;

name_scope


1

2

3

4

5

6

7

8

9

10

11

12

13

with tf.name_scope("ns") as ns:

   = tf.Variable(1.0, name=‘b‘)

   = tf.get_variable("w", shape=[2,10],dtype=tf.float32)

   = tf.add(b, [3],name=‘a‘)

print ns

print b.name

print w.name

print a.name<br>

输出:

ns /

ns / b:0

w:0

ns / a:0


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

with tf.name_scope("ns") as ns:

   with tf.name_scope("ns1") as ns1:

      b1 = tf.Variable(0, name=‘b1‘)

      w1 = tf.get_variable("w1", shape=[10], dtype=tf.float32)

      a1 = tf.add(b1, [3], name=‘a1‘)

print ns1

print b1.name

print w1.name

print a1.name

输出:

ns/ns1/

ns/ns1/b1:0

w1:0

ns/ns1/a1:0


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

with tf.name_scope("ns") as ns:

   with tf.variable_scope("vs1") as vs1:

      b2 = tf.Variable(0, name=‘b2‘)

      w2 = tf.get_variable("w2", shape=[2])

      a2 = tf.add(b2, [3], name=‘a2‘)

print vs1

print vs1.name

print b2.name

print w2.name

print a2.name

输出:

<tensorflow.python.ops.variable_scope.VariableScope object at 0x42fe790>

vs1

ns/vs1/b2:0

vs1/w2:0

ns/vs1/a2:0


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

with tf.name_scope("ns") as ns:

   with tf.name_scope(None) as n1:

      b3 = tf.Variable(2.0, name=‘b3‘)

      w3 = tf.get_variable("w3", shape=[2])

      a3 = tf.add(b3, [3], name=‘a3‘)

print n1

print b3.name

print w3.name

print a3.name

输出:

b3:0

w3:0

a3:0

variable_scope

注意事项

1. 在 variable_scope 里面的 variable_scope 会继承上面的 reuse 值,即上面一层开启了 reuse ,则下面的也跟着开启。但是不能人为的设置 reuse 为 false ,只有退出 variable_scope 才能让 reuse 变为 false:

2、当在某一 variable_scope 内使用别的 scope 的名字时,此时不再受这里的等级关系束缚,直接与使用的 scope 的名字一样:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

with tf.variable_scope("vs") as vs:

   = tf.Variable(1.0, name=‘b‘)

   = tf.get_variable("w", shape=[210], dtype=tf.float32)

   = tf.add(b, [3], name=‘a‘)

print vs

print vs.name

print b.name

print w.name

print a.name

输出:

<tensorflow.python.ops.variable_scope.VariableScope object at 0x46ee610>

vs

vs/b:0

vs/w:0

vs/a:0


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

with tf.variable_scope("vs") as vs:

   with tf.name_scope("ns1") as ns1:

      b1 = tf.Variable(0, name=‘b1‘)

      w1 = tf.get_variable("w1", shape=[10], dtype=tf.float32)

      a1 = tf.add(b1, [3], name=‘a1‘)

print ns1

print b1.name

print w1.name

print a1.name

输出:

vs/ns1/

vs/ns1/b1:0

vs/w1:0

vs/ns1/a1:0


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

with tf.variable_scope("vs") as vs:

   with tf.variable_scope("vs1") as vs1:

      b2 = tf.Variable(0, name=‘b2‘)

      w2 = tf.get_variable("w2", shape=[2])

      a2 = tf.add(b2, [3], name=‘a2‘)

print vs1

print vs1.name

print b2.name

print w2.name

print a2.name

输出:

<tensorflow.python.ops.variable_scope.VariableScope object at 0x4b1e310>

vs/vs1

vs/vs1/b2:0

vs/vs1/w2:0

vs/vs1/a2:0


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

with tf.variable_scope("vs") as vs:

   with tf.name_scope(None) as n1:

      b3 = tf.Variable(2.0, name=‘b3‘)

      w3 = tf.get_variable("w3", shape=[2])

      a3 = tf.add(b3, [3], name=‘a3‘)

print n1

print b3.name

print w3.name

print a3.name

输出:

b3:0

vs/w3:0

a3:0

总结:

1、使用tf.Variable()的时候,tf.name_scope()和tf.variable_scope() 都会给 Variable 和 op 的 name属性加上前缀。

2、使用tf.get_variable()的时候,tf.name_scope()就不会给 tf.get_variable()创建出来的Variable加前缀。

  

变量作用域机制主要由两个函数实现:

tf.get_variable(<name>, <shape>, <initializer>)
tf.variable_scope(<scope_name>)
  • 1
  • 2

常用的initializer有

tf.constant_initializer(value) # 初始化一个常量值,
tf.random_uniform_initializer(a, b) # 从a到b均匀分布的初始化,
tf.random_normal_initializer(mean, stddev) # 用所给平均值和标准差初始化正态分布.
  • 1
  • 2
  • 3

对如下实例,

with tf.variable_scope(conv1):
    # Variables created here will be named "conv1/weights".
    weights = tf.get_variable(‘weights‘,kernel_shape,
              initializer=tf.random_normal_initializer())

    # Variables created here will be named "conv1/biases".
    biases = tf.get_variable(‘biases‘,biases_shape,
              initializer=tf.constant_intializer(0.0))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

变量作用域的tf.variable_scope()带有一个名称,它将会作为前缀用于变量名,并且带有一个重用标签(后面会说到)来区分以上的两种情况。嵌套的作用域附加名字所用的规则和文件目录的规则很类似。

对于采用了变量作用域的网络结构,结构伪代码如下:

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_intializer(0.0))
    conv = tf.nn.conv2d(input, weights,
        strides=[1, 1, 1, 1], padding=‘SAME‘)
    return tf.nn.relu(conv + 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])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

如果连续调用两次my_image_filter()将会报出ValueError:

result1 = my_image_filter(image1)
result2 = my_image_filter(image2)
# Raises ValueError(... conv1/weights already exists ...)
  • 1
  • 2
  • 3

若不在网络架构中采用变量作用域则不会报错,但是会产生两组变量,而不是共享变量。

变量作用域是怎么工作的?

理解tf.get_variable()

情况1:当tf.get_variable_scope().reuse == False时,该方法用来创建新变量。

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

该情况下方法会生成一个“foo/v”,并检查确保没有其他变量使用该全称。如果该全程已经有其他的变量在使用了,则会抛出ValueError。

情况2:当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 == v
  • 1
  • 2
  • 3
  • 4
  • 5

该情况下会搜索一个已存在的“foo/v”并将该变量的值赋给v1,若找不到“foo/v”变量则会抛出ValueError。

注意reuse标签可以被手动设置为True,但不能手动设置为False。reuse 参数是不可继承的,所以当你设置一个变量作用域为重用作用域时,那么其所有的子作用域也将会被重用。

原文地址:https://www.cnblogs.com/wanshuai/p/9209387.html

时间: 2024-08-29 15:33:41

4、TensorFlow基础(二)常用API与变量作用域的相关文章

MySQL数据库8(二十五)变量作用域

变量作用域 变量作用域:变量能够使用的区域范围 局部作用域 使用declare关键字声明(在结构体内:函数/存储过程/触发器),而且只能在结构体内部使用. declare关键字声明的变量没有任何符号修饰,就是普通字符串,如果在外部能够访问该变量,系统会自动认为是字段. 会话作用域 用户定义的:使用@符号定义的变量,使用set关键字. 会话作用域:在当前用户当次连接有效,只要在本连接之中,任何地方都可以使用(可以在结构内部,也可以跨库) 会话变量可以在函数内部使用 会话变量可以跨库 全局作用域 所

java基础(15):常用API(Object、String、StringBuffer)

1. Java的API及Object类 在以前的学习过程中,我们都在学习对象基本特征.对象的使用以及对象的关系.接下来我们开始使用对象做事情,那么在使用对象做事情之前,我们要学习一些API中提供的常用对象.首先在学习API中的Object类之前,先来学习如何使用API. 1.1 Java 的API Java 的API(API: Application(应用) Programming(程序) Interface(接口)) Java API就是JDK中提供给我们使用的类,这些类将底层的代码实现封装了

FPGA编程基础(二)--常用行为仿真描述

1.常用的行为仿真描述语句 利用循环完成遍历 for.while语句常用于完成遍历测试.当设计代码包含了多个工作模式,那么就需要对各种模式都机型遍历测试,如果手动完成每种模式的测试,则将造成非常大的工作量.利用for循环,通过循环下标来传递各种模式的配置,不仅可以有效减少工作量,还能保证验证的完备性,不会漏掉任何一种模式. (1) for循环仿真 可综合文件: module signedMul( input clk, input rstn, input [7:0] a, input [7:0]

appium 基础:常用api接口(2)

一.获取手机分辨率 size=driver.get_window_size()#获取手机屏幕大小,分辨率 print(size)#{'width': 720, 'height': 1280} 得到的是一个字典,从而获取到手机的宽和高 height=size.get('height') width=size.get('width') 二.滑屏和拖拽 通过坐标实现划屏操作.那么首先我们要设置起始坐标的x,y和终点坐标的x,y.然后通过swipe方法实现划屏 s_x=width*0.5#0.5相当于宽

TensorFlow基础二(Shape)

首先说明tf中tensor有两种shape,分别为static (inferred) shape和dynamic (true) shape,其中static shape用于构建图,由创建这个tensor的op推断(inferred)得来,故又称inferred shape.在实际运行中,常常出现图中tensor的具体维数不确定而用placeholder代替的情况,因此static shape未必是已知的.tensor在训练过程中的实际维数被称为dynamic shape,而dynamic sha

【Android】深入掌握自定义LayoutManager(一) 系列开篇 常见误区、问题、注意事项,常用API。

转载请标明出处: http://blog.csdn.net/zxt0601/article/details/52948009 本文出自:[张旭童的博客] 本系列文章相关代码传送门: 自定义LayoutManager实现的流式布局 欢迎star,pr,issue. 本系列文章目录: 深入掌握自定义LayoutManager(一) 系列开篇 常见误区.问题.注意事项,常用API. 深入掌握自定义LayoutManager(二) 实现流式布局(creating) 概述 这篇文章是深入掌握自定义Layo

PHP和JS中变量作用域

一,PHP中变量作用域 对于大多数PHP的变量只有一个作用域.在用户自定义函数里采用局部变量作用域.所有的函数内使用的变量被设置为局部变量.例如: <?php $a=1; function test() { echo $a; } test(); ?> 这段程序不会输出任何的东西因为echo语句要输出局部变量 $a ,而函数内的 $a 从未被赋过值.你可能注意到和C语言有点小小的区别,C中全局变量可以直接在函数内引用,除非它被一个局部变量所覆盖.因为这使得人们可能不注意修改了全局变量的值.在PH

Java基础学习笔记十二 类、抽象类、接口作为方法参数和返回值以及常用API

不同修饰符使用细节 常用来修饰类.方法.变量的修饰符 public 权限修饰符,公共访问, 类,方法,成员变量 protected 权限修饰符,受保护访问, 方法,成员变量 默认什么也不写 也是一种权限修饰符,默认访问, 类,方法,成员变量 private 权限修饰符,私有访问, 方法,成员变量 static 静态修饰符 方法,成员变量 final 最终修饰符 类,方法,成员变量,局部变量 abstract 抽象修饰符 类 ,方法 我们编写程序时,权限修饰符一般放于所有修饰符之前,不同的权限修饰

二维数组(扩展hash数组)以及json,严格模式,字符串的常用api

二维数组 数组中的每一个元素也是数组 ?var arr=[ [1,2,3], [4,5,6], [7,8,9], [1,2,3,4,5,6,7] ...]; 怎么遍历二维数组 var arr=[ [1,2,3], [4,5,6,7], [10,20,30,40,60,80] ]; for(var r=0;r<arr.length;r++){ for(var c=0;c<arr[r].length;c++){ console.log(arr[r][c]); } } 怎么访问二维数组中的元素 ar