☰
机器学习复习地图:模型损失优化三段式与结构演化
2026/11/2 12:57:29 网站建设 项目流程

简介:这份李宏毅机器学习全套资料面向希望系统入门并逐步进阶机器学习的学习者,围绕监督学习、无监督学习、半监督学习、强化学习以及支持向量机、神经网络与深度学习等主题,配有课件、课程讲解和作业解答,帮助读者把概念理解落实到动手实践中。压缩包共234个文件、约70.21MB,包含png图表、py脚本、csv数据、pdf讲义、md笔记、pptx课件和ipynb实验文件等,兼顾课堂演示、数据处理、模型训练与作业复现。已有2497人学习,课程完整度与内容组织具备一定参考价值。读者可据此梳理课程主线,结合课件中的图表和示例理解算法,利用作业答案与脚本核对数据预处理、特征选择、模型训练、误差分析等环节,并参考讲义笔记完成复习和查漏补缺,既适合初学者建立知识框架,也便于有基础者按章节继续深入。

1. 先画地图:机器学习这套课到底在讲几条线

机器学习这门课最容易被学成一堆互不相干的模型名:回归、分类、卷积、循环、注意力、生成对抗、扩散,单看每一讲都懂,合起来就散。这套课程资料真正有价值的地方,是它从第一讲到最后都在用同一条主线解释新东西——把任务写成一个带未知参数的函数,用一个损失函数衡量输出和答案差多远,再沿着让损失变小的方向挪参数。先把地图画成三层:底层是「模型、损失、优化」的三段式,中间层是把三段式套到不同数据形态上长出来的结构,图像用卷积、序列用循环和注意力,顶层是训练范式,监督、自监督、生成、强化四条路。

课程中不少看起来“很新”的章节,本质上是把这三层里的某一层换掉:换损失就是换评价标准,换结构就是换归纳偏置,换范式就是换标签从哪来。这套资料适合已经跑过几个模型、但知识点还散着的人,用来把零散章节重新对齐到这三层上,复习时才知道自己在补哪一格。

2. 三段式主线:模型、损失与优化的复习骨架

这一章是整份笔记的基础结构。后面所有结构创新、所有训练技巧,都是在这三段式上做局部替换,所以第一遍复习如果只背模型图,第二遍一定会卡在“为什么这里要换成这个损失”上。比较稳妥的顺序是:先把三段式的每一格各自能填什么搞清楚,再去看具体任务怎么组合。

2.1 骨架三格:函数、损失、优化器

模型这一格解决的是“假设空间长什么样”,线性回归假设输出是输入的线性组合,深层网络假设输出是一串非线性变换的复合。损失这一格解决的是“什么叫好”,优化这一格解决的是“怎么走到好的地方去”。三格必须配套,最常见的错配是:任务指标是准确率,损失却随手挑了一个和准确率几乎无关的光滑函数,训练曲线很好看,实际指标不涨。

在复习时,可以把常见任务压成下面这张对照表,先记住“输出层形态和损失是绑定的”,很多推导就不用死记。

任务输出层常用损失常看的指标典型错配
回归线性输出,无激活均方误差 / L1MAE、RMSE用 MSE 却按分类阈值评价
二分类单个 logit二元交叉熵AUC、F1前面又加一次 sigmoid
多分类类别数个 logit交叉熵准确率、宏平均 F1前面又加一次 softmax
多标签每类一个 logit每类二元交叉熵mAP当成互斥多分类
排序 / 生成打分或概率序列对比损失、负对数似然命中率、困惑度用逐 token 损失评价整句

选损失的第一约束不是“听起来合理”,而是“可导且梯度有信息量”。均方误差配 sigmoid 输出,在输出饱和时梯度会被压得很小,训练前期几乎不动;换成交叉熵,梯度里那层饱和的导数会被约掉,这就是后面 2.3 要展开的那个拐点。

2.2 梯度下降与反向传播:最容易当成黑匣子的部分

反向传播不是一套独立算法,它是链式法则在计算图上的调度方案:前向时每个节点记住自己的输入,反向时按拓扑逆序把上游梯度乘上本地导数往下传。理解到这一层,很多“玄学”就有解释了——梯度消失是连乘里有一堆小于 1 的因子,梯度爆炸是连乘里有一堆大于 1 的因子,残差连接和归一化层做的事情,本质是给这条连乘链开一条导数接近 1 的旁路。

学习率和批大小要一起调。批大小翻倍时,梯度的方差大约减半,等效的步长可以适当放大,但放大过头会直接发散;线性缩放是个起点,不是定律。Adam 之所以是默认选择,是因为它对每个参数维度做了二阶矩的归一化,初期对学习率没那么敏感,代价是泛化有时不如调好的带动量随机梯度下降,这一点在复现论文数字时经常被忽略。

# 三段式的最小实现:模型 / 损失 / 优化 model = nn.Sequential(nn.Linear(784, 256), nn.ReLU(), nn.Linear(256, 10)) loss_fn = nn.CrossEntropyLoss() # 内部已含 log_softmax,模型输出不要再过 softmax optimizer = torch.optim.Adam(model.parameters(), lr=1e-3) for epoch in range(epochs): model.train() # 打开 dropout、批归一化的训练行为 for x, y in train_loader: logits = model(x) # (B, 10),未归一化分数 loss = loss_fn(logits, y) # y 是类别下标,不是 one-hot optimizer.zero_grad() # 不清零会与上一批梯度累加 loss.backward() # 反向传播把梯度写进 param.grad optimizer.step() # 按优化器规则更新参数 model.eval() # 切到推理行为,批归一化改用滑动统计量 with torch.no_grad(): # 验证阶段不建计算图,显存占用约减半 run_validation(model)

这段代码里三个容易写反的细节:zero_grad必须在backward之前、更新之前;CrossEntropyLoss吃的是 logits 和类别下标,如果模型尾部已经接了 softmax,等价于做了两次归一化,损失会一直卡在一个偏高的平台上;train()和eval()不是可选项,批归一化和 dropout 在两种模式下的行为完全不同,忘了切换的表现是“训练集指标很好,验证集怎么调都很差”。

提示:调不动的时候先别改结构,把学习率乘以 0.1 和 10 各跑一遍,再看损失曲线在前 100 步是抖还是平。抖多半是学习率过大或批太小,平多半是学习率过小、损失和任务不匹配、或者输入没归一化。

2.3 分类任务的拐点:softmax 与交叉熵为什么必须绑在一起

分类是这门课的分水岭:回归里“输出一个数”的直觉到这里失效,因为输出的语义变成了“每个类别的分数”,需要一个把分数变成概率、并且让损失对分数的梯度足够直接的结构。softmax 负责把任意实数压成概率,交叉熵负责衡量预测分布和真实分布的距离,两者组合后对 logit 的梯度恰好是“预测概率减真实标签”,形式极简,误差大时梯度大,误差小时梯度小,不会因为概率饱和而停住。

如果把交叉熵换成均方误差,链路上会多出一层 softmax 的导数,而这一项在预测概率接近 0 或 1 时接近 0,结果就是“错得很离谱但学得很慢”。这也是为什么几乎所有分类实现都把 softmax 和交叉熵合并成一个算子,数值上更稳,也避免了先算概率再取对数带来的下溢。

延伸出来的两个变体要分清适用场景:标签平滑把硬标签改成软标签,抑制过度自信,适合标签可能有噪声的分类;focal loss 给易分样本降权,适合正负样本极度不平衡的检测类任务。两者都是在改“真实分布长什么样”,而不是改模型结构,所以不要和结构侧的调整混在一起做对比实验。

3. 结构演化:从卷积到自注意力的形状与直觉

结构这一块最忌讳按年代背。卷积不是“旧方法”,自注意力也不是“更高级的方法”,它们各自编码了一种关于数据的先验:图像邻域相关、序列顺序相关、任意两个位置都可能相关。复习时把每种结构对应到“它假设了什么”,比记住层数有用得多。

3.1 卷积:用三个假设换参数效率

卷积层编码了三个假设:局部性(相邻像素更相关)、平移等变性(同一模式出现在哪都该被识别)、层级组合(边缘拼成纹理、纹理拼成物体)。这三个假设换来的是参数共享,一个 3×3 卷积核只有 9 个权重,却能扫过整张图。感受野可以按层累加估算,堆两层 3×3 的感受野等价于一层 5×5,但参数更少、非线性更多,这就是“小核堆深”的由来。

池化层的作用是降采样并扩大感受野,但现在很多结构改用步长大于 1 的卷积代替池化,因为后者是可学习的下采样。复习时容易被问到的对比是:全连接层参数量随空间尺寸平方增长,卷积层与空间尺寸无关,自注意力层的计算量随序列长度平方增长。

结构参数复杂度感受野编码的先验主要短板
全连接与输入尺寸平方相关全局无参数爆炸、丢空间结构
卷积与通道数平方相关逐层累加局部性、平移等变长距离依赖要多层堆叠
循环与隐藏维度平方相关理论上全局顺序、时序共享无法并行、长程梯度衰减
自注意力与维度平方相关全局内容寻址、位置弱先验序列长度平方复杂度

3.2 从循环到注意力:把梯度路径从 T 步压到 1 步

循环网络的训练要沿时间展开做反向传播,梯度从第 T 步传回第 1 步要连乘 T 次同一个权重矩阵,谱半径略小于 1 就衰减、略大于 1 就爆炸。长短期记忆网络用门控和一条加性的单元状态把这条连乘改成了加法通路,缓解但不根治,因为信息仍然要一步步往前挪。

注意力机制换了个思路:任意两个位置之间直接建一条长度为 1 的连接,梯度路径不再随时序长度增长,并且所有位置可以并行计算。代价是失去了顺序先验,所以必须显式加位置编码;同时计算量随序列长度平方增长,长序列场景要靠稀疏化、分块或者线性近似来压。

一句话对比:循环结构把“顺序”写进了计算图,注意力把“顺序”降级成了输入的一部分。这也解释了为什么同一份数据上,注意力模型训练更快、显存更贵、对小数据更不友好。

3.3 自注意力的形状与 Transformer 的复习重点

自注意力真正难的不是公式,是张量形状。把批维度、头维度、序列长度、每个头的维度四个轴理清楚,多头就只是“把通道切成几份各算一次再拼回来”,不是玄学。

import numpy as np def attention(Q, K, V, mask=None): # Q: (B, H, T_q, d_k) K/V: (B, H, T_k, d_k),H 为头数 d_k = Q.shape[-1] scores = Q @ K.transpose(0, 1, 3, 2) / np.sqrt(d_k) # (B, H, T_q, T_k) if mask is not None: # mask 形状需可广播到 (B, H, T_q, T_k),True 表示该位置可见 scores = np.where(mask, scores, -1e9) scores = scores - scores.max(axis=-1, keepdims=True) # 减最大值防溢出 weights = np.exp(scores) weights = weights / weights.sum(axis=-1, keepdims=True) # 沿 key 维归一化 return weights @ V # (B, H, T_q, d_k)

参数含义和易错点要一起记:除以sqrt(d_k)是因为点积的方差随维度线性增长,不缩放会让 softmax 进入饱和区,梯度几乎为零;softmax 必须沿最后一个轴(key 维)做,做在 query 维上语义就全错了;mask 的语义在不同代码库里可能相反,有的是“True 表示屏蔽”,移植时必须看注释而不是凭形状猜。

Transformer 的其余重点可以列成四组:位置编码解决顺序信息,正弦编码和可学习编码各有取舍;残差加层归一化解决深堆叠的优化问题,Pre-LN 更稳、Post-LN 在精调后可能更好;掩码有两种,填充掩码处理变长批,因果掩码保证自回归时看不到未来;多头的作用是让不同的头关注不同的关系,头数增加时每个头的维度要相应减小,保持总维度不变。

4. 生成与自监督:四个目标函数背后的概率分歧

这一块是很多人第一遍学完最糊的部分,因为模型名字多、示意图多,但真正区分它们的只有两件事:隐变量怎么定义,目标函数在优化什么。把这两件事想清楚,生成模型就不再是一堆互不相干的网络结构。

4.1 自监督的两种范式:从数据本身造标签

自监督的核心思路是把“没有标签”变成“标签由数据自己生成”。主流有两条路:一条是对比式,把一个样本的两种增强视为正对,批内其他样本视为负对,损失要求正对相似度高、负对相似度低,温度系数控制分布的尖锐程度,批越大负样本越多、效果通常越好;另一条是重建式,随机遮掉一部分输入让模型还原,图像里遮大块、文本里遮词,模型必须理解上下文才能填对。

两条路的取舍很实际:对比式对数据增强的设计极其敏感,增强选错了,正对本身就不相似,怎么调都上不去;重建式对增强不敏感,但如果遮得太少,模型可以靠局部插值蒙混过关,学不到语义。复习时建议把“代理任务是什么、正负样本怎么构造、对批大小是否敏感”这三问答出来,比背模型名有用。

范式代理任务典型损失对批大小主要风险
对比式判断两视图是否同源InfoNCE 类高度敏感增强设计错则正对失真
重建式还原被遮内容重建误差不敏感遮挡比例小则任务过易
预测式预测未来或相对位置交叉熵 / 回归中等捷径特征(如颜色统计)

4.2 四个生成模型的目标函数分歧

变分自编码器走的是“最大化对数似然的下界”,下界拆成两项:重建项要求解码器能从隐变量还原输入,KL 项要求隐变量分布靠近先验。这两项互相拉扯,KL 权重太小则隐空间混乱、采样质量差,权重太大则隐变量被压死、重建模糊。生成对抗网络绕开了似然,直接用一个判别器当可学习的目标函数,优点是样本锐利,缺点是训练不稳定、模式坍塌,判别器损失下降并不代表生成质量变好。

标准化流要求变换可逆且雅可比行列式好算,因此似然可以精确计算,代价是结构受限、维度必须对齐。扩散模型把生成拆成很多步去噪,每一步只学“怎么去掉一点点噪声”,训练目标极其简单,采样却要迭代几十上百步,质量和速度的权衡点落在采样步数与调度策略上。

模型优化目标隐变量采样方式常见误解
变分自编码器对数似然下界低维连续一次解码损失低就代表样本清晰
生成对抗网络极小极大博弈噪声向量一次生成判别器损失可作质量指标
标准化流精确对数似然与数据同维一次逆变换一定比其它模型更好训
扩散模型去噪回归与数据同维多步迭代训练损失可直接跨模型比较

注意:这四类的损失数值没有可比性。变分自编码器的下界、流模型的精确似然、扩散模型的去噪误差,量纲和含义都不同,拿两个数字比大小是最常见的一类误读。

4.3 从序列生成到强化学习:似然比那条线

生成模型和强化学习看起来是两块,其实共用一套数学。自回归生成时,模型每输出一个词就是一次动作,整句的对数概率就是这条轨迹的似然;当我们不满足于“拟合训练集”、而是想按某个外部回报去优化时,就变成用回报给对数概率加权,这就是策略梯度。它和对比学习里的似然比思路同源,都是“用采样估计期望的梯度”。

策略梯度的方差很大,实务上加基线、加折扣、加重要性裁剪来压方差,这些技巧和生成模型里加温度、加惩罚项的动机一致。复习到这一层,元学习、对抗样本、可解释性这些专题也能挂上来:元学习是换“任务的分布”,对抗样本是换“输入的邻域”,可解释性问的是“哪部分输入真正影响了输出”,它们都还在三段式的框架里,只是把某一格换成了更复杂的对象。

5. 易错点:五个反复翻车的地方与补法

这一章是整份笔记里最值得反复看的部分。前面几章讲的是“应该怎么理解”,这一章讲的是“实际动手时会在哪摔”,每一条都按“漏在哪、为什么会漏、怎么补”写,复习时可以直接当自检表用。

5.1 数据泄漏与验证集污染

易漏点:在划分数据集之前就做了全局归一化、全局填充缺失值、或者用全量数据拟合了特征编码;更隐蔽的一种是反复用测试集调超参数,最后报的那个数字其实是“调过的测试集分数”。

为什么漏:这些操作通常写在数据预处理脚本里,和模型代码隔着几个文件,跑通的时候没人回头检查统计量是从哪个集合算出来的;而反复看测试集这件事,在实验节奏快的时候几乎是无意识的。

怎么补:把划分提到所有预处理之前,归一化、编码、特征选择全部只在训练集上拟合,然后应用到验证集和测试集;测试集只在最终评估时打开一次,中间所有模型选择都看验证集。检查方法很简单——把预处理流水线单独抽出来跑一遍,打印每一步fit用到的样本数,如果等于全量样本数,就是漏了。

5.2 训练与推理行为不一致

易漏点:批归一化在推理时该用滑动统计量却继续用批统计量;dropout 在推理时没关;自回归解码时训练用真值输入、推理却忘了改成自己上一步的输出。

为什么漏:这三种错在训练阶段完全看不出来,训练损失照降,只有换到推理路径才暴露,而推理代码往往是另一个人写的或者几天后补的。

怎么补:把模式切换写进训练循环的固定位置,而不是靠记忆;写一个一致性检查——同一批数据在训练模式和推理模式下各跑一次前向,如果输出差异极大,先查归一化层的统计量来源;解码部分单独写一个贪心解码函数,用一条样本走通再上批量。

5.3 指标与损失脱节

易漏点:类别极不平衡时仍以准确率为主指标;损失用交叉熵但业务关心的是召回;多标签任务按单标签口径算准确率。

为什么漏:默认的评估代码通常就是准确率,一行就能出结果,而更换指标需要想清楚业务含义,成本更高。

怎么补:在实验开始前先写下“这个任务错了代价最大的是哪一类错误”,再据此选指标;不平衡场景至少同时报混淆矩阵、召回和 F1,别只看一个数;把指标计算写成独立函数并配一条单元测试,用构造的小样本验证数值符合预期。

5.4 张量形状与掩码方向

易漏点:把 softmax 做在了 query 维而不是 key 维;掩码语义搞反;广播时少了一个轴导致形状刚好对得上、语义却错了。

为什么漏:形状错误大多会直接报错,唯独“形状对但语义错”不会报错,而这类错误的表现往往只是效果差一点,很容易被归因为超参数没调好。

怎么补:每个中间张量都标注轴的含义,注释里写清(B, H, T, d)各是什么;对掩码单独做一个最小样例测试——手工构造一个明显该被屏蔽的位置,检查输出是否真的不受该位置影响;换代码库复现时,先跑一个已知答案的小例子再动真实数据。

5.5 把损失值当成模型好坏

易漏点:拿生成对抗网络的判别器损失判断生成质量;拿不同模型、不同损失函数的损失值横向比较;拿训练损失下降证明模型学到了语义。

为什么漏:损失是最容易打印的数字,而且它确实在大部分监督任务里和效果正相关,习惯一旦形成就会跨任务套用。

怎么补:给每个任务固定一套“与损失无关”的评估方式,比如生成任务看样本的多样性指标和人工抽查、分类任务看固定测试集上的混淆矩阵;跨模型比较时只比最终任务指标,不比损失;训练损失异常低但验证指标不动时,优先怀疑过拟合或数据泄漏,而不是庆祝收敛。

6. 复习清单:把这份笔记用成查漏补缺表

复习最容易陷入的误区是把讲义从头翻一遍,翻完感觉都见过,做题还是卡。比较有效的做法是反过来:先按模块给自己出题,答不上来的地方再回讲义定位。下面这张表可以直接当自测清单用,每格能合上讲义、手写出关键公式或代码,才算过。

模块必须能独立写出自测问法常见失分
三段式一个完整训练循环哪一行忘了会静默出错忘了切换训练/推理模式
优化反向传播的链式路径梯度消失出在连乘的哪一段只会说“梯度消失”不会定位
分类softmax 与交叉熵的组合梯度换成均方误差会怎样模型尾部重复归一化
卷积感受野的逐层计算两层 3×3 为何等价一层 5×5只记结论不会推
注意力缩放点积注意力的完整实现为什么要除根号 dmask 语义和方向搞反
生成变分下界的两个组成部分KL 项权重变大会发生什么跨模型比较损失值
自监督两条范式的代理任务对比学习为何依赖大批增强设计与任务不匹配

具体操作建议按三天一轮走。第一天只做“合上讲义写代码”,把三段式、注意力、一个生成模型的目标函数各写一遍,写不出来的地方标记下来,不查资料;第二天针对标记处回讲义,重点看公式的每一行对应哪个张量,把形状标在草稿上;第三天做交叉检验,用一个小数据集把写出来的代码跑通,观察损失曲线是否符合预期,不符合就回到第 5 章对症状。

还有一个很省时间的习惯:给每个模块准备一个“最小可运行例子”,参数量小到能在几分钟内跑完,比如两张图的分类、一条序列的注意力、一个二维分布的生成。概念模糊的时候不要重读讲义,直接改这个例子的一个参数,看输出怎么变,比读十页推导印象深。

我自己的教训是,早期复习总想先把所有模型结构背完再动手,结果每次卡在“知道有这么个东西,但说不清它换了哪一格”。后来改成每复习完一章就强制走一遍那张自测表,答不上来的当场标红,第二轮只碰红色部分,效率比通读高得多。这份课程资料的章节顺序本身就很适合这样切片复习,按模块对照着过一遍,能省掉不少来回翻找的时间。

从那以后我每次开新的一章之前,都会先把上一章的自测题默写一遍,写不出来就不往下走——这个习惯救过我很多次,尤其是在注意力和生成模型这两块。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询