对应 Maps to:CMU 17-630 Prompt Engineering(Prof. Travis Breaux),第 2 周的第一个主题 · In-Context Learning。原课 Schedule 对这一讲的说明(意译):模型怎样在推理时从类比和示例中学会想要的任务;提示模板;模型对提示、示例顺序和示例选择的敏感性;以及”非对称学习”(asymmetric learning)。 依据说明:原课的 slides 和阅读清单不公开。Schedule 点名的四个概念——推理时从示例中学习、提示模板、对顺序与选择的敏感性、非对称学习——在本讲里分别对应 §1–§3、§4、§7 和 §6。其中”非对称学习”原课没有进一步解释,讲义把它理解为”示例里的不同信息被模型不对称地使用”:格式和标签空间被大量使用,输入到标签的映射却常常被忽略;预训练形成的先验和示例给出的映射之间,谁压倒谁取决于模型(Min et al. 2022;Wei et al. 2023;Kossen et al. 2024)。这是讲义的解读,不代表课堂上的讲法。具体材料来自 Brown et al.(2020)、Zhao et al.(2021)、Lu et al.(2022)、Min et al.(2022)、Liu et al.(2022)、Wei et al.(2023)、Olsson et al.(2022)、Xie et al.(2022)、Chan et al.(2022)等论文;引用时按原文的说法转述结论,具体数字以原文为准。全部实验是本讲义自己设计的。 配套代码 Code:
code/lecture02/(PyTorch CPU;1 个模块 + 7 个脚本;不需要 API key;第一次运行会训练一个对照用的迷你 GPT,约 50 秒,之后读缓存;每个脚本都在 1 分钟以内) 预计阅读时间:4–5 小时(含运行代码)
0. 本讲导航 · How to read this lecture
0.1 学习目标 Learning goals
学完这一讲,你应该能够:
- 说清楚上下文学习(in-context learning,ICL)是什么、“学习”发生在哪里(不更新参数),以及零样本 / 单样本 / 少样本三种提示方式的区别。
- 把一个分类提示拆成模板(输入格式、标签字段)和标签词(verbalizer),并解释为什么换一个”意思相同”的词,准确率就可能大起大落。
- 用方差分解、按因素分组的方法,量化一个提示对模板、示例选择、示例顺序的敏感性;知道为什么”挑开发集第一名”需要留出集来验证。
- 解释多数标签偏差、近因偏差、常见词偏差从哪里来,会用上下文校准和批量校准修正它们,也知道它们什么时候会失效。
- 讲出”示例到底教了什么”的两个经典发现——随机标签影响不大(Min et al. 2022)、大模型会被翻转的标签带走(Wei et al. 2023)——以及两者为什么不矛盾。
- 了解挑示例(相似度检索)和排顺序(熵准则)的方法,并知道”一个方法有没有用,取决于模型怎样使用示例”。
- 用三种视角解释上下文学习的来源:归纳头、隐式贝叶斯推断、预训练数据的分布特性;并在一个玩具任务上亲眼看到归纳头的形成。
- 设计一个合格的提示对照实验(原课作业 1:文本分类上的指令、模板与示例)。
0.2 先修与本讲范围 Prerequisites & scope
| 默认你已经会 Assumed | 本讲会用到、但只给直觉 Previewed |
|---|---|
| 第 1 讲:base 模型在续写文档;迷你 GPT 和它的虚构世界;归纳头的直觉(§6.6) | 指令微调后的模型为什么零样本就很强(第 3 讲) |
| 前置讲 P1:token 与上下文窗口 | 思维链示例(第 4 讲)、检索示例的工程细节(第 7 讲) |
| 前置讲 P3:Wilson 区间、McNemar 配对检验、赢家诅咒、“把示例当作随机因素” | 自动搜索提示(第 10 讲) |
| 条件概率、对数、熵的定义 | 注意力的数学(第 1 讲 §6 已讲) |
0.3 本讲地图 Map
§1 什么是上下文学习:GPT-3 的三种提示方式;"学习"发生在哪里;本讲的三个问题
§2 零样本与少样本:示例首先教的是格式 ← 代码 01(演示 1)
§3 提示模板与标签词:表面形式、概率质量、示例的成本 ← 代码 01(演示 2–3)
§4 敏感性:模板、示例、顺序各占多少;顺序效应从哪里来;挑选与赢家诅咒 ← 代码 02
§5 偏差与校准:多数、近因、常见词;上下文校准与批量校准 ← 代码 03
§6 示例到底教了什么:随机标签、翻转标签、语义无关标签;"非对称学习" ← 代码 04
§7 挑示例与排顺序:相似度检索(KATE)与熵准则(Lu et al.) ← 代码 05
§8 上下文学习从哪里来:归纳头、隐式贝叶斯推断、数据的分布 ← 代码 06
§9 在真实的大模型上 ← 代码 07(可选)
§10 原课作业 1 对照:怎样做一个文本分类的提示实验
§11 小结 §12 常见误区 §13 练习 §14 延伸阅读 §15 下一讲预告
0.4 记号与术语 Notation & terms
| 术语 | 本讲义里的意思 |
|---|---|
| 示例(demonstration / in-context example / shot) | 放在提示里的”输入 + 标签”对。 个示例的提示叫 -shot |
| 模板(template / pattern) | 把一个输入写进提示的格式,例如 review : {x} . sentiment : {y} . |
| 标签词(verbalizer) | 每个类别用哪个词”说出来”,例如好评 → positive。这个术语来自 Schick & Schütze(2021)的 PET |
| 标签空间(label space) | 所有可能的标签词的集合 |
| 无内容输入(content-free input) | 不带任何任务信息的输入,例如 N/A,用来测量模型”不看输入时”的偏向 |
| 校准(calibration) | 本讲专指 Zhao et al.(2021)意义上的”修正标签偏向”。第 5 讲的”校准”是另一个意思:置信度和正确率是否一致 |
| 模型在提示后面写出标签词 的概率;本讲的分类都是”比较两个标签词的概率” |
0.5 本讲的实验装置 · The setup
本讲的任务是第 1 讲虚构世界里的评论情感二分类:一条评论(如 the soup was not cold)是好评还是差评。评论有三种难度:simple(同极性的一两个分句,看形容词就够)、but(“A but B”,以 B 为准)、not(带否定)。测试集是第 1 讲 §8 用过的同一批 300 条(138 条好评);示例从另外 400 条里抽,为了塞进 64 个 token 的上下文窗口,一般只用一个分句的短评论(§3.3)。
我们有三个”模型”:
- base:第 1 讲训练的迷你 GPT。它的预训练语料里,评论页的格式是
review : … . rating : positive .,同一页上的几条评论互相独立。 - bursty:本讲新训练的对照模型。语料、结构、超参数、训练步数都和 base 一样,只改了一处:每个评论页属于一家”好店”或”差店”,好店的评论 85% 是好评,差店 85% 是差评。于是在这份语料里,前面几条评论的评分是猜下一条评分的有用线索。(“bursty”——同类的东西成簇出现——这个词借自 Chan et al. 2022。)两个模型的对比回答一个问题:模型怎样使用示例,是不是由预训练数据决定的?
- SimICL:一个用公式代替神经网络的”大模型”玩具模型(§5.5、§6.3)。迷你 GPT 只有两层,有些只在大模型上出现的现象它表现不出来;SimICL 把这些现象的一种可能机制写成旋钮。它能把论证变具体,但不能证明任何关于真实模型的事。
分类的做法和第 1 讲 §8.1 一样:不让模型自由生成,而是比较两个标签词作为”下一个词”的概率(icl_lab.label_probs)。这是 Zhao et al.、Min et al. 等论文的标准做法;真实的 API 大多不返回概率,07 号脚本改为看模型写了哪个词。
1. 什么是上下文学习 · What is in-context learning
1.1 一个定义
GPT-3 论文(Brown et al. 2020)把”不更新任何参数、只靠提示里的文字让模型完成任务”分成三种:
- 零样本(zero-shot):只有任务描述和输入;
- 单样本(one-shot):再加一个示例;
- 少样本(few-shot):加若干个示例,论文里通常是 10 到 100 个,以塞满 2048 个 token 的窗口为限。
写成公式,一个 -shot 的分类提示是
其中 是冻结的模型参数, 是标签词, 是类别集合。和第 1 讲 §1.1 的微调对比:微调用 去改 ;上下文学习把同样的数据写进条件里, 一点不动。
GPT-3 论文把这种能力叫作上下文学习,核心发现是:模型越大,少样本相对零样本的提升越大。可它没有回答一个更基本的问题——参数没有变,“学习”到底发生在哪里?
1.2 “学习”发生在哪里
直觉上可以这样想。第 1 讲说过,base 模型在续写文档:它读提示时,在隐式地猜”我在写的是哪一种文档”,然后按那种文档的规律写下去。几个示例让这个猜测更准:
- 它们告诉模型这是什么格式的文档(一个评论页?一个问答页?);
- 它们告诉模型答案写在哪里、可以写哪些词;
- 在能力足够强的模型里,它们还告诉模型输入和答案之间的对应关系。
所以”学习”发生在前向计算里:模型在读示例时,把”这份文档的规律”表示在了内部的激活中,再用它来预测最后那个标签。这一讲的大部分篇幅都在问:上面三层信息,模型究竟用了哪几层?
1.3 本讲的三个问题
- 示例在做什么?(§2、§3、§6)格式?标签空间?映射?
- 为什么这么不稳定?(§4、§5、§7)换示例、换顺序、换个词,准确率就变;能修吗?
- 这种能力从哪里来?(§8)为什么有的模型会、有的不会?
每个问题都会先在我们自己训练的迷你模型上做实验,再对照论文里真实模型的发现。迷你模型和 GPT-3 差了六个数量级,它们的行为不能直接外推;但它们的好处是:我们知道它们的全部训练数据,于是可以问”为什么”。
2. 零样本与少样本:示例首先教的是格式 · Zero-shot vs few-shot
配套代码:
01_templates_shots.py演示 1
2.1 实验
同一个情感分类任务,用五种模板去问 base 模型,给 0 / 1 / 2 / 4 个示例(两类各半、顺序随机;有示例时换 10 组示例,报平均 [最低, 最高];标签词都是 positive / negative):
| 模板 | 词表外的词 | 0 个示例 | 1 个 | 2 个 | 4 个 |
|---|---|---|---|---|---|
review : {x} . rating : {y} .(和训练语料一样) | – | 100.0% | 100.0% | 100.0% | 100.0% |
review : {x} . sentiment : {y} . | sentiment | 55.3% | 58.3% | 85.5% [82.7, 86.3] | 89.7% [89.3, 90.0] |
q : {x} ? a : {y} .(借问答页的格式) | – | 92.3% | 90.6% | 87.6% | 91.5% |
{x} => {y} . | => | 54.0% | 54.0% | 54.0% | 54.0% |
{x} . {y} .(没有任何标记) | – | 46.0% | 46.0% | 46.0% | 44.7% |
(测试集 300 条,好评占 46%:全猜差评得 54%,全猜好评得 46%。)
五行讲了五件事:
- 熟悉的格式零样本就会。rating 模板就是训练语料里评论页的样子,模型不需要任何示例。
- 示例能把一个陌生的格式”教”会。sentiment 模板只把
rating换成了一个词表外的词(进模型就是<unk>),零样本跌到 55.3%——模型给 positive 的平均概率只有 0.04,几乎全猜差评。2 个示例 85.5%,4 个 89.7%。示例告诉了模型:<unk> :后面写的是 positive / negative,和rating :一样。 - 示例不总是帮忙。qa 模板零样本 92.3%,加示例后在 87.6%–91.5% 之间,没有一次比零样本好。
- 有些格式怎么教也教不会。在训练语料里,评论后面从来不直接跟
=>或标签,加 4 个示例也是”全猜一类”。这和第 1 讲 §8.2 的发现一样:预训练形成的习惯,几个示例扳不过来。 - 同一个模板里,换哪几个示例几乎无所谓。10 组示例之间最大的差别是 bare 模板 4 个示例时的 6.3 个百分点,其次是 sentiment 模板 2 个示例时的 3.7,其余都不超过 1 个百分点。记住这一点——GPT-3 不是这样的(§4)。
2.2 示例教会了什么,没教会什么
把 sentiment 模板按难度拆开:
| 简单句(180 条) | but 句(57 条) | not 句(63 条) | |
|---|---|---|---|
| 0 个示例 | 52.4% | 59.6% | 58.9% |
| 1 个 | 52.4% | 59.6% | 71.2% |
| 2 个 | 98.1% | 59.6% | 76.3% |
| 4 个 | 100.0% | 60.0% | 88.9% |
示例最先救回的是简单句:一旦模型知道”这里要写一个评分”,看形容词就能判对。but 句却始终停在 60% 左右——同一个模型在熟悉的 rating 模板下 but 句是 100%(第 1 讲 §8.1),可见它会处理 but;只是在陌生的模板下,它没能把这种能力调出来。
这给”少样本”一个更准确的描述:示例主要在帮模型认出任务和格式(Pan et al. 2023 把这叫作任务识别,task recognition),而不是在教模型一项新技能(任务学习,task learning)。Pan et al. 发现,任务识别在小模型上就有,任务学习要到很大的模型才明显出现。Reynolds & McDonell(2021)更早就提出过类似的看法:少样本示例的主要作用是”定位”预训练里已经学会的任务;在他们的实验里,写得好的零样本提示可以追平甚至超过少样本提示。
2.3 这对提示工程意味着什么
- 先找模型熟悉的格式。能用零样本解决的,不必加示例(加了还占窗口、花钱,§3.3)。
- 示例的第一价值是规定格式:答案写在哪里、可选的词有哪些、长度多长。今天的 chat 模型经过指令微调(第 3 讲),零样本已经很强,但”给一两个示例来规定输出格式”仍然是最常用的技巧之一。
- 示例不保证有用(qa 模板),要测。
3. 提示模板与标签词 · Templates and verbalizers
配套代码:
01_templates_shots.py演示 2–3
3.1 一个分类提示的三个零件
一个分类提示可以拆成三部分:
- 输入格式:输入怎么写(前面加不加
review :、结尾加不加句号); - 标签字段:答案前面的那个”引导”(
rating :、sentiment :、a :、Answer:); - 标签词:每个类别用哪个词说出来。
有了指令微调的 chat 模型之后,还有第四部分——指令(“Classify the sentiment as positive or negative.”)。第 3 讲专门讲它。这一讲的迷你模型没见过指令,所以只看前三部分。
3.2 标签词:意思一样,效果可以完全不同
保持模板不变,只换标签词(base 模型;4 个示例时是 10 组的平均 [最低, 最高]):
| 模板 | 标签词(好评 / 差评) | 0 个示例 | 4 个示例 |
|---|---|---|---|
| rating | positive / negative | 100.0% | 100.0% |
| rating | great / awful | 70.0% | 70.9% [70.0, 72.0] |
| rating | awful / great(反着用) | 30.0% | 27.2% [25.3, 29.7] |
| rating | copper / wheat(和情感无关) | 61.0% | 58.3% [56.0, 60.0] |
| sentiment | positive / negative | 55.3% | 89.7% [89.3, 90.0] |
| sentiment | great / awful | 54.3% | 71.8% [66.7, 79.0] |
| sentiment | awful / great | 45.7% | 24.1% [19.0, 30.7] |
几个要点:
- great / awful 和 positive / negative 意思一样,rating 模板下却从 100% 掉到 70%。训练语料里
rating :后面只出现过 positive 和 negative;great 和 awful 在这个位置上的概率都只有百万分之一左右(04 号脚本演示 2 打印了它们的概率之和)。比较两个极小的数,结果很不稳定。 - 标签词反着用(好评写 awful),示例也救不回来:4 个示例明明反复演示”好评 → awful”,准确率反而从 30.0% 降到 27.2%。模型在用标签词本来的意思回答,而不是示例给的映射(§6 详谈)。
- 示例的选择在”模型没把握”时最要紧:sentiment · great/awful 的 10 组示例之间差了 12.3 个百分点(66.7%–79.0%),而 positive/negative 只差 0.7。
这些现象在真实模型上都有对应。Zhao et al.(2021)把”偏向在预训练里常见的标签词”叫作常见词偏差(common token bias)。Holtzman et al.(2021)指出了一个更一般的问题——表面形式竞争(surface form competition):同一个意思有很多种说法(“computer”、“PC”、“laptop”),它们分摊了概率;一个标签词的概率低,可能只是因为它”不常被这样说”,不是因为模型认为它错。他们提出用”这个词在这里本来有多常见”去归一化,思路和 §5 的校准一样。
实践建议:标签词要选模型在这个位置上本来就会说的词。对 chat 模型,最稳的做法是在指令里明确列出可选的词,并检查输出里”不属于任何一个标签”的比例(07 号脚本的”答了别的词”一列)。
3.3 示例的成本:上下文窗口
示例占地方。sentiment 模板下(base 模型):
| 示例数 | 示例来源 | 平均 token 数 | 超出 64 个 token 的比例 | 平均准确率 |
|---|---|---|---|---|
| 0 | – | 15.2 | 0% | 55.3% |
| 2 | 短示例 | 37.2 | 0% | 85.5% |
| 4 | 短示例 | 59.2 | 0% | 89.7% |
| 4 | 任意长度 | 70.2 | 81.9% | 87.9% |
| 6 | 短示例 | 81.2 | 100% | 88.3% |
| 8 | 短示例 | 103.2 | 100% | 88.3% |
迷你 GPT 的窗口只有 64 个 token。超出时,tiny_gpt 只保留最后 64 个,最前面的页眉和示例被截掉,准确率不再上升。这就是为什么本讲的实验用短示例、最多 4 个。
真实模型的窗口有几十万个 token,“塞不下”很少见了,但成本还在:每个示例都按输入 token 收费、都增加延迟(P2 §6)。GPT-3 时代的论文受 2048 个 token 的限制,示例通常只有几个到十几个(Lu et al. 2022 主要用 4 个)。窗口变长之后,Agarwal et al.(2024)在 Gemini 1.5 Pro 上把示例加到几百、几千个(many-shot ICL),发现很多任务还在变好,甚至能部分推翻预训练形成的偏向。所以”放几个示例”不只是窗口问题,也是一个收益与成本的权衡,要和”写一个更好的零样本指令""微调”一起比较。
4. 敏感性:模板、示例、顺序各占多少 · Sensitivity
配套代码:
02_sensitivity.py
4.1 背景:GPT-3 上的观察
Zhao et al.(2021)系统地记录了 GPT-3 少样本提示的不稳定:同一个任务,换一组训练示例、换示例的顺序、换提示格式,准确率都可以从接近随机变到接近最好。Lu et al.(2022)专门研究了顺序:同样 4 个示例的 24 种排列,有的接近最好、有的接近随机;这个现象在不同规模的模型上都存在,而且一个模型上的”好顺序”换到另一个模型上未必还好。Sclar et al.(2024)只改分隔符、大小写、空格这类”无关紧要”的格式,LLaMA-2-13B 在某些任务上的准确率最多差了 76 个百分点(第 1 讲 §8.4)。
这些发现意味着:**“提示 A 比提示 B 好”这个结论,可能只是因为 A 碰巧用了一组好示例或一个好顺序。**我们来看在迷你模型上,这几种因素各占多少。
4.2 方差分解
4 种设计(模板 · 标签词)× 5 组示例(每组 2 条好评 + 2 条差评)× 每组 24 种顺序 = 480 个提示,每个提示在 300 条评论上测准确率。把 480 个准确率的总方差按全方差公式拆开:
(每一项都用”除以 “的总体方差,三项才严格加起来等于总方差。)
| base 模型 | bursty 模型 | |
|---|---|---|
| 换模板 / 标签词 | 90.4% | 89.9% |
| 同一模板内换示例 | 0.1% | 0.2% |
| 同一组示例换顺序 | 9.5% | 9.9% |
| 总方差(百分点²) | 95.2 | 164.9 |
再看每种设计内部 120 个提示的波动:
| 设计 | base:平均(最低–最高),标准差 | bursty:平均(最低–最高),标准差 |
|---|---|---|
| sentiment · positive/negative | 89.8%(89.3–90.0),0.18 | 94.1%(89.0–99.0),4.41 |
| sentiment · great/awful | 73.2%(66.0–80.3),5.92 | 81.6%(72.3–90.3),6.07 |
| rating · great/awful | 71.4%(69.3–74.3),1.14 | 66.3%(65.3–70.3),0.87 |
| qa · positive/negative | 91.7%(91.0–92.7),0.43 | 97.3%(92.0–100.0),3.06 |
三个结论:
- 对这两个迷你模型,模板和标签词是最大的因素(约 90% 的方差);换哪组示例几乎无所谓(0.1%–0.2%)。
- “平均来说不敏感”不等于”这个提示不敏感”。base 模型在 sentiment · great/awful 上,同样 4 条示例只换顺序,准确率就在 66.0%–80.3% 之间——14.3 个百分点。敏感性是提示设计的属性,不只是模型的属性。
- 越会读上下文的模型,对顺序越敏感。bursty 模型(§0.5)在四种设计里的三种上波动比 base 大。§5、§6 会看到,它比 base 更多地使用示例里的标签——上下文学习能力和对示例的敏感性,是同一枚硬币的两面。这也解释了为什么 GPT-3 这种强的上下文学习者比我们的迷你模型更”敏感”。
4.3 顺序效应从哪里来
把 120 个提示按”最后一个示例是好评还是差评”分成两组:
| 模型 · 设计 | 最后是好评 | 最后是差评 | 120 个的极差 | 分组后的组内极差 |
|---|---|---|---|---|
| base · sentiment · great/awful | 67.3% | 79.1% | 14.3 | 2.3 |
| bursty · sentiment · positive/negative | 98.3% | 89.8% | 10.0 | 3.8 |
| bursty · sentiment · great/awful | 87.4% | 75.8% | 18.0 | 7.7 |
| bursty · qa · positive/negative | 99.8% | 94.8% | 8.0 | 5.2 |
base 模型那一行最干净:分组之后,组内只剩 2.3 个百分点的差别——这个设计的顺序效应几乎全部来自”最后一个示例写的是哪个标签词”。有趣的是方向:最后一个示例写了 great,base 模型给 great 的平均概率反而更低(0.54 vs 0.58)。它的训练语料里同一页的评分互相独立,它没有学会”照抄上一个标签”。
bursty 模型正好反过来:最后一个示例是好评,它就更倾向好评。它的语料里同一页的评分相关,它学会了”下一个评分像上一个”——这就是近因偏差(§5)。同样大小的偏差,往两个方向推,对准确率的影响也不对称:bursty 对差评本来很有把握,往好评那边推不动;往差评那边推,一部分把握不大的好评就被推错了。
带走的经验:顺序效应不是神秘的噪声。先按”最后一个示例的标签”之类的简单因素分组看看,常常能解释大部分波动。
4.4 挑开发集上最好的那个,它在新题上还那么好吗?
面对这么多候选,一个自然的做法是”在开发集上全部试一遍,挑最好的”。把 300 道题随机分成开发集和留出集各 150 道(base 模型):
| 在哪里挑 | 第一名 | 开发集 | 留出集 [95% CI] | 全体平均:开发 / 留出 |
|---|---|---|---|---|
| 全部 480 个 | qa · positive/negative | 92.7% | 92.7% [87.3, 95.9] | 82.6% / 80.4% |
| sentiment · great/awful 的 120 个 | 第 4 组 · 顺序 PNPN | 80.7% | 78.0% [70.7, 83.9] | 75.0% / 71.3% |
| sentiment · positive/negative 的 120 个 | 第 4 组 · 顺序 NPPN | 90.0% | 90.0% [84.2, 93.8] | 89.5% / 90.0% |
- 在全部 480 个里挑,第一名在留出集上没有回落:设计之间的差别(约 20 个百分点)是真的,远大于 150 道题的抽样误差。开发集第一名和最后一名在留出集上的配对检验 p ≈ 5×10⁻⁹。
- 在 great/awful 里挑,第一名回落了 2.7 个百分点,但仍比平均好——它挑中的是”最后一个示例是差评”那一类(PNPN),这个效应是真的。
- 在 positive/negative 里挑,120 个提示的预测几乎一模一样,没有东西可挑,也就没有”诅咒”。
前置讲 P3 §5 的赢家诅咒在这里只露出了一点点,因为迷你模型的候选要么差别很大、要么几乎相同。真实的提示工程常常处在最危险的中间地带:很多个候选、真实水平差不多、各自错在不同的题上(P3 的模拟里,20 个一样好的版本、50 道开发题时,第一名平均虚高 7.8 个百分点)。规矩不变:
- 在开发集上挑,在没用来挑选的留出集上报告;
- 比较两个提示用同一组题做配对检验(McNemar);
- 把示例的选择和顺序当作随机因素:换几组、换几种顺序,报告平均和波动(P3 §6.3),而不是只报最好的那一个。
5. 偏差与校准 · Label biases and calibration
5.1 Zhao et al. 的三种偏差
Zhao et al.(2021)的论文标题就是建议:《Calibrate Before Use》(先校准,再使用)。他们把 GPT-3 少样本提示的不稳定归结为模型对某些标签的系统性偏向:
- 多数标签偏差(majority label bias):示例里哪个标签多,就偏向哪个;
- 近因偏差(recency bias):偏向最后几个示例的标签;
- 常见词偏差(common token bias):偏向在预训练里常见的标签词。
这三种偏差有一个共同点:它们是整体的——不管输入是什么,都往同一个方向推。这正是可以修正的那种偏差。
5.2 偏差从哪里来:一个”合理推断”的视角
为什么模型会有多数和近因偏差?一个直觉的解释来自预训练数据。真实网页里,同一页上的东西是相关的:同一家店的评论多半一样好或一样差,同一份试卷的答案分布不均匀,最近的几条最能代表当前的话题。一个把”下一个词”预测得很好的模型,应该利用这种相关性:前面好评多,下一条更可能是好评;刚出现的那个标签,下一个更可能还是它。
Xie et al.(2022)把这个想法形式化成隐式贝叶斯推断:预训练文档由某个隐含的”概念”生成,模型在读提示时隐式地推断这个概念,再按它预测下一个词:
少样本提示里的示例是推断”概念”的证据——包括”这个页面上的评分偏向哪边”。在我们的 bursty 语料里,“概念”就是”这是好店还是差店”。
所以多数和近因偏差不是 Transformer 天生的毛病,而是模型从数据里学到的合理推断,只是被用在了一个它不再合理的场合:少样本提示里,示例的标签分布是我们随手定的,和测试输入毫无关系。
5.3 直接测量偏差:无内容输入
怎样看到一个模型的偏差?Zhao et al. 的办法是:把测试输入换成一个无内容的输入(N/A),放进同一个提示,看模型给每个标签的概率。理想情况下应该是 50:50;偏离多少,就是偏差有多大。
迷你 GPT 的词表里没有 N/A,它进来就是 <unk>,我们直接用 <unk>。sentiment · positive/negative 模板下,P(positive | 无内容输入) 随示例标签的变化(10 组示例的平均):
| 示例的标签顺序 | 好 : 差 | base | bursty |
|---|---|---|---|
| (无示例) | 0 : 0 | 0.08 | 0.51 |
| PP | 2 : 0 | 0.60 | 0.53 |
| NN | 0 : 2 | 0.67 | 0.31 |
| PPPP | 4 : 0 | 0.73 | 0.77 |
| NNNN | 0 : 4 | 0.71 | 0.24 |
| PPNN | 2 : 2 | 0.70 | 0.26 |
| NNPP | 2 : 2 | 0.74 | 0.71 |
| PPPN | 3 : 1 | 0.69 | 0.29 |
| NNNP | 1 : 3 | 0.75 | 0.65 |
- bursty 模型有很强的近因偏差:PPPN(多数是好评、最后一个是差评)给出 0.29,NNNP 给出 0.65;PPNN 0.26、NNPP 0.71。当多数和”最后一个”冲突时,最后一个赢。
- base 模型几乎不看标签:PPPP 0.73、NNNN 0.71。它对无内容输入的判断主要取决于”有没有至少两个示例”(0、1 个示例时 0.05–0.08,2 个以上 0.60–0.75)。
同样的结构、同样的训练步数,只改了预训练数据里”同一页评分是否相关”,近因偏差就从无到有。这是 §5.2 那个解释最直接的证据。
零样本时的整体偏向也很明显(03 号脚本演示 1):sentiment · positive/negative 模板下,base 只把 1.3% 的评论判成好评(真实比例 46%);sentiment · great/awful 模板下,两个模型都几乎全判差评(0.3% 和 1.3%)。格式越陌生,模型越没把握,“默认答案”的影响就越大。
5.4 上下文校准与批量校准
如果偏差是”给某个标签整体加了一个分”,修正就很简单:测出这个分,减掉它。上下文校准(contextual calibration;Zhao et al. 2021)的公式是
也就是每个标签的概率除以它在无内容输入上的概率,再归一化。等价地,在对数空间里减掉 。Zhao et al. 把它写成仿射变换 ,取 、。它不需要任何标注数据,只多一次模型调用。
批量校准(batch calibration;Zhou et al. 2024)换了一个参考:不用无内容输入,而用整批测试输入的平均预测:
它的假设是”平均来看,模型不该偏向任何一类”。
在两个迷你模型 × 4 种设计 × 0 / 2 / 4 个示例上(10 组示例的平均,节选):
| 模型 · 设计 · 示例数 | 不校准 | 上下文校准 | 批量校准 |
|---|---|---|---|
| base · rating · great/awful · 4 | 70.9% [70.0, 72.0] | 82.6% [61.0, 94.0] | 94.8% [94.0, 95.7] |
| base · rating · great/awful · 2 | 72.9% [70.0, 74.0] | 79.3% [46.0, 94.7] | 88.4% [81.0, 91.7] |
| base · sentiment · positive/negative · 0 | 55.3% | 63.3% | 66.0% |
| base · sentiment · positive/negative · 2 | 85.5% [82.7, 86.3] | 71.5% [68.0, 76.3] | 86.3% |
| base · sentiment · great/awful · 0 | 54.3% | 12.3% | 42.0% |
| bursty · sentiment · great/awful · 4 | 82.5% [74.7, 89.0] | 76.3% [66.3, 91.3] | 90.9% [90.0, 91.7] |
| bursty · rating · great/awful · 2 | 77.1% [71.7, 80.0] | 67.9% [64.0, 70.7] | 94.9% [91.7, 96.7] |
| bursty · sentiment · positive/negative · 0 | 89.0% | 89.0% | 81.7% |
24 种情形的总账:上下文校准 9 种变好、3 种差不多、12 种变差;批量校准 15 种变好、5 种差不多、4 种变差。
- 校准救得最多的情形,是”模型看懂了输入,只是整体偏向一边”:base 的 rating · great/awful,4 个示例时从 70.9% 到批量校准的 94.8%。
- 上下文校准可以帮倒忙:base 的 sentiment · great/awful 零样本,从 54.3% 变成 12.3%。
<unk>上的概率很极端,除法把它放大成了反方向的偏差。 - 上下文校准的结果本身不稳定:它的参考值来自一个无内容输入;10 组示例之间的波动常常比不校准还大([70.0, 72.0] → [61.0, 94.0])。批量校准用 300 条输入的平均做参考,稳定得多。
- 批量校准也有前提:bursty 模型零样本时本来就几乎不偏(判成好评 51.7%),批量校准把平均预测强行拉到 50:50,反而从 89.0% 掉到 81.7%。测试集严重不平衡时(例如 90% 是差评),这一步会出更大的错。
5.5 “无内容”输入真的没有内容吗
03 号脚本演示 3 只换无内容输入(base,sentiment · positive/negative,零样本):
| 无内容输入 | 它的 P(positive) | 校准后 |
|---|---|---|
<unk> | 0.075 | 63.3% |
the | 0.092 | 63.0% |
the food was | 0.019 | 77.3% |
the soup was <unk> | 0.026 | 76.7% |
| (批量:测试输入的平均) | 0.036 | 66.0% |
同一个模型、同一个提示,只换”无内容”输入,校准后的准确率就在 63.0%–77.3% 之间。the food was 这种半句话,模型会把它补成一条评论来判断,根本不是无内容的。Zhao et al. 自己就用 N/A、空字符串、[MASK] 三个取平均来减轻这个问题;Fei et al.(2023)发现这些输入本身也带偏向,改用随机抽取的领域内词语构造参考输入(领域上下文校准);批量校准则干脆不用人造的输入。
5.6 SimICL:如果偏差真是加性的
为什么校准在 GPT-3 上很有效,在我们的迷你模型上却好坏参半?SimICL 把一种可能的答案写成了公式。它给第一个标签词的分数是
- :输入本身的证据(好评为正、差评为负;simple 句最清楚,but 句最难);
- :“看输入”的强度,随示例数增加——示例让模型认出任务、学到映射(§6.3);
- :多数标签 + 近因 + 一个由”这串示例的这个顺序”决定的随机项(代表 Lu et al. 观察到、但机制不明的顺序效应);
- :每条输入对 的”易感度”,在 1 附近浮动;
- 、:与输入无关的常数偏向。
除了 那一点点,所有偏差都是”加在分数上的常数”——正是校准能减掉的那种。SimICL-large 上(10 组随机示例,不保证两类平衡,和 Zhao et al. 一样):
| 示例数 | 不校准:均值 ± 标准差(最低) | 上下文校准 | 批量校准 |
|---|---|---|---|
| 0 | 72.0% | 95.5% | 98.0% |
| 1 | 77.5% ± 9.0(62.5) | 89.4% ± 3.0 | 86.5% ± 4.8 |
| 4 | 94.1% ± 5.6(79.5) | 94.6% ± 0.9(93.0) | 95.5% ± 2.8 |
| 8 | 96.1% ± 2.1(90.5) | 95.0% ± 0.4 | 96.5% ± 1.2 |
| 16 | 92.8% ± 4.7(84.0) | 94.5% ± 0.9 | 94.2% ± 2.8 |
这张表的形状和 Zhao et al. 报告的 GPT-3 结果相似:不校准时,零样本被常数偏向拖累,少样本的平均尚可但组间波动大、最差的一组很差;校准后均值上升、波动大幅缩小。Zhao et al. 报告上下文校准让 GPT-3 和 GPT-2 的平均准确率最多提高了 30 个百分点,并减小了不同提示之间的波动。(SimICL-medium 的 1 个示例甚至比 0 个还差:72.3% vs 87.0%——只有一个示例时,多数和近因两项偏差全部来自那一个标签。)
但请记住这张表是怎么来的:偏差是加性的,因为我们把它写成了加性的。SimICL 的作用是把”偏差是加性的,所以能被减掉”这个论证变具体;它说明了校准在什么条件下有效,而真实的迷你模型告诉我们,这个条件不总是成立。
5.7 实践建议
- 先测偏差:看零样本和少样本时各类的预测比例,和真实比例比较;用一两个无内容输入看看偏向。
- 偏差明显、而模型”看懂了输入”时,校准往往很有效。优先试批量校准(稳定、不需要人造输入),但要确认测试集不会严重不平衡。
- 校准是提示设计的一部分,要在开发集上验证——它可能帮倒忙。
- chat API 通常不给概率。这时没法直接做校准,但可以用同样的思路:平衡示例的标签、避免让同一个标签出现在最后(或者换几种顺序取多数),并检查输出的类别分布。
6. 示例到底教了什么 · What do demonstrations teach
6.1 Min et al.(2022):标签对不对,没那么重要
Min et al. 在 12 个模型(包括 GPT-3)上做了一个”拆示例”的实验:把示例里的标签换成随机的,准确率大多只下降几个百分点。他们进一步发现,示例真正起作用的是三样东西:标签空间(可以写哪些词)、输入的分布(输入长什么样)、整体格式;“这个输入对应这个标签”的信息反而用得不多。
我们在两个迷你模型上做同样的拆解(4 个示例,10 组的平均):
| 模型 · 设计 | 零样本 | 标签正确 | 标签随机 | 全部翻转 | 只有输入 | 只有标签 | 输入换成无关句子 |
|---|---|---|---|---|---|---|---|
| base · sentiment · pos/neg | 55.3% | 89.7% | 89.7% | 89.6% | 88.1% | 90.7% | 90.6% |
| base · sentiment · great/awful | 54.3% | 71.8% | 74.2% | 75.9% | 61.9% | 59.2% | 81.0% |
| bursty · sentiment · pos/neg | 89.0% | 95.2% | 95.0% | 95.2% | 94.2% | 98.3% | 97.4% |
| bursty · sentiment · great/awful | 55.3% | 82.5% | 81.6% | 85.0% | 85.8% | 89.3% | 78.7% |
(“只有输入”:示例只写 review : x .,没有标签字段;“只有标签”:review : . sentiment : positive .;“无关句子”:输入换成故事里的句子,如 the queen lives in the palace,标签照旧。)
- 标签正确、随机、全部翻转,三者几乎一样。这是 Min et al. 发现的极端版本:两个迷你模型都完全没有使用”输入 → 标签”的对应关系。
- 在 positive/negative 设计下,“半个示例”也差不多够用:只要提示看起来像”一页评论、这里要填评分”就行。
- 在 great/awful 设计下,完整的示例更要紧:base 只有输入 61.9%、只有标签 59.2%,都明显低于完整示例的 71.8%。标签词陌生时,模型需要同时看到”评论 + 标签词”的完整格式。
- “输入换成无关句子”并没有一致地变差(Min et al. 在大模型上发现它会明显变差),两个模型上有升有降。在这个模型最没把握的设计里,示例的细节能左右结果,但方向难以预测。
6.2 Wei et al.(2023):大模型会被翻转的标签带走
Min et al. 的结论容易被读成”模型根本不看标签”。Wei et al.(2023)用两个更极端的设定检验了它:
- 翻转标签(flipped-label ICL):示例里好评都标 negative、差评都标 positive。模型要么听标签词本来的意思(语义先验),要么跟着示例反着答(输入—标签映射)。
- 语义无关标签(semantically-unrelated label ICL,SUL):标签换成 foo / bar 这样和任务无关的词,模型只能从示例里学映射。
他们在 GPT-3、InstructGPT、Codex、PaLM、Flan-PaLM 等模型上发现:小模型几乎不受翻转标签影响(它们靠语义先验),足够大的模型会跟着翻转的标签走,准确率远低于随机;大模型在语义无关标签上也能学会映射,小模型不行。他们还发现,指令微调会让模型更依赖语义先验(更不容易被翻转的标签带走),同时也增强了它学习语义无关映射的能力。
我们的迷你模型站在”小模型”那一端(rating 模板;括号里是两个标签词的概率之和):
| 模型 | 标签词(好评 / 差评) | 0 个示例 | 1 个 | 2 个 | 4 个 |
|---|---|---|---|---|---|
| base | positive / negative | 100.0%(1) | 100.0% | 100.0% | 100.0% |
| base | awful / great | 30.0%(1e−6) | 30.7% | 27.1% | 27.2% |
| base | copper / wheat | 61.0%(6e−7) | 74.0% | 76.4% | 58.3% |
| bursty | awful / great | 3.7%(3e−6) | 4.3% | 18.8% | 29.7% |
| bursty | copper / wheat | 71.7%(1e−6) | 67.9% | 67.5% | 65.8% |
- 标签词反着用时,base 完全不跟示例;bursty 往示例给的映射那边挪了一点(3.7% → 29.7%),但仍远低于 50%。两个模型基本都按 awful、great 本来的意思回答——语义先验压倒了示例。bursty 挪动的那一点,和它”更会读上下文”一致。
- copper / wheat 的数字没有意义。这两个词在
rating :后面的概率只有百万分之一,模型根本不打算写它们;比较两个几乎为零的概率,结果取决于这两个词的向量和模型内部”好评 / 差评方向”偶然对得上多少。great / awful 本来就和好评、差评一起出现,所以对得上(70% 或反过来的 30%);copper / wheat 对不上,于是 base 随示例数在 58%–76% 之间乱跳,没有任何”学会新映射”的趋势。实践上:看一眼标签词的概率之和(或生成式输出里”不是任何一个标签”的比例),它很小时,准确率数字不可信。
6.3 两个发现并不矛盾
SimICL 把两种信息源写成公式里的两项:(多相信标签词本来的意思)和 (多会从示例里学映射)。三种”规模”只改这两个旋钮(8 个示例,10 组的平均):
| 规模 | , | 0% 翻转 | 25% | 50% | 75% | 100% |
|---|---|---|---|---|---|---|
| small | 1.6, 0.3 | 87.9% | 85.5% | 83.2% | 86.9% | 85.0% |
| medium | 1.3, 1.2 | 91.3% | 86.5% | 79.8% | 69.7% | 55.2% |
| large | 1.0, 3.0 | 96.6% | 88.6% | 72.9% | 39.1% | 16.6% |
语义无关的标签词(foo / bar):small 加到 16 个示例也只有 60.1%;large 从 54.5% 升到 88.2%。
- small 像我们的迷你 GPT:翻多少都几乎不变。large 像 Wei et al. 的大模型:100% 翻转时系统性地反着答。
- 50% 翻转(≈ 随机标签)时,small 只比 0% 低 4.6 个百分点,large 低 23.8 个。**Min et al. 的”随机标签影响不大”,前提是模型主要靠先验;Wei et al. 描述的是映射那一项变大之后的情形。**两者是同一个公式里两项的相对大小。
这也是本讲对原课”非对称学习”的解读:示例里的信息不是被平等使用的。格式和标签空间几乎总被用上;输入—标签映射只在 足够大时才被用上;而当示例和预训练先验冲突时,谁赢取决于模型。Kossen et al.(2024)在真实的大模型上得出相近的结论:上下文学习确实会利用示例里的标签关系,但它不像传统的学习算法那样平等地对待所有上下文信息,也很难完全克服预训练形成的预测偏好。
6.4 对提示工程意味着什么
- 示例里的标签要对——对强的模型,错标签会被学进去;对弱的模型,它至少不会帮忙。
- 但不要指望示例能”教会”模型一个和它的先验相反的规则(例如”在这个任务里,‘不错’算差评”)。这种情况下应该用指令把规则写清楚,或者换一个与规则一致的标签词(第 3 讲)。
- 示例最可靠的作用是规定格式和标签空间。所以示例的质量要求,首先是格式一致、标签词一致、覆盖所有类别。
7. 挑示例与排顺序 · Selecting and ordering demonstrations
7.1 按相似度检索示例
既然示例的选择会影响结果,能不能为每道题挑最合适的示例?Liu et al.(2022)提出 KATE:用一个句向量模型,从训练集里找和测试输入最相似的 个样本当示例。他们在 GPT-3 上报告,这在情感分类、表格到文本生成、开放域问答上都明显优于随机示例。后续工作把”相似”换成学出来的检索器(Rubin et al. 2022 的 EPR)、考虑示例之间的多样性和覆盖面,等等。
我们用最简单的词袋余弦相似度(共享的词越多越像),在两个迷你模型上比较三种挑法:随机、最相似、最不相似(示例池 400 条任意长度的评论;节选):
| 模型 · 设计 · k | 随机 | 最相似 | 最不相似 | 随机 vs 最相似(McNemar) |
|---|---|---|---|---|
| base · sentiment · pos/neg · 1 | 63.0% | 61.7% | 67.7% | p = 0.50 |
| base · sentiment · great/awful · 2 | 72.0% | 68.3% | 78.3% | p = 0.11 |
| bursty · sentiment · pos/neg · 1 | 84.3% | 82.7% | 74.3% | p = 0.57 |
| bursty · sentiment · pos/neg · 2 | 92.7% | 96.3% | 100.0% | p = 0.019 |
| bursty · sentiment · great/awful · 2 | 82.3% | 82.3% | 88.7% | p = 1.00 |
- 8 种情形里,最相似和随机只有 1 种有显著差别(bursty、k = 2,最相似更好)。检索相似示例没有稳定地帮到这两个迷你模型。
- 最相似的示例和题目同标签的比例是 71%–72%,比随机的约 50% 高——如果模型会”照抄相似示例的标签”,这本该有帮助。它没有帮助,和 §6 的结论一致:这两个模型不读”输入 → 标签”的对应关系。
- 意外的是,最不相似的示例在 7/8 种情形下最好或并列最好。词袋意义下最不相似的,往往是比较长、有两个分句的评论;也许对这两个小模型,示例的长度和句式比”像不像”更要紧——这只是一个猜测,这里没有验证(练习 6)。
一种挑示例的方法好不好,取决于模型怎样使用示例。KATE 在 GPT-3 上有效,一个合理的解释是大模型会从相似的示例里”借”答案的模式;对不这样做的模型,相似性就不是一个有用的信号。
7.2 不用标注数据挑顺序:熵准则
Lu et al.(2022)的问题是:没有开发集时,怎样从 24 种排列里挑一个好的?他们的观察是:坏的顺序往往让模型在所有输入上都偏向同一个标签。于是:
- 让模型自己生成一批”探测”输入(不需要标注);
- 对每种顺序,看模型在探测集上的预测:
- GlobalE:预测出的标签分布的熵 ——越大说明预测越均衡;
- LocalE:每条预测本身的概率分布的熵的平均——越大说明模型越”犹豫”、越不被顺序推着走;
- 选熵最大的那几种顺序。
他们在 GPT 系列模型、11 个文本分类任务上报告,这带来约 13% 的相对提升。
我们在 sentiment · great/awful 上试(每组 4 个示例的 24 种顺序 × 5 组;探测集是模型自己从 <doc> reviews : review : 开始写的 60 条评论,例如 the music was warm but the staff was bland):
| 模型 | 最差顺序 | 24 种的平均 | 最好顺序 | GlobalE 前 4 名 | LocalE 前 4 名 |
|---|---|---|---|---|---|
| base | 66.4% | 73.2% | 79.5% | 66.9% | 67.2% |
| bursty | 74.5% | 81.6% | 89.3% | 88.8% | 76.8% |
| SimICL-large(对照) | 82.3% | 94.2% | 97.6% | 95.6% | 93.4% |
(迷你模型是 5 组的平均;SimICL 用示例池里 60 条不带标签的评论当探测集。)
- 两个迷你模型上,GlobalE 挑中的都是”最后一个示例是好评”的顺序。§4.3 发现,这类顺序对 bursty 更好、对 base 更差——于是同一个准则、同样的选择,bursty 几乎追上了最好的顺序,base 却接近最差。
- SimICL 的顺序效应是”加在分数上的偏差”,正是 GlobalE 能检测到的那种:它避开了最差的几种,比平均好一点,但离最好还有距离。LocalE 在三个模型上都不如 GlobalE。
带走的经验:无监督的挑选准则都有自己的假设(这里是”好的顺序 = 不偏的顺序”)。它符合你的模型时有效,不符合时可能帮倒忙。用一小份带标注的开发集验证一下,比相信任何一个准则都可靠。
7.3 一份实用的清单
- 示例的格式和标签词比”选哪几个”更重要,先把它们定下来(§2、§3)。
- 让示例覆盖所有类别,数量大致平衡;不要让同一个标签总在最后(§4.3、§5)。
- 想用检索示例时,在开发集上和随机示例配对比较;检索器、相似度的定义都是要调的超参数。
- 报告结果时,把”哪几个示例、什么顺序”当作随机因素:至少换几组,报平均和波动(P3 §6.3)。
8. 上下文学习从哪里来 · Where does ICL come from
配套代码:
06_induction_heads.py;bursty 模型见icl_lab.py
8.1 三种视角
上下文学习是怎样从”预测下一个词”的训练里长出来的?目前有三类互补的解释:
- 机制视角:归纳头(Olsson et al. 2022)。一个两层的注意力电路:第一层的”前一位头”让每个位置记住它前面是哪个词;第二层的”归纳头”在当前词是 A 时,去找”前面是 A”的位置,把那里的词抄过来——“A B … A → B”。Olsson et al. 发现,归纳头在训练中突然形成,形成的那一小段训练里,模型的上下文学习能力(用前文降低后文损失的能力)也突然变强;他们提出(并承认证据是初步的、间接的),大模型里很大一部分上下文学习可能是由归纳头完成的。
- 统计视角:隐式贝叶斯推断(Xie et al. 2022;§5.2)。预训练文档有隐含的”概念”,模型学会了从前文推断概念;少样本示例只是推断的证据。
- 数据视角:分布特性(Chan et al. 2022)。他们在受控实验里发现,训练数据要有某些特性,上下文学习能力才会出现:同类的东西成簇出现(burstiness)、有大量很少出现的类别、类别分布有长尾(Zipf)。在很规整、很均匀的数据上,模型更倾向于把知识存进参数(“权重内学习”),而不是学会从上下文里读。
此外还有一条理论线:在线性回归之类的简单任务上,Transformer 的上下文学习可以精确地对应到某种学习算法,例如一步梯度下降(von Oswald et al. 2023;Akyürek et al. 2023;Garg et al. 2022)。这些结果说明”在前向计算里实现一个学习算法”是可能的,但它们和真实大模型的关系仍在研究中。
本讲的实验正好对应前两种视角和第三种视角的一个小例子。
8.2 一个干净的玩具任务:每条序列一条新的马尔可夫链
设计一个只能靠上下文学习的任务:每条训练序列来自一条新的、随机的马尔可夫链——3 个符号,转移概率矩阵的每一行都从均匀分布(Dirichlet(1,1,1))里重新抽。模型不可能把转移规律背进参数里,因为每条序列的规律都不一样;它只能从这条序列的前文里估计。这正是上下文学习:参数固定,规律从上下文里读出来。Edelman et al.(2024)系统地研究过同一个任务。
对这个任务,有三条”理论线”:
- 均匀猜:;
- 一元统计(只数前文里每个符号出现几次):,平均损失 1.0212;
- 二元统计(数前文里”当前符号 后面跟了 “的次数):,平均损失 0.9080。这是贝叶斯最优的预测——而要算它,模型必须”找到前文里和当前符号相同的位置,看它们后面是什么”,这正是归纳头的两步。
8.3 训练曲线:先数频率,再看前后
从零训练两个 TinyGPT(4 个头、d_model = 64),2 层(104,384 个参数)和 1 层(54,400 个参数),各 1500 步:
| 训练步数 | 2 层模型 | 1 层模型 |
|---|---|---|
| 1 | 1.0854(≈ 均匀) | 1.1083(≈ 均匀) |
| 50 | 1.0202(≈ 一元) | 1.0260(≈ 一元) |
| 200 | 1.0024(≈ 一元) | 1.0193(≈ 一元) |
| 300 | 0.9667 | 1.0121 |
| 400 | 0.9426(≈ 二元) | 1.0088 |
| 1000 | 0.9150 | 1.0067 |
| 1500 | 0.9121 | 1.0020 |
- 2 层模型先在约第 50 步走到一元统计那条线,在那里停了一百多步,然后在第 250–400 步之间跌到二元统计的水平;结束时 0.9121,离贝叶斯最优只差 0.004。这就是 Edelman et al. 描述的阶段性,也是 Olsson et al. 在真实语言模型里看到的”相变”的一个缩影。
- 1 层模型始终停在一元统计附近(1.0020)。
- 注意那个一元阶段:模型的策略是”前文里哪个多,就猜哪个”。放到少样本提示里,这就是多数标签偏差。二元阶段的”照着前文抄”,放到提示里就是从示例里复制格式和标签。上下文学习的能力和它的偏差,来自同一套机制。
8.4 打开模型:前一位头与归纳头
对每个头算两个得分(64 条验证序列上的平均):前一位得分——位置 放在 上的注意力;归纳得分——位置 放在”前一个符号和当前符号相同”的那些位置上的注意力之和。
| 头 | 前一位得分 | 归纳得分 |
|---|---|---|
| 2 层模型 · 第 1 层 · 头 3 | 0.635 | 0.461 |
| 2 层模型 · 第 1 层 · 头 4 | 0.599 | 0.457 |
| 2 层模型 · 第 2 层 · 头 1–4 | 0.050–0.055 | 0.701–0.886 |
| 1 层模型 · 4 个头 | 0.062–0.070 | 0.396–0.402 |
| (对照:注意力在前文上均匀分布) | 0.052 | 0.395 |
这就是第 1 讲 §6.6 手工搭出来的那个电路——这一次,它是梯度下降自己找到的:第 1 层有两个前一位头,把”我前面是谁”抄到每个位置上;第 2 层的四个头都变成了归纳头,去找”前面是当前符号”的位置。1 层模型的四个头和均匀注意力没有区别:没有第 1 层先把”前一个符号”抄过去,单独一层做不到。
8.5 上下文学习曲线
每个位置上的平均损失(看到的符号越多,越能估计这条链):
| 已看到的符号数 | 2 层模型 | 1 层模型 | 一元统计 | 二元统计 |
|---|---|---|---|---|
| 1 | 1.101 | 1.101 | 1.167 | 1.099 |
| 9 | 0.990 | 1.026 | 1.072 | 0.989 |
| 17 | 0.896 | 0.969 | 0.998 | 0.892 |
| 64 | 0.845 | 0.975 | 0.977 | 0.831 |
2 层模型的损失随位置一路下降,紧贴二元统计;1 层模型贴着一元统计。这是”示例越多越好”最简单的版本:上下文越长,模型对”这份文档的规律”估计得越准。
8.6 回到语言:数据决定了模型学会什么
两个迷你 GPT 有没有归纳头?06 号脚本演示 4 把 12 个随机词连写两遍,看模型在第二遍里能不能预测下一个词:base 和 bursty 都是 0.0%。它们的训练语料是模板化的句子,没有”同一段任意内容重复出现”的结构,归纳头没有理由长出来——这和 §6 的发现一致:它们的少样本能力靠的是认格式,不是从示例里复制。
把本讲的实验放在一起:
- 只改”同一页评分是否相关”,模型就学会了读前面的标签(bursty:零样本 sentiment 模板 89.0% vs base 55.3%)——也学会了近因偏差(§5.3);
- 在”每条序列一套新规律”的数据上,两层模型长出了归纳头,学会了从上下文里估计规律——也先经过了一个”数频率”的阶段;
- 在没有重复结构的数据上,同样的结构什么都不抄。
**上下文学习能力——以及它的偏差——由预训练数据的结构决定。**真实的网页文本里,重复和成簇无处不在:名字反复出现、代码里的变量、表格的列、同一个话题的帖子。这也许正是大模型普遍”会”上下文学习的原因。
9. 在真实的大模型上 · On real models
配套代码:
07_real_llm.py(可选;--toy不联网)
07 号脚本在真实的 Claude 上跑一个小实验:3 个英文模板 × 5 种条件(零样本;同一组 4 个示例 × 标签正确 / 全部翻转 × 最后一个是好评 / 差评)× 16 条评论 = 240 次短调用(默认 claude-opus-5-5、effort = low,预算上限 1 美元;--model claude-haiku-5-5 更便宜)。提示长这样:
Classify the sentiment of each review as positive or negative.
Review: The room was great.
Sentiment: negative
Review: The bread was noisy.
Sentiment: positive
...
Review: The bread was lovely and the waiter was great.
Sentiment:
(这是”翻转标签”条件:指令说分成 positive / negative,示例却全部标反了。)
几点说明:
- 真实的 chat API 不返回标签词的概率(P2 §3.6),所以只能看模型写了哪个词;这也意味着没法直接做 §5 的校准。
- 默认模型不接受 temperature,同一个请求两次的结果可能不同;缓存(
cache/)会把第一次的结果固定下来,第二次运行不再花钱。 - 16 条评论的区间很宽(一条就是 6.25 个百分点)。要下结论,加大题数,并用
stats_kit.mcnemar_exact做配对检验。 - 这个实验里指令和示例互相矛盾。一个经过指令微调的模型面对这种矛盾时听谁的,正是 Wei et al.(2023)研究的问题,也是第 3 讲的话题。
- 编写这份讲义的环境里没有安装 anthropic SDK,所以没有真实模型的结果可以报告;
--toy模式(SimICL-large)的输出只用来检查代码能跑通:标签正确时 6 种(模板 × 顺序)的平均 91.7%,翻转后 19.8%——这些数字由旋钮决定,不代表任何真实模型。
今天的 chat 模型和 GPT-3 有几个重要的不同,读论文时要注意:
- 零样本强得多。指令微调(第 3 讲)让模型直接听懂任务描述,少样本相对零样本的提升通常变小;示例更多是在规定格式和风格。
- 对示例格式的敏感性降低了,但没有消失。Sclar et al.(2024)的格式敏感性实验里,指令微调过的模型也有明显的波动。
- 窗口大到可以放几百个示例(many-shot ICL,Agarwal et al. 2024),这改变了”少样本 vs 微调”的权衡。
- 思考型模型会先在内部推理,示例对它的影响方式可能又不一样(第 4 讲)。
所以本讲的实验方法——拆开因素、配对比较、把示例当随机因素、检查偏差——比任何一个具体结论都更持久。
10. 原课作业 1 对照:怎样做一个文本分类的提示实验 · Assignment 1
原课作业 1 要求在一个文本分类任务上展示指令写法、模板使用和示例选择的效果。一份合格的实验报告大致是这样:
- 数据:分成开发集和测试集。提示的一切选择只在开发集上做,测试集只在最后用一次(P3 §5)。
- 因素:明确你在比较什么——指令的写法(第 3 讲)、模板(§3.1)、标签词(§3.2)、示例数(§2)、示例的挑法(§7.1)、顺序(§4.3)、是否校准(§5)。一次只改一个因素。
- 把示例当随机因素:每个设置至少换 5 组示例(或 5 种顺序),报告平均和标准差;比较两个设置时,每组示例上做配对比较(P3 §6.3)。
- 统计:单个准确率报 Wilson 区间;两个设置在同一组题上比较用 McNemar;比较了很多个设置时用 Holm 校正(P3 §3–§5)。
- 诊断:报告各类的预测比例(偏差)、“答了别的词”的比例(标签词是否可用)、按难度或类别拆开的准确率(哪里错了)。
- 成本:每个设置的平均输入 / 输出 token 和费用(P2 §6)。示例更多的提示,要更好多少才值得?
- 结论的范围:写清楚模型名和版本、日期、温度(如果能设)。提示的效果是”提示 × 模型”的属性,换模型要重测。
本讲的 02–05 号脚本就是这套流程的缩影,可以直接改成你的作业框架:把 icl_lab.label_probs 换成 P2 的 llm_api 调用,把评论换成你的数据集。
11. 小结 · Summary
- 上下文学习:参数冻结,把示例写进条件里。“学习”发生在前向计算中——模型在读示例时推断”这份文档的规律”。
- 示例首先教格式:在迷你模型上,示例把一个陌生的模板从 55.3% 救到 89.7%,却没教会 but 句;文献里叫”任务识别”而不是”任务学习”。
- 模板和标签词是最大的因素:意思相同的标签词可以差 30 个百分点;标签词要选模型在这个位置上”本来就会说”的。
- 敏感性是”提示 × 模型”的属性:平均不敏感的模型,在某个设计上换顺序也能差 14 个百分点;越会读上下文的模型,越敏感。顺序效应常常能用”最后一个示例的标签”解释。
- 偏差来自合理推断:多数和近因偏差是模型从”同页内容相关”的数据里学到的;只改这一点,近因偏差就从无到有。
- 校准修正整体的偏向:上下文校准和批量校准在”模型看懂了、只是偏了”时很有效,否则可能帮倒忙;要在开发集上验证。
- 示例的信息被不对称地使用:小模型只用格式和标签空间(随机、翻转标签都无所谓),大模型还会用映射(会被翻转的标签带走)。Min et al. 和 Wei et al. 描述的是同一个公式里两项的相对大小。
- 挑选方法都有假设:相似度检索、熵准则在一个模型上有效,在另一个上可能无效甚至有害。
- 能力来自数据:在”每条序列一套新规律”的数据上,两层模型先学会数频率(多数偏差的来源),再长出归纳头;在没有重复结构的数据上,同样的结构什么都不抄。
12. 常见误区 · Common pitfalls
| 误区 | 实际情况 |
|---|---|
| “示例越多越好” | 示例占窗口、花钱;对熟悉的格式,零样本已经最好(qa 模板加示例反而变差);超出窗口时最前面的内容被截掉 |
| “示例里的标签对不对无所谓” | 对靠先验的模型几乎无所谓;对会学映射的大模型,错标签会被学进去(Wei et al. 2023) |
| “标签词只要意思对就行” | great/awful 和 positive/negative 意思一样,可以差 30 个百分点;看一眼标签词的概率之和 |
| “我试了一种顺序,结果是 X%” | 换顺序可能差十几个百分点;至少换几种顺序、几组示例,报告平均和波动 |
| “在开发集上挑最好的提示,报它的成绩” | 挑选会抬高开发集成绩;要在没用来挑选的留出集上报告 |
| “上下文校准总能提高准确率” | 它修正的是整体偏向;无内容输入本身有偏向,结果可能更差(54.3% → 12.3%) |
| “检索最相似的示例一定更好” | 取决于模型是否从相似示例里借答案;在不这样做的模型上,相似度不是有用的信号 |
| “近因偏差是 Transformer 的缺陷” | 它是从”同页内容相关”的数据里学到的合理推断,被用在了不合理的场合 |
| “迷你模型 / 模拟器上的结论适用于 GPT” | 迷你模型说明机制,SimICL 说明论证;真实模型的结论要在真实模型上测 |
13. 练习 · Exercises
练习 1(概念) 零样本、单样本、少样本提示的区别是什么?它们和”微调”在使用标注数据的方式上有什么根本不同?
参考答案:三者的区别只在提示里放几个示例(0、1、若干个);共同点是模型参数都不更新。微调用标注数据计算梯度、改变参数,效果”写进”了模型;上下文学习把标注数据写进提示里作为条件,效果只存在于这一次前向计算,换一个提示就没有了。代价也不同:微调要训练一次、之后每次调用便宜;上下文学习不用训练,但每次调用都要为示例的 token 付钱。
练习 2(读表) §2.1 里 sentiment 模板零样本只有 55.3%,模型给 positive 的平均概率是 0.04。(a)“全猜差评”能得多少分?(b)为什么说这个模型”其实看得懂评论”的可能性很大?可以用什么方法验证?
参考答案:(a)测试集 162/300 是差评,全猜差评得 54.0%;55.3% 只比它好一点。(b)同一个模型在 rating 模板下是 100%,说明它的内部表示里有情感信息;sentiment 模板只是让它整体偏向了 negative。验证:做校准——如果偏差是整体的,除掉偏向后准确率应该明显上升。03 号脚本里批量校准把它提到 66.0%、用
the food was做参考的上下文校准提到 77.3%,说明确实有一部分”看懂了只是偏了”,但不是全部(2 个示例时可以到 85% 以上)。
练习 3(计算) 一个模型在某个提示下,对无内容输入给出 P(positive) = 0.8、P(negative) = 0.2。对一条测试评论,它给出 P(positive) = 0.6、P(negative) = 0.4。上下文校准后,这条评论被判成什么?
参考答案:,;归一化后 P(positive) = 0.75/2.75 ≈ 0.27,P(negative) ≈ 0.73。校准前判好评,校准后判差评:模型对这条评论的”好评倾向”(0.6)比它对任何输入的默认倾向(0.8)还低,所以相对来说它更像差评。
练习 4(设计) 你在一个三分类任务(正面 / 中性 / 负面)上用 4 个示例做少样本提示。请设计一个实验,区分”多数标签偏差”和”近因偏差”。
参考答案:用无内容输入(或一批测试输入的平均预测)测量预测分布,构造标签顺序不同、但多数和最后一个标签”冲突”的示例组,例如 [正, 正, 正, 负] 与 [负, 负, 负, 正](多数和最后一个相反),[正, 正, 负, 负] 与 [负, 负, 正, 正](多数相同、最后两个不同)。每种顺序用几组不同的示例内容重复(避免内容和顺序混在一起),比较预测分布。如果 [正正正负] 更偏负面,说明近因压过了多数(03 号脚本里 bursty 模型就是这样:PPPN 0.29 vs NNNP 0.65)。
练习 5(解释) Min et al.(2022)说随机标签几乎不影响准确率,Wei et al.(2023)说大模型会被翻转的标签带着走。用 §6.3 的公式解释为什么两者不矛盾,并说出一个能同时检验两个结论的实验。
参考答案:把模型的打分写成”语义先验 × 输入证据 + 示例映射 × 输入证据 + 偏差”。随机标签让映射项接近 0,准确率退回”只靠先验”的水平——对先验强的模型,这个水平本来就高,所以几乎没损失(Min et al.)。全部翻转让映射项变成负的;只有映射项的系数够大,它才能压过先验,让模型反着答(Wei et al. 的大模型)。实验:同一个模型、同样的示例,把翻转比例从 0% 调到 100%(04 号脚本演示 3 的做法),画出准确率曲线;先验强的模型曲线平坦,映射强的模型曲线下降、在 100% 时远低于随机。在多个规模的模型上重复,就同时检验了两个结论。
练习 6(动手) 05 号脚本发现”最不相似的示例”在迷你模型上反而常常最好,讲义猜测原因是这些示例更长、有两个分句。设计并实现一个实验检验这个猜测。
参考答案:把”相似度”和”长度 / 句式”两个因素拆开:(1)只从两个分句的评论里随机抽示例,和只从一个分句的评论里随机抽比较(控制相似度为随机、只改长度);(2)在同样长度的评论里比较最相似和最不相似(控制长度、只改相似度)。如果(1)里两分句的示例明显更好、(2)里差别消失,就支持”长度 / 句式”的解释。注意用同一组测试题做 McNemar 配对检验,并换几组示例。实现时可以复用
icl_lab.render和label_probs,按len(x.split())或" and " in x过滤示例池。
练习 7(机制) 06 号脚本里,1 层模型停在”一元统计”的水平。解释为什么一层注意力能实现一元统计,却实现不了二元统计。
参考答案:一元统计只需要”前文里每个符号出现几次”:一个在前文上均匀分布注意力的头,把每个位置的符号嵌入平均起来,就得到了符号频率的向量,输出层据此预测——一层就够。二元统计需要”在当前符号 之后出现过什么”:要找的位置是”前一个符号是 “的位置。可在一层模型里,每个位置的表示只有它自己的符号和位置,没有”我前面是谁”这个信息,注意力没法按”前一个符号”去匹配。两层模型的第 1 层先用前一位头把”前一个符号”写进每个位置,第 2 层才能按它匹配(演示 2 里正好看到这两种头)。
练习 8(批判) bursty 模型比 base 更会利用示例(sentiment 模板零样本 89.0% vs 55.3%),但也更受顺序影响、有更强的近因偏差。如果你要为一个产品选模型,你会怎样权衡?这对”选更大、更会上下文学习的模型”有什么启示?
参考答案:更会利用上下文意味着:给对的示例时效果更好,给偏的示例时也偏得更多。权衡时要看你能否控制示例:如果示例是固定的、可以在开发集上调好(平衡标签、验证顺序、校准),更强的上下文学习者通常更好;如果示例来自用户输入或检索结果、不可控,它的敏感性就是风险。对”选更大的模型”的启示:大模型零样本更强、上下文学习更强,但不能假设它”不敏感”——Lu et al. 发现顺序敏感性在各种规模上都存在。换模型之后,要重新做敏感性分析和偏差检查。
练习 9(作业对照) 按 §10 的清单,为原课作业 1 写一份实验计划(不超过一页):数据集划分、要比较的因素、每个因素的水平、重复次数、统计方法、要报告的诊断指标和成本。估算一下总的调用次数和费用。
参考答案(一种可能):数据 500 条,开发 200 / 测试 300。因素:指令(无 / 简短 / 详细)× 标签词(2 种)× 示例数(0 / 4 / 8)× 校准(有 / 无,只在能拿到概率时);每个有示例的设置换 5 组示例。开发集上的调用次数:3 × 2 ×(1 + 2 × 5)× 200 = 13,200 次;挑出 3 个候选后在测试集上跑 3 × 5 × 300 = 4,500 次。按每次约 400 个输入 token、5 个输出 token、某模型每百万 token 输入 1 美元 / 输出 5 美元估算,约 18,000 次 × (400 × 1 + 5 × 5)/10⁶ ≈ 7.7 美元(加上缓存后重跑不再花钱)。统计:Wilson 区间、McNemar 配对检验、Holm 校正;诊断:各类预测比例、非标签输出比例、按类别的准确率;成本:每个设置的平均 token 和费用。
14. 延伸阅读 · Further reading
少样本提示与敏感性
- Brown, T. et al. (2020). Language Models are Few-Shot Learners (GPT-3). NeurIPS.
- Zhao, Z., Wallace, E., Feng, S., Klein, D., & Singh, S. (2021). Calibrate Before Use: Improving Few-Shot Performance of Language Models. ICML.
- Lu, Y., Bartolo, M., Moore, A., Riedel, S., & Stenetorp, P. (2022). Fantastically Ordered Prompts and Where to Find Them: Overcoming Few-Shot Prompt Order Sensitivity. ACL.
- Sclar, M., Choi, Y., Tsvetkov, Y., & Suhr, A. (2024). Quantifying Language Models’ Sensitivity to Spurious Features in Prompt Design. ICLR.
- Holtzman, A., West, P., Shwartz, V., Choi, Y., & Zettlemoyer, L. (2021). Surface Form Competition: Why the Highest Probability Answer Isn’t Always Right. EMNLP.
校准
- Fei, Y., Hou, Y., Chen, Z., & Bosselut, A. (2023). Mitigating Label Biases for In-context Learning. ACL.
- Zhou, H., Wan, X., Proleev, L., Mincu, D., Chen, J., Heller, K., & Roy, S. (2024). Batch Calibration: Rethinking Calibration for In-Context Learning and Prompt Engineering. ICLR.
示例教了什么
- Min, S. et al. (2022). Rethinking the Role of Demonstrations: What Makes In-Context Learning Work? EMNLP.
- Wei, J. et al. (2023). Larger Language Models Do In-Context Learning Differently. arXiv:2303.03846.
- Pan, J., Gao, T., Chen, H., & Chen, D. (2023). What In-Context Learning “Learns” In-Context: Disentangling Task Recognition and Task Learning. Findings of ACL.
- Kossen, J., Gal, Y., & Rainforth, T. (2024). In-Context Learning Learns Label Relationships but Is Not Conventional Learning. ICLR.
- Reynolds, L., & McDonell, K. (2021). Prompt Programming for Large Language Models: Beyond the Few-Shot Paradigm. CHI Extended Abstracts.
- Schick, T., & Schütze, H. (2021). Exploiting Cloze Questions for Few Shot Text Classification and Natural Language Inference (PET). EACL.
挑选示例
- Liu, J. et al. (2022). What Makes Good In-Context Examples for GPT-3? DeeLIO Workshop.
- Rubin, O., Herzig, J., & Berant, J. (2022). Learning To Retrieve Prompts for In-Context Learning. NAACL.
- Agarwal, R. et al. (2024). Many-Shot In-Context Learning. NeurIPS.
上下文学习从哪里来
- Olsson, C. et al. (2022). In-context Learning and Induction Heads. Transformer Circuits Thread.
- Xie, S. M., Raghunathan, A., Liang, P., & Ma, T. (2022). An Explanation of In-context Learning as Implicit Bayesian Inference. ICLR.
- Chan, S. C. Y. et al. (2022). Data Distributional Properties Drive Emergent In-Context Learning in Transformers. NeurIPS.
- Edelman, E., Tsilivis, N., Edelman, B. L., Malach, E., & Goel, S. (2024). The Evolution of Statistical Induction Heads: In-Context Learning Markov Chains. NeurIPS.
- Garg, S., Tsipras, D., Liang, P., & Valiant, G. (2022). What Can Transformers Learn In-Context? A Case Study of Simple Function Classes. NeurIPS.
- von Oswald, J. et al. (2023). Transformers Learn In-Context by Gradient Descent. ICML.
- Akyürek, E., Schuurmans, D., Andreas, J., Ma, T., & Zhou, D. (2023). What Learning Algorithm is In-Context Learning? Investigations with Linear Models. ICLR.
- Dong, Q. et al. (2024). A Survey on In-context Learning. EMNLP.(综述,适合查漏补缺)
15. 下一讲预告 · Next lecture
这一讲里,base 模型只会”认格式”:提示必须伪装成它熟悉的文档,标签词必须是它在那个位置上会说的词,几个示例扳不动它的习惯。第 3 讲进入原课第 2 周的第二个主题:指令微调(Instruction Tuning)——让模型直接听懂”把这条评论分成好评或差评”。
- 为什么 base 模型不听指令;FLAN、T0、Super-NaturalInstructions 怎样把几十上千个任务改写成指令数据;任务的数量、模板的多样性、混入少样本和思维链数据各起什么作用;
- InstructGPT 的监督微调与 RLHF(13 亿参数的模型在人类评价中胜过 1750 亿参数的 GPT-3);用模型自己生成指令数据(Self-Instruct、Alpaca);“少而精”(LIMA)与”表面对齐假说”;
- chat 模板与 system prompt;指令微调怎样改变了本讲的结论(零样本变强、少样本收益变小、对语义先验更依赖);
- 动手:在第 1 讲的迷你 GPT 上做一次真正的指令微调——扩展词表、只在回答上算损失——比较微调前后它对同一组提示的反应,并做”任务多样性 vs 数据量”的消融。