Files
Video-Tree-TRM5/research-wiki/designs/2026-07-15-results-driven-video-split-design.md
T

211 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: results-driven-video-split
title: 结果驱动的视频级 train/val/test 切分(替代自造题模块)
type: design
created: 2026-07-15
status: draft
---
# 结果驱动的视频级切分设计
## 1. 目标与范围
**目标**:用一条**离线、结果驱动的视频级切分管线**,替代"自造 Video-MME 同质量训练题"这一在 AAAI 截止前风险过高的模块。基于已有的 `infer_adhoc` baseline900 题 / 300 视频 / 660 对 240 错 / 73.3%),把 300 视频按**视频原子**切成 train/val/test,产出一个冻结的 `pools.json` 供 harness run 消费。
**范围边界**
| 在范围内 | 不在范围内 |
|---------|-----------|
| 诊断 240 错题 → signal 分层 | 改诊断模块内部(只**调用** `core/evolution/diagnose` |
| signal_scorer + 视频级聚合 + 贪心联合选择器(新增) | 改进化循环内部 |
| `pools.py` 切分原子 unit→**video** + 信号感知 | AR 出题 v3 管线(另行废弃,本设计外) |
| `loader` 指向 Video-MME 900(已如此) | 重跑推理(复用现有 baseline |
| — | **不改 `gate_ladder.py` / 信息阶梯冷启动 2:1**Codex M-1;算法保真 §4.7 第 5 项不受本切分波及,切分只改 pools 归属不改冷启动比例) |
**故事重定位**:论文核心贡献是"视频树上可自进化的搜索 AgentHarness Engineering",出题从来不是卖点。PyTorch 类比中 DataLoader **本就只加载已有数据集 + 切分、从不合成数据**——所以砍掉自造题、改为对 Video-MME 做结果驱动切分,类比反而更忠实。头号数字诚实、可比。
## 2. 背景:核心洞察(耦合)
全数据集错题总数固定 = 240。**守恒式为 `train错题 + val错题 + test错题 = 240`**(选择器在 **train+val 并集**上优化覆盖,再内部切 train/val):越把信号往 train+val 塞,test 越简单、headline 越虚高。因此"把最难视频塞进 train+val"是有害的(偏置方向恰好注水 test)。**val 会分走部分 defect 视频——这是可接受的**gate/e-process 本就需要错题才有功效(§8),但 val 的抽取受 §8 的 correctness 分层约束,不破坏 train 的多样性目标。
**第一原则**:**test 神圣(代表性 + 冻结)**;train 的信号富集只能靠三条合法途径——① 每类型 floor(硬约束);② 调度层信息阶梯加权(运行时,本设计不涉及);③ 同 profile 视频交换自由度。ε 代表性约束是耦合的算法化身,天然挡住"偷 test 难题"。
信号地图(baseline 逐类型错题):Counting 24/48(0.50)、Action Recognition 22/63(0.65)、OCR 5/14、Object Reasoning 68/240、Action Reasoning 48/180、Temporal Reasoning 22/91 为高信号;Spatial Reasoning 0/11(全对,零信号)Temporal/Spatial Perception 量微。视频级:125 视频全对(零信号)、115 一错、55 两错、5 全错。
## 3. 架构与数据流
```mermaid
flowchart TD
P[infer_adhoc predictions<br/>900题/300视频] --> S{对错拆分}
S -->|660 对| CG[correct 视频画像<br/>供 ε 代表性/难度约束]
S -->|240 错| DG[诊断管线<br/>调用 core/evolution/diagnose]
DG --> QA[每题: error_type + cause_category<br/>+ QuestionMetrics]
QA --> SC[signal_scorer<br/>→ tier T0/T1/T2 + 多样性格子]
SC --> VA[视频级聚合<br/>每视频: 覆盖格子集 + tier 构成]
CG --> GS
VA --> GS[贪心联合约束选择器<br/>max 多样性覆盖 s.t. test ε + floor]
GS --> TV[选中 ~100 视频 train+val]
GS --> TE[补集 ~200 视频 test]
TV --> SP[correctness 视频原子切 train/val<br/>val 按 McNemar 功效定尺寸]
TE --> FZ
SP --> FZ[save_pools → 冻结 pools.json(原子写)]
FZ --> RUN[harness run 消费]
```
**关键不变量**:① 视频为原子,三池视频集互斥、绝不共享视频 → 零内容泄漏;② test = train+val 的补集,代表性由 ε 约束保证(非事后随机);③ 全程离线、可复现(固定 seed + baseline run_id 溯源),不触碰在线进化。
## 4. 组件落位(Clean Architecture 四层)
| 模块 | 职责 | 新增/改动 | 层 |
|------|------|----------|----|
| `core/evolution/diagnose.py` | 诊断 240 错题 | 不动(只调用) | core |
| `app/harness/baseline_diagnosis.py` | 编排离线诊断:读 baseline 错题预测+轨迹 → 调 diagnose → 落库 | 新增 | app |
| `app/harness/split_selection.py` | 纯函数:`score_signal`(→tier+格子) / `aggregate_video_signal` / `select_split`(贪心) | 新增 | app |
| `app/harness/pools.py` | 切分原子 unit→video`build_pools` 接选择器给的视频三分,做 video 原子 correctness train/val 切分 + 原子冻结 | 改动 | app |
| `app/question_gen/loader.py` | 指向 Video-MME 900 | 已如此 | app |
| `baseline_diagnosis` 落库端口 + SQLite 适配 | 每题 error_type/cause_category/tier/(派生)evolution_target/degraded/diag_fingerprint | 新端口(app/ports 或 core/protocols)+ adapters 实现 | ports+adapters |
`split_selection.py` 全为纯函数(相同输入→相同输出),诊断 I/O 隔离在 `baseline_diagnosis.py`(P6 可测试性)。**落库走端口/适配层,不在 app 拼裸 SQL**Codex I-5,对齐 §4.8 遥测规范与依赖方向)。
**视频原子改造要点(Codex I-3,防实现复用 unit 逻辑漏泄漏)**`build_units` 保留(pair 聚合仍需),但**新增 video 分组层**——`build_pools` 接选择器给定的 video→池 归属,`_split_one_category` 的采样原子从 `QuestionUnit` 提升为 **video 组**(同 video 全部 unit 同进同出)。改造后须由防御断言①验证三池视频不相交。
## 5. signal_score 与多样性定义
### 5.1 signal_score = DiagnosisResult 的确定性投影(不发明新分类)
`DiagnosisResult` 由现有两阶段管线产出:阶段1 规则指标(纯函数) + 5 个 LLM judge → `QuestionMetrics`;阶段2 瀑布归因出 **4 类 error_type**`extraction_failure``search_failure``reasoning_failure``mixed`,代码 928935),再由 `classify_defect_vs_lapse`(LLM judge) 判 `cause_category`INFRA(`stop_reason∈{error,parse_error}`) 阶段1前排除。
signal_score 主要是**分层标签**(非脆弱连续加权分,避 P5 魔法数):
| Tier | 判据(全来自诊断) | 训练处置 |
|------|------------------|---------|
| **T0 排除** | INFRA(`stop_reason∈{error,parse_error}`) | signal=0,永不进 train |
| **T1 低信号** | `cause_category='lapse'`(**接受此桶混着"真·无解/标注错"**,不做三分类) | 低权重,对照/appendix,不作主训练 |
| **T2 高信号** | `cause_category='defect'` 且映射到可执行进化目标 | 核心训练集,内部按多样性排序 |
| (uncertain) | `degraded`(judge 解析失败) 或诊断硬失败 | 排除出 T2 + 计数上报,不静默丢 |
> lapse 为低信号是诊断自身的判断(lapse 路由到受保护 appendix、不重写 skill),非本设计新增。
### 5.2 多样性 = 对诊断逐题一等字段的覆盖(非错题数量)
一个 train 集"多样"当且仅当它张成"可修复失败模式"的空间,使进化对每块参数面都拿到梯度。
**主格子 = `(task_type × error_type)` = 12 × 4 = 48 格**——两者都是**逐题一等字段**task_type 来自题、error_type 来自 `attribute_error`),无歧义、可确定性计算:
| 轴 | 取值空间 | 来源 |
|----|---------|------|
| task_type | 12 类 | 题目字段 |
| error_type | extraction/search/reasoning/mixed4 值) | `ErrorAttribution.error_type`(逐题一等字段) |
**`evolution_target` 是由 error_type 确定性派生的标注,不是独立第三轴**(Codex C-1:`ErrorAttribution` 无 evolution_target 字段,逐题 CasePack 路由非一等产物)。设计声明一张**固定映射表**(科研 config,可测试),用于报告"哪层参数组拿到梯度",不增加维度:
| error_type | evolution_target | 理由 |
|-----------|-----------------|------|
| extraction_failure | tool | 抽取发生在 view_node/observe_frame 工具 prompt → ToolCasePack |
| search_failure | skill | 搜索策略是 skill → SkillCasePack |
| reasoning_failure | skill | 推理是 skill → SkillCasePack |
| mixed | system | 跨切面 → SystemCasePack |
**`behavioral mode` 降为 tie-breaker,不进主格子**Codex I-2system pack 实际只有 `{early_submit, high_conf_wrong, confirmation_bias}` 三类)。平局时用这三类的真实取值打破,不臆造名字。
**度量 = 对 48 格 `(task_type × error_type)` 的覆盖数(set-cover**submodular。**视频级计数规则(Codex I-1)**:一个视频贡献其全部 T2 错题所覆盖格子的**并集(去重集合)**,每格全局只计一次 → 多错题视频不会虚高覆盖增益。奖励"开新格子",惩罚"同格子第 10 道重复错题"。对比"最大化错题数"——既有害(偷 test 难题)又冗余。
## 6. 贪心联合约束选择器(`select_split`
**floor = 硬约束(先满足,取值克制);多样性 = 目标(floor 后最大化)。** floor 违反 = 某高信号类型零梯度(灾难),少覆盖一格子仅边际损失。
```
输入: videos(每个带 其题对错 + 错题 tier/格子), 全局目标(类型比例,难度画像),
config(N_trainval, floor_K[type], ε, reportable_types, seed)
1. trainval=∅; test=all
2. # Floor 阶段(硬约束, 同样受 ε 守护 —— Codex C-2):
while 存在未达 floor 的高信号类型:
cand = 能填未满 floor 槽 且 "移走后 test 仍满足 ε" 的视频
若 cand 非空: 选填槽最多者 → 移入 trainval
否则: fail loud(floor 与 ε 死锁, 报是哪个类型的 floor 无法在不破 ε 下满足)
3. # 多样性阶段(submodular 贪心):
while |trainval| < N_trainval:
cand = 各候选视频移入 trainval 的"新开格子数"(并集去重边际增益)
按增益降序试: 取增益最大且"移走后 test 仍满足 ε"的视频 → 移入
若无任一视频可加而不破 ε → 停(报欠额, 不静默)
4. 返回 (trainval, test=补集)
```
- **submodular → 11/e 保证**;**ε 可行性检查在两个阶段都生效 = 耦合的算法化身**(拉太多难视频破坏 test 难度画像→被拒)。floor 阶段先前漏了 ε 检查(Codex C-2),已补:floor 视频移动同样必须保 test ε。
- **可行性冲突 fail loud**floor 与 ε 死锁(某类型 floor 只能靠"会破 ε 的视频"填)/欠额时明确报哪条约束差多少,人放松旋钮,**绝不静默退随机**。
- 平局与遍历顺序由固定 seed 决定 → 可复现。
## 7. 长尾类型处理(report_floor 拟定 = 总题数 ≥ 27
| 类型(总题) | per-type 报告 | train floor | 归属 |
|------|:---:|:---:|------|
| 8 类 ≥27Object/Action Reasoning, Info Synopsis, Temporal Reasoning, Action/Object Recognition, Counting, Attribute Perception | ✅ | ✅ | 参与 ε + floor 约束 |
| OCR(14) | ❌ 折进 overall | 🟡 无硬 floordefect 机会性进多样性池 | 随视频落 |
| Spatial Reasoning(11) | ❌ | ⛔ 全对零 defect | 随视频落 test |
| Temporal Perception(6)/Spatial Perception(3) | ❌ | ⛔ | 随视频落,披露计数 |
非报告类型不进 ε 代表性约束(太少无法分层),但其视频仍参与选择(每视频跨~3 类,长尾题搭车跟随其视频)。报告折进 overall + 一行"rare types (aggregate)",披露计数。
## 8. val 尺寸(McNemar 功效)
选中 100 视频内部用**现有 `_split_one_category`(改视频原子)** 做 correctness 分层切 train/valval 取较小片但带 `eval_min_per_class` 保底,且**含足够错题使 McNemar 有功效**(val 期望错题数 ≥ 功效阈值,具体值诊断后标定);train 取大头(defect 更密,供 rollout)。
## 9. 非功能性需求(强制四维)
离线一次性管线,但诊断阶段有 240 次 LLM judge 调用,必须可续跑。
| 维度 | 设计 |
|------|------|
| **持久化** | 诊断结果**逐题** upsert 入 `baseline_diagnosis` 表(崩溃最多丢在飞那题);signal/选择纯内存从表重算;最终 `pools.json` 冻结快照 |
| **幂等性** | 诊断表主键 = `(question_id, baseline_run_id, diag_fingerprint)`,其中 `diag_fingerprint = hash(诊断 prompt 版本 + model + 诊断代码版本)`Codex C-4:仅 question_id upsert 不足以约束 judge 非确定/prompt/model 漂移);`--force` 在**新 fingerprint** 下写、**不覆盖**旧记录;冻结的 `pools.json` 记录其构建所依据的 `diag_fingerprint`,重建时 fingerprint 不匹配 → **fail loud**(防脏续跑污染已冻结切分)。选择=纯函数(表切片,全局统计,config,seed)→同输入必同切分 |
| **断点续跑** | 诊断重启查已完成集 → 跳过(镜像建树逐项续跑);崩在第 150 题从 150 续;选择/冻结秒级重跑即可 |
| **原子性** | 逐题写=SQLite 单行事务原子;**pools.json 补原子写**——现有 `save_pools`(341) 与 per_category 增量路径(566) **都用 `path.write_text`(非原子, Codex I-4)**,抽出共用冻结助手统一改 tmp + `os.replace`,两条路径同受益 |
## 10. 错误处理(P5:不静默、不兜底)
| 情形 | 处置 |
|------|------|
| 诊断 LLM 基础设施失败 | GovernedLLMClient 重试栈后仍失败 → 传播报错,不掩盖 |
| 单题诊断硬失败 | slot 级隔离:记 `error`/`degraded` 入表(带错误)+计入报告,不静默跳;该题→uncertain→不进 T2 |
| judge 解析失败(degraded) | 现有 `degraded` → uncertain → 排除 T2 + 计数上报 |
| 选择器不可行(floor 与 ε 冲突/欠额) | **fail loud**:报哪条约束差多少,人放松旋钮,绝不静默退随机 |
| correctness 缺失 | 现有 `_assert_correctness_complete` fail-fast 保留 |
| judge 判不准默认 lapse | 该 fallback **仅用于语义歧义**(judge 回复无法解析),基础设施失败照常传播(`classify_defect_vs_lapse` 994-996);默认 lapse 的题**计数上报**,不静默(Codex M-2 |
**防御性断言清单(P5,Codex I-6,实现须逐条落地)**:① 三池视频集两两不相交断言;② baseline predictions 覆盖全 900 题(缺题 fail-fast);③ 每 video 恰 3 题完整性;④ 诊断表 `diag_fingerprint` 与冻结 pools 记录一致;⑤ 冻结产物写 manifest(含 baseline_run_id/diag_fingerprint/config/seed/文件 hash)供复现校验;⑥ question_id/video_id 唯一性。
## 11. 测试策略
- **单元**`score_signal`(INFRA/lapse/defect→正确 tier+格子)`aggregate_video_signal`(混 tier 视频→正确覆盖格子集);`select_split`(floor 满足 / **视频不跨池** / test ε 代表性 / 贪心覆盖下界 / **构造冲突→抛错** / 同 seed→同切分)video 原子 `_split_one_category`
- **集成**:真实 infer_adhoc 240 错题 + 缓存真实诊断端到端 → 产出合法冻结 pools.json(视频互斥、floor 达标、test 代表)。**续跑**:诊断中途 kill→重启跳过已完成→同一最终结果。
- **LLM 类测试产出 MD**(§4.6):诊断跑涉及 LLM → 结构化 MD 报告。
- **回归**:现有 pools/loader 测试在视频原子改造后仍过;非 AR/pair 行为保留。
## 12. 前序版本继承(step 1.5 审计逐条落实)
| 前序行为 | 处置 |
|---------|------|
| 三池 / 逐步排除互斥 / pair 原子 / baseline_val_accuracy / correctness dict / 复现 | 保留 |
| test 自然分布 | 升级为 ε 代表性约束(更强) |
| val correctness 分层 + min_per_class | 保留 |
| pools.json 持久化 | 保留 + 补原子写 |
| **per_category 增量模式** | **保留但闲置(选项 A**——AR 废弃在本设计外,新流程只走 global 视频感知;per_category 删除留给将来 AR 清理 |
## 13. 待标定旋钮(诊断跑完后用真实分布定,写入科研 YAML + run 快照)
`N_trainval`(~100)、`floor_K[type]`、代表性容差 `ε``report_floor`(≈27)、val 尺寸(McNemar 功效)、`seed`。设计固定**算法与约束结构**,数值不臆造。
## 14. 风险与回退
| 风险 | 回退 |
|------|------|
| 100 训练视频信号不足、进化曲线平 | 切方案 B:外部 benchmark 建树当训练集,全 900 Video-MME 留 held-outA 打底 B 升级) |
| floor 与 ε 联合不可行 | 选择器 fail loud 报冲突 → 放松 floor_K 或 ε 或 N_trainval |
| 诊断 LLM 成本/耗时(240 题) | Redis 缓存 + 逐题续跑;一次性离线 |
| test 长尾类型不可报 | 折进 overall + rare-aggregate 行,披露计数 |
## 相关
- baseline 结果:`workspaces/default/harness.db` run_id=`infer_adhoc`
- 诊断模块:`core/evolution/diagnose.py``core/evolution/types.py`
- 被替代:自造题 v3`2026-07-15-question-gen-v3-construction-paradigm-design.md`