智能系统与技术丛书
点击查看第二章
点击查看第三章
TensorFlow机器学习实战指南(原书第2版)
TensorFlow Machine Learning Cookbook
[美] 尼克·麦克卢尔(Nick McClure)著
李 飞 刘 凯 卢建华 李 静 赵秀丽 译
第1章
TensorFlow基础
本章将介绍TensorFlow的基本概念,帮助读者去理解TensorFlow是如何工作的,以及它如何访问数据集和其他资源。学完本章可以掌握以下知识点:
- TensorFlow如何工作
- 声明变量和张量
- 使用占位符和变量
- 操作(计算)矩阵
- 声明操作
- 实现激励函数
- 读取数据源
- 其他资源
1.1 简介
Google的TensorFlow引擎提供了一种解决机器学习问题的高效方法。机器学习在各行各业应用广泛,特别是计算机视觉、语音识别、语言翻译和健康医疗等领域。本书将详细介绍TensorFlow操作的基本步骤以及代码。这些基础知识对理解本书后续章节非常有用。
1.2 TensorFlow如何工作
首先,TensorFlow的计算看起来并不是很复杂,因为TensorFlow的计算过程和算法开发相当容易。这章将引导读者理解TensorFlow算法的伪代码。
1.2.1 开始
截至目前,TensorFlow支持Linux、macOS和Windows操作系统。本书的代码都是在Linux操作系统上实现和运行的,不过运行在其他操作系统上也没问题。本书的代码可以在GitHub(https://github.com/nfmcclure/tensorflow_cookbook )或Packt代码库(https://github. com/PacktPublishing/TensorFlow-Machine-Learning-Cookbook-Second-Edition )获取。虽然TensorFlow是用C++编写,但是全书只介绍TensorFlow的Python使用方式。本书将使用Python 3.6+(https://www.python.org )和TensorFlow 1.10.0+(https://www.tensorflow.org )。尽管TensorFlow能在CPU上运行,但大部分算法在GPU上会运行得更快,它支持英伟达显卡(Nvidia Compute Capability v4.0+,推荐v5.1)。TensorFlow上常用的GPU是英伟达特斯拉(Nvidia Tesla)和英伟达帕斯卡(Nvidia Pascal),至少需要4GB的视频RAM。为了在GPU上运行,需要下载Nvidia Cuda Toolkit及其v5.x+(https://developer.nvidia.com/cuda-downloads )。本书还依赖Python的包:Scipy、Numpy和Scikit-Learn,这些包均包含在Anaconda中(https://www.continuum.io/downloads )。
1.2.2 动手做
这里是TensorFlow算法的一般流程,本书提炼出的纲领如下:
1.导入/生成样本数据集:所有的机器学习算法都依赖样本数据集,本书的数据集既有生成的样本数据集,也有外部公开的样本数据集。有时,生成的数据集会更容易符合预期结果,但是本书大部分都是访问外部公开的样本数据集,具体细节见1.8节。
2.转换和归一化数据:一般来讲,输入样本数据集并不符合TensorFlow期望的形状,所以需要转换数据格式以满足TensorFlow。当数据集的维度或者类型不符合所用机器学习算法的要求时,需要在使用前进行数据转换。大部分机器学习算法期待的输入样本数据是归一化的数据。TensorFlow具有内建函数来归一化数据,如下:
3.划分样本数据集为训练样本集、测试样本集和验证样本集:一般要求机器学习算法的训练样本集和测试样本集是不同的数据集。另外,许多机器学习算法要求超参数调优,所以需要验证样本集来决定最优的超参数。
4.设置机器学习参数(超参数):机器学习经常要有一系列的常量参数。例如,迭代次数、学习率或者其他固定参数。约定俗成的习惯是一次性初始化所有的机器学习参数,从而提高程序的可读性,读者经常看到的形式如下:
5.初始化变量和占位符:在求解最优化过程中(最小化损失函数),TensorFlow通过占位符传入数据,并调整变量(权重/偏差)。TensorFlow指定数据大小和数据类型来初始化变量和占位符。本书大部分使用f?loat32数据类型,TensorFlow也支持f?loat64和f?loat16。注意,使用的数据类型字节数越多结果越精确,同时运行速度越慢。使用方式如下:
6.定义模型结构:在获取样本数据集、初始化变量和占位符后,开始定义机器学习模型。TensorFlow通过选择操作、变量和占位符的值来构建计算图,详细讲解见2.2节。这里给出简单的线性模型y = mx + b:
7.声明损失函数:定义完模型后,需要声明损失函数来评估输出结果。损失函数能说明预测值与实际值的差距,损失函数的种类将在第2章详细展示,这里给出n个样本的均方误差(loss = (1/n)Σ(y实际-y预测)2):
8.初始化模型和训练模型:TensorFlow创建计算图实例,通过占位符传入数据,维护变量的状态信息。下面是初始化计算图的一种方式:
也可以用如下的方式初始化计算图:
9.评估机器学习模型:一旦构建计算图,并训练机器学习模型后,需要寻找某种标准来评估机器学习模型对新样本数据集的效果。通过对训练样本集和测试样本集的评估,可以确定机器学习模型是过拟合还是欠拟合。这些将在后续章节来解决。
10.调优超参数:大部分情况下,机器学习者需要基于模型效果来回调整一些超参数。通过调整不同的超参数来重复训练模型,并用验证样本集来评估机器学习模型。
11.发布/预测结果:所有机器学习模型一旦训练好,最后都用来预测新的、未知的数据。
1.2.3 工作原理
使用TensorFlow时,必须准备样本数据集、变量、占位符和机器学习模型,然后进行模型训练,改变变量状态来提高预测结果。TensorFlow通过计算图实现上述过程。这些计算图是有向无环图,并且支持并行计算。接着TensorFlow创建损失函数,通过调整计算图中的变量来最小化损失函数。TensorFlow维护模型的计算状态,每步迭代自动计算梯度。
1.2.4 参考
- https://www.tensorflow.org/api_docs/python/
- https://www.tensorf?low.org/tutorials/
- https://github. com/jtoy/awesome-tensorflow
1.3 声明变量和张量
TensorFlow的主要数据结构是张量,它用张量来操作计算图。在TensorFlow里可以把变量或者占位符声明为张量。首先,需要知道如何创建张量。
张量是一个广义的向量或矩阵的数学术语。对于一维向量和二维矩阵的情况,张量是n维的(其中n可以是1、2甚至更大)。
1.3.1 开始
创建一个张量,声明其为一个变量。TensorFlow在计算图中可以创建多个图结构。这里需要指出,在TensorFlow中创建一个张量,并不会立即在计算图中增加什么。只有运行一个操作来初始化变量之后,TensorFlow才会把此张量增加到计算图。更多信息请见下一节对变量和占位符的讨论。
1.3.2 动手做
这里将介绍在TensorFlow中创建张量的主要方法:
1.固定张量:
- 创建指定维度的零张量。方式如下:
- 创建指定维度的全1张量。方式如下:
- 创建指定维度的常数填充的张量。方式如下:
- 用已知常数张量创建一个张量。方式如下:
f.constant()函数也能广播一个值为数组,然后模拟tf.fill()函数的功能,具体写法为:tf.constant(42, [row_dim, col_dim])。
2.相似形状的张量:
- 新建一个与给定的tensor类型大小一致的tensor,其所有元素为0或者1,使用方式如下:
因为这些张量依赖前面的张量,所以初始化时需要按序进行。如果打算一次性初始化所有张量,那么程序将会报错。
3.序列张量:
TensorFlow可以创建指定间隔的张量。下面函数的输出跟numpy包中的range()函数和linspace()函数的输出相似:
返回的张量是[0.0, 0.5, 1.0]序列。注意,上面的函数结果中最后一个值是stop值。另外一个rang()函数的使用方式如下:
返回的张量是[6, 9, 12]。注意,这个函数结果不包括limit值。
4.随机张量:
- 下面的tf.random_uniform()函数生成均匀分布的随机数:
注意,这个随机均匀分布从minval(包含minval值)开始到maxval(不包含maxval值)结束,即(minval <= x < maxval)。
- tf.random_normal()函数生成正态分布的随机数:
- tf.truncated_normal()函数生成带有指定边界的正态分布的随机数,其正态分布的随机数位于指定均值(期望)到两个标准差之间的区间:
- 张量/数组的随机化。tf.random_shuff?le()和tf, random_crop()可以实现此功能:
- 张量的随机剪裁。tf.random_crop()可以实现对张量指定大小的随机剪裁。在本书的后面部分,会对具有3通道颜色的图像(height,width,3)进行随机剪裁。为了固定剪裁结果的一个维度,需要在相应的维度上赋其最大值:
1.3.3 工作原理
一旦创建好张量,就可以通过tf.Variable()函数封装张量来作为变量,更多细节见下节,使用方式如下:
1.3.4 延伸学习
创建张量并不一定得用TensorFlow内建函数,可以使用tf.convert_to_tensor()函数将任意numpy数组转换为Python列表,或者将常量转换为一个张量。注意,tf.convert_to_tensor()函数也可以接受张量作为输入。
1.4 使用占位符和变量
使用TensorFlow计算图的关键工具是占位符和变量,也请读者务必理解两者的区别,以及什么地方该用谁。
1.4.1 开始
使用数据的关键点之一是搞清楚它是占位符还是变量。变量是TensorFlow机器学习算法的参数,TensorFlow维护(调整)这些变量的状态来优化机器学习算法。占位符是TensorFlow对象,用于表示输入输出数据的格式,允许传入指定类型和形状的数据,并依赖计算图的计算结果,比如,期望的计算结果。
1.4.2 动手做
在TensorFlow中,tf.Variable()函数创建变量,过程是输入一个张量,返回一个变量。声明变量后需要初始化变量,所谓初始化就是将变量与计算图相关联。下面是创建变量并初始化的例子:
占位符仅仅声明数据位置,用于传入数据到计算图。占位符通过会话中的feed_dict参数获取数据。在计算图中使用占位符时,必须在其上执行至少一个操作。在TensorFlow中,初始化计算图,声明一个占位符x,定义y为x的identity操作。identity操作返回占位符传入的数据本身。结果图将在下节展示,代码如下:
需要注意的是TensorFlow不会返回一个自关联的占位符,也就是说如果运行sess.run
(x,feed_dict={x:x_vales})将会报错。
1.4.3 工作原理
以零张量初始化变量,其计算图如图1-1所示。
在图1-1中可以看出,计算图仅仅有一个变量,全部初始化为0。图中灰色部分详细地展示计算图操作以及相关的常量。右上角的小图展示的是主计算图。关于在TensorFlow中创建和可视化计算图的部分见第10章。
相似地,一个占位符传入numpy数组的计算图展示如图1-2所示。
1.4.4 延伸学习
在计算图运行的过程中,需要告诉TensorFlow初始化所创建的变量的时机。TensorFlow的每个变量都有initializer方法,但最常用的方式是辅助函数global_variables_initializer()。此函数会一次性初始化所创建的所有变量,使用方式如下:
但是,如果是基于已经初始化的变量进行初始化,则必须按序进行初始化,方式如下:
1.5 操作(计算)矩阵
理解TensorFlow如何操作矩阵,对于理解计算图中数据的流动来说非常重要。
在机器学习领域,矩阵是非常重要的概念(在数学中也同样重要)。大多数的机器学习算法均是基于矩阵的运算。鉴于本书没有涵盖矩阵运算和线性代数内容,所以建议读者能自学线性代数,以方便本书内容的理解。
1.5.1 开始
许多机器学习算法依赖矩阵操作。在TensorFlow中,矩阵计算是相当容易的。在下面的所有例子里,我们首先创建一个图会话,代码如下:
1.5.2 动手做
1.创建矩阵:可以使用numpy数组(或者嵌套列表)创建二维矩阵,也可以使用创建张量的函数(比如,zeros()、ones()、truncated_normal()等)并为其指定一个二维形状来创建矩阵。TensorFlow还可以使用diag()函数从一个一维数组(或者列表)来创建对角矩阵,代码如下:
注意,如果再次运行sess.run(C),TensorFlow会重新初始化随机变量,并得到不同的随机数。
2.矩阵的加法、减法和乘法:
矩阵乘法函数matmul()可以通过参数指定在矩阵乘法操作前是否进行矩阵转置或是否每个矩阵都是稀疏的。
注意,矩阵除法设有明确定义。虽然许多人把矩阵除法定义为乘上它的例数,但它与实数除法有本质的不同。
3.矩阵转置,示例如下:
再次强调,重新初始化将会得到不同的值。
4.对于矩阵行列式,使用方式如下:
5.矩阵的逆矩阵:
TensorFlow中的矩阵求逆方法是Cholesky矩阵分解法(又称为平方根法),矩阵需要为对称正定矩阵或者可进行LU分解。
6.矩阵分解:
Cholesky矩阵分解法,使用方式如下:
7.矩阵的特征值和特征向量,使用方式如下:
注意,self_adjoint_eig()函数的输出结果中,第一行为特征值,剩下的向量是对应的向量。在数学中,这种方法也称为矩阵的特征分解。
1.5.3 工作原理
TensorFlow提供数值计算工具,并把这些计算添加到计算图中。这些部分对于简单的矩阵计算来说看似有些复杂,TensorFlow增加这些矩阵操作到计算图进行张量计算。现在看起来这些介绍有些啰嗦,但是这有助于理解后续章节的内容。
1.6 声明操作
现在开始学习TensorFlow计算图的其他操作。
1.6.1 开始
除了标准数值计算外,TensorFlow提供很多其他的操作。在使用之前,按照惯例创建一个计算图会话,代码如下:
1.6.2 动手做
TensorFlow张量的基本操作有add()、sub()、mul()和div()。注意,除特别说明外,这节所有的操作都是对张量的每个元素进行操作:
1.TensorFlow提供div()函数的多种变种形式和相关的函数。
2.值得注意的,div()函数返回值的数据类型与输入数据类型一致。这意味着,在Python 2中,整数除法的实际返回是商的向下取整,即不大于商的最大整数;而Python 3版本中,TensorFlow提供truediv()函数,其会在除法操作前强制转换整数为浮点数,所以最终的除法结果是浮点数,代码如下:
3.如果要对浮点数进行整数除法,可以使用floordiv()函数。注意,此函数也返回浮点数结果,但是其会向下舍去小数位到最近的整数。示例如下:
4.另外一个重要的函数是mod()(取模)。此函数返回除法的余数。示例如下:
5.通过cross()函数计算两个张量的叉积。记住,叉积函数只为三维向量定义,所以cross()函数以两个三维张量作为输入,示例如下:
6.下面给出数学函数的列表:
7.特殊数学函数:有些用在机器学习中的特殊数学函数值得一提,TensorFlow也有对应的内建函数。除特别说明外,这些函数操作的也是张量的每个元素。
1.6.3 工作原理
知道在计算图中应用什么函数合适是重要的。大部分情况下,我们关心预处理函数,但也通过组合预处理函数生成许多自定义函数,示例如下:
1.6.4 延伸学习
如果希望在计算图中增加其他操作(未在上述函数列表中列出的操作),必须创建自定义函数。下面创建一个自定义二次多项式函数3x^2 - x + 10:
1.7 实现激励函数
1.7.1 开始
激励函数是使用所有神经网络算法的必备“神器”。激励函数的目的是为了调节权重和偏差。在TensorFlow中,激励函数是作用在张量上的非线性操作。激励函数的使用方法和前面的数学操作相似。激励函数的功能有很多,但其主要是为计算图归一化返回结果而引进的非线性部分。创建一个TensorFlow计算图:
1.7.2 动手做
TensorFlow的激励函数位于神经网络(neural network,nn)库。除了使用TensorFlow内建激励函数外,我们也可以使用TensorFlow操作设计自定义激励函数。导入预定义激励函数(import tensorflow.nn as nn),或者在函数中显式调用.nn。这里,选择每个函数显式调用的方法。
1.ReLU(Rectif?ier Linear Unit,整流线性单元)激励函数是神经网络最常用的非线性函数。其函数为max(0, x),连续但不平滑。示例如下:
2.有时为了抵消ReLU激励函数的线性增长部分,会在min()函数中嵌入max(0,x),其在TensorFlow中的实现称作ReLU6,表示为min(max(0, x), 6)。这是hard-sigmoid函数的变种,计算运行速度快,解决梯度消失(无限趋近于0),这些将在第8章和第9章中详细阐述,使用方式如下:
3.sigmoid函数是最常用的连续、平滑的激励函数。它也被称作逻辑函数(Logistic函数),表示为1/(1+exp(-x))。sigmoid函数由于在机器学习训练过程中反向传播项趋近于0,因此不怎么使用。使用方式如下:
注意,有些激励函数不以0为中心,比如,sigmoid函数。在大部分计算图算法中要求优先使用均值为0的样本数据集。
4.另外一种激励函数是双曲正切函数(tanh)。双曲正切函数与sigmoid函数相似,但有一点不同:双曲正切函数取值范围为0到1;sigmoid函数取值范围为-1到1。双曲正切函数是双曲正弦与双曲余弦的比值,另外一种写法是((exp(x)-exp(-x))/(exp(x)+exp(-x))。使用方式如下:
5.softsign函数也是一种激励函数,表达式为:x/(abs(x) + 1)。softsign函数是符号函数的连续(但不平滑)估计,使用方式如下:
6.softplus激励函数是ReLU激励函数的平滑版,表达式为:log(exp(x) + 1)。使用方式如下:
注意,当输入增加时,softplus激励函数趋近于无限大,softsign函数趋近于1;当输入减小时,softplus激励函数趋近于0,softsign函数趋近于-1。
7.ELU(Exponential Linear Unit,指数线性单元)激励函数与softplus激励函数相似,不同点在于:当输入无限小时,ELU激励函数趋近于-1,而softplus激励函数趋近于0。其表达式为(exp(x)+1) if x < 0 else x,使用方式如下:
1.7.3 工作原理
上面这些激励函数是神经网络或其他计算图引入的非线性部分,并需要知道在什么位置使用激励函数。如果激励函数的取值范围在0和1之间,比如sigmoid激励函数,那计算图输出结果也只能在0到1之间取值。
如果激励函数隐藏在节点之间,就要意识到激励函数作用于传入的张量的影响。如果张量要缩放为均值为0,就需要使用激励函数以使得尽可能多的变量在0附近。这暗示我们选用双曲正切(tanh)函数或者softsign函数,如果张量要缩放为正数,那么应当选用保留变量在正数范围内的激励函数。
1.7.4 延伸学习
图1-3和图1-4展示了不同的激励函数,从中可以看到的激励函数有ReLU、ReLU6、softplus、ELU、sigmoid、softsign和tanh。
在图1-3中,我们可以看到四种激励函数:ReLU、ReLU6、softplus和ELU。这些激励函数输入值小于0时输出值逐渐变平,输入值大于0时输出值线性增长(除了ReLU6函数有最大值6)。
图1-4展示的是sigmoid、tanh和softsign激励函数。这些激励函数都是平滑的,具有S型,注意有两个激励函数有水平渐近线。
1.8 读取数据源
本书中使用样本数据集训练机器学习算法模型,本节简要介绍如何通过TensorFlow和Python访问各种数据源。
一些数据源依赖于外部网站的维护,以便你可以访问数据。 如果这些网站更改或删除此数据,则可能需要更新本节中的以下某些代码。你可以在作者的GitHub页面上找到更新的代码:https://github.com/nfmcclure/tensorflow_cookbook 。
1.8.1 开始
在TensorFlow中,有些数据集使用Python内建库,有的需要编写Python脚本下载,还有些得手动从网上下载。所有这些数据集都需要联网才能获取到。
1.8.2 动手做
1.鸢尾花卉数据(Iris data)。此样本数据是机器学习和统计分析最经典的数据集,包含山鸢尾、变色鸢尾和维吉尼亚鸢尾各自的花萼和花瓣的长度和宽度。总共有150个数据样本,每类有50个样本。用Python加载样本数据集时,可以使用Scikit Learn的数据集函数,使用方式如下:
2.出生体重数据(Birth weight data)。该数据来自1986年斯普林菲尔德的Baystate医疗中心,此样本数据集是婴儿出生体重以及母亲和家庭历史人口统计学、医学指标,有189个样本集,包含11个特征变量。使用Python访问数据的方式如下:
3.波士顿房价数据(Boston Housing data)。此样本数据集保存在卡内基梅隆大学机器学习仓库,总共有506个房价样本,包含14个特征变量。使用Python获取数据的方式如下(通过keras库):
4.MNIST手写体字库:MNIST手写体字库是NIST手写体字库的子样本数据集,可以网址https://yann.lecun.com/exdb/mnist/ 下载。包含70?000张数字0到9的图片,其中60?000张标注为训练样本数据集,10000张为测试样本数据集。TensorFlow提供内建函数来访问它,MNIST手写体字库常用来进行图像识别训练。在机器学习中,提供验证样本数据集来预防过拟合是非常重要的,TensorFlow从训练样本数据集中留出5000张图片作为验证样本数据集。这里展示使用Python访问数据的方式:
5.垃圾邮件文本数据(Spam-ham text data)。通过以下方式访问垃圾邮件文本数据:
6.影评样本数据。此样本数据集是电影观看者的影评,分为好评和差评,可以在网站http://www.cs.cornell.edu/people/pabo/movie-review-data/ 下载。这里用Python进行数据处理,使用方式如下:
7.CIFAR-10图像数据。此图像数据集是CIFAR机构发布的8000万张彩色图片(已缩放为32×32像素)的子集,总共分10类(包括飞机、汽车、鸟等),60?000张图片。50?000张图片训练数据集,10?000张测试数据集。由于这个图像数据集数据量大,并在本书中以多种方式使用,后面到具体用时再细讲,访问网址为:http://www.cs.toronto.edu/~kriz/cifar.html 。
8.莎士比亚著作文本数据(Shakespeare text data)。此文本数据集是古登堡数字电子书计划提供的免费电子书籍,其中编译了莎士比亚的所有著作。用Python访问文本文件的方式如下:
9.英德句子翻译数据。此数据集由Tatoeba(在线翻译数据库)发布,ManyThings.org(http://www.manythings.org )整理并提供下载。这里提供英德语句互译的文本文件(可以通过改变URL使用你需要的任何语言的文本文件),使用方式如下:
1.8.3 工作原理
如果需要使用这里介绍的数据集,建议读者采用如前所述的数据下载和预处理方式。
1.8.4 参考
1.9 其他资源
这里提供一些关于TensorFlow使用和学习的链接、文档资料和用例。
1.9.1 开始
当开始学习使用TensorFlow时,需要知道在哪里能找到帮助。本节提供了一个可以帮助读者使用TensorFlow以及纠错的目录。
1.9.2 动手做
TensorFlow资源列表如下:
1.本书代码可在GitHub(https://github.com/nfmcclure/tensorflow_cookbook )或Packt代码库(https://github. com/PacktPublishing/TensorFlow-Machine-Learning-Cookbook-Second-Edition )获取。
2.TensorFlow官方Python API文档地址为https://www.tensorflow.org/api_docs/python 。其中包括TensorFlow所有函数、对象和方法的文档和例子。
3.TensorFlow官方教程相当详细,访问网址为https://www.tensorflow.org/tutorials/index.html 。包括图像识别模型、Word2Vec、RNN模型和sequence-to-sequence模型,也有些偏微分方程的例子。后续还会不断增加更多实例。
4.TensorFlow官方GitHub仓库网址为https://github.com/tensorflow/tensorflow 。你可以查看源代码,甚至包含fork或者clone最新代码。也可以看到最近的issue。
5.TensorFlow在Dockerhub上维护的公开Docker镜像,网址为https://hub.docker.com/r/tensorflow/tensorflow/ 。
6.Stack Overflow上有TensorFlow标签的知识问答。随着TensorFlow日益流行,这个标签下的问答在不断增长,访问网址为http://stackoverflow.com/questions/tagged/TensorFlow 。
7.TensorFlow非常灵活,应用场景广,最常用的是深度学习。为了理解深度学习的基础,数学知识和深度学习开发,Google在在线课程Udacity上开课,网址为https://www.udacity.com/course/deep-learning--ud730 。
8.TensorFlow也提供一个网站,让你可以可视化地查看随着参数和样本数据集的变化对训练神经网络的影响,网址为http://playground.tensorf?low.org 。
9.深度学习开山祖师爷Geoffrey Hinton在Coursera上开课教授“机器学习中的神经网络”,网址为https://www.coursera.org/learn/neural-networks 。
10.斯坦福大学提供在线课程“图像识别中卷积神经网络”及其详细的课件,网址为http://cs231n.stanford.edu/ 。