# exp/exp2 数据集与样本流说明 本文件说明 Experiment 2 中支持的数据集、样本结构,以及在「采样阶段」与「归因阶段」的处理方式。 ## 支持的数据集 - `morehopqa`(`data/with_human_verification.json`) - RULER 系列 JSONL:`hotpotqa_long`、`niah_*`、`vt_*`(自动在 `data/ruler_multihop//.../validation.jsonl` 搜索),或直接传入任意 RULER JSONL 路径 - 其余数据集(如 math)被显式跳过 - 归因阶段同样优先使用缓存文件 `exp/exp2/data/.jsonl`,否则按上述规则解析;传入存在的 JSONL 路径也会按 RULER 结构加载 ### 共同的样本字段定义 ```json { "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` 字段一一对应。 - **采样阶段处理流(通用)**: 1. 加载原始数据集样本(`prompt`/`indices_to_explain` 等保持一致)。 2. 按模板调用生成模型,要求「思考文本 + 末尾 \\box{} 答案」。 3. 若生成不符合「思考 + 单个 \\box{} 且无尾巴」的格式,直接丢弃该样本。 4. 提取思考片段与 `\\box{}` 内文本,仅用 `\\box{}` 内文调用判定模型。 5. 判定为 True 时,重新拼接「思考片段 + 去除 box 包裹的答案文本」作为 `target`,并据此记录 `sink_span`/`thinking_span`。 6. 写入缓存:只保留 `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`)** ```json { "prompt": "\\n", "target": null, "indices_to_explain": null, "attr_mask_indices": null, "sink_span": null, "thinking_span": null, "metadata": { "answer": "", "_id": "", "original_context": <原始上下文结构> } } ``` - 加载时机:`DatasetLoader.load_raw("morehopqa")` 在采样阶段、归因阶段(无缓存时)都会产出 `CachedExample`。 - 说明:exp2 的 token-level row/rec 需要 `target` + 可定位的答案 token span;建议先跑 `sample_and_filter.py` 产出缓存后再做归因评估。 - **采样阶段(生成 & 过滤后写缓存)** ```json { "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": "", "_id": "", "original_context": <原始上下文结构>, "reference_answer": "", "judge_response": "", "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`)** ```json { "prompt": " + ", "target": "", "indices_to_explain": [0], "attr_mask_indices": [<句子索引>...] | null, "sink_span": null, "thinking_span": null, "metadata": { "dataset": "ruler", "length": , "length_w_model_temp": , "outputs": [...], "answer_prefix": "", "token_position_answer": , "needle_spans": [ { "title": "", "doc_index": , "document_number": , "sentence_index": , "sentence": "", "context_span": [start, end], "span": [start, end], "snippet": "" }, ... ], "prompt_sentence_count": , "reference_answer": "<在 loader 中补充,来自 outputs 或 target>" } } ``` - 加载时机:`DatasetLoader.load_raw("hotpotqa_long")` 在采样阶段、归因阶段(无缓存时)都会产出 `CachedExample`。 - **采样阶段(生成 & 过滤后写缓存)** ```json { "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": , "length_w_model_temp": , "outputs": [...], "answer_prefix": "", "token_position_answer": , "needle_spans": [...], "prompt_sentence_count": , "reference_answer": "", "judge_response": "", "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 通用)** ```json { "prompt": " + ", "target": "", "indices_to_explain": [0], "attr_mask_indices": [<句子索引>...] | null, "sink_span": null, "thinking_span": null, "metadata": { "dataset": "ruler", "length": , "length_w_model_temp": , "outputs": [...], "answer_prefix": "", "token_position_answer": , "needle_spans": [...], "prompt_sentence_count": , "reference_answer": "<在 loader 中补充>" } } ``` - 加载时机:`DatasetLoader.load_raw("")` 在采样阶段、归因阶段(无缓存时)使用。 - **采样阶段(生成 & 过滤后写缓存)** ```json { "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": , "length_w_model_temp": , "outputs": [...], "answer_prefix": "", "token_position_answer": , "needle_spans": [...], "prompt_sentence_count": , "reference_answer": "", "judge_response": "", "boxed_answer": "<可选>" } } ``` - 生成/判定流程与 `hotpotqa_long` 相同;`target` 是裁剪后的「思考 + 最终答案文本」。 - 写入:`exp/exp2/data/.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/.jsonl` 缓存 > 显式给定的 JSONL 路径 > 原始解析(MoreHopQA 或 RULER) - 恢复率 (`mode=recovery_ruler`) 仅支持 RULER(要求 `metadata.needle_spans`),否则拒绝 - 忠实度 (`mode=faithfulness_gen`) 使用生成文本;`ifr_multi_hop` 在有 `sink_span`/`thinking_span` 时才对答案/CoT 做多跳,否则退化为整段生成