LongProc 长程过程生成基准评测任务:在 lm-evaluation-harness 中使用与指标解析
2026/9/15 11:09:33 网站建设 项目流程

LongProc 长程过程生成基准评测任务:在 lm-evaluation-harness 中使用与指标解析

【免费下载链接】lm-evaluation-harnessA framework for few-shot evaluation of language models.项目地址: https://gitcode.com/GitHub_Trending/lm/lm-evaluation-harness

LongProc(Long Procedural Generation)是一个针对长上下文语言模型的基准测试,其核心思路是通过"长过程生成"(long procedural generation)来检验模型:模型必须严格遵循给定的过程性指令,并产出结构化的长输出。本文以 lm-evaluation-harness 仓库中lm_eval/tasks/longproc/的 README 与配套 YAML/源码为依据,完整讲解该基准的 6 类任务、16 个子任务、长度分级、评测指标与命令行运行方式,并结合metrics.pyutils.py与任务配置,深入剖析每类任务的打分原理与底层实现,帮助你直接上手评测长上下文模型的过程遵循与长程生成能力。

LongProc 基准概览

LongProc 由 Princeton PLI 团队提出(Ye, Xi et al., "LongProc: Benchmarking Long-Context Language Models on Long Procedural Generation",Conference on Language Modeling, 2025),目标是评测长上下文 LLM 的过程性生成能力:模型需要按照指定的过程(procedure)一步步执行并生成结构化输出,输出长度横跨 500 到 8K tokens。这意味着它不仅考验"能否读懂长上下文",更考验"能否在长输出中始终如一地遵循规则、不中途出错"。

在 lm-evaluation-harness 中,LongProc 通过 lm_eval/tasks/longproc/ 目录下的 YAML 任务配置接入评测框架,其完整引用信息(标题、摘要、Homepage 与 BibTeX)记录在 lm_eval/tasks/longproc/README.md 中。仓库内提供原文的 BibTeX 引用条目:

@inproceedings{ye25longproc, title={LongProc: Benchmarking Long-Context Language Models on Long Procedural Generation}, author={Ye, Xi and Yin, Fangcong and He, Yinghui and Zhang, Joie and Yen, Howard and Gao, Tianyu and Durrett, Greg and Chen, Danqi}, journal={Conference on Language Modeling}, year={2025} }

6 类任务与 16 个子任务

LongProc 覆盖 6 种任务类型,每种类型内部再按目标输出长度细分为多个子任务,总计16 个可评测任务。README 中的 Groups/Tags/Tasks 结构如下:

任务类型子任务(按长度)任务内容
Countdown0.5k / 2k / 8k通过算术运算(搜索)组合数字达到目标数
Path Traversal0.5k / 2k / 8k在图中遍历连接两座城市的路径
Theory-of-Mind Tracking0.5k / 2k / 8k在物体放置故事中跟踪位置与信念
HTML-to-TSV0.5k / 2k / 8k从 HTML 页面抽取信息并转为 TSV 格式
Pseudocode-to-Code0.5k / 2k将逐行伪代码翻译为 C++ 代码
Travel Planning2k / 8k依据时长与航班约束制定旅行计划

每个子任务的命名规则为longproc_<task_type>_<length>,例如longproc_countdown_0.5k。各任务入口配置位于 lm_eval/tasks/longproc/ 目录(如 countdown_0.5k.yaml、path_traversal_0.5k.yaml、travel_planning_2k.yaml 等),并通过include机制共享三份按长度划分的默认配置。

Group 层次结构与指标聚合

任务按三层 Group 组织,全部在longproc根 Group 下聚合:

  • 根 Grouplongproc:包含全部 16 个任务,定义于 lm_eval/tasks/longproc/_longproc.yaml;
  • 类型 Group:如longproc_countdown(0.5k/2k/8k)、longproc_path_traversallongproc_tom_trackinglongproc_html_to_tsvlongproc_pseudo_to_code(0.5k/2k)、longproc_travel_planning(2k/8k),每个类型一个 YAML,例如 lm_eval/tasks/longproc/_longproc_countdown.yaml;
  • 叶子任务:每个子任务一个 YAML 文件。

聚合时,lm_eval/tasks/longproc/_longproc.yaml 通过aggregate_metric_list将各任务score取均值(weight_by_size: false),从而得到整个基准的综合分:

group: longproc task: - longproc_countdown - longproc_path_traversal - longproc_tom_tracking - longproc_html_to_tsv - longproc_pseudo_to_code - longproc_travel_planning aggregate_metric_list: - metric: score aggregation: mean weight_by_size: false metadata: version: 1.0

任务配置的继承关系与长度分级

所有任务共享三份"按输出长度"的默认配置,通过include指令引用:

默认配置适用任务max_gen_toks
_default_yaml_0.5k各 0.5k 任务(含longproc_travel_planning_0.5k之外的 0.5k 任务)1024
_default_yaml_2k各 2k 任务3072
_default_yaml_8k各 8k 任务9216

0.5k 默认配置(_default_yaml_0.5k)的完整内容:

dataset_path: PrincetonPli/LongProc unsafe_code: true output_type: generate_until test_split: test process_docs: !function utils.process_docs doc_to_text: "{{input_prompt}}" doc_to_target: "{{reference_output}}" num_fewshot: 0 generation_kwargs: temperature: 0 do_sample: false until: [] max_gen_toks: 1024 metadata: version: 1.0

关键配置项说明:

  • dataset_path: PrincetonPli/LongProc:评测数据来自 Hugging Face 上的PrincetonPli/LongProc数据集,test_split: test指定使用 test 划分;
  • output_type: generate_until:任务属于自由生成型(非 loglikelihood 型),模型需要完整生成答案文本;
  • process_docs: !function utils.process_docs:调用 utils.py 中定义的process_docs对原始数据做预处理;
  • doc_to_text/doc_to_targetinput_prompt作为模型输入,reference_output作为标准答案(也是打分时的 ground truth);
  • generation_kwargstemperature: 0do_sample: false保证贪婪解码、结果可复现max_gen_toks依长度分级放宽(1024 → 3072 → 9216),保证足够空间生成长输出;
  • unsafe_code: true:标记该任务涉及执行模型生成的代码。在 lm_eval/api/task.py 中,unsafe_code is not False会令任务设置UNSAFE_CODE = True,提示评测环境存在安全风险(伪代码转 C++ 任务需要本地编译运行模型输出)。

数据预处理:utils.process_docs

utils.py 中process_docs的唯一职责是解析metadata:数据集中每行样本的metadata字段是 JSON 字符串,这里将其反序列化为 Python dict 存回metadata_parsed,供模板渲染和打分函数直接使用(例如 countdown 任务的数字与目标值、travel planning 的行程真值、pseudo_to_code 的测试用例都在其中)。

def process_docs(dataset): def _parse(doc): doc["metadata_parsed"] = json.loads(doc["metadata"]) return doc return dataset.map(_parse)

子任务 YAML 的构成

每个子任务 YAML 通过include继承对应长度的默认配置,并声明自身任务名、数据集子集名(dataset_name)、打分函数(process_results)与指标列表。以 countdown_0.5k.yaml 为例:

include: _default_yaml_0.5k task: longproc_countdown_0.5k dataset_name: countdown_0.5k process_results: !function metrics.process_results_countdown metric_list: - metric: score aggregation: mean higher_is_better: true - metric: accuracy aggregation: mean higher_is_better: true - metric: partial_accuracy aggregation: mean higher_is_better: true - metric: extraction_rate aggregation: mean higher_is_better: true

大部分任务上报score / accuracy / partial_accuracy / extraction_rate四类指标;HTML-to-TSV任务例外,上报score / f1 / precision / recall / extraction_rate(见 html_to_tsv_0.5k.yaml)。四类通用指标的含义贯穿全文:

  • score:该任务的主指标,也是 Group 聚合时使用的指标;
  • accuracy:严格正确率(输出与标准答案完全匹配);
  • partial_accuracy:部分正确率(按行/按步的渐进式评分,反映"做到第几步才出错");
  • extraction_rate:答案抽取率(模型输出中是否包含可解析的答案块,如<Solution><Route>等标签)。

六类任务的评测指标与源码解析

所有打分逻辑集中在 lm_eval/tasks/longproc/metrics.py 中。各process_results_*函数接收单个样本doc(dict)与results列表(首个元素为模型生成文本),返回指标名到标量值的映射。以下是逐类任务的解析。

Countdown:数字搜索与最终解校验

模型需用给定数字、通过加减乘除组合出目标数,输出必须包含最终解(<Solution>标签),且生成过程(# Search Procedure段)要与标准搜索过程逐行比对。

打分逻辑(process_results_countdown)分为三层:

  1. 最终解校验:先抽取<Solution>...</Solution>内容,调用_evaluate_countdown_final_solution校验——要求解恰好 3 行等式,每行lhs = rhs的算术结果成立,且左右操作数必须来自当前可用数字池(用过即移除、结果放回),最后剩余数字等于目标值。通过则score = accuracy = partial_accuracy = 1.0
  2. 搜索过程比对:若最终解不通过,则截取# Search Procedure之后、Now we have found the target之前的内容,与标准搜索过程逐行比对(_evaluate_countdown_search_procedure),返回"第几步开始出错"换算的partial_accuracyidx / len(gt_lines));
  3. 抽取率pred_solution存在则extraction_rate = 1.0,否则为 0。

注意该函数内部使用eval解析等式左端(metrics.py中注明 "trusted data"),且对搜索过程的比对相当严格:Pick two numbers|- Try等式、drop this branch分支标记都必须逐字匹配。

Path Traversal:路径输出的行级前缀比对

模型需在图中找出连接两座城市的完整路径,答案放在<Route>标签内。打分(process_results_path_traversal)步骤:

  1. _extract_with_tag抽取<Route>内容,抽不到则四项指标全为 0;
  2. 与标准路径gt精确相等 →score = accuracy = partial_accuracy = extraction_rate = 1.0
  3. 否则按行前缀比对:从第一行开始逐行比较,遇到第一个不匹配行即停止,partial_accuracy = (match_count + 1) / len(gt_lines)(即把"出错那一步"之前的行数计入),extraction_rate = 1.0

这种"前缀逐步加分"机制正是 LongProc 强调过程正确性的体现:只要模型在路径开头走对若干步,即便后半段出错,也能获得部分分数。

Theory-of-Mind Tracking:信念列表的归一化比对

模型需在"物体放置"类故事中跟踪各角色的位置信念,输出形如- <角色> believes <位置>的行。打分(process_results_tom_tracking)流程:

  1. 只保留预测与标准答案中以-开头的行,抽取信念内容;
  2. 通过_normalize_tom做归一化:转小写、去标点、去停用词(_TOM_STOPWORDS_RE覆盖a/an/the/step/thinks/believes/is/are/of/location/know/belief等)、压缩空白;
  3. 归一化后的信念列表与标准列表逐元素比对:完全一致则accuracy = 1.0;否则从第一个不一致的信念位置计算partial_accuracy = first_diff / len(gt_beliefs)(列表长度不足时按最短匹配比例计算)。

与 Path Traversal 类似,Tom Tracking 也采用"顺序敏感"的逐步评分,且归一化规则对冠词/停用词做了容错,避免因措辞差异误伤正确推理。

HTML-to-TSV:表格级精确率 / 召回率 / F1

模型需从 HTML 页面中抽取信息,输出为 TSV 表格(通常包裹在```tsv ... ```代码块中)。打分(process_results_html_to_tsv)是唯一使用 F1 的任务:

  1. 用正则```tsv([\s\S]*)```抽取 TSV 块;抽取失败则score = f1 = precision = recall = extraction_rate = 0
  2. _string_to_pd将 TSV 文本解析为 pandas DataFrame:首行作表头,行长度不足时补N/A,每个单元格经_normalize_answer_html归一化(小写、去标点、去冠词、去所有空白);
  3. _compute_html_to_tsv_metrics计算行级精确率(预测的每一行是否在真值表中存在)与召回率(真值的每一行是否在预测表中存在),进而得 F1;score直接取 F1;
  4. extraction_rate依据解析是否出错(m["error"] is None)判定。

注意:该指标需要pandas,源码中明确提示缺失时需pip install pandas。行级集合匹配 + 单元格归一化,使它对"内容正确但顺序略有不同"的表格输出相对宽容。

Pseudocode-to-Code:真实编译执行(g++)

模型需将逐行伪代码翻译为 C++ 代码,这是 LongProc 中唯一涉及真实代码执行的任务,也是unsafe_code: true的由来。打分(process_results_pseudo_to_code)流程:

  1. 用正则```cpp([\s\S]*)```抽取代码块(兼容```c++写法);
  2. 将代码拼接到_SPOC_IMPORT_HEADER#include <cstdio><vector><algorithm>using namespace std;等标准头)之后,得到完整 C++ 程序;
  3. _evaluate_spoc_code在临时目录中调用g++ -std=c++11 -O编译,编译失败返回compilation error
  4. 编译成功后,用metadata["testcases"]中的前 10 个测试用例逐一执行(Popen管道喂入输入、3 秒超时),比较程序输出与期望输出,全部一致才判对;任一步失败即score = 0,但extraction_rate = 1.0(代码块可抽取)。

运行此任务的环境必须具备g++(C++11),否则打分函数会记录g++ not found警告并判失败。临时目录与文件在打分结束后会被清理(finally块),保证评测过程相对隔离、不留垃圾文件。

Travel Planning:行程结构解析 + 搜索过程比对

模型需根据总天数与航班约束制定欧洲多城市旅行计划,最终行程放在<Plan>标签内。打分(process_results_travel_planning)包含两层:

  1. 行程正确性_parse_travel_response用正则解析输出中的Day N from A to B航班行与M-N停留区间行,还原成(city, stay_days)序列;随后_evaluate_travel_plan_solution将解析结果与metadata["ground_truth_cities"]metadata["ground_truth_durations"](以**分隔的字符串)逐项比对,要求城市与停留天数全部一致才accuracy = 1.0
  2. 搜索过程比对:行程不完美时,截取<Solving Procedure>段与标准过程比对,经_normalize_travel_line(小写、去标点、去a/an/the、压缩空白)归一化后逐行检查"标准行是否包含于预测行",得到partial_accuracy = idx / len(gt_lines)

extraction_rate由是否成功抽取<Plan>块决定;score直接取行程正确性(accuracy)。

在 lm-evaluation-harness 中运行 LongProc

LongProc 已通过 lm-evaluation-harness 的任务自动发现机制注册(目录级任务文件被 TaskManager 的索引机制收集,见 lm_eval/tasks/manager.py 与 lm_eval/tasks/init.py)。安装依赖后即可通过lm_evalCLI 运行。

运行单个子任务(例如 0.5k 的 Countdown):

lm_eval --model hf \ --model_args pretrained=your/model \ --tasks longproc_countdown_0.5k \ --device cuda

运行整个 LongProc 基准(16 个任务一次性评测并聚合):

lm_eval --model hf \ --model_args pretrained=your/model \ --tasks longproc \ --device cuda

运行某一任务类型(如 3 个长度的 Path Traversal):

lm_eval --model hf \ --model_args pretrained=your/model \ --tasks longproc_path_traversal \ --device cuda

运行要点:

  • 数据源为 Hugging Face 数据集PrincetonPli/LongProc,首次运行会自动下载;评测使用test划分,默认num_fewshot: 0(零样本),这是由任务配置写死的;
  • 解码参数已在配置中固定为贪婪解码(temperature: 0, do_sample: false),无需也无法在命令行覆盖;
  • 8k 任务的max_gen_toks高达 9216,请为模型预留足够长的上下文窗口与输出预算;
  • 运行longproc_pseudo_to_code_*前请确认评测机器装有g++(C++11)与pandas(HTML-to-TSV 任务需要),否则对应任务会因环境缺失而计 0 分或告警。

小结

LongProc 在 lm-evaluation-harness 中的实现完整继承了原基准的评测语义:以generate_until自由生成为主,6 类任务分别用"严格匹配 / 行级前缀 / 归一化列表 / 表格 F1 / 真实编译执行 / 行程结构解析"等差异化指标,衡量长上下文模型在 500 至 8K token 长输出场景下的过程遵循能力score / accuracy / partial_accuracy / extraction_rate四件套构成了统一的评测语言:partial_accuracy尤其值得关注,它能量化模型"在长过程中第几步开始崩溃",这正是长上下文评测区别于短任务评测的关键维度。

通过 lm_eval/tasks/longproc/README.md 可获取基准的完整引用信息与任务清单;lm_eval/tasks/longproc/metrics.py 与 lm_eval/tasks/longproc/utils.py 承载全部打分与预处理实现;lm_eval/tasks/longproc/ 目录下的各 YAML 文件则是可直接复用的任务定义。若你的模型宣称具备长上下文能力,不妨先用--tasks longproc跑一轮,观察它在不同长度下的partial_accuracy曲线——它能直观暴露模型"读得进长文,但写不出长过程"的短板。

【免费下载链接】lm-evaluation-harnessA framework for few-shot evaluation of language models.项目地址: https://gitcode.com/GitHub_Trending/lm/lm-evaluation-harness

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询