exp/exp2 数据集与样本流说明
本文件说明 Experiment 2 中支持的数据集、样本结构,以及在「采样阶段」与「归因阶段」的处理方式。
支持的数据集
morehopqa(data/with_human_verification.json)- RULER 系列 JSONL:
hotpotqa_long、niah_*、vt_*(自动在data/ruler_multihop/<len>/.../validation.jsonl搜索),或直接传入任意 RULER JSONL 路径 - 其余数据集(如 math)被显式跳过
- 归因阶段同样优先使用缓存文件
exp/exp2/data/<name>.jsonl,否则按上述规则解析;传入存在的 JSONL 路径也会按 RULER 结构加载
共同的样本字段定义
{
"prompt": "<上下文+问题>",
"target": "<答案或生成>",
"indices_to_explain": [start_tok, end_tok] | null, // token-level:需要解释的 generation token span(闭区间)
"attr_mask_indices": [...], // legacy:覆盖率金标句子索引(当前 exp2 不再使用),可能为 null
"sink_span": [start, end] | null, // 生成 token 中的答案片段
"thinking_span": [start, end] | null, // 生成 token 中的 CoT 片段
"metadata": { ... } // 数据集特定元信息
}
- **
CachedExample**:dataset_utils.py统一的内存态结构,字段与上述 JSON 完全一致,用于采样阶段(加载原始数据)与归因阶段(加载缓存或原始)。 - 缓存行(JSONL):
sample_and_filter.py写入的每行 JSON,与CachedExample字段一一对应。 - 采样阶段处理流(通用):
- 加载原始数据集样本(
prompt/indices_to_explain等保持一致)。 - 按模板调用生成模型,要求「思考文本 + 末尾 \box{} 答案」。
- 若生成不符合「思考 + 单个 \box{} 且无尾巴」的格式,直接丢弃该样本。
- 提取思考片段与
\\box{}内文本,仅用\\box{}内文调用判定模型。 - 判定为 True 时,重新拼接「思考片段 + 去除 box 包裹的答案文本」作为
target,并据此记录sink_span/thinking_span。 - 写入缓存:只保留
reference_answer、judge_response(可选boxed_answer),不再存储candidate_answer。
- 加载原始数据集样本(
生成切分与 span 解析
split_boxed_generation(dataset_utils.py)校验格式:必须是「非空思考文本 + 单个末尾 \box{}」且箱体之后无其他字符,否则直接跳过。target由「思考片段 + 换行 + 最终答案文本(无 box)」重组。attach_spans_from_answer使用 tokenizer 的 offset mapping 将最终答案在target中的字符区间映射到 token 级索引,得到sink_span;thinking_span取从开头到sink_span前一 token 的闭区间。两者均为 token 级 span,满足后续多跳 IFR 的调用约定。indices_to_explain在采样写缓存时统一设置为sink_span(boxed 内文在target中对应的 generation token span)。
MoreHopQA
原始样本结构(
MoreHopQAAttributionDataset→CachedExample){ "prompt": "<context 拼接>\\n<question>", "target": null, "indices_to_explain": null, "attr_mask_indices": null, "sink_span": null, "thinking_span": null, "metadata": { "answer": "<gold answer>", "_id": "<example id>", "original_context": <原始上下文结构> } }- 加载时机:
DatasetLoader.load_raw("morehopqa")在采样阶段、归因阶段(无缓存时)都会产出CachedExample。 - 说明:exp2 的 token-level row/rec 需要
target+ 可定位的答案 token span;建议先跑sample_and_filter.py产出缓存后再做归因评估。
- 加载时机:
采样阶段(生成 & 过滤后写缓存)
{ "prompt": "<同上>", "target": "<生成的 CoT + 最终答案文本(已去掉 box 包裹)>", "indices_to_explain": [start_tok, end_tok], "attr_mask_indices": null, "sink_span": [start_tok, end_tok] | null, "thinking_span": [start_tok, end_tok] | null, "metadata": { "answer": "<gold answer>", "_id": "<example id>", "original_context": <原始上下文结构>, "reference_answer": "<gold answer>", "judge_response": "<True/False 文本>", "boxed_answer": "<可选,boxed 解析结果>" } }sink_span/thinking_span:仅在成功解析\\box{}时填充;target为「思考 + 最终答案文本」的裁剪版。- 写入:
exp/exp2/data/morehopqa.jsonl。
归因阶段(加载缓存优先)
- 加载:
run_exp.py优先load_cached(JSONL →CachedExample),否则回退原始结构并在线生成target。 - 使用:忠实度(token-level RISE/MAS)直接用缓存的
target;ifr_multi_hop在有sink_span/thinking_span时限定答案/CoT,否则视整个生成为 sink。
- 加载:
RULER 热点问答(hotpotqa_long)
原始样本结构(
RulerAttributionDataset→CachedExample){ "prompt": "<input> + <answer_prefix>", "target": "<answer_prefix + sep + ', '.join(outputs)>", "indices_to_explain": [0], "attr_mask_indices": [<句子索引>...] | null, "sink_span": null, "thinking_span": null, "metadata": { "dataset": "ruler", "length": <int>, "length_w_model_temp": <any>, "outputs": [...], "answer_prefix": "<str>", "token_position_answer": <any>, "needle_spans": [ { "title": "<str>", "doc_index": <int>, "document_number": <int>, "sentence_index": <int>, "sentence": "<str>", "context_span": [start, end], "span": [start, end], "snippet": "<str>" }, ... ], "prompt_sentence_count": <int>, "reference_answer": "<在 loader 中补充,来自 outputs 或 target>" } }- 加载时机:
DatasetLoader.load_raw("hotpotqa_long")在采样阶段、归因阶段(无缓存时)都会产出CachedExample。
- 加载时机:
采样阶段(生成 & 过滤后写缓存)
{ "prompt": "<同上>", "target": "<生成的 CoT + 最终答案文本(已去掉 box 包裹)>", "indices_to_explain": [-2], "attr_mask_indices": [<句子索引>...] | null, "sink_span": [start_tok, end_tok] | null, "thinking_span": [start_tok, end_tok] | null, "metadata": { "dataset": "ruler", "length": <int>, "length_w_model_temp": <any>, "outputs": [...], "answer_prefix": "<str>", "token_position_answer": <any>, "needle_spans": [...], "prompt_sentence_count": <int>, "reference_answer": "<outputs 拼接或 target>", "judge_response": "<True/False 文本>", "boxed_answer": "<可选>" } }attr_mask_indices保留原值;indices_to_explain统一为末句[-2](最后一个非 EOS 生成句);sink_span/thinking_span仅在成功解析\\box{}时填充;target为「思考 + 最终答案文本」的裁剪版。- 写入:
exp/exp2/data/hotpotqa_long.jsonl。
归因阶段(加载缓存优先)
- 加载:优先
load_cached(JSONL →CachedExample),否则回退原始解析。 - 使用:覆盖率使用
attr_mask_indices;忠实度与ifr_multi_hop利用缓存的sink_span/thinking_span定位答案/CoT,若缺失则视整个生成为 sink。
- 加载:优先
RULER NIAH / Variable Tracking(niah_*, vt_*)
原始样本结构(同 RULER 通用)
{ "prompt": "<input> + <answer_prefix>", "target": "<answer_prefix + sep + ', '.join(outputs)>", "indices_to_explain": [0], "attr_mask_indices": [<句子索引>...] | null, "sink_span": null, "thinking_span": null, "metadata": { "dataset": "ruler", "length": <int>, "length_w_model_temp": <any>, "outputs": [...], "answer_prefix": "<str>", "token_position_answer": <any>, "needle_spans": [...], "prompt_sentence_count": <int>, "reference_answer": "<在 loader 中补充>" } }- 加载时机:
DatasetLoader.load_raw("<niah_* 或 vt_*>")在采样阶段、归因阶段(无缓存时)使用。
- 加载时机:
采样阶段(生成 & 过滤后写缓存)
{ "prompt": "<同上>", "target": "<思考 + 最终答案文本(无 box),无其他尾巴>", "indices_to_explain": [start_tok, end_tok], "attr_mask_indices": [<句子索引>...] | null, "sink_span": [start_tok, end_tok] | null, "thinking_span": [start_tok, end_tok] | null, "metadata": { "dataset": "ruler", "length": <int>, "length_w_model_temp": <any>, "outputs": [...], "answer_prefix": "<str>", "token_position_answer": <any>, "needle_spans": [...], "prompt_sentence_count": <int>, "reference_answer": "<outputs 拼接或 target>", "judge_response": "<True/False 文本>", "boxed_answer": "<可选>" } }- 生成/判定流程与
hotpotqa_long相同;target是裁剪后的「思考 + 最终答案文本」。 - 写入:
exp/exp2/data/<dataset>.jsonl(例如niah_mq_q2.jsonl,vt_h6_c1.jsonl)。
- 生成/判定流程与
归因阶段(加载缓存优先)
- 与
hotpotqa_long相同:优先缓存,否则原始;恢复率(recovery_ruler)使用metadata.needle_spans(映射到 prompt tokens);多跳 IFR 在有sink_span/thinking_span时作用于答案/CoT。
- 与
indices_to_explain 约定
- token-level:
indices_to_explain = [start_tok, end_tok](闭区间),坐标系为tokenizer(target, add_special_tokens=False)的 generation token indices。 - exp2 推荐:
indices_to_explain == sink_span,即 boxed 内文(最终答案)在target中对应的 token span。
自定义 RULER JSONL 路径
- 若
--dataset传入存在的 JSONL 路径,dataset_from_name按 RULER 文件解析,字段与流程同 RULER 系列。 - 采样、归因阶段行为与上文 RULER 描述一致,只是文件名由显式路径决定。
归因阶段加载优先级与效果
run_exp.py加载顺序:exp/exp2/data/<name>.jsonl缓存 > 显式给定的 JSONL 路径 > 原始解析(MoreHopQA 或 RULER)- 恢复率 (
mode=recovery_ruler) 仅支持 RULER(要求metadata.needle_spans),否则拒绝 - 忠实度 (
mode=faithfulness_gen) 使用生成文本;ifr_multi_hop在有sink_span/thinking_span时才对答案/CoT 做多跳,否则退化为整段生成