智能计算系统 第五章 编程框架机理

5.1 Tensorflow 设计原则

高性能、易开发、可移植

高性能

  • Tensorflow 中的算子,设计过程中就已经针对底层硬件架构进行了充分的优化
  • 针对生成的计算图,Tensorflow 又提供了一系列的优化操作,以提升计算图的运行效率
  • Tensorflow 调度器可以根据网络结构的特点,并发运行没有数据依赖的节点

易开发

  • 针对现有的多种深度学习算法,提取了大量的共性运算,封装成算子
  • 用户使用tensorflow进行算法开发时,能够直接调用这些算子,很方便的实现算法

可移植

  • 可工作与各种类型的异构系统
  • 对每个算子需提供在不同设备上的不同底层实现
  • 用户程序可以在不同的硬件平台上执行

5.2 Tensorflow 计算图机制

计算图的自动求导

  • 深度学习中通常采用梯度下降更新模型参数
  • 对于复杂模型,手动计算梯度困难
  • 大部分深度学习框架均需提供自动梯度计算功能
  • 用户只需要描述前向计算的过程,由编程框架自动推导反向计算图,完成求导

常见求导方法

手动求导法

手动用链式法则求出梯度公式,代入数值得到梯度值
缺点

  • 对大规模的深度学习算法,手动链式求导法则计算非常困难
  • 需要手动编写梯度求解代码
  • 每次修改算法模型,都需要修改对应的梯度求解方法

数值求导法

利用倒数的原始定义求解

f(x)=limh0f(x+h)f(x)hf'(x)=\lim_{h\rightarrow 0}\frac{f(x+h)-f(x)}{h}

优点

  • 易操作
  • 可对用户隐藏求导过程

缺点

  • 计算量大,速度慢
  • 可能引起舍入误差和截断误差

符号求导法

利用求导规则对表达式自动操作,从而获得倒数
缺点:表达式膨胀问题

自动求导法

介于数值求导和符号求导法的方法
计算图结构天然使用于自动求导
优点

  • 灵活,可以隐藏求导过程
  • 只对基本函数运行符号求导法,可以灵活结合编程语言的循环结构、条件结构等

tensorflow 中可注册函数的反向求导法

计算步骤

  • 原始函数建立计算图,数据正向传播,计算出中间节点xi,并记录计算图中节点依赖关系
  • 反向遍历计算图,计算输出对于每个节点的倒数

检查点机制

使用tf.train.Saver()来保存模型中的所有变量

恢复模型

使用 restore 函数

TensorFlow 中的控制流

  • TensorFlow 中使用控制流算子来实现不同复杂控制流场景
  • 引入少量简单基础操作,为多样的 Tensorflow 应用提供丰富的控制流表达
  • 在 Tensorflow 中,每一个操作都会在一个执行帧中被执行,控制流操作负责创建和管理这些执行帧

计算图本地执行

计算图剪枝

得到本地运行的最小子图

  • 为输入输出建立与外界交互
    • 通过函数调用帧来解决输入输出值传递问题
    • 在每个输入节点前插入arg节点,所有输入节点连接到Source节点上,并通过控制依赖边相连
    • 在每个输出节点后面加入retval节点,所有输出节点连接到sink节点上,也通过依赖边相连,最终行成完整的计算图
  • 去除与最终输出节点无关的节点和边
    • 从输出节点进行BFS,删除没有接触到的节点和边
    • 将每个连通图入度为0的节点通过控制依赖与source节点相连,出度为0的节点通过控制依赖边和sink节点相连

计算图分配

问题:多设备运行环境中,对计算图中每个节点如何分配计算设备
目标:保证计算的快速执行
对计算图中每个结点如何分配计算设备算法执行过程

  1. 从计算图起始点开始遍历
  2. 对于遍历中的每个结点,考虑其可行的设备集合
  3. 如果设备不提供实现特定操作的内核,则设备不可行
  4. 如果某个节点具有多个可行设备,则采用贪心算法,检查该节点在所有可行设备上完成的时间,将最快完成的设备分配给该节点
  5. 重复2-4直到遍历完成整个图

计算图优化

  • tensorflow 中图的优化由 Grappler 模块来实现
  • 通过图优化,可以根据不同的硬件结构调整计算调度策略,从而获得更快的计算速度和更高的硬件效率
  • 也能减少推断过程中所需的峰值内存,从而运行更大的模型
常量折叠 ConstFold

有的常数节点可以被提前计算,用得到的结果生成新的节点来代替原来的常数节点

算数优化

公共子表达式删除、算术简化

布局优化

数据摆放方式的转换
重映射

  • 算子融合,出现频率较高的子图用一个单独的算子来替代
    好处
  • 消除子图调度开销
  • 计算conv2d+biasAdd时,conv2d的数据处理是分块进行的,融合后的biasAdd也可以在片上存储里进行,降低访存开销

计算图切分和设备通信

  • 完成每个节点的设备分配后,将整个计算图按照所分配设备分成若干子图,每个设备一张子图

容错机制

  • 检查send和recv节点传输的正确性
  • 检查到错误时,计算图执行过程会停止并重启
  • 保存中间状态,用于立即恢复到出错前状态

5.3 Tensorflow 系统实现

整体架构

  • 面向各个语言的语言包
  • C/C++ API
  • 后端代码
    • session
    • 图的优化和切分
    • 算子库

计算图执行模块

  • session 是用户和 tensorflow 运行时的接口,session 接收到输入数据时,便可开始运行
  • 每个设备会有一个执行器,负责本设备上子计算图的执行
  • run 函数是 session 执行的核心逻辑,在其中完成计算图的执行,包括传参、运行和返回

执行器逻辑

  • 执行流:一个能够存储计算任务的队列
  • 流间任务可以并行执行,流内任务穿行执行

设备抽象和管理

  • tensorflow将设备分成本地设备和远程设备
  • 使用注册机制来管理设备,每个设备负责一个子图运算,可以通过注册接口支持自定义设备

网络和通信

  • tensorflow设备间通信由send和receive节点进行,使用rendezvous机制

算子实现

  • tensorflow的基本单元,OpKernel 是算子的特定执行,依赖于底层硬件
  • tensorflow 通过注册机制来支持不同的算子和相应的OpKernel函数

5.4 驱动范例

构建VGG网络
就像搭积木一样
内部构图逻辑
加载模型执行预测

5.5 编程框架对比

pytorch

  • 小而灵活
  • 支持python和c++
  • 学术界主要用

MXNet

  • 针对效率和灵活性设计
  • 支持声明式编程以及命令式编程
  • 支持R Julia Go等语言

Caffe

  • 最早出现的框架
  • 缺少灵活性、扩展性和复用性
  • 不再维护更新