在自然语言处理领域,评估大型语言模型(LLM)的性能是验证新技术和比较不同模型版本的关键环节。EleutherAI开发的LM Evaluation Harness提供了一个标准化框架,支持多种NLP任务评估,包括选择题、问答和分类等。本文将详细介绍如何将自定义数据集集成到这个框架中,特别是针对选择题形式的基准测试。
提示:本文假设读者已具备Python基础编程知识,并熟悉基本的机器学习概念。所有操作均在Linux环境下完成,但同样适用于其他操作系统。
LM Evaluation Harness采用模块化设计,主要组件包括:
框架支持两种主要的评估模式:
框架提供多种评估指标,对于选择题任务最常用的是:
归一化准确率的计算逻辑尤为重要。当答案包含多个token时,直接比较原始概率会导致偏差,因为:
code复制P("Abu Dhabi") = P("Abu") × P("Dhabi"|"Abu")
而单token答案如"Dubai"没有这种乘积效应。归一化通过将log概率除以token数量来解决这个问题:
code复制normalized_log_prob = total_log_prob / num_tokens
典型的原始数据集通常采用JSON格式,包含以下关键字段:
json复制{
"dataset": "DFIR-Metric Dataset",
"questions": [
{
"question": "渗透测试相关问题...",
"options": {
"A": "选项A内容",
"B": "选项B内容",
"C": "选项C内容",
"D": "选项D内容"
},
"answer": "B"
}
]
}
框架推荐使用jsonl(JSON Lines)格式,每个问题占一行。转换脚本示例:
python复制import json
with open("original_dataset.json", "r") as infile:
data = json.load(infile)
with open("formatted_dataset.jsonl", "w") as outfile:
for item in data["questions"]:
json.dump(item, outfile)
outfile.write("\n")
关键注意事项:
在框架中创建自定义任务的推荐结构:
code复制lm-evaluation-harness/
├── lm_eval
│ ├── tasks
│ │ ├── your_task_name
│ │ │ ├── dataset
│ │ │ │ └── formatted_data.jsonl
│ │ │ └── your_task.yaml
完整的任务配置文件示例:
yaml复制task: dfir_mcq_mod
dataset_path: json
dataset_name: null
dataset_kwargs:
data_files: "lm_eval/tasks/dfir/dataset/validation.jsonl"
validation_split: train
output_type: multiple_choice
num_fewshot: 5
doc_to_text: |
Answer the following question only by providing the letter corresponding to the right option only.
{{question.strip()}}
A.{{options['A']}}
B.{{options['B']}}
C.{{options['C']}}
D.{{options['D']}}
Answer:
doc_to_choice: ["A", "B", "C", "D"]
doc_to_target: "{{ ['A', 'B', 'C', 'D'].index(answer) }}"
metric_list:
- metric: acc
aggregation: mean
- metric: acc_norm
aggregation: mean
metadata:
version: 1.0
revision: "{{model_args['revision']}}"
关键参数说明:
num_fewshot: 设置few-shot learning的示例数量doc_to_text: 定义问题呈现模板(使用Jinja2语法)doc_to_choice: 指定选项列表doc_to_target: 将正确答案映射为选项索引基本评估命令结构:
bash复制python lm_eval/__main__.py \
--model hf \
--model_args pretrained=MODEL_NAME,dtype=bfloat16,revision=CHECKPOINT \
--tasks YOUR_TASK_NAME \
--batch_size auto \
--output_path results/
实际示例(评估Hugging Face模型):
bash复制NCCL_P2P_DISABLE=1 NCCL_IB_DISABLE=1 \
python ./lm_eval/__main__.py \
--model hf \
--model_args pretrained=HuggingFaceTB/SmolLM2-1.7B-intermediate-checkpoints,dtype=bfloat16,revision=step-125000 \
--tasks dfir_mcq_mod \
--batch_size auto \
--output_path results_mod/
评估生成JSON结果文件,可使用以下脚本可视化模型在不同checkpoint的表现:
python复制from pathlib import Path
import json
import matplotlib.pyplot as plt
results = []
for json_file in sorted(Path("./results_mod/").glob("**/*.json")):
with json_file.open() as f:
results.append(json.load(f))
steps, accuracies, acc_norms = [], [], []
for data in results:
steps.append(data["configs"]["dfir_mcq_mod"]["metadata"]["revision"])
result_data = list(data['results'].values())[0]
accuracies.append(result_data['acc,none'])
acc_norms.append(result_data['acc_norm,none'])
plt.figure(figsize=(10,6))
plt.plot(steps, accuracies, 'o-', label='Regular Accuracy')
plt.plot(steps, accuracies_norm, 's-', label='Normalized Accuracy')
plt.xlabel('Checkpoint Step')
plt.ylabel('Accuracy')
plt.title('Model Performance Progression')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
续写模式与标准模式的主要区别在于prompt构造方式。对应的YAML配置:
yaml复制task: dfir_mcq_mod_var
# ...其他参数与标准模式相同...
doc_to_text: "{{question.strip()}}\nAnswer:"
doc_to_choice: "{{options.values() | list}}"
关键变化:
doc_to_text不再包含选项内容doc_to_choice直接使用选项文本而非字母标识框架在续写模式下会:
评估命令与标准模式相同,只需更改任务名称:
bash复制python ./lm_eval/__main__.py \
--tasks dfir_mcq_mod_var \
# ...其他参数不变...
--batch_size参数(auto通常效果最佳)--num_fewshot和--limit参数分片评估问题1:任务未正确加载
python lm_eval/__main__.py --tasks list | grep your_task是否显示任务问题2:评估结果异常
doc_to_target是否正确映射了答案问题3:内存不足
--batch_size--limit限制评估样本数量通过评估模型在不同训练阶段的多个checkpoint,我们可以观察模型能力的演进。典型分析流程:
示例发现可能包括:
这种分析对模型开发和调优具有重要指导意义,可以帮助研究者: