Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 6 讲习题集

四组难度递进:A 概念判断 → B 推导证明 → C 编程实现 → D 开放设计。答案默认折叠,点击展开。 用法:先闭卷做 A 组(只写对错不给分,必须给一句话理由或反例),再对照答案;B 组手写推导,涉及形状与量纲的先写形状;C 组上机并跑通每题末尾的验收标准;D 组写成半页方案(方案 + 理由 + 失败判据 + 验证计划,四项缺一不可)。 本讲所有考点均以正文为限;凡是「具体规格」类数字(窗口、定价、榜单名次、模型版本)都不作为考点,引用时按勘误页的时效纪律标注核查时点与来源。

A 组 · 概念判断(8 题)

A1. 「困惑度(PPL)更低的模型一定更强,所以可以直接拿两个模型的 PPL 比高低。」(依据:定义 6.1.2、例 6.1.1)

A2. 「缩放律是理论规律,所以可以放心地代入常数外推点值;参数越多一定越强。」(依据:定义 6.2.1、方法 6.2.5)

A3. 「某团队报告:模型在 32B 规模上『突然学会』多步算术,说明跨过规模阈值后产生了新的推理机制。」(依据:6.2.4、例 6.2.3)

A4. 「自洽性(多采样投票)总是更好,采样条数越多准确率越高。」(依据:定义 6.3.3、例 6.3.2)

A5. 「思维链写出来的步骤就是模型的真实计算过程,所以 CoT 可以直接当作审计依据。」(依据:定义 6.3.2、6.3.2 的边界讨论、勘误·术语第 4 条)

A6. 「把连续动作分成离散 token 只是换了一种输出格式,对系统能达到的精度没有影响。」(依据:定义 6.5.1、6.5.2 的代价讨论)

A7. 「用了 MCP 这类标准工具协议之后,工具调用的安全问题就解决了。」(依据:定义 6.6.3、6.6.3 的三件事)

A8. 「评测集从来没有被主动放进训练数据,所以我们的分数不存在污染。」(依据:定义 6.7.1、6.7.2 的三层不可判定性)

答案

A1. 错。 三个理由:① PPL 只在同一 tokenizer、同一语料去重程度下可比——换分词方式连序列长度 TT 都变了,两个数字放在一起没有意义;② PPL 是逐 token 平均,高频功能词会把均值压低,「PPL 很低」与「关键事实说错」可以共存;③ 训练数据里的重复片段可人为压低 PPL:同难度文本从 L=0.693\mathcal L=0.693 变到整体 0.2830.283,PPL 从 2.02.0 降到 1.331.33,而能力没有变化(例 6.1.1)。跨分词器比较要改用每字节比特数(BPB)。(6.1.1)

A2. 错。 缩放律是经验拟合,不是推导:指数与常数随架构、优化器、数据分布变化,旧曲线不能搬到新设置上。而且「参数越多越强」是三条轴里最容易被孤立使用的一条——固定算力时参数与数据存在交换率(C≈6NDC\approx6ND),固定数据时参数过大会欠训练。(6.2.1、6.2 的误解 1–2)

A3. 错(至少不足以支撑「机制」结论)。 「整题全对率」是离散度量:若任务需 kk 步全对、单步成功率 pp 平滑上升,则 Acc=pk\mathrm{Acc}=p^{k} 会自己造出台阶(k=8k=8、p:0.5→0.8p:0.5\to0.8 时从 0.00390.0039 跳到 0.1680.168)。要区分「机制突变」与「度量假象」,须做三件事之一:换连续度量(逐步骤部分得分 / 编辑距离)重画曲线、直接测单步能力、对同一离散分数做单调重标定看阈值是否移动。(6.2.4、例 6.2.3)

A4. 错。 多数投票要有效必须 p>0.5p\gt0.5:p=0.4p=0.4、k=5k=5 时投票成功率仅 0.317<0.40.317\lt0.4——投出了错误的多数。即便 p>0.5p\gt0.5,收益也被错误相关性吃掉:p=0.6p=0.6 独立时 0.6830.683,若 30% 的概率全体共享同一错误则降到 0.4780.478。此外 kk 越大收益递减且不保证单调,开放写作类任务没有「多数答案」。(例 6.3.2)

A5. 错。 CoT 提高表现,不保证忠实(faithfulness):模型可能在生成理由前就已「倾向」某个答案,理由是被组织出来的。因此 CoT 不能当作内部计算过程的证据,做审计要靠外部信号(测试通过、检索核实、人工确认)。这一点与智能体的 Thought 是同一个问题。(6.3.2、6.6.9)

A6. 错。 分箱是有损的:把连续动作分到有限个箱子,等于给动作精度设了一个不可逾越的上限(例:平移 0.10.1 m 范围要 0.20.2 mm 精度 → 每维 500500 箱);而且「按维度依次预测」引入维度间的顺序依赖。离散化换来的是语义迁移与工程复用,代价正是精度上限与序列长度。(6.5.2、例 6.5.2)

A7. 错。 协议降低的是集成成本,不降低安全成本。标准化之后问题反而上移一层:① 权限与授权(谁能连、能连哪些、是否逐次确认);② 信任边界(工具返回的内容是外部数据,应被当作数据而不是指令——这是提示注入的入口);③ 工具发现与选择(可用工具从 5 个变成 500 个时,「选对工具」本身成为检索问题)。(6.6.3)

A8. 错。 污染的三条路径都不需要有人「主动放入」:① 近似泄漏——题库被模板改写(换数字、换人名)后散落在网上,字面查重查不出;② 间接泄漏——训练语料含讲解该基准解题技巧的长文,模型学到「套路」;③ 输出回流——上一代模型的解题过程被发布上网并被下一代数据管线抓取,污染自我增殖。因此「没有污染」是一个无法被证明的论断,只能通过私有题集、时间切分、动态更新、扰动改写、执行式判定、多基准并行来降低风险。(6.7.2)

B 组 · 推导与证明(6 题)

B1. 从「用模型分布 qq 作为编码器去压缩真实分布 pp 的序列」出发,推导期望码长 Ep[−log⁡2q(x)]=H(p)+DKL(p∥q)\mathbb E_p[-\log_2 q(\boldsymbol x)]=H(p)+D_{\mathrm{KL}}(p\lVert q);据此说明 PPL=2H2(q)\mathrm{PPL}=2^{H_2(q)} 的读法,并用 例 6.1.1 的数字复算「每 token 多少比特」。(依据:命题 6.1.1、定义 6.1.2)

B2. 已知训练算力 C=2.4×1022C=2.4\times10^{22} FLOPs(量级示意)。(a) 按 C≈6NDC\approx6ND 与计算最优配比 D≈20ND\approx20N 反解 (N,D)(N,D);(b) 若改用 D=10ND=10N 的配比,同一算力下 (N,D)(N,D) 变成多少;(c) 说明为什么工业界常常主动选择比计算最优更小的 NN、更大的 DD。(依据:例 6.2.2、6.2.2)

B3. 设某任务需要 kk 个步骤全部正确才判对,单步正确率 pp 随规模线性上升。(a) 取 k=8k=8、p∈{0.45,0.55,0.65,0.75}p\in{0.45,0.55,0.65,0.75},计算 Acc=pk\mathrm{Acc}=p^{k} 并描述曲线形状;(b) 若判据是「Acc≥0.1\mathrm{Acc}\ge0.1」,求 k=1,8,16k=1,8,16 各自所需的 pp,说明阈值如何随 kk 移动;(c) 由此写出一条可证伪的检验判据。(依据:例 6.2.3、6.2.4)

B4. 世界模型的单步预测相对误差为 ϵ\epsilon。(a) 写出独立随机误差与系统性偏差两种累积模型;(b) 容差 10%10%、ϵ=0.02\epsilon=0.02 时分别求最大 rollout 长度;(c) 换容差 8%8%、ϵ=0.02\epsilon=0.02 求两个长度;(d) 若要求「线性假设下可规划 5050 步」,ϵ\epsilon 需降到多少?(依据:例 6.6.2、6.6.7)

B5. 某模型在 200 道题上按置信度分三箱:[0.5,0.7)[0.5,0.7) 有 50 题、平均置信度 0.600.60、实际准确率 0.500.50;[0.7,0.9)[0.7,0.9) 有 100 题、0.800.80 / 0.750.75;[0.9,1.0][0.9,1.0] 有 50 题、0.950.95 / 0.920.92。(a) 算 ECE;(b) 分别取阈值 τ=0.9,0.7\tau=0.9,0.7(以及「不作答限制」的 τ=0.5\tau=0.5)算覆盖率与作答子集错误率;(c) 说明为什么阈值是业务决策,以及「校准必须在什么集合上做」。(依据:定义 6.7.3、例 6.7.4)

B6. 两个模型在 100 道题上逐题比较:55 道都对、18 道只有 A 对、9 道只有 B 对、18 道都错。(a) 求各自的准确率与配对口径下的分歧胜率;(b) 对「18/2718/27」做检验:写出精确二项单尾值、连续性修正后的正态近似值、未修正的正态近似值;(c) 用 14/2014/20 这个新例子说明「近似显著、精确不显著」的陷阱;(d) 给出报告纪律。(依据:例 6.7.3、6.7.3)

提示与答案

B1. (i) 先写期望码长。 用模型分布 qq 分配码长 −log⁡2q(x)-\log_2 q(\boldsymbol x),真实信源是 pp:

Ep[−log⁡2q]=Ep[−log⁡2p−log⁡2qp]=H(p)+DKL(p∥q) 比特.\mathbb E_p[-\log_2 q]=\mathbb E_p\Bigl[-\log_2 p-\log_2\frac{q}{p}\Bigr]=H(p)+D_{\mathrm{KL}}(p\lVert q)\ \text{比特}.

第二项因 DKL≥0D_{\mathrm{KL}}\ge0(Jensen)而恒非负,当且仅当 q=pq=p 取等——以 qq 编码的平均代价永远不低于真实熵,多出来的部分恰好是模型误差。

(ii) 与困惑度的关系。 若平均每 token 的负对数似然(自然对数)为 L\mathcal L,则每 token 的比特数是 L/ln⁡2=H2(q)\mathcal L/\ln 2=H_2(q),于是 PPL=eL=2H2(q)\mathrm{PPL}=e^{\mathcal L}=2^{H_2(q)}:困惑度的底‑2 对数就是「平均每 token 花多少比特」。

(iii) 复算。 L=0.693\mathcal L=0.693 nat ⇒PPL=e0.693≈2\Rightarrow \mathrm{PPL}=e^{0.693}\approx2,每 token 约 0.693/ln⁡2=10.693/\ln 2=1 比特;读作「模型平均在 2 个等可能 token 之间犹豫」。这正是「最小化交叉熵 == 最小化压缩长度」的字面含义。(命题 6.1.1)

B2. (a) 把 D=20ND=20N 代入:C≈6N⋅20N=120N2C\approx6N\cdot20N=120N^2,故

N=2.4×1022120=2×1020≈1.41×1010 (约 14.1B),D=20N≈2.83×1011 (约 283B).N=\sqrt{\frac{2.4\times10^{22}}{120}}=\sqrt{2\times10^{20}}\approx1.41\times10^{10}\ (\text{约 }14.1\text{B}),\qquad D=20N\approx2.83\times10^{11}\ (\text{约 }283\text{B}).

校验:6ND=6×1.41×1010×2.83×1011≈2.4×10226ND=6\times1.41\times10^{10}\times2.83\times10^{11}\approx2.4\times10^{22} ✓。

(b) 配比改成 D=10ND=10N 后 C≈60N2C\approx60N^2,故 N=4×1020=2.0×1010N=\sqrt{4\times10^{20}}=2.0\times10^{10}(20B)、D=2.0×1011D=2.0\times10^{11}(200B)。同一算力下,配比偏参数就得到更大的 NN 与更少的数据——这就是 2020 与 2022 两次结论分歧在数字上的样子。

(c) 因为世界里的目标函数不是「固定训练算力下最小化损失」,而是最小化总拥有成本:训练是一次性的,推理是每次调用都要付的。多训一些 token 换一个更小的模型,能在部署阶段反复省下推理成本与延迟;所以实践中的选择常小于计算最优规模(「推理最优」≠「训练最优」)。代价是训练算力花得更多、数据管线成为瓶颈(6.2.2、6.2.3)。

B3. (a) 逐点取幂(p8p^8):

pp 0.45 0.55 0.65 0.75
Acc=p8\mathrm{Acc}=p^{8} 0.0017 0.0084 0.0319 0.1001

前三点都贴在 0.030.03 以下(肉眼几乎不可分),最后一点跳到 0.100.10——pp 线性上升,观感却是一次跨阈值突变。

(b) 解 p=0.11/kp=0.1^{1/k}:k=1⇒p=0.100k=1\Rightarrow p=0.100;k=8⇒p≈0.750k=8\Rightarrow p\approx0.750;k=16⇒p≈0.866k=16\Rightarrow p\approx0.866。阈值随步骤数 kk 系统性右移:题目越长,需要越高的单步能力才能把整体准确率抬到同一水平。

(c) 可证伪判据(任一条,关键是能被实验推翻):固定模型族、只改题目的步骤数 kk,观察「涌现点」的位置——若阈值随 kk 单调右移,则台阶可由乘积效应 Acc=pk\mathrm{Acc}=p^{k} 解释,而不是新能力的出现;反之(阈值不随 kk 移动)则乘积效应不足以解释,需要另找机制。(例 6.2.3 的判据表)

B4. (a) 独立随机误差按随机游走累积 eH≈ϵHe_H\approx\epsilon\sqrt H;系统性偏差按线性累积 eH≈ϵHe_H\approx\epsilon H。实践中常见「早期像随机、后期像系统」——轨迹一旦偏离训练分布,误差就开始同向叠加。所以任何「可规划 HH 步」的说法都必须连带报告误差模型。

(b) 容差 10%10\%、ϵ=0.02\epsilon=0.02:线性 H≤0.10/0.02=5H\le0.10/0.02=5 步;平方根 ϵH≤0.10⇒H≤25\epsilon\sqrt H\le0.10\Rightarrow H\le25 步。两者相差 5 倍。

(c) 容差 8%8\%、ϵ=0.02\epsilon=0.02:线性 H≤0.08/0.02=4H\le0.08/0.02=4 步;平方根 H≤16H\le16 步。

(d) 线性假设下 H=50H=50 要求 ϵ≤0.10/50=0.002\epsilon\le0.10/50=0.002(即 0.2%)——比原来精确 10 倍。这解释了为什么世界模型研究的第一优先级是单步动力学精度,而不是规划算法本身。

B5. (a) 逐箱偏差 ∣|准确率 −- 置信度∣|:0.100.10、0.050.05、0.030.03。按样本数加权:

ECE=50200(0.10)+100200(0.05)+50200(0.03)=0.025+0.025+0.0075=0.0575.\mathrm{ECE}=\frac{50}{200}(0.10)+\frac{100}{200}(0.05)+\frac{50}{200}(0.03)=0.025+0.025+0.0075=0.0575 .

即平均偏差 5.75 个百分点,且每一箱的实际准确率都低于声称的置信度——系统性过度自信。

(b) 全量准确率 =50×0.50+100×0.75+50×0.92200=0.73=\frac{50\times0.50+100\times0.75+50\times0.92}{200}=0.73。

阈值 覆盖率 作答子集错误率
τ=0.9\tau=0.9 50/200=25%50/200=25\% 1−0.92=8%1-0.92=8\%
τ=0.7\tau=0.7 150/200=75%150/200=75\% 100×0.25+50×0.08150=19.3%\frac{100\times0.25+50\times0.08}{150}=19.3\%
τ=0.5\tau=0.5(不弃答) 100%100\% 1−0.73=27%1-0.73=27\%

「降低阈值换覆盖率、代价是错误率上升」就是风险—覆盖曲线:覆盖率越高、风险越高。

(c) 阈值直接对应两类错误的成本比:自动回复类场景错误便宜 → 阈值压低、少弃答;医疗/法律建议类场景错误极贵 → 阈值抬高、宁可把大部分请求转人工,弃答率就是人力成本预算。校准与阈值选择必须在留出的、与真实流量分布一致的校准集上做——在测试集上校准、在真实分布上部署,是最常见也最隐蔽的失误。(例 6.7.4)

B6. (a) A=55+18100=73%A=\frac{55+18}{100}=73\%,B=55+9100=64%B=\frac{55+9}{100}=64\%(差 9 个百分点)。配对口径:分歧题 18+9=2718+9=27 道,A 赢 18/27≈66.7%18/27\approx66.7\%;在「至少一个模型答对」的 82 道上 A 的胜率为 73/82≈89.0%73/82\approx89.0\%。

(b) 零假设「两个模型在分歧题上五五开」(p=1/2p=1/2,n=27n=27):

  • 精确二项:单尾 P(X≥18)=∑j=1827(27j)/227≈0.0610P(X\ge18)=\sum_{j=18}^{27}\binom{27}{j}/2^{27}\approx0.0610(双侧 0.12210.1221);
  • 正态近似 + 连续性修正:z=18−0.5−13.527/4≈1.5396z=\frac{18-0.5-13.5}{\sqrt{27/4}}\approx1.5396,单尾 ≈0.0618\approx0.0618(与精确值几乎一致);
  • 正态近似(不修正):z=18−13.52.598≈1.7321z=\frac{18-13.5}{2.598}\approx1.7321,单尾 ≈0.0416\approx0.0416。

正文 例 6.7.3 写的 p≈0.043p\approx0.043 属第三种口径(未做连续性修正的正态近似)。方向结论不变(A 更优),但「在 5% 水平上刚刚显著」这句话依赖方法:按精确检验 0.0610.061 并不显著。更正登记见勘误第四节。

(c) 新例子:2020 道分歧题里 A 赢 1414 道。精确二项单尾 P(X≥14)=∑j=1420(20j)/220≈0.0577P(X\ge14)=\sum_{j=14}^{20}\binom{20}{j}/2^{20}\approx0.0577;未修正正态近似 z=14−105≈1.789z=\frac{14-10}{\sqrt{5}}\approx1.789,单尾 ≈0.0368\approx0.0368。近似的口径说「显著」,精确的口径说「不显著」——同一组数据,两句话。

(d) 报告纪律:① 报配对口径(分歧题上的胜率)而不是两个平均分相减,因为题目难度这一主要噪声被抵消;② 报检验方法与显著性水平,精确检验与近似法的结论可能不同;③ 报样本量与统计功效——分歧题只有 27 道时,功效低到几乎无法分辨 60% 与 70% 的真实差距;④ 检查优势是否集中在某一类题型上(若 A 的全部优势来自数学题,而你的任务不涉及数学,这个结论对你无用)。(6.7.3)

C 组 · 编程实现(6 题)

依赖仅限标准库与 numpy(C1–C6 均可在无 GPU 环境跑通)。每题给出可运行的验收标准——不通过就说明对应环节没接上;所有「参考值」都能在正文里找到出处。

C1. 实现自洽性投票的闭式解与蒙特卡洛两个版本,并复现「p<0.5p\lt0.5 时投票劣于单链」,再实现「错误相关」情形。(依据:定义 6.3.3、例 6.3.2)

  • 验收标准:① 对 (k,p)=(5,0.4),(5,0.6),(7,0.45),(5,0.62)(k,p)=(5,0.4),(5,0.6),(7,0.45),(5,0.62) 的闭式输出分别为 0.3174, 0.6826, 0.3917, 0.71650.3174,,0.6826,,0.3917,,0.7165(误差 <10−4&lt;10^{-4});② 断言 vote_exact(5,0.4) < 0.4(反例成立);③ 20 万次蒙特卡洛与闭式之差 <0.005&lt;0.005;④ 打印「25% 概率全体共享同一错误」下的期望成功率 ≈0.5374\approx0.5374,并输出收益缩水比例。
参考实现
from math import comb
from random import Random
def vote_exact(k, p):
    """闭式:至少 k//2+1 条链正确(k 为奇数时即严格多数)。"""
    need = k // 2 + 1
    return sum(comb(k, j) * p**j * (1 - p)**(k - j) for j in range(need, k + 1))
def vote_mc(k, p, trials=200_000, seed=0):
    """蒙特卡洛:每条链独立以概率 p 判对,取多数。"""
    rng, ok = Random(seed), 0
    need = k // 2 + 1
    for _ in range(trials):
        if sum(rng.random() < p for _ in range(k)) >= need:
            ok += 1
    return ok / trials
for k, p in [(5, 0.4), (5, 0.6), (7, 0.45), (5, 0.62)]:
    e, m = vote_exact(k, p), vote_mc(k, p)
    tag = "劣于单链" if e < p else "优于单链"
    print(f"k={k} p={p}: 闭式={e:.4f} 蒙特卡洛={m:.4f} 单链={p:.2f} → {tag}")
assert vote_exact(5, 0.4) < 0.4, "p<0.5 时投票应劣于单链"
p0, rho = 0.62, 0.75            # rho:不落入「共同错误」模式的比例
indep = vote_exact(5, p0)
print(f"p={p0} 独立 {indep:.4f} → 含 25% 共同错误 {rho * indep:.4f},"
      f"相对收益缩水 {(1 - rho * indep / indep):.1%}")

C2. 实现一个污染扰动集:造模板题 → 三类扰动(换数字 / 换实体 / 改写表述)→ 用一个玩具「记忆型模型」算分数落差,并用 bootstrap 给出置信区间。(依据:定义 6.7.1、方法 6.7.2)

  • 验收标准:① 输出三行「原始 / 换数字 / 换实体」分数,且原始分数显著高于两个扰动分数;② 每行给出 bootstrap 95% 区间;③ 打印「落差」与「区间宽度的比值」,并断言落差 >&gt; 区间宽度(这才是「分数来自记忆而非能力」的判据);④ 换一个随机种子重跑,结论方向不变。
参考实现
import random
def make_cases(kind, n=200, seed=0):
    """kind: raw=模板题;number=换数字;entity=换实体(表述也被改写)。"""
    rng = random.Random(seed + hash(kind) % 1000)
    return [{"a": rng.randint(2, 20), "b": rng.randint(2, 20),
             "ans": None, "kind": kind} for _ in range(n)]
def toy_model(c):
    """玩具模型:模板题「背过答案」;一旦扰动就退回弱启发式。"""
    a, b = c["a"], c["b"]
    if c["kind"] == "raw":
        return a + b                                  # 记忆
    if c["kind"] == "number":
        return a + b + (0 if a % 4 else 3)            # 近似,但会系统性崩
    return a + b if a > b else -1                     # 换实体后≈随机
def score(cases):
    return sum(toy_model(c) == c["a"] + c["b"] for c in cases) / len(cases)
def bootstrap_ci(cases, n_boot=2000, seed=0):
    rng = random.Random(seed)
    accs = sorted(score([rng.choice(cases) for _ in cases]) for _ in range(n_boot))
    return accs[int(0.025 * n_boot)], accs[int(0.975 * n_boot)]
res = {}
for kind in ("raw", "number", "entity"):
    cases = make_cases(kind)
    lo, hi = bootstrap_ci(cases)
    res[kind] = score(cases)
    print(f"{kind:6s} 分数 {res[kind]:.3f}  95% CI [{lo:.3f}, {hi:.3f}]  宽度 {hi - lo:.3f}")
drop = res["raw"] - res["number"]
print(f"落差(原始 − 换数字)= {drop:.3f};结论:"
      f"{'分数主要由记忆支撑' if drop > 0.1 else '落差不足以定论'}")

C3. 实现 ECE(分箱加权)与风险—覆盖曲线,用正文三箱数据复算 0.0850.085,并验证「风险随覆盖率单调不降」。(依据:定义 6.7.3、例 6.7.4)

  • 验收标准:① 用正文三箱(40/100/6040/100/60、置信度 0.60/0.80/0.950.60/0.80/0.95、准确率 0.45/0.72/0.900.45/0.72/0.90)复算 ECE =0.085=0.085(误差 <10−9&lt;10^{-9});② 三个阈值 τ=0.9,0.7,0.5\tau=0.9,0.7,0.5 的输出分别为 (0.30, 0.100)(0.30,,0.100)、(0.80, 0.2125)(0.80,,0.2125)、(1.00, 0.27)(1.00,,0.27)(误差 <10−3&lt;10^{-3});③ 断言风险序列随覆盖率单调非降;④ 打印「每一箱的实际准确率都低于其置信度」以确认过度自信方向。
参考实现
import numpy as np
def ece(confs, accs, weights, edges):
    """期望校准误差:按给定分箱边界加权平均 |acc − conf|。"""
    confs, accs, weights = map(np.asarray, (confs, accs, weights))
    idx = np.clip(np.digitize(confs, edges[1:-1]), 0, len(edges) - 2)
    total = weights.sum()
    return sum(weights[idx == b].sum() / total * abs(accs[idx == b].mean() - confs[idx == b].mean())
               for b in range(len(edges) - 1) if (idx == b).any())
def risk_coverage(confs, accs, weights, thresholds):
    confs, accs, weights = map(np.asarray, (confs, accs, weights))
    out = []
    for t in thresholds:
        m = confs >= t
        out.append((weights[m].sum() / weights.sum(), 1 - (accs[m] * weights[m]).sum() / weights[m].sum()))
    return out
confs, accs, weights = [0.60, 0.80, 0.95], [0.45, 0.72, 0.90], [40, 100, 60]
edges = [0.5, 0.7, 0.9, 1.0]
print("ECE =", round(ece(confs, accs, weights, edges), 4))          # 0.085
curve = risk_coverage(confs, accs, weights, [0.9, 0.7, 0.5])
for t, (cov, risk) in zip((0.9, 0.7, 0.5), curve):
    print(f"τ={t}: 覆盖率 {cov:.2f} 错误率 {risk:.4f}")
risks = [r for _, r in curve]
assert all(b >= a - 1e-12 for a, b in zip(risks, risks[1:])), "风险应随覆盖率单调不降"
assert all(a < c for a, c in zip(accs, confs)), "每箱实际准确率都应低于置信度(过度自信)"

C4. 写一个 KV cache 显存估算器,复现正文的「约 33 GB」,并给出 GQA / KV 量化后的曲线。(依据:定义 6.1.5、6.1.6)

  • 验收标准:① L=1e5, n_layer=80, n_kv=8, d_h=128, bf16, B=1 的输出在 [32.5,33.5][32.5, 33.5] GB 内;② nkvn_{\text{kv}} 从 8 降到 1 时显存严格按比例下降(断言 nkv=1n_{\text{kv}}{=}1 的值恰为 nkv=8n_{\text{kv}}{=}8 的 1/81/8);③ KV 量化到 8 bit 时恰为一半;④ 打印「把 LL 翻倍」后的值,验证线性增长。
参考实现
def kv_cache_gb(L, n_layer, n_kv, d_h, bytes_per=2, B=1, base=1e9):
    """KV cache = 2 · B · L · n_layer · n_kv · d_h · bytes_per(系数 2 是 K 与 V)。"""
    return 2 * B * L * n_layer * n_kv * d_h * bytes_per / base
cfg = dict(L=100_000, n_layer=80, n_kv=8, d_h=128, bytes_per=2, B=1)
print(f"BF16, n_kv=8, L=1e5 → {kv_cache_gb(**cfg):.2f} GB")   # ≈ 32.77,正文写作「约 33 GB」
for n_kv in (8, 4, 2, 1):                                     # GQA / MQA 的效果
    print(f"n_kv={n_kv}: {kv_cache_gb(**{**cfg, 'n_kv': n_kv}):.2f} GB")
print(f"8bit KV: {kv_cache_gb(**{**cfg, 'bytes_per': 1}):.2f} GB")  # 恰为一半
print(f"L 翻倍 : {kv_cache_gb(**{**cfg, 'L': 2 * cfg['L']}):.2f} GB")  # 线性
assert abs(kv_cache_gb(**{**cfg, "n_kv": 1}) * 8 - kv_cache_gb(**cfg)) < 1e-9, "应严格线性"
assert 32.5 <= kv_cache_gb(**cfg) <= 33.5, "应与正文的 33 GB 对齐"

C5. 写视觉 token 与分辨率预算脚本:复现 336² / 672² / 1008² / 2016² 的 token 数,并复现「切片 + 缩略图」方案,最后用「每 patch 覆盖的原图像素数」判断有效分辨率。(依据:例 6.4.2、例 6.4.3)

  • 验收标准:① 四档分辨率分别输出 576, 2304, 5184, 20736576,,2304,,5184,,20736;② 切片方案 3×3+13\times3+1 输出 57605760、4×4+14\times4+1 输出 97929792;③ 断言「整图缩到 100821008^2」与「切 3×33\times3 后每片缩到 3362336^2」的每 patch 覆盖原图像素数相等(≈48.7\approx48.7,差 <0.1&lt;0.1);④ 打印结论:切片买的是「全局 + 局部并存」与「分辨率可分配」,不是像素效率。
参考实现
def tokens(edge, patch=14):
    """一条边的 patch 数取整后平方(与正文口径一致)。"""
    return (edge // patch) ** 2
print("336² :", tokens(336), " 672² :", tokens(672),
      " 1008² :", tokens(1008), " 2016² :", tokens(2016))
print("切 3×3 + 缩略图 :", 9 * tokens(336) + tokens(336))
print("切 4×4 + 缩略图 :", 16 * tokens(336) + tokens(336))
def px_per_patch(img_edge, n_patches):
    return img_edge / n_patches
# A4 文档(约 3508 px 高)两种方案:整图缩到 1008² vs 切 3 片每片缩到 336²
whole = px_per_patch(3508, 1008 // 14)          # 72 个 patch
tiled = px_per_patch(3508 / 3, 336 // 14)       # 每片 24 个 patch
print(f"整图每 patch 覆盖 {whole:.1f} px;切片每 patch 覆盖 {tiled:.1f} px")
assert abs(whole - tiled) < 0.1, "两者应几乎相等 → 切片不提高有效分辨率"
print("结论:切片买的是「全局+局部并存」与「分辨率可分配」,不是像素效率。")

C6. 写动作分箱与词表开销估算器:复现 21502150 个新 token、H=16H=16 时的 128128 个动作 token 与 8.81 M 输出层参数,并输出「精度—词表」权衡表。(依据:例 6.5.2、方法 6.5.5)

  • 验收标准:① 平移 / 旋转 / 夹爪三档分箱分别为 500500、200200、5050,合计新增 21502150 个 token;② H=16H=16、da=8d_a=8 时动作 token 数为 128128,且把平移精度提高一倍后该数字不变(断言:分箱数只影响词表,不影响序列长度);③ 输出层新增参数 2150×4096=8,806,4002150\times4096=8{,}806{,}400(约 8.81 M,对 7B 约 0.13%);④ 打印精度加倍后的新 token 数与参数量(36503650 与约 14.95 M)。
参考实现
from math import ceil
def bins(lo, hi, precision):
    """某维所需分箱数(精度决定词表上限,这是离散化路线的硬边界)。"""
    return ceil((hi - lo) / precision)
def budget(new_tokens_total, n_dims, H):
    return {"新 token 数(词表扩张)": new_tokens_total,
            "动作 token 数(序列长度)": n_dims * H}
spec = {"平移": (-0.05, 0.05, 0.0002),   # ±0.05 m,最细 0.2 mm
        "旋转": (-0.1, 0.1, 0.001),      # ±0.1 rad,最细 0.001 rad
        "夹爪": (0.0, 1.0, 0.02)}
per_dim = {k: bins(*v) for k, v in spec.items()}
print("每维分箱数:", per_dim)                       # {'平移': 500, '旋转': 200, '夹爪': 50}
new_tokens = 3 * per_dim["平移"] + 3 * per_dim["旋转"] + per_dim["夹爪"]
print("合计新增 token:", new_tokens, budget(new_tokens, n_dims=8, H=16))
d_model = 4096
extra = new_tokens * d_model
print(f"输出层新增参数: {extra:,} = {extra/1e6:.2f} M(7B 的 {extra/7e9:.3%})")
# 精度加倍:分箱数翻倍 → 词表变大,但动作 token 数不变
finer = 3 * 1000 + 3 * per_dim["旋转"] + per_dim["夹爪"]
print("精度加倍 →", finer, "个新 token,参数", f"{finer*d_model/1e6:.2f} M",
      ";动作 token 仍为", 8 * 16)
assert 8 * 16 == 128                      # 与分箱数无关

D 组 · 开放设计(4 题)

D1. 评测方案设计(两周、零标注预算) 场景:入职评审会上有人说「新模型 X 已经具备能力 A」(A 是你们产品要用的能力)。你的约束是:只有两周、没有标注预算、不能改模型,但要给出一个能证伪这个说法的评测方案。 要求:方案 + 理由 + 失败判据 + 验证计划(四项缺一不可)。

参考方案与评分要点

方案(按四道闸门组织,方法 6.7.4):① 匹配性——先写清「能力 A」在你的产品里的可观察定义(输入什么、输出什么算对),再从公开基准里挑一个因果相关的(若涉及工具/代码,优先执行式判定);② 自建私有小测集 100100–200200 题(人工半天可完成),题目在训练截止日之后取材或自造成有时间戳的场景;③ 稳定性——同一模型跑多种提示(0-shot / few-shot、允许/禁止 CoT)× 多次采样,报均值 ± 标准差,并做逐题配对比较;④ 污染——对自己可控的候选做 n-gram 与训练语料比对,对不可控的模型只能标注「无法证明无污染」;⑤ 扰动版:把自建题换数字 / 换实体各造一份,观察分数落差(落差大即提示记忆而非能力)。

理由:能力主张的三个失效方向(度量不匹配、污染、方差)恰好对应前三道闸门;扰动集是零标注预算下唯一能自己做的污染探针。

失败判据(可测量):① 换提示后分数差 >5&gt;5 个百分点,或重复采样标准差 >3&gt;3 个百分点 → 结论不可用,先固定协议;② 扰动版分数落差 >&gt; 配对置信区间宽度 → 先按「记忆」处理,不承认能力;③ 自建集与公开基准的结论方向相反(自建集上 A 不占优)→ 以自建集为准,并检查基准的匹配性;④ 两周内凑不出 100100 题 → 说明「能力 A」的定义还不清晰,先退回定义环节。

验证计划:把协议(提示模板、采样次数、抽取规则、评测集版本)写进一页文档并在第二次会议上复现一次;报告里同时给出「在什么条件下不成立」。评分要点:方案具体 4 分 + 判据可测量 4 分 + 风险识别(污染不可证明、方差、配对口径)2 分。

D2. 推理算力分配(延迟与成本双约束) 场景:一个问答服务,流量按难度分层:简单 60%60%、中等 30%30%、困难 10%10%。约束:P95 端到端延迟 ≤3\le3 s、月成本上限为「全部走大模型 + 长 CoT」的 30%30%。你已经有一个很小的模型可以低成本预判难度。 要求:方案 + 理由 + 失败判据 + 验证计划。

参考方案与评分要点

方案:按 6.3.3 的三形态与 6.7.5 的部署手段做分层分流:① 规则层先拦截结构化请求(可直接查表/模板回答的);② 小模型层处理简单题(短答),并用小模型的采样一致性当置信度代理(6.7.4)——一致性高的直接返回;③ 中等题走小模型 + 长 CoT(正文 例 6.3.4 的成本排序显示这一档的「每提升 1 个百分点成本」最低);④ 只有困难题(且有可验证通道时)才升级到「大模型 + 长 CoT + 多采样/搜索」;⑤ 长 CoT 的输出上限与超时降级策略必须显式设定。

理由:测试时计算的收益按难度分布不均(简单题无需搜索、超纲题无收益甚至更差),因此「把预算花在难度中间段」是唯一同时满足成本与延迟的做法;缓存(稳定前缀放最前)与流式输出用于压首 token 延迟。

失败判据(可测量):① 缓存命中率 <50%&lt;50\% → 前缀顺序或分片有问题(6.7.5);② 简单分流层的错误率高于其被替换的档位 → 一致性代理不可用,退回全量短答;③ 中等档的「每提升 1 个百分点的成本」超过直接换大模型档 → 说明长 CoT 在该难度上不划算;④ 困难档延迟 P95 >3&gt;3 s 或长 CoT 触发率 >15%&gt;15\% → 违反预算,需缩窄升级条件;⑤ 成本按 P95 token 数而非均值核算(均值估算法会超支)。

验证计划:先做影子流量(新策略与旧策略并跑,比同批请求的分数与延迟),再按 5% → 25% → 100% 金丝雀放量;每一步记录「分数 / P95 延迟 / 每千次成本 / 拒答率」四个指标。评分要点:分层方案与理由 4 分 + 成本—延迟账 3 分 + 判据可测量 3 分。

D3. Agent 工具权限设计 场景:给一个「设备采购助手」设计工具集,它要能查库存、比价、下单、发通知、读 CRM。团队曾经出过一次事故:助手在用户还没确认时就提交了订单。 要求:方案 + 理由 + 失败判据 + 验证计划(须覆盖 schema 设计、幂等性、不可逆操作闸门、工具输出的信任边界、权限最小化)。

参考方案与评分要点

方案:① 拆薄参数、动词化命名(6.6.2):search_stock(part_id)、compare_price(part_id, qty)、hold_order(part_id, qty, ttl_minutes)、confirm_order(hold_id, approver)、send_notice(channel, text)、read_crm_customer(customer_id)——一个工具做一件事;② 不可逆操作隔离:只有 confirm_order 有副作用且绝不授权自动重试,必须带 approver 字段并由用户或策略显式确认;hold_order 提供可撤销的中间态(把不可逆动作推到最后一刻);③ 幂等性显式标注:只读工具可重试、hold_order 有限重试、confirm_order 标 ❌;④ 信任边界:所有工具返回值一律当作数据注入,与指令分隔(网页/CRM 文本可能含注入指令,6.6.3);⑤ 权限最小化:只暴露读 CRM 的单客户接口而非全表查询;下单金额上限、白名单供应商、审计日志;⑥ 终止条件:最大步数、单会话工具调用预算、连续无进展即退出。

理由:模型的权限上限等于宿主授予的工具集合,与模型「意愿」无关;因此安全必须做在接口层,不能指望策略自己学会「永远不越权」。

失败判据(可测量):① 「未经确认的 confirm_order 次数」必须为 0(这条比总体成功率重要得多);② 无效工具调用率 <5%&lt;5\%(借用 20 条对抗指令测:日期歧义、跨月、数量为 0、同一单重复提交);③ 循环次数超过上限的会话占比 <1%&lt;1\%;④ 注入测试集里出现越权动作(读取非授权客户、跳过确认)即判定失败。

验证计划:先用重放式对抗指令集(不需要真下单,用 mock 后端)跑三遍,观察轨迹是否出现「未经确认的提交」;再在沙箱环境做影子运行,最后才接真实后端并保留人工复核通道。评分要点:schema 与幂等设计 3 分 + 闸门与权限最小化 4 分 + 判据可测量(含「0 次未确认扣款」)3 分。

D4. 部署四道闸门 场景:上线申请单只有五行字——「模型 A 在 MMLU 上比现网模型高 2 分、SWE-bench 高 5 分,已确认无污染;计划下周全量切换。」 要求:方案 + 理由 + 失败判据 + 验证计划(逐条走 方法 6.7.4 的四道闸门,并给出你的最终裁定:上线 / 有条件上线 / 不上线)。

参考方案与评分要点

闸门 ① 匹配性:MMLU / SWE-bench 与「我们的产品任务」因果相关吗?若产品是客服分类,两个分数都不构成依据——换基准或自建小测集(例 6.7.1 的 (b) 就是「按平均分会选错模型」的反例)。该申请单的最大缺陷就在这一层。

闸门 ② 污染:「已确认无污染」是一个不可证明的论断(6.7.2 的三层不可判定性);公开基准尤其危险。要求:时间切分或私有题集重测 + 扰动版落差 + 与训练语料的 n-gram 比对记录。

闸门 ③ 稳定性:「高 2 分 / 高 5 分」是单次分数还是均值 ± 方差?换提示会不会翻盘?要求:配对比较 + 多次重复 + 多种提示(两处独立方差各 1.5 个点即合成约 2.1 个点,2–5 分的差距可能落在噪声里)。

闸门 ④ 可用性:成本与延迟的 P95、低置信时系统做什么(弃答通道)、出事怎么回滚。注意回滚要版本化整个系统状态:提示模板、工具 schema、检索库、阈值参数、模型版本——只切回旧权重而保留新提示,常常无法恢复旧行为。

判定:不上线,退回补材料(这是本题的期望结论);若产品任务与基准确实相关,则给「有条件上线」:影子流量 → 5% 金丝雀 → 分三档放量,且每档检查「分数、P95 延迟、每千次成本、拒答率」四项。

失败判据(可测量):① 报告仍只有单次分数 → 不得进入放量;② 自建测集上优势 <&lt; 配对置信区间 → 结论为「无差异」,按成本与延迟决策而非能力;③ 影子流量中,新模型在长尾输入(长度 P95 以上)上的错误率高于旧模型 → 停止放量;④ 回滚演练超过 10 分钟 → 先修回滚,再谈上线。

验证计划:把四道闸门的证据写进上线文档(6.7.5 的六个问题逐条回答),而不是留在工程师脑子里;发布后第一周每日抽样人工评审、盯行为指标(拒答率、解析失败率、工具调用失败率、输入长度分布)——准确率下降是结果,行为指标是早期信号。评分要点:四道闸门逐条覆盖 5 分 + 裁定与条件 3 分 + 监控/回滚清单 2 分。