对应:Stanford CS224N Winter 2026 Lecture 6(Final Projects: Custom and Default);Winter 2025 Lecture 7(Final Projects and Practical Tips);Manning 主讲各版本中的 “Practical Tips for Final Projects” 一讲。 配套代码:
code/lecture08/(toy_reviews.py会被第 9、10 讲复用) 预计阅读时间:3–4 小时(这一讲公式很少,但每个实验都值得自己跑一遍、改一改)
0. 本讲导航
0.1 学完本讲,你应该能够
- 为一个 NLP 项目选题、找文献、找数据,并说出几类常见的项目。
- 正确地划分训练集、验证集、测试集,识别数据泄漏、测试集复用和分布偏移。
- 建立一串由简到繁的基线;在类别不平衡时选用精确率、召回率、F1,而不是只看准确率。
- 用一套固定的流程调试神经网络:先在一小批数据上过拟合、亲眼看数据、读学习曲线、监控梯度。
- 解释为什么随机搜索常常比网格搜索好,为什么学习率要在对数尺度上搜索。
- 估计随机种子带来的波动,用置换检验和配对 bootstrap 判断一个改进是不是真的。
- 让实验可复现,并写出一份结构清楚、有消融实验和错误分析的报告。
0.2 先修知识
| 知识点 | 用在哪里 | 最低要求 |
|---|---|---|
| 第 3 讲 | 全讲 | 训练循环、过拟合与正则化、Adam、dropout |
| 第 6、7 讲 | 第 5 节 | GRU;Transformer 的训练细节(学习率预热等) |
| 基础统计 | 第 4、7 节 | 均值、标准差、“置信区间”的大致含义(不熟悉也能看懂,代码里都是用模拟的方法算的) |
0.3 本讲地图
第1节 为什么要专门讲"实践方法"
第2节 项目从哪里开始:选题、文献、数据 ← toy_reviews.py、代码 01
第3节 数据划分:泄漏、复用、偏移、交叉验证 ← 代码 05
第4节 基线与评估指标 ← 代码 01
第5节 调试神经网络 ← 代码 02(本讲重点)
第6节 超参数搜索 ← 代码 03
第7节 随机种子与显著性检验 ← 代码 04
第8节 可复现性与实验记录 ← 代码 04
第9节 读论文与写报告
第10节 CS224N 的期末项目
第11–15节 小结、与作业的关系、练习、延伸阅读、下一讲预告
这一讲的所有实验都用同一个玩具数据集:影评情感分类(toy_reviews.py)。第 9 讲会在它上面做”预训练 → 微调”,第 10 讲会用它的打分规则当作”人类偏好”。
1. 为什么要专门讲”实践方法”
读论文时,深度学习看起来很”干净”:提出一个模型,训练,报告一个比别人高的数字。真正动手时,大部分时间花在完全不同的事情上:数据有问题、代码有 bug、模型不收敛、结果时好时坏、不知道一个改进是真的还是运气。
神经网络的 bug 尤其阴险。普通程序出了错,通常会报错或者输出明显不对的东西;神经网络出了错,代码照常运行,损失照常下降,只是最后的效果差几个百分点。你很难分辨这是 bug、超参数没调好,还是任务本身就这么难。Andrej Karpathy 在一篇有名的博客里(A Recipe for Training Neural Networks,2019)把这总结为:神经网络训练会”悄无声息地失败”(fails silently)。
所以,做实验需要一套系统的方法:先建立基线,一次只改一个地方,用便宜的检查尽早发现 bug,对结果保持怀疑。本讲把这些方法整理出来,每一条都配一个可以运行的实验。
本讲还有一个目的:为 CS224N 的期末项目做准备。期末项目占课程成绩的很大一部分,它要求你像做研究一样完成一个完整的项目——这正是本讲方法的用武之地。
2. 项目从哪里开始:选题、文献、数据
2.1 几类常见的项目
| 类型 | 做什么 | 例子 |
|---|---|---|
| 应用型 | 把已有的方法用到一个新任务或新数据上 | 用预训练模型做某个低资源语言的命名实体识别 |
| 方法型 | 提出或改进一个方法,在标准任务上比较 | 一种新的参数高效微调方法 |
| 分析型 | 研究模型”为什么”有效、学到了什么、在哪里失败 | 语言模型能否理解否定?注意力头在学什么? |
| 复现型 | 复现一篇论文的结果,检验它的结论是否成立、在什么条件下成立 | 换一个数据集,论文的改进还在吗? |
对第一次做研究的人,分析型和复现型项目往往比”提出一个新方法”更容易做出扎实的结果:问题清楚,基线现成,失败了也能写出有价值的发现(“这个方法在 X 上不起作用,原因是 Y”)。
CS224N 允许两种期末项目:默认项目(课程给定任务和起始代码,第 10 节)和自选项目。
2.2 文献调研
- 从哪里找:ACL Anthology(NLP 顶会 ACL、EMNLP、NAACL 等的全部论文,免费)、arXiv(预印本)、Semantic Scholar 和 Google Scholar(看引用关系)、Hugging Face 的论文页面和数据集页面。
- 怎样读:先读几篇最近的综述(survey)或者某个基准上排名靠前的论文,看它们的”相关工作”一节,顺藤摸瓜找到这个方向最重要的几篇论文。读论文的方法见第 9.1 节。
- 要回答的问题:这个任务现在最好的方法是什么?大家用什么数据集、什么指标?最简单的基线能做到多少?还有什么没解决?
2.3 数据
先找现成的。 Hugging Face Datasets 上有上万个数据集;语言数据联盟(LDC)有很多经典的标注语料(需要机构授权);各种共享任务(shared task)和比赛也会发布数据。
自己收集和标注时要注意:
- 写一份清楚的标注指南,先小规模试标注,修改指南,再大规模标注;
- 让至少两个人标注同一部分数据,计算标注者之间的一致性(例如 Cohen’s κ)。一致性低,说明任务定义不清楚,或者任务本身就很主观——模型的”上限”也不会超过人和人之间的一致程度;
- 注意数据的许可证和隐私:能不能用于研究?能不能公开?有没有个人信息?
拿到数据后的第一件事:看数据。 打印几十条样本,看标签分布、长度分布,找奇怪的样本。这比任何模型都更能帮你理解任务。
2.4 本讲的玩具数据集
toy_reviews.py 生成简单的英文影评,标签是正面或负面。生成方式(详见文件开头的注释):先抽一个整体倾向,然后写 02 句无关的话、14 句评价某个方面的句子(每句以 25% 的概率和整体倾向相反,即”混合评价”)、50% 的概率加一句总结。标签由一个打分规则 sentiment_score 决定:正面形容词 +1、负面形容词 −1、程度副词 ×1.5、前面有否定词就反过来、总结句的关键词 ±2。
这个数据集刻意包含了真实情感分类的几个难点:情感词很多(正面、负面各约 20 个形容词),有否定(“the plot was not boring” 是正面),有混合评价。
动手:代码
01_baselines_and_metrics.py演示 1。训练集 2000 条,正好一半正面;评论长度最短 5 个词、平均 26.4 个、最长 56 个。最有区分度的词是什么?正面评论里是 see、go、would、watch、again、loved、recommended……,负面评论里是 skip、money、back、hated、avoid、waste……——全是总结句里的词,而不是形容词。因为形容词有时出现在混合评价里,还经常被否定,单独看一个形容词并不可靠。
含有 not 的正面评论占了正面评论的 47%。
花几分钟看数据,就已经知道:否定是这个任务的关键难点。只数情感词的方法一定会在这里出错。
3. 数据划分
3.1 训练集、验证集、测试集
| 用来做什么 | 用几次 | |
|---|---|---|
| 训练集 | 更新模型的参数 | 无数次 |
| 验证集(开发集,dev set) | 选择超参数、模型结构、早停的轮次;做错误分析 | 很多次 |
| 测试集 | 估计最终模型在新数据上的表现 | 一次(项目最后) |
为什么需要三份,而不是两份?因为任何被用来做选择的数据,都不再能给出无偏的估计。在验证集上选了超参数,验证集上的分数就偏乐观了(第 6.5 节);所以需要一份从没被用来做过任何选择的测试集。
常见的比例是 80/10/10 或者按固定的条数划分。数据很多时,验证集和测试集各有几千条就足够精确了(第 4.4 节);数据很少时,考虑交叉验证(第 3.5 节)。公开的基准一般有官方的划分,用官方划分,结果才能和别人的比较。
测试集的作用是估计”模型在新数据上表现如何”。这个估计很容易被无意中破坏,下面是三种最常见的方式。
3.2 数据泄漏
数据泄漏(data leakage):测试集的信息以某种方式”漏”进了训练过程。最常见的是训练集和测试集里有重复或近乎重复的样本。
动手:代码
05_data_splits_and_leakage.py演示 1。800 条不同的评论(其中 15% 标签是错的),每条重复 1~5 次(模拟同一条评论被多次转发、抓取),共 2456 条,按 7:3 划分。随机划分时,测试集里 88% 的样本在训练集里有一模一样的副本:
模型 随机划分的测试集 按原始评论分组划分 全新的干净数据 1-近邻(找最像的训练样本,抄它的标签) 93.8% 61.1% 64.1% 逻辑回归(单词 + 相邻两词) 85.5% 73.4% 81.0%
随机划分时,“死记硬背”的 1-近邻看起来最好——它甚至把错误的标签都”抄对”了(测试集里的副本带着同样的错误标签)。按原始评论分组划分之后,它的真实水平暴露出来,两个模型的排名反了过来。
真实世界里的泄漏往往更隐蔽:
- 同一个用户、同一个作者的数据同时出现在训练集和测试集里;
- 时间泄漏:用”未来”的数据训练、“过去”的数据测试,而真实使用时只能用过去预测未来;
- 用全部数据(包括测试集)做了预处理,比如建立词表、计算归一化的均值(01 号文件的
build_index只用训练集,就是这个原因); - 大模型的预训练语料里混进了测试集(数据污染,第 13 讲)。
划分数据时要问自己:测试集应该模拟什么样的”新数据”? 如果模型将来要处理新用户的评论,就应该按用户划分;如果要预测未来,就应该按时间划分。
3.3 测试集复用
每在测试集上看一次结果、并据此做一个决定,测试集就”泄漏”了一点点。
动手:代码 05 演示 2。
(a) 1000 个”模型”都是瞎猜,挑出在测试集上准确率最高的那个:
测试集大小 挑出的模型在这个测试集上 同一个模型在 1 万条新数据上 100 67.0% 50.5% 1000 55.6% 49.5% 10000 51.6% 50.2% (b) 更真实的情形:50 个正经训练的逻辑回归(各用随机选出的 30% 的特征,相当于 50 组不同的”超参数”),在 200 条的测试集上挑最好的、报告它在这个测试集上的分数。换 100 个不同的测试集重复这件事:报告的准确率平均 85.9%,这些模型的真实准确率平均只有 81.9%,虚高 4 个百分点。
一千个瞎猜的模型里,总有一些”碰巧”在 100 条的测试集上猜对 67%。测试集越小、挑选的次数越多,挑出来的最好成绩就越虚高。 真实研究中也一样:在同一个公开测试集上反复试验、挑最好的结果发表,测试集就慢慢变成了训练过程的一部分。一些被使用了很多年的基准上,确实观察到了这种现象。
对策:所有的选择——模型、超参数、特征、早停轮次——都在验证集上做,测试集只在最后用一次。 公开基准常用不公开标签的测试集:排行榜服务器只返回分数,并限制提交次数。
3.4 分布偏移
测试集和训练集来自同一个分布,并不能保证模型在实际使用时表现一样好——实际的数据可能和训练数据不一样。这叫分布偏移(distribution shift)。
动手:代码 05 演示 3。在 2000 条影评上训练的逻辑回归:
测试数据 准确率 影评 91.2% 餐厅点评 85.4% ……其中只用通用形容词的(318 条) 94.0% ……含有餐厅特有形容词的(delicious、rude……,1682 条) 83.8% 在训练集里加入 200 条餐厅点评之后:影评 91.1%,餐厅点评 88.7%。
下降主要来自模型从没见过的词:对它来说,delicious、rude 没有任何情感倾向。如果你的模型要用在餐厅点评上,在影评测试集上的 91% 就是一个虚假的承诺。测试集要尽可能像模型真正要面对的数据。 常见的偏移有:领域不同(新闻 vs 社交媒体)、时间不同(新词、新话题)、人群不同(方言、非母语者)。
加入少量目标领域的标注数据,效果明显回升。第 9 讲会看到另一种办法:在大量没有标签的文本上预训练。
3.5 数据很少时:交叉验证
只有一两百条标注数据时,留出 20% 做测试,测试集只有几十条,估计非常不稳定。k 折交叉验证(k-fold cross-validation)把数据分成 份,轮流用其中一份测试、其余 份训练,取 次结果的平均。每条数据都当过一次测试数据。
动手:代码 05 演示 4。10 份不同的、各 100 条的数据集。“真实水平”是用全部 100 条训练、在 1 万条新数据上测得的准确率:
估计方法 平均误差 平均绝对误差 随机留出 20 条做测试 −5.5% 9.0% 5 折交叉验证 −1.0% 5.6%
交叉验证的误差小得多;它略微低估了真实水平,因为每次只用 80% 的数据训练。但即使是交叉验证,平均也差了 5.6 个百分点:数据少的时候,数据集本身就有随机性(这 100 条可能碰巧比较容易或比较难),交叉验证只能消除”怎样划分”带来的随机性。
深度学习通常数据多、训练一次很贵,一般只用一个固定的验证集;数据很少、模型训练很快时,交叉验证更可靠。
4. 基线与评估指标
4.1 为什么一定要有基线
基线(baseline)是”最简单的、合理的方法能做到多少”。没有基线,一个数字没有意义:90% 的准确率是好是坏?如果多数类就有 89%,那 90% 几乎什么都没学到。
基线还帮你发现 bug:如果你的深度模型还不如一个逻辑回归,几乎可以肯定哪里出了问题。
一个好习惯是建立一串由简到繁的基线,每一级都回答一个问题:
动手:代码 01 演示 2(测试集 2000 条):
方法 准确率 含 not 的评论 不含 not 的评论 随机猜 50.7% 51.5% 49.8% 多数类 51.3% 51.0% 51.7% 关键词规则(正面词多就判正面) 67.2% 48.9% 86.0% 逻辑回归,单个词,训练 100 条 74.0% 66.0% 82.1% 逻辑回归,单个词,训练 2000 条 85.5% 75.6% 95.6% 逻辑回归,单个词 + 相邻两词,2000 条 91.2% 86.4% 96.1%
从这张表能读出很多东西:
- 随机猜和多数类是”什么都没学到”的水平,任何方法都必须明显超过它们。
- 不需要训练的关键词规则比瞎猜好得多,但在含 not 的评论上和瞎猜差不多——错误几乎都出在否定上。
- 逻辑回归从数据里学到每个词的权重,数据越多越好。
- 加上”相邻两个词”的特征(“not boring” 作为一个整体),就能处理大部分否定。一个好的特征,胜过很多复杂的技巧。
报告里一定要列出基线的结果,读者才知道你的方法到底好了多少。
4.2 准确率什么时候会骗人
类别不平衡时。垃圾邮件检测、罕见疾病、仇恨言论检测……我们关心的往往恰恰是少数类。
对二分类,以”正面”为正类,混淆矩阵有四个数:真正例 TP、假正例 FP、假负例 FN、真负例 TN。
- 精确率:预测为正的里面,有多少真的是正(“报警的时候准不准”);
- 召回率:真正的正样本里,找出了多少(“有没有漏报”);
- F1:两者的调和平均,任何一个很低,F1 都低。
多个类别时,宏平均(macro)对每个类分别算 F1 再取平均(每个类同等重要);微平均(micro)把所有类的 TP、FP、FN 加起来再算(等价于准确率,大类说了算)。
动手:代码 01 演示 3。测试集只有 10% 是正面评论:
方法 准确率 精确率 召回率 正类 F1 宏平均 F1 全猜负面 89.3% 0 0 0 47.2% 关键词规则 59.5% 17.6% 76.1% 28.5% 50.1% 逻辑回归(单词 + 两词) 91.1% 54.8% 93.0% 69.0% 81.9% 逻辑回归的混淆矩阵:真实正面 213 条中找出了 198 条(漏掉 15 条);但它把 163 条负面评论误判成了正面。
“全猜负面”什么都没学,准确率却有 89%。逻辑回归的误报远多于漏报:它是在一半正面的数据上训练的,到了正面只占 10% 的测试集上,仍然”习惯性地”按一半一半的先验去猜——训练集和测试集的类别比例不同,本身就是一种分布偏移。可以通过调高判为正面的阈值来补偿。
哪种错误代价更大,取决于应用:癌症筛查宁可误报(看重召回率),垃圾邮件过滤宁可漏掉几封(看重精确率,不能把重要邮件扔进垃圾箱)。选指标之前,先想清楚应用场景。
4.3 其他任务的指标
| 任务 | 常用指标 | 讲次 |
|---|---|---|
| 语言模型 | 困惑度 | 第 5 讲 |
| 翻译 | BLEU、chrF、COMET(用模型打分) | 第 6 讲 |
| 摘要 | ROUGE | — |
| 问答 | 精确匹配(EM)、F1(按词重叠) | — |
| 开放式生成、对话 | 人工评估、用大模型当评委(LLM-as-a-judge) | 第 13 讲 |
自动指标都只是”质量”的近似。项目里至少要人工看一些输出,确认指标的提高真的对应着质量的提高。
4.4 测试集多大才够
测试集只是从”所有可能的数据”里抽出的一个样本;换一个测试集,准确率会变。bootstrap 方法可以估计这种变化:从测试集里有放回地抽同样多的样本,算一次准确率;重复很多次,取中间 95% 的范围作为置信区间。
动手:代码 01 演示 4。两个逻辑回归在不同大小的测试集上的准确率和 95% 置信区间:
测试集大小 单个词 单个词 + 相邻两词 100 91.0% [85.0%, 96.0%] 95.0% [90.0%, 99.0%] 500 83.0% [79.6%, 86.4%] 90.2% [87.6%, 92.6%] 2000 87.5% [86.1%, 88.9%] 92.0% [90.8%, 93.2%] 10000 85.7% [85.0%, 86.4%] 91.6% [91.1%, 92.2%]
- 同一个模型在 4 个不同的测试集上的准确率,最高和最低差了 8 个百分点。小测试集上的一个数字可能离真实水平很远。
- 置信区间的宽度大约和 成正比:100 条时宽约 10 个百分点,10000 条时只有一个多百分点。准确率的标准误差是 。
- 如果两个模型的差距比置信区间还小,就不能断定哪个更好。第 7 节介绍更精确的”配对”比较方法。
5. 调试神经网络
5.1 心态:从简单开始,一次只改一个地方
- 先让最简单的版本跑通:小模型、小数据、默认的超参数。确认它能学到东西,再逐步变复杂。
- 一次只改一个地方,改完马上验证。一次改五个地方,效果变差了,你不知道是哪个改动造成的。
- 怀疑一切:数据、标签、预处理、损失函数、评估代码。效果”好得不像真的”时,更要怀疑(很可能是泄漏)。
下面这些检查都很便宜,应该成为习惯。
5.2 先在一小批数据上过拟合
一个正确的模型加上正确的训练代码,在几十条数据上一定能把训练损失降到接近 0——它有足够多的参数把这些数据”背”下来。如果做不到,几乎可以肯定是代码有 bug。
动手:代码
02_debugging_toolkit.py演示 1。GRU 分类器在 32 条数据上训练 300 步的损失(瞎猜的损失是 ):
第 0 步 第 10 步 第 50 步 第 100 步 第 200 步 第 299 步 正确 0.715 0.003 0.000 0.000 0.000 0.000 忘了 zero_grad0.715 0.473 0.000 0.000 0.141 1.392 softmax 做了两次 0.703 0.315 0.313 0.313 0.313 0.313 学习率太大(1.0) 0.715 9.629 0.023 0.000 0.000 0.000 学习率太小() 0.715 0.715 0.715 0.714 0.712 0.711
- 忘了
opt.zero_grad():PyTorch 默认把新的梯度累加到已有的梯度上。忘了清零,每一步的”梯度”都是之前所有梯度之和,更新越来越大、方向越来越乱,损失忽高忽低。 - softmax 做了两次:模型最后一层已经输出了概率,
F.cross_entropy内部又做了一次 softmax。两个类别的”logit”之差最多是 1,损失永远降不到 以下。这个 bug 非常常见,因为代码完全不报错。 - 学习率太大:损失先暴涨,之后又降到了 0——在 32 条数据上,Adam 最终还是把它们背下来了。所以过拟合测试发现不了学习率太大的问题(第 5.6 节会在完整数据上看到它的危害)。
- 学习率太小:几乎不动。
5.3 亲眼看送进模型的数据
能在一小批数据上过拟合,不代表没有 bug。
动手:代码 02 演示 2 制造了一个常见的数据管线 bug:打乱了评论的顺序,却忘了同时打乱标签。
32 条上训练 100 轮后的损失 全部 2000 条训练后的训练损失 验证准确率 正确的数据 0.000 0.108 89.5% 标签和输入错位 0.000 0.625 40.8%
标签错位之后,模型照样能把 32 条数据背下来(随便什么标签都能背)。但在全部数据上,训练损失降不下去,验证准确率和瞎猜差不多——输入和标签之间已经没有关系了。
所以还要:把送进模型的张量解码回文字,和标签一起打印出来,亲眼看一看;检查训练损失能不能在完整数据上正常下降。
5.4 评估代码的 bug
动手:代码 02 演示 3。
(a) 带 dropout()的 GRU:正确评估(
model.eval())是 92.1%;忘了model.eval(),连续评估三次分别是 87.5%、88.7%、89.2%。(b) 词袋模型求平均时,分母里包含了填充位置:
评估时批大小 1 / 32 / 1000 的准确率 平均损失 “the music was clever .” 的 P(正面):单独 / 和最长的评论同一批 正确 89.5% / 89.5% / 89.5% 0.193 / 0.193 / 0.193 1.000 / 1.000 bug 89.9% / 89.9% / 89.9% 0.215 / 0.186 / 0.184 1.000 / 0.915
- 忘了
model.eval(),dropout 在评估时仍然在随机丢弃神经元:同一个模型、同一份数据,每次结果都不一样,而且偏低。 - 填充参与了平均:同一条评论,单独评估和跟一条长评论放在一起评估,得到的概率不一样。有意思的是准确率完全没变(向量整体缩小时,两个类别的打分谁大谁小基本不变)——只看准确率,这个 bug 根本发现不了。
评估结果应该是确定的、和批大小无关的。 用不同的批大小评估两次,是一个很便宜的检查。
5.5 读学习曲线
把每一轮的训练损失和验证损失画在一张图上,叫学习曲线。它是诊断问题最重要的工具。
动手:代码 02 演示 4 用字符画出了三种典型的学习曲线:
情形 最后一轮:训练损失 验证损失 验证准确率 验证损失最低的轮次 欠拟合:很小的词袋模型 0.242 0.253 87.7% 第 20 轮(最后一轮) 正常:GRU,2000 条 0.000 0.059 98.3% 第 8 轮 过拟合:大 GRU(256 维),只有 100 条 0.000 1.018 82.3% 第 6 轮
- 欠拟合:训练损失和验证损失都停在比较高的地方,而且两者很接近——模型的能力不够(这里是看不到词序)。办法:更强的模型、更好的特征,而不是更多的正则化。
- 正常:两条曲线一起下降,验证损失略高于训练损失。
- 过拟合:训练损失降到接近 0,验证损失降到某个点之后反而上升——模型在背训练数据。办法:更多数据、更强的正则化(dropout、权重衰减)、更小的模型,或者早停(early stopping):在验证损失最低的那一轮停下来,保存那时的模型。
注意过拟合那一行:验证损失从第 6 轮之后一路上升,验证准确率却几乎没变(82.1% → 82.3%)。模型对它判错的那些样本越来越”自信”,损失随之上升。损失比准确率更早、更敏感地反映过拟合。
5.6 监控梯度和其他量
动手:代码 02 演示 5。训练 GRU 5 轮,记录每一步的梯度范数:
设置 中位数 90% 分位数 最大值 验证准确率 学习率 0.404 0.764 1.63 96.4% 学习率 1.025 2.020 5.36 82.1% 学习率 + 梯度裁剪 1.0 0.954 2.176 4.16 82.2%
学习率太大时,梯度范数整体更大、波动更大,验证准确率明显更差。梯度裁剪在这里几乎没有帮助:问题不是偶尔出现的个别大梯度(那正是裁剪擅长处理的),而是学习率本身。
实际项目中,一般把训练损失、验证指标、梯度范数、学习率都实时画成曲线(TensorBoard、Weights & Biases 等工具),训练时随时看一眼。损失突然变成 NaN、梯度范数突然暴涨,都是要立刻停下来排查的信号。
5.7 一张排查清单
| 症状 | 可能的原因 |
|---|---|
| 一小批数据都过拟合不了 | 忘了 zero_grad;softmax / sigmoid 做了两次;损失函数用错(比如回归损失用在分类上);学习率太小;梯度没有传到某些参数(requires_grad、detach);输入全是填充 |
| 训练损失下降,验证很差,而且和瞎猜差不多 | 标签和输入错位;训练和验证的预处理不一致(不同的词表、分词方式);验证集的标签有问题 |
| 训练损失是 NaN 或突然暴涨 | 学习率太大;对 0 取 log、除以 0;混合精度溢出;没有梯度裁剪(RNN) |
| 评估结果每次不一样 | 忘了 model.eval();评估时数据被打乱且结果依赖顺序;填充没有正确处理 |
| 结果”好得不像真的” | 数据泄漏(重复样本、用测试集建词表、时间泄漏);标签信息混进了输入 |
| 训练损失和验证损失都很高、很接近 | 欠拟合:模型太小、特征不够、训练不够久、学习率不合适 |
| 训练损失很低,验证损失上升 | 过拟合:更多数据、正则化、早停、更小的模型 |
5.8 数据越多越好吗
动手:代码 02 演示 6。训练集大小和验证准确率(每种设置都取验证准确率最高的一轮):
训练条数 50 100 200 500 1000 2000 5000 词袋 64.9% 73.7% 78.9% 86.7% 87.7% 88.6% 89.2% GRU 82.1% 82.2% 82.1% 87.5% 95.9% 98.1% 98.8%
- 词袋模型的曲线很典型:每多一倍数据提高一点,越往后提高越少,最后停在 90% 以下——它看不到词序,再多的数据也学不会否定。
- GRU 在每个数据量上都更好,但它的曲线并不平滑:50~200 条时停在 82% 左右,500 条以后才快速提高。真实的学习曲线也常常这样,所以要多测几个点。
画出这样的曲线,可以帮你回答:再去标注一倍的数据值不值得?换一个模型值不值得?
6. 超参数搜索
6.1 哪些超参数最重要
学习率几乎总是最重要的超参数。其次是和”模型容量 / 正则化”有关的(模型大小、dropout、权重衰减)、批大小、训练步数和学习率调度。一个实用的顺序是:先固定其他超参数(用论文或常见的默认值),把学习率调好;再调正则化;最后再考虑其他的。
6.2 网格搜索 vs 随机搜索
网格搜索:每个超参数取几个值,试遍所有组合。随机搜索:在给定范围内随机抽取每个超参数。Bergstra 和 Bengio(2012)指出,同样的预算下,随机搜索通常更好。原因是:几个超参数里往往只有少数真正重要,而我们事先不知道是哪几个。
动手:代码
03_hyperparameter_search.py演示 1。人造的目标函数只有 重要(在 附近有一个窄峰,峰值 0.91), 几乎没有影响:
预算 网格:试过几个不同的 网格找到的最好值 随机搜索找到的最好值(1000 次的平均) 9 3 0.607 0.790 16 4 0.654 0.840 25 5 0.860 0.870
网格搜索 9 次只试了 3 个不同的 ,另外 6 次都”浪费”在了不重要的 上;随机搜索 9 次就试了 9 个不同的 。随机搜索还可以随时停下、随时加预算。
6.3 在对数尺度上搜索
学习率从 到 ,和从 0.1 到 1,是同样”大”的变化(都是 10 倍)。在 上均匀抽样,绝大多数样本都会大于 0.1。
动手:代码 03 演示 2。在 里抽 10 万个学习率,落在 里的比例:均匀抽样 10.1%,对数均匀抽样 40.0%;小于 的比例:均匀抽样只有 0.09%。
学习率、权重衰减这类影响”数量级”的超参数,应该先抽 ,再令 。dropout 概率、层数这类在普通尺度上抽就可以。
6.4 一次真实的搜索
动手:代码 03 演示 3。GRU 情感分类器,训练集 500 条,4 个超参数(学习率、隐藏层大小、dropout、权重衰减),网格搜索和随机搜索各 16 次:
试过的学习率个数 最好的验证准确率 中位数 最差 最好那组的测试准确率 网格搜索 2 88.7% 83.9% 80.5% 88.8% 随机搜索 16 90.3% 83.3% 68.8% 89.2% 把随机搜索的 16 次试验按学习率排序,验证准确率几乎随学习率单调上升( 时 68.8%, 时 90.3%)。验证准确率和 的相关系数是 0.83,和 dropout 的相关系数只有 0.18。
这再次说明学习率最重要:太小的学习率在 10 轮内根本学不好。这样的分析告诉你下一步该在哪个维度上细搜——先粗搜、看哪个重要,再在重要的维度上细搜(coarse-to-fine)。
预算更紧时,还有更聪明的方法:贝叶斯优化(根据已有的结果,预测哪里最可能更好),以及提前淘汰表现差的试验(Hyperband 等)。对大模型,常见的做法是在小模型上调好超参数,再按一定的规则推广到大模型(CS336 第 9、11 讲)。
6.5 早停与”赢家的诅咒”
从 16 次试验里挑验证准确率最高的那个,它之所以最高,一部分是因为超参数真的好,另一部分可能是它在这个特定的验证集上”运气好”。所以最好的验证分数通常偏乐观。
动手:代码 03 演示 4。网格搜索最好的验证准确率 88.7%,它的测试准确率 88.8%;随机搜索 90.3% → 89.2%。
在这里偏差很小:验证集有 1000 条,只比较了 16 组。验证集越小、比较的次数越多,偏差就越大——第 3.3 节的实验是一个极端的例子。早停的轮次也是在验证集上选的,同样会让验证分数偏高一点。这就是为什么必须有一个独立的测试集。
7. 随机种子与显著性检验
7.1 波动有多大
神经网络的训练有很多随机性:参数初始化、数据顺序、dropout。同样的代码换一个随机种子,结果就不一样。
动手:代码
04_seeds_and_significance.py演示 1。同一个 GRU(训练集 500 条),10 个随机种子在 2000 条测试集上的准确率:85.4%、87.0%、88.1%、86.6%、85.9%、86.6%、88.0%、82.6%、86.8%、87.4%
平均 86.4%,标准差 1.6%,最低 82.6%,最高 88.1%。
最好和最差差了 5.5 个百分点。作为对比,2000 条测试集本身的抽样误差,标准差只有 。这里训练的随机性比测试集的随机性还大。
所以报告里应该写”平均 ± 标准差( 个种子)“,而不是只报一次运行的结果,更不能只报最好的那次。10 个种子时,均值的 95% 置信区间约为平均 标准差 ,这里是 [85.3%, 87.6%](2.26 是自由度为 9 的 t 分布的 97.5% 分位数)。
7.2 比较两种设置:多个种子 + 置换检验
动手:代码 04 演示 2。比较 dropout 0(A)和 dropout 0.3(B),各跑 10 个种子:
种子 0 1 2 3 4 5 6 7 8 9 A:dropout 0 85.4 87.0 88.1 86.6 85.9 86.6 88.0 82.6 86.8 87.4 B:dropout 0.3 83.5 83.4 85.9 83.8 84.5 84.4 85.5 82.8 86.9 85.4 如果只用一个种子做实验,10 个种子里有 2 个会让你得出”B 更好”的结论。10 个种子的平均:A 86.4%,B 84.6%,差 −1.8%;置换检验 。
(在这里 dropout 反而有害,可能是因为只训练了 10 轮、数据又不多,dropout 拖慢了学习。训练更久时,结论可能不同——结论总是有条件的。)
置换检验(permutation test)的思路:假设两种设置其实没有区别(“零假设”),那么把 20 个结果混在一起、随机重新分成两组,得到的均值之差应该和真实的差”差不多大”。重复上万次,看有多大比例的随机分组,均值之差不小于真实的差——这个比例就是 p 值。p 值很小(常用 0.05 为界),说明”没有区别”很难解释我们看到的差距。
关于 p 值的几个常见误解:
- p 值不是”零假设为真的概率”;
- p 值大,只能说”没有足够的证据说明有区别”,不能说”两者一样好”;
- p 值小,不说明差距有多大、有没有实际意义(数据足够多时,0.1% 的差距也会”显著”);
- 多重比较:试了 20 种改进,只报告 的那一种,平均就会有一种是纯粹的运气。
7.3 比较两个训练好的模型:配对 bootstrap
另一个常见的问题是:“这两个已经训练好的模型,在这个测试集上,哪个更好?“两个模型在大部分样本上表现一样,差别只来自”一个对、一个错”的那些样本。配对 bootstrap(Koehn 2004;Berg-Kirkpatrick 等 2012)只关注这部分:每次从测试集里有放回地抽样,两个模型用同一组样本算准确率之差,重复很多次,看 B 不优于 A 的比例。
动手:代码 04 演示 3:
B − A 95% 置信区间 B 不优于 A 的比例 只有 A 对 / 只有 B 对 种子 0 的 A vs 种子 0 的 B −1.8% [−3.0%, −0.8%] 0.999 86 / 49 种子 7 的 A vs 种子 7 的 B +0.2% [−1.0%, +1.5%] 0.367 74 / 79 种子 1 的 A vs 种子 1 的 B −3.6% [−5.1%, −2.2%] 1.000 137 / 64
配对比较比”分别算两个置信区间、看是否重叠”灵敏得多。但它不考虑训练的随机性:同样是”设置 A vs 设置 B”,种子 1 上差距非常明显,种子 7 上几乎没有差别。所以两种检验回答的是不同的问题:
- “设置 B 是否比设置 A 好?”→ 跑多个种子,置换检验(或 t 检验);
- “模型 B 是否比模型 A 好(比如两个要部署的模型)?”→ 配对 bootstrap。
NLP 研究中,Dror 等(2018)的综述 The Hitchhiker’s Guide to Testing Statistical Significance in NLP 是一份很好的参考。
8. 可复现性与实验记录
动手:代码 04 演示 4。用同样的种子训练两次:参数完全相同,测试准确率都是 85.35%。初始化相同、只改变数据顺序:86.75%。
在 CPU 上固定所有随机种子(set_seed 同时固定 Python、numpy、PyTorch 的种子),同样的代码可以得到逐位相同的结果。只改变数据顺序,结果就变了——随机性的来源不止参数初始化。GPU 上有些运算本身是非确定性的(例如并行求和的顺序不固定),完全复现需要额外的设置。
一份好的实验记录应该包括:
- 代码版本(git commit)和未提交的改动;
- 所有超参数(最好用配置文件,每次运行自动保存一份);
- 数据版本和预处理方式;
- 随机种子、库的版本、硬件;
- 结果:不只是最终数字,还有学习曲线。
建议从项目第一天起就用一个表格或实验管理工具(Weights & Biases、MLflow,或者一个简单的 CSV 文件)记录每一次运行。几周之后写报告时,你会感谢自己。
9. 读论文与写报告
9.1 怎样读论文
一个常用的”三遍法”(Keshav,How to Read a Paper):
- 第一遍(5~10 分钟):读标题、摘要、引言、各节标题、结论,看图表。回答:这篇论文要解决什么问题?主要结论是什么?值不值得细读?
- 第二遍(1 小时):仔细读,但跳过证明和实现细节。重点看实验:和什么基线比?在什么数据上?提升有多大?有没有消融实验?有哪些地方让你怀疑?
- 第三遍(几个小时):想复现或在它的基础上做研究时,“在脑子里重新实现一遍”,搞清楚每一个细节和假设。
读的时候带着批判的眼光:基线是不是够强?提升是不是在随机波动的范围内?是不是只在一个数据集上有效?
9.2 报告的结构
| 部分 | 写什么 |
|---|---|
| 摘要 | 问题、方法、主要结果,一段话 |
| 引言 | 为什么这个问题重要;你做了什么;主要发现 |
| 相关工作 | 别人做过什么;你的工作和它们的关系 |
| 方法 | 足够让别人复现的细节 |
| 实验设置 | 数据(划分、规模)、评估指标、基线、超参数和如何选择的 |
| 结果 | 主要结果表(含基线和标准差);消融实验 |
| 分析 | 错误分析:模型在哪些样本上失败?为什么?定性的例子 |
| 结论与局限性 | 发现了什么;方法在什么情况下不适用;还有什么没做 |
消融实验(ablation study):每次去掉方法的一个组成部分,看效果下降多少,说明每个部分是否真的有用。本讲 01 号文件里”单个词 vs 单个词 + 相邻两词”就是一个最简单的消融:它说明了”相邻两词”这个特征的贡献。
错误分析往往是报告里最有价值的部分。把模型判错的样本拿出来分类(“否定""混合评价""罕见词”……),统计每类有多少,就知道下一步该往哪里努力。01 号文件把准确率拆成”含 not / 不含 not”两列,就是一个最简单的错误分析。
9.3 常见的问题
- 没有基线,或者基线太弱(没有调过参数的基线);
- 只报告一次运行的结果,提升小于随机波动;
- 用测试集选了超参数;
- 只有数字,没有分析,不知道方法为什么有效;
- 不承认局限性,结论推广得过远(在玩具数据上得到的结论,不能直接说”在真实语言上也成立”——本讲义的每个实验都会注明这一点)。
10. CS224N 的期末项目
10.1 默认项目
近几年的默认项目(以当年发布的版本为准)大致是:从零实现一个精简版的 GPT-2(注意力层、Transformer 块、整个模型,并加载公开的预训练权重),然后把它用于几个下游任务——例如情感分类、复述检测(判断两个问题是否同义)、诗歌生成——最后在这些任务上做改进(更好的微调方法、参数高效微调、数据增强等)并报告结果。
第 7 讲的 transformer.py 和 GPT-2 的结构完全相同(第 7 讲第 7.5 节验证了参数量);第 9 讲讲预训练和微调,第 11 讲讲参数高效微调,第 20 讲(拓展)会把这些串起来,完整地走一遍默认项目。
默认项目的好处:任务明确、有起始代码和基线、可以和同学比较;挑战在于做出有意义的改进和分析。
10.2 自选项目
自选项目的自由度更大,但要特别注意可行性:
- 数据能不能在一两周内拿到?
- 计算资源够不够?(训练一个小模型,还是只微调 / 调用现成的模型?)
- 有没有一个能在第一周就跑通的基线?
一个好的自选项目的范围通常比你想象的小:一个清楚的问题,一两个数据集,几个精心设计的实验,加上深入的分析。
10.3 时间线建议
- 项目提案:问题、相关工作、数据、基线、评估方法;
- 中期报告:基线已经跑通,有初步的结果和分析;
- 最终报告和海报。
最常见的失败模式是:前几周花在”想一个完美的方法”上,最后一周才开始跑实验,发现数据有问题、基线跑不通。尽早跑通端到端的基线,再一步步改进。
11. 本讲小结
- 神经网络会”悄无声息地失败”,需要一套系统的实验方法。
- 项目:分析型、复现型项目往往比”提出新方法”更容易做扎实;先看数据。
- 数据划分:训练集更新参数,验证集做选择,测试集只用一次。警惕数据泄漏(重复样本可能让死记硬背的模型看起来最好)、测试集复用(挑选越多越虚高)、分布偏移(测试集要像真实使用的数据)。数据很少时用交叉验证。
- 基线:一串由简到繁的基线,告诉你任务有多难、你的方法好了多少,也能帮你发现 bug。
- 指标:类别不平衡时看精确率、召回率、F1、宏平均;测试集越小,置信区间越宽()。
- 调试:先在一小批数据上过拟合;亲眼看送进模型的数据;评估结果应该和批大小无关;读学习曲线(欠拟合 / 过拟合);监控梯度范数。
- 超参数:学习率最重要;随机搜索优于网格搜索;学习率在对数尺度上搜索;先粗后细;最好的验证分数偏乐观。
- 随机种子:训练的随机性可能比测试集的随机性还大;报告多个种子的平均和标准差;比较设置用多种子 + 置换检验,比较两个固定模型用配对 bootstrap。
- 可复现:固定种子,记录代码、配置、数据和环境。
- 报告:基线、消融实验、错误分析、局限性。
12. 与作业的关系
这一讲没有对应的编程作业,它服务于期末项目:
- 项目提案要求写清楚数据、基线和评估方法(第 2–4 节);
- 中期和最终报告的评分标准通常包括:实验设计是否合理、是否有合适的基线、是否有消融实验和错误分析、结论是否有证据支持(第 7、9 节);
- 前面几次作业里遇到的训练问题(第 3 讲的初始化、第 6 讲的梯度爆炸、第 7 讲的学习率预热),都可以用本讲的工具排查。
课程的具体要求以当年官方发布的项目说明为准。
13. 练习
练习 1(数据划分)★:下面每种情形应该怎样划分训练集和测试集? (a) 预测一条推文是否会被转发超过 100 次,模型将用于预测明天发布的推文。 (b) 作者识别:判断一段文字是否出自某位作者,数据是 50 位作者的各 20 篇文章,模型要用于新的作者。 (c) 一个对话数据集,每段对话有 10 轮,要训练”给定前文预测下一句回复”的模型。
参考答案
(a) 按时间划分:用较早的推文训练,较晚的推文测试,否则模型可能利用”未来”的信息(比如某个话题后来爆火)。 (b) 按作者划分:测试集里的作者不能出现在训练集里,否则模型只是学会了认这 50 位作者。 (c) 按对话划分:同一段对话的不同轮次必须在同一边,否则测试时模型可能在训练集里”见过”同一段对话的上下文。
练习 2(指标)★:一个罕见疾病筛查模型,1000 个人里有 10 个患者。模型找出了 8 个患者,同时把 40 个健康人误判为患者。计算准确率、精确率、召回率和 F1。这个模型好不好?
参考答案
TP = 8,FN = 2,FP = 40,TN = 950。准确率 = 958/1000 = 95.8%(但”全判健康”也有 99%)。精确率 = 8/48 ≈ 16.7%,召回率 = 8/10 = 80%,F1 = 2 × 0.167 × 0.8 / 0.967 ≈ 27.6%。作为初筛,召回率 80% 可能是可以接受的(漏诊代价大,误报的人可以再做进一步检查);作为确诊,精确率 16.7% 太低了。好不好取决于用途。
练习 3(置信区间)★:一个模型在 400 条测试数据上的准确率是 80%。(a) 用 估计标准误差和 95% 置信区间(约 ±1.96 个标准误差)。(b) 要把置信区间的半宽缩小到 1%,大约需要多少条测试数据?
参考答案
(a) ,95% 置信区间约 ,即 [76.1%, 83.9%]。 (b) 需要 , 条。
练习 4(调试)★:你的训练损失从 0.69 降到 0.35 之后就再也不动了,在 32 条数据上也一样。最可能是什么问题?怎样验证?
参考答案
二分类时,损失卡在 0.31~0.35 附近、一小批数据都降不下去,非常像”softmax 做了两次”(下限 0.313)。检查模型的最后一层是否已经有 softmax(或者 nn.Softmax),而损失函数又是 F.cross_entropy / nn.CrossEntropyLoss(它们期望的是未归一化的 logits)。验证方法:去掉模型里的 softmax,看能否在 32 条数据上把损失降到接近 0。
练习 5(学习曲线)★:描述下面三种学习曲线分别说明什么,以及你下一步会做什么:(a) 训练损失 0.05,验证损失 0.9,且验证损失在第 3 轮后持续上升;(b) 训练损失 0.6,验证损失 0.62,都几乎不再下降;(c) 训练损失和验证损失都还在稳定下降。
参考答案
(a) 过拟合:用早停(取第 3 轮的模型)、加 dropout / 权重衰减、减小模型、增加数据。 (b) 欠拟合:模型能力不够或训练有问题。先确认能在一小批数据上过拟合;然后换更大的模型、更好的特征,或者调学习率。不要加正则化。 (c) 还没训练完:继续训练(或者增大学习率以加快收敛)。
练习 6(超参数):你有 20 次训练的预算,要调学习率( 到 )、dropout(0 到 0.5)、批大小(16、32、64)。设计一个搜索方案。
参考答案
一种合理的方案:第一轮 12 次随机搜索,学习率在对数尺度上抽样(,),dropout 在 [0, 0.5] 上均匀抽样,批大小随机选一个。看结果,找出学习率的好区间(通常它最重要)。第二轮 8 次,在好的学习率区间(比如缩小到一个数量级以内)和表现好的 dropout 附近再随机搜索。最后选验证集上最好的,用测试集评估一次;如果时间允许,用最好的配置多跑几个种子报告均值和标准差。
练习 7(显著性)★★:你的新方法在 5 个种子上的准确率是 85.2、86.1、84.9、85.7、86.0,基线是 84.8、85.9、85.0、84.6、85.3。(a) 两者的平均和差是多少?(b) 只看这些数字,你会怎样描述结果?(c) 如果再多试了 9 种别的改进都没有效果,这个”有效”的改进需要怎样更谨慎地对待?
参考答案
(a) 新方法平均 85.58,基线平均 85.12,差 0.46 个百分点。 (b) 差距和各自的波动(标准差约 0.5)差不多大,5 个种子中有 4 个新方法更高(但种子之间并不是配对的)。可以说”有小幅提升的迹象,但证据有限”,应该做置换检验或 t 检验给出 p 值,或者增加种子数。 (c) 多重比较:试了 10 种改进,即使都没用,也很可能有一种碰巧看起来有效。应该在新的种子(甚至新的数据集)上重新验证这一种改进,报告时也要说明一共试了多少种。
练习 8(泄漏):你用整个数据集统计了词频,去掉了出现少于 5 次的词,然后再划分训练集和测试集。这有什么问题?
参考答案
词表的构建用到了测试集的信息:一个只在测试集里出现过几次的词,可能因为测试集的计数而被保留下来。影响通常不大,但原则上是一种泄漏,在数据很小时可能显著影响结果。正确做法是先划分,只用训练集建立词表(01 号文件的 build_index 就是这样做的)。
练习 9(动手):
(a) 在代码 01 演示 2 中加入”单个词 + 相邻两词 + 相邻三词”(n_max=3),准确率还会提高吗?对含 not 的评论呢?
(b) 在代码 02 演示 1 中再制造一个 bug:计算损失时把标签整体错开一位(y.roll(1)),过拟合测试能发现它吗?
(c) 在代码 03 演示 3 中,把训练轮数从 10 改成 30,学习率还那么重要吗?
(d) 在代码 04 中把训练轮数改成 30,dropout 0.3 还比 dropout 0 差吗?
(e) 在代码 05 演示 1 中把标签噪声改成 0,1-近邻在随机划分和分组划分上的差距会怎样变化?
练习 10(思考):本讲的数据集是用规则生成的,标签完全由 sentiment_score 决定。和真实的情感分类数据相比,它少了哪些难点?这对本讲实验的结论有什么影响?
参考答案
真实数据还有:标注者之间的分歧和真正的标注错误(标签本身是主观的)、反讽和隐含的情感、长距离的转折(“开头很无聊,但结局让一切都值了”)、拼写错误和网络用语、远多于几十个的情感词、话题和情感的纠缠等。所以本讲的具体数字(比如”相邻两词把准确率提高到 91%“)不能推广到真实任务;但本讲演示的方法和现象——泄漏如何让分数虚高、随机种子的波动、学习率最重要、准确率在类别不平衡时会骗人——在真实任务上同样存在,往往还更严重。
14. 延伸阅读
- Andrej Karpathy,A Recipe for Training Neural Networks(博客,2019):调试神经网络的经典清单。
- Google Research,Deep Learning Tuning Playbook(2023,GitHub 上公开):超参数调整的系统方法。
- Bergstra & Bengio,Random Search for Hyper-Parameter Optimization(2012)。
- Dror, Baumer, Shlomov & Reichart,The Hitchhiker’s Guide to Testing Statistical Significance in Natural Language Processing(2018)。
- Berg-Kirkpatrick, Burkett & Klein,An Empirical Investigation of Statistical Significance in NLP(2012):配对 bootstrap。
- Dodge et al.,Show Your Work: Improved Reporting of Experimental Results(2019):报告超参数搜索的预算和结果分布。
- Gorman & Bedrick,We Need to Talk about Standard Splits(2019):只用一个标准划分可能得出错误的结论。
- Kapoor & Narayanan,Leakage and the Reproducibility Crisis in Machine-Learning-Based Science(2023):数据泄漏的分类和大量真实案例。
- Lipton & Steinhardt,Troubling Trends in Machine Learning Scholarship(2018):写论文时要避免的问题。
- S. Keshav,How to Read a Paper(2007):三遍读论文法。
- CS224N 官方的项目说明和往届优秀项目报告(课程主页上有链接)。
15. 下一讲预告
本讲 02 号文件演示 6 看到:标注数据少的时候,模型的表现很差;05 号文件演示 3 看到:换一个领域,模型就遇到很多没见过的词。标注数据又贵又少,没有标签的文本却几乎取之不尽。下一讲(预训练)回答:怎样利用海量的无标签文本?
- 从静态词向量到上下文相关的表示(ELMo);
- 三种预训练架构:编码器(BERT,掩码语言模型)、编码器—解码器(T5,span corruption)、解码器(GPT,因果语言模型);
- “预训练 + 微调”范式,以及上下文学习;
- 规模定律、训练成本和预训练数据的要点。
我们会在本讲的影评数据上做一个完整的实验:先在大量无标签影评上预训练一个迷你 Transformer,再用少量标注数据微调,看预训练到底带来多少收益。