大模型知识体系 第 23 章 🎮 交互版(含动画演示与测验)
← 强化学习与偏好优化:PPO 与 GRPO🏠 回到交互版首页岗位查阅:能力矩阵与四级标准 →
你正在浏览静态阅读版(无 JavaScript 也可阅读,便于搜索与 AI 抓取)。交互演示与答题功能请前往 交互版。
第 23 章 · 第六部分 · 评估 (Evaluate)

LLM Evaluation:模型到底有没有变好

PPL、Exact Match、pass@k、MMLU/C-Eval/GSM8K、LLM-as-a-Judge、置信区间、Contamination、失败案例分析 + 评测 Lab。

对应课件:LLM Systems(第二批新增)

本章定位:第二批收尾模块。第 3 章讲的是经典 ML 评估(Accuracy/Precision/Recall/F1/过拟合);本章专门讲 LLM 特有的评估体系,回答:模型到底有没有变好? 以及——benchmark 分数到底说明什么、不说明什么。

跨章闭环:Contamination(23.13)与数据管线第 18 章直接对应。

📘 代码类型约定(Build / Systems 章节统一)
  • 【Runnable】可直接运行(关键逻辑已在本课程验证脚本中实测)
  • 【Skeleton】工程骨架:逻辑完整,需要自备数据/环境

23.1 Evaluation Pipeline:评估也是一条流水线

先懂直觉

「跑个 benchmark」不是一个数,而是一条流水线:模型给出原始输出 → 用模板套出 prompt → 生成 → 解析出答案 → 和标准答案比对 → 汇总成指标。任何一环出错,分数都会失真——这是本章反复强调的核心。

Model
  ↓  Dataset(题目 + 标准答案)
  ↓  Prompt Template(few-shot / zero-shot / 指令格式)
  ↓  Generation(采样参数:temperature、max_tokens)
  ↓  Parser(从输出里抽出「答案」)
  ↓  Metric(EM / F1 / Accuracy / pass@k / judge)
  ↓  Report(分数 + 置信区间 + 失败样本)
🎮 交互:点击每一环看它在做什么、错在哪会怎样交互演示 · 静态阅读版

23.2 Perplexity:与预训练 loss 直接相连

PPL=eLoss\text{PPL} = e^{\text{Loss}}
Loss PPL 含义
2.0 7.39 平均在 ~7 个候选间犹豫
3.0 20.09 更不确定
⚠️ PPL 的两个使用边界
  1. 不同 tokenizer 之间不可直接比较(token 粒度不同 → 每步难度不同,第 21 章已讲);
  2. PPL 低 ≠ 下游任务好:它衡量「预测文本」的能力,与指令遵循、推理、安全性无直接关系。

23.3 Exact Match:解析器决定分数

先懂直觉

EM 要求输出与标准答案完全一致(规范化后)。问题是:模型很少只输出一个答案。

标准答案:42
模型输出:The answer is 42.

直接比较:Exact Match = 0
解析后比较(抽取"42"):Exact Match = 1

结论:metric 与 parser 是一体的。报告 EM 时必须说明规范化规则(大小写、空白、标点、是否抽取答案)。

🎮 交互:EM 与 F1 计算器交互演示 · 静态阅读版

编辑「标准答案」与「模型输出」,实时看规范化后的 Exact Match 与 token 级 F1——体会 parser 对分数的影响。

在交互版中打开这个演示 →

23.4 F1:QA 类任务的部分给分

先懂直觉

抽取式问答(SQuAD 风格)里,答案常常是「一段话里的一段」。完全一致要求太严格,于是用 token 级 F1 给部分分。

P=∣预测∩标准∣∣预测∣,R=∣预测∩标准∣∣标准∣,F1=2PRP+RP = \frac{|\text{预测} \cap \text{标准}|}{|\text{预测}|}, \qquad R = \frac{|\text{预测} \cap \text{标准}|}{|\text{标准}|}, \qquad F_1 = \frac{2PR}{P + R}

算例:标准「苹果公司位于库比蒂诺」,预测「苹果公司位于美国库比蒂诺」:

23.5 选择题准确率与随机基线

先懂直觉

选择题(MMLU / C-Eval / C3 / XCOPA)只看选项:Accuracy = 答对比例。但必须对照随机基线——4 选项 = 25%,2 选项 = 50%。不看基线的分数没有意义。

Benchmark 类型 随机基线 说明
MMLU 4 选 1(英文多学科) 25% 知识广度
C-Eval 4 选 1(中文多学科) 25% 中文知识
C3 中文阅读理解(多选) 25% 中文理解
XCOPA 2 选 1(因果常识) 50% 因果推理
📘 一个真实的小模型案例(本项目,描述性结果,非 SOTA)

用本课程路线训练的小模型在中文评测上的实测结果(描述性结果):

任务 分数 随机基线 相对基线
C3 40% 25% +15pt
XCOPA 55% 50% +5pt

怎么读这张表(重要):

  • 这两行是描述性结果:只说明「分数比随机基线高多少」;
  • 不能仅凭百分点差异判断提升是否具有统计显著性——区间估计需要样本量与置信区间(见 23.14)。本课程当前没有给出这两个评测的样本量,因此不做「已学到某能力」或「几乎没学会」这类结论;
  • 这正是本章 Confidence Interval 一节的动机:分数必须和不确定性一起看。

小模型的绝对分数通常低(非 SOTA),这是规模决定的正常现象;本案例用于演示「如何正确地报告分数」,不是能力结论。

🎮 交互:分数 vs 随机基线交互演示 · 静态阅读版

拖动分数滑块,看它相对不同基线(25% / 50%)的位置——同样的 40%,在不同任务里的意义完全不同。

在交互版中打开这个演示 →

23.6 pass@k:代码任务为什么要多次采样

先懂直觉

HumanEval 这类代码题:模型可能一次写错,但多采样几次有几率写对。pass@k = 采样 k 次里至少有一次通过的概率。

无偏估计(采 n 个样本、c 个通过):

pass@k=1−(n−ck)(nk)\text{pass@}k = 1 - \frac{\binom{n-c}{k}}{\binom{n}{k}}

直觉读法:从 n 个样本里随机抽 k 个,至少有一个通过测试的概率。k=1 时就是「单个样本的通过率」;k 增大时这个概率上升,但只有当 k = n 且 c > 0 时,pass@n 才等于 1——不是「只要样本里有对的,所有 pass@k 都是 100%」。所以报告必须写清 k、n 与采样温度。

🎮 交互:n / c / k 计算器交互演示 · 静态阅读版

拖动采样数 n、通过数 c、k,实时看 pass@k 的变化,理解「k 越大越乐观」。

在交互版中打开这个演示 →

23.7 数学评测:GSM8K / MATH

先懂直觉

数学题要求「解出答案」,但模型输出的是整段推理解答——不能拿整段做 EM。标准做法是抽取最终答案再比对。

做法 说明
抽取 \boxed{} 或 #### 42 格式 多数模型被训练输出固定格式
数值规范化 42 / 42.0 / $42 视为相同
只判最终答案 CoT 过程不计分(unless process reward)
⚠️ 常见的数学评测陷阱
  • 格式依赖:模型答案对但格式不对 → 被误判为错(parser 问题,不是能力问题);
  • 答案泄漏:训练集含原题(contamination)→ 分数虚高(见 23.13);
  • 用 exact match 比整段 CoT → 几乎所有模型都是 0 分。

23.8 Instruction Following:另一类能力

先懂直觉

有些评测不考「知识」,而考「听不听指令」:例如 IFEval 的「回答必须三句话、每句以 A 开头」。这类任务的分数与事实正确性无关。

指令:"列出三个水果,每条以数字开头,且不出现苹果二字。"
→ 检查:格式约束是否全部满足(可程序化验证)

意义:instruction following 反映「可用性」——一个知识很全但不听指令的模型,工程上很难用。

23.9 LLM-as-a-Judge:开放式回答怎么评

先懂直觉

开放式回答没有唯一 ground truth(「写一首关于秋天的诗」)。所以用强模型当裁判:给回答打 helpfulness / correctness / style 等维度分。

已知偏差 表现 缓解
位置偏差 偏爱 A 或 B 位置 交换顺序评两次
长度/啰嗦偏差 偏爱更长的回答 长度控制/对照实验
自我偏好 偏爱同族模型的输出 换不同裁判模型
提示敏感 rubric 措辞改变结论 固定并公开 rubric
🎮 交互:位置偏差演示交互演示 · 静态阅读版

同一对回答,「A 在前」与「B 在前」各评一次——点「交换顺序」看裁判结论是否会翻转。

在交互版中打开这个演示 →

23.10 Pairwise Evaluation:A vs B 比绝对分更稳

先懂直觉

让裁判打 1~10 分:不同裁判的标准不一致。改成「A 和 B 哪个更好」:相对判断往往更稳定、更适合比较模型。

绝对打分 Pairwise
输出 7 分 A 胜
稳定性 差(量表漂移) 好
聚合 平均分 胜率(可做 Elo/BT)
风险 分数不可比 平局处理、位置偏差

这与第 22 章的偏好数据一脉相承:相对比较是 RLHF/DPO 偏好数据的基础形式。

23.11 Human Evaluation:什么时候必须用人

先懂直觉

Benchmark 和裁判模型都有盲区。关键决策(上线、安全)依然需要人类评估——但要做得「可复现」。

原则 做法
盲评 不告诉评估者哪个是哪个模型
随机化 顺序随机(对应位置偏差)
规则明确 rubric 写清楚评分标准
一致性 多人标注时报告 inter-annotator agreement(一致性)

23.12 Prompt Sensitivity:同一模型,分数会飘

先懂直觉

同一模型同一题:few-shot 示例换一换、指令措辞换一换、选项顺序换一换——分数可能明显变化。所以评估必须固定模板,并报告模板。

Prompt A: "请选择正确答案:"      → 65%
Prompt B: "Answer with the letter." → 58%
Prompt C: 5-shot 示例             → 71%

报告分数时不写 prompt 模板 = 无法复现 = 无法比较。

23.13 Contamination:与数据管线闭环

先懂直觉

如果评测集的题目(甚至答案)出现在预训练数据里,模型可能「背过」,分数虚高。这在第 18 章叫 benchmark decontamination——数据管线的第 ⑧ 站。

Benchmark sample → normalize → n-gram / MinHash 匹配
  → 命中:从训练数据中移除该文档
症状 可能原因
小模型在某 benchmark 分数异常高 疑似污染(或题目泄漏进训练集)
benchmark 与训练语料高度重合 去污染流程缺失

把本章和第 18 章连起来看:评测有效性是数据工程的职责之一。

23.14 置信区间:别只看一个数

先懂直觉

「准确率 70%」在 n=20 和 n=10000 时的可信度完全不同。样本越少,随机波动越大,需要报告置信区间。

🧮 标准误(二项分布)
SE=p(1−p)n\text{SE} = \sqrt{\frac{p(1-p)}{n}}

95% 置信区间近似:p±1.96×SEp \pm 1.96 \times \text{SE}。

算例:p=0.70

  • n=20:SE = √(0.7×0.3/20) ≈ 0.102 → 区间 ≈ [0.50, 0.90](±20pt!)
  • n=1000:SE ≈ 0.0145 → 区间 ≈ [0.67, 0.73](±3pt)
🎮 交互:样本量与置信区间交互演示 · 静态阅读版

拖动样本量滑块,观察同一分数下 95% 置信区间如何收窄——小样本的「提升」可能只是噪声。

在交互版中打开这个演示 →

⚠️ 这个公式的边界(Wald 近似)

p±1.96p(1−p)/np \pm 1.96\sqrt{p(1-p)/n}
是 normal / Wald 近似,适合建立直觉,但在以下情况表现较差:n 很小、p 接近 0、p 接近 1。更严谨的二项比例区间可用:

  • Wilson interval(小样本更稳);
  • exact binomial interval(Clopper-Pearson 等);
  • 模型比较场景常用 paired bootstrap / paired tests(配对检验)。

本章只需掌握:「分数必须和样本量、不确定性一起看」。统计检验的完整方法属于后续专题。

23.15 Statistical Significance:72.0% vs 72.3%

先懂直觉

两个模型分差 0.3 个百分点,可能完全在噪声范围内。判断「谁真的更好」需要显著性检验(如配对 bootstrap / 二项检验),且要说明检验方法与样本量。

不要 要
「B 比 A 高 0.3%,所以 B 更好」 「B − A = 0.3pt,n=1000 时 95% CI 含 0 → 无显著差异」

23.16 Evaluation Harness:为什么要统一

先懂直觉

不同论文的分数常常不可比:prompt 不同、few-shot 数不同、parser 不同、采样参数不同。Harness(如 lm-evaluation-harness 类工具)把 dataset / prompt / generation / parser / metric 全部固定成标准流程。

本课程不教安装;要记住的是:看到任何分数,先问「用什么 harness、什么模板、什么 parser」。

23.17 Failure Case Analysis:分数之外

先懂直觉

一个数字不能告诉你模型「哪里不会」。工程上必须做失败样本分类,才能指导下一步数据/训练方向。

失败类型 例子 对应改进
事实错误 张冠李戴 数据质量/知识更新
推理错误 步骤对、结论错 推理数据 / RLVR
格式问题 答案对但解析不出 指令微调 / 格式规范
指令不遵循 少给了一条 IF 数据
语言混杂 中文问题英文答 语言配比
长上下文失败 长文档里找不到答案 上下文扩展 / 检索
工程里怎么用(失败样本记录模板)
{"task": "c3", "id": 152, "question": "……", "gold": "B", "pred": "D",
 "failure_type": "reasoning_error", "note": "定位到关键句但推理方向反了"}
{"task": "ppl_eval", "id": "doc-88", "loss": 6.8, "failure_type": "long_context",
 "note": "跨 2k token 的指代没有连上"}

23.18 Mini Evaluation Lab:给 Small LLM 做一次评测

目标

用你在第 13 章亲手训练的 TinyLM,跑一次两种指标的评测:困惑度 + 选择题准确率,并输出结构化结果。本节代码已实际运行验证。

# 类型:【Runnable】依赖:torch(+ 你的 TinyLM 定义与 tokenizer)
import json, math, torch
import torch.nn.functional as F

def evaluate_ppl(model, dataset, device="cpu"):
    """困惑度:e^平均交叉熵(注意:只能和同 tokenizer 比较)"""
    model.eval()
    losses = []
    with torch.no_grad():
        for x, y in dataset:
            logits = model(x[None].to(device))
            loss = F.cross_entropy(logits.view(-1, logits.size(-1)), y[None].to(device).view(-1))
            losses.append(loss.item())
    mean = sum(losses) / len(losses)
    return {"loss": mean, "ppl": math.exp(mean)}

def evaluate_mcq(model, items, device="cpu"):
    """选择题:比较各选项 continuation 的平均 log 概率,取最高"""
    model.eval()
    correct = 0
    log = []
    with torch.no_grad():
        for it in items:
            scores = {}
            for opt, text in it["options"].items():
                ids = torch.tensor(it["prompt_ids"] + text["ids"])
                logp = F.log_softmax(model(ids[None].to(device))[0], dim=-1)
                start = len(it["prompt_ids"])
                s = sum(logp[i - 1, ids[i]].item() for i in range(start, len(ids)))
                scores[opt] = s / max(1, len(ids) - start)     # 长度归一
            pred = max(scores, key=scores.get)
            ok = pred == it["answer"]
            correct += ok
            log.append({"id": it["id"], "gold": it["answer"], "pred": pred, "ok": ok})
    acc = correct / max(1, len(items))
    return {"accuracy": acc, "n": len(items), "random_baseline": 0.25, "log": log}

# —— 用本项目小模型的真实结果演示输出格式(数字来自实际评测)——
if __name__ == "__main__":
    results = {
        "c3":    {"accuracy": 0.40, "random_baseline": 0.25, "note": "中文阅读理解(4选1)"},
        "xcopa": {"accuracy": 0.55, "random_baseline": 0.50, "note": "因果常识(2选1)"},
    }
    with open("results.json", "w") as f:
        json.dump(results, f, ensure_ascii=False, indent=2)
    print(json.dumps(results, ensure_ascii=False, indent=2))

验收:输出 results.json:

{
  "c3":    { "accuracy": 0.40, "random_baseline": 0.25, "note": "中文阅读理解(4选1)" },
  "xcopa": { "accuracy": 0.55, "random_baseline": 0.50, "note": "因果常识(2选1)" }
}

这些数字来自本项目 Small LLM 的真实评测(非课程虚构、也非 SOTA)。报告时必须写清:任务、随机基线、样本量、prompt 模板、parser——否则无法复现。

🔑 本章必须记住
概念 一句话
Eval Pipeline Model→Dataset→Template→Generation→Parser→Metric,任一环失真
PPL e^Loss;不能跨 tokenizer 比;低 PPL ≠ 好对话
EM / F1 parser 决定分数;QA 常用 token 级 F1
选择题 必须对照随机基线(25% / 50%)
pass@k 1 − C(n−c,k)/C(n,k);k 越大越乐观
Judge 位置/长度/自我偏好偏差,需交换顺序与固定 rubric
Pairwise 比绝对打分更稳;偏好数据的基础
置信区间 SE=√(p(1−p)/n);小样本的分数波动巨大
Contamination 与数据管线闭环:去污染保障评测有效性
Harness 固定流程才有可比分数;报告要带模板与 parser
📝 小测验
某模型在 C3(4 选 1)上 40%、XCOPA(2 选 1)上 55%。以下哪种读法最严谨?
AC3 相对基线高出 15pt、XCOPA 高出 5pt——这是描述性对比,是否显著还需样本量与置信区间
BXCOPA 更好,因为 55% > 40%
C两个分数都不能解读
DC3 是过拟合
显示答案与解析

正确答案:A

必须对照随机基线读(C3 +15pt、XCOPA +5pt),且这属于描述性结果——没有样本量与置信区间时不能下显著性结论。B 错在跨任务比较绝对分数;C、D 无依据。
📝 小测验
关于 pass@k,说法正确的是?
A和 pass@1 一样
Bk 越大分数越乐观:只要 k 次采样中有一次通过就算通过
C不需要采样,直接算
D只能用于数学题
显示答案与解析

正确答案:B

pass@k 衡量「采样 k 次至少一次通过」的概率,常用无偏估计 1 − C(n−c,k)/C(n,k)。k 越大数字越乐观,报告必须写清 k、n 与采样温度。
📝 小测验
为什么「70% 准确率」在 n=20 与 n=1000 时意义不同?
A没有不同
Bn=20 时 95% 置信区间约 [50%, 90%],随机波动极大;n=1000 时区间约 [67%, 73%]
Cn 越大分数越低
D只与模型大小有关
显示答案与解析

正确答案:B

二项分布标准误 SE=√(p(1−p)/n) 随样本量减小而增大。小样本下所谓「提升」可能完全在噪声范围内——报告分数必须带样本量与置信区间。
← 强化学习与偏好优化:PPO 与 GRPO🏠 回到交互版首页岗位查阅:能力矩阵与四级标准 →
本章完。原始 Markdown:content/23-llm-eval.md