--- type: reference tags: - llm-evaluation - evaluation-guidebook - troubleshooting status: active created: 2026-08-21 source: https://github.com/huggingface/evaluation-guidebook --- # Troubleshooting(排错) > 本页提炼自 [HuggingFace LLM Evaluation Guidebook](https://github.com/huggingface/evaluation-guidebook) 的 **Troubleshooting** 章节(共三小节:推理排错、LaTeX 数学解析、可复现性排错)。这是整本指南中最实操的部分——当评测跑不起来、跑得慢、分数对不上时,先查这里。文内 ⭐ 标记为作者特别推荐的资源。 ## 本节速览(TL;DR) | 症状 / 诉求 | 第一反应 | 详见 | |---|---|---| | 评测跑得太慢 | 增大 batch size → 数据并行 → 换推理库 → 降精度 | §1.1 | | 模型太大放不进 GPU | 量化 → 模型并行(pipeline / tensor)→ CPU offloading | §1.2 | | 装得下却 OOM | 怀疑 context size,用 dummy 数据测试 | §1.3 | | 数学评测分数异常偏低 | 检查 LaTeX 解析器(sympy 自洽只有 0.94) | §2 | | 复现不出论文分数 | 逐项对齐:代码库 / seed / 指标 / normalization / prompt / 生成参数 / 加载方式 | §3 | > 贯穿全章的三条核心心法:**① 评测工具链本身也是被测对象**——解析器、normalization、指标实现都会系统性改变分数;**② 评测不只是"模型回答问题",而是"在特定环境里跑特定管道"**——环境细节决定一切;**③ 想对比两个分数,先确认它们是不是用同一套管道算出来的。** ## 1 推理排错(Troubleshooting Inference) 评测中跑模型推理会遇到三类典型问题:**慢**、**大**(内存装不下)、以及**装得下却 OOM**。本节逐一给出排查思路。先给一张按症状定位的速查表: | 症状 | 直接原因 | 对策 | 代价 / 注意 | |---|---|---|---| | 推理慢 | batch size 太小 | 增大 batch size | 破坏绝对可复现性 | | 推理慢 | 只用了单张 GPU | 数据并行(多 GPU) | 需同节点,避免节点间瓶颈 | | 推理慢 | 推理库实现不够优化 | 换更快推理库 / 参考优化清单 | 需要实测 | | 推理慢 | 精度过高 | 降到 `bfloat16`/`float16`,或 8bit/4bit 量化 | 精度损失,部分量化库本身偏慢 | | 模型太大 | 精度过高 | 量化 | 中规模模型建议停在 `float16`/8bit | | 模型太大 | 单卡放不下 | 模型并行 / CPU offloading | 并行较难编码;offloading 显著更慢 | | 装得下却 OOM | context size 过大 | dummy 测试 + 降 batch + 逆序呈现样本 | 让失败尽早暴露 | ### 1.1 模型太慢怎么办 #### ① 修改 batch size - 如果你追求**绝对可复现**(给定特定硬件与特定评测 prompt),通常只能用 batch size = 1。 - 但只要内存放得下,**调大 batch size 几乎必然显著加速**评测——这是最简单的提速手段。 #### ② 数据并行(data parallelism) - 思路:把模型复制到多张 GPU 上(而不是只加载到一张卡),把数据切成子集分给每张卡的副本,各自计算后再**聚合结果**。 - 效果:多条数据流同时被处理,总执行时间约**除以 GPU 数量**。 - 注意:尽量让所有 GPU 在**同一个节点(node)**上,避免节点间通信成为瓶颈(inter-node bottleneck)。 #### ③ 更换推理代码 - 不是所有推理库速度都一样,有些实现优化得更好,需要针对你的用例**实测对比**。 - 如果使用 PyTorch,作者推荐参考 [PyTorch 模型推理性能优化清单](https://pytorch.org/serve/performance_checklist.html)。 #### ④ 降低精度(precision) - `float32` 每个数占 32 bit,计算精确但**内存与算力开销都大**。 - 降到 **`bfloat16` / `float16`(一半精度)**,速度约翻倍,精度损失几乎可以忽略。 - 想进一步提速可量化到 **8 bit 或 4 bit**(例如用 `gptq` 或 `bitsandbytes`),n-bit 矩阵计算更快、模型占内存更少。 - ⚠️ 某些量化库本身可能偏慢,需要针对你的场景实测。 > 贯穿 1.1 的原则:以上手段**不是二选一的单选题,而是可以叠加的组合拳**(如"大 batch + 数据并行 + `bfloat16`"),且**提速效果必须在你的硬件与任务上实测确认**——作者多次强调"test things out for your use cases"。 ### 1.2 模型太大(GPU 装不下)怎么办 #### 估算内存需求 用如下公式估算加载模型所需的**最小理论内存**: ``` = × ``` 原理:1 Byte = 8 bit,总内存 ≈ 参数量 × 每个参数占用的 Byte 数。precision factor 取值: | 精度 | precision factor | |---|---| | `float32` | 4 | | `float16` / `bfloat16` | 2 | | 8 bit 量化 | 1 | | 4 bit 量化 | 0.5 | 更稳妥的推荐公式(留出推理时的 batch 等额外开销): ``` = × ( × 110%) ``` > 示例估算(用推荐公式 `参数(G) × factor × 110%`,取 7B 与 70B 两个常见规模): | 模型规模 | `float32` | `float16`/`bfloat16` | 8 bit | 4 bit | |---|---|---|---|---| | 7B | 7×4×1.1 ≈ **30.8 GB** | 7×2×1.1 ≈ **15.4 GB** | 7×1×1.1 ≈ **7.7 GB** | 7×0.5×1.1 ≈ **3.9 GB** | | 70B | 70×4×1.1 ≈ **308 GB** | 70×2×1.1 ≈ **154 GB** | 70×1×1.1 ≈ **77 GB** | 70×0.5×1.1 ≈ **38.5 GB** | > 由此可快速判断硬件选型:单张 80GB 的 GPU 要跑 70B 模型,`float16`(154GB)不行,需要 8bit(77GB,一张卡勉强)或 4bit 量化 / 模型并行;而 7B 模型在 `float16` 下单张 16–24GB 的消费级卡即可胜任。 #### ① 量化(quantization) - 最直接的手段:调小上面的 precision factor。从 `float32` 到 **4 bit**,内存需求直接**缩小 8 倍**。 - ⚠️ 精度过低会损害评测结果。对**中规模模型**建议保守停在 `float16` 或 8 bit。 - 经验观察:量化对**超大模型**的性能影响反而较小(可能因为存在信息冗余)。 #### ② 模型并行(model parallelism) 把模型切成小块,分别加载/运行在不同的 GPU 上;因为从不一次性加载完整模型,所以省内存,但**可能更慢**。两种主要类型: | 类型 | 切分粒度 | 机制 | 代价 / 特点 | |---|---|---|---| | **Pipeline parallelism**(流水线并行) | 整层(layer)级别 | 按层分派到不同 GPU,层 1 输出是层 2 输入 | GPU 会空转等待,产生所谓 **"bubble"**;把输入拆成更小的 batch 可缓解 bubble;需要 GPU 间传输数据 | | **Tensor parallelism**(张量并行) | 矩阵计算级别 | 把矩阵按行/列切开,各 GPU 算完再聚合 | 只要 GPU 都在同一节点就**极其高效**(避免节点间网络瓶颈),但**难以编码** | - Pipeline parallelism 正被原生加入 PyTorch 的 [`PiPPy`](https://github.com/pytorch/PiPPy) 库,也是 `accelerate` 底层使用的并行方式。 - Tensor parallelism 在 `vllm` 库中有很好的实现,作者形容其带来 **"insane speedups"(惊人的加速)**。 - 各类并行(含用于提速的 data parallelism)的最佳参考文档:[Transformers 官方并行文档](https://huggingface.co/docs/transformers/v4.15.0/en/parallelism)。 #### ③ CPU offloading - 把部分计算和模型参数挪到 CPU,以降低 GPU 显存占用。 - ⚠️ **比上面任何方法都慢得多**——因为要持续在设备之间搬运数据。 - 典型实现:DeepSpeed 的 [ZeRO-Offload](https://arxiv.org/abs/2101.06840)(在 ZeRO-2 优化之上):优化阶段的梯度、optimizer states、fp32 参数计算放 CPU;GPU 上保留 fp16 参数与前向/反向传播,以"用 CPU 内存 + GPU 算力、最小化通信"为设计目标。 ### 1.3 模型装得下,但还是 OOM 大概率是 **context size(上下文长度)** 的问题——显存峰值往往由"batch size × 序列长度"决定,模型权重本身反而放得下。作者建议: 1. **先用虚拟推理数据(dummy inference data)测试**模型是否真的放得下;虚拟数据要使用**足够大、能代表你任务**的 context size。 2. **降低 batch size**;如果你开了 auto-batch size search(自动搜索 batch size),考虑关掉——它可能导致意外的 OOM。 3. 一般性原则:**让样本按 context size 逆序(从大到小)呈现**给模型——这样如果 context 太大,会**一开始就立刻失败**,而不是跑了几小时后才崩。 ## 2 数学能力评测中的 LaTeX 解析问题(MATH & sympy) > 📌 **新版(2025 Space)更新**:新版指南把 LaTeX 解析问题并入「Designing your automatic evaluation」的 *Normalization* 小节,并推荐使用专门的数学解析库 **Math-Verify**(替代 sympy 手工解析/字符串比较,见 [[08-2025-Edition]] §5)。下方记录的是旧版(sympy)的探索过程与教训,仍有参考价值。 ### 2.1 问题背景 - 解析 LaTeX **非常困难**。当评测任务期望模型输出 LaTeX 时(典型如 [MATH benchmark](https://huggingface.co/datasets/lighteval/MATH),它用 LaTeX 表示数学计算与符号),问题就来了。 - 评测这类任务本应只是"解析并比较 ground truth 与模型输出",但**实际上不存在"正确"的 LaTeX 解析方式**(sympy 文档自己也这么说)。 ### 2.2 sympy 的局限:0.94 的自洽准确率 - `lm-evaluation-harness` 使用 **`sympy`**(Python 符号数学库)解析 LaTeX 并比较表达式。 - 残酷的事实:**即使用 ground truth 去解析 ground truth 本身**(自己和自己比),`sympy` 也只有约 **0.94 的准确率**。 - 原因:`sympy` 无法解析一部分**本身正确**的 LaTeX 表达式。 - 这个"用 ground truth 自比"的测试本质是一个**解析器健全性检查(round-trip test)**:它排除了模型因素,单独测量解析管道的上限。0.94 意味着即使模型 100% 输出正确答案,评测系统也会因解析失败丢掉约 6% 的分数——解析器成了评测误差的主要来源之一。 ### 2.3 典型报错示例 以下三个示例中,`sympy` 都因语法问题拒绝了正确的 LaTeX: **例 1:半开区间 `[0,1)`(interval)** ``` couldn't parse one of [0,1) or [0,1), I expected one of these: ']' [0,1) ~~^ ``` **例 2:并集 `\cup` 与无穷 `\infty`(此处写作 `\iny`)** ``` couldn't parse one of (-\iny,-5]\cup[5,\iny) or (-\iny,-5]\cup[5,\iny), I expected something else here (-\iny,-5]\cup[5,\iny) ~~~~~~^ ``` **例 3:分数中的空分组 `\frac{1}{{}2x}`** ``` couldn't parse one of -\frac{1}{{}2x} or -\frac{1}{{}2x}, I don't understand this -\frac{1}{{}2x} ~~~~~~~~~~~^ ``` > 小结:把上述失败归纳成三类典型盲区—— | 失败类别 | 报错示例 | 原因 | |---|---|---| | 区间表示(interval) | `[0,1)` | 半开区间 `[`/`)` 混用,sympy 期待 `]` 之类的闭合符号 | | 集合运算与特殊符号 | `(-\iny,-5]\cup[5,\iny)` | `\cup`(并集)等集合运算符、`\infty`(示例中写作 `\iny`)不被支持 | | 多余分组 | `-\frac{1}{{}2x}` | 分子/分母里的空分组 `{}` 导致语法不识别 | 三类都是**合法、正确的 LaTeX**,却会被解析器拒绝——这正是"解析器不是标准答案"的实证。 ### 2.4 怎么绕过 两条路: 1. **重写 LaTeX grammar**:向 [`sympy` 的 LaTeX 语法文件 `latex.lark`](https://github.com/sympy/sympy/blob/master/sympy/parsing/latex/lark/grammar/latex.lark) 添加所需特性(为解析器增加新规则)。 2. **在代码里加手动检查**:为模型输出增加字符串比较等后处理兜底。 作者的选择:在几乎掉进"重写 grammar"这个深坑之后,**决定只给代码加上字符串比较(string comparison)检查**就足够了——即对 `lm-evaluation-harness` 打一个修复补丁(见原文附图中的 LM Eval Harness fix)。 > 为什么选"字符串比较"而不是"重写 grammar"?重写 parser grammar 是个无底洞:LaTeX 语法变体无穷无尽(区间、集合、特殊符号、各种分组写法),每补一个规则都可能引入新冲突,维护成本高。而字符串比较实现简单、可立刻生效——解析失败时退而求其次做规范化后的字符串比对,足以覆盖评测场景中大多数"模型其实答对了"的情况。**对评测工程而言,够用、可维护,比理论上完美更重要。** ### 2.5 修复效果:MATH 上旧/新解析器对比 修复后对 MATH benchmark 前 25 个模型的分数(原始解析器 vs 修复后解析器)对比如下(分数列为 0–100;"提升"为两列差值): | 模型 | 原始 | 修复后 | 提升 | 排名变化 | |---|---|---|---|---| | rombodawg/Rombos-LLM-V2.5-Qwen-72b | 47.58 | 50.68 | +3.10 | 1 → 1 | | MaziyarPanahi/calme-2.2-qwen2-72b | 41.16 | 43.43 | +2.27 | 2 → 2 | | arcee-ai/Arcee-Nova | 40.48 | 42.90 | +2.42 | 3 → 3 | | fblgit/TheBeagle-v2beta-32B-MGS | 39.43 | 42.52 | +3.09 | 4 → 4 | | rombodawg/Rombos-LLM-V2.5-Qwen-32b | 39.12 | 41.99 | +2.87 | 5 → 5 | | dnhkng/RYS-XLarge | 38.97 | 41.24 | +2.27 | 6 → 6 | | dfurman/CalmeRys-78B-Orpo-v0.1 | 37.92 | 40.71 | +2.79 | 8 → 7 | | MaziyarPanahi/calme-2.2-rys-78b | 37.92 | 39.95 | +2.03 | 8 → 9 | | MaziyarPanahi/calme-2.4-rys-78b | 37.69 | 40.41 | +2.72 | 9 → 8 | | MaziyarPanahi/calme-2.3-rys-78b | 36.56 | 38.97 | +2.41 | 10 → 10 | | MaziyarPanahi/calme-2.1-rys-78b | 36.40 | 38.90 | +2.50 | 11 → 11 | | Qwen/Qwen2.5-72B | 36.10 | 38.67 | +2.57 | 12 → 12 | | MaziyarPanahi/calme-2.1-qwen2-72b | 36.03 | 38.07 | +2.04 | 13 → 15 | | Qwen/Qwen2-Math-72B-Instruct | 35.95 | 38.14 | +2.19 | 14 → 14 | | dfurman/Qwen2-72B-Orpo-v0.1 | 35.42 | 38.14 | +2.72 | 15 → 13 | | abacusai/Smaug-Qwen2-72B-Instruct | 35.35 | 37.46 | +2.11 | 16 → 19 | | anthracite-org/magnum-v1-72b | 35.27 | 37.69 | +2.42 | 18 → 16 | | alpindale/magnum-72b-v1 | 35.27 | 37.69 | +2.42 | 18 → 16 | | Qwen/Qwen2-72B-Instruct | 35.12 | 37.69 | +2.57 | 19 → 18 | | dnhkng/RYS-XLarge-base | 34.67 | 37.16 | +2.49 | 20 → 20 | | Undi95/MG-FinalMix-72B | 33.61 | 36.10 | +2.49 | 22 → 21 | | abacusai/Dracarys-72B-Instruct | 33.61 | 35.65 | +2.04 | 22 → 22 | | Qwen/Qwen2.5-32B | 32.85 | 35.50 | +2.65 | 23 → 23 | | anthracite-org/magnum-v2-72b | 31.65 | 34.06 | +2.41 | 24 → 24 | | dnhkng/RYS-Huge-bnb-4bit | 31.57 | 33.84 | +2.27 | 25 → 25 | **关键观察**: - 所有模型的分数都提升了约 **2–3 分**(最低 +2.03,最高 +3.10)——这个量级的差距足以改变一个模型的"好不好"结论,说明解析器(而非模型)曾经拖累了大量分数。 - 排名大体稳定,但个别模型有 ±1~3 位的变化(如 Smaug-Qwen2-72B-Instruct 从 16 掉到 19,Qwen2-72B-Orpo-v0.1 从 15 升到 13)——若按排名做基准对比,解析差异会**改变排行榜序**。 **为什么分数整体平移、排名却会变?** 解析器对每个模型的"扣分"并不均匀:模型 A 输出的 LaTeX 恰好多是 sympy 的盲区(区间、集合、多余分组),被多扣;模型 B 的输出风格恰好全被解析,少扣。所以修复解析器后,**被多扣的模型分数抬升更多**,相对位置就动了。结论:解析器不只是"对所有人一视同仁的常量误差",它还可能掩盖模型之间的真实差距。 > 引申教训:评测指标管道(metric pipeline)本身也是被测对象的一部分。解析器、normalization、后处理的实现差异会系统性抬高/压低某些模型的分数。 ## 3 可复现性排错(Troubleshooting Reproducibility) 场景:你读了某篇最新技术报告,想在本地复现它的分数,却**复现不出来**?以下是作者拆解的原因清单。 ### 3.1 不同的代码库(code base) - 要复现到小数点,第一步是**使用与论文完全相同的代码库**。 - 通常意味着:用**作者提供的评测默认代码**,或用参考库中的标准实现——如 Eleuther AI 的 `lm_eval`、HuggingFace 的 `lighteval`。这两个库是社区事实上的"标准管道":`lm_eval`(EleutherAI)是使用最广的评测框架,`lighteval`(HuggingFace)由 Open LLM Leaderboard 团队维护——用它们,等于和其他人共用同一套任务定义与指标实现,这是复现的前提。 - 如果论文**没提供评测代码**:几乎不可能精确复现,只能放弃精确比对。 - ⭐ 想直观理解不同实现带来的差异,读作者团队写的这篇博客:[MMLU 在不同评测实现下的差异](https://huggingface.co/blog/open-llm-leaderboard-mmlu)——它研究了 MMLU 在 `lm_eval`、`helm` 与原始作者实现三种版本下的分数差异。 - 背景:正因为如此,HuggingFace 团队才发起 [Open LLM Leaderboard](https://huggingface.co/spaces/open-llm-leaderboard/open_llm_leaderboard),用统一、同质的评测来做模型间的横向比较。 ### 3.2 同一代码库内也容易踩的坑 即使代码库相同,以下细节也容易出错: #### ① 不同的随机种子(random seed) - 推理受 seed 影响通常比训练小,但仍可能影响: - 部分 **CUDA 操作**(参考 [PyTorch 可复现性文档](https://pytorch.org/docs/stable/notes/randomness.html)); - **非 greedy 生成策略**下的预测结果; - 使用 few-shot 时的 **prompt 内容**(抽样选出哪些示例); - 某些**前处理 / 后处理函数**。 - 一个小 seed 差异就可能带来**几分之差**。 #### ② 同名但实际不同的指标(metric) 指标名相同 ≠ 计算方式相同,例如: - **log likelihood 版 `exact match`**(计算不同候选答案的对数概率) vs **生成式 `exact match`**(只把 greedy 生成与参考答案比较)——两者分数完全不同。 - 代码库里不少任务名叫 `exact match`,实际却是: - **`prefix exact match`**(只比生成的开头与参考); - **`suffix exact match`**(反过来,只比结尾); - **`quasi exact match`**(带 normalization 的 exact match)。 - **结论:不能只靠指标名判断评测做了什么,必须看代码。** #### ③ 不同的 normalization - 回到上面生成式 `exact match` 的例子:`lm_eval` v1 中不少任务只叫 generative `exact match`,你会以为预测是"原样与参考比较";但看代码会发现预测**先经过 normalization**(去标点、数字同质化等)再比较——这会**大幅改变结果**。 - `lm_eval` **v2 已把 normalization 的名字写进大多数指标名**。 - 这是最容易被搞砸的点,尤其对**需要大量 normalization / 答案后处理的任务**,比如数学评测(需要从模型生成的解释里**抽取最终答案**再比较)。 ### 3.3 不同的 prompt prompt 变化有三个来源。 #### ① prompt 本身(格式) prompt 格式对分数的影响**巨大**。以多选题为例,仅呈现选项的格式就有多种"语义等价"的变体: ```text Question: Choices: ``` ```markdown | A. | (A) | | | B. | (B) | | | C. | (C) | | | D. | (D) | | ``` ```text Answer: ``` 并要求模型预测 `A`/`B`/`C`/`D`,或直接输出 `` 的完整文本。 - 这些 prompt **语义等价**(内容完全相同),但对同一模型仍可能差**好几分**: - 作者团队实验([原帖](https://x.com/clefourrier/status/1777319187913875893/photo/1))观察到同一模型**最高差 7 分**; - [相关论文](https://arxiv.org/abs/2310.11324)也观察到了类似结果。 - 有些任务还会带**任务前缀 prompt**(如 `The following questions are about `),其有无也会影响分数。 - ⭐ [这篇论文](https://arxiv.org/abs/2407.07890)还揭示一个副作用:**不少模型被训练成"过拟合基准的 prompt 与答案格式"**,代价是在评测时对其他 prompt 的适应能力下降。 - 实例(Open LLM Leaderboard 2 上的 Llama3.1):这些模型在 MATH-Hard 评测中**能预测出正确答案,分数却很低**——因为它们过拟合了 GSM8K(另一个数学评测)的 prompt 与答案格式,无法适配 few-shot 中提供的模板。 #### ② system prompt 与 chat template - Chat 模型通常经过指令/偏好训练(instruction/preference training 或 fine-tuning),这个阶段它们学会了**遵循特定模板**推理。 - 常见模板要素: - 每轮对话以**system prompt** 开头(通常以特定 token 前缀,如 `System: `),用于给模型高层指令(人设、回答风格等); - 对话轮次给文本加**前缀关键词**,如 `User`(提问)与 `Assistant`(回答)。 - 使用 few-shot 时还要决定:示例**按多轮(multi-turn,模拟 user/assistant 轮次)提供**,还是**一次性放在单条 user prompt 里**。 - ⚠️ **不遵循模型期望的 chat template,会严重损害性能**——因为它把模型输出推向其已收敛的概率空间之外。 #### ③ few-shot 样本 - 显然要用**与参考任务相同的 few-shot 数量**。 - 还要用**完全相同的样本**——不同样本会改变结果(这不太意外:有些样本更能表达任务)。 - 更反直觉的一点:**样本完全相同还不够,顺序也必须完全相同**。作者团队观察到:同样的样本仅改变顺序,在 **MMLU 的某些子集上最多差 3 分**([结果见这里](https://huggingface.co/blog/evaluation-structured-outputs),第三个 colorgrid)。 - 因此这里同样要**注意随机种子**。 ### 3.4 不同的生成参数(generation parameters) 对生成式评测,需要对齐: - 使用**相同的 end of sentence token(EOS token)**; - 允许模型**生成相同数量的 token**; - 如果使用 sampling,确保**相同的 seed / temperature 参数**。 ### 3.5 不同的模型加载(model loading) 已观察到的差异来源: | 来源 | 说明 | |---|---| | **不同硬件** | PyTorch **不保证**非确定性操作在不同硬件上可复现 | | **不同推理库** | 例如用 `transformers` 还是 `vllm` 作为推理后端,矩阵计算的实现方式并不完全相同 | | **不同 batch size** | 多个评测库与模型后端都有文档记录:**batch size 不同会改变推理结果**;要完全可复现就固定 batch size(虽然内存受限时不一定总能做到) | | **不同加载精度** | 用更低精度加载权重可省内存与推理成本,但用的是不同版本的权重,**数值结果必然改变** | > 排查复现问题时的总思路:**从"最可能、最容易改"的项开始逐项对齐**——先核对 prompt 与 few-shot(改动最频繁、影响最直接),再查指标与 normalization(需要看代码确认),最后核对生成参数与加载方式(涉及硬件环境)。每锁定一项就重跑一次对比,通常很快能找到分差来源。 ### 3.6 可复现性检查清单(速查) 综合 3.1–3.5,复现一份评测分数前逐项核对(任一项不满足,分数就可能对不上): - [ ] 使用与参考完全相同的**代码库/评测框架**(`lm_eval` / `lighteval` / 作者实现) - [ ] 相同**随机种子**(尤其非 greedy 生成、few-shot 抽样) - [ ] 相同的**指标定义**(log-likelihood vs generative、prefix/suffix/quasi exact match,看代码确认) - [ ] 相同的 **normalization / 后处理**(数学评测尤其注意答案抽取) - [ ] 相同的 **prompt 格式、system prompt、chat template**(多轮 vs 单次 few-shot) - [ ] 相同的 **few-shot 数量、样本与顺序** - [ ] 相同的**生成参数**(EOS token、max tokens、seed / temperature) - [ ] 相同的**硬件、推理库、batch size、加载精度** ## 核心要点(一句话版) 1. **提速四杠杆**(按性价比排序):调大 batch size → 数据并行 → 换更快推理库 → 降精度(`bfloat16`/`float16` → 8bit/4bit 量化)。 2. **内存估算**:`memory(GB) = 参数(G) × precision factor × 110%`;factor 为 `float32`=4、`float16`/`bfloat16`=2、8bit=1、4bit=0.5。 3. **放不下时**:先量化(最多省 8 倍内存),再模型并行(pipeline 慢在 bubble、tensor 慢在难编码但同节点极快),CPU offloading 是最后手段(显著更慢)。 4. **装得下却 OOM**:八成是 context size 问题——用大 context 的 dummy 数据先测、降 batch、样本按 context 逆序呈现让失败提前暴露。 5. **数学评测的 LaTeX 解析没有标准答案**:`lm-evaluation-harness` 用的 `sympy` 连 ground truth 自比都只有约 0.94 准确率;别去重写 grammar,加字符串比较兜底就够(修复后 25 个模型 MATH 分数全部 +2~3 分)。 6. **复现不出分数 = 某个环境细节没对齐**:代码库、随机种子、指标真实定义(prefix/suffix/quasi exact match)、normalization、prompt 格式与 chat template、few-shot 的数量/样本/顺序(顺序变化最多差 3 分)、生成参数(EOS、max tokens、seed/temperature)、硬件/推理库/batch size/加载精度——每一项都可能差几分。 7. **最容易被低估的两处**:① 同名指标的实现差异(必须看代码,别信名字);② prompt 格式的微小变化——语义等价也能差 7 分,还有模型专门过拟合基准 prompt 格式,换格式分数暴跌。 8. **工具取向**:优先使用维护中的标准框架(`lm_eval` v2、`lighteval`),因为它们把 normalization 等细节暴露在指标名里,减少"实现悄悄不同"的踩坑概率;升级框架版本时,也要顺手核对指标定义是否变化。 ## 参考资料 ### 原文(GitHub 仓库) - [Troubleshooting inference(推理排错)](https://github.com/huggingface/evaluation-guidebook/blob/main/contents/troubleshooting/troubleshooting-inference.md) - [Using LaTeX to evaluate MATH capabilities(LaTeX 解析)](https://github.com/huggingface/evaluation-guidebook/blob/main/contents/troubleshooting/troubleshooting-math-parsing.md) - [Troubleshooting reproducibility(可复现性排错)](https://github.com/huggingface/evaluation-guidebook/blob/main/contents/troubleshooting/troubleshooting-reproducibility.md) - 仓库主页:[huggingface/evaluation-guidebook](https://github.com/huggingface/evaluation-guidebook) ### 文中引用的外部链接 - [PyTorch 模型推理性能优化清单](https://pytorch.org/serve/performance_checklist.html) - [PyTorch PiPPy(pipeline parallelism)](https://github.com/pytorch/PiPPy) - [Transformers 并行化文档(data / pipeline / tensor parallelism)](https://huggingface.co/docs/transformers/v4.15.0/en/parallelism) - [ZeRO-Offload 论文(arXiv:2101.06840)](https://arxiv.org/abs/2101.06840) - [MATH benchmark(lighteval/MATH)](https://huggingface.co/datasets/lighteval/MATH) - [sympy(符号数学库)](https://github.com/sympy/sympy) - [sympy 的 LaTeX grammar(latex.lark)](https://github.com/sympy/sympy/blob/master/sympy/parsing/latex/lark/grammar/latex.lark) - ⭐ [MMLU 在不同评测实现下的差异(HF 博客)](https://huggingface.co/blog/open-llm-leaderboard-mmlu) - [Open LLM Leaderboard](https://huggingface.co/spaces/open-llm-leaderboard/open_llm_leaderboard) - [PyTorch 可复现性文档](https://pytorch.org/docs/stable/notes/randomness.html) - [prompt 格式对分数影响的实验(X 原帖,最高差 7 分)](https://x.com/clefourrier/status/1777319187913875893/photo/1) - [Few-shot prompt 变化的影响(论文 arXiv:2310.11324)](https://arxiv.org/abs/2310.11324) - ⭐ [模型过拟合基准 prompt 格式(论文 arXiv:2407.07890)](https://arxiv.org/abs/2407.07890) - [few-shot 顺序对 MMLU 子集分数的影响(HF 博客)](https://huggingface.co/blog/evaluation-structured-outputs)