TensorFlow变量作用域 TensorFlow™ 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。 其命名来源于本身的原理,Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算.Tensorflow运行过程就是张量从图的一端流动到另一端的计算过程。张量从图中流过的直观图像是其取名为“TensorFlow”的原因。
TensorFlow的关键点是:“Data Flow Graphs”,表示TensorFlow是一种基于图的计算框架,其中节点(Nodes)在图中表示数学操作,线(Edges)则表示在节点间相互联系的多维数据数组,即张量(Tensor),这种基于流的架构让TensorFlow具有非常高的灵活性,该灵活性也让TensorFlow框架可以在多个平台上进行计算,例如:台式计算机、服务器、移动设备等。
备注:TensorFlow的开发过程中,重点在于构建执行流图。
What is Data Flow Graphs?
数据流图使用节点(Node)和线(Edges)的有向图描述数学计算;节点一般用来表示施加的数学操作,也可以表示数据输入(feed in)的起点和输出(push out)的终点,或者是读取/写入持久变量(persistent variable)的终点。线表示的是节点之间的输入/输出关系,这些线可以输运“size可动态调整”的多维数组,即张量(Tensor)。
一旦输入端的所有张量准备好,节点将被分配到各种计算设备完成异步并行地执行运算。
TensorFlow基本概念:
图(Graph):图描述了计算的过程,TensorFlow使用图来表示计算任务。
张量(Tensor):TensorFlow使用tensor表示数据。每个Tensor是一个类型化的多维数组。
操作(op):图中的节点被称为op(opearation的缩写),一个op获得/输入0个或多个Tensor,执行计算,产生0个或多个Tensor。
变量(Variable):运行过程中可以被改变,用于维护状态。
会话(Session):图必须在称之为“会话”的上下文中执行。会话将图的op分发到诸如CPU或GPU之类的设备上执行。
TensorFlow的边即有两种连接关系:
数据依赖
控制依赖
实线边表示数据依赖,代表数据,即张量。任意维度的数据统称为张量。在机器学习算法中,张量在数据流图中从前往后流动一遍就完成一次前向传播,而残差从后向前流动一遍就完成一次反向传播。
虚线边表示控制依赖,可以用于控制操作的运行,这被用来确保happens-before关系,这类边上没有数据流过,但源节点必须在目的节点开始执行前完成。
数据属性:
数据类型 | Python****类型 | 描述 |
---|---|---|
DT_FLOAT | tf.float32 | 32位浮点型 |
DT_DOUBLE | tf.float64 | 64位浮点型 |
DT_INT64 | tf.int64 | 64位有符号整型 |
DT_INT32 | tf.int32 | 32位有符号整型 |
DT_INT16 | tf.int16 | 16位有符号整型 |
DT_INT8 | tf.int8 | 8位有符号整型 |
DT_UINT8 | tf.uint8 | 8位无符号整型 |
DT_STRING | tf.string | 可变长度的字节数组,每一个张量元素都是一个字节数组 |
DT_BOOL | tf.bool | 布尔型 |
DT_COMPLEX64 | tf.complex64 | 由两个32位浮点数组成的复数:实数和虚数 |
节点:
节点又称为算子,它代表一个操作,一般用来表示施加的数字运算,也可以表示数据输入的起点以及输出的重点,或者是读取/写出持久化变量的终点。
类别 | 示例 |
---|---|
数学运算操作 | Add、Subtract、Multiply、Div、Exp、Log、Greater、Less、Equal…… |
数组运算操作 | Concat, Slice, Split, Constant, Rank, Shape, Shuffle…… |
矩阵运算操作 | MatMul, MatrixInverse, MatrixDeterminant…… |
有状态的操作 | Variable、Assign、AssignAdd…… |
神经网络构建操作 | SoftMax, Sigmoid, ReLU, Convolution2D, MaxPool…… |
检查点操作 | Save, Restore…… |
队列和同步操作 | Enqueue, Dequeue, MutexAcquire, MutexRelease…… |
控制张量流动的操作 | Merge, Switch, Enter, Leave, NextIteration…… |
使用TensorFlow必须理解下列概念:
使用图(graph)来表示计算任务;
在会话(session)的上下文中执行图;
使用tensor表示数据;
通过变量(Variable)来维护状态 ;
使用feed和fetch可以为任意的操作(Operation/op)赋值或者从其中获取数据。
TensorFlow程序结构:
TensorFlow的程序一般分为两个阶段:构建阶段和执行阶段;
构建阶段:op的执行步骤被描述称为一个图,然后使用TensorFlow提供的API构建这个图。
执行阶段:将构建好的执行图(Operation Graph)在给定的会话中执行,并得到执行结果。
TensorFlow图:
不使用默认图(Graph),使用多个图来进行编程;但是注意:操作必须属于同一个图,不同图中的节点不能相连。
TensorFlow会话:
当执行图构建完成后,才能给启动图,进入到执行阶段;启动图的第一步就是创建一个Session对象,如果无任何参数的情况下,会话构造器将启动默认图。
tf.Session在构建会话的时候,如果不给定任何参数,那么构建出来Session对应的内部的Graph其实就是默认Graph,不过我们可以通过参数给定具体对应的是那一个Graph以及当前Session对应的配合参数。Session的构造主 要有三个参数,作用如下:
target:给定连接的url,只有当分布式运行的时候需要给定(后面分布式运行讲);
graph:给定当前Session对应的图,默认为TensorFlow中的默认图;
config:给定当前Session的相关参数,参数详见:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/core/protobuf/config.proto中的[ConfigProto]
tf.Session(target='', graph=None, config=None) |
通过Session的config参数可以对TensorFlow的应用的执行进行一些优化调整,主要涉及到的参数如下:
属性 | 作用 |
---|---|
gpu_options | GPU相关参数,主要参数:per_process_gpu_memory_fraction和allow_growth |
allow_soft_placement | 是否允许动态使用CPU和GPU,默认为False;当我们的安装方式为GPU的时候,建议该参数设置为True,因为TensorFlow中的部分op只能在CPU上运行。 |
log_device_placement | 是否打印日志,默认为False,不打印日志 |
graph_options | Graph优化相关参数,一般不需要给定,默认即可,主要参数:optimizer_options(do_common_subexpression_elimination、do_constant_folding和opt_level) |
""" |
在TensorFlow中,除了可以使用Session表示这个会话外,还可以通过InteractiveSession来表示会话,InteractiveSession的意思是:交互式会话,使用交互式会话可以降低代码的复杂度,使用Tensor.eval()或者Operation.run()来代替Session.run()方法,这样可以避免一个变量来维持会话;备注:Session也可以使用Tensor.eval()和Operation.run()获取数据/执行操作(只要明确当前会话)。
Tensor张量:
TensorFlow使用Tensor数据结构来代表所有数据,计算图中,操作间传递的数据都是Tensor。Tensor可以看作是一个n维的数组或者列表,一个Tensor主要由一个静态数据类型和动态类型的维数(Rank、Shape)组成。Tensor可以在图中的节点之间流通。
TensorFlow变量:
变量(Variables)是维护图执行过程中的状态信息。在训练模型过程中,可以通过变量来存储和更新参数。变量包含张量(Tensor)存放于内存的缓存区。建模的时候变量必须被明确的初始化,模型训练后变量必须被存储到磁盘。这些变量的值可以在之后的模型训练和分析中被加载。
在构建变量的时候,必须将一个张量或者可以转化为张量的Python对象作为初始值传入构造函数Variable中。
占位符:
可以使用 shape=[None, 3], None使用类似于numpy。
input_x = tf.placeholder(dtype=tf.float32, shape=[None, 3], name=‘input_x’)
y_hat_, y_hat1_ = sess.run(
fetches=[y_hat, y_hat1], feed_dict={input_x: data2, input_c: 10.0})
以字典方式通过feed_dict传入
import tensorflow as tf |
tensorboard 可视化:
打开日志文件 tensorboard —logdir 绝对路径(到文件夹 )
“”"
tf.summary.FileWriter(self,
logdir, # 记录日志或者事件的路径。
graph=None, # 可视化的图对象
max_queue=10,
flush_secs=120,
graph_def=None,
filename_suffix=None,
session=None):
“”"
writer = tf.summary.FileWriter(
logdir=’./model/ai13’, graph=sess.graph
)
TensorFlow控制依赖:
with g.control_dependencies[a,b,c]:
“d” and “e” will only run after ‘’’a‘’ ‘’b’’ ‘’c’‘ have executed
我们可以通过Variable和assign完成变量的定义和更新,但是如果在更新变量之前需要更新其它变量,那么会导致一个比较严重的问题:也就是需要多次调用sess.run方法来进行变量的更新。通过这种方式,代码复杂程度上升,同时也没有执行效率。
解决该问题的方案就是:控制依赖。通过TensorFlow中提供的一组函数来处理不完全依赖的情况下的操作排序问题(即给定哪个操作先执行的问题), 通过tf.control_dependencies API完成。
def change_var_shape(): |
def factorial(): |
TensorFlow设备:
设备是指一块可以用来运算并且拥有自己的地址空间的硬件,如CPU和GPU。Tensorflow为了在执行操作的时候,充分利用计算资源,可以明确指定操作在哪个设备上执行。
一般情况下,不需要显示指定使用CPU还是GPU,TensorFlow会自动检测。如果检测到GPU,TensorFlow会尽可能地利用第一个GPU来执行操作。注意:如果机器上有超过一个可用的GPU,那么除了第一个外其它GPU默认是不参与计算的。所以,在实际TensorFlow编程中,经常需要明确给定使用的CPU和GPU。
“/cpu:0”:表示使用机器CPU运算
“/gpu:0”:表示使用第一个GPU运算,如果有的话
“/gpu:1”:表示使用第二个GPU运算,以此类推
import os |
TensorFlow变量作用域:
通过tf.Variable我们可以创建变量,但是当模型复杂的时候,需要构建大量的变量集,这样会导致我们对于变量管理的复杂性,而且没法共享变量(存在多个相似的变量)。针对这个问题,可以通过TensorFlow提供的变量作用域机制来解决,在构建一个图的时候,就可以非常容易的使用共享命名过的变量。
Tensorflow中有两个作用域,一个是name_scope,另一个是variable_scope。
变量作用域机制在TensorFlow中主要通过两部分组成:
tf.get_variable:通过所给定的名字创建或者返回一个对应的变量
tf.variable_scope:为通过创建的变量或者操作Operation指定命名空间
import tensorflow as tf |
TensorFlow变量作用域:
通过tf.Variable我们可以创建变量,但是当模型复杂的时候,需要构建大量的变量集,这样会导致我们对于变量管理的复杂性,而且没法共享变量(存在多个相似的变量)。针对这个问题,可以通过TensorFlow提供的变量作用域机制来解决,在构建一个图的时候,就可以非常容易的使用共享命名过的变量。
Tensorflow中有两个作用域,一个是name_scope,另一个是variable_scope。
变量作用域机制在TensorFlow中主要通过两部分组成:
tf.get_variable:通过所给定的名字创建或者返回一个对应的变量
tf.variable_scope:为通过创建的变量或者操作Operation指定命名空间
tf.get_variable方法在调用的时候,主要需要给定参数名称name,形状shape,数据类型dtype以及初始化方式initializer四个参数。该API底层执行的时候,根据variable score的属性reuse的值决定采用何种方式来获取变量。当reuse值为False的时候(不允许设置),作用域就是创建新变量设置的,此时要求对应的变量不存在,否则报错;当reuse值为True的时候,作用域就是为重用变量所设置的,此时要求对应的变量必须存在,否则报错。当reuse的值为tf.AUTO_REUSE的时候,表示如果变量存在就重用变量,如果变量不存在,就创建新变量返回。(备注:reuse一般设置在variable score对象上)
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的结果 |
tf.variable_score方法的作用就是定义一个作用域,定义在variable_score作用域中的变量和操作,会将variable score的名称作为前缀添加到变量/操作名称前,支持嵌套的作用域,添加前缀规则和文件目录路径的规则类似。
tf.variable_score参数如果给定的是一个已经存在的作用域对象的时候,那么构建变量的时候表示直接跳过当前作用域前缀,直接成为一个完全不同与现在的作用域(直接创建给定作用域下的变量)。但是构建操作的时候,还是和嵌套的方式一样,直接添加子作用域。
tf.variable_score参数中,可以给定当前作用域中默认的初始化器initializer,并且子作用域会直接继承父作用域的相关参数(是否重用、默认初始化器等)
TensorFlow中的name_score和variable_score是两个不同的东西,name_score的主要作用是为op_name前加前缀,variable_score是为get_variable创建的变量的名字加前缀。简单来讲:使用tf.Variable创建的变量受name_score和variable_score的的效果,会给变量添加前缀,但是使用tf.get_variable创建变量只受variable_score的效果。
name_score的主要作用就是:Tensorflow中常常会有数以千计的节点,在可视化的过程中很难一下子展示出来,因此用name_scope为变量划分范围,在可视化中,这表示在计算图中的一个层级。name_scope会影响op_name,不会影响用get_variable()创建的变量,而会影响通过Variable()创建的变量。
注意:variable_score内部会创建一个同名的name_score
import tensorflow as tf |
模型持久化
import tensorflow as tf |