智能计算系统 第四章 编程框架使用

以图像风格迁移为例
第三章已经介绍了上层的算法
第四章讲如何实现算法,怎么用编程框架

4.1 深度学习编程框架的概念

为什么需要编程框架?

深度学习算法越来越流行。而深度学习算法理论比较复杂、代码实现工作量大。有必要将算法的常用操作封装成组件,提高深度学习算法开发效率(避免重复造轮子)。

  • 深度学习算法具有多层结构,每层运算由一些基本操作构成
  • 这些基本操作中存在大量共性运算,如卷积、池化、激活等。
  • 面向这些封装起来的操作,硬件程序员可以基于硬件特征,有针对性地进行充分优化,使其能充分发挥硬件的性能

编程框架的定义

将深度学习算法中的基本操作封装成一系列组件,这一系列深度学习组件,即构成一套深度学习框架。

将VGGNet19作为驱动范例。
tensorflow是目前使用人数最多,影响最大的编程框架。

4.2 Tensorflow 概述

2015年,谷歌团队开源
其变种可以工作于各种异构系统,包括手机、平板电脑等移动设备,数百台机器和数千种计算设备的大规模分布式系统

  • 支持多种高级语言作为输入:Python、C、C++、Java、Go
  • 灵活的编程模型
  • 更高的性能
  • 支持在更广泛的异构硬件平台上进行训练和使用更大规模的神经网络模型

4.3 Tensorflow 编程模型及基本用法

命令式编程与声明式编程

  • 命令式编程:一步一步执行运算。整体优化困难。如:交互式UI、操作系统
  • 声明式编程:通过函数、推论规则等描述数据之间的关系,优化比较容易。如:人工智能、深度学习

几个基本概念

  1. 使用计算图表示机器学习算法的所有计算和状态
  2. 将所有的数据建模成张量
  3. 具体计算操作运行在会话环境中
  4. 将多种类型的计算定义为操作
  5. 通过变量存储计算图中的有状态参数
  6. 通过占位符将张量传递到会话中
  7. 通过队列处理数据读取和计算图的异步执行

计算图

  • tensorflow 中使用有向图来描述计算过程,有向图中包含一组节点和边
  • 支持通过多种高级语言来构建计算图
  • 计算图对应了神经网络的结构

节点和边

  • 节点一般用来表示各类操作,包括数学运算、变量读写、数据填充等,也可表示输入数据、模型参数、输出数据
  • 边表示节点之间的输入输出关系。
    • 一类是传递具体数据的边。传递的数据就是张量
    • 一类是表示节点之间控制依赖关系的边。不传递数据,只表示节点执行的顺序;必须前序节点计算完成,后续节点才开始计算。

tensorflow 程序简单示例
先构建计算图,再创建会话、执行计算图
Tensorflow 1.x 静态图,方便对整个计算图做全局优化,性能高;但调试困难,影响开发效率
Tensorflow 2.x 动态图,调试简单,适合快速开发;运行效率低于静态图

操作

  • 计算图的每个计算节点代表一个操作,其接受0个或多个tensor作为输入,产生0个或多个tensor作为输出
  • 操作对应了神经网络的具体计算

张量

  • 计算图上的数据载体,用张量同一表示所有数据,张量在计算图的节点之间传递
  • 张量中并没有实际保存数据,仅是对计算结果的引用,对应神经网络中各个节点之间流动的数据
  • 张量可以看作n维数组,数组的维数即为张量的阶数

数据类型一般用32为浮点数,但不一定
训练时不需要高位宽,有的时候用定点数性能更好效果也不错

会话 session

  • tensorflow 中的计算图描述了计算执行的过程,并没有真正给输入赋值并执行计算
  • 真正的神经网络计算过程需要在tensorflow程序的session部分中定义并执行
  • session 为程序提供求解张量、执行操作的运行环境。将计算图转化为不同设备上的执行步骤
1
2
3
4
5
6
# 创建会话
sess = tf.Session()
# 执行会话
sess.run()
# 关闭会话
sess.close()

执行会话

  • 基于计算图和输入数据,求解张量或执行计算。

关闭会话

  • 会话的执行占用大量硬件资源,因此会话结束时需要关闭会话,释放这些资源
  • 关闭会话的两种方式
    • sess.close()
    • 使用with语句隐式关闭会话

求解张量值的方法

  1. 会话中使用run函数
    每次可计算多个tensor
  2. tensor.eval()
    每次计算一个tensor

变量

  • 有状态节点
  • 输出由输入、节点操作、节点内部已保存状态值共同作用

创建变量
将一个tensor传递给Variable()构造函数,需指定变量的形状和数据类型

  • 使用tf.Variable()函数直接定义
  • 使用tensorflow内置的函数来定义变量初值,可以是常量和随机值
  • 用其它变量的初始值来定义新变量

初始化变量
最简单的变量初始化方法
tf.global_variables_initializer()

变量更新

  • 可以通过优化器自动更新完成,也可以通过自定义方法强制赋值更新

占位符

  • 使用占位符来构建计算图中的样本输入节点,而不需要实际分配数据
  • 占位符本身没有初始值,只是在程序中分配了内存
  • 使用占位符则只会在计算图中增加一个节点,并只在执行时向其填充数据

队列 queue

  • 通过多线程将读取数据和计算数据分开
  • 用来处理数据读取
  • 多线程读数据,一个线程消耗数据
  • FIFO
  • 队列满时操作会被阻塞,队列空时出队操作会被阻塞

4.4 基于 Tensorflow 的训练及预测实现

训练
输入数据、构建模型、定义损失函数、创建优化器、定义模型训练方法、训练模型
加上训练数据,使用深度学习方法

预测
新数据输入模型函数,得到预测值

tf.nn 模块

  • tensorflow 用于深度学习计算的核心模块,提供神经网络相关操作的支持,包括卷积、池化、损失、分类等。
  • 包含了常用的激活函数。relu、elu、sigmoid等
  • 包含了池化函数avg_pool, max_pool, max_pool_with_argmax, l2_loss

创建神经网络结构

加载数据

  • 注入 feeding:利用 feed_dict 直接传递输入数据
  • 预取 pre_load:利用 const 和 variable 直接读取输入数据
  • 基于队列 API:基于队列相关的 API 构建输入流水线
  • tf.data API:利用tf.data API 来构建输入流水线

定义损失函数

tensorflow内置的几个损失函数
softmax交叉熵
sigmoid交叉熵

创建优化器

定义模型训练方法