TensorFlow 框架和核心概念
https://www.cnblogs.com/miracle-Z/p/8988701.html
TensorFlow核心概念及基本使用
TensorFlow核心概念
综述:TensorFlow中的计算可以表示为一个有向图,或称计算图,其中每一个运算操作将作为一个节点,节点间的链接叫做边。这个计算图描述了数据的计算流程,它也负责维护和更新状态,用户可以对计算图的分支进行条件控制和循环操作。计算图中的每一个节点可以有任意多个输入和输出,每一个节点描述了一种运算操作,节点可以算是运算操作的实例化。在计算图的边中流动的的数据被称为张量。
1.计算图
TensorFlow是一个通过计算图的形式来表述计算的编程系统。每一个计算都是计算图的一个节点,而节点间的边描述了计算之间的依赖关系。
a.不同的图上的张量与运算不会共享(每个图中的数据类似于一个代码块中的局部变量),因此可以用计算图来隔离张量和计算,它还提供了管理张量和计算的机制(指定运算进行的设备)。
b.计算图还有个重要的功能是有效地整理TensorFlow程序中的资源。在一个计算图中可以通过集合(collection)来管理不同类别的资源。
2.TensorFlow的数据模型-张量(Tensor)
TensorFlow用张量这种数据结构来表示所有的数据.你可以把一个张量想象成一个n维的数组或列表.一个张量有一个静态类型和动态类型的维数.张量可以在图中的节点之间流通.
a.TensorFlow计算的结果不是一个具体的数字,而是一个张量结构。一个张量主要保存了三个属性:名字(name)、维度(shape)和类型(type)。
eg:print (result)
输出:
Tensor("add:0", shape=(2,), dtype=float32)
b.张量有两大用途:
对中间计算结果的引用。当一个计算包含很多中间结果时,使用张量可大大提高代码的可读性。
用来获得计算结果。虽张量本身没有储存具体的数字,但可通过tf.Session().run(...)语句得到计算结果。
3.TensorFlow的运行模型-会话(Session)
会话(Session)用来执行定义好的运算。会话拥有并管理TensorFlow程序运行时的所有资源。当所有计算完成后需关闭会话来帮助系统回收资源。使用会话的方式一般有两种:
(1)sess = tf.Session()
sess .run(...)
sess.close()
//因异常退出可能会未执行关闭会话的语句
(2)with tf.Session() as sess:
sess.run(...)
//执行完自动关闭会话
(3)在交互式环境中,通过设置默认会话的方式来获取张量的取值会更加方便。
sess = tf.TnteractiveSession()
sess.close()
无论使用哪种方法都可以通过ConfigProto Protocol Buffer来配置需要生成的会话。通过ConfigProto可以配置类似并行的线程数、GPU分配策略、运算超时时间等参数。
4.变量
变量是一类特殊的运算操作,它可以将一些需要保留的tensor储存在内存或显存中,比如神经网络中的系数。当训练模型时,用变量来存储和更新参数。通常会将一个统计模型中的参数表示为一组变量. 例如, 你可以将一个神经网络的权重作为某个变量存储在一个 tensor 中. 在训练过程中, 通过重复运行训练图, 更新这个 tensor.
变量的作用就是保存和更新以及使用神经网络中的参数。
在神经网络中,给参数赋予随机初始值最为常见,所以一般也使用随机数给TensorFlow中的变量初始化。下面是两个例子:
1.#将特征向量定义为一个常量,这里是一个1×2的矩阵
x = tf.constant([[0.7,0.9]])
2.#声明w1变量,还通过seed参数设定了随机种子,这样可以保证每次运行的结果是一样的。
w1 = tf.Variable(tf.random_normal((2,3), stddev=1, seed=1))
虽然在变量的定义时给出了变量初始化的方法,但这个方法并没有被真正运行。所以在计算结果前,需要运行下面语句来初始化变量,为变量赋值。
sess.run(w1.initializer)
但当变量数目增多,或者变量之间存在依赖关系时,单个调用变量初始化过程就比较麻烦。TensorFlow提供了一种更为便捷的方式来完成变量的初始化过程。
init_op = tf.global_variables_initializer()
sess.run(init_op)
该函数实现初始化所有变量的过程并自动处理变量之间的依赖关系。
5.神经网络优化的简单框架
1.前向传播算法
提取的特征向量通过连接节点边的权重计算,在对应节点求得加权和作为中间的张量,然后依次向后一层按相同的方式传播,最终得到的输出节点上的加权和为输出结果。前向传播算法可得到当前的预测值。
2.损失函数
损失函数用于刻画当前预测值与真实答案之间的差距,评价学习的情况好坏的标准,其重要性不言而喻。具体的介绍在后面文章总结。
3.反向传播算法
反向传播算法用于更新变量,既各层的权重,是训练神经网络的核心算法,它可以根据定义好的损失函数优化神经网络中参数的取值,从而使神经网络模型在训练数据集上的损失函数达到一个最小值。反向传播算法给出了一个高效的方法在所有参数上使用梯度下降算法。梯度下降算法总结在下文。
TensorFlow的基本使用
1.构建图
import tensorflow as tf
# 创建一个常量 op, 产生一个 1x2 矩阵. 这个 op 被作为一个节点
# 加到默认图中.
# 构造器的返回值代表该常量 op 的返回值.
matrix1 = tf.constant([[3., 3.]])
# 创建另外一个常量 op, 产生一个 2x1 矩阵.
matrix2 = tf.constant([[2.],[2.]])
# 创建一个矩阵乘法 matmul op , 把 'matrix1' 和 'matrix2' 作为输入.
# 返回值 'product' 代表矩阵乘法的结果.
product = tf.matmul(matrix1, matrix2)
2.在一个会话中启动图
这个使用在上一点会话中有提到的两种方法。
TensorFlow系统架构
https://blog.csdn.net/u013510838/article/details/84103503
TensorFlow设计十分精巧,基于分层和模块化的设计思想进行开发的。框架如下图
整个框架以 C API 为界,分为前端和后端两大部分。
前端:提供编程模型,多语言的接口支持,比如Python Java C++等。通过C API建立前后端的连接,后面详细讲解。
后端:提供运行环境,完成计算图的执行。进一步分为4层
运行时:分为分布式运行时和本地运行时,负责计算图的接收,构造,编排等。
计算层:提供各op算子的内核实现,例如conv2d, relu等
通信层:实现组件间数据通信,基于GRPC和RDMA两种通信方式
设备层:提供多种异构设备的支持,如CPU GPU TPU FPGA等
模型构造和执行流程
TensorFlow的一大特点是,图的构造和执行相分离。用户添加完算子,构建好整图后,才开始进行训练和执行,也就是图的执行。大体流程如下
图构建:用户在client中基于TensorFlow的多语言编程接口,添加算子,完成计算图的构造。
图传递:client开启session,通过它建立和master之间的连接。执行session.run()时,将构造好的graph序列化为graphDef后,以protobuf的格式传递给master。
图剪枝:master根据session.run()传递的fetches和feeds列表,反向遍历全图full graph,实施剪枝,得到最小依赖子图
图分裂:master将最小子图分裂为多个Graph Partition,并注册到多个worker上。一个worker对应一个Graph Partition。
图二次分裂:worker根据当前可用硬件资源,如CPU GPU,将Graph Partition按照op算子设备约束规范(例如tf.device('/cpu:0'),二次分裂到不同设备上。每个计算设备对应一个Graph Partition。
图运行:对于每一个计算设备,worker依照op在kernel中的实现,完成op的运算。设备间数据通信可以使用send/recv节点,而worker间通信,则使用GRPC或RDMA协议。
[图片上传失败...(image-7053eb-1576595920334)]
前端多语言实现 - swig包装器
TensorFlow提供了很多种语言的前端接口,使得用户可以通过多种语言来完成模型的训练和推断。其中Python支持得最好。这也是TensorFlow之所以受欢迎的一大原因。前端多语言是怎么实现的呢?这要归功于swig包装器。
swig是个帮助使用C或者C++编写的软件能与其它各种高级编程语言进行嵌入联接的开发工具。在TensorFlow使用bazel编译时,swig会生成两个wrapper文件
pywrap_tensorflow_internal.py:对接上层Python调用
pywrap_tensorflow_internal.cc:对接底层C API调用。
pywrap_tensorflow_internal.py 模块被导入时,会加载_pywrap_tensorflow_internal.so动态链接库,它里面包含了所有运行时接口的符号。而pywrap_tensorflow_internal.cc中,则注册了一个函数符号表,实现Python接口和C接口的映射。运行时,就可以通过映射表,找到Python接口在C层的实现了。
4 tensorflow 源码结构
TensorFlow源码基本也是按照框架分层来组织文件的。如下
其中core为tf的核心,它的源码结构如下
5 总结
TensorFlow框架设计精巧,代码量也很大,我们可以从以下部分逐步学习
TensorFlow内核架构和源码结构。先从全局上对框架进行理解。
前后端连接的桥梁--Session,重点理解session的生命周期,并通过相关源码可以加深理解Python前端如何调用底层C实现。
TensorFlow核心对象—Graph。图graph是TensorFlow最核心的对象,基本都是围绕着它来进行的。graph的节点为算子operation,边为数据tensor。
TensorFlow图的节点 -- Operation。operation是图graph的节点,承载了计算算子。
TensorFlow图的边 -- Tensor。Tensor是图graph的边,承载了计算的数据。
TensorFlow本地运行时。
TensorFlow分布式运行时。和本地运行时有一些共用的接口,但区别也很大。
TensorFlow设备层。主要了解设备层的定义规范,以及实现。
TensorFlow队列和并行运算。
TensorFlow断点检查checkpoint,模型保存Saver,以及可视化tensorboard。这三个为TensorFlow主要的工具。
https://www.ituring.com.cn/book/tupubarticle/24643
版本变迁
TensorFlow自2015年11月开源以来,已经发布了30多个版本。本节从TensorFlow的发展历程入手,考查其关键特性的发布和对应版本的变迁。图1-1展示了这一变化过程。
1.3 基本架构
在展开介绍TensorFlow的使用方法和设计原理之前,我们有必要建立对TensorFlow基本架构的直观认识。本节从工作形态和组件结构这两个角度对TensorFlow进行概要性的说明。读者可以以此为切入点,逐步理顺学习TensorFlow的脉络。
1.3.1 工作形态
基础平台层软件的设计模式多种多样,它们对应用层开发者体现出的工作形态也有所差别。在众多平台设计模式中,存在两类基础而典型的模式,即图1-2所示的库模式和框架模式。在库模式下,平台层软件以静态或动态的开发库(如 .a、.so文件)形式存在,应用层开发者需要编写程序调用这些库提供的函数,实现计算逻辑。程序的入口(如main()函数)及整体流程控制权把握在应用层开发者手中。在框架模式下,平台层软件以可执行文件的形式存在,并以前端交互式程序或后端守护进程方式独立运行。应用层开发者需要遵从平台规定的接口约束,开发包含计算逻辑在内的子程序,交由框架性质的平台层软件调度执行。程序的入口及整体流程控制权由框架把握。
图1-2 平台层软件的典型设计模式
在高性能与大数据计算领域,典型的库模式软件有用于计算的Eigen、NumPy,以及用于通信的MPI、ZeroMQ等。基于这些库开发应用时,编程方式比较灵活,部署模式也相对轻量。应用开发者具有较大的自由度,但不得不编写业务逻辑之外的不少“脚手架”代码,以便将算法代码片段转变为完整可用的软件。典型的框架模式软件有大数据计算平台Hadoop、Spark,以及基于SQL和类SQL语言的数据库、数据仓库等。使用这些框架开发应用时,开发者的工作相对轻松,只需要编写与业务逻辑密切相关的算法代码,不用关心运行时机制的复杂性。不过,程序的灵活性将受制于框架的约束。
TensorFlow的设计采用了库模式。之所以如此,是出于灵活通用、端云结合及高性能等设计目标的考虑。库模式的平台层软件便于与各种既有的框架协同工作,不对软件的运行时组件添加新的约束,应用范围也不受制约。除了依赖最基本的编程语言库和操作系统调用,这类平台层软件同其他环境因素解耦,从而可以做到高度的可移植性。在单机和终端等场景下,由于没有守护进程和调度框架的开销,有效计算逻辑的资源利用率也会提高,进而有助于性能优化。
综上,TensorFlow的工作形态是由用户编写主程序代码,调用Python或其他语言函数库提供的接口以实现计算逻辑。用户部署和使用TensorFlow系统时,不需要启动专门的守护进程,也不需要调用特殊的启动工具,只需要像编写普通的本地应用程序那样即可上手。用户也不用担心库模式的开发所必需的那些“脚手架”代码,因为TensorFlow已经提供了多种高级抽象,尽可能地最小化了核心计算逻辑之外的开发工作。
1.3.2 组件结构
TensorFlow作为一套包含数十万行代码的大型软件,其组件结构较为复杂。不过,由于其代码组织合理,文档资料充分,我们很容易将它的软件结构进行不同抽象程度的宏观呈现。初识TensorFlow的新手只需要从最高层的抽象视角观察其组件构成。图1-3给出了一幅粗粒度的TensorFlow组件结构示意图,展示了TensorFlow的主要内部结构及其与周边环境的关系。
构成TensorFlow的主体是其运行时核心库。对于普通的Python应用层开发者而言,这个核心库就是指通过pip命令等方式安装TensorFlow之后,部署到site-packages或类似目录中的动态链接库文件。生成这个库的C++ 源代码大致分为3个层次:分布式运行时、公共运行时和算子核函数。其中,公共运行时实现了数据流图计算的基本逻辑,分布式运行时在此基础上实现了数据流图的跨进程协同计算逻辑,算子核函数则包含图上具体操作节点的算法实现代码。
TensorFlow运行时核心库导出的函数接口基于C和C++ 语言。为了使用其他语言进行应用开发,TensorFlow提供了多语言的API层。Python应用层开发者在代码中调用import tensorflow as tf时,导入的便是TensorFlow安装在Python第三方库目录下的API层模块(本书后面沿用这种Python包导入惯例,使用tf作为tensorflow命名空间的缩写)。API层对用户屏蔽了TensorFlow核心库的动态链接逻辑,使得用户可以使用自己熟悉的语言编写算法模型。
为了简化经典模型的开发,使得TensorFlow成为一套“开箱即用”的工具,Google官方团队及开源贡献者们在TensorFlow社区开设了若干算法模型库及人工智能应用程序项目。用户可以复用这些项目的成果,加快自己的项目开发进度;也可以学习它们的实现原理,提升自己的模型与应用设计水平。这些外围项目中的部分代码(如Keras)已被认为具有较高的共性价值,因此逐步被加入到TensorFlow主项目之中。
TensorFlow运行时核心库底层对接的是各种计算库和通信库。这些库有的是外部组件(如用于CPU代数计算的Eigen库),有的则作为TensorFlow源代码的一部分集成在核心库内部(如用于GPU并行计算的StreamExecutor库)。用户在开发应用程序时看不到这些库的细节,只需要按照软件文档安装好必要的外部依赖包即可。
上面所有组件均运行在本地操作系统和硬件基础设施之上。在服务器端运行场景,最常见的宿主操作系统是Linux,硬件一般为x86 CPU和NVIDIA GPU。在移动终端运行场景,宿主操作系统可以是Android、iOS等,硬件一般为ARM CPU和专用的人工智能芯片。TensorFlow不仅支持原生的物理环境,对虚拟机和容器也完全兼容,这构成了云计算环境下的最佳实践。