UCLA-模式识别与机器学习笔记-全-
UCLA 模式识别与机器学习笔记(全)
1:模式识别与机器学习导论 🎯





在本节课中,我们将要学习模式识别与机器学习的基本概念。我们将从一个简单的例子出发,探讨如何利用数据中的特征来预测结果,并理解最优分类器的构建原理。

概述
模式识别与机器学习的核心任务是根据输入数据(特征)来预测输出结果(目标)。例如,给定一张图片,判断它是猫还是狗;或者根据一封邮件的内容,判断它是否为垃圾邮件。本节课我们将从一个非常简单的二元分类问题开始,逐步引入核心概念。
从简单例子开始:泰坦尼克号生存预测
假设我们有一个关于泰坦尼克号乘客的数据表。每一行代表一个人,包含诸如乘客等级、年龄、性别以及是否幸存等信息。我们的目标是预测一个人是否幸存。
在这个例子中,我们将幸存状态作为我们的预测目标 Y,它取值为0(未幸存)或1(幸存)。我们首先只使用一个非常简单的特征:性别 X,它取值为“女性”(F)或“男性”(M)。
我们的数据可以看作是从一个未知的联合分布 P 中独立同分布地抽取的样本。X 和 Y 都是随机变量。


最简单的分类器:多数规则



如果我们完全忽略特征 X,只根据 Y 的分布来预测,最简单的分类器就是多数规则。它总是输出出现概率更高的那个类别。




具体来说,分类器 F_majority 是一个常数函数:
F_majority(x) = argmax_{d ∈ {0,1}} P(Y = d)
在我们的数据中,P(Y=0)=0.62,P(Y=1)=0.38。因此,多数规则分类器总是预测 Y=0(未幸存)。这个分类器的误分类率(预测错误的概率)就是 P(Y=1) = 0.38。

上一节我们介绍了不依赖任何特征的最简单分类器。本节中我们来看看如何利用特征 X 来构建更好的分类器。

利用特征:条件概率与贝叶斯分类器


当我们观察到特征 X 的具体取值(例如,性别为女性)时,预测 Y 的更合理方式是基于条件概率。我们不再看 Y 的整体分布,而是看在给定 X 的条件下,Y 的分布。





对于给定的 X = x,最优的预测是选择条件概率更大的那个类别:
F_bayes(x) = argmax_{d ∈ {0,1}} P(Y = d | X = x)
这个分类器被称为贝叶斯分类器。


以下是计算条件概率的步骤:
- 从联合分布表中,我们可以计算出所需的边际概率和条件概率。
- 例如,
P(Y=1 | X=F) = P(Y=1, X=F) / P(X=F) = 0.26 / 0.36 ≈ 0.72。 - 类似地,
P(Y=1 | X=M) = 0.12 / 0.64 ≈ 0.19。




因此,贝叶斯分类器的决策规则是:
- 如果
X = F(女性),则预测Y=1(幸存),因为P(Y=1|X=F) > P(Y=0|X=F)。 - 如果
X = M(男性),则预测Y=0(未幸存),因为P(Y=0|X=M) > P(Y=1|X=M)。




评估分类器性能:误分类率

为了比较分类器的好坏,我们需要一个评估标准。一个常用的标准是误分类率,即分类器做出错误预测的概率。


对于一个分类器 F(x),其误分类率 R(F) 定义为:
R(F) = P( Y ≠ F(X) )
我们可以通过两种方式计算 R(F):

方法一:直接根据联合分布计算
误分类事件是以下两个互斥事件的并集:
X = F且Y = 0(对女性预测了幸存,但她实际未幸存)X = M且Y = 1(对男性预测了未幸存,但他实际幸存)
因此,R(F_bayes) = P(X=F, Y=0) + P(X=M, Y=1) = 0.10 + 0.12 = 0.22。

方法二:利用全概率公式计算
通过条件概率计算:
R(F) = P(Y ≠ F(X) | X=F) * P(X=F) + P(Y ≠ F(X) | X=M) * P(X=M)
对于贝叶斯分类器:
- 当
X=F时,我们预测Y=1,所以错误发生在Y=0时,即P(Y=0|X=F)=0.28。 - 当
X=M时,我们预测Y=0,所以错误发生在Y=1时,即P(Y=1|X=M)=0.19。
因此,R(F_bayes) = 0.28*0.36 + 0.19*0.64 ≈ 0.22。
可以看到,贝叶斯分类器的误分类率(0.22)远低于多数规则分类器的误分类率(0.38)。利用特征 X 显著提升了预测性能。
最优性证明:贝叶斯分类器是最优的




为什么贝叶斯分类器 F_bayes 是最优的?我们可以从最小化误分类率的角度来理解。


对于任意一个分类器 F(x),其误分类率可以写为:
R(F) = E_X [ P( Y ≠ F(X) | X ) ]
其中 E_X 表示对 X 的分布求期望。由于 P(X) 是固定的,要最小化 R(F),就需要对每一个可能的 X = x,最小化条件误分类概率 P( Y ≠ F(x) | X=x )。





对于给定的 x,F(x) 只能取 0 或 1。因此:
- 如果设置
F(x) = 1,则条件误分类概率为P(Y=0 | X=x)。 - 如果设置
F(x) = 0,则条件误分类概率为P(Y=1 | X=x)。
显然,为了最小化错误概率,我们应该选择条件概率更大的那个类别作为预测结果,即:
F*(x) = argmax_{d ∈ {0,1}} P(Y = d | X = x)
这正是贝叶斯分类器的定义。因此,贝叶斯分类器在所有可能的分类器中,实现了最小的可能误分类率。这个最小的误分类率被称为贝叶斯错误率,它反映了数据本身固有的、无法消除的不确定性。

在我们的例子中,0.22 就是使用性别特征 X 时的贝叶斯错误率,任何分类器都无法取得比这更低的错误率。

总结

本节课中我们一起学习了模式识别与机器学习的基础:
- 问题定义:我们引入了从特征
X预测目标Y的监督学习框架。 - 简单基准:我们首先构建了不依赖特征的多数规则分类器,并计算了其误分类率作为性能基准。
- 利用特征:我们引入了条件概率的概念,并构建了利用特征
X的贝叶斯分类器F_bayes(x) = argmax_d P(Y=d|X=x)。 - 性能评估:我们学习了使用误分类率
R(F) = P(Y ≠ F(X))来量化分类器的性能,并计算比较了两种分类器的误分类率。 - 最优性:我们证明了贝叶斯分类器在最小化误分类率的意义下是最优的,其错误率(贝叶斯错误率)是理论下限。



这个简单的二元分类例子揭示了机器学习的一个核心思想:通过利用相关特征和条件概率,我们可以构建比简单猜测更智能、更准确的预测模型。在接下来的课程中,我们将把这个框架扩展到更复杂的特征和更一般的场景。
2:模式识别与机器学习导论 - 第二讲 🧠

在本节课中,我们将学习模式识别与机器学习的基本概念,特别是如何构建一个简单的分类器。我们将从概率框架出发,探讨最优分类器的定义,并学习如何在实际数据中应用这些理论。
概述
上一节我们介绍了模式识别的基本问题。本节中,我们将深入探讨如何利用概率框架构建一个分类器,并学习如何评估其性能。
概率框架与最优分类器
我们首先将问题建模为概率问题。设特征为随机变量 X,目标(响应)为随机变量 Y。它们之间的关系由一个联合分布 P(X, Y) 描述。在二元分类问题中,Y 的取值为 0 或 1。
最简单的分类器是忽略所有特征的“多数规则”分类器。它总是预测出现概率更高的类别。例如,如果 P(Y=1) < 0.5,则总是预测 Y=0。
然而,当我们引入特征 X 后,最优决策应基于条件概率 P(Y | X)。对于给定的特征值 x,我们选择使条件概率 P(Y=d | X=x) 最大的决策 d。这被称为贝叶斯最优分类器,其决策规则为:
f*(x) = argmax_{d ∈ {0,1}} P(Y=d | X=x)
这个规则等价于最小化错误分类概率 P(Y ≠ f(X))。
损失函数与风险

为了更一般地衡量分类器的性能,我们引入损失函数 L(Y, Ŷ)。它量化了真实标签 Y 与预测标签 Ŷ 之间的“代价”。
我们之前使用的衡量标准(错误率)对应于 0-1 损失:
L_{0-1}(Y, Ŷ) = I(Y ≠ Ŷ)
其中 I(·) 是指示函数。该损失的期望值 E[L(Y, Ŷ)] 就是错误分类概率。
更一般地,我们可以定义非对称的代价。例如,在疾病诊断中,将健康人误诊为患病(假阳性)和将患者误诊为健康(假阴性)的代价可能不同。这被称为代价敏感学习。
在一般损失函数下,最优分类器变为最小化条件风险:
f*(x) = argmin_{d} E[L(Y, d) | X=x]
对于 0-1 损失,这简化为之前的最大后验概率规则。
从数据中学习:经验估计
在实际中,我们并不知道真实的概率分布 P(X, Y),我们只有从该分布中独立同分布采样得到的训练数据 {(X_i, Y_i)}_{i=1}^n。
最直接的方法是使用经验分布(即样本比例)来估计联合概率。对于离散特征,条件概率 P(Y=1 | X=x) 的估计为:
\hat{η}(x) = \hat{P}(Y=1 | X=x) = (∑_{i=1}^n I(X_i = x, Y_i = 1)) / (∑_{i=1}^n I(X_i = x))
这相当于在特征 X=x 的样本子集中,计算 Y=1 的比例。
得到估计的回归函数 \hat{η}(x) 后,我们的“插件”分类器规则为:
\hat{f}(x) = I(\hat{η}(x) > 1/2)
决策树与局部平均
上述估计方法可以直观地用决策树表示。从根节点(使用多数规则)开始,根据特征 X 的不同取值进行分支,在每个叶节点上计算 Y 的条件概率估计并做出决策。
经验条件概率估计公式可以重写为加权平均的形式:
\hat{η}(x) = ∑_{i=1}^n w_i(x) Y_i
其中权重 w_i(x) = I(X_i = x) / (∑_{j=1}^n I(X_j = x))。这揭示了其本质:对于给定的 x,我们只对具有相同特征值的训练样本的 Y 进行平均。
这为后续推广奠定了基础。当特征是连续值时,我们无法找到完全相同的 X_i,但可以平均“相似”或“邻近”的样本点,这引出了 k-近邻 等局部平均方法。
性能评估与过拟合
构建分类器后,我们需要评估其性能。一个自然的想法是使用训练误差来估计真实风险:
\hat{R}{train}(f) = (1/n) ∑^n I(Y_i ≠ f(X_i))
然而,这里存在一个关键问题:我们用来评估的分类器 f 本身正是基于这同一批训练数据学习得到的。这会导致对真实泛化误差的低估,这种现象与过拟合密切相关。
如果我们使用的模型复杂度过高(例如,可供选择的分类函数过多),它可能会“记住”训练数据中的噪声,使得训练误差非常小,但在未见过的数据上表现糟糕。这就是为什么我们需要使用独立的测试集或交叉验证来更可靠地评估性能。
总结
本节课中我们一起学习了:
- 在概率框架下,基于条件概率 P(Y|X) 的贝叶斯最优分类器。
- 使用 0-1 损失和更一般的损失函数来衡量分类器性能。
- 如何利用训练数据,通过经验估计(计算比例)来近似最优分类器,得到“插件”估计。
- 决策树是表示这种基于条件概率决策的直观方式。
- 经验估计可以视为局部加权平均,为处理连续特征提供了思路。
- 评估分类器性能时,需要注意训练误差的局限性以及过拟合的风险。

这些概念构成了监督学习,特别是分类问题的基础。下一讲我们将继续深入,探讨更复杂的模型和评估方法。
3:模式识别与机器学习导论 - 第3讲 🧠





在本节课中,我们将学习如何评估分类器的性能,理解训练误差与真实风险之间的差异,并探讨通过引入更多特征来改进分类器的方法。我们还将讨论过拟合问题及其解决方案。




回归函数的近似
上一节我们介绍了分类器的基本概念。本节中我们来看看,分类器可以被视为对回归函数的一种近似。回归函数是给定特征 X 时,目标变量 Y 的条件概率:P(Y=1 | X=x)。
分类器通过一种称为“局部平均”的形式来近似这个函数。对于任何一个新的数据点 x,我们为训练集中的每个数据点 i 分配一个权重 w_i(x)。这个权重衡量了新点 x 与训练点 x_i 的相似性。






在特征为离散变量的简单情况下,权重可以定义为:如果 x 与 x_i 完全匹配,则 w_i(x) = 1,否则为 0。然后,我们对所有匹配的训练点的 y_i 值进行平均,得到预测值。



公式表示:
f_hat(x) = (1 / N_match) * Σ_{i: x_i = x} y_i
其中,N_match 是训练集中特征与 x 匹配的样本数量。
这种方法可以推广到更复杂的权重函数,从而衍生出一大类估计器。

性能评估与风险
我们之前讨论了使用风险或错误概率来评估分类器的性能。如果我们知道真实的联合分布 P(X, Y),我们可以直接计算真实风险 R(f) = P(Y ≠ f(X))。

然而,在实际问题中,我们并不知道真实分布,只有一组训练数据 D_n = {(x_1, y_1), ..., (x_n, y_n)}。那么,如何在这种情况下评估风险呢?

一个最直接的想法是用经验风险(即训练误差)来近似真实风险。经验风险是模型在训练集上的平均错误率。
公式表示:
R_emp(f) = (1/n) * Σ_{i=1}^{n} I(y_i ≠ f(x_i))
其中,I(·) 是指示函数,当条件为真时取值为1,否则为0。


根据大数定律,对于一个固定的函数 f,当样本量 n 趋于无穷大时,经验风险 R_emp(f) 会收敛到其期望值,即真实风险 R(f)。这是因为训练样本是独立同分布的。






训练误差的问题与过拟合







虽然对于固定函数,经验风险是真实风险的良好估计,但在实际建模中,我们并非固定一个函数,而是从一组函数(称为假设空间 F)中选择一个使得训练误差最小的函数 f_hat。




公式表示:
f_hat = argmin_{f ∈ F} R_emp(f)
这里就出现了问题:f_hat 本身依赖于训练数据 D_n。当我们用同样的数据来计算 R_emp(f_hat) 时,各项损失项 I(y_i ≠ f_hat(x_i)) 不再是独立的(因为 f_hat 依赖于所有数据点)。因此,大数定律的条件不再满足。
结果是,最小化训练误差得到的 f_hat,其训练误差通常会低估真实的泛化误差。这种现象称为过拟合:模型过于复杂,以至于“记住”了训练数据中的噪声和特定细节,导致在新数据上表现不佳。

解决方案:训练-测试集划分



为了获得对真实风险的无偏且一致的估计,我们需要使用模型在训练过程中未曾见过的数据。标准的做法是将可用数据划分为两部分:

- 训练集:用于构建模型 f_hat。
- 测试集:用于评估 f_hat 的性能。




操作步骤:
假设我们有一个包含 N 个样本的数据集。
- 随机将其分为两部分,例如 70% 作为训练集(大小 n),30% 作为测试集(大小 m)。
- 仅使用训练集数据来训练模型,得到 f_hat。
- 在测试集上计算错误率,作为泛化误差的估计。





公式表示(测试误差):
R_test(f_hat) = (1/m) * Σ_{j=1}^{m} I(y_j_tilde ≠ f_hat(x_j_tilde))
其中,(x_j_tilde, y_j_tilde) 来自测试集。
在给定训练集的条件下,测试集中的样本是独立于训练过程的。因此,测试误差的各项是独立同分布的,其期望值等于真实风险 R(f_hat),并且随着测试集大小 m 的增加而收敛。这为我们提供了一个可靠的性能评估指标。



在实践中,有时会进一步划分出验证集,用于在训练过程中调整模型超参数,最终再用完全独立的测试集进行最终评估,形成“训练-验证-测试”的三步流程,以避免信息泄露。


引入更多特征



现在,让我们回到泰坦尼克号的例子,尝试通过添加更多特征来改进分类器。假设除了性别(Sex)之外,我们还考虑乘客等级(Pclass)。
现在,特征 X 是一个二维向量:X = (Sex, Pclass)。虽然有两个维度,但由于两者都是分类变量,我们可以将它们组合成一个新的复合分类变量。例如:
- (Female, 1)
- (Female, 2)
- (Female, 3)
- (Male, 1)
- (Male, 2)
- (Male, 3)
这样,我们又将问题简化回了处理单个分类变量的情形。我们可以像之前一样,计算这个新特征每个取值下的经验条件概率 P_hat(Y=1 | X)。
以下是构建分类器的步骤:



- 构建联合频率表:基于训练数据,统计每个 (新特征, 生存结果) 组合出现的次数。
- 计算条件概率:对于新特征的每个取值 x,计算生存的条件概率估计:
P_hat(Y=1 | X=x) = Count(Y=1, X=x) / Count(X=x) - 应用决策规则:如果 P_hat(Y=1 | X=x) > 0.5,则预测生存(1),否则预测死亡(0)。


这种方法得到的决策规则,可以用一个决策树来直观表示:首先根据性别分支,然后在男性分支下,再根据乘客等级进行细分。



通过引入额外特征,我们的假设空间变大了(从4个函数增加到2^6=64个函数)。在这个例子中,新模型的测试误差(0.211)略低于仅使用性别特征的模型(0.217)。然而,这种微小的改进是否具有统计显著性,可以通过假设检验(例如,比较两个伯努利分布比例)来评估。初步来看,由于数据量有限,这种差异可能并不显著。


总结


本节课中我们一起学习了:
- 分类器是对回归函数(条件概率)的近似。
- 使用经验风险(训练误差)评估固定函数是合理的,但对于通过最小化训练误差得到的数据依赖型函数,训练误差会低估真实风险,导致过拟合。
- 解决过拟合评估问题的核心方法是训练-测试集划分,使用独立的测试集来获得对泛化误差的无偏估计。
- 可以通过引入更多特征来构建更复杂的模型,但这会扩大假设空间,需要谨慎评估其带来的收益是否显著,并始终使用独立的测试集进行性能验证。
4:模式识别与机器学习导论

概述 📚
在本节课中,我们将要学习如何将分类器从离散特征空间扩展到连续特征空间。我们将探讨当特征变量是连续值时,之前基于精确匹配的“插件估计”方法为何会失效,并引入“核方法”这一核心概念来构建有效的非参数估计器。我们还将讨论模型选择中的统计显著性检验,以及估计误差中的偏差-方差权衡问题。
从离散到连续:问题的出现 🔄
上一节我们介绍了在离散特征情况下,如何通过经验联合分布来估计最优分类规则。具体方法是计算条件概率 P(Y=1|X=x),并应用贝叶斯规则(即当该概率超过0.5时判为1)。
然而,当特征 X 是一个连续的随机变量(例如,X ∈ ℝᴰ)时,我们遇到了一个根本性问题。在连续空间中,从训练集中精确观察到任何一个特定 x 值的概率几乎为零。这意味着,如果我们沿用之前的估计公式:
η̂(x) = (Σᵢ I(Xᵢ = x) Yᵢ) / (Σᵢ I(Xᵢ = x))
分母 Σᵢ I(Xᵢ = x) 在几乎所有新数据点 x 上都会是0,导致估计值未定义或变得毫无意义(例如,仅在训练数据点上精确插值,而在其他点上随机猜测)。
解决方案:引入核与相似性度量 💡
为了解决上述问题,我们需要修改估计方法。核心思想是:不再要求特征 Xᵢ 与待预测点 x 完全相等,而是允许它们“近似”或“相似”。
我们可以用一个衡量相似性的函数 K(称为核函数)来替换原来的指示函数 I(Xᵢ = x)。这样,估计器变为:
η̂(x) = (Σᵢ K((Xᵢ - x)/h) Yᵢ) / (Σᵢ K((Xᵢ - x)/h))
其中:
- K(·) 是核函数,通常满足 K(u) ≥ 0 且关于0对称,值越大表示越相似。
- h 是一个称为“带宽”的正参数,它控制着相似性的范围。h 越大,考虑的点越多,估计越平滑;h 越小,估计越依赖局部点,可能更波动。
以下是几种常见的核函数:
- 方框核:K(u) = I(||u|| ≤ 1)
- 高斯核:K(u) = exp(-||u||² / 2)
- Epanechnikov核:K(u) = (1 - ||u||²) I(||u|| ≤ 1)
这种估计器被称为 Nadaraya-Watson 核回归估计器。通过选择合适的核和带宽,我们可以在连续特征空间中得到一个光滑且合理的条件概率估计,进而用于分类。
模型比较与统计显著性检验 📊
在比较两个分类器(例如,一个简单模型和一个复杂模型)的性能时,我们不能仅仅比较它们在测试集上的错误率点估计值。由于测试错误率本身是基于有限样本的估计,存在随机波动,我们需要进行统计显著性检验。
假设我们有两个分类器,在大小为 M 的测试集上得到的错误率估计分别为 p̂₁ 和 p̂₂。我们想知道 p̂₁ 是否显著小于 p̂₂。
一种方法是构建 p̂₁ - p̂₂ 的置信区间,或进行假设检验。在原假设 H₀: p₁ = p₂(即两个分类器真实错误率相同)下,可以构造检验统计量:
Z = (p̂₁ - p̂₂) / SE(p̂₁ - p̂₂)
其中,SE(p̂₁ - p̂₂) 是差值的标准误的估计值。在大样本下,Z 近似服从标准正态分布。如果 |Z| 超过临界值(例如1.96对应5%显著性水平),我们就有证据拒绝原假设,认为两个分类器性能有显著差异。
需要注意的是,如果两个错误率是使用同一个测试集计算的,则 p̂₁ 和 p̂₂ 并非独立,计算标准误时需要考虑到它们的协方差,这会使检验变得更复杂。一个更稳妥的做法是将测试集划分为不相交的两部分,分别评估两个分类器。
核密度估计简介 📈
核方法不仅可用于回归和分类,还可直接用于估计连续随机变量的概率密度函数(PDF),这称为核密度估计。
给定样本 {X₁, ..., Xₙ},其核密度估计为:
f̂(x) = (1/n) Σᵢ (1/h) K((Xᵢ - x)/h)
这里的 (1/h) 项是为了保证估计出的 f̂(x) 在整个空间上的积分等于1,使其成为一个合法的概率密度函数。核密度估计是非参数统计中的核心工具,它不对数据分布做具体形式(如正态分布)的假设。
偏差-方差权衡 ⚖️
核估计器的性能严重依赖于带宽 h 的选择:
- h 过大:估计过于平滑,可能无法捕捉数据的真实结构,导致高偏差。
- h 过小:估计过于依赖个别数据点,对训练数据的随机波动非常敏感,导致高方差。
这就是机器学习中著名的偏差-方差权衡。我们的目标是选择一个 h,使得估计器的均方误差(MSE = 偏差² + 方差)最小。在实际应用中,常使用交叉验证等方法来自动选择带宽。
总结 🎯
本节课中我们一起学习了:
- 将分类器扩展到连续特征空间的关键障碍,即精确匹配失效。
- 引入核函数和带宽的概念,通过Nadaraya-Watson估计器来构建基于相似性的非参数回归与分类器。
- 在比较模型性能时,如何进行简单的统计显著性检验,以避免被样本随机性误导。
- 核方法在密度估计中的应用。
- 核估计中带宽选择的重要性,以及其背后所体现的偏差-方差权衡原理。

这些概念为我们处理现实世界中复杂的、连续的数据奠定了坚实的基础。下一节课,我们将深入探讨如何量化这些估计器的性能,并形式化地理解偏差和方差。
5:模式识别与机器学习导论

概述 📖
在本节课中,我们将学习如何推导最优分类器,并探讨在连续特征空间下如何估计回归函数。我们将从贝叶斯决策理论出发,通过一个具体的例子理解最优分类规则的计算,并介绍非参数估计方法,如核回归和最近邻方法。
贝叶斯最优分类器推导 🧠
上一节我们介绍了分类问题的基本框架,本节中我们来看看如何从理论上推导最优的分类器。
他们是如何做到这一点的?

这个练习的重点在于,通过一个一般性的案例,你可以将期望分类误差写成一个积分。
将期望误差写成一个积分是一种常用的方法。
然后,我们对 X 进行条件化处理。这是 X 的概率密度函数。这是一种书写方式。
在更一般的情况下,对于连续案例,你可以将其写为一个积分。例如,我可以将其写为 P(x)。
因此,如果你试图最小化这个误差,你会很容易地论证,你必须通过选择 f(x) 来最小化这个积分。这个论证过程是针对所有可能的分类器进行的。
现在,损失可以是0-1损失。我们选择 f(x),使得这个积分项最小化,因为另一项你无法控制。
我想让你们做的一件事是,在这个例子中计算这个最优规则。
这是一个例子,其中给定 X 和 Y 服从指数分布。整个重点在于尝试计算给定 X 时 Y 的条件分布,以及 Y 的边缘分布。
如果你回顾之前的课程,唯一的困难在于其中一个随机变量是离散的,另一个是连续的。
我将做一个介于2.6和2.7节之间的例子。例如,假设 x | y 服从正态分布,均值为 y,方差为1。
这意味着,如果 y=0,则 x 服从标准正态分布 N(0,1)。如果 y=1,则 x 服从正态分布 N(1,1)。
第一个参数是均值,第二个是方差,方差是相同的。这取决于你属于哪个类别。
这些被称为类条件分布。例如,如果 y=0,那么 x 的分布是均值为0的高斯分布。
我将使用这个符号:P(x | Y=0) 记为 p₀(x)。其公式为:
p₀(x) = (1/√(2π)) * exp(-x²/2)
而 P(x | Y=1) 记为 p₁(x)。其公式为:
p₁(x) = (1/√(2π)) * exp(-(x-1)²/2)
我们有两个这样的密度函数。一个以0为中心,另一个以1为中心。
然后,我还要给出 Y 的边缘分布:P(Y=0) 记为 π₀,P(Y=1) 记为 π₁,并且我们知道 π₀ + π₁ = 1。
基本思路是如何计算类似 P(Y=1 | X=x) 这样的量。
根据贝叶斯规则,对于离散的 Y,我们可以写为:
P(Y=1 | X=x) = [p(x | Y=1) * P(Y=1)] / p(x)
现在,我们将用密度函数来替换这些概率。所以,P(Y=1 | X=x) 可以视为一个密度。
我们知道 p(x | Y=1) 和 P(Y=1)。那么 p(x) 是什么?p(x) 是 x 的边缘密度。
p(x) 可以通过全概率公式得到:
p(x) = p(x | Y=0) * P(Y=0) + p(x | Y=1) * P(Y=1)
p(x) = π₀ * p₀(x) + π₁ * p₁(x)
这实际上是一个混合分布。如果权重相同,你基本上就是对这两个密度取平均。
这就是在忽略 Y 的情况下 X 的分布。这是基本的条件概率思想。
到目前为止有任何问题吗?
然后你意识到,我们为这些量使用了简写符号。一旦你把所有东西写下来,你会得到:
P(Y=1 | X=x) = [π₁ * p₁(x)] / [π₀ * p₀(x) + π₁ * p₁(x)]
你可以计算这个值。但我们实际上并不需要它的具体形式,它只是 x 的一个函数。
我们真正需要的是 η(x),即回归函数。分类器 f(x) 定义为:
f(x) = 1, 如果 η(x) > 1/2
f(x) = 0, 如果 η(x) ≤ 1/2
因此,我真正需要做的是将这个量与 1/2 进行比较。
如果 η(x) > 1/2,即 [π₁ * p₁(x)] / [π₀ * p₀(x) + π₁ * p₁(x)] > 1/2。
进行代数运算(所有项均为正),两边乘以分母,得到:
2 * π₁ * p₁(x) > π₀ * p₀(x) + π₁ * p₁(x)
简化后得到:
π₁ * p₁(x) > π₀ * p₀(x)
因此,我们的分类器规则是:如果 π₁ * p₁(x) > π₀ * p₀(x),则预测为1,否则预测为0。
这看起来熟悉吗?它有一个名字吗?是的,它被称为似然比。
所以这个分类器就是似然比分类器。在假设检验的背景下,你比较似然比与某个阈值。
在高斯案例中,p₁(x)/p₀(x) 的公式为:
[exp(-(x-1)²/2)] / [exp(-x²/2)] = exp(x - 1/2)
比较它与阈值。另一种方法是取对数。所以 log(p₁(x)/p₀(x)) 需要大于 log(π₀/π₁)。
如果类别是平衡的,即 π₀ = π₁ = 0.5,那么 log(π₀/π₁) = 0。在这种情况下,规则简化为:如果 x > 1/2,则预测为1,这非常合理。
如果类别不平衡,那么这个阈值就会改变,但分类器的结构仍然是基于似然比的。
对于指数分布的例子,你会得到类似的分类器:根据某个值的大小进行分类。
线性判别分析 📈
上一节我们推导了最优分类器,本节中我们来看看一个经典方法——线性判别分析。
线性判别分析是机器学习之前的经典统计学习结果之一,与费舍尔判别式有关。
其思想是假设类条件分布 P(x | Y=k) 是多元高斯分布,具有不同的均值 μ_k,但共享相同的协方差矩阵 Σ。
通过类似的论证,最终你会得到一个线性决策边界,形式为:
δ_k(x) = x^T Σ^{-1} μ_k - (1/2) μ_k^T Σ^{-1} μ_k + log(π_k)
然后将 x 分配给使 δ_k(x) 最大的类别 k。
在我们的简单单变量例子中,Σ = 1,μ₀ = 0,μ₁ = 1。这导致决策边界在 x = 1/2 + log(π₀/π₁) 处。
在多元情况下,这导致决策边界是 R^d 空间中的一个超平面。在二维问题中,一个类别的密度等高线可能像这样,另一个像那样,分类器是一条线,将空间的一侧分为一类,另一侧分为另一类。
记住我们是从最一般的情况开始的:首先假设你知道联合分布,那么这就是贝叶斯最优分类器。然后我们尝试从数据中学习它。
这引出了参数化模型。我们今天讨论的方法没有强加任何参数形式。但线性判别分析对类条件分布做了很强的假设,这指定了一个非常具体的联合分布。
在实践中,你从训练数据中估计 μ₀、μ₁ 和 Σ。这很容易做到:用类0的样本均值估计 μ₀,用类1的样本均值估计 μ₁,合并所有样本估计共享的 Σ。
一旦有了估计值,你就将它们“插入”到理论公式中,得到你的分类器。这被称为“插件”估计器。
非参数回归估计 🔍
上一节我们介绍了参数化方法,本节中我们来看看非参数方法,用于估计连续特征空间下的回归函数。
我们回到连续特征的情况,试图估计回归函数 η(x)。我们可以扩展在离散情况下使用的思想,将其推广到连续情况,只需将严格的指示函数替换为一个软的相似性度量,这通常被称为核函数。
这将有效地对每个测试点 x 附近的 Y 值进行平均。一个特定的案例是Nadaraya-Watson估计器,它是一种非参数回归函数估计器。
核函数是经过平移和缩放的母核函数。例如,高斯核经过缩放参数 h(称为带宽)后,其尖锐程度会改变:h 越小,核越尖锐;h 越大,核越平滑。
将这个核函数代入公式,你会得到一个估计量。例如,Nadaraya-Watson估计器的公式为:
η̂(x) = [Σ_i K((X_i - x)/h) * Y_i] / [Σ_i K((X_i - x)/h)]
在实践中应用,你可以得到类似的结果。这是乳腺癌数据,我们基于“半径”列预测诊断结果,使用高斯核的Nadaraya-Watson估计器。
X轴是特征“半径”,范围大约从11到20。数据点分布在中部(如15附近)。每个数据点有其对应的 Y 值(0或1)。估计出的函数曲线会随着 x 变化。
你可以看到,随着带宽 h 的变化,估计的曲线平滑度不同。绿色曲线 h=3 非常平滑,黑色曲线 h=0.25 更尖锐,红色曲线 h=0.05 最不平滑。
分类时,我们在 η̂(x) = 0.5 处设置阈值。对于绿色曲线,几乎将所有点判为一类;黑色曲线能更好地确定边界。
这表明你需要选择带宽 h。较小的带宽导致估计方差更大(更不平滑),这是估计量方差的表现。较大的带宽方差较小,但可能引入更大的偏差。
偏差定义为 E[η̂(x)] - η(x),方差是 η̂(x) 相对于训练数据的变异性。
直观上,增加 h,方差会下降,因为你平均了更多的数据点。但同时,你平均了可能具有不同回归值的远端点,这会增加偏差。
因此,存在一个偏差-方差权衡。另一个核函数是方框核,它不平滑,会产生阶梯状的估计。
带宽选择与交叉验证 ⚙️
上一节我们看到了带宽对估计的影响,本节中我们来看看如何选择最优带宽。
如何选择带宽?如果你理解了带宽的影响,你实际上需要选择一个 h。带宽选择是统计学中的一个经典问题。
Nadaraya-Watson估计器就是使用特定核函数(如高斯核)的上述估计器。
这个估计器在 Y 不是二值的情况下也有效,它可以逼近真实的回归函数。对于二值 Y,回归函数是 E[Y|X=x] = P(Y=1|X=x),估计值也总是在0和1之间。
一个关键问题是:我们如何选择带宽 h 以最小化分类错误率?
我们不能直接最小化真实风险,因为真实的联合分布未知。但我们可以估计它。
一种方法是使用测试集误差。如果你有一个大小为 M 的测试集,测试误差为:
Test Error = (1/M) * Σ_j I( f̂(x_test_j) ≠ y_test_j )
你可以将其作为 h 的函数进行计算并绘图,选择一个使测试误差最小的 h。
但请注意,你不应该使用最终的测试集来进行带宽选择,这应该是验证过程的一部分。正确做法是将训练数据分成训练部分和验证部分。
以下是具体步骤:
- 将可用数据分为训练集、验证集和测试集。
- 对于每个候选带宽 h,使用训练集数据构建分类器
f̂_h。 - 在验证集上评估
f̂_h的错误率。 - 选择在验证集上错误率最小的带宽 ĥ。
- 使用这个选定的带宽 ĥ 和全部训练数据(训练+验证)重新训练最终分类器。
- 最后,在独立的测试集上评估最终分类器的性能。
这个过程有时被称为超参数调优或网格搜索(当你在一组预定义的 h 值中进行搜索时)。
为了更稳定地估计验证误差,可以使用 K折交叉验证:
- 将训练数据随机分成 K 个大小相似的子集(折)。
- 对于每个候选带宽 h 和每一折 k:
- 使用其他 K-1 折的数据作为训练集训练模型
f̂_h^{-k}。 - 在第 k 折(作为验证集)上计算错误率。
- 使用其他 K-1 折的数据作为训练集训练模型
- 对每个 h,计算 K 次验证错误率的平均值。
- 选择平均验证错误率最小的带宽 ĥ。
交叉验证能更有效地利用数据,并提供对泛化误差更可靠的估计,尤其是在数据量不大时。
其他局部平均方法 📊
上一节我们深入探讨了核回归,本节中我们简要看看其他两种基于局部平均思想的非参数方法。
核回归可以写得更为一般化,即基于相似性度量的局部平均。一个例子是空间划分。
最容易构建相似性度量的方法是:将特征空间划分成固定的单元。然后定义两个数据点相似,当且仅当它们落在同一个单元内。
相似性核函数为:
K(x_i, x) = 1, 如果 x_i 和 x 在同一个单元内
K(x_i, x) = 0, 否则
这样,对于给定的 x,估计量只对落在 x 所在单元内的那些训练点的 Y 值进行平均。这类似于方框核,但单元的边界是预先固定好的,而不是以 x 为中心动态构建。这更容易进行理论分析。
另一种非常流行的方法是 K最近邻估计器。
其相似性核函数为:
K(x_i, x) = 1, 如果 x_i 是 x 的 K 个最近邻之一
K(x_i, x) = 0, 否则
最简单的例子是 1-最近邻:你找到距离 x 最近的训练点 X_i,然后直接取其对应的标签 Y_i 作为预测。K近邻则是取K个最近邻点的 Y 值的平均(对于回归)或投票(对于分类)。
这两种方法(划分和K近邻)在实践中广泛应用,并且也有丰富的理论来分析它们的偏差-方差特性。

总结 🎯
本节课我们一起学习了以下核心内容:
- 贝叶斯最优分类器:我们从最小化期望误差出发,推导出最优分类规则即比较后验概率,并具体计算了一个高斯类条件分布的例子,得到了似然比分类器。
- 线性判别分析:介绍了一种参数化方法,它假设类条件分布为高斯分布并共享协方差矩阵,最终导出一个线性决策边界。
- 非参数回归估计:介绍了Nadaraya-Watson核估计器,它通过局部加权平均来估计回归函数,并讨论了核函数与带宽的作用。
- 模型选择:重点讲解了带宽选择的重要性,并介绍了通过验证集误差或交叉验证来进行超参数调优的实用方法。
- 其他方法:简要提到了基于空间划分和K最近邻的局部平均方法,扩展了非参数估计的思路。
这些内容构成了从理论最优解到实用估计方法的完整路径,是理解模式识别与机器学习基础的重要部分。
6:模式识别与机器学习导论 - 线性判别函数与感知器算法 🧠

在本节课中,我们将学习模式识别中的一种基本方法——线性判别函数。我们将从几何角度理解其概念,并深入探讨一个经典的学习算法:感知器算法。通过本课,你将掌握如何利用线性决策边界对数据进行分类。
概述 📋


上一节我们讨论了基于概率的分类方法。本节我们将转向一种更直接的几何方法:线性判别函数。这种方法的核心思想是寻找一个线性超平面,将不同类别的数据点分开。我们将首先理解线性判别函数的定义和几何意义,然后学习如何通过感知器算法来找到这个超平面。
线性判别函数
线性判别函数是一种用于二元分类的简单而强大的工具。对于一个输入特征向量 x,其判别函数形式如下:
g(x) = wᵀx + w₀
其中:
- w 是权重向量(Weight Vector)。
- w₀ 是偏置项(Bias)。
决策规则非常简单:
- 如果 g(x) > 0,则将 x 判定为类别 C₁。
- 如果 g(x) < 0,则将 x 判定为类别 C₂。
- 方程 g(x) = 0 定义了一个决策超平面。
几何解释
从几何角度看,权重向量 w 决定了决策超平面的方向。具体来说:
- w 是决策超平面的法向量。
- 偏置项 w₀ 决定了超平面到原点的距离。
- 判别函数的值 g(x) 正比于点 x 到决策超平面的有符号距离。
感知器算法
理解了线性判别函数后,一个关键问题是如何从数据中学习到合适的参数 w 和 w₀。感知器算法是解决这个问题的经典在线学习算法。
感知器算法遵循一个简单的误差修正规则。其核心思想是:如果当前样本被错误分类,就调整决策超平面的位置来修正这个错误。
以下是感知器算法的步骤:
- 初始化:将权重向量 w 和偏置 w₀ 初始化为小随机数或零。
- 迭代:对于训练集中的每个样本 (xᵢ, yᵢ),其中 yᵢ ∈ {+1, -1} 是类别标签:
- 计算当前预测:ŷ = sign(wᵀxᵢ + w₀)。
- 如果预测错误(即 ŷ ≠ yᵢ),则更新参数:
- w ← w + η * yᵢ * xᵢ
- w₀ ← w₀ + η * yᵢ
- (其中 η 是学习率,一个小的正数)。
- 终止:重复步骤2,直到所有样本都被正确分类或达到预设的最大迭代次数。
算法收敛性
感知器算法有一个重要的理论保证:如果训练数据是线性可分的,那么感知器算法保证在有限步内收敛到一个解(即能完美分开所有数据的超平面)。这个结论被称为感知器收敛定理。
总结 🎯
本节课我们一起学习了模式识别中的线性判别函数方法。
- 我们首先定义了线性判别函数 g(x) = wᵀx + w₀,并理解了其作为决策超平面的几何意义。
- 接着,我们介绍了用于学习判别函数参数的感知器算法。该算法通过不断修正分类错误来更新权重,并且在数据线性可分的情况下保证收敛。

线性判别函数和感知器算法是神经网络和支持向量机等更复杂模型的基础。理解它们的工作原理,为我们后续学习更高级的模式识别技术奠定了坚实的基础。
7:模式识别与机器学习导论 - 偏差-方差分解与分区估计器分析 📊




在本节课中,我们将学习回归分析中的一个核心概念:偏差-方差分解。我们将通过分析一个具体的非参数估计器——分区估计器,来理解其预测误差如何分解为偏差和方差两部分,并探讨带宽选择对估计性能的影响。






上一节我们介绍了回归分析的基本框架和最优回归函数。本节中,我们来看看如何分析一个具体估计器的性能。



偏差-方差分解 🔍



我们关心的核心量是估计回归函数 \(\hat{\eta}(x)\) 与真实回归函数 \(\eta(x)\) 之间的均方误差(MSE)。在给定训练数据 \(X_1, ..., X_n\) 的条件下,我们分析以下期望:





为了分析这个量,我们使用一个经典的技巧:加减 \(\hat{\eta}(x)\) 的期望值 \(\mathbb{E}[\hat{\eta}(x)]\)。





将上式平方并取期望,交叉项为零,最终得到分解:

这个分解公式非常通用,它表明估计器的均方误差由两部分组成:
- 偏差平方:估计器期望值与真实值之间的差异。它衡量了估计器的系统性误差。
- 方差:估计器本身围绕其期望值的波动程度。它衡量了估计器对训练数据随机性的敏感度。



通常,偏差和方差之间存在权衡。









理解了通用的偏差-方差分解后,我们将其应用到一个具体的估计器上。
分区估计器 📏
分区估计器是一种简单的局部平均方法。假设输入 \(X\) 是一维的,且定义在区间 \([0,1]\) 上。我们将该区间划分为若干个长度为 \(h\) 的小区间(或称“单元”)。
对于给定的预测点 \(x\),令 \(A(x)\) 表示包含 \(x\) 的那个小区间。分区估计器的定义是,对落在 \(A(x)\) 内的所有训练样本的输出 \(Y_i\) 取平均:

其中 \(\mathbb{I}(\cdot)\) 是指示函数。这个估计器可以重写为加权和的形式:



这里,\(\hat{\nu}_n(A(x)) = \frac{1}{n} \sum_{i=1}^{n} \mathbb{I}(X_i \in A(x))\) 是经验测度,即训练样本落在区间 \(A(x)\) 中的比例。

现在,我们利用偏差-方差分解公式来分析分区估计器的性能。



方差分析

首先计算估计器 \(\hat{\eta}(x)\) 的方差。在给定训练输入 \(X_1,...,X_n\) 的条件下,权重 \(w_i(x)\) 是常数,而 \(Y_i\) 是条件独立的。










我们假设条件方差是常数,即 \(\text{Var}(Y \mid X) = \sigma^2\)。代入权重公式并进行化简:




当样本量 \(n\) 很大时,经验测度 \(\hat{\nu}_n(A(x))\) 会收敛于真实概率 \(\nu(A(x)) = P(X \in A(x))\)。如果我们进一步假设 \(X\) 在 \([0,1]\) 上均匀分布,那么 \(\nu(A(x)) = h\)。因此,对于大的 \(n\),方差近似为:

结论:分区估计器的方差与带宽 \(h\) 成反比。\(h\) 越大(单元越宽),用于平均的样本越多,方差越小。

分析完方差,我们接下来看看偏差部分。








偏差分析
接下来计算估计器 \(\hat{\eta}(x)\) 的期望,即偏差部分。

代入权重表达式并利用大数定律,当 \(n\) 很大时:


在 \(X\) 均匀分布的假设下,这简化为在区间 \(A(x)\) 上对真实回归函数 \(\eta(u)\) 取平均:





因此,偏差为:







直观理解:分区估计器用整个区间 \(A(x)\) 上 \(\eta\) 的平均值,来近似该区间内某一点 \(x\) 的真实值 \(\eta(x)\)。只有当区间宽度 \(h \to 0\) 时,这个平均值才会趋近于 \(\eta(x)\),从而使偏差趋近于零。
结论:分区估计器的偏差与带宽 \(h\) 正相关。\(h\) 越小(单元越窄),局部平均越接近点值,偏差越小。



权衡与总结 ⚖️
综合方差和偏差的分析,我们得到分区估计器均方误差(MSE)的近似表达式:






这揭示了一个根本性的权衡(Bias-Variance Tradeoff):
- 选择大的带宽 \(h\):方差小,但偏差大(估计过于平滑,可能欠拟合)。
- 选择小的带宽 \(h\):偏差小,但方差大(估计波动剧烈,可能过拟合)。






最优的带宽 \(h^*\) 需要平衡这两者,使得总的均方误差最小。偏差收敛到零的速度取决于真实回归函数 \(\eta(x)\) 的平滑度,这将在后续课程中讨论。





本节课中我们一起学习了偏差-方差分解这一核心概念,并将其应用于分区估计器的分析。我们了解到,任何估计器的预测误差都可以分解为偏差和方差两部分,而带宽参数 \(h\) 的选择正是在偏差(要求 \(h\) 小)和方差(要求 \(h\) 大)之间进行权衡的关键。理解这一权衡对于选择和调整机器学习模型至关重要。
8:模式识别与机器学习导论 - 偏差-方差分解与性能评估 📊
















在本节课中,我们将深入分析回归问题中的偏差-方差分解,并探讨分类器性能评估的常用方法。我们将从上一节引入的均方误差分解开始,理解其组成部分,并学习如何通过权衡偏差与方差来优化模型。最后,我们将回到分类问题,介绍ROC曲线等评估工具。



偏差-方差分解回顾 🔍
上一节我们分析了条件均方误差,这是一个衡量回归函数估计器性能的重要指标。我们论证了该指标可以分解为偏差平方与方差之和。



具体公式如下:

这个分解被称为偏差-方差分解或权衡。当我们尝试优化估计器时,需要同时考虑这两个部分。



分区估计器的分析 📐


我们以分区估计器为例进行计算。首先引入一些符号:经验分布或经验测度表示训练数据中X的分布。根据大数定律,经验分布会收敛于真实分布。

分区估计器可以写为Y值的加权平均,权重由特定的质量函数决定。我们计算了其方差,并做了一个简化假设:给定X的条件方差是常数。在此假设下,方差最终近似为:
其中,\(\mu(A_x)\) 是包含点x的单元格在真实分布下的测度。


以一维空间[0,1]划分为长度为h的区间为例。一个随机点落在任一区间的概率约为h。因此,对于大的n,方差近似为 \(\sigma^2 / (n h)\)。当带宽h变小时,落入该区间的点变少,方差会增大。


偏差的分析与利普希茨条件 📈


接下来我们分析偏差。分区估计器的期望行为类似于分段常数函数。偏差源于用单元格内的平均值来近似真实回归函数在点x的值。




为了使偏差趋于零,我们需要让带宽h趋于零。偏差收敛到零的速度取决于真实回归函数 \(\eta(x)\) 的平滑度。我们引入利普希茨连续性来量化函数的平滑度。




利普希茨条件定义:如果存在常数L,使得对于定义域内任意两点x和z,函数 \(\eta\) 满足:
则称函数 \(\eta\) 是L-利普希茨连续的。这等价于说函数的导数(几乎处处存在)的绝对值有界于L。



以下是一些例子:
- 常数函数:是利普希茨连续的(L=0)。
- 线性函数:\(\eta(x) = ax + b\) 是利普希茨连续的,L等于斜率a的绝对值。
- 函数 \(x^2\):在整个实数域上不是利普希茨连续,因为其导数 \(2x\) 无界;但在任何有界区间(如[0,1])上是利普希茨连续的。
- Sigmoid函数:是利普希茨连续的。






在利普希茨假设下,我们可以控制偏差的大小。通过分析可得,偏差满足:
这意味着偏差以线性速度随h减小。
偏差-方差的权衡与维度灾难 ⚖️
现在,我们将偏差和方差的结果结合起来。均方误差的上界近似为:



- 偏差项 \(L^2 h^2\):随h减小而改善。
- 方差项 \(\sigma^2 / (n h)\):随h减小而恶化。
如果绘制MSE随h变化的曲线,会呈现一个U形,存在一个最优的h值使得MSE最小。通过令两项相等,可以近似求解最优带宽 \(h^*\) 及其对应的最小MSE:
这个收敛速率 \(n^{-2/3}\) 比参数化模型(如线性回归)的典型速率 \(n^{-1}\) 要慢,这是因为我们假设的函数类(利普希茨连续)非常广泛,属于非参数估计。


维度灾难:在高维(D维)情况下,问题变得更加严峻。方差项会变为 \(\sigma^2 / (n h^D)\)。最优MSE速率会恶化到大约 \(n^{-2/(2+D)}\)。当维度D很高时,这个速率变得极慢,意味着需要海量的样本才能准确估计一个一般的平滑函数。这解释了为什么在高维问题中,我们常常需要转向参数化模型或低维假设来避免这个问题。



分类器性能评估:ROC曲线 📉





现在,让我们切换话题,回到分类问题,讨论如何更细致地评估分类器的性能。
除了整体的分类错误率,我们经常需要分别考察模型在不同类别上的表现。特别是对于通过估计回归函数并设置阈值 \(\tau\) 来决策的分类器(即 \(\hat{f}(x) = \mathbb{I}(\hat{\eta}(x) > \tau)\)),其性能强烈依赖于 \(\tau\)。
以下是两个关键指标:
- 假正率:真实类别为0时,被预测为1的概率。$ \text{FPR}(\tau) = P(\hat{Y}=1 | Y=0) $
- 真正率:真实类别为1时,被预测为1的概率。$ \text{TPR}(\tau) = P(\hat{Y}=1 | Y=1) $

通过让阈值 \(\tau\) 从 \(+\infty\) 变化到 \(-\infty\),我们可以得到一系列(FPR, TPR)点,将它们连接起来形成的曲线称为接收者操作特征曲线。




ROC曲线提供了分类器性能的完整图像:
- 曲线从左下角(0,0)(总是预测为0)延伸到右上角(1,1)(总是预测为1)。
- 对角线(FPR = TPR)表示随机猜测的性能。
- 曲线越向左上角凸起,分类器性能越好。完美的分类器对应的ROC曲线经过点(0,1)。
曲线下面积是另一个汇总性指标,表示随机选取一个正样本和一个负样本,分类器对正样本给出更高分数的概率。完美分类器的AUC为1,随机分类器的AUC为0.5。



ROC曲线的优势在于它不依赖于类别的先验分布,并且能让我们根据实际应用中对假正率和真正率的不同容忍度来选择合适的决策阈值。

总结 🎯

本节课我们一起学习了以下核心内容:
- 偏差-方差分解:深入理解了回归问题中均方误差如何分解为偏差平方和方差,并分析了分区估计器在这两方面的表现。
- 利普希茨连续性:作为衡量函数平滑度的工具,它帮助我们量化了非参数估计中偏差项的收敛速度。
- 维度灾难:认识到在高维空间中,非参数估计的方差会急剧增大,导致所需样本量指数级增长,这为使用参数化模型提供了动机。
- 分类器评估:学习了超越简单准确率的评估方法,特别是ROC曲线和AUC,它们能更全面地反映分类器在不同决策阈值下的性能,尤其在类别不平衡时非常有用。


这些概念是理解模型复杂度、泛化能力以及选择合适评估指标的基础。
9:分类器性能评估与线性回归基础 📊


在本节课中,我们将学习两种评估分类器性能的方法:ROC曲线和精确率-召回率曲线。随后,我们将从局部平均方法过渡到参数化模型,并介绍经验风险最小化的通用框架,最后聚焦于线性回归这一具体模型。

第一部分:分类器性能评估指标

上一节我们讨论了分类错误率。本节中,我们来看看另一种评估分类器性能的视角,它不依赖于类别分布,能提供更稳健的评估。
ROC曲线与相关概念


ROC曲线通过两个条件概率来评估分类器性能:真正例率和假正例率。对于一个由阈值参数化的分类器族,我们可以得到一条曲线。

以下是定义真正例率和假正例率的公式:



- 真正例率:
P(ŷ = 1 | y = 1) - 假正例率:
P(ŷ = 1 | y = 0)

这两个概率分别衡量了分类器在正类样本上的“检出能力”和在负类样本上的“误报水平”。



基于这两个基本概率,我们可以推导出其他相关指标:


- 真负例率:
P(ŷ = 0 | y = 0) = 1 - 假正例率 - 假负例率:
P(ŷ = 0 | y = 1) = 1 - 真正例率


分类错误率可以用这些条件概率和类先验概率表示:
P(ŷ ≠ y) = 假正例率 * P(y=0) + 假负例率 * P(y=1)




当某一类别的先验概率非常小时,分类错误率可能无法有效反映模型对稀有类别的识别能力。ROC曲线通过分离条件概率,提供了更稳健的性能视图。

对于一个通过阈值 τ 决策的分类器(例如,当估计概率 η̂(x) > τ 时预测为正类),随着 τ 从 1 变化到 0,假正例率和真正例率会形成一条从 (0,0) 到 (1,1) 的曲线,即ROC曲线。

ROC曲线下的面积是一个常用的汇总指标:
- 完美分类器的AUC为 1。
- 随机分类器的AUC为 0.5。
- 实际分类器的AUC介于 0.5 和 1 之间,越接近 1 越好。


AUC有一个直观的概率解释:它等于从正类分布中随机抽取一个样本的得分,高于从负类分布中随机抽取一个样本得分的概率。即:
AUC = P(η̂(X⁺) > η̂(X⁻))
其中 X⁺ ~ P₁, X⁻ ~ P₀。


需要注意的是,不同的ROC曲线可能拥有相同的AUC值,但形状不同。此时,需要根据对假正例率的容忍度来选择更合适的分类器。

在实践中,我们使用测试集来估计这些概率。对于给定的阈值 τ,假正例率的估计为:
假正例率 ≈ (∑ I(ŷ_i=1 且 y_i=0)) / (∑ I(y_i=0))
通过遍历所有可能的唯一得分值作为阈值,我们可以计算出ROC曲线上的点。




精确率-召回率曲线



除了ROC曲线,另一种常用的评估工具是精确率-召回率曲线。




以下是相关定义:
- 召回率:与真正例率相同,
P(ŷ = 1 | y = 1)。 - 精确率:
P(y = 1 | ŷ = 1),即所有被预测为正类的样本中,真实为正类的比例。
精确率-召回率曲线通过变化阈值,绘制召回率与精确率的关系图。这条曲线在类别不平衡的场景下特别有用,因为它关注的是被模型“发现”的正类样本的质量(精确率)。
精确率可以通过贝叶斯定理用真正例率、假正例率和类先验计算得出。与ROC曲线不同,PR曲线直接包含了类先验信息。
假发现率是精确率的互补概念:FDR = 1 - 精确率 = P(y=0 | ŷ=1)。
第二部分:从非参数方法到参数模型
上一节我们介绍了评估分类器性能的多种方法。本节中,我们来看看如何通过引入模型假设来克服高维数据下局部平均方法(如划分回归)的方差问题。
经验风险最小化框架
局部平均方法在维度增加时,方差会急剧增大,导致收敛速度变慢。一种缓解思路是假设真实的回归函数或决策边界来自一个较小的函数类(例如线性函数)。这就是参数化模型的思路。
其通用框架称为经验风险最小化:
- 我们不再在所有可能的函数中最小化真实风险,而是限制在一个特定的函数类
F中。 - 用训练集上的经验平均(训练误差)来近似真实风险。
- 在这个函数类
F中,寻找最小化经验风险的函数。
对于二分类问题(0-1损失)或回归问题(平方损失),ERM的通用形式为:
f̂ = argmin_{f∈F} (1/n) Σ L(y_i, f(x_i))



通过限制函数类 F,我们可以避免在0-1损失下产生的平凡插值解(即完美拟合所有训练点但泛化能力差)。
线性回归模型




最简单的参数函数类之一是线性函数类。我们假设回归函数是输入特征的线性组合。


对于回归问题,使用平方损失,经验风险最小化就变成了经典的线性回归问题:
θ̂ = argmin_{θ∈R^d} (1/n) Σ (y_i - θᵀx_i)²
为了简化,我们暂时忽略了截距项。截距可以通过在特征向量 x 中添加一个恒为1的维度来并入参数 θ。



我们可以使用矩阵记号来更简洁地表示这个问题。令设计矩阵 X 的每一行是一个样本的特征向量,y 是响应向量。则损失函数可写为:
L(θ) = (1/n) ||y - Xθ||²

通过对 θ 求梯度并令其为零,我们得到正规方程:
XᵀXθ = Xᵀy



假设 XᵀX 是可逆的,则线性回归的解析解为:
θ̂ = (XᵀX)⁻¹Xᵀy





最终得到的回归函数估计为:
η̂(x) = f̂(x) = θ̂ᵀx


需要记住的是,线性回归估计是在假设真实回归函数为线性的前提下,对最优回归函数(条件期望)的近似。如果该假设成立,线性回归会是一个很好的估计器;如果不成立,则可能引入较大的偏差。







总结


本节课中我们一起学习了:
- 分类器性能的深入评估:了解了ROC曲线及其面积AUC,它们通过真正例率和假正例率评估分类器,对类别不平衡更稳健。同时介绍了精确率-召回率曲线及其在关注“发现”质量时的应用。
- 经验风险最小化框架:为了克服高维非参数方法的“维数灾难”,我们引入了通过限制函数类来进行参数化建模的思想。
- 线性回归基础:作为ERM框架下最简单的例子,我们推导了线性回归的优化目标、正规方程及其解析解。


下一节课,我们将对线性回归估计器进行理论分析,考察其偏差和方差。
10:梯度下降与逻辑回归入门 🧠

在本节课中,我们将学习梯度下降这一优化方法,并探讨如何将其应用于分类问题,特别是逻辑回归模型。我们将从回顾线性回归的分析开始,逐步引入更通用的优化思想。
回顾线性回归的误差分析
上一节我们分析了线性回归模型,并得到了其风险的一个上界。在线性回归模型中,我们假设回归函数是线性的,并且给定X时Y的条件方差为常数σ²。
在这些假设下,我们推导出均方误差的期望近似为:
MSE ≈ σ² / n * xᵀ Σ⁻¹ x
其中,Σ是特征X的协方差矩阵。
对于一个简单的例子,假设Σ是单位矩阵,且每个特征分量xᵢ ∈ [-1, 1],那么误差上界约为σ² * D / n。这里D是特征维度。
相比之下,如果我们使用之前讨论过的分区估计器,其误差上界的形式为σ² / n^(2/(2+D))。当维度D很大时,这个收敛速率(n的幂次)会变得非常慢。这说明,如果我们对模型有正确的线性假设,线性回归可以学得更快;而如果我们不做任何假设,使用非参数方法虽然更稳健,但需要付出收敛速度变慢的代价。
从经验风险最小化到优化问题
我们之前的工作流程是:定义风险(期望损失),然后用经验风险(训练集上的平均损失)来近似它。接着,我们将函数类F限制在某个特定集合(如线性函数)中,从而得到一个优化问题。
对于回归问题,使用平方损失,我们得到了一个关于参数θ的凸优化问题:
min_θ (1/n) Σ (yᵢ - xᵢᵀθ)²
幸运的是,这个问题有解析解(正规方程)。然而,对于许多更复杂的模型,我们可能无法得到闭式解。
梯度下降法:一种通用的优化方法 🏔️
那么,如何求解没有解析解的优化问题呢?一个通用且强大的数值方法是梯度下降法。
其核心思想是:从一个初始参数估计θ₀开始,迭代地朝函数下降最快的方向移动一小步。这个方向就是负梯度方向。
算法步骤如下:
- 初始化参数 θ⁽ᵗ⁾(t=0)。
- 计算当前点损失函数 L(θ) 的梯度:∇L(θ⁽ᵗ⁾)。
- 沿负梯度方向更新参数:
θ⁽ᵗ⁺¹⁾ = θ⁽ᵗ⁾ - η * ∇L(θ⁽ᵗ⁾)。 - 重复步骤2和3,直到收敛(梯度接近零)。
参数说明:
θ:模型参数。η:学习率(步长),是一个需要手动设置的正数。∇L(θ):损失函数在θ处的梯度。
直观理解:梯度指向函数值增长最快的方向。因此,向相反方向移动会使函数值减小。通过不断重复这个过程,我们最终会(在凸函数的情况下)到达一个局部最小值点,该点的梯度为零。
在线性回归中的应用:线性回归的损失函数梯度为 ∇L(θ) = (2/n) Xᵀ(Xθ - y)。应用梯度下降更新规则,就变成了:
θ⁽ᵗ⁺¹⁾ = θ⁽ᵗ⁾ - η * (2/n) Xᵀ(Xθ⁽ᵗ⁾ - y)
即使不直接求解正规方程,我们也可以通过迭代来逼近最优解。现代计算框架(如PyTorch、TensorFlow)可以自动计算复杂函数的梯度,使得这种方法非常强大和方便。
从回归到分类:逻辑回归的引入 🔄
现在,我们想将类似的线性建模思想应用到分类问题中。在二分类中,理想的预测函数 f*(x) 是后验概率 P(Y=1|X=x)。我们同样希望用线性函数来近似它。
但直接使用线性函数 f_θ(x) = θᵀx 会遇到两个问题:
- 输出范围问题:线性函数的输出是任意实数,而概率值必须在 [0, 1] 区间内。
- 模型合理性:概率与特征之间的关系不一定是线性的。
解决方案是引入一个连接函数,将线性组合的结果映射到 [0, 1] 区间。最常用的函数是 Sigmoid 函数(或称逻辑函数):
σ(z) = 1 / (1 + e^{-z})
其中 z = θᵀx。
于是,我们的模型变为:
P(Y=1|X=x) ≈ f_θ(x) = σ(θᵀx) = 1 / (1 + e^{-θᵀx})
这个模型被称为 逻辑回归。它本质上是用一个线性决策边界(θᵀx = 0)来对概率进行建模,再通过Sigmoid函数将其转化为合法的概率值。
总结
本节课我们一起学习了以下核心内容:
- 回顾与对比:回顾了线性回归的误差上界,并与非参数方法对比,说明了参数化模型在假设正确时的高效性。
- 优化基础:介绍了梯度下降法这一解决复杂优化问题的通用迭代算法。其核心是沿着损失函数的负梯度方向更新参数。
- 模型扩展:为了解决分类问题中线性模型的局限性,我们引入了逻辑回归模型。它通过Sigmoid函数将线性组合的输出映射为概率,巧妙地将线性思想应用于分类任务。

通过梯度下降,我们可以求解逻辑回归的优化问题(尽管没有像线性回归那样的解析解),这为我们处理更广泛的机器学习模型提供了强大的工具。在接下来的课程中,我们将深入探讨逻辑回归的损失函数及其优化细节。
11:逻辑回归与最大似然估计 🧠

在本节课中,我们将学习如何将风险最小化或经验风险最小化(ERM)的思想应用于分类问题。我们将重点介绍逻辑回归模型,并展示如何通过最大似然估计(MLE)来推导其损失函数。
从分类问题到参数化模型
上一节我们讨论了分类问题中的风险最小化思想。然而,直接应用存在一些困难。首先,分类问题中常用的损失函数(如0-1损失)不平滑。其次,我们寻找的函数(分类器)是离散的。
因此,我们希望找到一个参数化模型,例如线性模型,来简化问题。我们的思路是,对回归函数 η(x) 进行建模。
我们最初考虑将其建模为线性函数 θᵀx,但线性函数的输出范围是整个实数轴 R,而我们需要将其映射到 [0, 1] 区间以表示概率。
一个简单的解决方案是应用一个将 R 映射到 (0, 1) 的函数。我们从 x 的某个线性函数出发,然后应用一个映射函数 σ。σ 可以是任何将 R 映射到 (0,1) 的函数,一个常见的选择是 Sigmoid 函数。
选择 Sigmoid 函数是因为它在数学上易于处理。
因此,如果我们将回归函数 η(x) 建模为 σ(θᵀx),那么我们实际上是在建模条件概率:
P(Y = 1 | X = x) = σ(θᵀx)
这就是给定 X 时 Y 的条件概率模型。
通过条件概率指定联合分布
另一种思考方式是回到最初的问题。我们有一个来自未知分布的 (X, Y),并获得从中独立同分布抽取的训练数据。我们的目标是弄清楚这个未知分布。
正如我们所看到的,我们可以通过 X 的边缘分布和给定 X 时 Y 的条件分布来描述这个联合分布。在分类问题中,通常足以指定 P(Y = 1 | X = x)。
为什么只指定这个就足够了?因为它完全指定了 Y 的演化。P(Y = 0 | X = x) 自然就是 1 - P(Y = 1 | X = x)。对于二分类问题,这足以指定整个条件分布。对于多分类问题,则需要指定更多参数。
我们的方法是使用参数族(例如 Sigmoid 函数)来指定这个条件概率 P(Y = 1 | X = x),这等价于指定回归函数 η。
连接回经验风险最小化
现在,我们如何将其与经验风险最小化联系起来?我们希望将模型拟合到训练数据,并得到一个类似 ERM 的形式:
min_θ (1/n) Σ_{i=1}^n L(y_i, η_θ(x_i))
其中 L 是某个损失函数,η_θ 是我们的模型。
问题在于,如何得到一个好的损失函数 L?


最大似然估计方法
假设我们有一个训练集 {(x₁, y₁), ..., (x_n, y_n)}。根据我们的模型,我们知道:
P(Y_i = 1 | X_i = x_i) = σ(θᵀx_i)
给定这个参数模型,估计参数 θ 的一个通用且严谨的方法是 最大似然估计。
我们指定给定 X 时 Y 的条件概率质量函数。由于在给定 X 的条件下 Y_i 是独立的,联合条件概率可以分解为乘积形式。
为了紧凑地表示伯努利分布的 PMF,我们可以使用公式:
P(Y=y) = p^y * (1-p)^{1-y},其中 y ∈ {0, 1}。
将我们的模型 p = σ(θᵀx_i) 代入,对于单个数据点,其概率为:
P(Y_i=y_i | X_i=x_i) = [σ(θᵀx_i)]^{y_i} * [1 - σ(θᵀx_i)]^{1-y_i}
因此,整个数据集的似然函数(视为参数 θ 的函数)为:
L_n(θ) = Π_{i=1}^n [σ(θᵀx_i)]^{y_i} * [1 - σ(θᵀx_i)]^{1-y_i}
最大似然估计是寻找使这个似然函数最大化的参数 θ。
推导损失函数
最大化似然函数等价于最大化其对数似然,也等价于最小化负对数似然。
对似然函数取对数并乘以 -1/n,我们得到:
-(1/n) log L_n(θ) = -(1/n) Σ_{i=1}^n [ y_i log(σ(θᵀx_i)) + (1-y_i) log(1 - σ(θᵀx_i)) ]
这正是经验风险最小化的形式!其中,每个数据点的损失函数是:
L(y, p) = -[y log(p) + (1-y) log(1-p)]
这个函数被称为 二元交叉熵损失。
因此,逻辑回归的 ERM 问题可以写为:
min_θ (1/n) Σ_{i=1}^n L_BCE( y_i, σ(θᵀx_i) )
这与线性回归的 ERM 形式非常相似。在线性回归中,我们有二次损失 (y_i - θᵀx_i)²。在逻辑回归中,我们只是将损失函数换成了交叉熵损失。
简化损失函数形式
利用 Sigmoid 函数的性质,我们可以进一步简化交叉熵损失。
Sigmoid 函数定义为:σ(z) = 1 / (1 + e^{-z})
其反函数(logit 函数)为:σ^{-1}(p) = log( p / (1-p) )
将 p = σ(z) 代入交叉熵损失并进行代数运算,可以得到一个简化形式:
L(y, z) = log(1 + e^{z}) - y*z
其中 z = θᵀx。这个损失函数直接度量了真实标签 y 和对数几率 z 之间的差异。
因此,逻辑回归也可以被视为直接对对数几率 θᵀx 进行建模,并最小化损失 log(1 + e^{θᵀx_i}) - y_i*(θᵀx_i)。
优化与模型几何
一旦我们得到了这个优化问题,就可以通过梯度下降等方法求解。可以证明,这个损失函数关于参数 θ 是凸的,因此通常可以收敛到全局最小值。
从几何角度看,逻辑回归模型定义了线性的决策边界。决策边界是满足 P(Y=1|X=x) = 0.5 的点集,即:
σ(θᵀx) = 0.5 => θᵀx = 0
这是一个通过原点的超平面。参数 θ 的方向垂直于这个决策边界。
参数 θ 的范数 ||θ|| 控制了决策的“锐利”程度或问题的内在噪声水平:
||θ||大:Sigmoid 曲线很陡峭,从概率 0 到 1 转变很快,分类置信度高,噪声小。||θ||小:Sigmoid 曲线平缓,概率变化慢,分类不确定性高,噪声大。
因此,逻辑回归模型本身已经内置了噪声机制,由参数 θ 的幅度控制。
总结
本节课中,我们一起学习了:
- 逻辑回归模型:通过对数几率函数将线性预测
θᵀx映射到概率σ(θᵀx),用于建模P(Y=1|X=x)。 - 最大似然估计:为参数模型推导损失函数提供了一个通用且严谨的框架。对于逻辑回归,MLE 自然地导出了 二元交叉熵损失。
- 经验风险最小化形式:逻辑回归的训练目标是最小化平均交叉熵损失,这与线性回归的最小化均方误差形式相似。
- 模型特性:逻辑回归产生线性的决策边界 (
θᵀx = 0)。参数θ的方向决定边界朝向,其范数控制分类的置信度或问题的噪声水平。

通过最大似然估计,我们为分类问题找到了一个平滑、可优化的损失函数,从而能够使用梯度下降等算法有效地训练模型。
12:模式识别与机器学习导论

在本节课中,我们将要学习模式识别与机器学习中的核心概念,包括最优分类器、风险最小化框架、损失函数以及从理论到实践的估计方法。我们将从简单的二元分类问题入手,逐步扩展到更一般的情况。
概述:从预测问题到最优分类器 🎯
我们从一个预测问题开始,目标是预测一个输出变量 $ Y $。我们首先关注一个非常简单的案例:当 $ Y $ 是二元变量(例如0或1)时,这就是一个分类问题。我们还研究了当特征 $ X $ 也是离散的情况。
通过分析,我们讨论了如何找到最优分类器。最优分类器是一个函数 $ f(X) $,它将输入空间 $ X $ 映射到输出空间 $ Y $,并预测出最可能的 $ Y $。
为了衡量分类器的性能,我们引入了损失函数 $ L(Y, \hat{Y}) $,它度量了预测值 $ \hat{Y} $ 与真实值 $ Y $ 之间的差异。与分类器相关联的风险 $ R(f) $ 是这个损失函数的期望值。
一个具体的损失函数是0-1损失:$ L(Y, \hat{Y}) = \mathbb{I}(Y \neq \hat{Y}) $。在这种情况下,风险就等于误分类的概率 $ P(Y \neq f(X)) $。
那么,什么是最优分类器呢?我们通过以 $ X $ 为条件对风险进行分解来寻找答案。最优规则被称为贝叶斯决策规则。然而,这一切都基于一个假设:我们知道 $ X $ 和 $ Y $ 的联合分布。在现实中,我们并不知道这个分布,因此需要从训练数据中对其进行估计。
风险最小化:一般框架 📊
上一节我们介绍了在已知联合分布下的最优分类器。本节中我们来看看更一般的风险最小化框架。
风险的一般形式是期望损失:$ R(f) = \mathbb{E}[L(Y, f(X))] $。通过以 $ X $ 为条件,我们可以将风险分解为:
其中,$ \mathbb{E}_X $ 是关于 $ X $ 边际分布的期望。我们无法控制 $ X $ 的分布,但可以针对每个具体的 $ x $ 最小化条件期望 $ \mathbb{E}[L(Y, d) | X = x] $,其中 $ d $ 是我们的决策(在分类中是预测的类别,在回归中是预测的实数值)。
因此,最优决策规则 $ f^*(x) $ 就是在给定 $ X = x $ 时,最小化条件期望损失的那个决策 $ d $:
对于0-1损失,这个规则简化为选择后验概率最大的类别:
对于平方损失 $ L(Y, \hat{Y}) = (Y - \hat{Y})^2 $(即回归问题),最优规则是条件期望,也称为回归函数:
我们可以通过展开平方项并求导来证明这一点。设 $ g(d) = \mathbb{E}[(Y - d)^2 | X=x] $。展开得:
这是一个关于 $ d $ 的二次函数,其最小值在导数等于零处取得:
这证明了在均方误差意义下,给定 $ X $ 时对 $ Y $ 的最佳预测就是其条件期望。
从理论到实践:参数估计与核方法 ⚙️
上一节我们讨论了已知分布时的最优理论解。本节中我们来看看当分布未知时,如何从数据中进行估计。
在离散特征的情况下,我们可以使用简单的计数来估计联合概率分布。例如,概率 $ P(Y=1|X=x) $ 的估计量为:
这可以重写为加权平均的形式:$ \sum_{i=1}^{n} w_i(x) Y_i $,其中权重 $ w_i(x) $ 与指示函数 $ \mathbb{I}(X_i = x) $ 成正比。
这个思想可以推广到连续特征或更一般的情况。我们不再要求 $ X_i $ 严格等于 $ x $,而是引入一个核函数 $ K(x, X_i) $ 来衡量 $ x $ 和 $ X_i $ 之间的相似度。核函数在 $ X_i $ 接近 $ x $ 时值较大,远离时值较小。
于是,我们的估计量变为局部加权平均:
其中 $ h $ 是一个带宽参数,控制着“局部”的范围。这种方法称为核平滑或Nadaraya-Watson估计。
常见的核函数包括:
- 高斯核:$ K(u) = \exp(-u^2/2) $,产生平滑的权重衰减。
- 箱式核:$ K(u) = \mathbb{I}(|u| \leq 1) $,在指定邻域内赋予均匀权重。
- K近邻:本质上也是一种核方法,权重只分配给距离 $ x $ 最近的 $ K $ 个点。

代码实践:实现核回归分类器 💻
理论需要实践来巩固。以下是如何使用PyTorch实现一个Nadaraya-Watson核分类器的简要示例。核心思想是将上述公式转化为矩阵运算,以提高效率。
import torch
import torch.nn as nn
class NadarayaWatson(nn.Module):
def __init__(self, X_train, y_train, kernel, bandwidth=1.0):
super().__init__()
self.X_train = X_train
self.y_train = y_train.float() # 确保类型一致
self.kernel = kernel
self.bandwidth = bandwidth
def forward(self, X):
# 计算核矩阵:X (m个测试样本) 和 self.X_train (n个训练样本) 之间的相似度
# 结果 K 的形状为 (m, n)
pairwise_dist = torch.cdist(X, self.X_train) / self.bandwidth
K = self.kernel(pairwise_dist) # 例如高斯核:torch.exp(-pairwise_dist**2 / 2)
# 计算加权平均:分子是 K * y_train,分母是 K 每行的和
numerator = torch.mm(K, self.y_train.view(-1, 1)) # (m, n) @ (n, 1) -> (m, 1)
denominator = torch.sum(K, dim=1, keepdim=True) # (m, 1)
# 预测值是条件概率估计
y_hat = numerator / denominator # (m, 1)
return y_hat.squeeze() # 返回 (m,)
# 示例:高斯核函数
def gaussian_kernel(distances):
return torch.exp(-distances**2 / 2)
# 假设我们有训练数据 X_train, y_train 和测试数据 X_test
model = NadarayaWatson(X_train, y_train, kernel=gaussian_kernel, bandwidth=0.5)
predictions = model(X_test)
# 对于分类,可以将预测概率与阈值(如0.5)比较得到类别
class_predictions = (predictions > 0.5).int()
在这个实现中:
__init__方法存储训练数据和核函数配置。forward方法是核心:- 使用
torch.cdist高效计算所有测试点与所有训练点之间的距离。 - 通过核函数将距离转换为相似度权重。
- 通过矩阵乘法
torch.mm快速计算加权和。 - 最后通过逐元素除法得到预测值。
- 使用
- 通过调整
bandwidth参数,我们可以控制模型的平滑程度。较小的带宽使模型更关注局部数据点,可能产生更复杂(也可能更过拟合)的决策边界;较大的带宽则考虑更广的范围,使模型更平滑。
我们可以用这个模型在数据集(如乳腺癌数据集)上测试不同带宽对测试误差的影响,并绘制误差曲线来寻找最佳带宽。
总结与回顾 🏁
本节课中我们一起学习了模式识别与机器学习的核心基础。
- 最优决策理论:我们从预测问题出发,定义了损失函数和风险。在已知数据联合分布的前提下,通过条件风险最小化,我们推导出了最优分类器(贝叶斯分类器)和最优回归器(条件期望)。
- 风险最小化框架:我们建立了一个通用的框架 $ f^*(x) = \arg\min_d \mathbb{E}[L(Y,d)|X=x] $。这个框架统一了分类(0-1损失)和回归(平方损失)问题。
- 从理论到估计:由于真实分布未知,我们需要从数据中学习。对于离散数据,可以使用简单的频率估计。对于连续数据,我们引入了核方法和局部加权平均的思想,通过核函数度量相似性,从而对条件概率或回归函数进行非参数估计。
- 实践实现:我们看到了如何将Nadaraya-Watson估计器实现为一个高效的、基于矩阵运算的PyTorch模块,并讨论了带宽参数的选择对模型性能的影响。



理解从总体最优解到基于数据的估计这一过程,是掌握机器学习的关键。核方法为我们提供了一种强大而灵活的非参数建模工具,是连接经典统计与现代机器学习的重要桥梁。
13:逻辑回归模型与梯度下降优化 🧠
在本节课中,我们将学习逻辑回归模型的基本原理、如何从该模型生成数据,以及如何使用梯度下降及其变体(如带动量的梯度下降)来拟合模型。我们还将通过代码示例来直观地理解这些概念。
模型概述与贝叶斯最优决策
上一节我们介绍了回归函数的一般形式。本节中,我们来看看一个具体的参数化模型。其核心思想是假设回归函数具有特定的参数形式。
在二分类问题中,我们可以将最优的贝叶斯规则设定为一个阈值决策。具体来说,当 P(Y=1|X=x) > 0.5 时,我们预测为类别1,否则预测为类别0。在逻辑回归模型中,这个概率由sigmoid函数给出:
公式: P(Y=1|X=x) = σ(θ^T x) = 1 / (1 + exp(-θ^T x))
因此,决策边界就是使得 θ^T x = 0 的所有点 x 构成的超平面。这个超平面的方向由参数向量 θ 决定。当我们沿着与 θ 平行的方向移动时,预测的概率值会增大。
数据生成与模型噪声
要从上述模型生成数据,不仅需要指定参数形式,还需要一个关于 X 的模型。通常,我们假设 X 服从多元高斯分布。
数据点并非都远离决策边界。许多点靠近边界,它们的标签具有不确定性。例如,一个在边界上的点 x,其 θ^T x = 0,则 σ(0) = 0.5。这意味着在生成标签时,有50%的概率为1,50%的概率为0。这种不确定性是模型固有的噪声,代表了真实标签与贝叶斯最优预测之间的差异,也构成了问题的基本误差极限。
信号噪声比(SNR)的大小会影响决策边界的“清晰度”。SNR较大时,sigmoid函数变化陡峭,两类数据点分离较好;SNR较小时,sigmoid函数变化平缓,数据点混合程度高,分类更困难。
模型拟合:极大似然估计与损失函数

为了拟合逻辑回归模型,我们采用极大似然估计(MLE)框架。在独立同分布的假设下,数据的似然函数是每个数据点伯努利概率的乘积。
取负对数后,最大化似然等价于最小化以下经验风险(也称为对数损失或二元交叉熵损失):

公式: L(θ) = - (1/N) Σ [y_i log(σ(θ^T x_i)) + (1 - y_i) log(1 - σ(θ^T x_i))]
我们可以将模型看作两部分:一个线性层 z = θ^T x,后接一个非线性的sigmoid激活函数 σ(z)。在优化时,通常将sigmoid函数合并到损失函数中,直接对线性输出 z 计算损失。
梯度下降优化算法
最小化上述损失函数需要使用优化算法。最基础的方法是梯度下降。



以下是梯度下降算法的基本步骤:
- 初始化参数
θ。 - 计算当前参数下的损失
L(θ)。 - 计算损失关于参数的梯度
∇L(θ)。 - 沿负梯度方向更新参数:
θ = θ - η * ∇L(θ),其中η是学习率。 - 重复步骤2-4,直到收敛。



在代码实现中,我们需要:
- 注意张量的克隆以避免引用问题。
- 在每次反向传播后,将参数的梯度属性清零,防止梯度累积。


基础梯度下降在损失函数平坦区域可能收敛缓慢。为了解决这个问题,我们可以使用带动量的梯度下降。
带动量的梯度下降引入了一个速度变量 v,其更新规则如下:
v = α * v + ∇L(θ)(累积梯度动量)θ = θ - η * v(沿动量方向更新参数)

其中 α 是动量系数(通常接近0.9)。这种方法有助于在梯度变小时继续保持更新速度,加速收敛。
学习率 η 和动量系数 α 是需要调优的超参数。在实践中,经常使用网格搜索在验证集上寻找最佳组合。

代码实践:从生成数据到模型训练
现在,让我们通过代码将理论付诸实践。我们将生成合成数据,并用带动量的梯度下降训练一个逻辑回归模型。
首先,我们生成数据。假设真实的 θ* = [3, 3],X 来自标准高斯分布,SNR控制信号的强度。
代码:数据生成
import torch
n_samples = 500
SNR = 1.0
X = torch.randn(n_samples, 2) # 设计矩阵
theta_true = torch.tensor([3.0, 3.0])
z = X @ theta_true * SNR
prob = torch.sigmoid(z) # P(Y=1|X)
Y = torch.bernoulli(prob) # 根据概率生成标签
接下来,我们定义对数损失函数。
代码:损失函数
def logistic_loss(theta, X, Y):
z = X @ theta
# 使用数值稳定的log-sigmoid计算
loss = torch.nn.functional.binary_cross_entropy_with_logits(z, Y, reduction='mean')
return loss
然后,我们实现带动量的梯度下降。



代码:带动量的梯度下降
def gradient_descent_momentum(loss_fn, theta_init, X, Y, lr=0.1, momentum=0.9, steps=1000):
theta = theta_init.clone().requires_grad_(True)
v = torch.zeros_like(theta) # 速度变量
loss_history = []
theta_history = [theta_init.clone()]
for _ in range(steps):
loss = loss_fn(theta, X, Y)
loss.backward()
with torch.no_grad():
v = momentum * v + theta.grad # 更新动量
theta -= lr * v # 更新参数
theta.grad.zero_() # 梯度清零
loss_history.append(loss.item())
theta_history.append(theta.clone())
return theta, loss_history, theta_history
在真实数据(如乳腺癌数据集)上应用时,需要注意为线性模型添加偏置项(intercept)。这可以通过在特征矩阵 X 前添加一列全1来实现。

代码:添加偏置项
# X_original 是原始特征矩阵 [n_samples, n_features]
X_augmented = torch.cat([torch.ones(X_original.size(0), 1), X_original], dim=1)
# 现在 theta 的维度是 [n_features + 1],第一个元素是偏置




训练完成后,我们可以评估模型在训练集和测试集上的准确率,并绘制决策边界。








总结





本节课中我们一起学习了逻辑回归模型的核心内容。我们从贝叶斯决策边界出发,理解了模型的参数化形式 σ(θ^T x) 以及其几何意义。我们探讨了模型固有的噪声和信号噪声比(SNR)对数据可分性的影响。
在模型拟合部分,我们推导了通过极大似然估计得到的目标函数——二元交叉熵损失。为了最小化这个损失,我们深入介绍了梯度下降优化算法,并针对其收敛慢的问题,引入了带动量的梯度下降变体,它通过累积历史梯度方向来加速训练。

最后,我们通过完整的代码实践,演示了从合成数据生成、模型定义、带动量的梯度下降实现,到在真实数据上应用(包括添加偏置项)的全过程。这些知识为理解更复杂的分类模型和优化算法奠定了坚实的基础。
14:多类别分类与Softmax回归 🧠
概述
在本节课中,我们将学习如何将二分类的逻辑回归模型扩展到多类别分类问题。我们将介绍Softmax函数,并学习如何构建和训练一个参数化的多类别分类模型。
从二分类到多类别分类
上一节我们讨论了逻辑回归模型及其优化方法。本节中,我们来看看如何将其扩展到处理多个类别。
二分类问题的目标是学习一个从输入 x 到输出 y 的映射,其中 y 是二元的(例如0或1)。多类别分类则非常相似,我们仍然学习从 x 到 y 的映射,但现在的 y 可以取多个值,例如从0到 C-1,其中 C 是类别总数。
为了简化表示,我们使用集合 {0, 1, ..., C-1} 来表示 C 个类别。这与PyTorch等框架的零基索引惯例一致。
参数化模型与决策边界
在二分类中,我们使用逻辑回归模型,它指定了条件概率 P(Y=1|X=x),其形式为 σ(θᵀx),其中 σ 是sigmoid函数。这本质上定义了一个线性决策边界。
对于多类别分类,我们需要指定 C 个概率值:P(Y=y|X=x),其中 y ∈ {0, 1, ..., C-1}。这些概率必须非负且和为1,因此我们有一个约束条件。
我们可以将模型写成一个通用形式:P(Y=y|X=x) = g_θ(x)_y。这里的 g_θ(x) 是一个从输入 x 映射到 C 维概率向量的函数。在二分类特例中,g_θ(x) 就是 [1-σ(θᵀx), σ(θᵀx)]。
Softmax函数:从得分到概率
如何构造函数 g_θ(x),使其输出一个有效的概率向量(各元素≥0,和为1)?一个标准且方便的选择是Softmax函数。
Softmax函数将一个 C 维向量 u 映射到另一个 C 维向量,其第 y 个分量为:
softmax(u)y = exp(u_y) / Σ^{C-1} exp(u_j)
这个函数确保输出向量的所有元素都是正数且总和为1,正好满足概率分布的要求。当 C=2 时,Softmax函数退化为sigmoid函数。
以下是Softmax函数的一个关键特性:它对输入向量的常数偏移具有不变性。也就是说,对于任意常数 c,softmax(u + c) = softmax(u)。这意味着模型参数存在不可识别性问题,不同的参数可能给出完全相同的预测。如果我们只关心预测结果,这通常不是问题;但如果需要精确恢复参数值,则需要施加额外的约束(例如固定某一类别的参数为零)。
构建多类别分类模型
现在我们可以构建完整的模型了。模型接收一个 D 维输入 x。首先,我们使用一个线性变换将 x 映射到 C 维空间,得到得分向量 z = Θᵀx,其中 Θ 是一个 C × D 的矩阵参数。然后,我们对得分向量 z 应用Softmax函数,得到属于各个类别的概率。
因此,完整的模型定义为:
P(Y=y|X=x) = softmax(Θᵀx)_y
这个模型通常被称为多项逻辑回归(Multinomial Logistic Regression)或Softmax回归。其最优决策规则是选择概率最大的类别:ŷ = argmax_y P(Y=y|X=x)。可以证明,该模型的决策边界是由超平面交集构成的,仍然是线性的,但比二分类情况更复杂。


模型训练:损失函数与优化
给定训练数据 {(x_i, y_i)},我们如何学习参数 Θ?与二分类类似,我们采用最大似然估计(MLE)。
模型的似然函数是每个样本预测概率的乘积。我们通常最小化负对数似然,这等价于最小化交叉熵损失(Cross-Entropy Loss)。
对于单个样本 (x, y),交叉熵损失定义为:
L_CE(y, z) = -log( softmax(z)_y )
其中 z = Θᵀx 是模型的得分输出。
对于整个训练集,经验风险为:
R_n(Θ) = (1/n) Σ_{i=1}^n L_CE(y_i, Θᵀx_i)
我们的目标是找到最小化 R_n(Θ) 的参数 Θ。由于这个损失函数通常是凸的(对于线性模型),我们可以使用梯度下降法或其变体(如带动量的随机梯度下降)进行优化。优化过程与二分类逻辑回归非常相似,只是损失函数的形式不同。
在PyTorch中实现
以下是如何在PyTorch中实现和训练一个Softmax回归模型的关键步骤。
首先,我们需要理解PyTorch中的一些基本模块。

1. Softmax函数
PyTorch的 F.softmax 函数可以方便地计算Softmax。需要指定沿哪个维度进行归一化(通常是特征维度)。
import torch.nn.functional as F
z = torch.tensor([[1.0, 0.0, -1.0]])
prob = F.softmax(z, dim=1) # 沿列(特征)维度计算
2. 线性层
PyTorch的 nn.Linear 层实现了 z = Wx + b 的线性变换。
import torch.nn as nn
linear_layer = nn.Linear(in_features=2, out_features=3, bias=True)
# 这将创建一个 3x2 的权重矩阵 W 和一个 3 维的偏置向量 b
3. 构建完整的Softmax回归模型
我们可以通过继承 nn.Module 类来定义自己的模型。
class SoftmaxRegression(nn.Module):
def __init__(self, input_dim, output_dim):
super(SoftmaxRegression, self).__init__()
self.linear = nn.Linear(input_dim, output_dim)
def forward(self, x):
# 线性变换后接Softmax
z = self.linear(x)
return F.softmax(z, dim=1)
4. 生成与可视化模拟数据
为了演示,我们可以从一个已知的“真实”模型中生成数据,并观察决策边界。
# 创建真实模型并生成数据
true_model = SoftmaxRegression(input_dim=2, output_dim=4)
X = torch.randn(2000, 2)
# 通过真实模型得到概率,然后根据多项式分布采样标签
with torch.no_grad():
probs = true_model(X)
# torch.multinomial 用于根据概率进行采样
Y = torch.multinomial(probs, num_samples=1).squeeze()
通过缩放线性层的权重,可以控制生成数据中的“噪声”水平,从而观察决策边界的清晰度变化。
5. 训练新模型
定义好模型、损失函数(nn.CrossEntropyLoss 已经包含了Softmax)和优化器后,就可以进行训练了。
model = SoftmaxRegression(input_dim=2, output_dim=4)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
for epoch in range(num_epochs):
optimizer.zero_grad()
outputs = model(X_train)
loss = criterion(outputs, Y_train)
loss.backward()
optimizer.step()





总结
本节课中我们一起学习了多类别分类的基本框架。我们从二分类的逻辑回归出发,引入了Softmax函数作为将任意得分向量转换为概率分布的核心工具,并由此构建了Softmax回归模型。我们讨论了该模型的决策边界、参数不可识别性以及用于训练的最大似然估计/交叉熵损失方法。最后,我们简要介绍了在PyTorch中实现该模型的关键组件。这为后续学习更复杂的非线性模型(如神经网络)奠定了基础。
15:PyTorch中的Softmax回归与梯度下降 🧠
在本节课中,我们将学习如何使用PyTorch框架实现Softmax回归模型,并应用梯度下降算法进行训练。我们将从构建模型的基本模块开始,逐步深入到损失计算、梯度反向传播以及随机梯度下降等核心概念。
概述:从线性模型到Softmax分类器
上一节我们介绍了线性模型作为神经网络的基础构建块。本节中,我们将看看如何扩展线性模型,构建一个用于多类分类的Softmax回归模型。
Softmax函数将线性层的原始输出(logits)转换为概率分布。其公式为:
softmax(z_i) = exp(z_i) / Σ_j exp(z_j)
其中,z_i 是第i个类别的logit值。该函数确保所有输出概率之和为1,且具有平移不变性(即对logits加上一个常数不会改变输出概率)。
1. 构建模型:线性层与Softmax
在PyTorch中,线性层(nn.Linear)是实现仿射变换 y = xW^T + b 的模块。它接受输入维度和输出维度作为参数。
以下是如何定义一个简单的线性层:
import torch.nn as nn
# 定义一个线性层,输入特征为2维,输出为3维
linear_layer = nn.Linear(in_features=2, out_features=3)
当我们向该层输入一个形状为 (n_samples, in_features) 的张量时,它会独立地对每一行(即每个样本)应用变换,输出形状为 (n_samples, out_features) 的张量。偏置项 b 会自动添加。
对于分类任务,输出维度通常等于类别数量。在线性层之后,我们应用Softmax函数来获得类别概率。


2. 定义完整的Softmax模型
现在,我们将线性层和Softmax组合成一个完整的模型。在PyTorch中,我们通过继承 nn.Module 类并定义 forward 方法来实现。
以下是Softmax模型的定义:
class SoftmaxModel(nn.Module):
def __init__(self, input_dim, output_dim):
super().__init__()
self.linear = nn.Linear(input_dim, output_dim)
def forward(self, x):
# 线性变换得到logits
logits = self.linear(x)
# 沿最后一个维度(类别维度)应用Softmax
probabilities = torch.softmax(logits, dim=-1)
return probabilities
初始化模型时,其权重和偏置是随机设置的。这种随机初始化是必要的,它为优化提供了一个起点。
3. 生成与理解数据
为了训练模型,我们需要数据。我们将使用一个“真实”的Softmax模型生成合成数据。
- 创建真实模型:实例化一个Softmax模型作为数据生成器,并固定其参数。
- 生成特征X:从标准正态分布中随机采样得到输入特征
X。 - 生成标签y:将
X输入真实模型得到概率,然后根据这些概率分布对每个样本采样,得到类别标签y。
这个过程模拟了现实世界中数据存在的噪声:即使模型给出了某个类别的概率最高,实际观察到的标签也可能不同。
4. 计算损失:负对数似然
我们的目标是让模型预测的概率分布与真实数据分布一致。常用的损失函数是负对数似然损失。
对于单个样本 (x_i, y_i),损失是模型赋予真实类别 y_i 的概率的负对数:L_i = -log(p_model(y_i | x_i))。
对于整个数据集,损失是平均负对数似然:
L = - (1/N) * Σ_i log(p_model(y_i | x_i))
在代码中,我们可以通过索引操作高效地计算这个损失:
# probs 是模型对所有样本预测的概率矩阵,形状为 (N, C)
# y 是真实标签向量,形状为 (N,)
loss = -torch.mean(torch.log(probs[torch.arange(N), y]))
5. 训练的核心:反向传播与梯度下降
理解了损失函数后,我们来看如何通过优化模型参数来最小化它。这依赖于两个关键步骤:反向传播和梯度下降。


- 反向传播(Backpropagation):这是一个利用链式法则,从损失函数开始,向后计算模型中每个参数梯度的高效算法。在PyTorch中,调用
loss.backward()会自动完成此过程,并将梯度填充到每个参数的.grad属性中。 - 梯度下降(Gradient Descent):在得到梯度后,我们沿着梯度的反方向更新参数,因为梯度方向是损失增长最快的方向。参数更新公式为:
θ_new = θ_old - η * ∇L(θ_old)
其中η是学习率,控制更新步长。
PyTorch的 torch.optim 模块提供了各种优化器(如SGD, Adam)来执行更新。一个基本的训练循环如下:


optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
for epoch in range(num_epochs):
# 前向传播,计算预测和损失
probs = model(X)
loss = -torch.mean(torch.log(probs[torch.arange(N), y]))
# 反向传播,计算梯度
optimizer.zero_grad() # 清除上一轮的梯度
loss.backward()
# 根据梯度更新参数
optimizer.step()


注意:在每次 loss.backward() 之前,必须调用 optimizer.zero_grad() 将参数的梯度清零,否则梯度会不断累积。











6. 随机梯度下降(SGD)与小批量训练





当数据集很大时,每次迭代都计算所有样本的损失和梯度(批量梯度下降)会非常慢。随机梯度下降 是更实用的方法。

其核心思想是:每次迭代只随机抽取一小部分样本(称为一个小批量或批次)来计算损失和梯度。虽然基于单个批次的梯度估计噪声更大,但它仍然是真实梯度的一个无偏估计,并且计算效率极高。





以下是实现小批量SGD的关键代码:


batch_size = 64
for epoch in range(num_epochs):
# 随机打乱数据索引
indices = torch.randperm(N)
for i in range(0, N, batch_size):
# 获取一个小批量的索引
batch_idx = indices[i:i+batch_size]
X_batch, y_batch = X[batch_idx], y[batch_idx]
# 在这个小批量上进行前向传播、反向传播和参数更新
probs = model(X_batch)
loss = -torch.mean(torch.log(probs[torch.arange(len(batch_idx)), y_batch]))
optimizer.zero_grad()
loss.backward()
optimizer.step()
与批量梯度下降相比,SGD的训练损失曲线会更波动,但通常能更快地达到一个不错的解,有时甚至有助于跳出局部最优。
7. 模型评估与决策边界
训练完成后,我们需要评估模型性能。对于分类任务,一个直观的指标是准确率,即模型预测类别(取概率最高的类别)与真实标签一致的样本比例。



我们可以通过可视化决策边界来理解模型学到了什么。对于二维输入的多类Softmax回归,决策边界是多个线性边界的交汇区域。在噪声较低的情况下,训练后的模型决策边界应能较好地逼近真实模型生成数据时的边界。




然而,评估时必须使用独立的测试集。如果只在训练集上评估,当样本量很小时,模型可能会“记住”数据(过拟合),从而得到虚假的高准确率。这强调了将数据分为训练集和测试集的重要性。


总结与展望
本节课中我们一起学习了:
- 使用
nn.Linear和nn.Module在PyTorch中构建Softmax回归模型。 - 理解并实现了负对数似然损失函数。
- 掌握了训练神经网络的核心循环:前向传播、损失计算、反向传播(
loss.backward())和参数更新(optimizer.step()),并理解了梯度清零(optimizer.zero_grad())的必要性。 - 认识了随机梯度下降的原理与优势,并实现了小批量训练。
- 了解了模型评估的基本方法和过拟合的风险。


Softmax回归是一个线性分类器。当数据本身不是线性可分时(例如,一个类别被另一个类别环形包围),它的性能会受限。下一节,我们将探讨解决此问题的两种主要思路:特征映射(将数据投影到更高维空间使其线性可分)和神经网络(通过堆叠非线性层来构建复杂的非线性决策边界)。神经网络正是这种思路的自然延伸,也是现代AI模型的基础。
16:神经网络入门 🧠
在本节课中,我们将学习神经网络的基本概念。我们将从线性分类模型的局限性开始,探讨如何通过引入非线性组件来构建更强大的模型,即神经网络。我们将了解其基本结构、工作原理,并通过简单的代码示例来直观理解。
概述
上一节我们介绍了逻辑回归等线性分类模型。这些模型本质上是带有特定损失函数的线性函数,其分类边界是线性的(例如直线或超平面)。然而,当数据分布更复杂时,例如类别边界是曲线或环形时,单纯的线性模型将无法很好地工作。
本节中,我们将看看如何通过构建神经网络来扩展线性模型,使其能够学习复杂的非线性决策边界。
从线性模型到非线性模型
线性模型的形式通常为 f(x) = θ^T x,其中 x 是特征向量。这种模型的表达能力有限。
为了处理非线性模式,一个直接的扩展思路是使用特征映射。另一个非常流行且强大的方法是引入神经网络。
神经网络的核心思想是:引入简单的非线性组件,并将它们组合起来。
神经网络的基本构建块
那么,具体如何操作呢?让我们从一个简单的线性函数开始:
f(x) = w^T x + b
在神经网络中,我们在线性变换后引入一个非线性函数,称为激活函数。
假设 σ 是一个从实数映射到实数的非线性函数,例如:
- Sigmoid 函数:将输入映射到 (0, 1) 区间。
- ReLU(修正线性单元)函数:
σ(z) = max(0, z)。它几乎像线性函数,但对负输入输出为零。
现在,我们构建一个简单的单层网络:
z = σ(θ^T x)
这里,σ 被逐元素地应用于线性组合的结果。这样,我们就得到了一个非线性变换。
组合层:深度神经网络
单个非线性层的能力仍然有限。神经网络的强大之处在于层的组合。
我们可以将第一层的输出 z 作为第二层的输入:
第一层:z = σ(θ₁^T x)
第二层:输出 = σ(θ₂^T z)
最终,我们得到一个由参数 θ₁ 和 θ₂ 定义的复合函数:
G(x) = σ( θ₂^T ( σ( θ₁^T x ) ) )
通过堆叠更多这样的层,我们就得到了一个深度前馈神经网络。信息从输入层流向输出层,没有反馈循环。
网络架构与神经元
以下是描述上述两层网络的常见图示方式:

输入 (x) → [线性层 θ₁] → [激活函数 σ] → 隐藏层 (z) → [线性层 θ₂] → [激活函数 σ] → 输出

- 输入层:接收原始特征
x。 - 隐藏层:
z中的每个单元称为一个“神经元”。每个神经元计算所有输入的线性组合,然后通过激活函数。 - 输出层:产生最终的预测值。

这种结构受到大脑中神经元连接方式的启发:每个神经元接收来自其他神经元的信号(加权和),如果信号超过某个阈值(由激活函数和偏置项控制),则被激活并传递信号。




为什么使用多层组合?
一个自然的问题是:为什么不直接使用一个复杂的非线性函数,而要组合多个简单函数?
- 表达性与可控性:直接设计一个通用的高维非线性函数非常困难。通过组合简单的线性层和固定的非线性激活函数,我们定义了一个受控但依然非常富有表达力的函数族。
- 参数效率与理论保证:即使只有两层,只要隐藏层足够宽,神经网络理论上可以以任意精度逼近任何“合理的”函数(通用近似定理)。同时,其参数数量仍可管理。
- 优化便利性:这种组合结构使得利用链式法则计算梯度(反向传播)变得非常高效,便于使用梯度下降法进行优化。





实践中的神经网络
在实际应用中,特别是在分类任务中,我们通常会在神经网络的末端加上一个 Softmax 层,将最终的输出转换为类别概率。




因此,一个用于多类分类的完整神经网络流程是:
输入 → 多个(线性层 + 激活函数)→ 最终线性层 → Softmax → 类别概率



我们可以灵活地设计网络架构:
- 改变隐藏层的数量(深度)。
- 改变每一层神经元的数量(宽度)。
- 使用不同的激活函数。

以下是构建一个简单两层网络的代码框架示例:
import torch
import torch.nn as nn


class SimpleNN(nn.Module):
def __init__(self, input_dim, hidden_dim, output_dim):
super(SimpleNN, self).__init__()
self.layer1 = nn.Linear(input_dim, hidden_dim) # 第一线性层
self.activation = nn.ReLU() # 激活函数
self.layer2 = nn.Linear(hidden_dim, output_dim) # 第二线性层
# 注意:分类任务中,Softmax通常合并到损失函数中计算
def forward(self, x):
z = self.activation(self.layer1(x))
output = self.layer2(z)
return output # 输出的是 logits(未归一化的对数概率)

# 实例化模型
model = SimpleNN(input_dim=2, hidden_dim=10, output_dim=1)
当我们随机初始化这个模型并检查其输出时,即使尚未训练,它也已经可以产生复杂的非线性形状。训练过程就是通过优化算法(如梯度下降)调整参数 θ,使这些形状能够拟合我们的数据。
总结


本节课中我们一起学习了:
- 线性模型的局限性:无法处理复杂的非线性决策边界。
- 神经网络的核心思想:通过组合线性变换与简单的非线性激活函数来构建强大的非线性模型。
- 基本架构:包括输入层、隐藏层、输出层,以及前馈传播的过程。
- 设计灵活性:可以通过调整深度、宽度和激活函数来设计不同的网络架构。
- 实践概览:我们看到了如何用代码框架定义一个简单的神经网络,并理解了其初始状态和训练目标。




神经网络为我们提供了构建复杂模型的强大框架。在接下来的课程中,我们将深入探讨如何有效地训练这些模型。
17:语言模型基础与Bigram实现 🧠

概述
在本节课中,我们将学习语言模型的基本概念,特别是Bigram模型。我们将了解如何将文本建模为一个简单的概率模型,并使用神经网络框架(如PyTorch)来实现和训练它。本节课是理解现代大型语言模型(如GPT)的基础。
从神经网络到语言模型
上一节我们讨论了通过神经网络进行非线性参数建模的方法。从这一思路出发,我们可以探索更多现代技术。
大规模、多层的神经网络在大量数据集上训练,催生了图像分类、语言建模等领域的突破性性能。
另一个方向是使用特征映射或基函数来建模非线性,这引出了核方法与核技巧。从核方法出发,我们可以讨论与再生核希尔伯特空间相关的有趣理论,这些是捕捉核思想的函数空间。
此外,还有像支持向量机这样的方法,它使用不同的损失函数(如铰链损失)和最大间隔分类的思想。正则化的思想也贯穿其中,我们在作业中已经见过。
本节课我想重点讨论的是特征映射和正则化。如果时间允许,我们也会简要提及集成方法(如随机森林)和无监督学习(如表示学习、聚类、密度估计)。生成模型(如扩散模型、变分自编码器)是当前的热点,但它们需要更多的背景知识。
鉴于课程时间,我们今天将聚焦于一个核心且 surprisingly simple 的模型:Bigram语言模型。它是理解ChatGPT等复杂模型的概念基石。
什么是语言模型?
人们希望建模语言,即对文本序列建模,然后进行预测。
基本思想是:如果给我一些文本,我能预测下一个词,那么我就能预测下下个词,从而生成文本。这就是当前所有生成模型的工作原理。
你给模型一些文本(上下文),它生成下一个词。你可以把整个问答过程看作是一段由分隔符隔开的文本。模型根据截止到当前点的文本来预测后续部分。
它基于海量文本进行训练,并不严格区分问题或答案,整个序列都是文本。模型根据之前生成的所有内容,来生成下一个词。
将语言建模转化为监督学习问题
这看起来不像一个监督分类问题,但我们可以将其转化为一个。
假设我们有一段文本。我们观察一个大小为 T 的块。在这个块中,每个元素是一个词,或者更技术地说,是一个词元。它可能是一个字符或字符组合。
我们从索引0开始,假设有 T 个词元。我们将前 T-1 个词元称为 X,将第 T 个词元称为 Y。
词元属于一个大小为 C 的词典。我们可以将每个词编码为索引(例如,0代表词典中的第一个词)。
这样一来,这就变成了一个多类分类问题:给定 X,预测 Y 的类别(即下一个词是什么)。我们学过的所有方法都可以应用到这里。
唯一的问题是 X 是离散的。X 有多少种可能的组合?是 C^(T-1) 种。如果上下文长度 T 是8,词典大小 C 是64,那么组合数就是 64^8,这是一个巨大的数字。
我们无法像最初几讲那样,简单地通过计数来估计经验联合分布 P(X, Y),因为组合太多,很多组合在文本中根本不会出现。
伪似然与独立性近似
我们采用一种重要的近似思想:伪似然。
我们假设从长文本中随机抽取的、可能重叠的文本块是独立同分布的。虽然这些块在原始文本中并不独立,但我们忽略这种依赖性,将其视为独立样本。
这是一种一阶近似。它极大地简化了问题,并且在实践中效果很好。
现在,我们只需要对一个通用的文本块 [w0, w1, ..., wT] 进行建模。
Bigram模型与马尔可夫假设
任何序列的概率都可以分解为:
P(w0, w1, ..., wT) = P(w0) * P(w1|w0) * P(w2|w0,w1) * ... * P(wT|w0,...,wT-1)
在Bigram语言模型中,我们做一个关键的简化假设:下一个词的出现只依赖于前一个词。即:
P(wt | w0, ..., wt-1) ≈ P(wt | wt-1)
这意味着序列是一个马尔可夫链。如果我们进一步假设这个条件概率不随时间位置改变(齐次马尔可夫链),那么整个模型就可以用一个矩阵来表示。
我们用一个 C x C 的矩阵 θ 来建模。其中,行索引由前一个词 wt-1 决定,列索引对应下一个词 wt。矩阵的每一行都是一个概率分布,表示给定前一个词时,下一个词的概率。
公式表示:
P(wt = j | wt-1 = i) = softmax(θ[i])_j
其中 θ[i] 是矩阵 θ 的第 i 行,softmax 函数将其转换为一个概率分布。
这个矩阵被称为Bigram统计矩阵,因为它收集了所有“词对”的统计信息。

模型生成文本的过程
模型是固定的。生成文本时:
- 给定一个初始上下文(最后
T个词)。 - 模型查看上下文的最后一个词
wt-1,找到矩阵θ中对应的行θ[wt-1]。 - 对该行应用
softmax得到下一个词的概率分布。 - 从这个分布中采样(或选择概率最高的词),得到新词
wt。 - 将
wt加入上下文,移除最旧的词,重复步骤2-4。
这就是一个简单的自回归生成过程。模型的随机性来自采样步骤。同样的提示可能产生不同的输出。
模型训练:转化为交叉熵损失
我们将每个训练样本视为一个 (X, Y) 对,其中 X 是前一个词的索引,Y 是下一个词的索引。
对于参数矩阵 θ,给定 X=i 时,模型对 Y 的预测逻辑值为向量 θ[i]。经过 softmax 后,得到概率分布。
我们的目标是最大化训练数据的似然,这等价于最小化负对数似然。对于单个样本 (i, j),损失为:
L = -log( softmax(θ[i])_j )
这正好就是交叉熵损失,衡量的是模型预测分布与真实“one-hot”分布之间的差异。
对于整个数据集,损失是所有样本损失的平均。我们可以使用梯度下降来优化矩阵 θ。
代码实现解析
以下我们将结合一段简化的PyTorch代码,说明Bigram模型的关键实现步骤。
1. 数据准备:编码与解码
首先,需要将文本字符转化为模型可以处理的数字索引。
# 创建词汇表
text = "..." # 输入文本
chars = sorted(list(set(text))) # 唯一字符列表
vocab_size = len(chars) # 词典大小 C
# 创建编码映射
stoi = {ch:i for i,ch in enumerate(chars)} # 字符 -> 索引
itos = {i:ch for i,ch in enumerate(chars)} # 索引 -> 字符
encode = lambda s: [stoi[c] for c in s] # 编码函数
decode = lambda l: ''.join([itos[i] for i in l]) # 解码函数
# 将整个文本编码为张量
data = torch.tensor(encode(text), dtype=torch.long)
2. 构建数据集(批处理)
我们需要从长文本中随机抽取训练块 (X, Y)。这里 X 和 Y 是等长的序列,Y 是 X 向右移动一位的结果。
def get_batch(split):
# 选择训练集或验证集
data = train_data if split == 'train' else val_data
# 随机生成一批起始索引
ix = torch.randint(len(data) - block_size, (batch_size,))
# 构建输入 x 和目标 y
x = torch.stack([data[i:i+block_size] for i in ix])
y = torch.stack([data[i+1:i+block_size+1] for i in ix])
return x, y
# 示例:x[0] = [24, 43, 58, ...], y[0] = [43, 58, 46, ...]
# 在位置 t,模型应根据 x[0][:t+1] 来预测 y[0][t]
3. 定义Bigram模型
模型的核心是一个词嵌入层,它本质上是一个查找表。
import torch.nn as nn
class BigramLanguageModel(nn.Module):
def __init__(self, vocab_size):
super().__init__()
# 词元嵌入表,形状为 (vocab_size, vocab_size)
# 第 i 行对应词 i 的嵌入,也即预测下一个词的逻辑值向量
self.token_embedding_table = nn.Embedding(vocab_size, vocab_size)
def forward(self, idx, targets=None):
# idx 和 targets 形状都是 (batch_size, block_size)
# 获取逻辑值
logits = self.token_embedding_table(idx) # 形状: (B, T, C)
if targets is None:
# 生成模式,只返回逻辑值
return logits, None
else:
# 训练模式,计算损失
B, T, C = logits.shape
# 将逻辑值和目标展平,以计算交叉熵损失
logits = logits.view(B*T, C)
targets = targets.view(B*T)
# 计算负对数似然损失(交叉熵)
loss = F.cross_entropy(logits, targets)
return logits, loss
说明:
nn.Embedding(vocab_size, vocab_size)层是一个可学习的矩阵,其权重形状为(C, C)。这正是我们的参数矩阵θ。- 输入
idx是整数索引张量,嵌入层会输出对应行的向量。 cross_entropy函数内部已经包含了softmax操作,它直接接受逻辑值logits和目标targets。
4. 训练循环
训练过程就是标准的梯度下降。
model = BigramLanguageModel(vocab_size)
optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3)
for step in range(max_iters):
# 获取一个数据批
xb, yb = get_batch('train')
# 前向传播,计算损失
logits, loss = model(xb, yb)
# 反向传播,更新参数
optimizer.zero_grad(set_to_none=True)
loss.backward()
optimizer.step()
5. 文本生成
使用训练好的模型进行自回归生成。
def generate(model, idx, max_new_tokens):
# idx 是当前上下文,形状为 (B, T)
for _ in range(max_new_tokens):
# 获取预测(只取最后一个时间步的上下文)
logits, loss = model(idx[:, -block_size:])
# 聚焦于最后一个时间步的预测
logits = logits[:, -1, :] # 形状变为 (B, C)
# 应用softmax得到概率
probs = F.softmax(logits, dim=-1)
# 从分布中采样下一个词元
idx_next = torch.multinomial(probs, num_samples=1)
# 将新词元附加到序列中
idx = torch.cat((idx, idx_next), dim=1)
return idx

# 从初始上下文开始生成
context = torch.zeros((1, 1), dtype=torch.long) # 初始词元索引(例如0)
print(decode(generate(model, context, max_new_tokens=100)[0].tolist()))
总结
本节课我们一起学习了语言模型的基础——Bigram模型。
我们首先了解了如何将语言建模问题转化为监督学习中的分类任务。然后,通过引入马尔可夫假设(下一个词仅依赖于前一个词),我们得到了极其简单的Bigram模型,它仅用一个 C x C 的概率矩阵即可描述。
我们详细讨论了该模型的训练目标,即最小化交叉熵损失,这等价于最大似然估计。最后,我们通过PyTorch代码逐步解析了Bigram模型的实现细节,包括数据编码、批处理、模型定义、训练循环以及文本生成过程。

Bigram模型虽然简单,但它包含了现代语言模型最核心的自回归生成思想。理解它是迈向理解更复杂模型(如基于Transformer的GPT)的重要第一步。
18:从二元语法模型到GPT架构 🚀

在本节课中,我们将学习语言模型的核心思想,从基础的二元语法模型过渡到更复杂的GPT架构。我们将探讨如何将序列预测问题建模为分类任务,以及如何通过参数化和优化来构建更强大的模型。
概述:从序列预测到语言模型
上一节我们介绍了语言模型的基本概念。其核心思想是:给定一个由标记(token)组成的序列(上下文),我们想要预测序列中的下一个标记。这本质上是一个具有离散特征和离散标签(即词汇表中的所有可能标记)的多类别分类问题。
例如,如果我们的词汇表大小 C = 64,上下文长度 T = 8,那么可能的上下文组合数量是 64^8,这是一个巨大的数字。直接计算所有组合的联合概率分布是不现实的。
二元语法模型与马尔可夫假设
为了解决组合爆炸问题,我们引入了马尔可夫假设。该假设认为,下一个标记的概率仅依赖于前一个标记,而不是整个历史上下文。
具体来说,我们不是建模完整的联合概率 P(w_0, w_1, ..., w_T),而是将其分解为一系列条件概率的乘积:
P(w_0, w_1, ..., w_T) ≈ P(w_0) * P(w_1 | w_0) * P(w_2 | w_1) * ... * P(w_T | w_{T-1})
这被称为二元语法模型。此时,我们需要估计的参数就从 C^(T+1) 个减少到了 C * C 个(一个条件概率表)。
以下是估计这些概率的直观方法:
- 遍历训练文本中的所有连续标记对。
- 统计每个标记
w_i后面出现标记w_j的频率。 - 条件概率
P(w_j | w_i)就可以用这个频率来近似。

参数化与逻辑参数
然而,直接使用频率作为概率存在限制(例如,必须满足非负且和为1)。在机器学习中,我们更倾向于使用参数化的方法。
我们不直接建模概率矩阵 P,而是引入一个逻辑参数矩阵 θ(logits)。这个矩阵的每一行对应一个上下文标记,每一列对应一个目标标记。θ 的元素可以是任意实数。
然后,我们通过 softmax 函数将每一行的逻辑值转换为概率分布:
P(w_next = j | w_current = i) = softmax(θ[i])_j = exp(θ[i, j]) / Σ_k exp(θ[i, k])
这种参数化的好处是:
- 优化过程可以自由地调整实数参数
θ,不受概率约束的限制。 - 我们可以使用基于梯度的优化算法(如随机梯度下降)来最小化损失函数。
经验风险最小化框架

我们将语言模型训练纳入经验风险最小化框架。对于一组训练数据(文本块),我们的目标是最大化模型分配给真实下一个标记的概率,这等价于最小化负对数似然损失。
对于一个批次的数据,损失函数可以写为:
# 伪代码示意
loss = 0
for (context, target) in batch:
logits = model(context) # 模型输出逻辑值矩阵,形状为 [batch_size, context_length, vocab_size]
probs = softmax(logits, dim=-1)
# 计算交叉熵损失:-log(probs[对应真实目标标记的位置])
loss += cross_entropy_loss(probs, target)
loss = loss / len(batch)
通过反向传播计算损失相对于参数 θ 的梯度,并使用优化器(如Adam)更新参数,模型就能逐渐学会预测下一个标记。
从二元模型到GPT:引入嵌入
二元语法模型只考虑了前一个标记的信息。而像GPT这样的现代模型,其核心突破之一是能够考虑整个上下文中所有标记的信息。这是通过嵌入和自注意力机制实现的。
首先,每个输入标记(一个整数ID)会被转换成两个嵌入向量:
- 标记嵌入:表示标记本身的语义信息。
- 位置嵌入:表示该标记在序列中的位置信息。

这两个向量相加,得到该标记的最终表示 x_t,它是一个 d_model 维的向量(例如384维)。因此,一个长度为 T 的上下文被表示为一个矩阵 X,其形状为 [T, d_model]。








GPT的Transformer块
GPT模型由多个相同的 Transformer块 堆叠而成。每个块的主要作用是让序列中每个标记的表示能够“注意到”其他所有标记的信息,并进行信息整合。





一个Transformer块主要包含两个子层:
- 多头自注意力层:这是模型的核心。它允许序列中的每个位置根据其他所有位置的加权组合来更新自己的表示。权重(注意力分数)由标记之间的相关性动态计算得出。
- 前馈神经网络层:这是一个应用于每个位置上的独立全连接层,用于进一步处理信息。


每个子层周围都应用了残差连接和层归一化,这有助于稳定深度网络的训练。








模型输出与预测


经过多个Transformer块处理后,我们得到了经过深度上下文编码的序列表示。最后,通过一个线性层(通常称为语言模型头)将每个位置的 d_model 维向量映射回词汇表大小 C 的维度,得到逻辑值。




最终,对最后一个位置的输出逻辑值应用 softmax,就得到了下一个标记的预测概率分布。
最终输出逻辑值: logits = Linear(LayerNorm(TransformerBlock(...(X))))
预测概率: P(next_token) = softmax(logits[-1, :])




总结


本节课我们一起学习了语言模型的演进路径:
- 我们从序列预测问题出发,将其形式化为分类任务。
- 为了简化计算,引入了马尔可夫假设和二元语法模型。
- 通过逻辑参数化和softmax函数,我们将问题转化为可优化的机器学习模型。
- 在经验风险最小化框架下,使用梯度下降来训练模型。
- 最后,我们探讨了GPT架构的核心思想:使用标记嵌入和位置嵌入将离散符号转化为连续向量,并通过堆叠Transformer块(利用自注意力机制)来建模长距离上下文依赖,从而构建出强大的语言模型。



下一节课,我们将深入探讨Transformer块中自注意力机制的详细工作原理。
19:GPT模型架构与正则化 🧠





在本节课中,我们将学习GPT(Generative Pre-trained Transformer)模型的核心架构,并探讨如何通过正则化技术来防止模型过拟合。我们将从语言模型的基本概念出发,深入理解自注意力机制,最后介绍一种处理高维特征空间过拟合问题的方法。






语言模型与监督学习

上一节我们讨论了语言模型学习。其核心在于,这些模型本质上是一个监督学习问题,目标是预测给定上下文中的下一个词。



这是一个非常自然的分类问题。例如,上下文可能很长,如果仅将其视为离散特征,预测效果可能不佳。二元语言模型(Bigram Language Model)就是一个简单的例子。


在初始化阶段,模型的输出可能不理想。经过训练后,输出会有所改善,但仍然不够完美,生成的句子可能不连贯或存在语法问题。

训练损失与评估损失通常非常接近,这表明模型复杂度适中,没有出现过拟合。这与我们在第一章中看到的训练集和测试集误差接近的情况类似。



GPT模型的核心创新
那么,GPT模型试图建模和学习词语之间的复杂关系。它有几个关键创新:

1. 词嵌入(Word Embedding)
在更大的语言模型中,我们有一个参数表 theta,可以将其视为词的嵌入(Embedding)。这本质上是为每个词创建一个向量表示,用于计算下一个词的条件概率。
词嵌入将词语映射到向量空间,使其能够编码语义信息。这样做的好处是,我们可以对词向量进行数学运算。例如,“猫”和“狗”的向量相加,可能得到一个代表“动物”含义的向量。我们可以通过线性或非线性变换来操作这些向量,就像操作实数向量一样。




2. 位置编码(Positional Encoding)

同样地,词语在序列中的位置也是一个离散索引。我们可以将位置信息也编码成一个向量。




例如,一个句子中的每个词,我们不仅嵌入词本身,还嵌入其位置。然后,我们将词嵌入向量和位置编码向量相加。这样,位置信息就可以与词语的语义信息进行交互。

最终,对于一个长度为 T 的上下文,我们得到一个维度为 T x d_model 的矩阵,其中 d_model 是嵌入维度(例如384)。
GPT模型架构总览


这些嵌入向量会经过一系列块(Blocks)或层(Layers)的处理。每一层通常包含层归一化(Layer Norm)和自注意力(Self-Attention)等操作。



在模型的最后,有一个线性层将 d_model 维的向量映射到词汇表大小 V 的维度(例如65)。这样,对于序列中的每个位置,我们都得到一个 V 维的向量,可以看作是下一个词的逻辑值(Logits)。我们取最后一个位置的输出,应用Softmax函数,就得到了下一个词的概率分布。
整个模型架构可以概括为以下几个步骤:
- 通过查表获取词嵌入和位置编码,并相加。
- 将结果输入一系列相同的Transformer块。
- 每个块内部进行自注意力和前馈神经网络处理。
- 最后通过一个线性层(LM Head)映射到词汇表维度。





Transformer块详解
每个Transformer块是模型的核心组件。它的结构基于残差连接(Residual Connection)的思想。
残差连接是指将块的输入直接加到其输出上。这类似于在回归中,先用一个模型预测,然后对残差(预测值与真实值的差)再用另一个模型建模。在神经网络中,这有助于信息流动和梯度传播,使深层网络更容易训练。
一个标准的Transformer块主要包含两个子层:
- 多头自注意力层(Multi-Head Self-Attention):这是模型的核心创新,我们稍后会详细解释。
- 前馈神经网络层(Feed-Forward Network):这是一个简单的多层感知机(MLP),通常包含一个隐藏层和非线性激活函数。

每个子层周围都应用了层归一化和残差连接。具体流程为:输入 -> 层归一化 -> 子层计算 -> 加回输入(残差连接)。





自注意力机制


现在,让我们深入理解自注意力机制,它是Transformer架构的灵魂。
自注意力的灵感可以追溯到我们在第二章讨论过的“相似性加权平均”思想。在非参数回归中,我们通过计算查询点与所有训练数据点的相似度,来加权平均对应的响应值。






一个常见的相似度度量是内积的指数形式:sim(x, z) = exp(x^T z)。这可以写成Softmax函数的形式。我们可以将其参数化,引入一个可学习的权重矩阵 A,使得相似度变为 exp(x^T A z)。这定义了在由 A 决定的度量下的内积,增加了模型的灵活性。
Transformer中的自注意力机制正是这一思想的扩展和应用。其核心操作如下:


对于输入序列中的每个位置 i 的向量 x_i:
- 通过线性变换生成一个查询向量(Query)
q_i。 - 通过另一个线性变换生成一个键向量(Key)
k_i。 - 通过第三个线性变换生成一个值向量(Value)
v_i。

为了计算位置 i 的新表示,我们:
- 用
q_i与所有位置的k_j计算相似度(通常用点积)。 - 对这些相似度应用Softmax函数,得到一组权重。
- 用这组权重对所有的
v_j进行加权求和,得到位置i的输出。
公式表示如下:
Attention(Q, K, V) = softmax(Q K^T / sqrt(d_k)) V

其中,Q, K, V 分别是由所有位置的查询、键、值堆叠而成的矩阵,d_k 是键向量的维度,缩放因子 sqrt(d_k) 用于稳定梯度。
“自注意力” 的含义在于,查询、键、值都来自同一组输入序列。这使得序列中的每个位置都可以关注到所有其他位置的信息,并根据相似度动态地聚合信息。




“多头注意力” 是指并行地运行多个这样的自注意力机制(即多个“头”),每个头使用不同的线性变换参数,从而允许模型在不同的表示子空间中关注不同的信息。最后,将所有头的输出拼接起来,再通过一个线性层映射回原始维度。




在GPT这样的解码器(Decoder-Only)模型中,我们还会使用掩码(Mask),确保在预测位置 i 时,只能看到位置 i 之前的信息,而不能看到未来的信息,这符合语言建模的因果性。








模型规模与过拟合
当我们增加模型的层数(块的数量)和参数量时,模型的表达能力会增强。例如,一个拥有6层、约1000万参数的小型GPT模型。

然而,如果模型参数量远大于训练数据量(token数量),就容易出现过拟合。过拟合表现为训练损失持续下降,但验证损失在经过一段下降后开始上升,这意味着模型记住了训练数据的噪声,而非学习到泛化模式。


解决过拟合的一种常见方法是早停(Early Stopping),即在验证损失不再下降时停止训练。另一种更根本的方法是使用正则化(Regularization)。








特征映射与正则化


最后,我们简要介绍一种将线性模型扩展到非线性领域并控制过拟合的方法:特征映射结合正则化。
假设我们有一个线性回归模型:y = θ^T x。要使其能够拟合非线性关系,我们可以先将输入 x 通过一个特征映射函数 φ(x) 映射到高维空间。例如,将一维的 x 映射为多项式特征 φ(x) = [1, x, x^2, ..., x^k]。
然后,我们在新的高维特征空间 φ(x) 中执行线性回归:y = θ^T φ(x)。这样,在原输入空间 x 中,模型就变成了一个非线性函数(如多项式)。
然而,特征映射会急剧增加特征维度。如果原始特征维度是 d,映射到 k 阶多项式,特征数量会爆炸式增长。当参数数量接近甚至超过样本数量时,方差会增大,极易导致过拟合。
此时,我们可以引入正则化,例如在损失函数中添加权重的L2范数惩罚项(岭回归/Ridge Regression):
损失函数公式:
L(θ) = Σ (y_i - θ^T φ(x_i))^2 + λ ||θ||^2
其中,λ 是正则化强度超参数。通过调整 λ,我们可以在偏差(Bias)和方差(Variance)之间进行权衡:
λ很大时,模型权重被严重压缩,偏差高,方差低(可能欠拟合)。λ很小时,模型接近普通最小二乘,方差高,偏差低(可能过拟合)。- 合适的
λ可以找到最佳平衡点,提升模型在未见数据上的性能。
在实际的深度学习框架中,这种L2正则化通常通过权重衰减(Weight Decay) 来实现,即在优化器更新权重时,额外减去一个与权重成正比的小量。
总结
本节课中,我们一起学习了:
- GPT模型架构:理解了词嵌入、位置编码、Transformer块(包含残差连接、层归一化、前馈网络)以及最终的概率映射。
- 自注意力机制:深入探讨了其数学原理(查询、键、值、相似度加权平均),以及多头注意力和因果掩码的作用。
- 过拟合与正则化:认识了模型规模过大可能导致的过拟合问题,并学习了通过特征映射将模型非线性化后,如何使用L2正则化(权重衰减)来控制模型复杂度,在偏差和方差之间取得平衡,从而提升泛化能力。

这些概念是现代大语言模型的基础,理解它们有助于我们更好地把握深度学习模型的设计与优化思路。

浙公网安备 33010602011771号