深度学习的数学实用指南-全-
深度学习的数学实用指南(全)
原文:
annas-archive.org/md5/eb6425f289df44a65392a9f51d8ac935译者:飞龙
序言
大多数程序员和数据科学家在数学上存在困难,要么忽视了,要么忘记了核心的数学概念。本书帮助你理解理解各种神经网络如何工作的数学知识,以便你能够构建更好的深度学习(DL)模型。
你将从学习设计和实现深度学习算法所需的核心数学和现代计算技术开始。本书将涵盖一些重要的主题,如线性代数、特征值与特征向量、奇异值分解概念以及梯度算法,帮助你理解如何训练深度神经网络。后续章节重点介绍重要的神经网络,如线性神经网络、多层感知机和径向基函数网络,主要帮助你理解每个模型的工作原理。随着学习的深入,你将探索用于标准化、多层深度学习、前向传播、优化和反向传播技术的数学,理解构建完整深度学习模型所需的内容。最后,你将探索卷积神经网络(CNN)、递归神经网络(RNN)和生成对抗网络(GAN)模型及其实现。
到本书结束时,你将建立起神经网络和深度学习(DL)数学概念的坚实基础,这将帮助你自信地进行研究并构建定制的深度学习模型。
本书适合的人群
本书适合数据科学家、机器学习开发者、有志成为深度学习开发者的人,及任何想通过学习构成深度学习算法基础的数学概念,深入理解深度学习算法的人。了解机器学习的基础知识是理解本书所涉及主题的前提条件。拥有强大的数学背景并非必须,但在理解某些概念时会非常有帮助。
为了充分利用本书
本书假定你们大多数人已经有过实现机器学习模型的经验,并且至少对其工作原理有基本的理解。本书还假定你们中许多人有一定的微积分、线性代数、概率论和统计学的基础;具备这些先前的经验将帮助你更好地理解本书内容。
对于那些已经掌握了前五章所涉及数学知识并有机器学习背景的读者,欢迎跳到第七章《前馈神经网络》及之后的内容,继续阅读本书的内容。
然而,对于缺乏上述经验的读者,建议你按照书中的流程和顺序进行学习,特别注意理解前五章中的概念,只有当你对所学内容感到舒适时,再进入下一个章节或部分。重要的是不要急于求成,因为深度学习(DL)是一个庞大而复杂的领域,不容忽视。
最后,要成为一名非常优秀的深度学习从业者,保持学习和复习基础概念非常重要,因为这些概念常常容易被遗忘。在完成本书的所有章节后,我建议你尝试阅读代码并/或实现一些架构,尽量回忆你在本书中学到的内容,因为这样做会进一步巩固你的概念,帮助你更快地学习。
下载彩色图片
我们还提供了一份包含本书中使用的截图/图表的彩色图片 PDF 文件。你可以在这里下载:static.packt-cdn.com/downloads/9781838647292_ColorImages.pdf。
使用的约定
本书中使用了若干文本约定。
粗体:表示新术语、重要词汇或你在屏幕上看到的单词。例如,菜单或对话框中的单词会以这种形式出现在文本中。比如:“这被称为反导数,我们将其正式定义为一个函数。”
警告或重要提示以这种形式出现。
提示和技巧以这种形式出现。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果你对本书的任何方面有疑问,请在邮件主题中提及书名,并通过customercare@packtpub.com联系我们。
勘误:尽管我们已尽最大努力确保内容的准确性,但错误仍然会发生。如果你在本书中发现任何错误,我们将感激你向我们报告。请访问www.packtpub.com/support/errata,选择你的书籍,点击“勘误提交表单”链接,并输入相关细节。
盗版:如果你在互联网上遇到我们作品的任何非法复制品,我们将感激你能提供该位置地址或网站名称。请通过copyright@packt.com与我们联系,并附上相关材料的链接。
如果你有兴趣成为作者:如果你在某个领域有专长,并且有兴趣撰写或为书籍贡献内容,请访问authors.packtpub.com。
评审
请留下评论。在阅读并使用完本书后,为什么不在您购买本书的网站上留下评论呢?潜在的读者可以看到并参考您的客观评价来做出购买决策,我们 Packt 可以了解您对我们产品的看法,而我们的作者也能看到您对他们书籍的反馈。谢谢!
欲了解更多关于 Packt 的信息,请访问 packt.com。
第一部分:深度学习的基础数学
在本节中,你将学习如何使用设计和实现深度学习算法时所需的核心数学和现代计算技术。
本节包括以下章节:
-
第一章,线性代数
-
第二章,矢量分析
-
第三章,概率与统计
-
第四章,优化
-
第五章,图论
第一章:线性代数
在本章中,我们将讲解线性代数的主要概念,这些概念将成为我们学习接下来的各章内容的基础,因此你需要认真听讲。
你必须知道,这些章节无法替代数学教育;它们仅仅是为了帮助你更好地理解深度学习的概念以及各种架构如何工作,并培养你对这些概念的直觉,以便你能成为这个领域的更好实践者。
从本质上讲,代数不过是研究数学符号及其操作规则的学科。代数领域作为数学的统一体,为我们提供了一种思维方式。我们不再使用数字,而是使用字母来表示变量。
然而,线性代数只涉及线性变换和向量空间。它使我们能够通过向量、矩阵和张量表示信息,深入理解线性代数将大大推动你对深度学习的理解。人们常说,只有将一个数学问题转化为线性代数中的计算,它才有可能被解决。这体现了线性代数的强大力量和实用性。
本章将涉及以下主题:
-
比较标量和向量
-
线性方程
-
矩阵运算
-
向量空间与子空间
-
线性映射
-
矩阵分解
比较标量和向量
标量是常规数字,如 7、82 和 93,454。它们只有大小,用于表示时间、速度、距离、长度、质量、功、功率、面积、体积等。
另一方面,向量在许多维度上具有大小和方向。我们用向量表示速度、加速度、位移、力和动量等。我们用粗体字表示向量—例如 a 而不是 a—它们通常是多个数字的数组,这些数字中的每一个都是向量的一个元素。
我们用以下方式表示:

这里,
表示向量位于 n 维实数空间中,这是通过取
的 n 次笛卡尔积得到的;![] 表示每个元素是实数;i 是每个元素的位置;最后,
是自然数,表示向量中有多少个元素。
与常规数字一样,你可以对向量进行加法和减法运算。然而,向量有一些限制。
让我们拿之前看到的向量(x)和另一个向量(y)进行加法运算,它们都位于
,因此可以得到以下结果:

然而,我们不能将维度不同的向量或标量相加。
请注意,当
在
中时,我们降维到二维(例如,纸张的表面),当 n = 3 时,我们降维到三维(现实世界)。
然而,我们可以将标量与向量相乘。设 λ 为任意标量,我们将其与向量
相乘,得到如下关系:

如我们所见,λ 被乘以向量中的每个 x[i]。这个操作的结果是,向量按标量的值进行了缩放。
例如,设
,和
。然后,我们得到如下结果:

虽然这样乘以整数时没问题,但在处理分数时它就不起作用了,但你应该能够猜出它是如何工作的。让我们看一个例子。
令
,和
。然后,我们得到如下结果:

存在一个非常特殊的向量,我们可以通过将任何向量乘以标量 0 来得到。我们将其表示为 0,并称其为 零向量(一个仅包含零的向量)。
线性方程
线性代数的核心是解一组线性方程,称为 方程组。许多问题可以表述为线性方程组。
我们有两个方程和两个未知数,如下所示:

两个方程都表示直线。两个方程的解是这两条直线交点的位置。在这种情况下,答案是点 (3, 1)。
但为了我们的目的,在线性代数中,我们将前面的方程写成一个向量方程,如下所示:

这里,b 是结果向量。
将点 (3, 1) 代入向量方程,我们得到如下结果:

如我们所见,左边等于右边,因此它实际上是一个解!不过,我个人更喜欢将其写成系数矩阵,形式如下:

使用系数矩阵,我们可以将方程组表示为如下矩阵问题
,其中列向量 v 是变量向量。我们写成如下形式:
。
接下来,我们将以这种格式表示我们所有的问题。
为了更好地理解,我们将分解矩阵 A 和向量 v 的乘法。最简单的理解方法是将其看作是向量的线性组合。让我们看一下下面的例子,其中有一个 3x3 的矩阵和一个 3x1 的向量:

需要注意的是,矩阵与向量的乘法仅在矩阵的列数等于向量的行数(元素数)时才能进行。
例如,让我们看一下以下矩阵:

由于矩阵的列数等于向量的行数,因此可以进行乘法运算,但以下矩阵由于列数和行数不相等,不能进行乘法:

让我们通过一些向量运算来可视化它们,以帮助我们更直观地理解它们是如何工作的。请看以下截图:

我们之前处理的向量都位于
(二维空间中),并且这些向量的所有组合也将位于
。同样的情况也适用于位于
、
和
中的向量。
还有一种非常重要的向量运算,称为点积,它是一种乘法。让我们取两个任意向量 v 和 w,并计算它们的点积,如下所示:

以下是乘积:
。
让我们继续,使用之前处理的相同向量,如下所示:

通过计算它们的点积,我们得到了零,这告诉我们这两个向量是垂直的(它们之间有 90° 的角度),如图所示:

最常见的垂直向量例子是表示 x 轴、y 轴等的向量。在
中,我们将 x 轴向量写作 ![],将 y 轴向量写作 ![]。如果我们计算 i•j 的点积,我们会发现结果为零,因此它们是垂直的。
通过将 i 和 j 组合成一个 2x2 矩阵,我们得到以下单位矩阵,这是一个非常重要的矩阵:

以下是我们在求解类型为
的线性方程时可能遇到的几种情况:
-
让我们考虑矩阵![]和方程![]以及![]。如果我们进行代数运算并将第一个方程乘以 3,我们得到![]。但是第二个方程等于零,这意味着这两个方程没有交点,因此没有解。当一个列向量依赖于另一个列向量——即它是另一个列向量的倍数时,![]和![]的所有组合都位于同一方向。然而,由于![]不是这两个列向量的组合,并且不在同一条直线上,它不能是方程的解。
-
我们采用之前相同的矩阵,但这次是![]。由于b在这条线上,并且是依赖向量的组合,因此存在无限多个解。我们说b在矩阵 A 的列空间中。虽然只有一种特定的v组合能够产生b,但存在无限多的列向量组合可以得到零向量(0)。例如,对于任意值a,我们有以下等式:

这引出了另一个非常重要的概念,即完全解。完全解是所有可能的产生![]的方式。我们将其表示为![],其中![]。
求解 n 维空间中的线性方程组
现在我们已经处理了二维线性方程组并理解了它们,接下来我们进一步研究三维方程组。
之前,我们的方程在二维空间(xy平面)中产生了曲线。现在,我们将处理的方程将在三维空间(xyz平面)中产生平面。
让我们取一个任意的 3x3 矩阵,如下所示:

从之前处理二维线性方程组时我们知道,我们的解b,像以前一样,是三个列向量的线性组合,因此有![]。
方程产生一个平面,方程和也分别产生平面。
当两平面相交时,它们会在一条直线上相交;然而,当三平面相交时,它们会在一个点上相交。这个点就是向量![],它是我们问题的解。
然而,如果三个平面没有在一个点相交,那么线性方程就没有解。解决线性方程的这个概念可以扩展到更多的维度。
假设我们现在有一个包含 15 个线性方程和 15 个未知数的系统。我们可以使用前述方法,并根据该方法,我们需要找到满足所有 15 个方程的点——也就是它们的交点(如果存在的话)。
它看起来将是这样的:

正如你所见,我们需要处理很多方程,而且维度越大,解起来就越困难。
使用消元法解线性方程
解决线性方程的一种最佳方法是通过一种系统化的方法,称为消元法。这是一种允许我们系统地消去变量并通过代入法解方程的方法。
让我们来看两个包含两个变量的方程,如下所示:

消元后,结果变为如下:

如我们所见,x 变量不再出现在第二个方程中。我们可以将 y 值代入第一个方程,解出 x。这样,我们得到 x = 3 和 y = 1。
我们称之为三角形分解。它有两种类型——下三角矩阵和上三角矩阵。我们通过一种叫做回代法的过程,从上到下解决上三角矩阵系统,这种方法适用于任何大小的系统。
虽然这是一个有效的方法,但并非万无一失。我们可能会遇到方程比变量多,或者变量比方程多的情况,这种情况是无法解的。或者,我们可能遇到像 0x = 7 这样的情况,正如我们所知,除以零是无法进行的。
让我们解决以下三个包含三个变量的方程:

我们将使用上三角形分解法并逐一消去变量,首先是 y,然后是 z。让我们首先将其表示为矩阵形式,如下所示:

为了简化问题并使其更易理解,我们将忽略v,即列向量,并得到以下结果:

然后,交换第二行和第三行,如下所示:

然后,将第二行与第一行相加,以消去第二行中的第一个值,如下所示:

接下来,将第一行乘以 3/2,并从第三行中减去,如下所示:

最后,将第二行乘以 6 并从第三行中减去,如下所示:

如你所见,矩阵中的值现在形成一个指向上方的三角形,这就是为什么我们称其为上三角矩阵。通过将值代入之前的方程并反向求解(从下到上),我们可以求得:![],![],以及![]。
总结来说,
变成了
,如下所示:

注意:在三角形分解矩阵的对角线上方的值被称为枢轴,当矩阵分解时,对角线下方的值全部为零。
为了验证我们找到的解是否正确,我们使用找到的x、y和z值来解这个方程:
,像这样:

然后变成了如下方程:

正如我们所看到的,左侧等于右侧。
上三角分解后,任意一个 4x4 矩阵将会是这样的:

我们可以进一步分解上三角矩阵,直到得到一个仅包含对角线上的枢轴值,其他位置为零的矩阵。这个得到的矩阵P基本上完全解决了问题,无需进行前向或后向代入,结果如下所示:

但正如你所看到的,从A到P的过程中涉及了很多步骤。
还有一种非常重要的分解方法,叫做下三角-上三角 (LU 分解)。其方法是将A分解为一个上三角矩阵U,并将高斯消元的步骤记录在下三角矩阵L中,最终得到如下结果:![]。
让我们重新审视之前进行的上三角矩阵分解,并将其转化为 LU 分解的形式,像这样:

如果我们将右侧的两个矩阵相乘,就能得到原始矩阵A。但是我们是怎么得到这个结果的呢?让我们一步步来看:
- 我们从
开始,得出如下结论:

- 我们在原本是单位矩阵的l[2,1]位置上加上-1,以表示操作(第二行)-( -1 )(第一行),因此它变成了如下所示:

- 然后我们将![]加到l[3,1]的位置,表示![]操作,结果变成了如下所示:

- 然后,我们将 6 加到矩阵的l[3,2]位置上,表示操作(行 3)-6(行 2),结果如下:

这是我们之前看到的 LU 分解矩阵。
你现在可能会想,这与解
有什么关系,这个问题非常有效。消去法通常效果不错,但我们必须将对A做的所有操作同样应用于b,并且这涉及到额外的步骤。然而,LU 分解仅应用于A*。
现在,让我们来看一下如何使用这个方法解线性方程组。
为了简化,我们省略了变量向量,直接将A和b写成如下:

但即便如此,随着推导的进行,这样写会变得繁琐,因此为了简化,我们将以如下方式书写:

然后我们两边同时乘以
,得到以下结果:

这告诉我们
,并且我们已经从之前的方程得知。通过回代法,我们可以求解出向量v。
在前面的例子中,你可能注意到一些我还未介绍的符号,但不用担心——我们将在下一节中观察所有必要的符号和操作。
矩阵运算
现在我们已经理解了如何解类型为
的线性方程组,即我们将矩阵与列向量相乘,接下来我们将探讨如何进行一个或多个矩阵的运算。
矩阵加法
与标量和向量类似,有时我们需要将两个或多个矩阵相加,过程相当直接。我们以两个
矩阵A和B为例,将它们相加:

需要注意的是,我们只能相加具有相同维度的矩阵,正如你可能已经注意到的,我们是按元素对矩阵进行加法运算的。
矩阵乘法
到目前为止,我们只进行了矩阵与列向量的乘法运算。但现在,我们将矩阵A与另一个矩阵B相乘。
这里列出了四个简单的规则,帮助我们进行矩阵乘法:
-
首先,当矩阵A的列数等于矩阵B的行数时,我们才能进行矩阵的乘法运算。
-
其次,矩阵A的第一行与矩阵B的第一列相乘,得到矩阵AB中的第一个元素,依此类推。
-
第三,当进行乘法运算时,顺序非常重要——具体来说,AB ≠ BA。
-
最后,位于第 i 行,第 j 列的元素是矩阵 A 的第 i 行与矩阵 B 的第 j 列的乘积。
让我们将一个任意的 4x5 矩阵与一个任意的 5x6 矩阵相乘,如下所示:

这将得到一个 4x6 的矩阵,如下所示:

从中我们可以推导出,一般来说,以下结论成立:

让我们将以下两个矩阵相乘,如下所示:
和 
这将得到如下矩阵:
。
注意:在这个例子中,矩阵 B 是单位矩阵,通常表示为 I。
单位矩阵在矩阵乘法中有两个独特的性质。当它与任何矩阵相乘时,返回原始矩阵不变,并且乘法的顺序不影响结果——所以,AI = IA = A。
例如,假设我们使用之前的矩阵 A,并将其与另一个矩阵 B 相乘,如下所示:

另一个非常特殊的矩阵是逆矩阵,表示为 A^(-1)。当我们将 A 与 A^(-1) 相乘时,我们得到 I,即单位矩阵。
如前所述,乘法的顺序很重要。我们必须保持矩阵的顺序,但也有一些灵活性。正如我们在以下方程中看到的,括号可以移动:

这是矩阵运算的第一条法则,称为 结合律。
以下是三条重要的法则,必须遵守:
-
交换律:![]
-
分配律:![] 或 ![]
-
结合律:![]
作为证明 AB ≠ BA 的例子,让我们看一下以下示例:

这清楚地证明了这两个结果是不同的。
我们知道可以将数字进行幂运算,但我们也可以将矩阵进行幂运算。
如果我们将矩阵 A 提升到 p 次幂,我们得到以下结果:
(将矩阵乘以自己 p 次)
矩阵的幂运算还有两个额外的法则—![] 和 ![]。
逆矩阵
让我们重新审视逆矩阵的概念,并深入了解它们。我们之前知道 AA^(-1) = I,但并不是每个矩阵都有逆矩阵。
在求逆矩阵时,我们需要遵循一些规则,具体如下:
-
只有通过上三角或下三角分解的过程,得到所有主元值在对角线上时,才存在逆矩阵。
-
如果矩阵是可逆的,它只有一个唯一的逆矩阵——也就是说,如果 AB = I 且 AC = I,则 B = C。
-
如果 A 可逆,那么解 Av = b 时,我们可以两边同时乘以 A^(-1),得到 AA^(-1)v = A^(-1)b,最终得到 A^(-1)b。
-
如果 v 非零且 b = 0,那么该矩阵没有逆矩阵。
-
2 x 2 矩阵只有在 ad - bc ≠ 0 时才可逆,具体规则如下:

而 ad - bc 被称为 行列式。 A^(-1) 涉及将矩阵中的每个元素除以行列式。
- 最后,如果矩阵的对角线有零值,则它是不可逆的。
有时,我们可能需要求两个矩阵的乘积的逆矩阵,但只有当两个矩阵本身都是可逆的时候才可能(遵循之前的规则)。
例如,假设我们有两个矩阵 A 和 B,它们都是可逆的。然后, ![],因此 ![]。
注意:请密切注意逆矩阵的顺序——它也必须遵循顺序。左侧是右侧的镜像。
矩阵转置
假设我们有一个矩阵 A。如果该矩阵的转置是 B,那么 B 的维度为
,如此: ![]。 这里是矩阵 A:

然后,矩阵 B 如下所示:
。
本质上,我们可以将 A 的列看作转置矩阵 B 的行。
我们通常将 A 的转置写作 A^T。
对称矩阵是一种特殊类型的矩阵。它是一个 n×n 的矩阵,当转置后,它与转置前完全相同。
以下是逆矩阵和转置的性质:
-
![]
-
![]
-
![]
-
![]
-
![]
-
![]
如果 A 是可逆矩阵,那么 A^T 也是可逆的,因此 (A(-1))T = (AT)(-1) = A^(-T)。
排列
在解线性方程组的例子中,我们交换了第 2 行和第 3 行的位置。这被称为 排列。
在进行三角分解时,我们希望将主元值放在矩阵的对角线上,但这并非每次都会发生——事实上,通常不会。所以,取而代之的是,我们交换行,以便将主元值放在我们想要的位置。
但这并不是它们唯一的应用场景。我们还可以用它们通过标量值对单独的行进行缩放,或将行加到其他行,或从其他行中减去行。
让我们从一些基本的置换矩阵开始,这些矩阵通过交换单位矩阵的行得到。通常,我们有 n! 种可能的置换矩阵,可以从一个 n×n 的单位矩阵中构建。在这个例子中,我们使用的是 3×3 矩阵,因此我们有六个置换矩阵,它们如下:
-
![] 这个矩阵对它所应用的矩阵没有任何改变。
-
![] 这个矩阵交换它所应用的矩阵的第二行和第三行。
-
![] 这个矩阵交换它所应用的矩阵的第一行和第二行。
-
![] 这个矩阵将第二行和第三行上移一行,并将第一行移至第三行的位置。
-
![] 这个矩阵将第一行和第二行下移一行,并将第三行移到第一行的位置。
-
![] 这个矩阵交换它所应用的矩阵的第一行和第三行。
需要注意的是,置换矩阵有一个特别迷人的性质,即如果我们有一个矩阵
并且它是可逆的,那么存在一个置换矩阵,当它作用于 A 时,会得到 A 的 LU 分解。我们可以这样表示:

向量空间和子空间
在本节中,我们将探讨向量空间和子空间的概念。这些对我们理解线性代数非常重要。实际上,如果我们不理解向量空间和子空间,我们就无法真正理解如何解决线性代数问题。
空间
向量空间是线性代数的基本设置之一,正如名称所示,它们是所有向量所在的空间。我们将向量空间表示为 V。
思考维度最简单的方式是计算列向量中的元素数量。假设我们有 ![],那么
。
是一个直线,
是所有可能的点在 xy 平面上,
是所有可能的点在 xyz 平面上——即三维空间,以此类推。
以下是一些关于向量空间的规则:
-
在 V 中存在一个加法单位元素,使得
对所有
都成立。 -
对于所有 ![],存在加法逆元,使得 ![]。
-
对于所有 ![],存在一个乘法单位元,使得 ![]。
-
向量是可交换的,即对于所有 ![],有 ![]。
-
向量是可结合的,例如 ![]。
-
向量具有分配性,即对于所有 ![] 和所有 ![],有 ![] 和 ![]。
一组向量被称为线性无关,如果 ![],这意味着 ![]。
另一个我们需要了解的重要概念是 生成。向量组 ![] 的生成是通过 n 个向量所能组成的所有线性组合的集合。因此, ![],如果向量是线性无关并且完全生成 V,那么这些向量 ![] 就是 V 的基。
因此,V 的维度是我们拥有的基向量的数量,我们表示为 dimV。
子空间
子空间是另一个非常重要的概念,它表明我们可以在一个向量空间内拥有一个或多个子空间。假设 V 是一个向量空间,并且我们有一个子空间 ![]。那么,S 只有在遵循以下三个规则时,才能成为一个子空间:
-
![]。
-
![] 和 ![],这意味着 S 在加法下是封闭的。
-
![] 和 ![],因此 ![],这意味着 S 在标量乘法下是封闭的。
如果 ![],那么它们的和是 ![],其中结果也是 V 的子空间。
和的维度 ![] 如下所示:
![]。
线性映射
线性映射是一个函数 ![],其中 V 和 W 都是向量空间。它们必须满足以下条件:
-
![],对于所有 ![]。
-
![],对于所有的
和 ![]()
线性映射通常会保持向量空间在加法和数乘下的性质。一个线性映射被称为 向量空间同态;然而,如果这个同态是可逆的(其中的逆映射也是同态),那么我们称这个映射为 同构。
当 V 和 W 是同构时,我们表示为 ![],并且它们具有相同的代数结构。
如果 V 和 W 是
中的向量空间,且 ![],那么它被称为 自然同构。我们可以写作:

这里,![] 和 ![] 是 V 和 W 的基。使用前面的方程,我们可以看到 ![],这告诉我们
是一个同构。
假设我们再次使用相同的向量空间 V 和 W,它们的基分别为 ![] 和 ![]。我们知道 ![] 是一个线性映射,矩阵 T 的元素是 A[ij],其中 ![] 和 ![] 可以定义如下:
。
根据我们对矩阵的了解,我们应该知道 A 的 j^(th) 列包含 Tv[j],这是在 W 的基下的表示。
因此,![] 生成了一个线性映射 ![],我们可以写作 ![]。
图像与核
在处理线性映射时,我们常常会遇到两个重要的术语:图像和核,它们都是具有非常重要性质的向量子空间。
核(有时称为 零空间)是 0(零向量),并且由线性映射生成,定义如下:

图像(有时称为 值域)的定义如下:
使得
。
V 和 W 有时也被称为 T 的 定义域 和 值域。
最好将核视为一个线性映射,它将向量 ![] 映射到 ![]。然而,像是图像,是所有可能的线性组合的集合,
可以被映射到向量集合 ![]。
秩-零空间定理(有时称为线性映射的基本定理)指出,给定两个向量空间 V 和 W 以及一个线性映射 ![],以下内容始终成立:
。
度量空间和范数空间
度量帮助定义欧几里得空间(用
表示)中的距离概念。然而,度量空间不一定总是向量空间。我们之所以使用它们,是因为它们使我们能够为除了实数以外的对象定义极限。
到目前为止,我们一直在处理向量,但我们尚不清楚如何计算一个向量的长度,或计算两个或多个向量之间的距离,以及它们之间的角度,因此也涉及正交(垂直)的概念。这时,欧几里得空间就派上用场了。事实上,它们是几何学的基本空间。现在看起来这可能显得有些琐碎,但随着我们进一步深入,本书会让你更加清楚它们的重要性。
在欧几里得空间中,我们通常将向量称为点。
集合 S 上的度量被定义为一个函数
,并满足以下标准:
-
![],当 ![] 时 ![]
-
![]
-

对所有 ![]。
这些都很好,但我们到底该如何计算距离呢?
假设我们有两个点,![] 和 ![];那么,它们之间的距离可以如下计算:

我们可以将此扩展到找到
中的点之间的距离,如下所示:

虽然度量有助于距离的概念,但范数定义了欧几里得空间中长度的概念。
向量空间上的范数是一个函数 ![],并满足以下条件:
-
![],当
时,![] -
![]
-
![] (也称为三角不等式)
对所有![] 和 ![]。
需要注意的是,向量空间上的任何范数都会在该向量空间上创建一个距离度量,具体如下所示:

这满足度量的规则,告诉我们范数空间也是度量空间。
一般来说,对于我们的目的,我们只关心在
上的四种范数,如下所示:
-
![]
-
![]
-
![]
-
![] (仅当 ![] 时适用)
仔细观察这四种范数,你可以注意到 1 范数和 2 范数是 p 范数的特例。然而,
-范数是 p 范数的极限,当 p 趋于无穷大时。
使用这些定义,我们可以定义两个向量为正交,如果满足以下条件:

内积空间
向量空间上的内积是一个函数 ![],并满足以下规则:
-
![]
-
![] 和 ![]
-
![]
对所有 ![] 和
。
需要注意的是,向量空间上的任何内积都会在该向量空间上创建一个范数,具体如下所示:

我们可以从这些规则和定义中注意到,所有内积空间也是范数空间,因此也是度量空间。
另一个非常重要的概念是正交性,简而言之,意味着两个向量彼此垂直(即它们在欧几里得空间中相互成直角)。
如果两个向量的内积为零——即 ![],则这两个向量是正交的。为了简化表示垂直性,我们写作 ![]。
此外,如果两个正交向量的长度为单位长度——即 ![],则它们称为正交归一。
一般来说,
中的内积如下所示:

矩阵分解
矩阵分解是一组方法,我们用它们来描述矩阵,通过更易解释的矩阵给我们提供关于矩阵性质的洞见。
行列式
之前,我们简要地看了一下 2x2 方阵的行列式,当我们想要判断一个方阵是否可逆时。行列式是线性代数中的一个非常重要的概念,在解线性方程组时经常使用。
注意:只有在我们拥有方阵时,行列式才存在。
在符号表示上,行列式通常写作![]或![]。
让我们以一个任意的n×n矩阵 A 为例,表示如下:

我们还将计算它的行列式,具体如下:

行列式将矩阵简化为一个实数(换句话说,将A映射为一个实数)。
我们首先检查一个方阵是否可逆。让我们以一个 2x2 的矩阵为例,根据前面的定义,我们知道该矩阵与其逆矩阵相乘会得到单位矩阵。它的原理与我们将a与![]相乘时相同(仅在![]为真时),结果为 1,唯一的区别是应用在矩阵上。因此,AA^(-1) = I。
让我们继续求解我们矩阵的逆矩阵,具体如下:

A 只有在![]时才可逆,这个结果值就是我们所称的行列式。
现在我们知道如何在 2x2 的情况下找到行列式,让我们继续研究 3x3 矩阵并求解它的行列式。它的形式如下:

这会产生以下结果:

我知道这看起来可能更让人畏惧,但实际上并不是这样的。花点时间仔细看看我们做了什么,以及这对于更大的n×n矩阵是如何工作的。
如果我们有一个n×n矩阵,并且它可以被三角分解(上三角或下三角),那么它的行列式将是所有主元素值的乘积。为了简单起见,我们将所有可以三角分解的矩阵表示为T。因此,行列式可以这样表示:

看着前面的 3×3 矩阵示例,我敢肯定你已经明白,对于n > 3的矩阵,计算行列式是一个相当冗长的过程。幸运的是,有一种方法可以简化计算,这就是拉普拉斯展开式的作用。
当我们想找到一个 n×n 矩阵的行列式时,拉普拉斯展开通过对(n×1)×(n×1)矩阵的展开来计算行列式,并重复这一过程,直到得到 2×2 矩阵。一般来说,我们可以使用 2×2 矩阵来计算 n×n 矩阵的行列式。
让我们再考虑一个n维方阵,其中
。然后,我们对所有 ![]进行展开,如下所示:
- 沿第i行展开:

- 沿第j行展开:

并且 ![] 是
的一个子矩阵,它是通过去掉第i行和第j列得到的。
例如,我们有一个 3×3 矩阵,如下所示:
![]
我们希望通过沿第一行应用拉普拉斯展开来找到它的行列式。结果如下:

现在我们可以使用前面 2×2 情况的公式,计算 A 的行列式,如下所示:
。
以下是一些非常重要的行列式性质,了解这些性质非常重要:
-
![]
-
![]
-
![]
-
![]
-
![]
行列式还有一个附加性质,即我们可以使用它来计算一个位于
中,顶点由矩阵中的列向量构成的物体的体积。
作为一个例子,我们来考虑一个平行四边形,位于
,它由向量 ![] 和 ![] 组成。通过计算这个 2×2 矩阵的行列式,我们可以得到该形状的面积(对于高于二维的物体,我们只能找到体积),如下所示:

欢迎你自己动手尝试对任何 3×3 矩阵进行练习。
特征值和特征向量
假设我们有一个任意的实数 n×n 矩阵 A。当我们将此矩阵应用于某个向量时,很可能它们被一个常数值缩放。如果是这种情况,我们说该非零的
维向量是A的特征向量,并且它对应于特征值λ。我们可以表示为:

注意:零向量(0)不能是A的特征向量,因为 A0 = 0 = λ0 对所有λ都成立。
让我们再次考虑一个矩阵 A,它有一个特征向量 x 和相应的特征值 λ。那么,以下规则将适用:
-
如果我们有一个矩阵 A,并且它已从当前位置移动到 ![],那么它有特征向量 x 和对应的特征值 ![],对于所有 ![],使得 ![]。
-
如果矩阵 A 可逆,那么 x 也是矩阵的逆的特征向量,![],对应的特征值为 ![]。
-
![] 对任何 ![]。
我们从本章之前知道,每当我们将一个矩阵与一个向量相乘时,向量的方向会发生变化,但特征向量并非如此。它们与 A 的方向相同,因此 x 保持不变。特征值作为标量值,告诉我们特征向量是否被缩放,如果是,缩放了多少,以及向量的方向是否发生了变化。
另一个非常有趣的性质是,行列式等于矩阵的特征值的乘积,可以写成如下形式:

但这并不是行列式与特征值之间唯一的关系。我们可以将
重写成 ![]。由于这等于零,这意味着它是一个不可逆矩阵,因此它的行列式也必须等于零。利用这一点,我们可以通过行列式来求特征值。让我们看看如何做到这一点。
假设我们有 ![]。然后,它的行列式表示如下:

我们可以将其重写为以下二次方程:

我们知道,二次方程会给出两个特征值 ![]。因此,我们将数值代入二次公式并得到根。
另一个有趣的性质是,当我们遇到如本章前面找到的三角矩阵时,它们的特征值就是主元值。因此,如果我们想找到一个三角矩阵的行列式,那么我们所要做的就是找到对角线上的所有元素的乘积。
迹
给定一个 n×n 矩阵 A,所有对角线元素的和称为 迹。我们写成这样:

以下是迹的四个重要性质:
-
![]
-
![]
-
![]
-
![]
迹的一个非常有趣的性质是,它等于其特征值的和,因此以下关系成立:

正交矩阵
正交性的概念在线性代数中经常出现。它其实只是“垂直”的一种更花哨的说法,只不过它不仅仅局限于二维或一对向量。
为了理解这一点,我们从两个列向量开始 ![]。如果它们是正交的,那么以下关系成立:
。
正交矩阵是一种特殊的矩阵,其中列是成对正交标准化的。这意味着我们有一个矩阵 ![],它具有以下特性:

然后,我们可以推导出 ![] (即 Q 的转置也是 Q 的逆矩阵)。
与其他类型的矩阵一样,正交矩阵也有一些特殊的性质。
首先,它们保持内积,因此以下关系成立:
。
这引出了第二个特性,即正交矩阵保持 2-范数,如下所示:

当与正交矩阵相乘时,可以将其视为一种保持长度的变换,但向量可能会围绕原点旋转一定角度。
最著名的正交矩阵,也是标准化的正交矩阵,是我们已经处理过几次的特殊矩阵。它就是单位矩阵 I,由于它表示轴方向上的单位长度,我们通常称之为标准基。
对角化和对称矩阵
假设我们有一个矩阵 ![],它具有
特征向量。我们将这些向量放入一个可逆矩阵 X 中并将两个矩阵相乘,结果如下:

我们从
知道,当处理矩阵时,这变成了
,其中 ![] 和每个 x[i] 都有唯一的 λ[i]。因此, ![]。
让我们继续讨论对称矩阵。这些是特殊的矩阵,当转置后,它们与原矩阵相同,意味着 ![],并且对所有 ![],有 ![]。这看起来可能有些微不足道,但它的含义却相当深远。
谱定理指出,如果一个矩阵
是对称矩阵,则存在一个正交标准基用于
,其中包含矩阵 A 的特征向量。
这个定理对我们很重要,因为它允许我们分解对称矩阵。我们称之为谱分解(有时也称为特征分解)。
假设我们有一个正交矩阵 Q,其特征向量的标准正交基为 ![] 和 ![],对应的特征值矩阵为 ![]。
从之前的结果中,我们知道 ![] 对于所有 ![] 都成立;因此,我们得出以下结论:

注意:Λ 排在 Q 后面是因为它是一个对角矩阵,而 ![] 需要乘以 Q 的各个列。
通过两边同时乘以 Q^T,我们得到以下结果:

奇异值分解
奇异值分解 (SVD) 在线性代数中广泛应用,并且因其强大而著称,特别是因为每个矩阵都有一个 SVD。其形式如下:

对于我们的目的,假设 ![]、![]、![] 和 ![],并且 U, V 是正交矩阵,而 ∑ 是一个包含矩阵 A 奇异值(用 σ[i] 表示)沿对角线排列的矩阵。
上述方程中的 ∑ 看起来是这样的:

我们还可以将 SVD 写成如下形式:

这里,u[i],v[i] 是 U, V 的列向量。
Cholesky 分解
正如你现在应该已经明白的那样,矩阵分解有不止一种方法,而且对于特定矩阵,有专门的分解方法。
Cholesky 分解类似于平方根,只能应用于对称正定矩阵。
这种方法通过将 A 分解为 LL^T 形式来实现。在这里,L,如之前所述,是一个下三角矩阵。
为了培养一些直觉,它大概是这样的:

然而,在这里,L 被称为 Cholesky 因子。
让我们来看一下 ![] 的情况。
从之前的矩阵中我们知道 ![];因此,我们得到以下结论:

让我们按如下方式相乘右边的上三角和下三角矩阵:

完全写出 A 并将其与我们之前的矩阵等式相比较,得到以下结果:

我们接下来可以逐元素地比较 A 和 LL^T 的对应项,并通过代数方法求解 ![, ],如下所示:

我们可以对任何对称正定矩阵重复这个过程,并计算给定的 a[i,j] 值对应的 l[i,j] 值。
总结
通过这些内容,我们结束了关于线性代数的章节。到目前为止,我们已经学会了线性代数的所有基础概念,如矩阵乘法和因式分解,这将帮助你深入理解 深度神经网络 (DNNs) 是如何工作的,以及它们为何如此强大。
在下一章,我们将学习微积分,并将其与本章前面学到的概念结合,来理解向量微积分。
第二章:向量微积分
你们大多数人可能在过去接触过一些微积分,无论是在高中、大学还是大学里,可能希望再也不碰它。然而,微积分不仅是数学上最深刻的发现之一,它还在深度学习中发挥着至关重要的作用。
在本章中,我们将从介绍单变量微积分的核心概念开始,然后我们将继续学习多变量微积分,并将我们在多变量微积分中学到的内容扩展到向量微积分,并理解它与深度学习的关系。
本章将涵盖以下主题:
-
单变量微积分
-
多变量微积分
-
向量微积分
单变量微积分
从本质上讲,微积分无非是研究关系和变化。对微积分有深刻的理解将帮助你更好地理解深度学习算法的工作原理,并在作为实践者时帮助你让它们更有效地为你服务。
让我们继续了解一下微积分为什么是一个如此强大的工具。我们从单变量微积分开始,它涉及到那些接受单一输入并产生单一输出的函数。
导数
首先,让我们想象一条直线,方程如下:

在这个方程中,以下几点适用:
-
y 是 x 的函数,通常简写为 f(x)(这是我们在本书剩余部分将主要使用的符号)。在前面的方程中,输出值 y 依赖于输入值 x。
-
m 值是梯度,告诉我们直线的陡峭程度,或者说它的变化率(即 x 值的变化对 y 值的影响有多大)。
-
该值 ![] 告诉我们直线是向上还是向下移动。
-
该值 ![] 告诉我们直线相对于原点的位置是向上还是向下。
-
直线中的 m 和 b 值在整个过程中是常量。
现在你已经知道了直线方程的样子,你可能会想知道如何找到任意直线的方程。
我们首先选择两点,(x[1], y[1]) 和 (x[2], y[2]), 它们位于直线上,然后将它们的值代入公式中 ![]。在找到了 m 的值后,我们通过使用直线方程并代入 m 的值和其中一个 (x, y) 点的值,来求解 b。
好吧,这非常简单直接。然而,外面还有许多复杂的方程并不像这样直接——比如那些与曲线(非线性函数)相关的方程,如下图所示:

想象一下几座山丘或骆驼背的图片。如果你沿着它们的表面描绘,你将得到一条曲线,正如你可能已经注意到的那样,它会上升,然后下降,再上升,过程不断重复。
从前面曲线的图像中,你可以很容易看出,梯度不是常数,正如在前面的直线示例中看到的那样。我们可以沿着曲线画出直线并计算它们的斜率来理解曲线如何变化。然而,比这种繁琐方法更简单的方法是存在的。
微积分的核心有两个概念,如下所示:
-
微分帮助我们理解函数输出相对于输入变化的变化量。
-
积分帮助我们理解在某些点之间输入变化的影响。
我们将首先深入研究微分。求导数的基本方程如下所示:

我知道这里有一些新的符号,看起来很复杂,但其实非常简单。这个方程做的是求函数f对于分母中的变量x的导数。这与我们之前看到的方程(我们用来计算直线的梯度)并没有太大区别。我们减去两个值,f(x+h) 和 f(x),然后除以它们的差值,h。但![]与这个有什么关系呢?这告诉我们,我们希望曲线上的两点尽可能靠近,以便当我们在曲线上绘制梯度时,它看起来像是在某一点上的一条直线。这样,我们就能更好地可视化并理解变化的效果,正如下面的截图所示:

请看以下示例:

既然我们已经理解了导数是什么以及如何为任何函数找到导数,让我们继续了解一些重要的微分规则。
求和法则
求和法则表明,两个函数的和的导数等于这两个函数的导数之和,具体如下方程所示:

假设我们有![] 和 ![]。
从这个,我们可以看到以下方程,![],与这个方程是相同的:![]。
幂法则
幂法则有助于找到变量具有指数的函数的导数。简而言之,你将幂次与变量前的常数相乘,并将幂次减小 1。让我们来看一个使用幂法则的例子 ![],如下所示:

请注意,并非每个函数都有导数,至少在该函数的定义域内没有。
有些函数——例如 ![] 或 ![] ——不像我们之前看到的那些函数那样简单。函数 ![] 在 x = 0 处不可导,因为其值是未定义的。这被称为不连续性。
同样适用于 ![];然而,e(即欧拉常数)具有一个非常有趣的特性,即该函数等于其导数——也就是说, ![]。
三角函数
在高中或大学,你可能学习过三角学,并遇到过正弦、余弦和正切函数。对我们来说,更重要的是正弦和余弦函数,你将经常遇到这两者,我们将在这里进行讨论。这些函数可以在以下图片中看到:

在这里,正弦是 ![],余弦是 ![]。
正弦和余弦函数是相关的,导数将向我们展示这种关系。
如果 ![],则 ![]。然而,如果 ![],则 ![]。
导数形成一个循环,我们可以通过以下方式看到:

一阶和二阶导数
既然我们知道如何找到函数的导数,那么接下来需要知道的是,我们可以对函数进行多次求导。
如我们所知,第一导数给出了函数在任意给定点 (x) 处的梯度(切线的斜率)——换句话说,就是该曲线的高度(即 y 或 f(x)) 是在增加还是在减少。正斜率告诉我们 f(x) 随着 x 增加而增加,负斜率告诉我们 f(x) 随着 x 增加而减少,斜率为 0 则告诉我们无法确定曲线的方向,只能推测它可能处于转折点(局部最小值或局部最大值)。这可以写成如下形式:
-
如果 ![],则 f(x) 在 x = t 处是递增的。
-
如果 ![],则 f(x) 在 x = t 处是递减的。
-
如果![],那么 x=t 是 f(x) 的一个临界点。
例如,设![]。该函数的导数如下所示:

在 x = 0 时,导数为 9,这告诉我们函数在这一点是递增的。但在 x = 1 时,导数为-3,说明函数在这一点是递减的。
二阶导数是函数导数的导数。我们将其表示为![] 或 ![]。如同之前,第一导数告诉我们函数是增是减,二阶导数则告诉我们第一导数的增减情况。
如果二阶导数为正,那么随着 x 的增大,第一导数也在增大;如果二阶导数为负,则随着 x 的增大,第一导数在减小。
为了帮助我们可视化,当二阶导数为正时,曲线在某点是向上的凹曲线(抛物线朝上开口);而当二阶导数为负时,曲线是向下的凹曲线(抛物线朝下开口)。正如之前所说,当二阶导数为零时,我们不会获得新的信息。这个点可能是局部最大值、局部最小值或拐点。可以写成如下形式:
-
如果![],那么在 x=t 时,f(x) 是向上的凹曲线。
-
如果![],那么 f(x) 在 x=t 处是向下凹的。
-
如果![],那么在 x=t 处,我们无法获得关于 f(x) 的新信息。
例如,我们可以对之前使用的相同函数求二阶导数,结果如下:

在 x = 0 时,二阶导数为-24,这告诉我们函数在这一点是向下凹的。但在 x = 2 时,二阶导数为 24,说明函数在这一点是向上凹的。
之前我们学到,当 x 是函数的临界点时,我们在该点无法得到关于函数的新信息,但我们可以用它来判断该点是局部最大值还是局部最小值。这些规则可以写成如下形式:
-
如果![] 和 ![],那么 f(x) 在 x=t 处有一个局部最小值。
-
如果![] 和 ![],那么 f(x) 在 x=t 处有一个局部最大值。
-
如果![] 和 ![],那么在 x=t 处我们无法获得关于 f(x) 的新信息。
积分法则
积分法则为我们提供了一种直接的方法来求两个函数的乘积的导数。假设我们有两个任意函数,f(x) 和 g(x),并将它们相乘。所以,![]。其导数为 ![]。
让我们更详细地探讨一下,看看它是如何工作的。请看下面的方程:

我们可以将导数重写为如下形式:

这可以进一步简化为 ![],其结果与之前相同。
商法则
商法则使我们能够求出一个函数与另一个函数相除时的导数。这可以通过积分法则推导出来。和之前一样,我们取两个函数 f(x) 和 g(x),但现在我们将它们相除。所以,![]。其导数为 ![]。
假设我们有 ![] 和 ![]。那么我们得到如下结果:

通过求出 f(x) 和 g(x) 的导数,并将它们代入前面的方程,我们得到以下结果:

如果我们扩展它,就能求出导数。
链式法则
链式法则适用于输入是另一个函数的函数。我们考虑 ![],通常写作 ![],表示 f 是 g 的 x 的函数。这意味着 g(x) 的输出将成为函数 f 的输入。
这个导数将写成如下形式:

这与 ![] 相同。
例如,假设我们有 ![] 和 ![]。我们对这两个函数进行求导,得到 ![] 和 ![]。
将这个代入之前的公式,我们得到 ![]。
反导数
我们现在知道了什么是导数以及如何求导,但现在假设我们知道了人口 (f) 的变化率 (F),并且我们想找出某一时刻的具体人口数量。我们需要做的是找到一个函数 F,使得它的导数是 f。这就是所谓的反导数,我们正式定义它为,如果在 ![] 上,f 的反导数 F 满足 ![] 对所有
成立。
假设我们有一个函数![],然后是,由此我们可以确认![]。
以下表格显示了我们将经常遇到的一些重要函数及其反导数:
| 函数 | 反导数 |
|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
假设我们有以下函数:

我们想要找到它的反导数。我知道这看起来可能是一个复杂的方程,但通过使用前面的表格,我们可以让这一过程变得非常简单。让我们看看如何做。
首先,我们将函数重写为如下形式:

所以,反导数如下所示:

为了简化,我们将其重写如下:
。
就是这样。
现在你可能会想知道我们是否能找到c的值,如果能,应该怎么找。让我们通过另一个例子,看看如何操作。
假设我们有一个是二阶导数的函数,我们想找到反导数的反导数——也就是原始函数。我们有以下内容:
和
和 
然后,第一个反导数如下所示:

所以,二阶反导数如下所示:

在这里,我们想要找出c和d的值。我们可以通过代入前面的值并解出未知数,简单地做到这一点,如下所示:
;因此,
我们还可以这样做:
;因此, 
因此,我们的函数看起来像这样:

积分
到目前为止,我们已经学习了导数,这是一种提取函数变化率的信息的方法。但正如你可能已经意识到的,积分是之前问题的逆过程。
在积分中,我们找到曲线下方的面积。例如,如果我们有一辆车且我们的函数给出了它的速度,曲线下方的面积将告诉我们它在两个点之间行驶的距离。
假设我们有如下曲线 ![],曲线下方在 x = a(下限)和 x = b(上限,亦可写作 [a, b])之间的面积为 S。那么,我们得到以下公式:

曲线的图示如下:

这也可以写成如下形式:

在前面的函数中,以下适用:![],且
位于子区间 ![] 中。
该函数看起来像这样:

积分给我们提供了一个关于曲线下方面积的近似值,以至于对于某些 ε > 0(ε 假定为一个很小的值),适用以下公式:

现在,假设我们的函数既在 x 轴上方也在 x 轴下方,因此它既有正值也有负值,如下所示:

如我们从前面的截图中看到的,x 轴上方的部分 (A[1]) 具有正面积,而* x* 轴下方的部分 (A[2]) 具有负面积。因此,以下公式适用:

与和的运算是评估积分的重要部分,理解这一点需要一些新的和的规则。看下面的例子:
-
![]
-
![]
-
![]
-
![]
-
![]
-
![]
-
![]
现在,让我们探讨积分的一些重要属性,这将帮助我们在深入本章时更好理解。看下面的例子:
-
![]
-
,当 ![] -
![],其中 c 是常数
-
![]
-
![]
-
![]
现在,假设我们有一个函数 ![],它看起来是这样的:

然后,我们得到以下性质:

这个性质只适用于连续且具有相邻区间的函数。
微积分基本定理
微积分基本定理是微积分中最重要的定理,名字也非常恰当,因为它建立了微分学和积分学之间的关系。我们来看看是如何做到的。
假设 f(x) 在 [a, b] 上是连续的,并且在 (a, b) 内可导,且 F(x) 是 f(x) 的原函数。那么,我们得到以下结果:

让我们稍微重写一下前面的方程,使它变成以下形式:

我们所做的只是将 x 替换为 t,并将 b 替换为 x。而且我们知道 F(x)-F(a) 也是一个函数。由此,我们可以推导出以下性质:

我们可以推导出前面的性质,因为 F(a) 是常数,因此它的导数为零。
通过稍微改变我们的视角,我们得到以下函数:

因此,我们得到
。
总结来说,如果我们对函数 f 进行积分,然后再对其求导,我们最终会得到原函数 f。
代换法则
显然,能够找到一个函数的原函数是非常重要的,但反积分公式并没有告诉我们如何计算每种类型的积分——例如,当我们遇到如下的函数时该如何处理:

这并不像我们之前看到的例子那么简单。在这种情况下,我们需要引入一个新的变量来帮助我们,使问题变得更加可管理。
让我们设定一个新的变量 u,并且
,那么 u 的微分就是
。这将问题转化为以下形式:

这显然要简单得多。它的原函数变为以下形式:

然后,代入原始值
,我们得到以下结果:

就这样。
这个方法非常有用,当我们遇到以下形式的问题时,它是有效的:

如果 ![],那么以下公式适用:

那个方程可能看起来对你来说有些相似。它应该是的。这是微分法中的链式法则。
曲线之间的面积
我们知道,积分让我们能够找到两点之间曲线下方的面积。但现在,假设我们想找到两个图形之间的面积,如下图所示:

我们的区域S,如图所示,位于曲线f(x)和g(x)之间,夹在两条竖直线x = a和x = b之间。因此,我们可以将曲线之间的面积近似为以下公式:

我们可以将其重写为如下积分形式:

为了更好地可视化并形成直觉,我们有以下图像:

分部积分法
到目前为止,我们知道每一个微分法则都有对应的积分法则,因为它们之间存在反向关系。
在之前的微分部分,我们遇到了乘积法则。在积分中,对应的法则称为分部积分法。
回顾一下,乘积法则表明,如果f和g是可微的,则以下公式适用:

因此,在积分时,这变成了以下形式:

我们可以按如下方式重写这个公式:

我们可以将这个公式与微积分基本定理结合,得到以下方程:

我们可以利用这一点来计算区间[a, b]之间的积分。
注意:术语 ![ ]仅表示我们将值b代入x并进行计算,然后从a的计算结果中减去它。
我们还可以使用之前的替代法来简化分部积分法中的积分计算。我们进行 ![] 和 ![],然后,微分是 ![] 和 ![]。于是,公式变为:

多变量微积分
现在,我们已经学习了单变量微积分并理解了微积分的基本概念,是时候深入一点,看看多变量微积分了。多变量微积分与单变量微积分有许多相似之处,唯一的区别是——正如其名字所示——在这里,我们将处理接受两个或更多变量作为输入的函数。
多元微积分在现实世界中被广泛应用,几乎所有领域和行业都有涉及,从医疗保健到经济学,再到金融、机器人学、航空航天等等。一个例子是,尝试模拟空气如何绕过飞机,以了解飞机的空气动力学性能以及飞机机身设计在哪些方面可以改进。这是我们在单变量微积分中无法做到的。
偏导数
偏导数是我们用来求解依赖于多个变量的函数的导数的方法,这个导数是关于其中一个变量的偏导数,同时保持其他变量不变。通过这种方法,我们可以了解一个函数是如何受单一变量影响的,而不是所有变量的影响。假设我们在建模某个商品的价格,并且该价格依赖于多个不同的因素。我们可以逐个改变每个变量,来确定这种变化会如何影响商品的价格。这与求总导数不同,总导数是所有变量都变化时的导数。
多元函数可以包含任意多个变量,但为了简化问题,我们将以一个包含两个变量的函数为例,如下所示:

这个函数看起来比我们之前处理的要复杂得多。让我们分解一下。当我们对一个函数关于 x 求偏导数时,我们得到的是 z 随着 x 变化的变化率,同时保持 y 不变。对其他变量求导时也是如此。
让我们直观地想象 xy 平面(一个平面)作为可接受的输入点集。这些点可以作为我们函数的输入。输出 z 可以理解为我们距离 xy 平面的高度。
让我们首先对函数关于
求导,如下所示:

这给我们带来了以下结果:

现在,我们将对 y 进行求导,如下所示:

这给我们带来了以下结果:

正如我们之前所见,在单变量微分中,我们可以对函数求二阶导数(当然是合理的情况下),但在多元微积分中,我们还可以进行混合偏导数的求解,如下所示:

你可能已经注意到,当我们进行混合偏导数时,变量的顺序并不重要,无论我们是先对 x 求导,再对 y 求导,还是反过来,结果都是相同的。
我们还可以以另一种形式来写这个表达式,这种形式通常更为方便,并且我们将在本书中继续使用这种方式。函数如下所示:

链式法则
让我们取一个任意的函数 f,它以变量 x 和 y 为输入,并且某一个变量发生变化,从而得到![]。利用这一点,我们可以通过以下方式找到 f 的变化:

这将我们带入如下方程:

然后,通过取函数的极限![],我们可以推导出偏导数的链式法则。
我们将其表示如下:

我们现在通过一个额外的小量(t),其中 x 和 y 依赖于 t,来除以这个方程,以找到沿![]的梯度。前面的方程变为如下:

我们之前遇到的微分规则在这里仍然适用,并且可以扩展到多变量的情况。
积分
和单变量情况一样,对于依赖多个变量的函数,我们也有反导数和积分。之前我们学到,积分给出了曲线![]下的面积,位于区间[a, b]之间。现在,我们不再寻找区间上的面积,而是寻找图形![]下的体积,位于某个区域内。方程如下:

在上面的方程中,R 是 xy 平面上的一个区域。可以将 R 看作被切割成多个小矩形区域,记为 ΔA。然后,我们可以按如下方式近似体积:

此外,![;]因此,![]。
注意:双重积分并不等同于对积分进行两次计算。
现在,我们不再计算小矩形区域,而是将区域划分为宽度为 Δx 的长且薄的切片。听起来熟悉吗?它应该很熟悉,因为这和我们在单变量积分中做的非常相似。
现在让我们分配![],于是我们的积分变成了如下形式:

然后,我们将结果乘以 Δx。
现在我们可以将积分重写为如下形式:

这里,![] 和 ![]。
假设我们有一个函数![],并且区域的边界定义在![]和![]上。那么,积分为:

通过计算内积分,我们得到如下结果:

通过计算外部积分,我们得到如下结果:

就这样。这就是我们如何找到多变量函数的积分。
现在假设我们有一个函数 ![],我们在区域内对其进行积分,其中 ![] 和 ![]。然后,我们得到如下结果:

这是分配律的直接结果。
我们迄今为止所计算的区域是矩形的,但这不一定总是这样。如果区域是一个不规则的形状,那么每一片的积分限将会有所不同。
解决这个问题的最佳方法是将其写成我们没有进行积分的变量的函数。
假设我们有 ![],且它存在的点集是 ![],这告诉我们 ![] 和 ![]。现在我们可以写成以下形式:

如我们所见,x 定义在区间[a, b]上,y 介于两条* x*的函数之间——g(x) 和h(x)。
我们知道从三角学,特别是毕达哥拉斯定理,y的最小值将是 ![],最大值将是 ![]。
我们现在可以继续重写前面的一组点,如下所示:

这样写和改变写法,将单位圆盘切成了间隔固定宽度的竖直线。
然后,我们的积分变成了这样:

由于 ![],我们可以像这样重写前面的积分:

然后,我们通过计算内积分,再计算外积分,像这样继续:

我们从圆的面积中知道这是正确的: ![]
双重积分的一些重要性质如下所示:
-
![]
-
![],其中c是一个常数
-
![] 如果R可以分成两个区域,R[1] 和 R[2]
-
![] 当 ![] 对于所有 ![] 成立
现在,假设我们有一个带有球形顶部的圆柱体,如下图所示,我们想要求它的体积。球体下方的区域是![],圆柱体内部是![],并且在z = 0之上,如下所示:

我们知道,求一个区域的体积的方法如下:

为了计算这个积分,我们首先将球体的方程重写为![],并且x和y被定义的点集是![]。
我们重写我们的点,并用极坐标系中的θ和半径r来定义区域的边界,使得方程看起来如下:
和
现在,我们可以重写z,如下所示:

所以,体积如下所示:

通过计算内外积分,我们得到以下结果:

我们现在知道如何在
中对区域进行积分并找到图形下的体积。但是当我们有
中的区域时怎么办呢?之前我们对二维区域使用了二重积分;所以,自然,对于三维区域,我们将使用三重积分。我们将其写成如下:

假设现在我们积分的区域由![]、![]和![]定义。三重积分变成如下:

之前我们遇到了一种叫做替换的方法,我们将我们的函数设为一个变量,这样就更容易找到导数。我们在积分中也可以做同样的事情。
假设我们有以下积分:

我们可以设![],然后积分变成这样:

现在,让我们继续研究二重积分,看看如何转化区域以便我们更容易处理。为此,我们需要请出我们熟悉的老朋友——雅可比矩阵来帮忙。
作为复习,假设我们有![]和![]。然后,雅可比矩阵如下所示:

此外,请记住,雅可比矩阵也可以被视为行列式。因此,我们可以将前面的方程重写为:

假设现在我们想对![]在 R 上进行积分。现在,让我们做出![]和![],并将我们的区域重新命名为 S。积分现在看起来像这样:

从中我们可以很容易地观察到![]。
现在让我们继续讲解三重积分。假设我们有一个函数![],并且我们想对其在 R 上进行积分。我们首先做出![],![],和![],并像之前一样将新区域重新命名为 S。雅可比矩阵随后是以下形式:

三重积分现在看起来像这样:

我们现在已经对多变量微积分有了足够的理解,准备深入探索向量微积分的精彩世界。
向量微积分
当我们对关于向量的函数求导时,我们需要更加细心。如我们在第二章《线性代数》中看到的那样,向量和矩阵是不可交换的,并且与标量的行为大不相同,因此我们需要找到一种不同的方式来对它们进行微分。
导数
之前,我们看到通过使用变量在商中的极限来对函数求导。但如我们所知,向量与标量不同,我们不能对向量进行除法运算,这就需要对向量值函数进行新的定义。
我们可以将向量函数定义为一个函数!,也就是说,它接受一个标量值作为输入,并输出一个向量。因此,F 的导数定义如下:

在前面的方程中,δx 是对 x 的小扰动。此外,F 只有在以下条件下才可微分:

我们还可以将前面的微分写成如下形式:

通常,我们按分量对向量进行微分,因此,前面的微分变为:

这里的 e[i] 是一个正交归一基向量。
一些向量微分的规则如下所示:
-
![]
-
![]
-
![]
-
![]
-
![]
-
![]
我们之前知道,使用极限的概念来求解一个函数的导数。那么,接下来我们看看如何求解一个向量的极限。我们在这里使用范数的概念。我们说 ![],因此,如果 ![],那么当
, ![]。
通常情况下,导数是在所有可能的方向上计算的。但如果我们只想在一个特定的方向 n(单位向量)上找到导数呢?那么,假设 δr = hn,我们得到如下结果:

从中我们可以推导出方向导数如下:

这给出了 f 在这个方向上的变化率。
假设现在我们有 n = e[i]。那么,我们的方向导数变为以下:

因此,我们得到以下结果:

因此,差分性条件现在变为以下:

我们可以用微分符号表示如下:

这看起来与我们之前遇到的情况非常相似。它是偏导数的链式法则。
现在让我们取一个函数 ![],它接收一个向量输入
,使得 ![]。该函数的偏导数表示如下:

然后我们可以将其整体表示为一个
向量,我们写作如下:

让我们更进一步,设想一个由 m 个不同标量函数组成的向量函数,这些函数接受向量 x 作为输入。我们将其写为 y = f(x)。
展开 y = f(x),我们得到以下:

让我们简要回顾一下雅可比矩阵。正如你所见,它仅仅是一个包含所有早期向量函数的偏导数的 (m×n) 矩阵。我们可以看到它长什么样:

让我们进一步扩展这个定义到多个函数。这里,我们有 y,它是两个函数 f 和 g 的和,每个函数接受一个不同的向量输入,从而得到以下结果:

为了简化,f、g、a 和 b 都是 n 维的,这会导致一个 n×n 矩阵,如下所示:

我们可以对这个矩阵分别关于 a 或 b 求导,并找出每个的雅可比矩阵。
通过对 a 求导,我们得到以下结果:

通过对 b 求导,我们得到以下结果:

我们可以对两个函数进行任何类型的逐元素操作。
如同单变量和多变量微积分中一样,我们也有向量微分的链式法则。
让我们考虑两个向量函数的组合,它们接受一个向量输入 ![],因此其梯度将是 ![],这看起来与我们之前遇到的相似。让我们进一步展开,如下所示:

在大多数情况下,对于雅可比矩阵中的参数,其中 i ≠ j,参数往往为零,这导致我们得出以下定义:

因此,以下适用:

如我们所见,这是一个对角矩阵。
向量场
我们将向量场定义为一个函数
,只有在以下条件下,它才能被微分:

这里,
是 F 的导数。
我们可以将 M 看作是一个将一个向量映射到另一个向量的矩阵,现在我们可以将 F 表示为:

这里, ![] 对所有 ![] 都成立,因此,F 的导数是:

在单变量和多变量微积分的早期,我们学习了链式法则的重要性,因此我们在向量微积分中也有它,这不足为奇。其原理如下:
假设我们有 ![] 和 ![],并且坐标是 ![],![] 和 ![]。然后,链式法则给出了以下结果:

我们可以将其改写为矩阵形式,如下所示:

逆函数
逆函数是一类非常有趣的函数,如果我们有两个函数,并将它们互相作用,我们会得到恒等式。在数学上,我们将其定义如下:
假设我们有![]。那么,只有当![]时,它们才是反函数。例如,我们可能有![]和![]。因此,![],这告诉我们![]。
这是另一个很酷的属性:

总结
通过这一部分,我们结束了微积分的章节。到目前为止,我们已经学习了单变量、多变量和向量微积分的基本概念,以及它们为何如此有用。
在下一章节中,我们将进入概率与统计,并探讨我们在线性代数和微积分中学到的知识如何在这些领域中应用。
第三章:概率与统计
在本章中,我们将涵盖数学中两个最重要的领域——概率与统计。这是你在日常生活中可能多次遇到的两个术语。人们常用它来为发生的事情辩解或证明某个观点。完成本章后,你将牢固掌握这两者,并理解它们是如何相互关联和不同的。
本章将涉及以下内容:
-
理解概率中的概念
-
统计学中的基本概念
理解概率中的概念
概率论是数学中最重要的领域之一,并且对于理解和构建深度神经网络至关重要。我们将在接下来的章节中探讨这一论断的具体内容。不过,现在我们将重点放在深入理解这个领域上。
我们使用概率论来理解某个事件发生的可能性。一般来说,概率论是关于理解和处理不确定性的学科。
古典概率
假设我们有一个随机变量,它将随机实验的结果映射到我们感兴趣的属性上。上述的随机变量衡量了一个或多个结果集合发生的可能性(概率)。我们称这种分布为 概率分布。请将概率分布视为我们将在本章中研究的概念基础。
概率论中有三个非常重要的概念——概率空间、随机变量和概率分布。让我们首先定义一些较基础但重要的概念。
样本空间是所有可能结果的集合。我们用 Ω 来表示它。假设我们有 n 个可能的结果,那么我们有 ![],其中 w[i] 是一个可能的结果。样本空间(Ω)的子集称为 事件。
概率与集合密切相关,因此让我们先了解一些符号,以便更好地掌握接下来将出现的概念和例子。
假设我们有两个事件,A 和 B,⊆ Ω。我们有以下公理:
-
A 的补集是 A^C,因此 ![]。
-
如果 A 或 B 其中一个发生,那么写作 A ∪ B(读作 A 并集 B)。
-
如果 A 和 B 都发生,那么写作 A ∩ B(读作 A 与 B 的交集)。
-
如果 A 和 B 是互斥事件(或不相交事件),那么我们写作 ![.]
-
如果 A 的发生意味着 B 的发生,那么写作 A ⊆ B(因此, ![])。
假设我们有一个事件,A ∈ Ω,且 ![]。在这种情况下,A 发生的概率定义如下:

这是 A 发生的次数除以样本空间中可能结果的总数。
让我们来看一个简单的掷硬币的例子。在这里,样本空间由掷硬币的所有可能结果组成。假设我们处理的是两次掷硬币而不是一次,其中 h 表示正面,t 表示反面。那么,样本空间是 Ω = {hh, ht, th, tt}。
所有实验的可能结果构成事件空间,![]。实验完成后,我们观察结果 ω ∈ Ω 是否在 A 中。
由于在每个事件中,![],我们用 P(A) 表示事件发生的概率,并且我们读作 P(A) 是事件 A 发生的概率。
从前述公理继续,
必须满足以下条件:
-
![] 对所有情况的 ![]。
-
![]。
-
如果事件 A[1], A[2], … 是互不相交且可列加的——即,对于所有 i, j——我们可以得到 ![]。
这三项 ![] 被称为 概率空间。
作为经验法则,当 ![],则事件 A 几乎肯定会发生,而当 ![],则事件 A 几乎不会发生。
使用前面的公理,我们可以推导出以下结论:

所以, ![]。
此外,如果我们有两个事件,A 和 B,则可以推导出以下结论:
。
从前述公理继续,
必须满足以下条件:
![] 对所有 
为了找到任何事件的概率,通常我们需要计数。假设我们有一个装满网球的桶,并且我们从桶中抽取 r 次球;那么,第一次抽取有 n[1] 种可能性,第二次抽取有 n[2] 种可能性,依此类推。总的选择数是 n[1]×n[2]×…×n[r]。
有放回和无放回抽样
现在假设桶中有 n 个物品,我们必须从中选取 r 个。然后,令 R = {1, 2,…, r} 表示被选中的物品列表,N = {1, 2, …, n} 表示所有物品的总数。可以写成一个函数,如下所示:

这里,f(i) 是第 i^(th) 项。
放回抽样是指我们随机挑选一个物品,然后将其放回,这样该物品可以再次被挑选。
然而,不放回抽样是指我们选择一个物品后不将其放回,因此无法再次选择它。让我们来看一下两者的例子。
假设我们需要打开办公室的门,我们有一个袋子,里面有n把钥匙;它们看起来都一模一样,因此无法区分。
第一次我们尝试挑选钥匙时,每试一次就将钥匙放回去,我们最终在r^(th)试验时找到了正确的钥匙,意味着我们错了 r-1 次。概率为:

现在,我们知道之前的策略并不是最聪明的,所以这次我们尝试不放回抽样,并且淘汰每把不对的钥匙。现在,概率如下:

多项式系数
我们从二项式定理(你很可能在高中学过)知道以下是正确的:

然后,三项式如下:

假设我们有n颗糖果,糖果有蓝色和红色两种。我们挑选糖果的不同方式定义为![],这可以读作n选择k。
多项式系数如下:

这样,我们将n个物品分配到k个位置,其中第i^(th)位置有n[i]个物品。
例如,假设我们在打牌,四个人在一起玩。一副扑克牌有 52 张卡牌,我们给每位玩家发 13 张牌。那么,我们可以分发这些牌的可能方式如下:

这真是庞大无比!
这时,斯特林公式派上了用场。它可以帮助我们近似计算答案。
斯特林公式
为了方便讨论,假设![]。
我们知道以下是正确的:

然而,我们现在声明以下内容:

这可以通过以下方式来说明:

现在,通过求解积分,我们得到以下结果:

我们现在将两边都除以![],并让n→∞。我们观察到两边都趋向于 1。因此,得到以下结果:

斯特林公式表明,当n→∞时,以下是正确的:

此外,我们有以下内容:

我们将避免讨论斯特林公式的证明,但如果你有兴趣了解更多,强烈推荐你去查阅相关资料。
独立性
事件在相互不相关时是独立的;也就是说,一个事件的结果不会影响另一个事件的结果。
假设我们有两个独立事件,A和B。那么,我们可以测试以下内容:

如果这不成立,则说明事件是相关的。
想象一下你在赌场里玩掷骰子。你投掷了两个骰子——它们的结果是相互独立的。
独立性的一个有趣性质是,如果A和B是独立事件,那么A和B^C也是独立的。
让我们看一下这个是如何工作的:

当我们有多个事件,A[1], A[2], …, A[n],如果对于所有 n ≥ 2 的情况,![],我们称这些事件是相互独立的。
假设我们在实验室里进行两个实验;我们将它们独立建模为![]和![],每个实验的概率分别为![]和![]。如果这两个实验是独立的,那么我们得到以下结果:

这适用于所有i和j的情况,我们的新样本空间为Ω = Ω[1]×Ω[2]。
假设A和B分别是Ω[1]和Ω[2]实验中的事件。我们可以通过计算A × Ω[2]和B × Ω[1],将它们视为新样本空间Ω的子空间,从而得到如下结果:

即使我们通常将独立性定义为同一实验中不同(不相关)结果之间的关系,我们也可以将其扩展到任意数量的独立实验。
离散分布
离散指的是我们的样本空间是可计数的,比如投掷硬币或掷骰子的情况。
在离散概率分布中,样本空间是![]和![]。
以下是我们在概率论中常遇到的六种离散分布:
-
伯努利分布
-
二项分布
-
几何分布
-
超几何分布
-
泊松分布
让我们依次定义它们。
对于伯努利分布,假设我们以抛硬币为例,其中我们的样本空间为Ω = {H, T}(其中H代表正面,T代表反面),且p ∈ [0, 1](即 0 ≤ p ≤ 1)。我们将该分布记作B(1, p),因此有如下公式:
和
但现在,假设硬币被投掷n次,每次投掷正面结果的概率是p。那么,二项分布,记作B(n, p),表示如下:

因此,我们得到如下公式:

通常,二项分布表示如下:

几何分布不会记录过去事件的任何信息,因此是无记忆的。假设我们再次投掷硬币;这个分布并不会告诉我们何时可以期望出现正面结果,或者需要多长时间才能得到正面。因此,我们将得到正面结果的概率,在经历了k次反面后,表示如下:

假设我们有一个装满红色和黑色球的桶(我们分别表示为 r 和 b)。从桶中我们拿出了 n 个球,我们想计算其中 k 个球是黑色的概率。为此,我们使用超几何分布,其形式如下:

泊松分布与其他分布略有不同。它用于建模发生的稀有事件,发生率为λ。它记作 P(λ),并表示如下:

条件概率
条件概率在一个事件的发生导致另一个事件发生时非常有用。如果我们有两个事件,A 和 B,其中 B 已经发生,我们想找到 A 发生的概率,那么我们可以这样表示:

这里,![]。
然而,如果两个事件 A 和 B 是独立的,那么我们有:

此外,如果![],那么可以说 B 吸引 A。然而,如果 A 吸引 B^C,那么它会排斥 B。
A和B之间的吸引力是双向的;也就是说,A 只有在 B 也吸引 A 时,才会吸引 B。
以下是一些条件概率的公理:
-
![.]
-
![.]
-
![.]
-
![] 是一个仅对 B 的子集有效的概率函数。
-
![.]
-
如果![],那么![。]
以下方程被称为贝叶斯定理:

这也可以表示为:

这里,我们有以下内容:
-
![] 被称为先验。
-
![] 被称为后验。
-
![] 是似然函数。
-
![] 作为归一化常数。
符号读作与...成比例。
通常,我们最终需要处理复杂事件,为了有效地处理这些事件,我们需要将其分解为更简单的事件。
这引出了分区的概念。分区定义为一组事件,这些事件一起构成样本空间,对于所有的B[i],有![]。
在掷硬币的例子中,样本空间被分成两种可能的事件——正面和反面。
如果A是一个事件,B[i]是Ω的一个分区,那么我们有以下内容:

我们还可以将贝叶斯公式用分区的形式重写,如下所示:

这里,![]。
随机变量
随机变量是附有概率分布的变量,它决定了每个变量可以取的值。我们将随机变量视为一个函数,X:Ω → Ω[x],其中![]。X函数的值域记作![]。
离散随机变量是可以取有限或可数无限值的随机变量。
假设我们有S∈Ω[x]:

这是S为包含结果的集合的概率。
在随机变量的情况下,我们关注的是随机变量取某个特定值的概率,而不是某个特定事件发生的概率。
如果我们的样本空间是可数的,那么我们有以下内容:

假设我们有一个骰子,X是掷骰子的结果。那么,X的样本空间为Ω[x]={1, 2, 3, 4, 5, 6}。假设这个骰子是公平的(无偏),那么我们有以下内容:

当我们有有限数量的可能结果,并且每个结果赋予相同的概率时,即每个结果的可能性都与其他结果相等时,我们称这种分布为离散均匀分布。
假设X∼B(n, p)。那么,X取值为r的概率如下:

有时候,在概率文献中,![]写作![]。
很多时候,我们可能需要找到随机变量的期望(平均)值。我们使用以下公式来做这件事:

我们也可以将上述方程写成如下形式:

前面的两个方程只在我们的样本空间是离散(可数)时有效。
以下是一些关于 ![] 的公理:
-
如果 ![],则 ![]。
-
如果 ![] 和 ![],则 ![]。
-
![.]
-
![],假设 α 和 β 是常数,且 X[i] 不是独立的。
-
![],适用于当 X[i] 是独立时。
-
![] 最小化 ![] 关于 c。
假设我们有 n 个随机变量。则它们的期望值如下:

现在我们对实值随机变量的期望有了较好的理解,接下来我们将定义两个重要的概念——方差和标准变量。
方差
我们定义 X 的方差如下:

X 的标准差是方差的平方根:

我们可以把它理解为值与期望(均值)之间的离散程度。如果它们高度分散,则方差很大;如果它们聚集在一起,则方差较小。
下面是一些关于方差的性质,重要的是要记住:
-
![.]
-
如果 ![],则 ![]。
-
![.]
-
![.]
-
![],假设所有的 X[i] 值是独立的。
假设我们现在有
个离散随机变量。则如果我们取以下值,它们是独立的:

现在,设我们的 n 个随机变量是独立且同分布(iid)。我们现在有以下内容:

这个概念非常重要,尤其在统计学中。它意味着,如果我们想要减少实验结果的方差,我们可以多次重复实验,样本平均值的方差会变小。
例如,假设有两根长度未知的绳子——分别为 a 和 b。由于这些物体是绳子——因此是非刚性的——我们可以测量绳子的长度,但我们的测量可能并不准确。令 A 为绳子 a 的测量值,B 为绳子 b 的测量值,那么我们有以下表达:

我们可以通过测量 X = A + B 和 Y = A – B 来提高测量的准确性。现在,我们可以使用以下方法估算 a 和 b:

现在,![] 和 ![],它们都是无偏的。此外,我们可以看到,使用以下方法,我们的测量方差减少了:

从中我们可以清楚地看到,将绳子一起测量,而不是单独测量,显著提高了我们的准确度。
多个随机变量
很多时候,我们会遇到多个随机变量。当我们有两个或更多变量时,我们可以检查这些随机变量之间的线性关系。我们称之为协方差。
如果我们有两个随机变量 X 和 Y,那么协方差定义如下:

以下是协方差的一些公理:
-
如果 c 是常数,那么 ![.]
-
![.]
-
![.]
-
![.]
-
![.]
-
![.]
-
![],假设 X 和 Y 是独立的(但这并不意味着它们是独立的)。
-
![]
然而,有时协方差并没有完全反映出两个变量之间的相关性。这可能是由 X 和 Y 的方差造成的。因此,我们将协方差标准化如下,得到相关性:

结果值将始终位于 [-1, 1] 区间内。
这引出了条件分布的概念,在这种情况下我们有两个随机变量 X 和 Y,它们不是独立的,并且我们有联合分布,![],我们可以从中得到概率,![] 和 ![]。然后,我们的分布定义如下:

从这个定义中,我们可以得到条件分布 X 给定 Y 如下:

我们也可能想要找到给定Y的条件期望X,其表达式如下:

现在,如果我们的随机变量是独立的,那么 ![],我们知道这是真的,因为Y 对X没有影响。
连续随机变量
到目前为止,我们已经看过了样本空间中的离散结果,在其中我们可以找到某个结果的概率。但是现在,在连续空间中,我们将找出我们的结果处于某个特定区间或范围内的概率。
现在,为了找到X的分布,我们需要定义一个函数 f,使得X的概率必须位于区间 ![] 内。
形式上,随机变量
是连续的,如果在一个函数中, ![],这样我们得到以下结果:

我们称函数 f为概率密度函数(PDF),它必须满足以下条件:
-
![]
-
![]
还有一个对我们非常重要的分布函数,我们称之为累积分布函数。如果我们有一个随机变量X,它可以是连续的或离散的,那么 ![],其中F(x)是递增的,以至于 x→∞时,F(x)→1。
当我们处理像以下这样的连续随机变量时,我们知道F既是连续的又是可微的:

所以,当F可微时,F'(x) = f(x)。
一个重要的事实是![]。
这引出了均匀分布的概念,均匀分布一般具有如下的概率密度函数(PDF):

所以,我们得到以下结果:

这就是
的情况。
如果X在区间[a, b]上服从均匀分布,我们写作 ![]。
现在,假设我们的随机变量是一个指数型随机变量,并且它有一个附加的 λ 参数。那么,它的概率密度函数(PDF)是 ![],并且对于所有
来说,函数为![]。
我们将其写为 ![],所以我们得到以下公式:

还需要非常注意的是,指数型随机变量,比如几何型随机变量,是无记忆的;也就是说,过去的事件不会给我们关于未来的任何信息。
就像在离散情形中一样,我们可以在连续随机变量的情况下定义期望和方差。
连续随机变量的期望值定义如下:

但是,假设 ![]。那么,我们有如下公式:

对于连续随机变量,方差定义如下:

这给出了如下公式:

现在,举个例子,假设我们有 ![]。我们可以如下求出 X 的期望值:

它的方差可以如下计算:

现在,我们已经很好地掌握了连续分布中的期望和方差。接下来,让我们了解两个与概率密度函数(PDF)相关的额外术语——众数 和 中位数。
在概率密度函数中,众数是出现频率最高的值;然而,众数也可能出现多次。例如,在均匀分布中,所有的 x 值都可以视为众数。
假设我们有一个概率密度函数 f(x)。那么,我们将众数表示为
,因此,![] 对于所有的 x 都成立。
我们定义中位数如下:

然而,在离散情况下,中位数如下所示:

在概率论中,很多时候我们使用样本均值而不是总体均值。假设我们有一个包含 X 所能取所有值的分布。从中,我们随机抽取 n 个值并取平均值,那么我们可以得到如下公式:

联合分布
到目前为止,我们处理并学习了与单一随机变量相关的分布;但现在,假设我们有两个随机变量,X 和 Y。那么,它们的联合分布定义为 ![],使得 ![]。
在联合分布中,我们通常希望知道一组变量的分布,但有时,我们可能只想知道某个子集的分布。我们称这种分布为边缘分布。我们将 X 的边缘分布定义如下:

假设我们在 A 中的 n 个连续随机变量是联合分布,并且具有 f 的概率密度函数(PDF)。那么,我们有如下公式:

在这里,![] 和 ![]。
让我们回顾一下之前的一个例子,其中我们有两个变量,X 和 Y。如果这些变量是连续的,那么它们的联合分布为 ![] 和 ![]。
如果随机变量是联合连续的,那么它们也是个别连续的。
现在,假设我们的n个连续随机变量是独立的。那么, ![] 对于所有情况的 ![]。
如果 ![] 是累积分布函数,而 ![] 是概率密度函数(PDF),那么 ![] 和 ![]。
更多概率分布
在本章早些时候,我们在随机变量部分介绍了几种不同类型的分布。我相信,在某个时刻,你可能会想,一定也有适用于连续随机变量的概率分布
。
正态分布
以下分布是一个相当重要的分布,称为正态分布。它的形状如下:

正态分布,写作 ![],在所有情况中都有 ![] 的概率密度函数(PDF),适用于所有
。
此外,我们还有以下内容:

当正态分布具有 ![] 和 ![] 时,它被称为标准正态分布,我们将 ![] 表示为其概率密度函数(PDF),并将 ![] 表示为其累积分布函数。
正态分布具有一些相当有趣的属性,具体如下:
-
![]
-
![]
假设我们有两个独立的随机变量, ![] 和 ![],那么我们有以下结果:
-
![]
-
![],其中 a 为常数
该概率分布之所以如此重要,是因为它与中心极限定理的关系,中心极限定理表明,如果我们有大量独立且同分布的随机变量,那么它们的分布将近似于正态分布。
多元正态分布
正态分布也可以扩展到多个随机变量,这就给出了多元正态分布。
假设我们有n个独立同分布(iid)随机变量,采样自N(0, 1)。然后,我们定义它们的联合密度函数如下:

这里, ![]。
让我们进一步讨论。现在,假设我们有一个可逆的n×n矩阵A,并且我们对![]感兴趣。那么,![]和![]。因此,我们得到如下结果:

在这里,![]。因此,Z是多元正态分布,其表达式如下:

你可能想知道这个新矩阵![]代表什么。它是协方差矩阵,其中第i和第j个元素为![]。
当协方差为 0 时,这意味着变量是独立的,则![]。
二元正态分布
当n = 2时,表示多元正态分布的特例,称为二元正态分布。其协方差矩阵表示如下:

其逆运算如下:

在这种情况下,两变量之间的相关性变为如下:

为了简化,我们假设均值为 0,因此二元正态分布的联合 PDF 如下:

Gamma 分布
Gamma 分布是一种广泛使用的分布,用于建模偏态分布的正值连续变量。
Gamma 分布用![]表示,其 PDF 为:

至此,我们结束了概率部分的内容,接下来将开始探讨统计学。
统计学中的基本概念
概率使我们能够衡量和计算事件或结果发生的几率,而统计学则使我们能够根据由某个未知概率模型生成的数据做出判断和决策。我们使用这些数据来学习潜在概率模型的属性。我们称这个过程为参数推断。
估计
在估计中,我们的目标是给定n个具有与X相同分布的独立同分布(iid)样本(概率模型)。如果 PDF 和概率质量函数(PMF)是![],我们需要找到θ。
正式地,我们定义一个统计量作为θ的估计量。
统计量是数据的一个函数,T,![],因此我们的估计是![]。因此,T(x) 是统计量的采样分布,是θ的估计量。
在后续的讨论中,X 表示随机变量,x 表示观测值。
假设我们有 ![],它们是独立同分布的 ![]。然后,μ 的一个可能估计如下:

然而,我们对特定观察样本
的估计如下:

判断我们的估计量是否优秀的一种方法是偏差。偏差定义为真实值与期望值之间的差异,记作 ![]。如果 ![],则估计量是无偏的。
均方误差
均方误差 (MSE) 是衡量估计量好坏的指标,它比偏差更能有效地反映这一点。我们可以将其表示为:

然而,有时我们使用根均方误差,它是均方误差的平方根。
我们还可以通过偏差和方差来表示 MSE,如下所示:

有时候,当我们试图获得较低的均方误差(MSE)时,拥有一个带偏估计量且方差较低对我们最有利。我们称之为 偏差-方差权衡。
充分性
很多时候,进行实验的目的是为了找到 θ 的值并理解更大的背景。充分统计量就是能够提供关于 θ 所有信息的统计量。
幸运的是,分解定理使我们能够找到充分统计量。它指出,如果我们满足以下条件,T 就是 θ 的充分统计量:

这里,g 和 h 是任意函数。
一般来说,如果 T 是一个充分统计量,那么它不会丧失任何关于 θ 的信息,最佳的统计量是能够最大程度减少信息的那个。我们称之为最小充分统计量;根据其定义,T(X) 是最小的,前提是它是所有其他统计量的函数。因此,如果 T'(X) 是充分的,那么 T'(X) = T'(Y) ⇒ T(X) = T(Y)。
假设 T = T(X) 是一个统计量,满足 ![],当且仅当 ![] 时,它不依赖于
。那么,T 是 θ 的最小充分统计量。
接下来,假设我们有 ![],它们是独立同分布的 ![]。然后,我们可以推导出以下结论:

这是一个常数函数,它告诉我们 ![] 和 ![]。因此, ![] 是最小充分的。
最小充分统计量的优势在于,它们使我们能够以最有效的方式存储实验结果,并且可以用来改进我们的估计器。
这引出了 Rao-Blackwell 定理,它表明,如果![] 是 θ 的充分统计量,并且如果![] 是 θ 的估计量——其中对于所有的 θ,![]。让![],那么对于所有 θ 的情况,我们有![]。
似然
通常在实践中,当我们想确定我们的估计器是否好时,我们通常使用最大似然估计器(MLE)。
给定 n 个随机变量(其中![] 是联合概率密度函数),如果 X = x,则 θ 的似然定义为![]。因此,θ 的最大似然估计(MLE)是最大化![]的估计值。
然而,在实际中,我们最大化的是对数似然函数,而不仅仅是似然函数。
回到有 n 个独立同分布随机变量的例子,假设它们具有![] 概率密度函数(PDF),其似然函数和对数似然函数如下:

假设我们的 n 个变量是伯努利分布(p)。那么,![]。因此,![] 当![] 等于 0 时,它是一个无偏的最大似然估计器(MLE)。
到现在为止,你可能在想 MLE 与充分性到底有什么关系。如果 T 对 θ 是充分的,那么它的似然是![],而为了最大化我们的估计,我们必须最大化 g。因此,MLE 是充分统计量的函数——瞧!
置信区间
置信区间使我们能够确定某些区间包含 θ 的概率。我们将其正式定义如下。
一个![] θ 的置信区间是一个随机区间![],使得![],无论 θ 的真实值如何。
假设我们为多个样本 x 计算了![],那么,100γ% 的样本会覆盖我们的真实值 θ。
假设我们有 ![],它们是独立同分布的 ![],并且我们想要找到 95% 置信区间的 θ。我们知道 ![],因此 ![]。接着,我们选择 z[1], z[2],使得 ![],其中 Φ 是正态分布。因此,
,从中我们得到以下置信区间:

这是一个常用的三步法,用来寻找置信区间:
-
找到 ![],使得 ![] 的 ![] 与 θ 无关。我们称其为枢轴。
-
在上面的 ![],以 ![] 的形式书写概率陈述。
-
调整不等式以找到该区间。
通常,c[1] 和 c[2] 是已知分布中的百分位数;例如,对于 95% 置信区间,我们会有 2.5% 和 97.5% 的点。
贝叶斯估计
在本节统计学中,我们讨论的是所谓的频率学派方法。现在,然而,我们将探讨所谓的贝叶斯方法,在这种方法中,我们将 θ 视为一个随机变量,我们通常会对其分布有先验知识,经过一些额外数据的收集后,我们找到后验分布。
正式地,我们将先验分布定义为收集任何额外数据之前,θ 的概率分布;我们表示为 π(θ)。后验分布是 θ 的概率分布,依赖于我们进行实验的结果;我们表示为 π(θ|x).
先验分布和后验分布之间的关系如下:

通常,我们避免计算 ![],而只观察其关系:

我们可以将其读取为 ![]。
在进行实验并得到后验分布之后,我们需要确定一个估计量,但为了找到最好的估计量,我们需要一个损失函数,如二次损失或绝对误差损失,以查看 θ 的真实值与我们估计的参数值之间的偏差。
假设我们要估计的参数是 b。那么,贝叶斯估计量 ![],最小化预期的后验损失,如下所示:

如果我们选择我们的损失函数为二次损失,那么我们得到如下结果:

然而,如果我们选择绝对误差损失函数,则我们有以下结果:

由于后验分布是我们真实的分布,我们知道通过对其进行积分,结果如下:

如果你在想这两种统计学流派有什么不同,可以将频率主义者和贝叶斯学派分别理解为绝对与相对的对比。
假设检验
在统计学中,我们通常需要检验假设,并且很可能会比较两种不同的假设——零假设和备择假设。零假设告诉我们,实验没有统计学意义;也就是说,变量之间没有观察到关系。备择假设则告诉我们,变量之间存在某种关系。
一般来说,我们从假设零假设为真的前提出发,若要拒绝零假设,我们需要通过实验找到与之矛盾的证据。
简单假设
一个简单假设H是指分布的参数完全确定的假设,否则称为复合假设。
在检验零假设(H[0])与备择假设(H[1])时,我们使用我们的检验将
划分为两个区域C和![]。如果![],则我们拒绝零假设,但如果![],则我们不拒绝零假设。我们称C为临界区。
当我们进行假设检验时,希望得到正确的结论,但我们可能会犯以下两种错误:
-
错误 1:在H[0]为真时拒绝H[0]
-
错误 2:在H[0]为假时不拒绝H[0]
如果H[0]和H[1]都是简单假设,那么我们有以下情况:

这里,α是我们检验的大小,1-β是检验的功效,即发现H[1]的概率。
如果我们有一个简单假设,
,那么我们也想要找到给定x时的似然性。我们可以这样做:

我们还可以找到给定x时H[0]和H[1]的似然比,方法如下:

似然比检验是指,给定k时,临界区域如下:

让我们通过一个例子来进行演示,并对其进行一些直观的理解。假设我们有 ![],它们是独立同分布的 ![],并且 ![] 是已知的量。现在,我们想要找出针对原假设 ![],相对于备择假设 ![],最佳的检验大小。假设我们还知道
和
,使得
。因此,我们得到了以下内容:

我们知道这个函数是递增的,所以对于任何 k, ![],这告诉我们对于某些任意的 c 值,
。
我们选择
的值,使得 ![],如果
,我们拒绝原假设。
在原假设下,![];因此, ![]。现在,由于
,如果我们有以下情况,检验大小将拒绝原假设:

这就是所谓的 z-检验,我们用它来检验假设,而 z 分数告诉我们数据点距离均值有多少个标准差。
这里,似然比会在 z > k 时拒绝原假设。检验大小是 ![],随着 k 增加而减小。如果 ![],则 z 的值位于拒绝区间内。
在上面的方程中,*p^** 被称为数据 x 的 p-值;换句话说,它是观察到的数据(证据)与原假设相对的概率。
复合假设
现在,如果我们有一个复合假设,例如 ![],那么误差概率不是单值的。
所以,我们定义了功效函数,如下所示:
。
理想情况下,我们希望 W(θ) 在原假设下较小,而在备择假设下较大。
检验的大小是 ![],这不是理想的大小。考虑到 ![],我们得到 ![]。
之前我们看到了,H[0] 和 H[1] 的最佳检验大小是由以下临界区域给出的:

这取决于![]和![],但与![]的值无关。
我们称由C指定的测试为均匀最强的大小,
,即![]测试与![]之间的比较,但前提是以下条件成立:
-
![]
-
![]对于所有![]的情况,如果![]
现在,和之前一样,我们想要找到一个复合假设的似然性,![],给定一些数据,x。我们按以下方式进行:

多元正态理论
在这一部分中,我们到目前为止处理的是随机变量或一组独立同分布的随机变量。现在,假设我们有一个随机向量,![],其中X[i]值是相关的。
现在,如果我们想找到X的均值,我们可以如下操作:

如果它存在,协方差矩阵如下:

此外,如果我们有![],那么![]和![]。
如果我们处理的是两个随机向量,那么我们有以下内容:
-
![]
-
![]
现在,让我们定义什么是多元正态分布。
假设我们有一个随机向量,X。如果对于![],![]具有正态分布,则它有一个多元正态分布。
如果![]和![],那么![],其中![]是对称且半正定矩阵,因为![]。
你们中的一些人可能在想多元正态分布的 PDF 是什么样子的。我们马上就会看到。
现在,假设![],并且我们将
分成两个较小的随机向量,使得![],其中![]和![]。
类似地,![]和![]。
现在,我们得到以下内容:
-
![]
-
X[1] 和 X[2] 如果![] 是独立的
当![]是半正定时,X具有以下 PDF:

这里,n 是 x 的维度。
假设我们有 ![],它们是独立同分布的![,] 和![] 以及![]。然后,我们得到以下内容:
-
![]
-
![]
-
X 和 S[xx] 是独立的
线性模型
在统计学中,我们使用线性模型来建模因变量与一个或多个预测变量之间的关系。
例如,假设我们有 n 个观测值 Y[i] 和 p 个预测变量 x[j],其中 n > p。我们可以将每个观测值写为:

对于所有的![],我们可以假设如下:
-
![] 是我们希望找出的未知固定参数
-
![] 是第 i^(th) 响应的 p 个预测变量的值
-
![] 是独立的随机变量,具有 0 均值和σ²方差
我们通常认为![]是x[ij]的因果效应,ε[i]是一个随机误差项。因此,![], ![] 和![]是独立的。
给定所有数据,我们可能希望在数据上绘制一条直线,所以一个可能的模型可以如下所示:

这里,a 和 b 是常数。
我们可以将前面的模型重写如下:

这里,扩展形式如下所示:

同样,![] 和![]。
最小二乘估计量,![],通过最小化线条与点之间垂直距离的平方来最小化我们的线性模型,如下所示:

为了最小化它,我们对所有 k 的情况应用以下内容:

因此,我们得到![],并且对所有 k 的情况,![]。
将前面的函数转换为矩阵形式,正如我们之前所做的,我们得到 ![]。
我们知道 ![] 是正定的,半正定的,并且具有逆矩阵。因此, ![]。
在正常假设下,我们的最小二乘估计量与最大似然估计(MLE)相同。
现在我们有了以下内容:

这告诉我们我们的估计量是无偏的,并且 ![]。
我知道你在想什么——那真是太紧张了!做得好,能够走到这一步;我们已经非常接近完成这一章了,所以再坚持一下。
假设检验
在假设检验中,我们的目标是确定某些变量是否对结果产生影响。
让我们检验一个一般线性模型的假设。假设我们有 ![] 和 ![]。我们想要检验 ![] 与 ![] 和 ![],因为在H[0]下, ![] 消失。
在零假设下,β[0] 和 σ² 的最大似然分别为 ![] 和 ![], ]而我们从之前知道,它们是独立的。
零假设的估计量戴着两顶帽子,而备择假设只有一顶。
恭喜你!你已经正式完成了这一章,并且现在已经对概率和统计有了扎实的直觉。
总结
在这一章中,我们学习了许多概念。如果需要的话,我建议再读一遍这一章,因为这些话题对于深入理解深度学习非常重要。很多人可能会想,直到现在学习的内容与神经网络有什么关系;我们将在接下来的几章中把它们串联起来。
下一章将重点介绍凸优化和非凸优化方法,并为理解训练神经网络时使用的优化算法奠定基础。
第四章:优化
优化是应用数学的一个分支,广泛应用于物理学、工程学、经济学等多个领域,在深度神经网络的开发和训练中具有至关重要的作用。在本章中,我们之前章节所涉及的很多内容将非常相关,特别是线性代数和微积分。
正如我们所知,深度神经网络是在计算机上开发的,因此可以用数学表达式表示。通常,训练深度学习模型归结为找到正确(或者尽可能接近正确的)参数集。我们将在本书的进一步学习中了解更多内容。
在本章中,我们主要将学习两种类型的连续优化——约束优化和无约束优化。然而,我们还将简要介绍其他形式的优化,如遗传算法、粒子群优化和模拟退火。在这个过程中,我们还将学习何时以及如何使用这些技术。
本章将涵盖以下主题:
-
理解优化及其不同类型
-
探索各种优化方法
-
探索种群方法
理解优化及其不同类型
在优化中,我们的目标是要么最小化,要么最大化一个函数。例如,企业希望在最大化利润的同时最小化成本,或者购物者可能希望在尽可能少花费的情况下得到尽可能多的东西。因此,优化的目标是找到满足特定标准的最佳情况
,表示为 x^* (其中 x 是一组点),这些标准是对我们来说的数学函数,称为 目标函数。
例如,假设我们有![] 方程。如果我们绘制它,我们将得到如下图表:

你会从第一章,向量微积分中回忆起,我们可以通过求取函数的导数,将其等于 0,并解出 x 来找到函数的梯度。我们可以找到函数具有最小值或最大值的点,如下所示:

解这个方程后,我们发现它有三个不同的解(即,三个函数的最小值和最大值出现的点)。
为了找到这三个解中哪些是最小值和最大值,我们求出二阶导数,![],并检查我们的驻点是正值还是负值。
从图形上看,当我们看到图表时,可以识别局部和全局最小值,但在计算时并不像这样简单。所以,我们从一个值开始,沿着梯度前进,直到到达最小值(希望是全局最小值)。
假设我们从右侧开始,x = 2。梯度是负的,这意味着我们逐渐向左移动(这些增量叫做步长),然后我们到达局部最小值,但这不是我们想找到的最小值。然而,如果我们从x = -2开始,我们最终会到达全局最小值。
有约束优化
有约束优化,通常有一些规则或约束必须遵循。一般来说,问题的定义形式如下:

在前面的方程中,
包含了决策变量,![]是我们的目标函数,![]和
是功能约束,而![]是区域约束。
所有这些变量都是向量;实际上,本章中的所有变量都是向量,因此为了简化,我们不会像在第一章、《向量微积分》和第二章、《线性代数》中那样将它们写成粗体。
有时候,我们的约束可能是以不等式的形式出现,例如![],我们可以加入一个松弛变量z,这使得我们的函数约束变为![],并且区域约束变为z ≥ 0。
我们可以直接列出所有约束,但那样太乱了。我们通常将它们写作如下形式:

这是线性规划的一般形式。然而,标准形式通常写作如下:

我知道现在这一切可能看起来非常不清楚,但别担心——我们很快就能弄清楚所有这些内容。
无约束优化
优化问题的目标是最小化f(x),我们主要处理的是二次可微的函数,并且满足![]。一个非常重要的属性是,由于f是可微且凸的,我们有如下结论:

如果你记得我们在第一章、《向量微积分》中学到的内容,这应该是显而易见的。
无约束优化,正如你可能已经能看出来的那样,就是没有任何约束的情况,任何点都可能是最小值、最大值或鞍点,这使得问题变得不容易。
假设我们有一个含有n个方程和n个变量的问题。求解这个问题并找到最优解并不简单,通常我们是通过迭代方式来解决问题。可以把它看作是在f的定义域内计算一个有序的点集,逐步接近最优解。
现在,假设我们有一个函数,![],并且
,使得 ![]。现在的问题如下所示:

这里,我们有![],根据前面的章节我们知道它是f的梯度。
自然地,为了开始计算这些点,我们需要一个起始点,我们称之为初始点,并且它必须位于f的定义域内。然后,我们通过迭代从那里找到更好的点,直到找到最优点。
凸优化
凸优化问题关注的是在凸集上最小化一个凸函数。一般来说,它的形式如下:

在这里,![]是凸函数,因此它们满足以下条件:

这是当![]和![]为非负数且![]时的情况。
凸集
在优化中,我们常常遇到凸和非凸这两个术语。
我们定义一个凸集为:如果我们选取任意两个点并画一条线连接它们,那么这条线将完全位于该集的边界内。
我们标记我们的凸集为![],如果我们有两个点,![]和某个标量![]值,那么![]。
现在,假设我们有![]函数。如果θ=0,f=y;但如果θ=1,那么f=x。从这个可以看出,随着θ的增加,f会逐渐从y变到x。
一个函数,![],如果* S *对于所有![]和![]的情况都是凸的,那么它就是凸函数。然后我们得到![]。
此外,如果我们有![],其中该函数的定义域是对于所有![]的凸集,那么![]。
为了帮助我们可视化一个凸函数,我们有以下图示,其中可以看到它几乎像一个碗,碗内的所有点都是凸集合中的点:

现在,假设我们的函数可以进行二次微分。那么,f在凸区域上是凸的,我们可以将我们的 Hessian 矩阵定义如下:

对于所有
的情况,这是半正定的。
仿射集合
如果我们有一个
集合,当连接我们在
中的两点的直线位于
中时,它是仿射的;也就是说,这个空间包含了
中点的线性组合,但只有当系数之和等于 1 时,![]、![]和![]。
此外,如果我们有超过两个点,那么![]是n个点的仿射组合,给定以下条件:

此外,如果
是一个仿射集合,并且我们有一个![]点,那么我们可以得到以下结论:

这是
的一个子空间。
现在,假设我们有一些![]和![]点。从前面我们知道![]和![]。因此,我们可以将
表示如下:

一般而言,我们称
中所有点组合的集合为
的仿射外壳。
现在假设我们有一个单位球体在
中,其中x是其中心,r是半径,且![]。
的相对内部,其中
的维度小于n,定义为![]集合,其中![]。
然后,定义相对边界为![]的闭包与![]的相对内部之间的差。
凸函数
如果一个函数的定义域是一个凸集,并且对于x,![]和![]满足条件,那么该函数被定义为一个![]函数,如下所示:

让我们用以下图形可视化这个不等式:

连接两点的直线在函数之上,这告诉我们该函数是凸的。然而,当函数是-f时,它是凹的,否则是凸的。
另一方面,仿射函数具有等式,因此既是凹函数又是凸函数。
优化问题
我们可以从本章前面回顾到,优化问题可以定义如下:

我们问题的最优值定义如下:

我们称*x^**为一个最优点(或者是我们问题的解),如果![]。因此,包含所有最优点的最优集如下所示:

在凸优化中,有一个相当重要的性质,指出任何局部最优点也是全局最优点。
非凸优化
在凸优化中,我们需要找到一个局部最优解,这也恰好是全局最小值。然而,在非凸优化中,我们需要找到全局最小值,这并不是局部最小值;事实上,可能会有多个局部最小值以及鞍点。
这使得非凸优化比凸优化更具挑战性。
探索各种优化方法
现在你已经了解了优化是什么,是时候探索一些实际应用中使用的方法了。我们不会覆盖整个优化领域,因为这需要一本书来讲解。我们只会涵盖适用于深度学习的基本优化方法。
最小二乘法
最小二乘法是凸优化的一个子集。它被归类为无约束优化,形式如下:

这里,![],![]是A的行,而![]是我们的优化变量。
我们还可以将其表示为![]形式的线性方程组。因此,![]。
最小二乘问题与最大似然估计问题非常相似。
拉格朗日乘子
在求解约束优化问题时,最好将约束条件包含在目标函数中。这样,任何不包含在约束中的部分就不会被认为是最小值。
让我们回顾一下之前的问题:

我们将我们的约束称为 C。
所以,我们定义 C 的拉格朗日函数如下:

这里,
被称为 拉格朗日乘子。
当我们的约束条件得到满足时,![] 和 ![]。通过对 L 在 x 和 λ 上进行最小化,我们得到了关于约束条件的解。
假设我们有
和
,这样我们得到如下式子:

然后,*x^** 对 C 是最优的;也就是说,它最小化了 f。这被称为 拉格朗日充分性。
要找到 λ^* 和 *x^**,我们必须解如下方程:
和
。
例如,假设我们想要最小化 ![],并满足 ![] 和 ![]。
所以,拉格朗日充分性方程如下:

我们可以将其改写为如下形式:

我们还需要选择一个 λ^() 和 x^* 的值,使得 L(x^, λ^**) 最小。所以,对于 λ^,L(*x, λ^**) 必须有一个有限的最小值。
从前面的方程中,我们知道 ![] 在 ![] 处有一个有限的最小值,并且 x[1] 和 x[2] 项只有在 ![] 时才有有限的最小值。
现在,为了找到最小值,我们求导并令其等于 0,如下所示:

由于一阶导数必须等于 0,我们得到了如下式子:
, 
为了确认这些是最小值,我们求解 Hessian 矩阵:

正如我们预期的那样,当 ![] 时,这个矩阵是正半定的。
我们想要的 λ 值在 ![] 集合中,这告诉我们 ![] 的唯一最小值如下:

现在我们要做的就是找到 λ 和 x 对应的 x(λ) 的值,以满足约束条件。
牛顿法
牛顿法是一种二阶优化方法,它通过使用海森矩阵对应特征值的逆来重新缩放各个方向上的梯度。
如我们所知,我们试图找到最小化 f(x) 且满足 ![] 的 x^* 的值。假设我们当前位于 x[k] 处,并且我们移动到更接近 x^* 的 x[k+1] 处。我们可以将这一步表示为 。
牛顿法之所以有效,是因为当 x 接近 x^* 时,它能表现得很好,因为它在 x 处取的是最速下降方向。然而,当我们位于 x[0] 时,它的表现较慢,因为在 x[0] 处的二阶导数不能为我们提供关于需要朝哪个方向移动才能到达 x^* 的可靠信息。
现在,假设 ![]。那么,我们得到以下结果:

这里,![]。
我们可以将其重写如下:

这被称为牛顿步。因此,在 x[k] 处,x[k+1] 最小化以下二次函数:

我们还知道 Hf(x) 是正定的,这告诉我们 ![],除非 ![]。
当我们接收到新的值 x[k+1] 时,可以预期其中会有误差。这个误差与 x[k] 中的误差的平方成正比。我们可以如下观察这一点:

这使得该方法以二次收敛的速度收敛(快速,但仅当 x[k] 接近最优值时)。
割线法
在牛顿法中,我们计算了一阶和二阶导数,但在一个大问题中计算海森矩阵并不理想。
假设我们有一个函数,![],并且 n = 50。如果我们分别对每个 x[i] 求 f 的一阶导数,我们得到 50 个方程。现在,如果我们计算二阶导数,我们将得到 2,500 个关于 x[i] 和 x[j] 的方程,这些方程组成一个矩阵。然而,由于海森矩阵是对称的,我们实际上只需要计算 1,275 个二阶导数。这仍然是一个相当庞大的数量。
割线法利用了牛顿法,但它不是计算二阶导数,而是使用一阶导数来估计,这使得它在实际应用中更加适用。
它通过如下方式近似二阶导数:

我们将这个近似值代入牛顿法,得到以下结果:

尽管这样可以减少计算复杂度,但它和牛顿法有相同的缺点,因为它需要额外的迭代才能收敛。
准牛顿法
割线法近似第二导数,而准牛顿法近似 Hessian 矩阵的逆。步骤如下:

在这里,Q[k] 是 x[k] 处的 Hessian 矩阵的近似逆。
我们从让Q[1] = 1 开始,并使用两个项,α和β,在每次迭代中更新矩阵,以帮助改进我们的估计。它们的定义如下:
和 
为了在每次迭代中更新矩阵,我们使用Broyden-Fletcher-Goldfarb-Shanno(BFGS)方法,具体过程如下:

为了使最小化有效,Q 必须是正定的。
博弈论
让我们稍微偏离一下,谈谈博弈论。包含三个或更多玩家的游戏通常很难解决,但双人游戏要简单得多,我们将在这里集中讨论。
假设我们有两个玩家,分别由![]表示,他们正在进行剪刀石头布游戏。正如我们所知道的,在这个游戏中,我们通常在没有任何关于对方选择的信息的情况下做出决定。每个玩家自然都希望获胜,因此每个玩家都有以下的收益矩阵:

就我个人而言,我不是最喜欢以这种方式展示收益,因为你需要写两个矩阵并每次查找单个收益。我更喜欢以下方式:
| R | P | S | |
|---|---|---|---|
| R | (0, 0) | (-1, 1) | (1, -1) |
| P | (1, -1) | (0, 0) | (-1, 1) |
| S | (-1, 1) | (1, -1) | (0, 0) |
在前面的表格中,玩家 1 选择一行,![],玩家 2 选择一列,![]。因此,如果我们查看前面的表格,(-1, 1) 表示玩家 1 输了,玩家 2 赢了。
在博弈论中,玩家有一组策略来决定他们的行为或可以采取的行动。
玩家X,在我们的案例中,拥有以下一组策略:

玩家Y拥有以下一组策略:

在这里,每个向量代表选择每一列或每一行的概率。
每个![]的情况表示一个策略配置,我们计算玩家X的期望收益为![]。如果对于某个i的情况,x[i] = 1,那么我们总是选择i,并称x为纯策略。
让我们继续讨论另一个著名的例子——囚徒困境。这里有两个人,他们犯了罪并被抓住。他们每个人有两个选择可以做——作证(T)或保持沉默(Q)。
以下是他们可以做出的选择结果:
-
如果他们俩都保持沉默,他们两个人都会被判刑两年,关进监狱。
-
如果一个人作证而另一个人保持沉默,那么保持沉默的人将被判刑三年,而作证的人因为配合警方而被释放。
-
如果他们俩都作证,他们两个人都会被判刑五年。
我们的支付表格如下所示:
| S | T | |
|---|---|---|
| S | (2, 2) | (0, 3) |
| T | (3, 0) | (1, 1) |
自然地,每个人都希望最大化自己的回报;请注意,这两个人都没有机会知道或讨论对方将做什么,所以合谋并不是一个选项。因此,每个人都会更倾向于作证,因为这个选择显然更好。我们称 T 为占优策略,而 (1, 1) 是帕累托最优,且被 (2, 2) 所支配。
假设我们有一个游戏和一个策略组合 (x, y),使得它们处于均衡状态(即 x 是 y 的最佳回应,反之亦然)。那么,我们定义
为对 ![] 的最佳回应,如果对于所有情况
,我们有以下内容:

你们中的许多人可能听说过零和游戏这个术语,但对于那些没有听说过的人来说,它是指总回报为 0 的特殊游戏,因此 ![]。早前的石头剪刀布示例很好地展示了这一点。
对于这个二人博弈的矩阵游戏,一个非常重要的解法是极小极大定理。假设我们有一个 ![] 支付矩阵。然后,我们得到以下内容:

这表示如果两个玩家都使用极小极大策略,那么它们处于均衡状态,因为这导致玩家 1 和玩家 2 都得到最差的回报,从而满足均衡条件。这与在约束条件下找到 ![] 的最优值非常相似,就像线性规划中的问题一样。
下降方法
一般来说,下降方法的形式如下:

在这里,![],以及 ![]。在之前的算法中,k 是步骤的序列,x[k] 是最优点,而
是一步。标量值,c[k],是第 k^(th) 次迭代中的步长。
在下降法中,![],除非 x[k] 是最优值,这告诉我们 ![] 对所有 k 的情况都适用。
梯度下降
梯度下降是一种广泛使用的第一阶优化问题,它从当前所在的点出发,沿着函数的负梯度方向逐步前进,直到最终停在最优解处。
想象你在滑板公园,手里拿着一个网球。你弯下腰,将球放在一个坡道的表面上并放开;重力起作用,球沿坡道的曲率滑动,最终到达底部。这就是梯度下降的概念。
在这种情况下,步长的自然选择是负梯度;即,![]。这就是梯度下降,其形式如下:

在优化中,我们通常定义停止标准为一个条件,当满足时,应该停止我们的算法继续优化。它通常呈现如下形式:

这里,η 是一个小的正数。
我们应该记得,在前一章中,如果我们有一个函数 f(x, y),则它的梯度为 ![]。因此,我们可以按如下方式计算在 (x, y) 处的函数的幅度(或陡峭度):

这起到了指导作用,告诉我们在每一步应该朝哪个方向移动(因为随着我们向下移动,曲率会变化),以达到最小值。
然而,梯度下降并不完美。如果步长 c^((k)) 太小,可能会非常慢;如果步长太大,则可能由于过度跳跃而无法到达最优点,这样会导致算法无法收敛,反而会发散。
为了更好地理解这一点,让我们看一下以下两个图示。第一个图示有一个较小的步长,图示如下:

第二个图示展示了较大的步长:

如你所见,选择一个合适的步长非常重要,而选择它并不总是容易的。幸运的是,有一种叫做 自适应步长 的方法,它会在每次迭代后调整步长。它遵循两个规则:
-
如果步长后函数值增加——这意味着步长过大——那么就撤销这个步骤并减小步长。
-
如果函数的值在减小步长时下降,那么就增加步长。
然而,这也并不完美。从图示中可以看出,优化过程有些不稳定,当我们遇到更平坦的表面时,算法的速度往往会减慢。
随机梯度下降
到现在为止,你应该能察觉到,计算梯度并达到最优解并不容易,而且非常耗时。
这就是为什么计算一个能指引我们朝着大致方向前进的近似值是有用的。我们称这种方法为随机梯度下降(SGD),它是一个非常重要的算法,从理论上保证收敛。随机这个词来源于我们并不清楚梯度的精确值,只能得到一个近似值。
假设我们有M个点![],其中M非常大。这变成了一个巨大的优化问题。所以,我们采取一个目标函数,L(x),它是所有点的损失之和。我们将其表示如下:

在这里,我们的目标是尽可能地最小化损失,以使我们的模型最贴合真实函数y,就像回归问题中一样。通过最小化损失,我们减少了模型计算点与真实点之间的距离。
我们使用这种方法的原因是,当我们有大量点或较大的优化问题时,计算每个点的梯度是非常不切实际的,尤其是如果我们还要计算海森矩阵的话。而这种方法,另一方面,在计算上更为可行。
损失函数
我们知道,我们正在尝试逼近一个函数,并且尽可能地接近真实函数。为此,我们需要定义一个损失函数——我们有很多选择。以下是实践中常用的主要损失函数:
-
![],也称为均方误差。
-
![],也称为均值绝对误差。
-
![],也称为平方损失。
-
![],也称为铰链损失。
-
![],也称为交叉熵损失。
-
![],也称为Huber 损失。
我们将在稍后重新审视这些内容,并理解何时最好使用每一种方法。
带动量的梯度下降
正如我们所见,梯度下降需要一些时间才能找到相对平坦的区域。对前一个例子的改进是带动量的梯度下降,它通过平滑梯度更新来减少波动性。考虑一颗网球和一块巨石同时从山上滚下。网球会四处弹跳,可能会被卡住,但巨石会随着时间的推移获得动量,并保持相对笔直的路径向下滚动。这就是这个改进的核心思想。它通过记住以前的更新,将每次更新作为前一次和当前梯度的结合,表示如下:

这里, ![] 和 ![]。
在这种方法中,正如你所注意到的,我们不仅需要选择步长 c[k],还需要选择动量系数 α。
Nesterov 加速梯度
动量能够抑制梯度下降的振荡,而 Nesterov 方法则允许小球在下坡时向前看,并计算出未来位置的梯度。
本质上,我们不是在 x[k] 计算梯度,而是使用 ![] (其中 ![]),它接近我们在下一步之后的位置。因此,我们有以下表达式:

我们还可以通过将 γ = α 来结合动量更新与 Nesterov 加速梯度,这样就得到了 ![] 和 ![]。
在这里,你会注意到,我们现在有三个参数(c、α 和 γ),而不是动量法中的两个。
自适应梯度下降
我们之前简要提到过自适应步长。这些方法通常使用前一步的梯度来指导搜索方向和步长,从而帮助我们更快地收敛。我们将要重点讲解的两种方法是 自适应梯度 (Adagrad) 和 自适应矩估计 (Adam)。
如前所述,我们的目标是找到 *x^**,使得损失函数最小化。
这些梯度下降方法的形式是 ![],其中 G[k] 是第 k 步的梯度。
在 Adagrad 的情况下,我们有 ![] 和 ![],将其代入前面的方程后,得到以下结果:

如你所见,我们使用损失平方和的平方根来更新每一步的步长,这样就不需要我们自己手动计算了。
Adam 也会保留前几步的梯度历史,但与 Adagrad 不同的是,它保存了梯度平方和梯度的指数加权平均值。
我们将其写作 ![] 和 ![]。
模拟退火
模拟退火的灵感来源于冶金学领域,我们通过加热来改变材料的属性。施加的热量增加了离子的能量,使其更加自由地移动。当材料开始冷却时,它会在达到平衡状态时呈现出不同的形状。热量需要缓慢而逐渐地减少,以避免材料陷入亚稳态,这代表了一个局部最小值。
在我们的案例中,为了优化问题,我们使用温度来控制随机性。当温度较高时,意味着该过程在自由和随机地探索空间,希望能够找到一个有更有利最小值的良好凸区域。通过降低温度,我们减少随机性,使得算法逐渐收敛到一个最小值。
模拟退火是一种非凸优化算法,其有效性来自于它能够逃脱局部最小值。
在每次迭代中,我们从转移分布T中抽取一个可能的步长,根据以下概率接受它:

这里,![]和
是温度。这个概率被称为Metropolis 准则,它使模拟退火能够在温度较高时逃离局部最小值。
为了逐渐降低温度,我们使用一个衰减因子,![],其形式如下:

该过程会持续进行,直到满足停止准则;也就是说,温度降低到一个程度,以至于我们从n[k]到n[k+1]没有看到任何改进。
自然进化
自然进化是一种利用梯度下降的方法,我们的目标是最小化![]。我们从样本中估计梯度,具体如下:

之前,在讨论梯度下降时,我们需要计算目标函数的梯度;但是在这里,我们处理的是对数似然![],并且可以使用这种梯度估计来改进θ,并应用于我们之前介绍的任何梯度下降方法。
探索群体方法
到目前为止,我们处理的优化问题中,我们有一个球体或粒子,通过沿着曲面逐渐移动,并使用梯度下降或牛顿法朝着最小值前进。然而,现在我们将观察另一类优化问题,在这种问题中,我们使用一个个体群体。
我们将这些个体分布在优化空间中,这可以防止优化算法在局部最小值或鞍点处卡住。这些个体可以互相分享它们所在局部区域的信息,并利用这些信息找到一个最优解,从而最小化我们的函数。
使用这些算法时,我们有一个初始的个体群体,我们希望将其分布开来,以便尽可能覆盖更多区域,从而增加找到全局最优区域的最佳机会。
我们可以从一个多变量正态分布中抽样我们的种群,这个分布被输入到我们感兴趣的区域,或者在某些约束条件下均匀地分布种群;然而,只有当你想限制种群覆盖的空间时,才建议使用这两种分布。或者,我们可以使用柯西分布,它允许我们覆盖更大的空间。
遗传算法
遗传算法的灵感来源于达尔文主义,即适应性更强的个体将某些可遗传的特征传递给下一代。在这种情况下,目标函数与个体的适应度或繁殖能力呈反比关系。每一代中适应性更强的个体的染色体将在经过交叉和突变后传递给下一代。
我们表示染色体的最简单方式是使用二进制字符串,类似于 DNA 编码的方式。然而,更好的方法是将每个染色体写成一个表示优化空间中一个点的向量,
。这样,我们可以更轻松地表示交叉和突变。
我们从一个随机种群开始,然后从中选择一组染色体作为下一代的父代。如果我们有 n 个染色体,那么我们将选择 n 对父代,它们将生成 n 个孩子,形成下一代。
我们的目标是最小化目标函数。因此,我们从种群中抽取 k 个随机个体,并从每个样本中选出表现最好的个体,或者根据它们相对于种群的表现概率来选择。然后,每个个体的适应度与![]成反比,我们可以通过![]来计算它。
另一方面,交叉是父代染色体的组合,结果生成孩子。这个组合可以通过多种方式发生,比如单点交叉、两点交叉或均匀交叉,或者我们可以使用自定义的交叉方式。
在适应度和交叉中,只有有限的特征能够从初代种群传递到后代。然而,如果只传递最佳的特征,我们最终会得到一个饱和的种群,这不是我们想要的。这时,突变就变得非常有用。突变允许产生新的特征并传递下去,从而使个体能够探索更多的优化空间。在每次交叉后,种群中的每个孩子都会经历一些突变,突变的发生有一定的概率。
粒子群优化
该算法利用了群体智能的概念,就像一群鱼或一群鸟。假设它们正在寻找食物。它们到达一个区域后稍微分开,开始各自寻找食物。当其中一只发现了食物时,它会告诉其他个体,以便大家一起参与。
种群中的每个个体都知道其当前的位置和速度,并且只记录它所访问过的最佳位置。速度向量决定了搜索的方向,如果个体具有较高的速度,则表现出更强的探索性;而如果速度较低,则表现出更多的利用性。
在每次迭代的开始,整个种群都会被加速到任何个体迄今为止遇到的最佳位置。更新过程如下所示:

这里,x[best] 是整个群体所找到的最佳位置,![] 是个体所找到的最佳位置,w、α[1] 和 α[2] 是参数,![]。
c[1] 和 c[2] 的值在它们收敛的速度上有着重要的影响。
总结
在本章中,我们讨论了几种不同的优化方法,如凸优化和非凸优化,以及使优化成为一个具有挑战性问题的原因。我们还学习了如何定义优化问题,并探索了包括种群方法、模拟退火法和基于梯度下降的方法在内的多种方法。在后续的章节中,我们将进一步了解优化在深度学习中的应用,以及为何它是我们必须理解的一个重要领域。
在下一章中,我们将学习图论及其在该领域中的应用,解决各种问题。
第五章:图论
既然我们已经对线性代数、微积分、统计学和优化有了一定了解,接下来就是学习一个非常有趣的主题——图论。顾名思义,图论研究的是图,图被用来模拟物体之间的关系。我们通过图来帮助可视化和分析问题,从而帮助我们解决这些问题。
图论是一个非常重要的领域,应用于各种问题,包括搜索引擎中的网页排名、社交网络分析、以及在 GPS 中找到回家的最佳路线。它对于我们深入理解深度神经网络也至关重要,因为大多数神经网络都是基于一种叫做有向无环图(DAG)的图类型。
图论的内容远超本章(以及本书)的范围,但我们会涵盖一些对于深入理解神经网络至关重要的内容。
本章将涵盖以下主题:
-
理解基本概念和术语
-
邻接矩阵
-
图的类型
-
图拉普拉斯算子
理解基本概念和术语
图论最早是由莱昂哈德·欧拉在 18 世纪提出的,目的是解决一个著名的问题——哥尼斯堡桥问题,该问题问的是是否可以在不重复的情况下,经过所有七座桥梁,走完哥尼斯堡的所有桥梁。桥的形态如下所示:

在继续之前,试着自己动手操作,用手指沿路径滑动,或者画下来用铅笔描摹。你能找到解决方案吗?如果没有也没关系!
让我们停下来思考一下,究竟什么是图。图(G)是由两个集合组成的数学结构——顶点(V(G))和边(E(G))。如果两个顶点(v[1]和v[2])之间有一条边(e或(v[1], v[2]))连接,它们就是相连的。既然这已经解决了,我们需要了解图的一些规则,这些规则对于理解图非常重要。规则如下:
-
如果![],则v[1]与v[2]相邻(连接/邻居);但如果![],则v[1]与v[2]不相邻(不连接/不是邻居)。
-
如果v[1]与v[2]相邻,那么我们可以说v[1]的邻域(记作![])是与v[1]相连接的顶点集合。我们写作![]。
-
如果![],则
与v[1]和v[2]相关(即v[1]和v[2]是
的端点)。 -
如果G有n个顶点,那么v[1]最多可以有n-1个邻居。
-
如果 v[1] 有邻居,那么 v[1] 的度数就是它的邻居数量(或相交次数)。我们可以将其表示为 ![]。图中顶点的最小度数用 ![] 表示,最大度数用 ![] 表示。
-
如果 ![],那么它就是一个孤立的顶点。
现在我们已经了解了图形的基本规则,让我们回到之前提到的问题,看看我们能否找到它的解决方案。我们可以将桥问题重新绘制成图形,如下图所示(请参考图形包中提供的彩色版本):

在这里,我们有以下内容:
-
绿色的顶点是 A
-
红色的顶点是 B
-
蓝色的顶点是 C
-
橙色的顶点是 D
-
连接 A 和 B 的弯曲边是桥 a
-
连接 A 和 B 的直边是桥 b
-
连接 A 和 C 的弯曲边是桥 c
-
连接 A 和 B 的直边是桥 d
-
连接 A 和 D 的直边是桥 e
-
连接 B 和 D 的直边是桥 f
-
连接 C 和 D 的直边是桥 g
如果我们查看图形并沿着边遍历,我们可以轻松观察到无论选择什么路径,都无法解决哥尼斯堡桥问题。然而,如果我们在 D 和 A、D 和 B,或者 D 和 C 之间添加一条额外的路径,那么我们就能确实解决这个问题。
现在,假设我们有一堆多面体。在几何学中,多面体是三维物体,如四面体(金字塔)、立方体、双锥体、菱形多面体、十二面体、五角六十面体等(不用担心,你不需要了解它们的所有细节)。在下图中,我们有两个不同的多面体及其对应的图形:

让我们观察这些形状及其图形片刻。正如你所看到的,图形看起来与实际结构有些不同,但仍然捕捉到了形状的特性。这里的每个图形都有顶点(V)和边(E),这些我们已经知道。但还有一个额外的属性——面(F)。通过之前的图形,我们可以推导出一个通用规则,捕捉顶点、边和面之间的关系。它是:

在这里,|V| = n,|E| = m,|F| = r。为了验证这一点,让我们看一下之前的图形。
在立方体的情况下,有 8 个顶点,12 条边和 6 个面,所以我们有以下内容:

在八面体的情况下,有 6 个顶点,12 条边和 8 个面,所以我们有以下内容:

现在我们理解了基本概念,是时候学习图论中的第一定理了。假设我们有一个图,图中有 n 个顶点和 m 条边。那么,我们可以观察到以下几点:

这告诉我们,图中每个顶点的度数之和是图中边数的两倍。或者我们可以写成如下形式:

邻接矩阵
如你所想,记录下所有连接节点的对(即那些有边连接的节点对)来跟踪图中的关系可能会变得乏味,特别是当图非常庞大时。因此,我们使用被称为邻接矩阵的方式,它是图的基本数学表示。
假设我们有一个图,其中有 n 个节点,每个节点都有一个独特的整数标签(![]),这样我们可以轻松地引用它,且毫无歧义。为了简化起见,在这个例子中,n = 6。那么,这个图的对应邻接矩阵如下:

让我们看一下这个矩阵,看看它为什么是这样的。首先立刻显现出来的是,这个矩阵的大小是 6 × 6(或 n × n),因为大小对我们来说很重要。接下来,我们注意到它是对称的,并且沿对角线只有零。那么为什么呢?它以这种方式写出来有什么意义?
如果我们查看前一部分中的图形图表,可以看到边缘如下:

回头看矩阵的上三角或下三角部分,我们可以看到在特定的 (i,j) 位置上有七个 1。每个 1 代表两个编号节点之间有一条边,如果两个节点之间没有边,则为 0。我们可以将其概括并写成如下形式:

之所以对角线上只有零,是因为没有自环;也就是说,没有节点与自身连接。这被称为简单图。然而,也有更复杂的图,如带有自环和多重边的图。
多重边图和简单图的区别在于,在多重边图中,一对节点之间可以有一条或多条边。为了更清楚地理解这一点,假设我们有如下的邻接矩阵,在这个矩阵中我们可以看到现在存在自环和节点对之间的多重边:

与简单图的邻接矩阵相比,这个邻接矩阵有一些显著的不同。我们首先注意到矩阵不再仅由 1 和 0 构成。你认为这些数字代表什么呢?在这个邻接矩阵中,两个节点之间的双向边写作 A[i,j] = A[j,i] = 2。自环则是那些从 i 到 i 的边;也就是说,我们可以写成 A[i,i],并且它等于 2。之所以是 2 而不是 1,是因为这条边在 i 的两端都有连接(而且在做计算时,这样处理也更方便)。
图的类型
在上一节中,我们学习了图论的基础知识,正如你所看到的,这是一个非常强大的数学工具,可以用于各个领域中的许多任务。然而,没有一种通用的解决方案,因此我们需要额外的工具来帮助我们,因为每个问题都是独一无二的。在这一节中,我们将学习各种类型的图及其应用场景和优缺点。这包括加权图、有向图、多层图、动态图和树图。
加权图
到目前为止,我们已经看到了具有某种二进制表示的图,其中 1 表示两个节点之间存在边,而 0 表示两个节点之间没有连接。我们还看到了包含自环和多重边的图。然而,有时我们可能希望表示节点之间的强度,这就是通过权重来表示的。权重越大,强度也越大。
这种类型的图可以在多种场景中使用,比如在社交网络中,边的权重表示两个人之间的交流频率,我们可以用它来判断他们之间的亲密度。在加权图的邻接矩阵中,每个 A[i,j] 实例表示节点 i 和 j 之间的权重。
假设我们有以下的邻接矩阵:

我们可以看到,节点 1 和节点 2 之间的权重(或强度)是节点 1 和节点 3 之间的两倍,而节点 2 和节点 3 之间的权重是节点 1 和节点 3 之间的四倍。
这些边上的权重不一定非要代表两个节点之间连接的强度;它也可以表示从一个节点到另一个节点的旅行时间或两节点之间的距离。
有向图
普通图和有向图之间的区别在于,普通图中的边可以任意方向连接,这就是为什么邻接矩阵是对称的。如果节点 i 和节点 j 之间有一条边,那么我们可以从 i 到 j,也可以从 j 到 i。然而,在有向图的情况下,边是有方向的。这些边是有向边,只能朝一个方向延伸。
这种类型图的邻接矩阵如下所示:

现在,假设我们有以下图:

然后,它对应的邻接矩阵如下:

如你所见,这个矩阵是不对称的(不是对称的)。例如,节点 3 指向节点 2,节点 6 指向节点 4,但它们不会反向连接。
和无向网络一样,有向网络也可以有多个边和自环。然而,在这种情况下,如果存在自环,那么对角线上的元素将为 1,而不是 2。
有向无环图
DAG 是一种没有环的有向图。这意味着它没有封闭的循环;也就是说,没有三个或更多节点在相似的方向上连接。假设我们有以下邻接矩阵:

我们可以看到,在前面的邻接矩阵中,我们有一条从节点 1 到节点 3 的边,一条从节点 3 到节点 4 的边,以及一条从节点 4 到节点 1 的边。这在图中形成了一个环。
从视觉上看,你可以将 DAG 视为一个层级结构,其中节点可以向下或向上流动至后续的层级。因此,如果我们的边都是朝上的,节点将永远不会从较高的层级指向较低的层级。但如果是这种情况,我们的网络可能会永远运行下去,那么这个图在哪里结束呢?肯定至少有一个节点是有输入边,但没有输出边的。
要确定我们的网络是否是无环的,我们可以使用一个简单的程序:
-
找到一个没有任何输出边的节点。
-
如果不存在这样的节点,那么图就是无环的。然而,如果存在这样的节点,那么请将它和它的输入边从图中删除。
-
如果所有这些节点都已被移除,那么图就是无环的。否则,请重新从步骤 1开始。
现在,这种类型图的邻接矩阵非常有趣。假设我们对所有节点进行编号,使得边从较高编号的节点指向较低编号的节点。那么,它的邻接矩阵将是严格的三角形矩阵,且对角线上的值为零。如果我们有以下邻接矩阵,我们可以清楚地观察到没有自环,并且这对于无环图始终成立:

我们非常重要的一点是要注意为什么这个邻接矩阵是严格的三角形矩阵。这是由于节点的排序(编号)。如果排序不正确,我们将无法得到一个三角形矩阵。有趣的是,总是至少有一种节点排序能够生成上三角矩阵,并且可以通过前述的三步法找到它。
多层次和动态图
我们通常使用图来映射非常复杂的关系。例如,假设我们想创建一个包含所有交通方式及路线的图,类似于谷歌地图提供的涉及公交、火车、汽车、飞机甚至它们的组合的路线。我们可以使用多层图来创建这样一个图,其中节点代表机场、公交车站、火车站和其他交通方式,而边代表航班、路线等。
我们可以仅通过标记边和节点来描述每个元素代表的意义,但这样可能会变得相当杂乱。因此,我们可以使用多层图,每一层代表一种特定类型或类别的节点。然后这些层堆叠在一起,且有互相连接的边,将不同层的节点连接起来。这些多层边可以用来表示处于一定半径内的节点:

多层网络的一个特别重要的子类是多重图,其中每一层都具有相同的节点,这些节点可以代表人、物体、地点等,但它们有各种类型的边,代表不同的关系。在社交网络中,这种图非常有用,因为不同的人可能以不同的方式相互关联:

多层图的另一个子类是动态(或时间)图。这些图的特点是它们的结构随着时间的变化而变化。这些图可能是固定数量的节点,其中边不断变化,或者节点随着时间的推移被添加或移除。
我们可以使用一组n × n的邻接矩阵,Aα*,来数学表示多重图,其中*α*表示层的编号或时间步长(如果是动态或时间图的话)。我们可以将矩阵的元素写作![]。这些元素构成了一个三维张量。相比之下,多层图要复杂得多,因为每一层的节点数可以不同,并且它们有层内边和层间边。我们可以使用邻接矩阵*Aα表示层内边,其中每一层α都有一个大小为n[α] × n[α]的邻接矩阵。而层间边的邻接矩阵可以表示为B^(αβ)(其大小为n[α] × n[β]),如果在层α中的节点i与层β中的节点j之间存在边,则矩阵元素为![]。
树图
树图是一种图形类型,顾名思义,它们具有树状结构。它们是无向图,且没有任何环路。它们还有一个相当有趣的性质,称为连通性,即我们可以从图中的任意一个节点找到通往其他任何节点的路径。
在下面的图示中,我们可以看到树图的样子:

如你所见,图形从一个节点(根节点)开始,并以叶节点结束。在这之间,它们分支出去形成更小的子树。一个有趣的性质是,一个有n个节点的树形图有n-1条边。
图拉普拉斯
在本章早些时候的邻接矩阵部分,我们学习了邻接矩阵,以及如何使用它来判断图的结构。然而,还有其他方法可以用矩阵形式表示图。
现在,假设我们有一个无向的、无权重的图。那么,它的拉普拉斯矩阵将是一个对称的n × n矩阵,L,其元素如下:

这里, ![]。我们也可以将其写为如下形式:

这里,A[i,j]是邻接矩阵,δ[i,j]是克罗内克δ函数。我们可以将其以矩阵形式重写,如下所示:

在这里,我们有以下内容:

类似地,我们也可以通过将这里的邻接矩阵替换为之前定义的加权图的邻接矩阵,来写出加权图的图拉普拉斯矩阵。
总结
在本章中,我们学习了一个非常有趣的数学主题,它几乎在每个领域都有应用,从社会科学到社交网络,再到万维网、人工智能——尤其是在我们讨论的神经网络领域。
在下一章中,我们将学习线性神经网络,它是最简单类型的神经网络,并且在统计学习中使用最为频繁。
第二部分:基本神经网络
在上一节中,已经建立了对深度学习基础概念的扎实理解,在这一节中,你将学习到目前使用的关键神经网络。
本节包含以下章节:
-
第六章,线性神经网络
-
第七章,前馈神经网络
-
第八章,正则化
-
第九章,卷积神经网络
-
第十章,递归神经网络
第六章:线性神经网络
在本章中,我们将讨论一些机器学习的概念。希望你已经学习过并理解机器学习的相关内容。因此,本章将作为对本书中需要的某些概念的复习,而不是全面学习所有机器学习方法。
在本章中,我们将重点讲解线性神经网络,这是最简单的神经网络类型,常用于诸如线性回归、多项式回归、逻辑回归和 softmax 回归等任务,这些任务在统计学习中最为常见。
我们使用回归来解释一个或多个自变量与因变量之间的关系。本章中我们将学习的概念对于进一步理解机器学习的工作原理至关重要,尤其是在下章深入了解深度神经网络之前。
本章将涵盖以下主题:
-
线性回归
-
多项式回归
-
逻辑回归
线性回归
回归的目的是找出数据(用 x 表示)与其对应输出(用 y 表示)之间的关系,并进行预测。所有回归问题的输出都是一个实数(![])。这可以应用于一系列问题,例如预测房价或预测电影评分。
为了能够使用回归,我们需要以下内容:
-
输入数据,可以是标量值或向量。它有时被称为特征。
-
训练示例,包含大量的 (x[i], y[i]) 对;也就是每个输入的输出。
-
捕捉输入与输出之间关系的函数——模型。
-
损失或目标函数,告诉我们模型的准确度。
-
优化,以最小化损失或目标函数。
在进一步讲解之前,让我们回顾一下第一章,向量微积分,在其中我们注意到直线的方程如下:

在这里,m 是梯度(或斜率),b 是修正项。我们使用以下方程,通过直线上的两个点来找到斜率:

如我们所知,这很容易做到。然而,在线性回归中,我们给定了许多 (x[i], y[i]) 点,我们的目标是找到最能捕捉关系的最佳拟合线。这条线就是我们模型所学习的内容。我们可以如下表示:

在这里,ε 代表误差,我们假设它是高斯分布,y 是真实标签,且 ![] 是我们的模型所提供的预测值。
现在让我们考虑一个有多个自变量的案例,我们希望找到一个因变量之间的关系。这种回归方法称为多元回归。在这种情况下,每个自变量都会影响预测结果。
在这种情况下,我们的输入将采取如下形式:

这里,n 是自变量的数量。
为了找到 ![],我们可以对所有因变量求平均或将它们加起来,但这不太可能给我们期望的结果。假设我们想预测房子的价格;我们的输入可能是地块的平方英尺、卧室数量、浴室数量,以及是否有游泳池。
每个输入都会有一个对应的权重,模型会从数据点中学习这个权重,它最能描述每个输入的重要性。这就变成了如下形式:

或者,我们可以得到如下形式:

我们也可以将其重新写成矩阵形式:

但现在,显然有一个问题——我们的模型如何学习这些权重和这种关系? 对我们来说,这很容易,因为我们的脑袋可以瞬间识别模式,我们能够从分析中发现关系。然而,如果我们的机器要学习这种关系,它需要一个指南。这个指南就是损失函数,它告诉模型预测偏差有多大,并指示它需要朝哪个方向移动才能改进。
损失通常是预测值 (![]) 与真实值 (y[i]) 之间的距离,我们可以如下表示:

但这仍然没有给我们完整的视图。我们的目标是最小化模型在所有数据样本上的损失,因此我们将所有数据样本的损失求和并取平均。这看起来如下:

训练的目标是找到最佳参数:

在了解了线性回归之后,接下来让我们看看多项式回归的具体内容。
多项式回归
线性回归,正如你所想,它并不是一个适用于所有问题的通用解决方案。现实中,变量之间的许多关系并不是线性的;也就是说,一条直线无法捕捉到这些关系。对于这些问题,我们使用前述线性回归的变体——多项式回归,它能够捕捉到更多的复杂性,例如曲线。这种方法利用将解释变量应用不同的幂次来发现非线性问题。其形式如下:

或者,我们可能会有以下情况:

这是 ![] 的情况。
如前面的方程所示,这样的模型不仅能够捕捉到一条直线(如果需要的话),还能够生成一个二阶、三阶或 n^(th)-阶方程来拟合数据点。
假设我们有以下数据点:

我们可以立即判断,直线无法完成任务,但当我们应用多项式回归时,我们可以看到我们的模型学习拟合曲线,这个曲线类似于正弦波。我们可以在下图中观察到这一点:

现在让我们来看一个案例,我们试图学习一个表面,并且有两个输入,![],和一个输出, y。同样,如下图所示,表面并不平坦;实际上,它相当崎岖:

我们可以使用以下三阶多项式来近似建模:

如果这给出了令人满意的结果,我们可以添加另一个更高阶的多项式(以此类推),直到找到一个能够拟合表面的模型。
逻辑回归
还有一种我们在实践中常用的回归方法——逻辑回归。假设我们想要判断一封电子邮件是否是垃圾邮件。在这种情况下,我们的 x**(s) 值可以是 !(s) 出现的次数,或者是邮件中的拼写错误总数。然后, y 可以取值为 1(表示垃圾邮件)和 0(表示非垃圾邮件)。
在这种情况下,线性回归将无法发挥作用,因为我们不是在预测一个实际值——我们是在预测电子邮件属于哪个类别。
这通常会呈现如下形式:

如你所见,数据被分成了两个区域——一个代表非垃圾邮件,另一个代表垃圾邮件。
我们可以按以下方式计算:

这里, ![]。
然而,这仅适用于二分类问题。如果我们想要分类多个类别怎么办?那我们可以使用 softmax 回归,它是逻辑回归的扩展。其形式如下:

这是 ![] 和 ![] 的情况。
总结
在这一章,我们学习了各种回归形式,例如(多元)线性回归、二次回归、逻辑回归和 softmax 回归。每种模型都帮助我们找出了一个或多个自变量与因变量之间的关系。对一些人来说,这些概念可能显得非常基础,但它们将在我们本书的旅程中为我们提供很大帮助,并帮助我们更深入地理解接下来的概念。
在下一章,我们将学习前馈神经网络。
第七章:前馈神经网络
在上一章中,我们介绍了线性神经网络,这些网络在回归等问题中证明是有效的,因此在工业中得到了广泛应用。然而,我们也看到它们有自己的局限性,无法在高维问题上有效工作。
本章将深入探讨多层感知器(MLP),这是一种前馈神经网络(FNN)。我们将首先了解生物神经元如何处理信息,然后转向生物神经元的数学模型。本书中我们将研究的人工神经网络(ANNs)是由生物神经元的数学模型构成的(我们很快就会深入了解这一点)。一旦我们建立了基础,我们将继续理解 MLP(即 FNN)如何工作以及它们与深度学习的关系。
前馈神经网络(FNN)使我们能够近似一个将输入映射到输出的函数,这可以用于各种任务,例如预测房价或股票价格,或判断某个事件是否会发生。
本章将涵盖以下主题:
-
理解生物神经网络
-
比较感知机与麦卡洛克-皮茨神经元
-
多层感知器(MLP)
-
神经网络训练
-
深度神经网络
理解生物神经网络
人类大脑能够完成一些非凡的壮举——它执行非常复杂的信息处理。构成我们大脑的神经元连接非常密集,并与其他神经元并行工作。这些生物神经元通过它们之间的连接(突触)接收并传递信号。这些突触有各自的强度,增强或削弱神经元之间连接的强度,促进了我们的学习,并使我们能够不断学习并适应我们所生活的动态环境。
如我们所知,大脑由神经元组成——实际上,根据最近的研究,估计人类大脑大约包含 860 亿个神经元。这是一个庞大的神经元数量,而且还有更多的连接。每天有大量的神经元被同时使用,以帮助我们完成各种任务,并成为社会中的功能性成员。单独的神经元被认为是相当缓慢的,但正是这种大规模的并行操作赋予了大脑非凡的能力。
以下是生物神经元的示意图:

如前图所示,每个神经元有三个主要组成部分——细胞体、轴突和多个树突。突触将一个神经元的轴突与其他神经元的树突连接,并决定从其他神经元接收到信息的权重。只有当神经元的加权输入之和超过某个阈值时,神经元才会激活(发放);否则,它处于静止状态。神经元之间的这种通信是通过电化学反应完成的,涉及钾、钠和氯(我们不会深入讨论这一点,因为它超出了本书的范围;不过,如果你对此感兴趣,可以找到很多相关文献)。
我们之所以研究生物神经元,是因为本书中我们将学习和开发的神经元和神经网络在很大程度上受到生物学的启发。如果我们想要开发人工智能,哪里比学习真正的智能更好呢?
由于本书的目标是教你如何在计算机上开发人工神经网络(ANNs),因此我们有必要看看我们的大脑与计算机在计算能力上的差异。
计算机在计算能力上相较于我们的大脑具有显著的优势,它们每秒能够执行大约 100 亿次操作,而人脑每秒只能执行约 800 次操作。然而,大脑运作所需的功率约为 10 瓦特,仅为计算机所需功率的十分之一。计算机的另一个优势是其精度;它们可以比大脑高出数百万倍的精度进行操作。最后,计算机执行操作是按顺序进行的,无法处理未经过编程的数据,而大脑则能并行执行操作,并能够很好地处理新的数据。
比较感知机与麦卡洛克-皮茨神经元
在本节中,我们将介绍两种生物神经元的数学模型——麦卡洛克-皮茨(MP)神经元和罗森布拉特感知机——它们为神经网络的基础奠定了基础。
MP 神经元
MP 神经元由沃伦·麦卡洛克和沃尔特·皮茨于 1943 年创建。它是仿生神经元模型,是第一个生物神经元的数学模型。它主要用于分类任务。MP 神经元接受二进制值作为输入,并根据阈值输出二进制值。如果输入之和大于阈值,则神经元输出 1(如果低于阈值,则输出 0)。在下图中,我们可以看到一个具有三个输入和一个输出的基本神经元:

如你所见,这与我们之前看到的生物神经元并不完全不同。
从数学上看,我们可以将其写成如下形式:

这里,x[i] = 0 或 1。
我们可以将其视为输出布尔值答案;也就是说,true或false(或者yes或no)。
虽然 MP 神经元看起来简单,但它能够建模任何逻辑函数,如OR、AND和NOT;但是它无法对XOR函数进行分类。此外,它没有学习能力,因此阈值(b)需要通过解析方法进行调整以适应我们的数据。
感知机
由 Frank Rosenblatt 于 1958 年创建的感知机模型是 MP 神经元的改进版,它可以接受任何实数值作为输入。每个输入都会乘以一个实值权重。如果加权输入的和大于阈值,则输出为1,如果低于阈值,则输出为0。下图展示了一个基本的感知机模型:

这个模型与 MP 神经元有很多相似之处,但它更接近生物神经元。
数学上,我们可以将其写成如下形式:

这里, ![]。
有时,我们将感知机方程写成以下形式:

下图展示了感知机方程的形式:

这里, ![] 和 ![]。这避免了我们必须硬编码阈值,从而使得阈值成为一个可学习的参数,而不是像 MP 神经元那样需要手动调整的内容。
MP 神经元和感知机的优缺点
感知机模型相对于 MP 神经元的优势在于,它能够通过错误修正进行学习,并且通过超平面将问题进行线性分割,因此,超平面下的所有点为0,超平面上的所有点为1。这种错误修正使得感知机可以调整权重并移动超平面的位置,从而正确地分类数据。
之前,我们提到过感知机学习线性分类一个问题——但是它究竟学习了什么呢?它学习的是问题本身的性质吗?不是。它学习的是输入对输出的影响。因此,某个输入所关联的权重越大,它对预测(分类)的影响就越大。
权重的更新(学习)过程如下:

这里,δ = 预期值 – 预测值。
如果我们想加快学习速度,也可以加入学习率(![]);那么,更新公式将如下所示:

在这些更新过程中,感知机计算超平面与待分类点之间的距离,并调整自身以找到最佳位置,从而能够完美地线性分类这两个目标类别。因此,它会最大限度地将两侧的点分开,这一点可以从以下图中看到:

更加令人着迷的是,由于上述的学习规则,感知机在给定有限次数的更新时保证会收敛,因此能够处理任何二分类任务。
但遗憾的是,感知机也并不完美,它也有局限性。由于它是一个线性分类器,因此无法处理非线性问题,而非线性问题占我们通常希望开发解决方案的大多数问题。
MLPs
如前所述,MP 神经元和感知机模型都无法处理非线性问题。为了解决这个问题,现代感知机使用一种激活函数,将非线性引入到输出中。
我们将使用的感知机(神经元,但接下来我们大多数情况下称其为节点)形式如下:

这里,y 是输出,φ 是非线性激活函数,x[i] 是单元的输入,w[i] 是权重,b 是偏差。这个改进版的感知机如下所示:

在前面的图示中,激活函数通常是 sigmoid 函数:

Sigmoid 激活函数的作用是将所有输出值压缩到(0, 1)范围内。Sigmoid 激活函数主要是出于历史原因被广泛使用,因为早期神经元的开发者关注的是阈值处理。当引入基于梯度的学习时,sigmoid 函数证明是最佳选择。
MLP 是最简单的 FNN 类型。它基本上是许多节点组合在一起,计算过程是按顺序进行的。网络结构如下:

FNN 本质上是一个有向无环图;也就是说,连接总是朝着一个方向流动。没有将输出反馈到网络的连接。
如前面的图示所示,节点按层排列,每一层的节点与下一层的每个神经元相连。然而,同一层的节点之间没有连接。我们将这种网络称为全连接。
第一层称为输入层,最后一层称为输出层,所有中间的层称为隐藏层。输出层中的节点数量取决于我们为 MLP 构建的任务类型。请记住,层的输入和输出与网络的输入和输出是不同的。
你可能还会注意到,在上述架构中,输出层只有一个单元。这通常出现在回归或二分类任务中。所以,如果我们希望网络能够检测多个类别,那么输出层将包含K个节点,其中K是类别的数量。
请注意,网络的深度是指它的层数,而宽度是指每层的节点数量。
然而,使得神经网络如此强大且有效的原因,也是我们研究它们的原因,是它们是通用的函数近似器。通用近似定理表明:“一个具有有限个神经元的单隐层前馈神经网络可以在激活函数满足温和假设的条件下,近似定义在紧致子集上的连续函数。”这意味着,如果隐层包含特定数量的神经元,那么我们的神经网络可以合理地近似任何已知的函数。
你会发现,隐层需要多少神经元才能近似任何函数并不明确。这可能会有很大不同,取决于我们希望它学习的函数。
到现在,你可能在想,既然 MLP 自 1960 年代末期就已存在,为什么它们直到今天才广泛应用并取得成功?这是因为 50 年前的计算能力远不如今天的强大,同时,当时也没有现在如此丰富的数据。因此,由于当时 MLP 未能取得显著成果,它们逐渐被遗忘。由于这一原因,再加上通用近似定理,当时的研究者并未深入研究超过几层的网络。
让我们分解模型,看看它是如何工作的。
层
我们现在知道,MLP(以及前馈神经网络 FNN)由三种不同类型的层组成——输入层、隐藏层和输出层。我们也知道一个单一神经元的样子。现在让我们从数学角度探索 MLP 及其工作原理。
假设我们有一个包含
输入的多层感知器(MLP)(其中
),L层,每层有N个神经元,一个激活函数![],以及网络输出y。该 MLP 的结构如下:

如你所见,这个网络有四个输入——第一隐藏层有五个节点,第二隐藏层有三个节点,第三隐藏层有五个节点,输出层有一个节点。数学上,我们可以将其写作如下:

在这里,![]是l(th)*层中的*i(th)节点,![]是l(th)*层的激活函数,*x[j]*是输入网络的*j(th)个输入,![]是l(th)*层中*i(th)节点的偏置,![]是将l-1(st)*层的*j(th)节点与l(th)*层的*i(th)节点连接起来的有向权重。
在我们继续之前,先来回顾一下前面的方程式。从这些方程式中,我们可以很容易地观察到,每个隐藏节点都依赖于前一层的权重。如果你拿起一支铅笔,画出这个网络(或者用手指沿着连接线走一遍),你会发现,随着我们深入网络,后面隐藏层中的节点与前面层的节点之间的关系变得越来越复杂。
现在你已经有了一些关于 MLP 中每个神经元如何计算的概念,你可能已经意识到,显式地写出每个节点在每一层中的计算过程可能是一项艰巨的任务。所以,让我们以更简洁清晰的方式重写前面的方程式。我们通常不会以每个节点上的计算来表达神经网络,而是通过层来表示,因为每层有多个节点,我们可以用向量和矩阵来表示前面的方程式。现在,前面的方程式可以写作如下:

这简单多了。
记得在第二章《线性代数》中提到的,当你将向量或矩阵与标量值相乘时,标量值会作用于所有的条目。
对于我们想要构建的网络,输入很可能不再是向量,正如前面的例子中那样;它将是一个矩阵,所以我们可以将其重写如下:

在这里,X 是包含我们希望用来训练模型的所有数据的矩阵,H^([l])包含每一层所有数据样本的隐藏节点,其他的和之前一样。
如果你有留心的话,你会发现矩阵中的乘法顺序与之前的有所不同。你认为这是为什么呢?(我给你个提示——转置。)
现在,你应该对神经网络的构造有了相当不错的高层次理解。现在,让我们揭开面纱,看看底层发生了什么。我们从前面的方程中知道,神经网络由一系列矩阵乘法、矩阵加法和标量乘法组成。由于我们现在处理的是向量和矩阵,它们的维度非常重要,因为如果它们没有正确对齐,我们就无法进行乘法和加法运算。
让我们以完整的矩阵形式查看前面的 MLP。(为了简化,我们将逐层进行,并且由于我们的输入是向量形式,所以使用第二种形式。)为了简化视图并正确理解发生了什么,我们现在表示
和![]。
按如下方式计算z^([1]):

按如下方式计算h^([1]):

按如下方式计算z^([2]):

按如下方式计算h^([2]):

按如下方式计算z^([3]):

按如下方式计算h^([3]):

按如下方式计算z^([4]):

按如下方式计算y:

就这样。这些是我们 MLP 中发生的所有操作。
我稍微调整了前面的符号表示,将![]放在括号中,并将y表示为向量,尽管它显然是一个标量。这只是为了保持流程并避免更改符号。如果我们使用k类分类(得到多个输出神经元),y将是一个向量。
现在,如果你回想一下第二章,线性代数,我们做了矩阵乘法,我们学习到,当一个矩阵或向量与另一个维度不同的矩阵相乘时,得到的矩阵或向量的形状会不同(当然,除非我们与单位矩阵相乘)。我们称这种操作为映射,因为我们的矩阵将一个空间中的点映射到另一个空间中的点。记住这一点,让我们再看一下在 MLP 中进行的操作。从中我们可以推导出我们的神经网络将输入向量从一个欧几里得空间映射到另一个欧几里得空间中的输出向量。
根据这一观察,我们可以概括并写出以下内容:

在这里,![] 是我们的 MLP,![] 是输入层维度中的节点数,![] 是输出层中的节点数,而 L 是总层数。
然而,在之前的网络中,有多个矩阵乘法操作发生,每个操作的维度不同,这表明映射序列发生了(从一层到下一层)。
我们可以分别写出映射关系,如下所示:

在这里,每个 f^i 值将 l^(th) 层映射到 l+1^(st) 层。为了确保我们已覆盖所有内容,
和
。
现在,我们可以通过以下方程来总结我们的多层感知器(MLP):

完成这一部分后,我们可以继续进入下一小节,了解激活函数。
激活函数
到目前为止,我们已经提到过几次激活函数,并且也介绍过其中一个——Sigmoid 激活函数。然而,这并不是我们在神经网络中使用的唯一激活函数。事实上,激活函数是一个活跃的研究领域,今天有许多不同类型的激活函数。它们可以分为两种类型——线性和非线性。我们将重点讨论后者,因为它们是可微分的,这一特性对于我们训练神经网络时非常重要。
Sigmoid
首先,我们将查看 Sigmoid,因为我们已经遇到过它。Sigmoid 函数的公式如下:

该函数的形式如下:

Sigmoid 激活函数将加权输入和偏置的和作为输入,并将其压缩到(0, 1) 范围内。
它的导数如下:

该导数的形式如下:

该激活函数通常用于输出层,用于预测基于概率的输出。我们避免在深度神经网络的隐藏层中使用它,因为它会导致所谓的梯度消失问题。当 x 的值大于 2 或小于 -2 时,Sigmoid 函数的输出将非常接近 1 或 0,分别地。这会阻碍网络学习的能力或极大地减慢学习速度。
双曲正切函数
另一种替代 Sigmoid 的激活函数是双曲正切函数(tanh)。其公式如下:

该函数的形式如下:

tanh函数将所有输出值压缩到(-1, 1)范围内。其导数如下所示:

导数如下所示:

从前面的图中可以看出,tanh函数是零中心的,这使得我们能够建模非常正、非常负或中性的值。
Softmax
softmax 激活函数将包含K元素的向量标准化为K元素的概率分布。因此,它通常用于输出层,以预测它属于某一类别的概率。
softmax 函数如下所示:

它的导数可以通过以下方式找到:

整流线性单元
整流线性单元(ReLU)是最广泛使用的激活函数之一,因为它比我们之前见过的激活函数在计算上更高效;因此,它使得网络能够更快地训练,从而更快地收敛。
ReLU 函数如下所示:

该函数如下所示:

如你所见,所有负值x都被剪切并变为0。虽然这看起来像一个线性函数,但它的导数如下所示:

导数如下所示:

这同样在训练中面临一些问题,特别是“死亡 ReLU”问题。当输入值为负时,学习会受到阻碍,因为我们无法对0进行求导。
Leaky ReLU
Leaky ReLU 是 ReLU 函数的一种修改版,它不仅能让网络学习更快,还更加平衡,帮助解决梯度消失问题。
漏斗 ReLU 函数如下所示:

该函数如下所示:

如你所见,区别在于之前被剪切掉的负值x现在被重新缩放为!,这克服了“死亡 ReLU”问题。该激活函数的导数如下所示:

导数如下所示:

参数化 ReLU
参数化 ReLU(PReLU)是漏斗 ReLU 激活函数的一种变种,具有类似的性能提升,唯一不同的是,在这里,参数是可学习的,而之前不是。
PReLU 函数如下所示:

该函数如下所示:

导数如下所示:

导数如下所示:

指数线性单元
指数线性单元 (ELU) 是一种改进版的泄漏 ReLU 激活函数,不同于所有情况下都有直线的形式,ELU 使用了对数曲线。
ELU 激活函数如下所示:

函数如下所示:

该激活函数的导数如下所示:

损失函数
损失函数是神经网络及其训练中非常关键的一部分。它们为我们提供了一种计算神经网络在前向传播后误差的方法。这个误差将神经网络的输出与训练数据中指定的目标输出进行比较。
我们关注的主要有两种误差——局部误差和全局误差。局部误差是神经元的预期输出与实际输出之间的差异。然而,全局误差是总误差(所有局部误差的和),它告诉我们网络在训练数据上的表现如何。
在实际应用中,我们有许多方法,每种方法都有其特定的使用场景、优缺点。传统上,损失函数被称为成本函数,表示为 J(θ) (或等效地,J(W,b))。
平均绝对误差
平均绝对误差 (MAE) 就是我们在第三章《概率与统计》中看到的 L1 损失,它的公式如下:

这里,N 是我们训练数据集中样本的数量。
我们在这里做的是计算预测值与真实值之间的绝对距离,并对所有误差的总和进行平均。
均方误差
均方误差 (MSE) 是最常用的损失函数之一,尤其在回归任务中(它输入一个向量并输出一个标量)。它计算的是输出与预期输出之间差异的平方。公式如下:

这里,N 是我们训练数据集中样本的数量。
在前面的方程中,我们计算的是 L2 范数的平方。直观上,我们应该能够看出,当![]时,误差为 0,且点之间的距离越大,误差越大。我们之所以使用这个,是因为它总是输出一个正值,通过对输出与预期输出之间的距离进行平方处理,它使我们更容易区分小误差和大误差,并加以修正。
均方根误差
均方根误差(RMSE)是前面提到的均方误差(MSE)函数的平方根,表达式如下:

我们使用这个损失的原因是,它将 MSE 函数缩放回平方误差之前的原始尺度,这使得我们更好地理解相对于目标的误差。
Huber 损失
Huber 损失的表达式如下:

这里,ε 是一个常数项,可以配置。它越小,损失对大误差和异常值的敏感度越低;而它越大,损失对大误差和异常值的敏感度越高。
现在,如果你仔细观察,你会发现,当ε非常小的时候,Huber 损失类似于 MAE,而当它非常大的时候,它则类似于 MSE。
交叉熵
交叉熵损失主要用于二分类问题,也就是网络输出值为 1 或 0 的情况。
假设给定一个训练数据集, ![] 和 ![]。我们可以将其表示为以下形式:

这里, θ 是网络的参数(权重和偏置)。我们可以通过伯努利分布来表示,表达式如下:

给定整个数据集的概率如下:

如果我们取其负对数似然,我们得到如下结果:

所以,我们得到以下公式:

当我们有超过两个类别时,也会使用交叉熵,这种情况称为多分类交叉熵。假设我们有 K 个输出单元,那么我们会计算每个类别的损失,然后将它们相加,表达式如下:

这里, ![] 是观察值 (i) 属于类别 k 的概率。
库尔贝克-莱布勒散度
库尔贝克-莱布勒(KL)散度 衡量两个概率分布 p 和 q 的差异。表达式如下:

所以,当 p(x)=q(x) 时,KL 散度在所有点的值为 0。这通常用于生成模型。
詹森-香农散度
像 KL 散度一样,詹森-香农(JS)散度衡量两个概率分布的相似度;然而,它更加平滑。以下方程表示 JS 散度:

当 p(x) 和 q(x) 都很小的时候,它表现得比 KL 散度要好得多。
反向传播
现在我们知道了如何计算 MLP 中的前向传递过程,以及如何初始化它们并计算网络的损失,是时候了解反向传播了——这是一种利用损失函数的信息计算网络梯度的方法。此时,我们需要用到多元微积分和偏导数的知识。
如果你还记得,这个网络是全连接的,这意味着每一层中的所有节点都与下一层的节点相连,并且对下一层有影响。正因为如此,在反向传播中,我们首先对最靠近输出层的权重求损失函数的导数,然后是前一层的权重,以此类推,直到达到第一层。如果你还不理解这个过程,不用担心,我们将详细讲解反向传播,并以之前的网络为例。我们假设激活函数为 sigmoid,损失函数为交叉熵。首先,我们将计算损失函数对W^([4])的导数,其表达式如下:






这样,我们就完成了第一次导数的计算。正如你所看到的,这个过程需要花费相当多的工作,计算每一层的导数可能是一个非常耗时的过程。所以,我们可以利用微积分中的链式法则来简化计算。
为了简便起见,假设![]和![],并且假设![]。现在,如果我们要计算损失对W^([2])的梯度,我们得到如下结果:

我们可以将其重写为:

假设我们确实要计算损失对b^([4])的偏导数,其表达式如下:

在进入下一部分之前,请密切注意前面的导数,![]。如果你回头看看层这一节,![]仍然是向量和矩阵。这一点仍然成立。因为我们又在处理向量和矩阵,所以确保它们的维度一致非常重要。
我们知道!,但其他的呢?我将留给你作为练习,看看其他的是否正确,如果不正确,你会如何调整顺序以确保它是正确的?
如果你对自己的数学能力非常有信心并且愿意挑战一下,我鼓励你尝试求导,![]。
训练神经网络
现在我们已经理解了反向传播和梯度是如何计算的,你可能会想知道它的作用是什么,以及它与训练我们的 MLP 有什么关系。如果你还记得在第一章《向量微积分》中,当我们讨论偏导数时,我们学到可以使用偏导数来检查改变一个参数对函数输出的影响。当我们使用一阶和二阶导数绘制图形时,我们可以从分析上得知局部和全局最小值与最大值。然而,在我们的例子中并非如此直接,因为我们的模型并不知道最优解在哪里或者如何到达那里;因此,我们使用反向传播和梯度下降作为引导,帮助我们到达(希望是全局的)最小值。
在第四章《优化》中,我们学习了梯度下降法,以及我们如何通过迭代地从函数的一个点移动到函数的一个较低点,在指向局部/全局最小值的方向上沿着负梯度的方向迈进一步。我们将其表示为如下形式:

然而,对于神经网络来说,权重的更新规则在此情况下写作如下:

在这里,θ = (W,b)。
正如你所见,尽管看起来类似,但这并不是我们学过的优化方法。我们的目标是最小化网络的总损失,并相应地更新我们的权重。
参数初始化
在第四章《优化》中,我们提到在开始优化之前,我们需要一个初始(起始)点,这就是初始化的目的。这是训练神经网络中一个极其重要的部分,因为正如本章前面提到的,神经网络有很多参数——通常超过千万——这意味着找到在权重空间中最小化损失的点可能非常耗时且具有挑战性(因为权重空间是非凸的;也就是说,存在很多局部最小值和鞍点)。
由于这个原因,找到一个好的初始点非常重要,因为它能让我们更容易找到最优解并减少训练时间,同时减少权重消失或爆炸的可能性。现在让我们探索一下可以初始化权重和偏置的不同方式。
全零初始化
正如名字所示,在这里我们将模型的初始权重和偏置设置为 0。我不建议这么做,因为,正如你可能猜到的那样,这意味着我们模型中的所有神经元都“死了”。实际上,这正是我们在训练网络时想要避免的问题。
让我们看看会发生什么。为了简化起见,假设我们有以下的线性分类器:

如果权重初始化为 0,那么我们的输出将始终是 0,这意味着我们丧失了训练数据中所有的信息,并且我们投入大量精力构建的网络什么也学不到。
随机初始化
初始化权重为非零的其中一种方法是使用随机初始化,对于这一点,我们可以使用两种分布之一——正态分布或均匀分布。
为了使用正态分布初始化我们的参数,我们必须指定均值和标准差。通常,我们选择均值为 0,标准差为 1。为了使用均匀分布初始化,我们通常使用[-1, 1]的范围(在这个范围内,每个值被选中的概率是相等的)。
虽然这给我们提供了可以用于训练的权重,但它非常慢,并且之前在深度网络中曾导致梯度消失和梯度爆炸,导致表现平平。
Xavier 初始化
正如我们所看到的,如果我们的权重过小,那么它们会消失,导致神经元死亡;相反,如果我们的权重过大,就会出现梯度爆炸。我们希望避免这两种情况,这意味着我们需要将权重初始化得刚刚好,以便我们的网络能够学习所需的内容。
为了解决这个问题,Xavier Glorot 和 Yoshua Bengio 创建了一种规范化的初始化方法(通常称为 Xavier 初始化)。它的具体方法如下:

这里,n[k] 是第 k 层中的神经元数量。
但是,为什么这种方法比随机初始化我们的网络效果更好呢?这个想法是,我们希望在通过后续层传播时保持方差。
数据
正如你现在所了解的,我们在这里尝试构建的是能够学习将输入映射到输出的网络。为了让我们的网络能够做到这一点,它需要接受数据——而且是大量数据。因此,我们需要知道数据应该是什么样子的,这一点非常重要。
假设我们有一个分类或回归任务。我们的数据将呈现以下形式:

在这里,我们假设以下内容:

如你所见,数据集中的每个样本都有输入(x[i])和相应的输出/目标(y[i])。然而,具体表现可能会根据任务有所不同。在回归中,我们的输出可以是任意实数值,而在分类中,它必须是我们可以预测的某个类别。
如你所料,我们的数据(x)包含了我们希望用来预测目标变量(y)的各种信息,这当然取决于问题的具体情况。例如,假设我们使用波士顿住房数据集,这是一个回归任务。它包含以下特征:
-
每个城镇的犯罪率(按人均计算)
-
规划为 25,000 平方英尺以上大块地皮的住宅用地比例
-
每个城镇非零售商业用地的比例
-
查尔斯河虚拟变量(如果区域边界接壤河流则为 1,否则为 0)
-
一氧化氮浓度值(百万分之一)
-
每个住宅的平均房间数
-
1940 年之前建造的自有住宅比例
-
距离五个波士顿就业中心的加权距离
-
通往径向高速公路的可达性指数
-
每$10,000 的全额房产税税率
-
每个城镇的师生比
-
每个城镇非裔美国人比例
-
处于较低社会地位的群体所占人口比例
目标变量是自有住房的中位数价值,单位为$1,000。
所有数据都是数值型的(因为机器并不真正理解这些标签的含义,但它们知道如何解析数字)。
现在,我们来看一个分类问题——因为我们正在尝试预测数据属于哪一类,所以目标将变成一个向量,而不是前面数据集中使用的标量,目标向量的维度将是类别的数量。那么我们该如何表示这个目标向量呢?
假设我们有一个包含图像及其对应目标标签的数据集:

如你所见,每个标签都有一个数字分配给它,在训练过程中,我们的网络可能会误将这些视为可训练参数,这显然是我们希望避免的。相反,我们可以进行独热编码,将标签向量转化为如下形式:

很好!现在我们知道了数据集的内容以及数据集的结构。那么接下来呢?我们将数据集分为训练集、测试集和验证集。如何将数据划分为这三个集合,很大程度上取决于我们拥有的数据量。在深度学习的情况下,我们通常会处理非常大的数据集,也就是说,数百万到千万级的样本。
一般来说,我们通常选择 80-90%的数据集用于训练我们的网络,其余的 10-20%则分为两个部分——验证集和测试集。在训练过程中,验证集用于确定我们的网络是否出现过拟合或欠拟合,而测试集则用于最后检查我们的模型在处理未见数据时的泛化能力。
深度神经网络
现在,到了真正有趣的部分(也是你拿起这本书的原因)——深度神经网络。深度的来源是神经网络中的层数,要使一个前馈神经网络被认为是深度的,它必须具有超过 10 个隐藏层。今天许多最先进的前馈神经网络已经有了超过 40 层。现在,让我们来探索一下深度前馈神经网络的一些特性,并了解它们为何如此强大。
如果你还记得,之前我们遇到过普适逼近定理,它指出一个只有单一隐藏层的 MLP 能够逼近任何函数。但如果是这样,那为什么我们还需要深度神经网络呢?简单来说,神经网络的容量随着每增加一个隐藏层而增加(而大脑本身具有深度结构)。这意味着,深度网络相比浅层网络具有更强的表现力。这一点我们之前在学习 MLP 时就有所接触。当时我们看到,通过增加隐藏层,我们能够创建一个能够解决线性神经网络无法解决的问题的网络。
此外,深型网络比宽型网络更受偏爱,并非因为它们提高了整体性能,而是因为具有更多隐藏层(但宽度较小)的网络比具有较少隐藏层但宽度更大的网络拥有更少的参数。
假设我们有两个网络——一个是宽型的,一个是深型的。这两个网络都有 20 个输入和 6 个输出节点。让我们计算这两个网络的总参数数量,也就是所有层之间的连接数和偏置。
我们的宽型神经网络有两个隐藏层,每个隐藏层包含 1,024 个神经元。总的参数数量如下:

我们的深度神经网络有 12 个隐藏层,每个隐藏层包含 150 个神经元。总的参数数量如下:

如你所见,深型网络的参数比宽型网络少了一半。
总结
在这一章中,我们首先学习了一个简单的前馈神经网络(FNN),即多层感知机(MLP),并将其拆解为各个组成部分,以更深入地理解它们是如何工作的以及如何构建的。接着,我们将这些概念扩展到更深的神经网络,进一步加深了对它们的理解。现在,你应该已经对前馈神经网络的工作原理有了深刻的理解,并且明白了各种模型是如何构建的,以及如何为自己构建并可能改进它们。
接下来,让我们进入下一章,学习如何改进我们的神经网络,使其在未见数据上能够更好地泛化。
第八章:正则化
在上一章,我们学习了(深度)前馈神经网络及其结构。我们了解了这些架构如何利用隐藏层和非线性激活函数来学习如何在一些非常具有挑战性的任务上表现出色,而线性模型则无法做到这一点。我们还看到神经网络倾向于通过学习数据集中的噪声来过拟合训练数据,从而导致测试数据上的误差。自然地,由于我们的目标是创建能够很好地泛化的模型,我们希望缩小差距,使我们的模型在两个数据集上表现得同样好。这正是正则化的目标——减少测试误差,有时可能会牺牲一定的训练误差。
在本章中,我们将介绍多种用于正则化的方法,讲解它们的工作原理,并解释为何某些技术比其他技术更受偏好。这包括限制神经网络的能力、应用范数惩罚和数据集扩增等内容。
本章将涵盖以下内容:
-
正则化的必要性
-
范数惩罚
-
早停法
-
参数类型和共享
-
数据集扩增
-
Dropout
-
对抗训练
正则化的必要性
在前面的章节中,我们学习了前馈神经网络如何通过使用训练数据学习底层分布,将输入映射到相应的目标/标签,从而基本上成为一个复杂的函数。我们回想一下,在训练过程中,前向传播计算出误差后,反向传播用于更新参数,以减少损失,更好地逼近数据分布。我们还学习了神经网络的能力、偏差-方差权衡以及神经网络如何过拟合或欠拟合训练数据,导致它在未见数据或测试数据上表现不佳(即发生了泛化误差)。
在我们深入探讨正则化的具体内容之前,让我们先回顾一下过拟合和欠拟合。正如我们所知,神经网络是通用的函数逼近器。深度神经网络具有多个隐藏层,这意味着有很多需要训练的参数。一般来说,模型的参数越多,模型越复杂,也就意味着它过拟合训练数据的风险更大。
这意味着我们的模型已经完美地学习了数据中所有的模式,包括噪声,在训练数据上的损失为零,但在测试数据上的损失很高。此外,过拟合的模型通常具有较低的偏差和非常高的方差。相反,参数较少的模型往往较为简单,这意味着它们更可能欠拟合训练数据,因为它们观察到的数据量较小,且这些数据之间差异不大。因此,它们往往具有更大的偏差,这也导致了高方差。以下图表说明了上述解释:

在过拟合和欠拟合之间有一个甜蜜点,我们在这个位置上有最优的容量;也就是说,模型的超参数是完全适应当前任务和数据的——这就是我们的目标。它告诉我们,正则化的目标是防止模型过拟合,我们更倾向于选择较简单的模型,而不是复杂的模型。然而,最好的模型是一个大型并且正则化得当的模型。
现在我们已经了解了正则化的目的,接下来让我们探讨一些我们可以用来正则化深度神经网络的方法。
范数惩罚
在目标函数中添加一个参数范数惩罚是最经典的正则化方法。这么做的目的是限制模型的容量。这个方法已经存在了几十年,甚至早于深度学习的出现。我们可以将其写为如下形式:

在这里,![]。前述方程中的 α 值是一个超参数,决定了正则化项对正则化成本函数的影响有多大。α 值越大,正则化作用越强,越小则正则化对成本函数的影响越小。
在神经网络的情况下,我们仅对权重应用参数范数惩罚,因为它们控制着连续层之间两个节点的交互或关系,而我们保持偏置不变,因为它们相比权重需要的数据较少。
在选择使用哪种参数范数时,我们有几种不同的选择,每一种都有不同的解决效果。
L2 正则化
L2 正则化方法通常被称为 岭回归(但更常见的名字是 权重衰减)。它通过以下正则化项,迫使网络的权重朝向原点收缩:

为了简化起见,我们假设 θ = w,且所有字母都代表矩阵。
在这种情况下,正则化后的目标函数如下:

如果我们计算它的梯度,那么就变成了以下形式:

使用前述的梯度,我们可以计算每一步梯度更新的权重更新,如下所示:

我们可以展开并重写前述更新式的右侧如下:

从这个方程中,我们可以清晰地看到,修改后的学习规则使得我们的权重在每一步都按 ![] 收缩,就像下面的图示一样:

在前面的图中,我们可以看到 L2 正则化对我们权重的影响。右上方的实心圆表示原始目标函数的等值线,![],我们尚未对其应用正则化项。另一方面,虚线圆圈表示正则化项的等值线,
。最后,
,两个等值线交汇的点代表两个目标达到平衡时的情况。
L1 正则化
另一种范数惩罚形式是使用 L1 正则化,有时也称为最小绝对收缩和选择算子(lasso)回归。在这种情况下,正则化项如下:

这意味着它将参数的绝对值求和。其效果是通过将一些值归零,给我们的模型引入稀疏性,告诉我们这些值并不重要。这可以被看作是特征选择的一种形式。
类似于前面的 L2 正则化,在 L1 正则化中,α超参数控制正则化对目标函数的影响程度:

具体如下图所示:

正如你在前面的图示中看到的,目标函数的轮廓现在与坐标轴相交,而不是像在 L2 正则化中那样与某一点相交,这也是该方法中稀疏性产生的原因。
现在我们已经学习了如何对深度神经网络进行正则化,接下来让我们看看什么是早停法。
早停法
在训练过程中,我们知道我们的神经网络(它有足够的容量来学习训练数据)有过拟合训练数据的倾向,经过多次迭代后,它们无法将所学知识推广到测试集上,表现不佳。克服这个问题的一种方法是在每次迭代时绘制训练集和测试集的误差,并通过分析寻找训练集和测试集误差最接近的迭代次数。然后,我们选择这些参数作为我们的模型。
这种方法的另一个优点是,它并不会像参数范数那样改变目标函数,这使得它易于使用,并且不会干扰网络的学习动态,正如下图所示:

然而,这种方法并不完美——它确实存在一些缺点。它计算开销较大,因为我们必须训练网络更长时间并收集更多数据,然后观察性能开始下降的点。
参数绑定与共享
上述参数范数惩罚通过惩罚模型参数的偏离(从 0,即固定值)来起作用。但有时,我们可能希望表达一些关于哪些参数更适合模型的先验知识。虽然我们可能不知道这些参数是什么,但得益于领域知识和模型的架构,我们知道模型的参数之间可能存在一些依赖关系。
这些依赖关系可能是一些特定的参数,它们与某些参数比与其他参数更接近。假设我们有两个不同的分类任务模型,并且检测相同数量的类别。然而,它们的输入分布并不相同。我们将第一个模型命名为 A,其参数为 θ^((A)),第二个模型命名为 B,其参数为 θ^((B))。这两个模型分别将各自的输入映射到输出:
和 
由于这两种模型都在执行相对类似(甚至可能是相同)任务,并且很可能具有相似(或相同)输入分布,因此模型 A 和模型 B 的参数应该彼此接近。
我们可以使用参数范数惩罚,例如 L2 惩罚,来确定 θ^((A)) 和 θ^((B)) 参数的接近度,方法如下:

除了 L2 范数,我们还可以使用其他度量来衡量距离。
这种强制使参数彼此接近的方法称为参数共享。其原因在于,这可以解释为不同模型共享一组参数。与参数范数惩罚相比,这种方法更为优选,因为它需要更少的内存,因为我们只需存储一组独特的共享参数。
数据集增强
如我们所学,深度前馈网络非常依赖数据,它们利用所有这些数据学习潜在的数据分布,以便能够使用所获得的知识对未见数据进行预测。这是因为它们看到的数据越多,它们在测试集上遇到的内容就越有可能是它们已经学习过的分布的插值。但获得一个足够大且具有良好质量标签的数据集绝非易事(尤其是对于某些问题,收集数据可能非常昂贵)。绕过这个问题的一种方法是使用数据增强;也就是说,生成合成数据并利用这些数据训练我们的深度神经网络。
合成数据生成的方式是我们使用生成模型(在第十二章《生成模型》中会进一步讲解)来学习数据集的潜在分布,然后用生成模型创建类似于真实数据的合成数据,使其看起来像是来自同一数据集。我们还可以对合成数据添加一些小的变异,使模型对噪声更加鲁棒。
这种方法在计算机视觉中已经被证明非常有效——特别是在目标检测/分类中——我们在卷积神经网络中使用了它(我们将在第九章《卷积神经网络》中学习到更多内容)。
另一种常用于图像识别的数据增强方法是图像裁剪和图像旋转,我们可以对输入图像进行裁剪,或者将其旋转一定的角度。这些方法也被证明能增加鲁棒性,并提高在未见数据上的泛化能力。我们还可以对图像进行损坏、模糊处理,或加入一些高斯噪声,以使网络更具鲁棒性,因为许多真实世界的数据往往是噪声较大的。
然而,这也存在一些局限性。例如,在光学字符识别(我们希望识别字母和数字)的情况下,水平翻转和 180 度旋转可能会影响类别。经过变换后,b 可能变成 d,6 可能变成 9。在一些情况下,数据增强根本就不是一个选项;例如,在医学领域,我们可能需要处理 MRI 和 CT 扫描数据。然而,在这种情况下,我们可以应用仿射变换,比如旋转和平移。
让我们暂时聚焦于噪声注入。有两种方法可以做到这一点——第一种是将噪声注入到输入数据中,第二种是将噪声注入到隐藏单元中。事实上,研究发现,将噪声添加到隐藏单元中,比参数收缩更能起到更好的正则化作用,因为它有助于提高稳定性。
丢弃法(Dropout)
在前面的章节中,我们学习了如何通过对权重的范数应用惩罚来进行正则化,以及其他方法,例如数据集增强和早停。然而,还有一种在实际中广泛使用的有效方法,称为丢弃法(dropout)。
到目前为止,在训练神经网络时,所有权重都是一起学习的。然而,dropout 改变了这一观点,在每次迭代中,网络只学习一部分权重。这样做的原因是为了避免共同适应(co-adaptation)。当我们在所有训练数据上训练整个网络时,某些连接会比其他连接更强,从而对网络的预测能力贡献更大,因为强连接压倒了弱连接,实际上忽略了它们。随着我们进行更多次迭代训练,一些较弱的连接会逐渐“死掉”,不再可训练,因此最终只会训练出一个子网络,导致部分网络被浪费掉。前述的正规化惩罚方法是无法解决这个问题的。
dropout 克服过拟合的方式是通过随机(根据预设的概率)从隐藏层中移除(drop out)神经元;也就是说,我们临时将某些节点的输入和输出边缘归零,使其在该次训练迭代中不对网络产生影响。例如,如果我们有一个多层感知器(MLP),它有一个包含 10 个神经元的隐藏层,并且我们使用 dropout,p = 0.5,那么一半的神经元将被置为 0。如果 p = 0.2,则 20% 的神经元会被丢弃:

让我们考虑一个具有 L 个隐藏层的 MLP,其中 ![],每层的输入向量为 z^((l)),每层的输出向量为 y((l))*(为了简便起见,*y((0)) = x)。每层的权重和偏置分别用 W^((l)) 和 b^((l)) 表示。然后,我们得到如下公式:

这里,f 是任意激活函数。
现在,使用 dropout 后,前向传播操作变为以下形式:

所以,我们发现 p = 0.5 在训练过程中具有最佳的正则化效果。
对抗训练
现在,神经网络在许多任务上已经达到了人类水平的准确性,在某些任务上甚至超越了人类。但它们真的超越了人类,还是仅仅看起来如此?在生产环境中,我们常常需要处理噪声数据,这可能会导致我们的模型做出错误的预测。因此,我们接下来将学习另一种非常重要的正则化方法——对抗训练。
在我们讨论对抗训练的“是什么”和“如何做”之前,让我们先看一下下面的图示:

在前面的图示中,我们所做的是在原始图像的像素中加入了微小的高斯噪声。对我们来说,图像看起来完全一样,但对卷积神经网络来说,图像看起来完全不同。这是一个问题,即使我们的模型训练得非常完美,几乎没有错误,依然会发生这种情况。
我们所做的是找到一个数据点,x',它接近x,但模型预测x'属于不同的类别。现在,为了向我们的图像添加噪声,我们可以按如下方式进行:

我们之所以关注这个问题,是因为向训练数据集中添加对抗性扰动的数据样本可以帮助减少测试集上的误差。
概述
在这一章中,我们讨论了多种用于正则化神经网络参数的方法。这些方法在训练模型时非常重要,因为它们帮助确保模型能够推广到未见过的数据,防止过拟合,从而在我们希望使用它们的任务中表现良好。在接下来的章节中,我们将学习不同类型的神经网络,以及每种网络如何更好地解决某些类型的问题。每种神经网络都有一种正则化方法,可以用来帮助提升性能。
在下一章,我们将学习卷积神经网络,它们用于计算机视觉。
第九章:卷积神经网络
在本章中,我们将介绍一种最受欢迎且广泛使用的深度神经网络——卷积神经网络(CNN,也称为ConvNet)。
正是这一类神经网络在过去几年里大大推动了计算机视觉领域的惊人进展,从由 Alex Krizhevsky、Geoffrey Hinton 和 Ilya Sutskever 创建的 AlexNet 开始,该模型在 2012 年ImageNet 大规模视觉识别挑战赛(ILSVRC)中超越了所有其他模型,从而开启了深度学习的革命。
卷积神经网络(ConvNets)是一种非常强大的神经网络类型,用于处理数据。它们具有网格状拓扑结构(即,相邻点之间存在空间关联),并且在各种应用中非常有用,例如人脸识别、自动驾驶汽车、监控、自然语言处理、时间序列预测等。
我们将首先介绍卷积神经网络的基本构建块,并介绍一些实际应用中使用的架构,例如 AlexNet、VGGNet 和 Inception-v1,同时探索它们为何如此强大。
本章将涵盖以下主题:
-
卷积神经网络的灵感来源
-
卷积神经网络中使用的数据类型
-
卷积和池化
-
使用卷积神经网络架构
-
训练与优化
-
探索流行的卷积神经网络架构
卷积神经网络的灵感来源
卷积神经网络(CNN)是一种人工神经网络(ANN);它们受到人类视觉皮层处理图像并使我们的脑部能够识别世界中的物体并与之互动的概念启发,这使我们能够做许多事情,例如驾驶、打球、阅读、看电影等。
已经发现,类似卷积的计算过程在我们的大脑中发生。此外,我们的大脑中存在简单和复杂细胞。简单细胞捕捉基本特征,如边缘和曲线,而复杂细胞则表现出空间不变性,同时也响应与简单细胞相同的线索。
卷积神经网络中使用的数据类型
卷积神经网络在视觉任务上表现出色,例如图像和视频中的物体分类与识别,以及音乐、音频片段中的模式识别等。它们在这些领域的效果良好,因为它们能够利用数据的结构进行学习。这意味着我们无法改变数据的属性。例如,图像具有固定结构,如果我们改变这一结构,图像将不再有意义。这与人工神经网络(ANN)不同,后者中特征向量的顺序不重要。因此,卷积神经网络的数据存储在多维数组中。
在计算机中,图像可以是灰度图像(黑白图像)或彩色图像(RGB),视频(RGB-D)由像素组成。像素是数字化图像中最小的单位,可以在计算机上显示,并且其值的范围为[0, 255]。像素值表示其强度。
如果像素值为0,则表示黑色;如果像素值为128,则表示灰色;如果像素值为255,则表示白色。我们可以在以下截图中看到这一点:

正如我们所见,灰度图像只需要 1 字节的数据,而彩色图像则由三种不同的值——红色、蓝色和绿色组成——因为任何颜色都可以通过这三种颜色的组合来显示。我们可以在以下图示中看到色彩空间(参见图形包中的色彩图):

根据我们在立方体中的位置,我们显然会得到不同的颜色。
我们可以将其看作是拥有三个独立通道——红色、蓝色和绿色,而不是看作一个立方体或不同的颜色强度。那么,每个像素需要 3 字节的存储。
通常,我们无法看到显示在显示器上的图像和视频中的单独像素,因为它们的分辨率非常高。这可以有很大的不同,但像素通常在每英寸几百到几千个点(像素)每英寸(dpi)之间。
位(binary unit)是计算机的基本单位,每个位可以取 0 或 1 两个值。一个字节由 8 个位组成。如果你想知道,[0, 255]范围来自像素值被存储为 8 位(2⁸ - 1 = 255)。然而,我们也可以有一个 16 位数据值。在彩色图像中,我们可以使用 8 位、16 位、24 位或 30 位值,但通常使用 24 位值,因为我们有三种颜色的像素,RGB,每种颜色有 8 位的数据值。
假设我们有一个灰度图像,尺寸为 512 × 512 × 1(高度 × 宽度 × 通道)。我们可以将其存储在一个二维张量(矩阵)中,![],其中每个i和j的值表示一个具有一定强度的像素。要将这个图像存储到磁盘上,我们需要 512 × 512 = 262,144 字节。
现在,假设我们有一个尺寸为 512 × 512 × 3(高度 × 宽度 × 通道)的彩色图像。我们可以将其存储在一个三维张量中,![],其中每个i, j,和k的值表示一个具有一定强度的彩色像素。要将这个图像存储到我们的磁盘上,我们需要 512 × 512 × 3 = 786,432 字节,这说明存储彩色图像需要更多的空间,因此处理时间也更长。
彩色视频可以表示为一系列帧(图像)。我们从将时间离散化开始,使得每帧之间有固定的时间间隔。我们可以将常规视频(灰度图像)存储在一个三维数组中,其中一个轴表示帧的高度,另一个表示宽度,第三个表示时间长度。
我们将在本章稍后学习到,CNNs 对于音频和时间序列数据也非常有效,因为它们能抵抗噪声。我们将时间序列数据表示为一维数组,其中数组的长度表示时间,这正是我们进行卷积的对象。
卷积和池化
在第七章《前馈神经网络》中,我们看到深度神经网络是如何构建的,以及如何通过权重将一个层的神经元与前一层或后一层的神经元连接。然而,CNNs 中的层是通过一种线性操作,即 卷积,来连接的,这也是它们名字的来源,也是它们在图像处理方面如此强大的原因。
在这里,我们将介绍在实践中使用的各种卷积和池化操作,以及每种操作的效果。但首先,让我们看看卷积到底是什么。
二维卷积
在数学中,我们将卷积表示为如下形式:

这意味着我们有一个函数 f 作为输入,另一个函数 g 作为卷积核。通过对它们进行卷积,我们得到一个输出(有时称为特征图)。
然而,在卷积神经网络(CNNs)中,我们通常使用离散卷积,表示方式如下:

假设我们有一个高度为 5,宽度为 5 的二维数组,以及一个高度为 3,宽度为 3 的二维卷积核。那么,卷积及其输出将如下所示:

输出矩阵中的一些值留空,作为我们手动尝试卷积操作的练习,帮助更好地理解此操作是如何工作的。
如你所见,卷积核滑过输入,生成一个高度为 3,宽度为 3 的特征图。这个特征图告诉我们函数 f 和 g 重叠的程度,即一个函数如何在另一个函数上滑动。我们可以把这看作是在输入中扫描某个模式;换句话说,特征图在不同位置查找相同的模式。
为了更好地理解卷积核是如何在输入上移动的,可以想象一下打字机。卷积从左上角开始,进行逐元素的乘法和加法,然后向右移动一步并重复此过程,直到到达最右侧的位置,且不越过输入的边界。接着,它向下一行移动,并重复这一过程,直到到达右下角的位置。
假设我们现在有一个 3 × 3 的二维张量作为输入,并应用一个 2 × 2 的卷积核。结果如下所示:

我们可以将特征图中的每个输出数学地表示如下:

现在,我们可以将前面的离散卷积公式重写如下:

这让我们对发生的事情有了更清晰的理解。
从前面的操作可以看出,如果我们不断地对特征图进行卷积处理,每一层的高度和宽度会逐渐减小。所以,有时我们可能希望在卷积操作后保持I的大小(尤其是当我们构建一个非常深的卷积神经网络时),在这种情况下,我们可以在矩阵外部填充零。这样做是为了在应用卷积操作之前增大矩阵的大小。
所以,如果I是一个 n × n 的数组,而我们的卷积核是一个 k × k 的数组,并且我们希望我们的特征图也是 n × n 的,那么我们对I进行一次填充,将其变为(n+2) × (n+2)的数组。现在,经过卷积操作后,生成的特征图将是 n × n 的大小。
填充操作如下所示:

实际上,这被称为全填充。当我们不进行填充时,我们称之为零填充。
如果我们希望减小特征图的大小,可以使用更大的卷积核或增加步幅大小——每种方式都会产生不同的结果。当步幅为 1 时,我们像往常一样每次滑动一个位置。然而,当步幅增加到 2 时,卷积核每次跳跃两个位置。
让我们使用前面卷积过的矩阵,看看当我们将步幅设置为 2 时会发生什么:

有了这些知识,我们可以使用以下公式计算特征图的结果形状:

这里,I是一个 n × n 的数组,K是一个 k × k 的数组,p是填充,s是步幅。
此外,我们可以根据需要重复此过程,使用不同的卷积核并生成多个特征图。然后,我们将这些输出堆叠在一起,形成一个三维特征图阵列,我们称之为一层。
例如,假设我们有一个大小为 52 × 52 的图像,卷积核的大小为 12 × 12,步幅为 2。我们将其应用到输入上 15 次,并将输出堆叠在一起。我们得到一个大小为![]的三维张量。
当我们为实际应用构建卷积神经网络时,很可能需要处理彩色图像。我们之前看到,灰度图像可以表示为二维张量(矩阵),因此卷积也是二维的。然而,彩色图像由三个通道组成,分别是红色、蓝色和绿色。这三个通道堆叠在一起,图像具有![]的形状,因此相关的卷积也将具有相同的形状。但有趣的是,对彩色图像进行三维卷积会得到一个二维的特征图。
在前面的例子中,我们讲解了如何对二维张量进行卷积,但是彩色图像有三个通道。因此,我们要做的是将这三个通道分开,分别对它们进行卷积,然后使用逐元素加法将它们各自的输出加在一起,最终得到一个二维张量。为了更好地理解这个过程,假设我们的输入大小为 3 × 3 × 3,我们可以将其分成三个通道,如下所示:

这告诉我们,I[i,j] = R[i,j] + B[i,j] + G[i,j]。现在我们已经将通道分开,让我们用 2 × 2 的卷积核分别对它们进行卷积。每个通道与卷积核进行卷积后,我们得到以下输出:
- 对红色通道进行卷积后的结果如下:

- 对蓝色通道进行卷积后的结果如下:

- 对绿色通道进行卷积后的结果如下:

如果我们想更深入地了解,可以通过数学公式写出每个输出元素是如何计算的。公式如下:

我们可以把这看作是对输入应用三维卷积。这里需要注意的是,卷积核的深度与图像的深度相同,因此它的移动方式与二维卷积操作相同。
我们并不是单独对每个通道应用卷积核,而是一次性对输入应用一个三维卷积核,并使用逐元素相乘和相加。这样做的原因是它允许我们对体积数据进行卷积。
在这里,我们对一个大小为 52 × 52 的输入应用了 15 个大小为 12 × 12,步长为 2 的卷积核,得到的输出大小为 21 × 21 × 15。接下来,我们可以对这个输出应用大小为 8 × 8 × 15 的卷积。这样,这次操作的输出大小将是 14 × 14。当然,和之前一样,我们可以将多个输出堆叠在一起形成一个层。
一维卷积
现在我们知道了二维卷积的工作原理,是时候看看它们在一维中的工作方式了。我们将这些用于时间序列数据,例如与股票价格或音频数据相关的数据。在前面的章节中,卷积核从左上角沿着轴移动到右上角,然后跳过一行或多行(取决于步幅)。这一过程会重复,直到它到达网格的右下角。
在这里,我们只沿着时间轴进行卷积——也就是说,沿着时间维度(从左到右)。然而,填充和步幅的影响在这里依然适用。
假设我们有以下数据:

我们还有以下一个大小为 1 × 3 的卷积核,我们希望将其应用到该数据上:

然后,在使用步幅为 2 的卷积后,我们得到以下输出:

有趣的是,我们还可以将一维卷积应用于矩阵(图像)。让我们看看它是如何工作的。假设我们有一个 4 × 4 的输入矩阵和一个 4 × 1 的卷积核。那么,卷积将按以下方式进行:

让我们来看看每个输出是如何计算的:

然而,我们的卷积核大小也可以更大,就像之前二维卷积的情况一样。
1 × 1 卷积
在前一节中,我们介绍了在体数据上进行的二维卷积,这些卷积是沿深度方向执行的(每个卷积的深度与输入的深度相同)。这实际上就像是将通道深度上的值与卷积核的值相乘,然后将它们相加得到一个单一的值。
如果我们取之前相同的输入,形状为 21 × 21 × 15,并应用一个形状为 1 × 1 × 15 的 1 × 1 卷积核,那么我们的输出将是 21。如果我们应用此操作 12 次,则输出将是 21 × 21 × 12。我们使用这些形状是因为它们可以减少数据的维度,因为应用更大大小的卷积核在计算上更为昂贵。
三维卷积
现在我们已经对二维卷积的工作原理有了一个很好的了解,是时候继续探讨三维卷积了。但等一下——我们不是已经学习了三维卷积吗?有点,但不完全是,因为如果你记得的话,三维卷积的深度与我们正在卷积的体积相同,并且其移动方式与二维卷积相同——沿着图像的高度和宽度移动。
三维卷积的工作方式稍有不同,它不仅在高度和宽度方向上进行卷积,还在深度方向上进行卷积。这意味着卷积核的深度小于我们希望卷积的体积的深度,在每一步,它都会进行逐元素的乘法和加法运算,最终得到一个标量值。
如果我们有一个大小为 21 × 21 × 15 的体积数据(如前一部分所述),并且有一个大小为 5 × 5 × 5 的三维卷积核,步幅为 1,那么输出将会是 16 × 16 × 11 的大小。
从视觉效果来看,结果如下:

我们可以像之前处理二维卷积那样,计算三维卷积的输出形状。
这种类型的卷积常用于需要我们在三维数据中寻找关系的任务。特别是在三维物体分割和视频中检测动作/运动的任务中使用较多。
可分离卷积
可分离卷积是一种非常有趣的卷积类型。它作用于二维输入,可以在空间或深度方向上应用。其原理是将我们的 k × k 大小的卷积核分解为两个较小的卷积核,分别为 k × 1 和 1 × k。我们不再直接应用 k × k 卷积核,而是先应用 k × 1 卷积核,再对其输出应用 1 × k 卷积核。这样做的原因是它减少了网络中的参数数量。使用原始卷积核时,我们每一步需要进行 k² 次乘法运算,但使用可分离卷积后,我们只需要进行 2,000 次乘法运算,减少了很多。
假设我们有一个 3 × 3 的卷积核,想要将其应用于 6 × 6 的输入,具体如下:

在前述的卷积中,我们的卷积核需要在 16 个位置上执行每个 9 次的乘法运算,然后才会输出结果。总共需要进行 144 次乘法运算。
让我们看看可分离卷积是如何不同的,并对比其结果。我们首先将卷积核分解为 k × 1 和 1 × k 两个卷积核:

我们将分两步将卷积核应用于输入。其效果如下:
- 步骤 1:

- 步骤 2:

这里, ![] 是第一次卷积操作的输出,![] 是第二次卷积操作的输出。然而,正如你所看到的,我们仍然得到了与之前相同大小的输出,但进行的乘法运算数量减少了。第一次卷积在每个 24 个位置上进行三次乘法运算,总共进行了 72 次乘法运算,第二次卷积也在每个 16 个位置上进行三次乘法运算,总共进行了 48 次乘法运算。通过将两次卷积的乘法总数相加,我们发现它们一共进行了 120 次乘法运算,少于 k × k 卷积核需要进行的 144 次乘法。
需要澄清的是,并不是每个卷积核都是可分的。举个例子,让我们看看 Sobel 滤波器及其分解:

我们刚刚学到了空间可分卷积。基于我们目前所学的,你觉得深度卷积会如何工作呢?
你应该记得,当我们讲解二维卷积时,我们引入了一个三维卷积核来处理彩色图像,其中深度与图像的通道数相同。因此,如果输入是 8 × 8 × 3,而卷积核的大小是 3 × 3 × 3,我们将得到一个大小为 6 × 6 × 1 的输出。然而,在深度可分卷积中,我们将 3 × 3 × 3 的卷积核拆分成三个 3 × 3 × 1 的卷积核,每个卷积核卷积其中一个通道。在将卷积核应用于输入后,我们得到的输出大小是 6 × 6 × 3,并且我们会在该输出上应用一个大小为 1 × 1 × 3 的卷积核,从而得到一个大小为 6 × 6 × 1 的输出。
如果我们想将输出的深度增加到,比如说 72,那么我们不会应用 72 个 3 × 3 × 3 的卷积核,而是应用 72 个 1 × 1 × 3 的卷积。
让我们比较一下两者,看看哪种计算方式更高效。使用 3 × 3 × 3 卷积核计算 6 × 6 × 72 的输出时,所需的乘法次数是 (3×3×3) × (6×6) × 72 = 69,984,非常多!而使用深度可分卷积来计算相同的输出时,所需的乘法次数是 (3×3×1) × 3 × (6×6) + (1×1×3) × (6×6) × 72 = 8,748,少得多,因此效率更高。
转置卷积
我们知道,对图像反复应用卷积会减少图像的尺寸,但如果我们想要逆向操作,也就是从输出的形状恢复到输入的形状,同时保持局部连接性,该怎么做呢?为此,我们使用转置卷积,它的名字来源于矩阵转置(你应该记得在第一章中讲解过的 向量微积分)。
假设我们有一个 4 × 4 的输入和一个 3 × 3 的卷积核。然后,我们可以将卷积核重写为一个 4 × 16 的矩阵,用于矩阵乘法来进行卷积操作。其形式如下:

如果你仔细看,会发现每一行代表一次卷积操作。
为了使用这个矩阵,我们将输入重写为一个 16 × 1 的列向量,如下所示:

然后,我们可以将卷积矩阵和列向量相乘,得到一个 4 × 1 的列向量,如下所示:

我们可以将其重写为以下形式:

这与我们在上一节中看到的相同。
你现在可能会想,这和转置卷积有什么关系呢?其实很简单——我们沿用之前的概念,不过这次我们使用卷积矩阵的转置来从输出反向推导回输入。
让我们取上面的卷积矩阵并转置它,使其变为一个 16 × 4 的矩阵:

这次,我们将要相乘的输入向量是一个 4 × 1 的列向量:

我们可以将它们相乘,得到一个 16 × 1 的输出向量,如下所示:

我们可以将输出向量重写为一个 4 × 4 的矩阵,如下所示:

就是这样,我们可以从低维空间转换到高维空间。
需要注意的是,应用于卷积操作的填充和步长也可以在转置卷积中使用。
然后,我们可以使用以下公式计算输出的大小:
。
这里,输入是 n × n,核是 k × k,p 是池化,s 是步长。
池化
卷积神经网络(CNN)中另一个常用的操作被称为 池化(子采样 或 降采样)。它的工作原理有点像卷积操作,不同的是它通过滑动窗口跨越特征图,并在每一步要么对窗口内的所有值取平均值,要么输出最大值,从而减小特征图的大小。池化操作与卷积的不同之处在于,它没有任何参数,因此不能学习或调优。我们可以计算池化后的特征图大小,如下所示:

这里,I 是一个 n × n 形状的二维张量,池化操作是一个 r × r 形状的二维张量,而 s 是步长。
这是一个步长为 1 的最大池化示例:

这是一个步长为 2 的平均池化示例:

一般经验法则发现,最大池化操作的表现更好。
从中,你可能会注意到输出与原始信息有很大不同,并且没有完全代表所有信息。事实上,很多信息已经丢失。正因为如此,池化操作在实际应用中越来越少使用。
全局平均池化
全局平均池化是池化操作的一种变体,在这种操作中,我们不再像之前那样在特征图上滑动子采样内核,而是直接取整个特征图的平均值,输出一个单一的实数值。假设我们有一个大小为 6×6×72 的特征图,在应用这种池化操作后,输出的大小将为 1×1×72。
这种方法通常在最后一层使用,在通常情况下,我们会应用子采样,并将输出送入全连接层;而这种方法允许我们跳过全连接层,直接将全局平均池化的输出送入 softmax 进行预测。
使用这种方法的优点是显著减少了我们需要在网络中训练的参数数量。如果我们将前述特征图展开,并将其输入到一个 500 节点的层中,那么它将有 129.6 万个参数。它还具有减少过拟合训练数据的额外好处,并且由于输出更接近类别,能够提高分类预测的效果。
卷积和池化大小
现在我们已经了解了各种类型的卷积和池化,是时候讨论一个与它们相关的非常重要的话题——它们的大小。如你所见,当我们对图像应用卷积时,输出的大小比输入小。输出大小由内核的大小、步长以及是否有填充决定。这些都是在构建卷积神经网络时非常重要的因素。
实际应用中有几种常用的卷积大小,最常用的是 7×7、5×5 和 3×3。但我们也可以使用其他大小,包括但不限于 11×11、13×13、9×9、17×17 等。
在实际应用中,我们通常使用更大的卷积和更大的步长生成较小大小的特征图,以减少计算约束,并默认使用 3×3 和 5×5 的内核。这是因为它们在计算上更为可行。一般来说,使用更大的内核可以让我们观察图像中的更大区域并捕捉更多关系,但使用多个 3×3 内核已经证明能够提供类似的性能,并且计算负担较轻,因此我们更倾向于使用它们。
使用 ConvNet 架构
现在我们已经了解了构成卷积神经网络的不同组件,接下来我们将把它们结合起来,看看如何构建一个深度 CNN。在本节中,我们将构建一个完整的架构,并观察前向传播如何工作,以及如何决定网络的深度、应用卷积核的数量、何时以及为什么使用池化等内容。但在我们深入探讨之前,先让我们探索一些 CNN 与 FNN 的区别。它们如下:
-
CNN 中的神经元具有局部连接性,这意味着每个神经元在后续层接收来自图像中一小块局部像素的输入,而不是像前馈神经网络(FNN)那样接收整个图像。
-
CNN 中每一层的神经元具有相同的权重参数。
-
CNN 中的各层可以进行归一化。
-
CNN 具有平移不变性,这使得我们能够检测图像中无论位置如何的相同物体。
-
CNN 的参数较少,因为卷积操作对周围的神经元加权,并将它们加总到下一层的神经元,从而平滑图像。
-
CNN 中常用的激活函数有 ReLU、PReLU 和 ELU。
CNN 架构与我们在本书早些时候看到的 FNN 架构并不完全不同,只是它不再使用全连接层,而是使用卷积层,从输入和前一层中提取空间关系,并在每一层学习输入特征。
通常,架构所学习的内容可以通过以下流程展示:

从之前的流程中可以看到,特征在后期层中逐渐变得复杂。这意味着最早的层(离输入层最近的层)学习的是非常基本的特征,比如边缘和线条、纹理,或者是某些颜色的区分。后续层将从前一层的特征图中获取输入,并从中学习更复杂的模式。例如,如果我们创建一个人脸识别模型,最早的层会学习最简单的线条、曲线和梯度。下一层会从前一层的特征图中获取输入,并利用它学习更复杂的特征,如头发和眉毛。接下来的一层会学习更复杂的特征,如眼睛、鼻子、耳朵等。
我们可以在以下图中看到神经网络学习的内容:

CNN 像 FNN 一样,具有一个我们可以作为构建自己应用程序时的指南的结构。它通常如下所示:

接下来,我们将分解一种最流行的 CNN 架构,叫做 AlexNet,它在 2012 年 ILSVRC 中以比其他模型高 10%的准确率获得了胜利,并启动了深度学习革命。它是由 Alex Krizhevsky、Ilya Sutskever 和 Geoffrey Hinton 创建的。我们可以在以下图中看到它的架构:

如你所见,该架构包含八个可训练层,其中五个是卷积层,三个是全连接层。ImageNet 数据集包含超过 1500 万张标注图像,但对于 ILSVRC,我们的训练集约有 120 万张图像,验证集有 5 万张图像,测试集有 15 万张图像,且每个类别(共 1000 个类别)有近 1000 张图像。每张图像都被重缩放至 256 × 256 × 3,因为图像大小不同,经过缩放后,作者生成了大小为 256 × 256 × 3 的随机裁剪图像。此外,AlexNet 的创建者使用了 ReLU 激活函数,而不是tanh,因为他们发现这样可以在不牺牲准确度的情况下,训练速度提高了六倍。
每一层对图像应用的操作及其大小如下:
-
卷积层 1:96 个大小为 11 × 11 × 3 的卷积核,步幅为 4。结果得到的层大小为 55 × 55 × 96。
-
非线性层 1:对卷积层 1 的输出应用 ReLU 激活。
-
下采样层 1:最大池化,大小为 3 × 3,步幅为 2。结果得到的层大小为 27 × 27 × 96。
-
卷积层 2:256 个大小为 5 × 5 的卷积核,填充为 2,步幅为 1。结果得到的层大小为 27 × 27 × 256。
-
非线性层 2:对卷积层 2 的输出应用 ReLU 激活。
-
下采样层 2:最大池化,大小为 3 × 3,步幅为 2。结果得到的层大小为 13 × 13 × 256。
-
卷积层 3:384 个大小为 3 × 3 的卷积核,填充为 1,步幅为 1。结果得到的层大小为 13 × 13 × 384。
-
非线性层 3:对卷积层 3 的输出应用 ReLU 激活。
-
卷积层 4:384 个大小为 3 × 3 的卷积核,填充为 1,步幅为 1。结果得到的层大小为 13 × 13 × 384。
-
非线性层 4:对卷积层 4 的输出应用 ReLU 激活。
-
卷积层 5:256 个大小为 3 × 3 的卷积核,填充为 1,步幅为 1。结果得到的层大小为 13 × 13 × 256。
-
非线性层 5:对卷积层 5 的输出应用 ReLU 激活。
-
下采样层 3:最大池化,大小为 3 × 3,步幅为 2。结果得到的层大小为 6 × 6 × 256。
-
全连接层 1:一个包含 4096 个神经元的全连接层。
-
非线性层 6:对全连接层 1 的输出应用 ReLU 激活。
-
全连接层 2:一个包含 4096 个神经元的全连接层。
-
非线性层 7:对全连接层 2 的输出应用 ReLU 激活。
-
全连接层 3:一个包含 1000 个神经元的全连接层。
-
非线性层 8:对全连接层 3 的输出应用 ReLU 激活。
-
输出层:Softmax 应用于 1,000 个神经元,用来计算其属于某个类别的概率。
在构建架构时,理解模型中的参数数量是非常重要的。我们用来计算每层参数数量的公式如下:

让我们计算一下 AlexNet 的参数。它们如下:
-
卷积层 1:11 x 11 x 3 x 96 = 34,848
-
卷积层 2:5 x 5 x 96 x 256 = 614,400
-
卷积层 3:3 x 3 x 256 x 384 = 884,736
-
卷积层 4:3 x 3 x 384 x 384 = 1,327,104
-
卷积层 5:3 x 3 x 384 x 256 = 884,736
-
全连接层 1:256 x 6 x 6 x 4096 = 37,748,736
-
全连接层 2:4096 x 4096 = 16,777,216
-
全连接层 3:4096 x 1000 = 4,096,000
现在,如果我们将参数加总起来,就会发现 AlexNet 共有 6230 万个参数。大约 6%的参数来自卷积层,剩余 94%来自全连接层。这应该能让你明白为什么 CNN 如此有效,以及我们为什么如此喜爱它们。
你可能会想,为什么我们要使用 CNN,而不直接使用 FNN 呢?难道不能将图像压平为一个全连接层,并将每个像素输入到一个节点吗?我们可以这样做,但如果这么做的话,我们的第一层将有 154,587 个神经元,整个网络的神经元数量可能会超过 100 万个,且可训练参数达到 5 亿。这是巨大的,我们的网络可能会因为没有足够的训练数据而欠拟合。此外,FNN 并没有 CNN 所具备的平移不变性。
使用前述参数,让我们看看是否能将架构进行概括,从而为将来要构建的 CNN 提供一个框架,或者帮助我们理解遇到的其他架构如何工作。你在前述架构中应该已经意识到,每个后续特征图的大小在减小,而其深度在增加。此外,你可能还注意到深度总是能被 2 整除,很多时候我们在各层中使用 32、64、128、256、512 等等。
就像我们之前在 FNN 中看到的那样,网络越深,准确率通常越高,但这并非没有问题。更大的网络训练起来要困难得多,可能会出现过拟合或欠拟合的情况。这可能是因为网络过小、过大、训练数据过多或过少造成的。目前还没有固定的方案来确定 CNN 中到底应该使用多少层;这更多依赖于反复试验和在为多种任务构建和训练多种架构后积累的直觉。
训练与优化
现在我们已经搞清楚了这些内容,是时候深入了解一些真正有趣的部分了。我们如何训练这些出色的架构?我们是否需要一个全新的算法来促进训练和优化?不!我们仍然可以使用反向传播和梯度下降来计算误差,对其在前一层的导数进行求解,然后更新权重,以便尽可能接近全局最优解。
但在继续之前,让我们回顾一下卷积神经网络中反向传播的工作原理,特别是卷积核的部分。让我们再看看本章早些时候使用的例子,我们用一个 3×3 的输入和一个 2×2 的卷积核进行卷积,效果如下:

我们将输出矩阵中的每个元素表示如下:

我们应该记得在第七章《前馈网络》中,我们介绍了反向传播,在那里我们对损失(误差)对权重和偏置的导数进行计算,并利用这些信息来更新参数,以减少网络预测误差。然而,在卷积神经网络中,我们找到的是误差对卷积核的梯度。由于我们的卷积核有四个元素,因此其导数如下所示:

如果我们仔细观察这些方程,它们表示的是前馈计算的输出,我们可以看到,通过对每个卷积核元素求偏导数,我们得到了它所依赖的相应输入元素,I[i,j]。如果我们将这个值代回到导数中,我们可以简化它们,得到以下结果:

我们可以通过将其重新写为卷积操作来进一步简化,这看起来如下:

那么如果我们想要找到输入的导数呢?嗯,我们的雅可比矩阵肯定会看起来有些不同。由于输入矩阵有九个元素,我们将得到一个 3×3 的矩阵:

我们可以通过手动推导前面的方程式来验证这一点,我鼓励你尝试这样做,以更好地理解发生了什么以及为什么会这样。然而,现在让我们特别注意我们使用的卷积核。如果我们仔细观察,它几乎看起来像行列式,但它并不是。我们只是将卷积核旋转(即转置)了 180°,这样我们就可以计算梯度。
这是卷积神经网络中反向传播工作原理的一个简化视图;我们之所以简化,是因为其余部分与前馈神经网络完全相同。
探索流行的卷积神经网络架构
现在我们已经知道了卷积神经网络是如何构建和训练的,是时候探索一些常用的架构,了解它们为什么如此强大。
VGG-16
VGG 网络是 AlexNet 的一种变种,由 Andrew Zisserman 和 Karen Simonyan 于 2015 年在牛津大学的视觉几何组(VGG)创建。该架构比我们之前看到的更简单,但它为我们提供了一个更好的工作框架。VGGNet 也在 ImageNet 数据集上进行了训练,不过它使用的是大小为 224 × 224 × 3 的图像,这些图像是从数据集中重新缩放后的图像中采样得到的。你可能已经注意到我们在本节中使用了VGG-16——这是因为 VGG 网络有 16 层。这个架构还有 11 层、13 层和 19 层的变体。
我们首先将探索网络的基本构建模块,即 VGG 块。这些模块由两到三个卷积层和一个池化层组成。网络中的每个卷积层都使用大小为 3 × 3 和步幅为 1 的卷积核;然而,每个模块中使用的卷积核数量是相同的,但可以在不同的模块之间有所不同。在子采样层中,我们使用大小为 2 × 2 的池化层,采用相同的填充大小和步幅为 2。
整个网络可以分解为以下操作:
-
卷积层 1:64 个大小为 3 × 3 的卷积核,步幅为 1,采用相同的填充。这会生成一个大小为 224 × 224 × 64 的层。
-
非线性激活 1:对卷积层 1 的输出应用 ReLU 激活函数。
-
卷积层 2:64 个大小为 3 × 3 的卷积核,步幅为 1,采用相同的填充。这会生成一个大小为 224 × 224 × 64 的层。
-
非线性激活 2:对卷积层 2 的输出应用 ReLU 激活函数。
-
子采样层 1:大小为 2 × 2、步幅为 2 的最大池化层。这会生成一个大小为 112 × 112 × 64 的层。
-
卷积层 3:128 个大小为 3 × 3 的卷积核,步幅为 1,采用相同的填充。这会生成一个大小为 112 × 112 × 128 的层。
-
非线性激活 3:对卷积层 3 的输出应用 ReLU 激活函数。
-
卷积层 4:128 个大小为 3 × 3 的卷积核,步幅为 1,采用相同的填充。这会生成一个大小为 112 × 112 × 128 的层。
-
非线性激活 4:对卷积层 4 的输出应用 ReLU 激活函数。
-
子采样层 2:大小为 2 × 2、步幅为 2 的最大池化层。这会生成一个大小为 56 × 56 × 128 的层。
-
卷积层 5:256 个大小为 3 × 3 的卷积核,步幅为 1,采用相同的填充。这会生成一个大小为 56 × 56 × 256 的层。
-
非线性激活 5:对卷积层 5 的输出应用 ReLU 激活函数。
-
卷积层 6:256 个大小为 3 × 3 的卷积核,步幅为 1,采用相同的填充。这会生成一个大小为 56 × 56 × 256 的层。
-
非线性激活 6:对卷积层 6 的输出应用 ReLU 激活函数。
-
卷积层 7:256 个 3 × 3 的卷积核,步长为 1,采用相同的填充。结果生成一个大小为 56 × 56 × 256 的层。
-
非线性 7:对卷积层 7 的输出应用 ReLU 激活函数。
-
子采样层 3:大小为 2 × 2、步长为 2 的最大池化。结果生成一个大小为 28 × 28 × 256 的层。
-
卷积层 8:512 个 3 × 3 的卷积核,步长为 1,采用相同的填充。结果生成一个大小为 28 × 28 × 512 的层。
-
非线性 8:对卷积层 8 的输出应用 ReLU 激活函数。
-
卷积层 9:512 个 3 × 3 的卷积核,步长为 1,采用相同的填充。结果生成一个大小为 28 × 28 × 512 的层。
-
非线性 9:对卷积层 9 的输出应用 ReLU 激活函数。
-
卷积层 10:512 个 3 × 3 的卷积核,步长为 1,采用相同的填充。结果生成一个大小为 28 × 28 × 512 的层。
-
非线性 10:对卷积层 10 的输出应用 ReLU 激活函数。
-
子采样层 4:大小为 2 × 2、步长为 2 的最大池化。结果生成一个大小为 14 × 14 × 512 的层。
-
卷积层 11:512 个 3 × 3 的卷积核,步长为 1,采用相同的填充。结果生成一个大小为 14 × 14 × 512 的层。
-
非线性 11:对卷积层 11 的输出应用 ReLU 激活函数。
-
卷积层 12:512 个 3 × 3 的卷积核,步长为 1,采用相同的填充。结果生成一个大小为 14 × 14 × 512 的层。
-
非线性 12:对卷积层 12 的输出应用 ReLU 激活函数。
-
卷积层 13:512 个 3 × 3 的卷积核,步长为 1,采用相同的填充。结果生成一个大小为 14 × 14 × 512 的层。
-
非线性 13:对卷积层 13 的输出应用 ReLU 激活函数。
-
子采样层 5:大小为 2 × 2、步长为 2 的最大池化。结果生成一个大小为 7 × 7 × 512 的层。
-
全连接层 1:一个包含 4,096 个神经元的全连接层。
-
非线性 14:对全连接层 1 的输出应用 ReLU 激活函数。
-
全连接层 2:一个包含 4,096 个神经元的全连接层。
-
非线性 15:对全连接层 2 的输出应用 ReLU 激活函数。
-
输出层:对 1,000 个神经元应用 Softmax,以计算其属于某一类别的概率。
该网络在 2014 年 ILSVRC 比赛中获得第二名,约有 1.38 亿个可训练参数。因此,它非常难以训练。
Inception-v1
InceptionNet 架构(通常被称为GoogLeNet)在 2014 年 ILSVRC 中获得了第一名,并达到了近人类水平的 93.3%准确率。Inception这个名称来源于电影盗梦空间,特别是指需要更深入(在层数方面)的含义。这个架构与我们之前看到的有些不同,它使用了 Inception 模块而非传统的层。每个 Inception 块包含三种不同大小的滤波器——1 × 1、3 × 3 和 5 × 5。这样做的目的是让网络能够通过空间信息和不同尺度的变化捕捉稀疏模式,从而使网络能够学习到更复杂的信息。然而,以前我们的网络在整个层中始终使用相同大小的卷积核。
Inception 模块如下所示:

如你所见,每个块包含四个并行的通道。第一个通道包含一个 1 × 1 的卷积核,第二个通道包含一个 1 × 1 卷积核,后接一个 3 × 3 卷积核,第三个通道包含一个 1 × 1 卷积核,后接一个 5 × 5 卷积核,第四个通道包含一个 3 × 3 的最大池化,后接一个 1 × 1 卷积核。得到的特征图会被拼接起来,作为输入传递到下一个块。应用 1 × 1 卷积核在较大卷积核(如 3 × 3 和 5 × 5 卷积核)之前的原因是为了减少维度,因为较大的卷积核计算开销较大。
这个网络输入的图像大小为 224 × 224,进行均值减法,并包含 22 层可训练参数(如果包括池化层则为 27 层)。
架构的详细信息如下表所示:

网络架构如下所示:

有趣的是,尽管这个网络比 AlexNet 和 VGG-16 要深得多,但我们需要训练的参数却要少得多,因为它使用了较小尺寸的卷积核,并且进行了深度减少。我们知道,较大的网络通常比较浅的网络表现更好。这个架构的意义在于,尽管它很深,但训练起来相对简单,比如果它有更多的参数的话。
总结
恭喜你!我们刚刚学习了一个强大的神经网络变种——卷积神经网络(CNNs),它在与计算机视觉和时间序列预测相关的任务中非常有效。我们将在本书的后续章节中再次讨论 CNN,但在此之前,让我们继续前进,学习递归神经网络和递归神经网络。
第十章:循环神经网络
本章我们将深入探讨循环神经网络(RNNs)。在上一章中,我们学习了卷积神经网络(CNNs),这种神经网络在计算机视觉任务中非常有效,因为它能够捕捉空间关系。然而,本章我们要研究的神经网络在处理顺序数据方面非常有效,广泛应用于算法交易、图像描述、情感分类、语言翻译、视频分类等领域。
在常规神经网络中,所有输入和输出被假设为独立的,但在 RNN 中,每个输出都依赖于前一个输出,这使得它们能够捕捉序列中的依赖关系,例如语言中,接下来的单词依赖于前一个单词及其之前的单词。
我们将首先了解基础 RNN,然后是双向 RNN、深度 RNN、长短期记忆网络(LSTM)和门控循环单元(GRU),以及一些目前工业界使用的最先进架构。
本章我们将涵盖以下主题:
-
RNN 的需求
-
在 RNN 中使用的数据类型
-
理解 RNN
-
长短期记忆网络
-
门控循环单元
-
深度 RNN
-
训练与优化
-
流行的架构
RNN 的需求
在上一章中,我们学习了 CNN 及其在图像和时间序列任务中的有效性,尤其是处理具有网格状结构的数据时。我们还看到 CNN 的灵感来源于人类视觉皮层如何处理视觉输入。类似地,本章我们要学习的 RNN 也是受到生物学启发的。
这种神经网络的需求源于模糊神经网络(FNNs)无法捕捉数据中的时间依赖性。
第一个 RNN 模型由约翰·霍普菲尔德(John Hopfield)于 1982 年创建,旨在理解我们大脑中联想记忆的工作原理。这个模型被称为霍普菲尔德网络。它是一个完全连接的单层循环网络,存储和访问信息的方式类似于我们大脑的处理方式。
在 RNN 中使用的数据类型
如本章介绍所述,RNN 被广泛应用于自然语言处理、机器翻译和算法交易等任务,并取得了显著成果。对于这些任务,我们需要顺序或时间序列数据——即数据有固定的顺序。例如,语言和音乐都有固定的顺序。当我们说或写句子时,它们遵循一定的结构,这使得我们能够理解它们。如果我们打破规则,混淆那些没有关联的单词,那么句子就不再有意义。
假设我们有一句话The greatest glory in living lies not in never falling, but in rising every time we fall,并将其通过句子随机化处理。我们得到的输出是fall. falling, in every in not time but in greatest lies The we living glory rising never,这显然没有意义。另一个例子是按日期和开盘收盘价格或每天固定时间间隔(可能是每小时)的股价进行排序。
其他顺序数据的例子包括连续几天的降水量测量、DNA 链中的核苷酸碱基对,或者股票的每日波动值。
我们将以类似于一维卷积的方式组织这类数据。不过,不同的是,RNN(我们很快就会熟悉的)会接收相同的输入,其中每个节点对应数据的时间步长(稍后会更清楚)。
理解 RNN
这个神经网络名称中的递归(recurrent)一词来源于其具有循环连接的特点,并且对序列中的每个元素执行相同的计算。这使得它能够学习(或记住)数据的部分信息,从而对未来进行预测。RNN 的优势在于,它可以处理比非序列模型更长的序列。
标准 RNN
不再赘述,让我们先来看一下最基本的 RNN 版本,称为标准 RNN。其结构如下:

看起来有点熟悉,是吧?应该是。如果我们去掉循环,这将与传统神经网络相同,但只有一个隐藏层,而我们已经见过这种情况。现在,如果我们展开循环并查看完整的网络,它的结构如下:

在这里,我们有以下参数:
-
x[t]是时间步长t的输入
-
h[t]是时间步长t的隐藏状态
-
o[t]是时间步长t的输出
从前面的图示中可以看出,在每个时间步上对输入执行相同的计算,这也是它与我们之前遇到的 FNN(前馈神经网络)的区别。FNN 每一层的参数(权重和偏置)是不同的,但在这种架构中,参数(U、V和W)在每个时间步保持不变。因此,RNN 相比 CNN 来说,内存占用更大,并且需要更长的训练时间。值得注意的是,在 RNN 中,时间步并不一定与现实世界中的时间对应;它只是意味着输入序列的长度是t。
那么,为什么这些权重在所有时间步长中保持相同呢?为什么不能在不同的时间步长中使用需要学习的单独参数?原因在于,单独的参数无法对训练过程中未遇到的序列长度进行泛化。在整个序列中共享相同的三个权重,并且在不同的时间步长中使用这些权重,使得网络能够处理可能出现在多个位置的信息,这在语言中是常见的。例如,the 可以出现在给定句子的多个位置,RNN 应该能够识别并提取它,而不论它处于哪个位置。这种共享的统计强度特性相较于 FNN 是有优势的,因为 FNN 需要在每个位置学习语言规则,正如你能想象的那样,这对于训练来说是非常具有挑战性的。
直观地,我们可以将其看作是有一个序列 ![],我们试图找到 ![],这是我们在第三章 概率与统计 中已经熟悉的内容。这并不完全是发生的情况;我们将其简化,以帮助你理解 RNN 试图学习做什么。
利用我们现在获得的知识,我们可以为各种任务创建非常复杂的 RNN,例如语言翻译或将音频转换为文本。根据我们想要为之构建模型的任务类型,我们可以从以下几种类型的 RNN 中选择:
-
一对一(一个输入和一个输出)
-
一对多(一个输入和多个输出)
-
多对一(多个输入和一个输出)
-
多对多(多个输入和多个输出,输入和输出的数量相等)
-
多对多(多个输入和多个输出,输入和输出的数量不相等)
让我们更深入地探讨 RNN,看看在每个时间步长从输入到输出经过所有隐藏层时发生了什么。
从数学上讲,我们可以使用以下方程式计算每个时间步长的隐藏状态:

这里, f[1] 是一个非线性函数,例如 ReLU、tanh 或 sigmoid。输出计算如下:
。
我们可以使用非线性函数 f[2](例如 softmax)计算输出的概率向量,如下所示:

通过使用这些方程并重复应用它们,我们可以计算每个时间步长的隐藏状态和输出。
所以,RNN 看起来如下:

通过观察前面的图示和方程式,你应该能够大致猜测出我们的权重矩阵和偏置向量的形状——,,,,以及。
从前面的方程式中,我们可以清楚地看出,时间步* t 的隐藏状态依赖于当前的输入和先前的隐藏状态。然而,初始隐藏状态h[0]必须以类似初始化 FNN 和 CNN 中的权重和卷积核的方式进行初始化。另一方面,每个时间步的输出则依赖于当前的隐藏状态。此外,a和b*是偏置,它们是可训练的参数。
在 RNN 中,h[t]包含了之前所有时间步发生的事情的信息(但实际上,我们通常只限制在少数几个时间步,而不是所有之前的时间步,这是因为梯度消失/爆炸的问题),而o[t]则是基于最新的信息计算出来的。这使得 RNN 能够利用序列之间的关系,并用它来预测最可能的输出,这与 CNN 如何通过一维卷积捕捉序列数据中的空间关系并不完全不同。
然而,这并不是构建 RNN 的唯一方式。我们可以改变计算隐藏状态的方式,而不是像前面的图示那样将输出从一个隐藏层传递到另一个隐藏层(![]),我们可以将上一个输出的结果传递到下一个隐藏状态(![]),这样就改变了计算隐藏状态的方式。新的计算公式变为如下:

在下图中,我们可以看到在时间步* t *的隐藏状态单元中发生的各种操作:

当我们使用 FNN 时,我们会在每次通过网络的前向传递后计算损失,并进行误差反向传播以更新权重。然而,在 RNN 中,我们会在每个时间步计算损失,如下所示:

这里,L是交叉熵损失函数(我们已经熟悉它了),y[t]是目标,![]是一个概率向量,n是输出/目标的数量。
尽管有效,这些普通的 RNN 并不完美。它们确实存在一些我们在训练过程中通常会遇到的问题,特别是消失梯度问题。消失梯度问题发生在权重变得非常小,导致神经元无法激活,从而阻止了后续时间步的隐藏神经元激活,因为每个神经元依赖于上一个神经元,依此类推。
为了更好地理解这一点,我们来考虑以下例子。假设我们有一个非常简单的普通 RNN,没有任何非线性激活函数或输入。我们可以将这个网络表示为![]。正如你所看到的,我们在每个单元上每个时间步都会重复应用相同的权重。然而,让我们把注意力集中在权重上。
为了理解消失和爆炸梯度问题,假设我们的权重矩阵的形状为 2 × 2,并且是可对角化的。你应该还记得在第二章《线性代数》中提到,如果矩阵是可对角化的,那么它可以分解成形如![]的形式,其中Q是包含特征向量的矩阵,Λ是包含特征值的方阵,特征值位于对角线上。如前所述,如果我们有八个隐藏层,那么我们的权重矩阵会是![]。我们可以如下理解:

在上面的方程中,我们可以清楚地看到消失梯度和爆炸梯度问题。我们假设有八个隐藏单元,通过不断相乘,我们可以看到值变得非常小或非常大,这使得训练 RNN 变得相当困难,因为它们不稳定。小的权重使得 RNN 很难学习长期依赖关系,这也是长短期记忆网络(LSTM)和门控循环单元(GRU)等单元创新的原因(稍后我们将学习这两种 RNN 单元变体)。
现在,如果我们的 RNN 有 20 个时间步或更多,并且我们希望网络记住第一个、第二个或第三个输入,那么它很可能无法记住这些输入,但它会记住最近的输入。例如,我们可能有一句话我记得几年前去那不勒斯旅行的时候...我吃到了人生中最好吃的披萨。在这种情况下,我们需要理解那不勒斯的背景,以便知道这块美味的披萨是来自哪里,但 RNN 很难回溯到这么远的历史。
类似地,如果我们的权重大于 1,它可能会变得非常大,导致梯度爆炸。然而,我们可以通过使用梯度裁剪来解决这个问题,梯度裁剪是通过重新缩放权重,使其范数最多为η。我们使用以下公式来实现:

双向 RNN(Bidirectional RNNs)
现在我们已经了解了基本的 RNN 工作原理,让我们来看一下它的一个变种——双向 RNN。前面的 RNN 是前馈型的;也就是说,数据从左边 (
) 到右边 (
) 传递,这会产生对过去的依赖。然而,对于一些我们可能希望处理的问题,展望未来也是有帮助的。
这使我们能够分别将训练数据正向和反向地输入到两个独立的递归层中。需要注意的是,这两个层共享相同的输出层。这种方法允许我们将输入数据与过去和未来的上下文相结合,从而在涉及语音和翻译的任务中产生比之前的单向 RNN 更好的结果。然而,双向 RNN 并不是每个时间序列任务的解决方案,例如股票价格预测,因为我们无法知道未来会发生什么。
在下面的图示中,我们可以看到一个双向 RNN 的结构:

如你所见,网络现在包含两个平行的层,分别朝相反的方向运行,并且在每个时间步上应用六组不同的权重;即,输入到隐藏层的权重 (U 和 C),隐藏到隐藏层的权重 (A 和 W),以及隐藏到输出层的权重 (V 和 B)。需要注意的是,前向层和后向层之间没有共享信息。
现在,每个隐藏状态在时间点
处的操作如下:
-
![]
-
![]()
在这里,f[1] 是一个非线性函数,a 和 b 是偏置项。输出单元可以按以下公式计算:

这里,d 是偏置项。然后,我们可以通过以下公式找到概率向量:

上面的公式告诉我们,前向层的隐藏状态从先前的隐藏状态获取信息,而后向层的隐藏状态则从未来的状态中获取信息。
长短期记忆
正如我们之前所见,标准的 RNN 确实存在一些局限性;尤其是它们受到梯度消失问题的影响。LSTM 架构由 Jürgen Schmidhuber 提出(ftp://ftp.idsia.ch/pub/juergen/lstm.pdf),作为解决 RNN 所面临的长期依赖问题的一种方案。
LSTM 单元与传统的 RNN 单元在几个方面有所不同。首先,它们包含我们所谓的记忆块,实际上是一个递归连接的子网络集合。其次,每个记忆块不仅包含自连接的记忆单元,还包含三个乘法单元,分别代表输入门、输出门和遗忘门。
让我们看看一个 LSTM 单元的样子,然后我们将深入研究它,帮助更好地理解。在以下图示中,你可以看到 LSTM 块的外观以及其中发生的操作:

如你所见,在前面的 LSTM 单元中,每个时间步都会发生一系列操作,并且它包含以下组件:
-
f:遗忘门(一个带有 sigmoid 的神经网络)
-
![]: 候选层(一个带有 tanh 的神经网络)
-
I:输入门(一个带有 sigmoid 的神经网络)
-
O:输出门(一个带有 sigmoid 的神经网络)
-
H:隐藏状态(一个向量)
-
C:记忆状态(一个向量)
-
W 和 U:遗忘门、候选层、输入门和输出门的权重
在每个时间步,记忆单元接收当前输入(X[t])、前一个隐藏状态(H[t-1])和前一个记忆状态(C[t-1])作为输入,并输出当前的隐藏状态(H[t])和当前的记忆状态(C[t])。
如你在前面的图示中所见,这里发生的操作比传统 RNN 的隐藏单元中要多得多。这意味着它能够在整个网络中保持梯度,允许更长时间的依赖关系,并提供了解决梯度消失问题的方法。
那么,LSTM 到底是如何做到这一点的呢?让我们来看看。记忆状态存储信息,并一直这样做,直到新信息覆盖旧信息。每个单元都可以决定是否要输出这些信息或存储它。在深入解释之前,我们首先来看一下每个 LSTM 单元中发生的数学操作。它们如下:
-
![]
-
![]
-
![]
-
![]
-
![]
-
![]
现在我们已经了解了每个单元中发生的不同操作,让我们真正理解一下前面方程的含义。它们如下:
-
候选层(![])的输入是一个单词(X[t])和来自前一个隐藏状态的输出 H[t-1],并生成一个新的记忆,其中包括新的单词。
-
输入门 (I) 执行一个非常重要的功能。它根据前一个隐藏状态的输出,决定当前的新输入词是否值得保留。
-
忘记门 (f),尽管它看起来与输入门非常相似,但执行的是不同的功能。它决定在计算当前记忆时,前一个记忆单元的相关性(或有用性)。
-
记忆状态(有时称为最终记忆)是在接收忘记门和输入门作为输入后生成的,然后它将新记忆进行门控并将输出加和,最终生成 C[t]。
-
输出门将记忆与隐藏状态区分开,并决定在隐藏状态中应该保留多少记忆中的信息。这个过程产生 O[t],我们接着用它来门控 tanh (C[t])。
门控循环单元
与 LSTM 类似,GRU 也是对传统 RNN 中隐藏单元的改进。GRU 的设计也是为了应对梯度消失问题,通过存储过去的记忆来帮助做出更好的未来决策。GRU 的动机源于对 LSTM 中所有组成部分是否都必要的质疑,尤其是控制遗忘性和单位时间尺度的部分。
这里的主要区别在于,这种架构使用一个门控单元来决定忘记什么以及何时更新状态,这使得它拥有更持久的记忆。
在下图中,你可以看到 GRU 架构的样子:

正如你在前面的图示中看到的,它接收当前输入 (X[t]) 和前一个隐藏状态 (H[t-1]),并且与前面的 LSTM 相比,这里进行的操作要少得多。它包含以下几个组成部分:
-
Z[t]:更新门
-
R[t]:重置门
-
![]:新的记忆
-
H[t]:隐藏状态
为了生成当前隐藏状态,GRU 使用以下操作:
-
![]
-
![]
-
![]
-
![]
现在,让我们解析之前的方程式,更好地了解 GRU 是如何处理其两个输入的。它们如下:
-
GRU 接收当前输入 (X[t]) 和前一个隐藏状态 (H[t-1]),并根据它所拥有的关于前一个单词的信息来上下文化当前词语,从而生成 ![]——新的记忆。
-
重置门 (R[t]) 决定在计算当前隐藏状态时,前一个隐藏状态的重要性;也就是说,它决定前一个隐藏状态是否与获得新记忆相关,这有助于捕捉短期依赖关系。
-
更新门 (Z[t]) 决定了应将多少先前的隐藏状态传递给下一个状态,以捕捉长期依赖关系。简而言之,如果 Z[t]≈1,则大部分先前的隐藏状态会被纳入当前的隐藏状态;但如果 Z[t]≈0,则大部分新记忆会被传递向前。
-
最终,当前的隐藏状态 (H[t]) 是通过新记忆和之前的隐藏状态计算得到的,取决于更新门的结果。
深度 RNN
在前几章中,我们看到将深度添加到神经网络中有助于取得更好的结果;对于 RNN 来说也是如此,增加更多的层可以帮助我们学习更复杂的信息。
现在我们已经了解了 RNN 的基本概念,并且理解了它们是如何工作的,让我们深入探讨一下深度 RNN 长什么样子,并且从中获得的好处。深入研究 RNN 并不像处理 FNN 和 CNN 时那么简单;我们在这里需要考虑一些不同的因素,特别是关于我们应该如何以及在哪里在层之间添加非线性。
如果我们想更深一些,我们可以将更多的隐藏递归层堆叠在一起,这样我们的架构就可以在多个时间尺度上捕捉并学习复杂信息,并且在信息从一层传递到另一层之前,我们可以加入非线性或门控机制。
让我们从一个两层隐藏层的双向 RNN 开始,如下图所示:

如你所见,它看起来像是三个多层感知机(MLP)并排堆叠在一起,隐藏层依然是互相连接的,形成一个网格。同时,同一层的前向和反向隐藏单元之间没有连接。每个隐藏节点在相同时间步长下同时输入直接位于其上方的节点,并且每个隐藏节点从上一层相关的隐藏节点获取两个参数作为输入——一个来自前向层,另一个来自反向层。
我们可以概括并写出深度双向 RNN 的方程,如下所示:
- 在前向层中,我们有以下内容:

- 在反向层中,我们有以下内容:

- 在输出层中,我们有以下内容:

以此为指导,我们可以对 LSTM 或 GRU 进行相同的操作并将其添加进去。
训练与优化
正如我们在之前的神经网络中遇到的,RNN 也通过反向传播来更新其参数,通过计算误差(损失)相对于权重的梯度。然而,在这里,它被称为时间反向传播(BPTT),因为 RNN 中的每个节点都有一个时间步长。我知道这个名字听起来很酷,但它与时间旅行无关——它仍然是经典的反向传播,使用梯度下降进行参数更新。
在这里,使用 BPTT,我们想要找出隐藏单元和输出对总误差的影响,以及更改权重(U, V, W)对输出的影响。W,如我们所知,在整个网络中是常量,因此我们需要一直回溯到初始时间步长进行更新。
在 RNN 中进行反向传播时,我们再次应用链式法则。训练 RNN 之所以棘手,是因为损失函数不仅依赖于输出层的激活,还依赖于当前隐藏层的激活及其对下一个时间步长中隐藏层的影响。在下列方程中,我们可以看到 RNN 中反向传播的工作原理。
如你所见,我们首先找到交叉熵损失(在Vanilla RNNs部分定义);我们的总误差如下:

我们可以使用链式法则展开前述方程,相对于损失和隐藏层,如下所示:

让我们聚焦于右侧第三项并对其展开:

你应该注意到这里的每个偏导数都是一个雅可比矩阵。
我们现在可以将前述方程结合起来,全面了解如何计算误差,结果如下所示:

我们知道在本章前面的部分,h[t]是使用以下公式计算的:

所以,我们可以计算h[t]的梯度,如下所示:

由于隐藏神经元也将x[t]作为输入,我们还需要对U进行求导。我们可以按如下方式操作:

等等——正如我们所看到的,隐藏单元接收两个输入。那么,接下来让我们使用刚才所学的内容回传一步,看看它是如何工作的:

使用这个,我们现在可以对所有先前的梯度进行求和,直到当前为止,如下所示:

LSTM 或 GRU 中的反向传递与我们在普通 RNN 中所做的非常相似,但由于门控机制的存在,情况变得更加复杂(这里我们不会深入讨论 LSTM 或 GRU 中的反向传递差异)。
流行架构
现在我们已经了解了所有用于对比 RNN 的组件,让我们来探索一种由该领域研究人员开发的流行架构——时钟工作 RNN(CW-RNN)。
时钟工作 RNN
正如我们所了解的那样,在 RNN 中发现长期依赖关系是非常具有挑战性的,LSTM 和 GRU 被设计用来克服这个限制。CW-RNN 由 IDSIA 团队在 Jürgen Schmidhuber 的带领下开发,它修改了传统的 RNN 模块,使隐藏层被分割成多个独立的模块,每个模块以不同的时间粒度处理其输入。这意味着隐藏层以预设的时钟速率执行计算(这也是该名称的来源)。其效果是,相比于传统的 RNN 和 LSTM,训练参数数量减少并且精度更高。
就像我们之前的 RNN 具有输入到隐藏和隐藏到输出的连接一样,CW-RNN 也有这些连接,只不过隐藏层的神经元被分割成* g 个大小为k*的模块,每个模块都有一个指定的时钟周期,![]。
这些模块是完全连接在一起的,但模块j到i的递归连接在周期![]的情况下是不成立的。这些模块按周期递增排序,因此连接是从较慢的到较快的(从右到左)。
在下面的图中,我们可以看到 CW-RNN 的架构:

模块i的时钟周期可以通过以下公式计算:

输入和隐藏权重矩阵被分割成* g *个块行,如下所示:
和 
在前面的方程中,* W 是一个上三角矩阵,每个 W[i] *值被分割成块列:

在前向传播过程中,只有隐藏权重矩阵和输入权重矩阵的块行对应于已执行的模块,其中以下条件成立:

时钟速率较低的模块从输入中学习并保持长期信息,而时钟速率较高的模块则学习局部信息。
在前面的方程中,我们提到每个隐藏层被分割成* g 个大小为k的模块,这意味着总共有n = kg*个神经元。由于神经元仅与具有相似或更长周期的神经元相连,因此隐藏层到隐藏层矩阵中的参数数量如下所示:

让我们将其与我们的传统 RNN 进行比较,后者有n²个参数。让我们看看这是如何实现的:

CW-RNN 的参数数量大约是普通 RNN 的一半。
总结
本章,我们介绍了一种非常强大的神经网络——RNN。我们还学习了几种 RNN 单元的变体,如 LSTM 单元和 GRU。像前几章中的神经网络一样,这些也可以扩展到深度神经网络,这具有许多优势。特别是,它们可以学习关于序列数据的更复杂的信息,例如在语言处理中的应用。
在下一章,我们将学习注意力机制及其在语言和视觉相关任务中日益增长的应用。
第三部分:简化的高级深度学习概念
在上一节中已经建立了深度学习基础思想的坚实理解后,本节将介绍各种深度学习网络;即,用于处理图像、文本和序列的网络,以及用于生成项目的网络。
本节包括以下章节:
-
第十一章,注意力机制
-
第十二章,生成模型
-
第十三章,迁移学习与元学习
-
第十四章,几何深度学习
第十一章:注意力机制
在前两章中,我们学习了卷积神经网络(CNN)和循环神经网络(RNN),这两者在机器翻译、图像描述、物体识别等顺序任务中非常有效。但我们也看到它们有一些局限性。RNN 存在长时间依赖性的问题。在本章中,我们将介绍注意力机制,它在语言和视觉相关任务中越来越受欢迎,并且取得了惊人的成果。
本章将涵盖以下主题:
-
注意力机制概述
-
理解神经图灵机
-
探索注意力的类型
-
Transformer
让我们开始吧!
注意力机制概述
当我们在现实世界中生活时,大脑并不会时刻观察到我们周围环境的每个细节;相反,我们会专注于(或者说更关注)与当前任务相关的信息。例如,当我们开车时,我们能够调整焦距,专注于不同的细节,有些更近一些,有些则远一些,然后根据我们观察到的情况做出反应。类似地,当我们与他人交谈时,我们通常并不会仔细听每一个字;我们只听其中一部分内容,并根据听到的内容推断出与其他词语的关系,从而理解对方的意思。通常,在我们阅读或听别人说话时,我们可以根据已读或已听的内容推测出对方接下来要说什么。
那么,为什么深度学习需要这些注意力机制呢?让我们回顾一下第十章,循环神经网络,在那一章中我们学习了序列到序列的模型(RNN),正如我们所看到的,这些模型可以用于语言翻译等任务。我们应该回想起,这些模型采用了编码器-解码器架构,其中编码器将输入压缩到嵌入空间(或上下文向量),而解码器则将上下文向量转化为所需的输出。编码器和解码器都是 RNN(可能配合 LSTM 或 GRU 来处理长期记忆)。
在上一章中,我们还遇到了一些 RNN 的局限性——特别是梯度消失或爆炸的问题,这妨碍了长时间依赖的处理。因此,注意力机制应运而生。它的创建就是为了解决 RNN 在记忆长句子时遇到的这个问题。
在 RNN 中,每个时间步的隐藏状态以前一个隐藏状态(包含迄今为止看到的序列的上下文信息)和该时间步的输入作为输入,最终的隐藏状态会传递给解码器序列。注意力机制通过在上下文向量和整个输入序列之间建立连接来进行区分。这样,我们不再需要担心有多少信息最终会被遗忘。与 ANN 中的所有其他连接类似,这些注意力连接是有权重的,这意味着它们可以根据每个输出进行调整。本质上,上下文向量控制输入与目标(输出)之间的对齐。
假设我们有一个输入,![],和一个目标,![],其中由编码器(为了简单起见为一个普通的 RNN,尽管它可以是任何 RNN 架构)生成的隐藏状态为![]。解码器的隐藏状态与我们之前看到的略有不同:

对于所有 ![],这里,c[t](上下文向量)是所有输入的隐藏状态的总和。这个总和根据对齐得分进行加权,以便 ![] 和 ![] 确定 y[t] 和 x[i] 的对齐,通过根据两者的匹配程度分配得分。每个 α[t,i] 都是一个权重,决定了每个源的隐藏状态对每个输出的影响程度。
前述的得分函数由一个具有单层隐藏层的 MLP 进行参数化,并通过以下方程计算:

这里,V[a] 和 W[a] 是需要学习的权重矩阵。
在深入探讨各种注意力机制的内部工作原理之前,先来了解一下神经图灵机。
理解神经图灵机
图灵机(TM)由艾伦·图灵在 1936 年提出,它是由一条无限长的带子和一个通过读取、编辑和移动带子上的符号与带子互动的头部组成的计算模型。它通过按照预定的规则操作带子上的符号来工作。带子由无限多个单元组成,每个单元可以包含三种符号之一——0、1 或空白(" ")。因此,这被称为三符号图灵机。尽管它看起来很简单,但它能够模拟任何计算机算法,无论其复杂性如何。执行这些计算的带子可以被视为机器的内存,类似于我们现代计算机的内存。然而,图灵机与现代计算机的不同之处在于它具有有限的内存和计算能力。
在 第十章,递归神经网络 中,我们学习到这种类型的 ANN 是图灵完备的,这意味着当它们经过适当训练时,可以模拟任何任意的过程。但这仅仅是理论上的。在实践中,我们看到情况并非如此,因为它们确实有其局限性。为了克服这些局限性,2014 年,Alex Graves 等人提出将 RNN 与一个大型、可寻址的内存(类似于图灵机中的磁带)结合,从而赋予其“神经图灵机”(NTM)这一名称。正如作者所言,它是一个可微分的计算机,可以通过梯度下降进行训练,提供一个学习程序的实用机制。
NTM 借鉴了工作记忆(人类认知中的一个过程)的概念,工作记忆与短期记忆相同,并将其应用于 RNN,从而赋予其通过注意力控制器选择性地读取和写入内存的能力。我们可以在以下图示中看到 NTM 的样子:

在前面的图示中,我们可以看到 NTM 有两个主要组成部分——控制器,它是一个神经网络,以及内存,它包含处理过的信息。控制器通过接收输入向量并输出输出向量与外部世界进行交互,但它与前几章的 ANNs 不同,因为它还通过选择性读取和写入操作与内存矩阵进行交互。
读取
假设我们的内存是一个 N×M 矩阵,记作 ![],其中 t 是时间步长,N 是行数(内存位置),M 是每个位置的向量大小。然后,我们有另一个权重向量,w[t],它决定了要分配给内存中不同位置(即矩阵的行)的注意力。权重向量中的每个 N 个权重都经过标准化,这意味着 ![],对于所有 i,我们有 ![],其中 ![] 是 w[t] 的 i^(th) 元素。
由头部返回的读取向量,r[t],可以按如下方式计算:

这里,![] 是 i^(th) 内存向量。从前面的方程式中,我们还可以看到 r[t] 可以相对于权重和内存进行求导。
写入
写入操作的灵感来源于 LSTM 的输入和遗忘门,其中一些信息会被擦除,然后被替换(或添加)。
然后,内存通过两个公式进行更新,第一个公式擦除内存,第二个公式添加内存:
-
![]
-
![]
这里, ![] 是擦除向量,a[t] 是加向量,1 是一个只包含 1 的向量。从这些公式中,我们可以看出,特定位置的记忆只有在权重和擦除向量都等于 1 时才会被擦除,否则保持不变。由于擦除和加操作都是可微的,因此整个写操作也是可微的。
定址机制
现在我们知道了读写操作是如何进行的,让我们深入了解权重是如何生成的。权重是两个机制的结合输出——内容基定址机制和基于位置的定址机制。
基于内容的定址机制
这个定址机制聚焦于控制器根据接收到的输入输出的键值k[t]与记忆行之间的相似性。基于这种相似性,它生成一个注意力向量。其计算公式如下:

这里, ![] 是一个归一化的权重,β[t] 是一个强度乘数。
基于位置的定址机制
在学习位置基定址如何工作的之前,我们需要定义我们的插值门,它将当前时间步的内容基注意力与前一时间步的注意力向量中的权重进行混合。这可以通过以下公式完成:

这里, ![] 是标量插值门。
基于位置的定址机制通过对注意力向量中的值进行求和来工作,每个值都由一个移动权重s[t]加权,该权重是允许的整数移动分布。例如,如果它可以在-1 和+1 之间移动,那么可以执行的移动为-1、0 和+1。现在,我们可以将这种旋转公式化,使得移动权重作用于![] 作为一个循环卷积。我们可以在以下公式中观察到这一点:

为了防止由于权重变化而引起的泄漏或模糊,我们使用以下公式来锐化注意力向量,w[t]:

这里, ![] 是一个正的标量值。
最后,控制器输出的值对于每个读写头来说是唯一的。
探索注意力机制的类型
注意力在机器翻译中已被证明是非常有效的,甚至扩展到自然语言处理、统计学习、语音理解、目标检测与识别、图像描述以及视觉问答等领域。
注意力的目的是估算两个或多个元素之间的相关性(联系)。
然而,注意力不仅仅只有一种类型。实际上,有很多种类型,例如以下几种:
-
自注意力:捕捉输入序列中不同位置之间的关系
-
全局或软注意力:关注输入序列的整个部分
-
局部或硬注意力:只关注输入序列的某一部分
让我们更详细地看一下这些内容。
自注意力
自注意力在输入序列的不同位置之间寻找关系,并计算该输入序列的表示。你可以将其视为对输入的总结。这有点类似于我们在上一章看到的 LSTM,它尝试学习前一个输入与当前输入之间的相关性,并决定哪些是相关的,哪些是不相关的。
比较硬注意力和软注意力
这些类型的注意力最初是为生成图像的描述性文字而创建的。首先使用 CNN 提取特征,然后将其压缩成编码。为了对编码进行解码,使用 LSTM 生成描述图像的词语。但现在我们不需要关注这些内容——区分软注意力和硬注意力才是重点。
在软注意力中,训练过程中学到的对齐权重被柔和地放置在图像的各个区域上,使得它更关注图像的某些部分。
另一方面,在硬注意力中,我们每次只专注于图像的某一部分。它只做出一个二元决策,决定关注哪里,而且与软注意力相比,训练起来要难得多。这是因为它是不可微分的,需要通过强化学习来训练。由于强化学习超出了本书的范围,我们将不讨论硬注意力。
比较全局注意力和局部注意力
全局注意力与软注意力的工作原理有些相似,都是考虑了所有输入。
局部注意力与全局注意力不同,它可以看作是硬注意力和软注意力的混合,只考虑输入的一个子集。它首先预测当前输出的一个对齐位置。然后,围绕当前输入的窗口用于创建上下文向量。
Transformer 模型
对于那些在看到标题时感到兴奋的朋友(Transformer),很遗憾,本节与擎天柱或大黄蜂无关。说正经的,我们已经看到,注意力机制在 RNN 和 CNN 等架构中表现良好,但它们足够强大,可以单独使用,正如 Vaswani 在 2017 年发表的论文《Attention Is All You Need》中所证明的那样。
Transformer 模型完全由自注意力机制构成,能够执行序列到序列的任务,而不需要任何形式的循环单元。等等,怎么做到的呢?让我们拆解一下架构,看看这是怎么可能的。
RNN 接收编码后的输入,然后解码以映射到目标输出。然而,变换器在这里有所不同,它将编码处理为一组键值对(K,V),其维度(=n)等于输入序列的长度。解码器被视为查询(Q),其维度(=m)等于输出序列的长度。每个输出是通过将键值对映射到查询来生成的。
这里的注意力通过一个缩放点积计算,它使用以下公式计算值的加权和:

现在,我们不再只计算一次注意力,而是并行计算多次。这被称为多头注意力。在下图中,我们可以看到缩放点积注意力和多头注意力计算的可视化:

每次注意力计算的输出会被拼接在一起,然后我们对它们应用线性变换,以确保它们的维度与预期匹配。这样做的原因是,单一注意力无法同时集中在不同子空间中的信息,而多头注意力能够做到这一点。这是如何工作的:

在这里,每个头的计算如下:

这里,![]、![]、![]和![]是可训练的参数。
现在让我们将注意力转向编码器和解码器。
编码器由六个相同的层堆叠而成,每层由两个子层组成。第一个子层是一个多头自注意力层,而第二个是一个前馈神经网络(FNN),它对整个序列中的每个元素应用相同的权重。这类似于卷积操作,在每个位置应用相同的卷积核。FNN 可以表示为:

每个都有一个残差连接到层归一化。这么做的目的是从整体中识别出文本/图像中的特定信息,也就是说,识别出我们需要更加关注的最重要部分。该编码器的计算如下:

编码器架构如下所示:

前面的层归一化将输入转换,使其均值为零,方差为一。它使用以下公式来实现:
-
![]
-
![]
这里,![]。
解码器(其架构如以下图所示)也由六个相同的层堆叠而成;然而,这些层中的每一层都由三个子层组成。前两个子层是多头注意力层,每个子层后面跟着一个层归一化,这是残差连接所在的地方。第一个子层被修改为带有掩码,以确保位置不传递到后续的位置,避免使用未来的预测来预测当前的输出:

解码器的输出随后传递给一个线性层,我们在这里应用 softmax。
在该架构中,我们可以很容易地注意到,模型在序列中并没有使用卷积或递归连接,这是它看到这些信息的地方。为了解决这个问题,这种方法的作者使用了位置编码,将元素在序列中的绝对和相对位置的信息注入到输入嵌入中,这些嵌入位于编码器和解码器的底部。
这为我们提供了完整的变换器架构,可以在以下图示中看到:

位置编码是使用以下两个公式计算的:
-
![]
-
![]
在这里,pos 是位置,i 是维度。
现在,让我们总结本章内容。
总结
在本章中,我们学习了深度学习中的一个热门新领域——注意力机制。这些机制用于让网络关注输入的特定部分,从而帮助网络克服长期依赖问题。我们还学习了如何使用这些注意力机制来替代诸如 RNN 之类的顺序模型,以在机器翻译和句子生成等任务中产生最先进的结果。然而,它们也可以用来关注图像中的相关部分。这可以用于诸如视觉问答的任务,在这种任务中,我们可能希望网络告诉我们给定场景中发生了什么。
在下一章,我们将学习生成模型。
第十二章:生成模型
到目前为止,在本书中,我们已经介绍了三种主要的神经网络类型——前馈神经网络(FNNs)、卷积神经网络(CNNs)和循环神经网络(RNNs)。它们都是判别模型;也就是说,它们学会了区分(区分)我们希望它们能够预测的类别,例如这个语言是法语还是英语?,这首歌是经典摇滚还是 90 年代流行歌?,以及这个场景中有哪些物体?。然而,深度神经网络不仅仅止步于此。它们还可以用于提升图像或视频的分辨率,或者生成全新的图像和数据。这些类型的模型被称为生成模型。
在本章中,我们将涵盖与生成模型相关的以下主题:
-
为什么我们需要生成模型
-
自编码器
-
生成对抗网络
-
基于流的网络
为什么我们需要生成模型
本书中我们学习到的各种神经网络架构都有一个特定的目的——对给定的数据进行预测。每个神经网络在不同的任务中都有其各自的优势。CNN 在物体识别任务或音乐类型分类中非常有效,RNN 在语言翻译或时间序列预测中非常有效,而 FNNs 在回归或分类任务中表现优异。另一方面,生成模型是那些建模数据p(x)的模型,我们可以从中抽样数据,这与判别模型不同,后者学习估计条件分布,例如p(•|x)。
但这对我们有什么好处呢?我们可以用生成模型做什么?嗯,有几个原因解释了为什么理解生成模型的工作原理对我们很重要。首先,在图像识别中,我们必须学习估计一个高维空间,形式为p(y[i]| x),我们可以用它来预测我们的数据属于哪个类别。你应该记得,这些模型需要大量的训练数据。那么,我们可以做的是让我们的数据从低维潜在变量生成,
,这会使我们的概率函数变成![]。现在我们需要做的是将我们的预测问题改成(y[i]| z)。我们还可以通过另一种方式利用生成模型,那就是理解我们的神经网络学到了什么。正如我们所知,深度神经网络相当复杂,要弄清楚它们究竟学到了什么或者没有学到什么是非常具有挑战性的。因此,我们可以从中采样,并将这些采样与真实数据进行比较。最后,如果数据不足,我们可以使用生成模型来创建合成数据,进而训练我们的模型。
既然我们已经知道生成模型可以用来做什么,让我们来探索一些更常见的生成模型,并了解它们是如何工作的。
自编码器
自编码器是一种无监督的前馈神经网络(FNN),它通过潜在编码的数据来学习重构高维数据。你可以把它看作是在尝试学习一个恒等函数(也就是说,输入x并预测输出x)。
让我们从查看下面的图开始,这将展示自编码器的样子:

如你所见,网络分为两个部分——编码器和解码器——它们是彼此的镜像。两个部分通过一个瓶颈层(有时称为潜在空间表示或压缩)连接,该层的维度远小于输入层。你应该注意到,网络结构是对称的,但这并不意味着它的权重必须对称。那么为什么呢?这个网络学习了什么,它是如何做到的?我们来看看这两个网络,探索它们的作用。
编码器网络接收高维输入,并将其减少到低维潜在编码(即它学习输入数据中的模式)。这类似于主成分分析和矩阵分解。其工作原理如下:

解码器网络接收低维潜在编码(即模式)作为输入,潜在编码包含了关于输入的所有主要信息,并从中重构原始输入(或尽可能接近原始输入)。其工作原理如下:

我们可以将前面的两个方程结合起来,表达为如下形式:

我们的目标是使原始输入与重构输出尽可能接近(理想情况下,相同)——也就是说,
。
编码器和解码器有各自的权重,但我们一起学习这些参数,以输出重构数据,该数据几乎与原始输入相同。在训练过程中,我们可以使用均方误差(MSE)损失:

这种类型的自编码器通常被称为欠完备自编码器,因为瓶颈层的维度远小于输入和输出层的维度。
那么,在这个瓶颈层中发生了什么,使得解码器能够从中重建输入数据呢?这种潜在编码是将高维空间映射到低维空间的过程,它学习了一个流形,流形是一个拓扑空间,在每个点上都类似欧几里得空间(我们将在第十二章《几何深度学习》中详细讲解拓扑空间和流形)。我们可以将这个流形表示为一个向量场,并可视化数据的聚类。正是这个向量场,自动编码器正在学习如何从中重建输入数据。每个数据点都可以在这个流形上找到,我们可以将其投射回高维空间以重建它。
假设我们有 MNIST 数据集,它包含了从 0 到 9 的手写数字图像。在以下截图中,我们可以看到一些来自数据集的图像:

编码器网络将这些数据作为输入,并将其编码成一个低维的潜在瓶颈层,这个瓶颈层包含了高维输入的压缩表示,并将其显示在二维空间中。这个嵌入空间如下所示,其中每种颜色代表一个特定的数字:

现在,你可能会想知道这样的架构有什么用途。我们通过训练模型来重建并输出自己的输入能得到什么好处呢?结果表明,我们可以从中获得许多好处——我们可以利用它来压缩数据并存储,从而节省空间,等到需要访问时再重建数据;我们还可以从图像或音频文件中去除噪声,或者用它进行数据可视化的降维处理。
然而,仅仅因为这种架构可以用来压缩图像,并不意味着它与 MP3 或 JPEG 这样的数据压缩算法相似。自动编码器只能压缩它在训练过程中见过的数据,因此,如果它是基于汽车图像进行训练的,那么它在压缩马的图像时效果会非常差,因为它学习到的特征是特定于汽车的,这些特征不能很好地推广到马身上。另一方面,像 MP3 和 JPEG 这样的压缩算法并不会学习输入的特征;它们会对输入做出一般性假设。
在下图中,你可以看到自动编码器将一张图像压缩到潜在空间,并在输出中重建它:

你可以在图中看到,自动编码器成功地重建了输入图像,并且它仍然看起来像数字四,但它不是完全复制的;一些信息丢失了。这不是训练中的错误,这是有意为之。自动编码器设计为有损的,仅近似复制输入数据,从而能够提取出必要的信息,优先考虑它认为更有用的部分。
正如我们在本书中看到的,增加层数并深入自编码器确实有其优势;它允许我们的神经网络捕捉更大的复杂性,并减少所需的计算成本(与加宽变浅相比)。类似地,我们可以为编码器和解码器添加额外的层。这在处理图像时尤为重要,因为我们知道卷积层比将图像展平并作为输入使用能带来更好的结果。
现在,让我们探索一些自编码器的变体,这些变体可以帮助我们实现上述任务。
去噪自编码器
去噪自编码器(DAE)是前述自编码器的变体,它学习如何以接近确定性的方式重构被损坏或带噪声的输入。假设我们有一张图像,由于某些原因,它变得模糊,或者某些像素已经损坏,我们希望提高图像的分辨率(就像电影中,他们能够从相对低分辨率的图像中找到线索一样)。我们可以通过我们的 DAE 来处理它,得到一张完全重构的图像。
我们通过使用条件分布![]开始损坏初始输入——这基本上是一个随机映射——它将返回给我们损坏的样本。现在我们有了新的输入,我们的自编码器将学习如何重构未损坏的数据——即![]——为了训练这个,我们的数据将是![]配对。我们希望解码器学习的是![,]在之前的情形中,z 是编码器的输出。
前述的损坏过程如下:

在这里,σ² 是噪声的方差。
我们可以像训练任何其他前馈神经网络(FNN)一样训练我们的 DAE,并在以下内容上执行梯度下降:

在这里,![] 是训练数据的分布。
如前所述,编码器将高维数据投影到低维空间,这个空间被称为潜在空间,并学习流形的形状。然后,它尝试将损坏的数据映射到这个流形上或接近流形,以确定它可能是什么,然后在重构过程中将其拼接起来,通过估计![]并最小化平方误差![]来得到 x。
我们可以在下图中查看这个过程:

在这里,黑色曲线是潜在空间中学习到的流形,你可以看到噪声点,
,它们被投影到流形上最接近的点,以估计它们可能是什么。
变分自编码器
变分自编码器(VAE)是另一种类型的自编码器,但它有一些特别的区别。事实上,它不是学习函数 f() 和 g(),而是学习输入数据的概率密度函数。
假设我们有一个分布 p[θ],它由 θ 参数化。在这里,我们可以表达 x 和 z 之间的关系,如下所示:
-
p[θ](z): 先验分布
-
p[θ](x|z): 似然函数(给定潜在空间的输入分布)
-
*pθ: 后验分布(给定输入的潜在空间分布)
前述的分布是由神经网络参数化的,这使得它们能够捕捉复杂的非线性特征,并且正如我们所知道的,我们通过梯度下降来训练它们。
但为什么该方法的作者决定偏离之前的分布学习方法呢?有几个原因表明这种方法更有效。首先,我们常常处理的数据是有噪声的,因此建模分布对我们来说更为合适。这里的目标,正如你可能已经猜到的,是生成具有与输入数据相似统计特征的数据。
在进一步讨论之前,让我们来看一下 VAE 的结构:

如你所见,它与自编码器有一些相似之处,但正如我们所提到的,z = f(x) 和 x' = g(z) 的关系不再成立,我们学习的是 p = (z | x) 和 p = (x | z),分别表示输入和输出之间的分布。然而,由于现在输入和输出之间有一个随机变量,这种架构不能通过常规的反向传播来训练;我们需要通过潜在分布的参数来进行反向传播。
一旦我们知道了先验分布、似然分布和真实参数 *θ^**,我们可以通过反复执行以下步骤来生成样本:
-
随机生成来自![]的样本。
-
生成一个![]样本。
利用我们在第三章《概率与统计》中学到的概率知识,我们知道 θ^* 应该最大化生成真实数据样本的概率;即,![]。
用于生成数据的方程现在如下所示:

现在,假设我们可以通过反复采样 z[i] 来逼近 x 的分布,如下所示:

但是,要做到这一点,我们需要大量的样本,其中大多数样本可能是零或接近零的。这是不可处理的(即在计算上不可行)。因此,我们所做的是学习另一个分布(即可处理的分布)——![]——以近似后验分布,![]。自然地,我们希望这两个分布尽可能接近,以便它们能够更好地近似后验分布;因此,我们使用Kullback-Leibler(KL)散度来衡量它们之间的距离,并尽量通过φ来最小化这个距离。我们可以通过以下公式来看我们是如何做到的:

根据贝叶斯规则,我们知道以下公式:

如果我们对其取对数,会得到以下结果:

我们可以将其代入 KL 散度的公式中,得到以下结果:

由于p(x)不依赖于z,我们可以将其保留在外面。
现在,我们可以将公式重新排列成以下形式:

由于 ![],这里的目标是最大化 ![] 的下界,因为 ![],我们这么做是因为 KL 散度的输出是非零且非负的。
等等——编码器是什么,解码器又是什么?毕竟这是一个自编码器。有趣的是,它一直就在我们面前。VAE 中的编码器是 ![] ,通常假设它是高斯分布的:

解码器是 ![.] 这两者都是通过神经网络建模的。
生成对抗网络
生成对抗网络(GAN)是一种受博弈论启发的神经网络架构,由 Ian Goodfellow 于 2014 年创建。它由两个网络组成——生成器网络和判别器网络——这两个网络在一个极小化博弈中相互竞争,使得它们能够通过努力超越对方来同时改进。
在过去的几年里,GAN 在任务上取得了令人瞩目的成果,比如创造出与真实图像无法区分的图像、在给定一些录音的情况下生成音乐,甚至生成文本。但这些模型以训练困难而著称。现在,让我们来看看 GAN 到底是什么,它们是如何带来如此惊人的结果的,以及它们为何如此难以训练。
如我们所知,判别模型学习条件分布,并试图给定输入数据预测一个标签——即 P(Y | X)。而生成模型则建模联合分布——即 P(X, Y)——并且,利用贝叶斯定理,在给定标签时,它们可以生成数据。所以,像 VAE 一样,它们学习分布 P(X)。
评论网络是一个判别器 (D),它有参数 θ^((D)), 它的任务是判断输入数据是真实的还是伪造的。生成器网络是一个生成器 (G),它有参数 θ^((G)), 任务是学习从噪声中创建合成数据样本,并使判别器高概率地认为这些合成数据是真实的。
正如我们在本书中所见,判别器模型非常擅长学习将输入数据映射到期望的标签(输出),并能够判断一个对象是否出现在图像中,追踪视频中的物体以及进行语言翻译。然而,它们无法像我们一样利用所学知识生成全新的数据。
在继续之前,让我们看看这个架构是怎样的。在下图中,你可以看到 GAN 的结构:

现在我们知道 GAN 的结构是怎样的,接下来让我们看看它是如何工作的。我们可以用以下方程来总结 GAN:

判别器的目标是让 ![] 和 ![],而生成器的目标是让 ![]。
由于生成器和判别器有不同的目标,自然它们会有不同的成本函数。判别器和生成器的各自损失如下:
-
![]
-
![]
自然地,两个网络之间没有直接影响对方的参数。如前所述,由于这是一个受博弈论启发的架构,我们将其视为一个双人博弈,我们的目标是找到当 x 如下时的纳什均衡:

这是一个鞍点。当我们达到这个点时,判别器无法区分真实数据和生成的数据。
那么,我们现在如何找到判别器的最优值呢?首先,我们知道损失函数,通过它我们可以找到最优的 D(x) 值:

然而,在训练时,生成器理想情况下会输出 x,因此我们可以将损失函数重写为:

这里,p[r] 是实际的数据分布,p[g] 是生成的数据分布。现在,我们有以下内容:

为了让生活稍微简单一些,让我们用以下变量替代方程中的部分内容:
-
![]
-
![]
-
![]
由于我们是对所有可能的 x 值进行采样,我们可以将前面的三个变量写成如下形式:

现在,为了找到判别器的最优值,我们将前面的导数设为 0,并得到以下结果:

所以,当 ![], ![],这满足了我们的条件。损失函数现在变成了如下:

现在我们知道如何找到最优的判别器,自然,你可能会想知道如何找到最优的生成器。我们的目标是最小化Jensen–Shannon(JS)散度,计算真实分布和生成分布之间的差异,公式如下:

所以, ![],这告诉我们,如果我们的生成器确实是最优的,那么!。
这就是 GAN 的工作原理。然而,GAN 存在一些问题,特别是两个网络的收敛性并不保证,因为其中任何一个模型的梯度下降不会直接影响另一个模型,而且模型参数往往会发生震荡并导致不稳定。另一个问题是模式崩溃,这是由于不当的收敛导致的,意思是生成器只输出少数几种生成样本,这些样本它知道能欺骗判别器让其认为是真的。由于生成器开始一次又一次地输出相同的几个样本,判别器便学会将这些样本分类为假的。模式崩溃是一个相当具有挑战性的问题。最后,我们的判别器可能变得太强,以至于生成器的梯度消失,最终什么也学不到。
如果我们比较变分自编码器(VAE)和生成对抗网络(GAN),这两者都是生成模型,我们会发现,在 GAN 中,我们的目标是最小化两个分布之间的散度,而在 VAE 中,我们的目标是最小化两个分布散度的界限。这是一个更容易的任务,但其生成的结果并不像 GAN 那样。
Wasserstein GANs
在前一部分中,我们学习了 GAN,了解了它们的工作原理以及它们在训练中面临的一些问题。现在,我们将学习Wasserstein GAN(WGAN),它利用 Wasserstein 距离。Wasserstein 距离是一个函数,用于测量在给定度量空间中两个概率分布之间的距离。假设我们在沙滩上,决定在沙子上建模一个三维概率分布。Wasserstein 距离测量的是将分布移动并重塑成另一个分布所需的最小能量。因此,我们可以说,这个代价是我们移动的沙子总质量与它移动的距离的乘积。
对于 GAN 来说,这可以平滑梯度,并防止判别器过度训练。我们判别器和生成器的损失分别如下:
-
![]
-
![]
为什么它比 JS 和 KL 散度表现得更好?让我们通过以下例子来找出答案。
我们有两个分布,P 和 Q,它们的参数如下:

现在,让我们将 KL 散度与 JS 散度以及 Wasserstein 距离进行比较。如果 θ ≠ 0,那么我们可以观察到以下内容:

当 ![] 时,我们可以观察到以下内容:

如你所见,Wasserstein 距离相对于 KL 和 JS 散度有一些明显的优势,因为它对 θ 可微,这提高了学习的稳定性。因此,损失函数现在变为以下形式:

这是 K-Lipschitz 连续的——即,![] 对 ![] 和 ![]。
可惜的是,尽管 WGAN 相比于 GAN 有很多优势,它仍然难以训练。有许多 GAN 的变种试图解决这个问题。
基于流的网络
到目前为止,在本章中,我们学习了两种生成模型——GAN 和 VAE——但还有另一种模型,称为基于流的生成模型,它直接学习数据分布的概率密度函数,而这是前面提到的模型所没有做到的。基于流的模型利用了归一化流,克服了 GAN 和 VAE 在学习分布时所面临的困难。这种方法可以通过一系列可逆映射将简单的分布转化为更复杂的分布。我们反复应用变量变化规则,这使得初始概率密度通过这一系列可逆映射流动,最终得到目标概率分布。
归一化流
在我们深入理解基于流的模型之前,先回顾一些概念,如雅可比矩阵、计算矩阵的行列式以及概率论中的变量变换定理,然后再继续理解什么是归一化流。
作为复习,雅可比矩阵是一个m×n维的矩阵,包含一个函数的第一导数,该函数将一个n维向量映射到m维向量。该矩阵的每个元素表示为![]。
行列式只能对方阵进行求解。所以,假设我们有一个n×n的矩阵M,它的行列式可以通过以下方式求得:

在这里,求和是对所有n!排列进行计算,![] 对![],而σ(•)告诉我们排列的符号。然而,如果|M|= 0,则M不可逆。
现在,假设我们有一个随机变量,
,其概率密度函数为z∼π(z)。基于此,我们可以通过一一映射得到一个新的随机变量,x = f(z)。由于该函数是可逆的,我们知道z = f^(-1)(x)。那么,我们新随机变量的概率密度函数是什么呢?根据我们对概率分布的知识,我们知道以下是成立的:

从第一章,《向量微积分》中,我们应该记住,积分是曲线下的面积,在概率论中,这个面积总是等于 1。曲线下的这一面积可以被切分为宽度为Δz的无穷小矩形,这个矩形在z处的高度是π(z)。
知道z=f^(-1)(x)告诉我们,z相对于x的微小变化的比率给出如下结果:

我们可以将其重写如下:

现在,我们可以将前述分布重写如下:

由于我们将处理向量,我们可以将前述方程用多个变量来表示,如下所示:

太棒了!现在这些概念已经清晰地在我们脑海中,我们继续理解什么是归一化流。
获取一个好的概率密度估计在深度学习中非常重要,但通常非常具有挑战性。因此,我们使用归一化流来通过一系列可逆函数将简单分布转化为更复杂的分布,从而更高效地逼近目标分布。归一化流这一名称来源于变量变化后使概率密度规范化,并且流意味着这些简单的变换可以连续应用,创造出更加复杂的变换。对于这些变换函数来说,它们需要容易逆转,并且行列式需要容易计算。
假设我们有一个初始分布,应用K次变换(或映射),看我们如何从中获得x。其过程如下:

我们也可以使用以下方法:

这里我们有以下参数:
-
![]
-
![]
-
![]
-
行列式是一个雅可比矩阵。
让我们展开我们用来找到p[i](z[i])的第四个方程,以便更清晰地理解它:

如果我们对两边取对数,就可以得到如下结果:

这告诉我们变量序列之间的关系,并且通过扩展,我们可以获得x与初始分布z[0]之间的关系,其形式如下:

这个过程被称为归一化流。
实值非体积保持
到目前为止,本章我们已经介绍了两种非常流行的生成神经网络架构——变分自编码器(VAEs)和生成对抗网络(GANs)——这两者都非常强大,并在生成新数据方面取得了巨大成果。然而,这两种架构也各有其挑战。另一方面,基于流的生成模型虽然不如前两者流行,但也有其优点。
基于流的生成模型的一些优势如下:
-
它们具有精确的潜变量推理和对数似然评估,而在变分自编码器(VAEs)中,我们只能大致推断潜变量,而生成对抗网络(GANs)由于没有编码器,无法进行潜变量的推断。
-
它们在合成和推理过程中都很高效,便于并行化。
-
它们为下游任务提供了有用的潜在空间,因此能够在数据点之间进行插值,并修改现有数据点。
-
与生成对抗网络(GANs)和变分自编码器(VAEs)相比,它们更加节省内存。
在本节中,我们将深入探讨一种被称为实值非体积保持(real NVP)的生成概率模型,它能够有效地建模高维数据。该模型通过将一系列可逆的双射变换堆叠在一起实现。
假设我们有一个D-维输入,x,它被分成两部分,d < D,输出y由以下两个方程计算得到:
-
![]
-
![]
这里,
是逐元素乘积;s(•)和t(•)是尺度和平移函数,映射![]。
通过我们对归一化流的了解,我们知道这种方法必须满足两个特性——它必须是容易可逆的,并且其雅可比矩阵必须易于计算。现在,让我们检查一下这种方法是否符合这两个标准。
在以下方程中,我们可以看到,实际上找到逆是相当简单的:

计算耦合层的逆并不需要我们计算s(•)和t(•)的逆,这一点非常好,因为在这种情况下,这两个函数都是卷积神经网络(CNN),而且很难反转。
现在,我们可以确定雅可比矩阵的计算难度:

这是一个下三角矩阵。如果我们想要找到雅可比矩阵的行列式,可以使用以下公式:

这两条映射方程告诉我们,当我们在正向计算中组合耦合层时,某些部分保持不变。为了解决这个问题,这种方法的作者采用了交替模式来耦合层,以确保所有部分最终都会被更新。
摘要
在本节中,我们介绍了多种生成模型,这些模型学习真实数据的分布,并尝试生成与真实数据无法区分的数据。我们从一个简单的自编码器开始,并基于它理解了一个变体,该变体使用变分推理生成类似输入的数据。接着我们学习了生成对抗网络(GAN),它将两个模型——判别器和生成器——对抗起来,在博弈中让生成器学习创建足够真实的数据,以便骗过判别器让其认为数据是真的。
最后,我们了解了基于流的网络,这些网络通过对数据应用几个可逆变换,近似一个复杂的概率密度,使用较简单的密度。这些模型用于各种任务,包括——但不限于——合成数据生成,用以克服数据限制和从数据中提取洞见。
在下一章中,我们将学习转移学习和元学习,它们涵盖了将网络已经为一个任务学习到的知识转移到另一个任务上,以促进学习的各种方法。我们将区分这两种方法。
第十三章:迁移学习与元学习
到目前为止,在本书中,我们已经学习了各种神经网络,正如我们所见,每种神经网络在处理不同任务时都有其自身的优缺点。我们还了解到,深度学习架构由于其庞大的规模和大量可训练参数,往往需要大量的训练数据。正如你可以想象的,对于我们希望为之构建模型的许多问题,收集足够的数据可能是不可能的,即使能够收集到,这也将非常困难、耗时,甚至可能是昂贵的。一种应对之策是使用生成模型来创建合成数据(我们在第八章,正则化中提到过),这些数据是从我们为任务收集的小数据集生成的。
本章将介绍最近越来越受欢迎的两个主题,这些主题在这一领域的使用将会持续增长,且理应如此。它们分别是迁移学习和元学习。它们之间的区别在于,迁移学习是指我们尝试利用一个模型学到的知识来解决另一个不同但相似的问题,而元学习是指我们尝试创建可以学习如何学习新概念的模型。关于迁移学习的文献非常少,且其实践更为“黑客式”;我们主要介绍它是因为理解迁移学习和元学习之间的差异非常重要,因为它们看似相似,但本质上是不同的,且常常被混淆。然而,本章的重点是元学习。随着章节的进展,我们将深入探讨它们的区别。
本章将涵盖以下主题:
-
迁移学习
-
元学习
迁移学习
我们人类有着惊人的学习能力,然后我们将所学的知识应用到不同类型的任务中。新任务与我们已经知道的任务越相似,我们解决新任务的难度就越小。基本上,我们在学习新事物时,几乎从来不需要完全从零开始。
然而,神经网络没有这种奢侈的选择;它们需要为我们希望应用的每个任务从零开始进行训练。正如我们在前几章中看到的那样,神经网络非常擅长学习如何做一件事,并且因为它们只学习训练集中的分布插值,因此它们无法将知识推广到训练数据集之外的任务。
此外,深度神经网络可能需要数千万的数据样本,才能在数据中学习到潜在的模式,然后才有可能表现良好。正因为如此,研究人员在这个领域提出了迁移学习——一种将一个神经网络学到的知识转移到另一个神经网络上的方法,本质上是通过自举学习过程。这在我们有一个项目要构建或者有一个假设要测试,但又没有足够的资源(比如 GPU、足够的数据等)从头开始构建和训练网络时,非常有用。相反,我们可以使用一个已经在类似任务上表现良好的现有模型,并将其用于我们自己的任务。
让我们稍微回想一下第九章,卷积神经网络。我们看到的架构都包含一个输入层,该输入层接受一定大小的图像(h × w × c),然后有多个卷积层,接着是一个可选的池化(或子采样)层。在网络的末尾,我们将特征图展开成全连接层,然后输出层的节点数与我们想要检测的类别数相同。我们还了解到,卷积神经网络(CNNs)可以提取自己的特征,每一层学习不同种类或层次的特征。离输入层更近的层学习非常细粒度的特征,例如边缘、曲线、颜色斑块等,而离输出层更近的层学习更大的特征,例如眼睛、耳朵、尾巴、嘴巴等。
我们可以做的是,取一个已经训练好的卷积神经网络(CNN),去掉最后几层(即全连接层和输出层),并将这个 CNN 作为新数据集的特征提取器,用于我们正在构建的模型。或者,我们还可以通过微调一个已经训练好的 CNN,来解决一个新问题,针对我们想要创建 CNN 的新数据集进行微调。我们可以通过冻结前面的层(因为它们学习的是非常细粒度或通用的特征),然后使用反向传播微调后面的层,这样 CNN 就能学习到更复杂的特征,这些特征是特定于新数据集的。
在我们深入探讨迁移学习的细节之前,理解它的定义非常重要。我们将采用 Zhuang 等人给出的定义;但在此之前,让我们回顾一下“领域”和“任务”的定义。
领域,![],由两部分组成;即特征空间,![],和边际分布,P(X)。换句话说,![],其中X表示一个数据样本,定义为![]。
一个任务,![],由标签空间,![],和映射函数,f,组成;即,![]。映射函数(我们的模型)是一个隐式的函数,期望从样本数据中学习。
在迁移学习的情况下,我们有两个不同的领域和任务——每个领域和任务都对应一个源和目标——我们的目标是将模型在源领域学到的知识迁移到目标领域的模型中,以提高其整体性能。
在深入探讨这个话题之前,有四个概念是我们必须理解的。它们如下:
-
目标领域的特征空间,![],和源领域的特征空间,![],是不相同的。
-
目标领域的标签空间,![],和源领域的标签空间,![],是不相同的。
-
领域自适应——这是指目标领域的边际概率,P(X[t]),和源领域的边际概率,P(X[s]),是不相等的。
-
目标领域的条件概率,P(Y[t]|X[t]),和源领域的条件概率,P(Y[s]|X[s]),是不相等的。
正如你所想象的,这里存在一些限制,决定了能够做什么。你不能将任何任意大小的预训练模型应用到另一个任务上。选择使用哪种预训练网络在很大程度上取决于我们当前任务的数据集与预训练模型所用的数据集是否相似,以及我们当前任务的可用数据集的大小。例如,如果我们有一个目标检测任务,我们不能使用预训练的 GAN 或 RNN,因为它们是针对不同任务的。此外,如果模型已经在识别各种农场动物的图像上进行了训练,它在执行一个新任务时(如要求我们的网络识别飞机和汽车的品牌和型号)将表现不佳。
元学习
元学习——也被称为学习如何学习——是深度学习中的另一个迷人话题,被许多人视为通向人工通用智能(AGI)的有前途的路径。对于那些不知道什么是 AGI 的人来说,它是指人工智能达到理解并学习执行任何人类能够完成的智能任务的能力,这是人工智能的目标。
正如我们所知,深度神经网络非常依赖数据,且需要大量的训练时间(取决于模型的大小),有时可能需要几周的时间,而人类则能更快、更高效地学习新概念和技能。例如,作为孩子,我们只需要看到一次或几次,就能迅速学会分辨驴、马和斑马,并能完全确定它们的区别;然而,神经网络可能需要几十万到一百万个数据样本,才能学习如何区分这三种类别并达到专家级的准确度。
元学习方法
我们在元学习中试图回答的问题是,是否可以创建一个模型,让它像我们一样学习——也就是说,仅凭少量的训练样本,学习新的概念和技能来应对新任务。因此,简而言之,我们希望找到我们已学到的知识之间的相似性,并用它来加速学习新任务的过程。一个好的元学习模型应该是在多个任务上进行训练,并已优化以在这些任务上表现良好,同时也能在未见过的任务上表现出色。
到目前为止,我们在本书中看到的深度神经网络都需要数百万个数据样本,有时甚至需要几亿个样本。然而,在元学习中,我们希望我们的模型仅使用少量样本进行学习;我们将其称为少样本学习。
使用仅有少量数据样本进行学习的问题被称为少样本学习或k-shot 学习(其中k是每个类别的数据样本数量)。假设我们有一个图像识别问题,包含三个类别——驴、马和斑马。如果每个类别有 10 个样本,那么这就是 10-shot 学习。然而,如果每个类别只有 1 个样本,那么这就是 1-shot 学习。还有一种有趣的情况是,我们没有任何数据样本,这种情况被称为零样本学习。(没错,我们可以在没有数据的情况下训练神经网络...开个玩笑!我们会用元数据代替,稍后我们会学习到这部分内容。)
如果我们的数据集中有多个类别,并且我们希望进行少样本学习,那么这就是n 类 k-shot 学习,其中n是类别的数量。在我们的例子中,我们有 3 个类别,每个类别有 10 个样本,因此我们进行的是 3 类 10-shot 学习。
每个前述任务都会有一个相关的数据集,。如我们所知,我们的模型,f,有可训练的参数θ,因此我们可以将模型表示为学习以下内容:

在这里,![]。
对于元学习,我们将数据集分为两部分——支持集,S,和查询集,B——使得![]。然后,我们从![]标签中提取一个子集,使得![]。接着,我们在支持集上训练模型,并在查询集上测试模型,采取的是一种情节式的方式。支持集是通过从![]的每个类别中采样来构建的,而预测集是通过使用同一数据集中的其他样本类似地构建的。通过这种方法,我们的模型逐渐学会从较小的数据集中学习。然后,我们计算模型的损失并使用反向传播优化它,正如我们之前所做的那样。
现在的目标如下所示:

如你所见,这与迁移学习有些相似,不同之处在于它更进一步,优化以便能够在多个任务上表现良好,而不仅仅是一个任务。
实践中使用了三种元学习方法,如下所示:
-
基于模型的
-
基于度量的
-
基于优化的
基于模型的元学习
在基于模型的元学习中,我们希望创建一个能够快速学习和更新其参数的模型,使用的训练步骤仅限于少数几步。我们可以在模型内部(模型内)或外部(使用另一个模型)执行此操作。现在让我们来探讨一些方法。
增强记忆的神经网络
顾名思义,增强记忆神经网络(MANNs)通过外部记忆(存储缓冲区)进行增强,这使得模型能够更容易地学习并保留新信息,从而避免之后遗忘。使用的一种方法是训练神经图灵机(NTM),通过改变训练设置和记忆检索来学习学习算法。
为了将 NTM 应用于元学习,我们需要它能够快速编码与新任务相关的信息,同时确保存储的信息能够迅速被访问。其工作原理是,我们传递当前时间步的信息以及下一个时间步的相应标签,这迫使网络保持更长时间的信息。因此,在每个时间步,网络接收到以下内容:

在下图中,我们可以观察到网络的结构:

通过稍后提供标签,网络被迫记住信息,以便当给定标签时,它可以回顾并回忆数据进行预测。为了确保模型最适合元学习,读写机制也已被改变。
读取过程通过内容相似性来进行,如下所示:

在这里,![],k[t] 是控制器在 t^(th) 时间步输出的关键特征向量,![] 是通过计算记忆中每一行与 k[t] 和 r[t] 的余弦相似度来得到的 N 元素的读取权重,k[t] 和 r[t] 是加权记忆记录的总和,M[t] 是记忆矩阵(而 Mt 是它的 i^(th) 行)。
现在,为了写入记忆,我们使用最近最少使用访问 (LRUA),它将新信息写入存储最近最少使用 (LRU) 或最常使用 (MRU) 内存的位置。这样做的原因是,通过替换 LRU 内存,我们能够保持更频繁使用的信息,而一旦 MRU 内存被检索,它可能很长一段时间都不需要,因此我们可以覆盖它。
我们通过以下公式计算 LRUA:
-
![]
-
![]
-
![]
-
![],其中 ![] 是 ![] 中的 n^(th) 最小元素
在最后的更新公式中,当 LRU 内存设置为 0 时,记忆中的每一行都通过以下公式进行更新:

现在我们已经看到如何通过使用外部记忆来进行元学习,通过覆盖一段时间未使用的信息来学习新信息,接下来我们将讨论另一种基于模型的元学习方法,该方法利用内部架构迅速学习新信息。
元网络
元网络 (MetaNet) 是一种旨在快速泛化任务的架构;它使用快速权重来实现这一点。之所以称其为快速权重,是因为我们不再像通常那样使用梯度下降来更新权重,而是使用一个神经网络来预测另一个神经网络的权重。另一个神经网络生成的权重被称为快速权重,而依赖于梯度下降的权重则被称为慢速权重。这样做的效果是,它支持元级持续学习。
在下图中,你可以看到 MetaNet 的整体架构:

MetaNet 由两个组件组成——一个元学习者,它学习一个嵌入函数 f[θ],帮助确定两个数据输入之间的相似性,并验证这两个输入是否属于同一类;另一个是基础学习者 g[φ],它执行实际的学习。正如前面的图示所示,快速权重和慢速权重都会加在一起并重新输入到模型中。元学习者和基础学习者都有各自的快速权重。
这需要两个神经网络——F[w](一个 LSTM,其输入为f的嵌入损失)和G[v](一个 ANN)——它们分别输出f[θ]和g[φ]的快速权重。对应于f[θ]和g[θ]的快速权重分别是θ*和*φ。两者的区别在于,F[w]的输入是f的嵌入损失的梯度,而G[v]则通过g的损失梯度进行学习。
如您所见,这意味着我们需要学习四组不同的参数![]。为了训练我们的网络,我们使用两个数据集——一个训练集![]和一个支持集![]。
该网络的整体训练可以分为三个不同的部分:
-
获取元信息
-
生成快速权重
-
优化慢权重
我们首先创建一系列任务,每个任务都有一个训练集和一个支持集,并随机从支持集中采样T个输入对,![]和![],其中T < N,然后计算验证任务的嵌入的交叉熵损失。
然后,我们计算任务级别的快速权重,![]。完成此步骤后,我们从支持集计算示例级别的快速权重,![],并更新值记忆的第i(th)*位置,*M*(对于元学习)为![]。然后,我们使用![]将支持集中采样的点通过快速和慢权重编码到任务空间中,该权重在第*i(th)位置的关键记忆R(对于基础学习者)中更新。
完成此步骤后,我们从测试集中进行采样,并使用![]将其编码到任务空间中,然后计算余弦相似度,以确定记忆索引和输入嵌入的相似性。
基于度量的元学习
基于度量的元学习使用与聚类中类似的概念,在这种方法中,我们尝试学习对象之间的距离。这类似于核密度估计,其中我们使用核函数k[θ]来计算权重或两个样本的相似度,然后计算标签上的预测概率:

这一类元学习算法显式地学习数据的嵌入,以创建最优的核。
原型网络
原型网络是一种用于少样本学习的元学习算法。其工作方式是我们使用编码函数f[θ]将每个D维输入编码成一个M维向量。这个原型向量定义如下:

对于每个类的情况,
也是如此。我们计算测试数据嵌入与原型向量之间的距离,![],然后用它来计算类的概率分布,如下所示:

这里,d[φ] 是距离函数,但φ必须是可微的。
在下面的图示中,我们可以看到原型网络计算了少样本原型和零样本原型:

孪生神经网络
孪生神经网络是一种由两个相同的神经网络组成的架构,这些网络共享权重,它们的参数经过训练来确定两个数据样本之间的相似度,使用嵌入的距离度量。这种架构已被证明对一-shot 图像分类有效,在这种分类中,网络学习判断两张图片是否属于同一类别。
在下面的图示中,我们可以看到网络接收两张图像,并且每张图像都通过一个相同的 CNN (f[θ]) 来生成特征向量(嵌入):

一旦计算出嵌入,我们就可以计算两个嵌入之间的距离,如下所示:

从距离计算的输出会通过一个多层感知机(MLP)与 Sigmoid 函数,以计算两个输入是否属于同一类的概率。
由于图像的标签是二元的(1表示是,0表示否),我们使用交叉熵计算损失:

我们使用以下方式计算它属于哪个类的概率:

这里,S 是支持集,x 是测试图像,c(x) 是与图像对应的标签,而![] 是类的预测。
基于优化的元学习
在第七章《前馈神经网络》中,我们介绍了反向传播和梯度下降方法,作为优化模型参数以减少损失的手段;但我们也看到,这种方法相对较慢,并且需要大量的训练样本和计算资源。为了克服这一点,我们采用了基于优化的元学习,其中我们学习优化过程。但我们该如何做呢?
长短期记忆元学习器
让我们回想一下,当我们学习基于梯度的优化时,发生了什么?我们从参数空间中的一个初始点开始,然后计算梯度,并朝着局部/全局最小值迈出一步,接着重复这些步骤。在带动量的梯度下降中,我们利用之前更新的历史信息来指导下一步的更新。如果仔细想想,这与 RNN 和长短期记忆(LSTM)有些相似,因此我们可以用 RNN 替代整个梯度下降的过程。这种方法被称为通过梯度下降学习学习。这个名字的背后原因是我们使用梯度下降训练 RNN,然后用 RNN 来执行梯度下降。在这种情况下,我们将 RNN 称为优化器,而基础模型称为优化对象。
正如我们所知,普通的 RNN 存在一些问题(梯度消失),因此在这里,我们将介绍如何使用 LSTM 单元来优化模型。但在此之前,让我们先回顾一下参数优化是如何工作的。其过程如下:

让我们将其与 LSTM 单元中的更新进行比较:

这里,![]、![]、![] 和 ![]。然而,遗忘门和输入门不必是固定的;它们可以被学习,以便我们能够将其适应其他任务。遗忘门、输入门、候选层和记忆状态的计算分别如下:
-
![]
-
![]
-
![]
-
![]
在下图中,我们可以看到 LSTM 元学习器的结构:

在训练过程中,我们希望尽量模拟测试过程中会发生的情况,在训练期间,我们按如下方式采样数据集:

接下来,我们从![]中进行采样,通过T次迭代来更新模型的参数,并计算基模型(θ)权重的损失,同时将损失、梯度和元学习器参数(φ)传递给优化器(元学习器)。然后,元学习器将输出新的单元状态,我们用它来更新基模型的参数。
一旦我们完成了 T 次迭代,我们可以期待找到一个最优的基础模型参数。为了测试 θ[T] 的优良性并更新元学习者的参数,我们需要根据 θ[T] 在测试数据上找到损失,然后计算测试损失对 φ 的梯度,进而对 φ 执行 N 次迭代更新。
模型无关元学习
模型无关元学习(MAML)是一种优化算法,可以在任何通过梯度下降训练的神经网络中使用。假设我们有一个模型 f,它的参数为 θ,并且有一个任务 τ[i],它对应一个数据集 ![]。然后,我们可以通过单步或多步梯度下降更新模型。这个算法的单步操作如下:

上述步骤学习了如何优化单一任务,但我们希望优化多个任务。因此,我们可以通过改变任务来寻找在多个任务上优化的参数,如下所示:

在这里,L^((0)) 是对应于初始训练批次的损失,L^((1)) 是下一批次训练的损失。
这看起来与我们熟悉的梯度下降非常相似,那么它有什么特别之处呢?其实,这个方法是在学习与其他任务相关的参数,并尝试学习出最适合用于下一个任务的初始参数,从而减少训练时间。然而,它使用了二阶优化,这在计算上稍显复杂,因此我们可以改用一种计算更加可行的一级方法。这种方法被称为一阶模型无关元学习(FOMAML)。让我们在接下来的计算中看看这两者的区别。
假设我们执行了 n 步梯度下降,其中 n ≥ 1。我们的起始点是 θ[meta],步骤如下:

一旦计算了 n 步,我们就可以抽取下一批次并对其进行更新。这样就变成了以下内容:


在这里,![]。
然而,在 FOMAML 中的梯度如下:

恭喜你——你已经完成了本章关于迁移学习和元学习的内容!
总结
在本章中,我们探讨了深度学习领域内两个非常有趣的方向——迁移学习和元学习——这两者都承诺能够推动深度学习甚至人工智能领域的发展,通过使神经网络能够学习额外的任务并在未见过的分布上进行泛化。我们还探索了几种元学习方法,包括基于模型的方法、基于度量的方法和基于优化的方法,并分析了它们之间的区别。
在下一章,我们将学习几何深度学习。
第十四章:几何深度学习
在本书中,我们学习了多种用于深度学习的神经网络类型,如卷积神经网络和循环神经网络,并且它们在各种任务中取得了惊人的成果,如计算机视觉、图像重建、合成数据生成、语音识别、语言翻译等。我们迄今为止研究的所有模型都在欧几里得数据上进行训练,即可以以网格(矩阵)格式表示的数据——图像、文本、音频等。
然而,我们希望将深度学习应用于的许多任务使用的是非欧几里得数据(稍后会详细讨论)——这类数据是我们到目前为止接触到的神经网络无法处理的。这包括处理传感器网络、网格表面、点云、物体(计算机图形学中使用的那种)、社交网络等等。一般来说,几何深度学习旨在帮助深度神经网络在图形和流形上进行泛化(我们在第五章中学习了图论,接下来在本章中我们将学习流形)。
本章我们将覆盖以下主题:
-
比较欧几里得数据与非欧几里得数据
-
图神经网络
-
谱图 CNNs
-
混合模型网络
-
3D 人脸识别
让我们开始吧!
比较欧几里得数据与非欧几里得数据
在我们学习几何深度学习技术之前,理解欧几里得数据和非欧几里得数据之间的差异以及为什么我们需要一种单独的方法来处理它非常重要。
深度学习架构,如 FNNs、CNNs 和 RNNs,在过去的 8 年中已证明在各种任务中取得了成功,如语音识别、机器翻译、图像重建、物体识别与分割以及运动追踪。这是因为它们能够利用和使用数据中存在的局部统计属性。这些属性包括平稳性、局部性和组合性。以 CNNs 为例,它们所接受的输入数据可以以网格形式表示(例如图像,可以用矩阵和张量表示)。
在这种情况下(图像),平稳性来自于 CNNs 具备以下特性:
-
移位不变性,归功于卷积的使用。
-
局部性可归因于局部连接性,因为卷积核不仅观察单个像素,还会观察相邻像素。
-
组合性来自于它由多个尺度(或层次)组成,其中简单的结构被组合在一起以表示更抽象的结构。
然而,并非所有数据都能以深度神经网络所需的格式表达,如果数据能够被扭曲成网格形态,这意味着我们不得不牺牲复杂数据中存在的许多关系,转而使用一种更简单的表示方式,以便神经网络能够将其作为输入。
这三个属性限制了神经网络能够学习的内容,以及我们可以使用它们解决的各种问题。
你可能已经猜到,现实世界中许多数据无法被恰当地捕捉到网格中。然而,这种数据可以通过图或流形来表示。可以通过图表示的数据的例子包括社交网络、学术论文引用网络、通信网络、知识图谱、分子和道路地图。另一方面,我们可以利用黎曼流形(下一节将详细介绍)来表示三维物体(即体积物体),如动物、人体、面孔、飞机、椅子等。简而言之,两者都是捕捉节点之间可能存在关系的方法。
这种类型的数据对神经网络来说很难处理,因为它缺乏神经网络在训练过程中习惯处理的结构。例如,我们可能想通过两个节点之间的权重(或强度)来表示社交网络中两个人的亲密程度。在这种情况下,我们可能会这样做,以便为用户提供一个新朋友的建议,供他们添加到现有的网络中。然而,我们没有简单的方法来将这些信息表示为特征向量。
在我们学习几何深度学习中使用的方法之前,首先让我们了解一下什么是流形。
流形
流形 是任何一个拓扑空间,其中在任何点(p)的邻域内,它在拓扑上等价于(或同胚于)一个 k 维欧几里得空间。我们在本书的早些时候遇到过流形这个词,但当时并没有正确地定义它,所以现在我们将进行定义。前面的定义可能听起来有些令人生畏,但稍后它会变得更容易理解。
假设我们有一个一维流形。为了简化,我们将使用一个圆圈或圆盘(我们用S¹表示),它存在于。
假设我们有以下流形:

现在,如果我们反复放大左上角象限中的圆弧,最终我们会到达一个放大程度,在这个程度下,圆弧看起来像一条直线(有点像那个点的切线):

如前图所示,我们已放大至左上角,并在某点画了切线,在该点,曲线几乎与切线平行。我们越放大,线条看起来就越像是直线。
类似地,如果我们有一个二维流形,例如一个球面(我们表示为S²),它存在于
中,并且我们对其进行放大,那么在表面上的任何一点,都会看起来像一个平坦的圆盘。流形不一定非得是球面;它可以是任何具有流形特性的拓扑空间。为了形象地理解这一点,可以将地球视为一个流形。从你站立的任何地方向四周看,地球看起来是平的(或平面),尽管它实际上是弯曲的。
我们可以分别如下表示单位圆和单位球:
-
![]
-
![]
类似地,我们也可以如下表示更高维度的流形:

正式地说,k维可微流形 M 在
中是
中的一组点,对于每一个点,p ∈ M,存在一个p的小开放邻域U,一个向量值可微函数,![],以及一个开集,![],满足以下条件:
-
![]
-
F的雅可比矩阵在V中的每个点都有秩k,其中F的雅可比矩阵是一个n × k的矩阵,形如下所示:

这里,F是流形的局部参数化。
我们还可以使用现有的拓扑空间通过笛卡尔积构建新的拓扑空间。假设我们有两个拓扑空间,X和Y,它们的笛卡尔积是 ![],其中每个 ![] 和 ![] 生成一个点, ![]。一个熟悉的笛卡尔积是三维欧几里得空间,其中 ![]。然而,需要注意的是 ![] (它实际上等于T²,即一个环面,但我们将避免探讨其原因,因为那超出了本书的范围)。
在计算机图形学中,我们使用嵌入在 ![] 中的二维流形来表示三维物体的边界表面。
由于这些参数化流形是对象,它们会有一个方向性,而为了定义这一点,我们需要所谓的流形的切空间。然而,在我们能够定义切空间之前,我们需要先澄清一些概念。假设我们有一个 k 维流形 M,它被定义在 ![] 上(其中 k < n)。在这里,对于每个 p ∈ M,都有一个包含 p 的开集 U 和 (n-k) 个实值函数 ![],这些函数在 U 上定义,并且满足 ![],在每一点 ![] 处,我们有以下线性无关的向量:

现在,流形 M 在点 p 处的法空间表示为 Np,并由以下向量张成:

正如我们所知,切向量是垂直于法向量的,因此流形上点 p 处的切空间 Tp 包含所有与每个法向量 Np 垂直的向量,
。然而,![] 只有在对于所有的 ![],我们有如下条件时,才能属于 Tp:

一旦我们有了切空间,就可以用它来定义黎曼度量,具体定义如下:

该度量使我们能够执行角度、距离和体积的局部测量,以及度量所定义的任何流形。这被称为 黎曼流形。
在我们继续之前,有两个重要的术语需要我们熟悉:
-
等距性:度量保持形状变换
-
测地线:在 M 上 p 和 p' 之间的最短路径
有趣的是,我们可以通过标量场和向量场来定义流形,这意味着我们可以将微积分扩展到流形中。在这种情况下,我们需要引入以下三个新概念:
-
标量场: ![]
-
向量场: ![]
-
带内积的希尔伯特空间:

希尔伯特空间是一个抽象的向量空间,它仅仅是对欧几里得空间概念的推广。因此,我们关于向量代数和微积分的方法可以从二维和三维欧几里得空间扩展到任意维数甚至无限维数。
自然地,如果我们要在流形上定义微积分,我们希望能够求导,但这不像曲线那样清晰。对于流形,我们利用切空间,使得![],方向导数是![],它告诉我们f在点p沿方向F(p)的变化量。而内在梯度算子,告诉我们f变化最陡的方向,可以通过以下方程计算:

内在散度算子通过以下方程计算场F在点p的净流量:

使用这个,我们可以找到梯度的正式伴随算子,如下所示:

现在,我们可以找到拉普拉斯算子![],它通过![]计算f(x)与点p附近f的平均值之间的差异,这告诉我们拉普拉斯算子是等距不变的(等距是度量空间之间保持距离的变换。然而,在几何学中,我们有时希望对象的形状以不受等距影响的方式定义。这意味着对象可以被变形,使其弯曲但不被拉伸,从而不影响内在的距离),是正定的,且是对称的,如下所示:

离散流形
让我们暂时回顾一下第五章,图论,我们在其中学习了图论。简单回顾一下,图G由顶点![]和边![]组成,且无向边![]当且仅当![]。加权图的边具有权重![],对于所有![],顶点也可以有权重![],即顶点权重![]。
我们之所以关心图,是因为我们也可以在图上做微积分。为此,我们需要定义一个顶点场![]和一个边场。带有内积的希尔伯特空间是![]和![]。
正如我们现在所知道的,在微积分中,我们非常喜欢梯度,因此我们自然可以为图定义一个梯度算子,![,],给我们带来!,以及一个散度算子,![,],它生成![],并且是梯度算子的伴随算子,![]。
图拉普拉斯算子,![,]定义为![]。通过结合前面两个方程,我们可以得到如下结果:

如同流形的情况,这计算了f与其局部平均值之间的差异(即邻近节点的平均值)。我们可以将其重新写成一个正半定的方阵:

我们还可以将其写为一个未归一化的拉普拉斯算子,其中A = I:

最后,我们可以将其写为随机游走拉普拉斯算子,其中A = D:

这里,![],![],和![]。
使用图形,我们可以构建离散流形,即使用顶点,![],边,![],和面,![]来描述三维物体。这通常被称为三角网格。在一个流形网格中,每条边由两个面共享,每个顶点有一个循环。
在继续之前,让我们使用余切公式重新定义三角网格上的拉普拉斯算子,这可以为具有坐标![]的嵌入网格定义,并且是基于边长的。
嵌入网格的余切拉普拉斯算子如下:

这里,,且余切拉普拉斯算子在边长的定义下如下:

这里,![],s是半周长,且![]。
谱分解
为了理解谱分析,我们必须首先定义紧致流形M上的拉普拉斯算子,它有可数多个特征函数:

这是针对![]的。
由于对称性特性,特征函数将是实数且正交归一化的,这给我们带来以下结果:

这里,特征值是非负的,也就是说,![]。
对于二维流形,我们通常使用 Weyl 定律来描述特征值的渐近行为,形式如下:

使用特征函数和特征值,我们可以将图拉普拉斯算子特征分解为以下形式:

这里,![] 和 ![]。
现在,如果我们将其作为一个广义特征问题来提出,我们可以从前面的方程中得到以下结果,假设有A正交特征向量,![]:

如果我们通过代入来改变变量,![],我们将得到标准特征问题:

这里,特征向量是正交的,也就是说,![]。
图神经网络
图神经网络是几何深度学习的典型神经网络,正如其名所示,它们在基于图的数据(如网格)上表现尤为出色。
现在,假设我们有一个图G,它有一个二进制邻接矩阵A。然后,我们有另一个矩阵X,其中包含所有节点特征。这些特征可以是文本、图像、类别、节点度、聚类系数、指示向量等。这里的目标是通过局部邻域生成节点嵌入。
如我们所知,图上的节点有邻居节点,在这种情况下,每个节点试图通过神经网络从其邻居处聚合信息。我们可以将网络邻域视为计算图。由于每个节点与不同节点之间有边,因此每个节点都有一个独特的计算图。
如果我们回顾卷积神经网络,我们会发现卷积是一种窗口操作,我们可以滑动窗口并将输入数据汇总为简化的形式。聚合操作与卷积操作的工作原理类似。
让我们深入探讨一下,看看它们在数学上的运作原理。
在每一层,节点都有嵌入,初始嵌入等同于节点特征:

k^(th)层的* v *嵌入如下所示:

这对所有 k > 0 都适用,其中![]是* v 的前一层嵌入,![]是邻居的前一层嵌入的平均值。在训练过程中,模型学习W[k]和B[k],并且每个节点在经过K*层邻域聚合后的输出嵌入如下所示:

为了生成高质量的嵌入,我们在z[v]上定义一个损失函数,并将嵌入传递给它,之后我们执行梯度下降以训练聚合参数。
在监督任务的情况下,我们可以定义损失函数如下:

假设我们有以下无向图:

在此基础上,我们想要计算实心节点的更新,如下所示:

要计算更新,我们可以使用以下方程:

这里,N^((i))是节点i的邻居,c[i,j]是归一化常数。
频谱图卷积神经网络(Spectral Graph CNNs)
如其名所示,频谱图卷积神经网络(Spectral Graph CNNs)使用频谱卷积,我们定义如下:

这里,![]。我们可以将其重新写为矩阵形式如下:

这不是平移不变的,因为G没有循环结构。
现在,在频谱域中,我们定义卷积层如下:

这里,![],![],和![]是一个 n×n 的频谱滤波器系数对角矩阵(这些系数是基依赖的,意味着它们不能跨图之间推广,仅限于单一域),ξ是应用于顶点函数值的非线性。
这意味着,如果我们在一个域上使用基Φ学习卷积滤波器,它将不能转移或应用于具有基Ψ的另一个任务。这并不意味着我们不能创建可以用于不同域的基——我们可以——然而,这需要使用联合对角化过程。但这样做需要事先了解两个域以及它们如何相互关联。
我们还可以在非欧几里得域中定义池化函数。我们称之为图粗化,在其中,只有一部分α < 1的图节点被保留下来。如果我们在不同分辨率下拥有图拉普拉斯算子的特征向量,那么它们将通过以下方程关联:

这里,Φ是一个n × n矩阵,
是一个αn × αn矩阵,P是一个αn × n的二进制矩阵,表示粗化图中第i个顶点在原图中的位置。
图神经网络(GNNs),就像我们在前几章学习的神经网络一样,也可能发生过拟合。为了避免这种情况发生,我们通过适应学习复杂度来尽量减少模型中自由参数的总数。为此,我们使用滤波器在频域中的空间局部化。在欧几里得领域中,我们可以将其写为:

这告诉我们,为了学习一个特征不仅在原始领域中局部化良好,而且在其他位置也能共享的层,我们必须学习平滑的谱乘子。谱乘子的参数化如下:

这里,![] 是一个固定大小为 k × q 的插值矩阵,α 是大小为 q 的插值系数向量。
混合模型网络
现在我们已经看到了一些 GNN 工作的示例,让我们更进一步,看看如何将神经网络应用于网格。
首先,我们使用一个在局部 d 维伪坐标系统中定义的补丁, ![],围绕 x。这被称为大地测量极坐标。在这些坐标上,我们应用一组参数化核, ![],产生局部权重。
这里的核不同之处在于它们是高斯型的,而不是固定的,并且是通过以下方程式产生的:

这些参数(![] 和 ![])是可训练的并且是学习得到的。
可以定义带有滤波器 g 的空间卷积如下:

这里,![] 是顶点 i 处的特征。
之前,我们提到了大地测量极坐标,但它们是什么?让我们定义它们并了解一下。我们可以将它们写成如下:

这里,![] 是 i 和 j 之间的大地测量距离,![] 是从 i 到 j 的大地测量方向。然而,在这里,方向是有些模糊的。
现在,我们可以定义角度最大池化(即旋转滤波器),如下所示:

3D 人脸识别
让我们继续看看这如何应用于现实世界中的问题,例如 3D 人脸识别,它被广泛应用于手机、安全等领域。在 2D 图像中,这通常依赖于姿态和光照,并且我们无法获取深度信息。由于这个限制,我们改用 3D 人脸,以便不用担心光照条件、头部朝向和各种面部表情。对于这个任务,我们将使用网格数据。
在这种情况下,我们的网格构成了一个无向的连通图,G = (V, E, A),其中 |V| = n 是顶点,E 是边的集合,且![]包含了d-维伪坐标,![],其中![]。节点特征矩阵表示为![],其中每个节点包含d-维特征。我们接着定义特征图的 l^(th) 通道为 f[l],其中 i^(th) 节点表示为 fl。
伪坐标 u(i, j) 决定了网格中如何聚合特征,正如我们所知道的,网格是由更小的三角形构成的,我们可以从所有节点 i 到节点 j 计算伪坐标。在这里,我们将使用全局归一化的笛卡尔坐标:

这使得我们能够将空间关系映射到固定区域。
我们使用![]初始化权重,其中 l[in] 是 k^(th) 层输入特征的维度。
现在,我们可以从相邻节点计算特征聚合到节点 i,如图所示![],具体如下:

这里,![]。![] 是 B-样条的基础,阶数为 m,而![] 是可以学习的参数。
这是一个分类任务,我们将使用交叉熵作为我们的损失函数。具体如下:

这里,![] 和 Y 是标签矩阵。
至此,我们可以结束这一章关于几何深度学习的内容。
总结
在本章中,我们学习了一些重要的数学主题,如欧几里得数据与非欧几里得数据及流形之间的区别。接着,我们学习了深度学习领域中一些引人入胜且新兴的主题,这些主题在许多传统深度学习算法已证明无效的领域中有着广泛的应用。这类新的神经网络,被称为图神经网络,极大地扩展了深度学习的实用性,使其能够在非欧几里得数据上工作。章末,我们还看到了图神经网络的一个实际应用案例——三维人脸识别。
本书到此结束,恭喜你成功完成了所提供的课程!


开始,得出如下结论:
对所有
都成立。
和 
时,![]

















,当 ![]
与v[1]和v[2]相关(即v[1]和v[2]是
的端点)。
浙公网安备 33010602011771号