AB
AiBoss站
教程

CMMLU

教程

用 CMMLU 评测脚本给中文大模型跑 67 科选择题基准

CMMLU 是一套覆盖 67 个学科、约 1.1 万道中文选择题的评测集。本文说明如何准备数据、配置参数并运行评测脚本,以及如何读懂 submission.json 与 summary.json 里的分科、分类与总分结果。

CMMLU 是一套面向中文能力评测的选择题基准集,测试集包含约 1.1 万道多项选择题,覆盖 67 个学科。它的用途很直接:给一个中文大模型(或声称支持中文的模型)打一个可横向比较的分数,看它在人文、社科、理工等不同学科上的表现差异。本文要讲的是如何用配套的推理评测脚本,把本地模型在 CMMLU 上完整跑一遍,并正确解读输出结果。适合已经能把模型加载起来、需要一份可复现评测流程的开发者。如果你更想先了解这类基准的题目构成与评分口径,可以先看 CMMLU 的工具页,再回到本文动手。

整个流程分三段:下载并摆放数据集、按参数运行评测脚本、读取输出目录里的两份 JSON。脚本本身不训练模型,只做前向推理和答案抽取,因此耗时主要取决于模型规模、量化设置和重复评测次数。

准备工作

模型文件

评测脚本要求传入的是完整模型权重,也就是基座模型或指令微调后的完整模型,不能是 LoRA 适配器。如果你的权重是 LoRA 形式,需要先与基座合并成完整模型再评测,否则脚本无法正常加载。模型路径通过 model_path 传入,指向本地目录即可。

数据集

从 CMMLU 官方发布渠道获取数据集压缩包(版本为 cmmlu_v1_0_1.zip),解压到项目的 data 目录下。素材给出的下载与解压命令形如:

wget <数据集下载地址>
unzip cmmlu_v1_0_1.zip -d data

下载地址请以官方发布页当前提供的为准。解压完成后,把数据移动到本项目的 scripts/cmmlu 目录下,使评测脚本能通过 --input_dir data 找到它。目录层级不要随意改动,脚本按固定相对路径读取题目文件。

运行环境

脚本基于 Python 与 Transformers 生态运行,需要能加载对应模型架构的推理环境。素材中提到的两个与性能相关的开关值得提前确认:

  • use_flash_attention_2:启用 flash-attn2 加速推理;不启用时脚本回退到 SDPA 加速。两者都需要相应依赖已正确安装,否则会在加载模型阶段报错。
  • load_in_4bit:以 4 比特量化形式加载模型,用于显存不足以容纳全精度权重的情况。

显存需求、依赖版本与量化后端支持情况随模型和框架版本变化,请以官网当前信息为准。

操作步骤

第一步:进入脚本目录并设置路径变量

先把模型路径和输出路径写成 shell 变量,后续命令直接引用,避免长命令里反复粘贴路径出错:

model_path=path/to/chinese_mixtral
output_path=path/to/your_output_dir
cd scripts/cmmlu

output_path 指向的目录用于存放评测结果,脚本会在其下自动创建子目录,不需要手动建好每一层。

第二步:运行评测脚本

素材给出的基础调用方式如下:

python eval.py \
  --model_path ${model_path} \
  --few_shot False \
  --with_prompt True \
  --constrained_decoding True \
  --output_dir ${output_path} \
  --input_dir data

这组参数的含义是:不使用 few-shot 示例,输入中带上指令提示(适配 instruct 类模型),用约束解码方式抽取答案,数据从 data 目录读取。这是一条能覆盖大多数场景的起点配置,下面逐个说明可调参数。

第三步:按需调整参数

答案抽取方式是这套脚本里最关键的参数。CMMLU 的标准答案格式是选项 A / B / C / D,脚本提供两种从模型输出中取答案的方法:

  • constrained_decoding=True:计算模型生成的第一个 token 为 A、B、C、D 各自的概率,取概率最高者作为答案。这种方式不依赖模型是否按格式输出,对输出格式不稳定的模型更稳。
  • constrained_decoding=False:用正则表达式从模型生成的完整输出中提取答案 token。适合模型会先输出推理过程、再给出选项字母的情形。

其余参数:

参数作用
model_path待评测模型的路径,必须是完整模型,不能是 LoRA
cot是否使用思维链(chain-of-thought)方式作答
few_shot是否使用少样本示例
ntrain当 few_shot=True 时指定示例数量,例如 5-shot 设 ntrain=5;few_shot=False 时该参数不起作用
with_prompt输入中是否包含面向 instruct 模型的指令提示
constrained_decoding答案抽取方式,见上文两种模式
temperature解码温度
n_times重复评测次数,每次结果单独存放
load_in_4bit以 4 比特量化形式加载模型
use_flash_attention_2使用 flash-attn2 加速推理,否则使用 SDPA
output_dir结果输出路径
input_dirCMMLU 数据所在路径

注意 few_shot 与 ntrain 的联动关系:只打开 few_shot 而不设 ntrain,示例数量不会按你预期生效;反过来在 few_shot=False 时调 ntrain 完全是空操作。

第四步:读取输出结果

评测结束后,脚本会在 output_dir 下创建形如 outputs\take* 的目录,其中 * 是从 0 到 n_times-1 的编号,分别对应每一次重复评测。每个 take* 目录里有两份文件:

  • submission.json:保存模型生成的答案,按学科组织,形如 {"arts": {"0": "A", "1": "B", ...}, "nutration": {"0": "B", "1": "A", ...}, ...},键是题目序号,值是该题选出的选项字母。
  • summary.json:保存评测得分,覆盖 67 个学科、5 个更粗的分类,以及一个总体平均。

summary.json 末尾的 All 键就是总体平均分,结构如下:

"All": {
  "score": 0.39984458642721465,
  "num": 11582,
  "correct": 4631.0
}

三个字段分别是:score 为总体准确率,num 为参与评测的样本总数,correct 为预测正确的样本数。核对 correct / num 是否等于 score,是检查结果是否被正确汇总的一个简单办法。

一个完整示例

下面从零走一遍最小可跑通的流程。假设模型权重已合并为完整模型,放在 /models/chinese-mixtral,数据集压缩包已下载到当前目录。

1. 解压数据并放到脚本目录

unzip cmmlu_v1_0_1.zip -d data
mv data scripts/cmmlu/

2. 设置变量并进入脚本目录

model_path=/models/chinese-mixtral
output_path=/results/cmmlu_run1
cd scripts/cmmlu

3. 先跑一次单轮评测

python eval.py \
  --model_path ${model_path} \
  --few_shot False \
  --with_prompt True \
  --constrained_decoding True \
  --output_dir ${output_path} \
  --input_dir data

这条命令不设 n_times,只产生一轮结果,适合先确认流程通畅、显存够用、答案抽取方式与模型输出风格匹配。

4. 确认无误后做多轮重复评测

python eval.py \
  --model_path ${model_path} \
  --few_shot False \
  --with_prompt True \
  --constrained_decoding True \
  --n_times 3 \
  --output_dir ${output_path} \
  --input_dir data

此时 ${output_path} 下会出现三个 take 目录,各自带一份 submission.json 与 summary.json。对比三份 summary.json 中 All 的 score,可以判断结果波动幅度;如果波动明显,说明该模型在该基准上的表现对采样较敏感,报告单次分数时需要说明这一点。

5. 查看分科结果

打开任意一份 summary.json,先看 67 个学科各自的 score,再看 5 个粗分类的汇总,最后看 All。分科分数往往比总分更有信息量:总分接近时,不同模型在学科上的强项分布可能完全不同。

6. 显存不足时的替代跑法

python eval.py \
  --model_path ${model_path} \
  --few_shot False \
  --with_prompt True \
  --constrained_decoding True \
  --load_in_4bit True \
  --output_dir ${output_path} \
  --input_dir data

量化会改变模型的实际数值表现,因此量化跑出的分数不能与全精度分数直接混用比较,报告时应注明加载方式。

注意事项

  • 不能直接评测 LoRA。 model_path 必须指向完整模型权重,LoRA 适配器需要先合并。
  • 答案抽取方式要与模型输出风格匹配。 约束解码只看第一个 token 的 A/B/C/D 概率,若模型习惯先输出一段解释再给答案,用这种方式可能取到错误位置;反之,正则抽取依赖模型确实按格式输出选项字母,格式漂移会导致抽取失败。切换模型时建议两种方式各跑一次小规模验证。
  • ntrain 只在 few_shot=True 时生效。 少样本设置与零样本设置下的分数不可直接比较。
  • 重复评测的结果是分开存放的,不会自动平均。 n_times 只负责生成多份结果,汇总需要自己处理。
  • 加速开关依赖环境。 use_flash_attention_2 与 load_in_4bit 都需要对应的依赖与硬件支持,缺失时会在加载阶段失败,而不是在评测中途降级。
  • 数据集版本要固定。 不同版本的数据集题目数量可能不同,summary.json 里的 num 是判断本次评测实际覆盖了多少题的直接依据,跨版本比较分数前先核对这个数字。
  • 价格、配额、依赖版本与硬件要求以官网当前信息为准。 本文只描述脚本的参数语义与输出结构,不涉及具体资源消耗数字。