深入探讨机器学习算法——机器学习算法

217 阅读20分钟

本章内容包括:

  • 机器学习算法的类型
  • 从零开始学习算法的重要性
  • 贝叶斯推理和深度学习简介
  • 从零开始实现机器学习算法的软件

算法是为完成特定任务而需要的步骤序列。算法接受输入,执行一系列操作,并生成所需的输出。最简单的算法示例是排序:给定一个整数列表,我们执行一系列操作以生成一个排序后的列表。排序后的列表使我们能够更好地组织信息,并在数据中找到答案。

关于算法,两个常见的问题是它运行的速度(运行时间复杂度)和它占用的内存(内存或空间复杂度),其中输入的大小为n。例如,基于比较的排序算法(如我们稍后将看到的)具有O(n log n)的运行时间复杂度,并且需要O(n)的内存存储。

排序有许多不同的方法,在每种情况下,经典的算法范式下,算法设计师会创建一套指令。试想一下,在一个世界里,你可以基于一系列输入和输出示例来学习这些指令。这就是机器学习算法范式的设定。就像人类大脑在玩连接点游戏或勾画自然景观时通过比较每一步的预期输出与实际输出,并填补空白来学习一样,机器学习(ML)算法也如此。概括来说,这就是(监督式)机器学习算法的工作方式。在训练过程中,机器学习算法通过优化目标函数,基于训练样本学习规则(例如,分类边界)。在测试过程中,机器学习算法将先前学习到的规则应用于新的输入数据点,并提供预测,如图1.1所示。

image.png

1.1 机器学习算法的类型

让我们稍微解析一下前面的段落,并引入一些符号。本书重点介绍可以分为以下几类的机器学习算法:监督学习、无监督学习和深度学习。在监督学习中,任务是从输入 x 到输出 y 学习一个映射 f,给定一个训练数据集 D = {(x1, y1), …, (xn, yn)},其中包含 n 个输入输出对。换句话说,我们被给定了 n 个示例,展示了在给定输入的情况下,输出应该是什么样的。输出 y 通常也称为标签,它是告诉算法正确答案的监督信号。

监督学习可以根据我们要预测的数量进一步细分为分类和回归。如果我们的输出 y 是离散的量(例如,K 个不同的类别),我们面临的是分类问题。另一方面,如果我们的输出 y 是连续的量(例如,实数,如股票价格),我们面临的是回归问题。

因此,问题的性质根据我们要预测的 y 的量而变化。我们的目标是尽可能接近 y 的真实值。

衡量性能或接近真实值的常见方法是通过损失函数。损失函数计算预测值与真实标签之间的距离。设 y = f(x; θ) 为我们的机器学习算法,它将输入示例 x 映射到输出标签 y,且由 θ 参数化,其中 θ 捕捉了机器学习算法所有可学习的参数。那么,我们可以将分类损失函数定义为误分类样本的数量,如方程 1.1 所示。

image.png

在这里,1[] 是一个指示函数,当其中的参数为真时,其值为 1,否则为 0。方程 1.1 中的表达式表示我们正在累加所有预测 f(xi; θ) 与真实标签 yi 不匹配的实例,并将其除以总示例数 n。换句话说,我们正在计算平均误分类率。我们的目标是最小化损失函数(即找到一组参数 θ,使得误分类率尽可能接近零)。请注意,分类问题有许多其他损失函数,如交叉熵,我们将在后续章节中进行探讨。

对于连续标签或响应变量,一个常见的损失函数是均方误差(MSE)。MSE 测量我们的估计值与真实值之间的偏差,如方程 1.2 所示。

image.png

正如我们从方程中可以看到的那样,我们将预测值与真实标签相减,平方后,对数据点的结果进行平均。通过平方操作,我们消除了负号,并惩罚了与真实值的较大偏差。

机器学习的一个核心目标是能够对未见过的示例进行泛化。我们不仅希望在训练数据(已经标记好的数据)上取得高准确度(低损失),还希望在新的、未见过的测试数据上也能表现出高准确度。正是这种泛化能力使得机器学习如此具有吸引力:如果我们能设计出能够“走出”训练框的机器学习算法,我们就更接近人工通用智能(AGI)。

在无监督学习中,我们没有得到标签 y,也不是在学习输入和输出示例之间的映射;相反,我们关注的是理解数据本身。通常,这意味着要发现数据中的模式。如果我们将高维数据投影到低维空间中,发现模式通常会变得更容易,如图 1.2 所示。因此,在无监督学习中,我们的训练数据集由 D = {x1, …, xn} 的 n 个输入示例组成,没有任何对应的标签 y。无监督学习的最简单示例是寻找数据中的聚类。直观地说,我们知道属于同一聚类的数据点具有相似的特征。事实上,聚类内的数据点可以通过聚类中心作为示例来表示,并可以作为数据压缩算法的一部分使用。或者,我们可以查看在投影的低维空间中各聚类之间的距离,以了解不同群体之间的相互关系。此外,距离所有现有聚类较远的点可以视为异常,这可以引出一个异常检测算法。正如你所看到的,来自无监督学习的有趣应用场景是无穷无尽的,在本书中,我们将从零开始学习一些最具吸引力的算法。

image.png

现代机器学习算法的另一个非常重要的领域是深度学习。这个名字来源于一系列计算层堆叠在一起形成计算图。图的深度指的是顺序计算,而宽度则指并行计算。

正如我们将看到的,深度学习模型通过反向传播算法逐渐调整其参数,直到它们满足目标函数。深度学习模型由于能够以高精度解决复杂问题,已经在各个行业中得到了广泛应用。例如,图 1.3 显示了一个用于情感分析的深度学习架构。我们将在后续章节中深入了解各个模块的具体含义。

image.png

深度学习是一个非常活跃的研究领域,我们将在本书中重点讨论现代深度学习算法。例如,在自监督学习中,使用于 transformer 模型,我们利用自然语言的上下文和结构作为监督信号,从而从数据本身提取标签。除了深度学习在自然语言处理(NLP)和计算机视觉(CV)中的经典应用外,我们还将讨论生成模型、时间序列数据的预测以及关系图数据的学习。

1.2 为什么要从零开始学习算法?

从零开始理解机器学习算法对读者有几个宝贵的好处。首先,我们将能够为任务选择合适的算法。通过了解一个算法的内部工作原理,我们可以理解它的缺点、算法推导中所做的假设,以及在不同数据场景下的优势。这使我们在选择问题解决方案时能够作出明智的判断,并通过排除不适用的方法节省时间。

其次,我们将能够向利益相关者解释给定算法的结果。能够在工业或学术环境中解读并向观众呈现结果是一个机器学习算法设计师的重要特质。

第三,我们将能够利用本书中培养的直觉来排除高级机器学习问题。在分解复杂问题并理解问题出错的地方时,通常需要强大的基础知识和算法直觉。本书将帮助读者构建最小工作示例,并在现有算法的基础上开发和调试更复杂的模型。

第四,当现实世界中出现新情况时,我们将能够扩展一个算法——尤其是在教科书算法或库无法直接使用时。你将在本书中获得的深入理解将帮助你修改现有算法以满足你的需求。

最后,我们常常希望提高现有模型的性能。本书中讨论的原理将使读者能够实现这一目标。总之,从零开始理解机器学习算法将帮助你选择合适的算法、解释结果、排除高级问题、将算法扩展到新场景,并提高现有算法的性能。

1.3 数学背景

为了从零开始学习机器学习算法,复习一些应用概率、微积分和线性代数的概念是一个好主意。对于概率的复习,建议读者查阅 Dimitri Bertsekas 和 John Tsitsiklis 的《Introduction to Probability》(Athena Scientific, 2002)。读者应该熟悉连续和离散随机变量、条件分布和边际分布、贝叶斯定理、马尔可夫链和极限定理。

对于微积分的复习,我推荐 James Stewart 的《Calculus》(Thomson Brooks/Cole, 2007)。读者应该熟悉微分和积分的规则、数列和级数、向量和空间几何、偏导数和多维积分。

最后,Gilbert Strang 的《Introduction to Linear Algebra》(Wellesley-Cambridge Press, 2016)是学习线性代数的好书。读者应该熟悉向量空间、矩阵、特征值和特征向量、矩阵范数、矩阵分解、正定矩阵和半正定矩阵以及矩阵微积分。除了上述书籍,附录 A 中还列出了可以丰富你对本书中算法理解的推荐书目。

1.4 贝叶斯推理与深度学习

贝叶斯推理使我们能够根据观察到的数据更新我们对世界的信念。我们的思维中持有多种精神模型,用于解释世界的不同方面,通过观察新的数据点,我们可以更新潜在的表示并改善对现实的理解。任何概率模型都由一组参数 θ 描述,这些参数被建模为随机变量,控制模型的行为,并且与数据 x 相关。

贝叶斯推理的目标是找到后验分布 p(θ|x)(给定数据后的参数分布),以便更好地捕捉现实的某一方面。后验分布与似然 p(x|θ)(给定参数后的数据分布)和先验 p(θ)(参数的初始分布)的乘积成正比,这一点可以通过贝叶斯定理(方程 1.3)得出。

image.png

先验分布 p(θ) 是我们对世界的初始信念,可以是非信息性的(例如,对所有可能的状态进行均匀分布)或信息性的(例如,基于特定领域的经验)。此外,我们的推理结果依赖于所选择的先验——不仅仅是先验参数的值,还包括先验的函数形式。我们可以想象一个更新链,其中随着更多数据的获取,先验转变为后验,形成一个贝叶斯引擎,如图 1.4 所示。我们可以看到,随着我们观察到更多数据,先验是如何通过贝叶斯定理更新为后验的。

image.png

具有与后验分布相同形式的先验被称为共轭先验,这通常是首选的,因为它们通过封闭形式的更新简化了计算。分母 Z=p(x)=∫p(x∣θ)p(θ)dθZ = p(x) = \int p(x|\theta)p(\theta) d\thetaZ=p(x)=∫p(x∣θ)p(θ)dθ 被称为归一化常数或配分函数,由于在高维参数空间中的积分,通常是不可计算的。在本书中,我们将探讨几种估计 ZZZ 的技术。

我们可以将模型中不同随机变量之间的关系建模为图形,如图 1.5 所示,这产生了概率图模型。图中的每个节点代表一个随机变量(RV),每条边代表一个条件依赖关系。模型参数由清晰的节点表示,而阴影节点表示观察到的数据,矩形板表示随机变量的副本或重复。图的拓扑结构本身会根据你感兴趣的应用而变化。然而,贝叶斯推理的目标保持不变:在给定观察数据的情况下,找到模型参数的后验分布。

image.png

与概率图模型(PGMs)不同,后者的连接由领域专家指定,深度学习模型通过反向传播算法自动学习世界的表示,目标是最小化一个目标函数。深度神经网络(DNNs)由多个层组成,这些层由权重矩阵和偏置参数进行参数化。从数学上讲,DNNs 可以表示为各个层函数的组合,如方程 1.4 所示。

image.png

在这里,fl(x)=f(x;θl)f_l(x) = f(x; \theta_l)fl​(x)=f(x;θl​) 是第 lll 层的函数。DNN 的组合形式让我们想起了在进行随机梯度下降时对参数求导的链式法则。在本书中,我们将讨论几种不同类型的 DNN,如卷积神经网络(CNNs)、循环神经网络(RNNs)、变换器(Transformers)和图神经网络(GNNs),这些应用涵盖了从计算机视觉到金融等多个领域。

1.4.1 贝叶斯推理的两大阵营:MCMC 和 VI

马尔可夫链蒙特卡洛(MCMC)是一种从高维参数空间中采样的方法,用于逼近后验分布 p(θ∣x)p(\theta|x)p(θ∣x)。在统计学中,采样指的是从给定的概率分布中生成一个随机样本。针对高维参数空间的采样有许多方法。正如我们将在后续章节中看到的,MCMC 基于构建一个马尔可夫链,其平稳分布是我们感兴趣的目标密度(即后验分布)。通过在状态空间上执行随机游走,我们在每个状态 θ\thetaθ 中停留的时间比例将与 p(θ∣x)p(\theta|x)p(θ∣x) 成正比。因此,我们可以使用蒙特卡洛积分来推导与后验分布相关的感兴趣量。

在讨论高维参数空间之前,让我们先看一下如何从低维空间进行采样。从单变量分布中采样的最常用方法被称为反向累积分布函数(CDF)方法;它的定义是 CDFX(x)=P(X≤x)\text{CDF}_X(x) = P(X \leq x)CDFX​(x)=P(X≤x)(见图 1.6)。

image.png

例如,让我们考察一个指数随机变量(RV),其概率密度函数(PDF)和累积分布函数(CDF)如方程 1.5 所示。

image.png

image.png

反向累积分布函数(inverse CDF)可以通过方程 1.6 所示的方法找到。

image.png

因此,为了从指数随机变量生成一个样本,我们首先需要从均匀随机变量 u∼Unif(0,1)u \sim \text{Unif}(0, 1)u∼Unif(0,1) 中生成一个样本,并应用变换 −ln⁡(1−u)λ-\frac{\ln(1 - u)}{\lambda}−λln(1−u)​。通过生成足够多的样本,我们可以达到任意精度。MCMC 的一个挑战是确定如何高效地从高维分布中生成样本。在本书中,我们将讨论两种方法:吉布斯采样和梅特罗波利斯-哈斯廷斯(MH)采样。

变分推理(VI)是一种基于优化的方法,用于逼近后验分布 p(x)p(x)p(x)。我们在这里简化了符号,假设一个通用分布 p(x)p(x)p(x) 表示后验分布。VI 的基本思想是从一个可处理的分布族中选择一个近似分布 q(x)q(x)q(x),然后使这个近似分布尽可能接近真实的后验分布 p(x)p(x)p(x)。可处理的分布指的是那些容易计算的分布。正如我们将在本书的均场部分看到的,近似的 q(x)q(x)q(x) 可以采用完全分解的形式来表示联合后验分布。这种分解大大加速了计算过程。

接下来,我们介绍了 Kullback-Leibler(KL)散度,并用它来衡量我们近似分布与真实后验的接近程度。图 1.7 显示了 KL 散度的两种版本。

image.png

原始分布 p(x)p(x)p(x) 是一个双峰高斯分布(也称为包含两个分量的高斯混合分布),而近似分布 q(x)q(x)q(x) 是一个单峰高斯分布。正如我们在图 1.7 中看到的,我们可以通过使 q(x)q(x)q(x) 具有较高的方差来近似双峰分布的两个峰值,位于中心,以捕捉双峰分布的支撑区域;或者让 q(x)q(x)q(x) 的一个峰值位于双峰分布的某一个模式上,如右侧所示。这是方程 1.7 中前向和反向 KL 散度定义的结果。正如我们在后续章节中将看到的,通过最小化 KL 散度,我们实际上将变分推断(VI)转化为一个优化问题。

image.png

image.png

1.4.2 现代深度学习算法

多年来,深度学习架构已经从基础的 LeNet CNN 构建块发展到视觉 Transformer 架构。某些架构设计主题,如 ResNet 模型中的残差连接,已成为现代神经网络架构的标准选择,可以支持任意深度的网络,并开始逐渐显现出来。在本书的后续章节中,我们将介绍现代深度学习算法,包括基于自注意力机制的 Transformer;生成模型,如变分自编码器(VAE);以及图神经网络(GNN)。
我们还将讨论摊销变分推断(amortized variational inference),这是一个有趣的研究领域,它结合了深度神经网络的表达能力和表示学习能力,以及概率图模型的领域知识。我们将看到混合密度网络(Mixture Density Networks)的一个应用案例,在这个应用中,我们使用神经网络将观察空间映射到近似后验分布的参数。

大多数深度学习模型属于窄人工智能(Narrow AI)类别,在特定数据集上表现出高性能。虽然能够在一小部分任务上取得优异成绩是一项有用的技能,但我们希望能够从窄人工智能向人工通用智能(AGI)进行泛化。

1.5 实现算法

从零开始学习算法的一个关键部分是软件实现。编写高效的代码非常重要,既要在数据结构的使用上高效,也要在算法复杂度上低效。在本章中,我们将把代码的功能部分组织到类中,并从头开始实现不同的计算方法。因此,你将接触到大量的面向对象编程(OOP),这是流行的机器学习库(如 scikit-learn)中的常见做法。虽然本书的目的是从零开始编写所有代码(不依赖第三方库),但如果可用的话,我们仍然可以使用机器学习库(例如 scikit-learn,scikit-learn.org/stable/)来检查我们实现的结果。我们将在本书中全程使用 Python 语言。

1.5.1 数据结构

数据结构是一种存储和组织数据的方式。每种数据结构提供不同的性能权衡,有些比其他结构更适合特定任务。在我们实现机器学习算法时,我们将主要使用线性数据结构,如固定大小的数组,因为数组中访问元素的时间是常数时间 O(1)。我们还将频繁使用动态可调整大小的数组(例如 Python 中的列表),以跟踪多次迭代中的数据。

在本书中,我们还将使用非线性数据结构,如映射(字典)和集合。我们选择这些数据结构,是因为有序字典和有序集合是基于自平衡二叉搜索树(BST)构建的,这些树保证了 O(n log n) 的插入、查找和删除操作。最后,哈希表或无序映射是另一种常用且高效的数据结构,假设没有碰撞的情况下,访问时间为 O(1)。

1.5.2 问题解决范式

本书中的大多数机器学习算法可以归纳为四种问题解决范式之一:完全搜索、贪心算法、分治法和动态规划。

完全搜索 是通过遍历整个搜索空间来寻找解决方案的一种方法。在机器学习中,完全搜索的一个例子是通过完全枚举进行精确推断。在精确推断过程中,我们必须完全指定多个概率表来进行计算。

贪心算法 在每一步选择局部最优解,并期望最终能够达到全局最优解。贪心算法通常依赖于贪心启发式。贪心算法在机器学习中的一个例子是传感器布置。例如,给定一个房间和多个温度传感器,我们希望以一种方式布置传感器,以最大化房间的覆盖面积。

分治法 是一种将问题分解为更小、独立的子问题,然后结合每个子问题的解决方案的技术。使用分治法的机器学习例子可以在 CART 决策树算法中找到。正如我们在未来的章节中将看到的,在 CART 算法中,通过优化分类目标(例如,基尼指数),找到分裂决策树的最优阈值。相同的过程应用到深度增加一的树上,形成了递归算法。

动态规划(DP) 是一种将问题分解为更小、重叠的子问题,计算每个子问题的解决方案并将结果存储在 DP 表中的技术。在强化学习(RL)中使用动态规划的一个例子是求解贝尔曼方程。当状态数较少时,我们可以使用动态规划以表格方式计算 Q 函数。

总结

  • 算法是实现特定任务所需的一系列步骤。机器学习算法可以分为以下几类:监督学习、无监督学习和深度学习。

  • 从零开始理解算法将帮助你选择适合任务的算法、解释结果、排查高级问题,并提高现有模型的性能。

  • 贝叶斯推断使我们能够根据观察到的数据更新我们对世界的信念,而深度学习模型则通过反向传播算法学习世界的表示,从而最小化目标函数。贝叶斯推断有两个流派:马尔可夫链蒙特卡罗(MCMC)和变分推断(VI)。这两个流派分别专注于采样和近似后验分布。

  • 编写高效的代码非常重要,既要在数据结构的使用上高效,也要在算法复杂度上低效。本书中的大多数机器学习算法可以归纳为四种问题解决范式:完全搜索、贪心算法、分治法和动态规划。