Files
Video-Tree-TRM5/research-wiki/designs/2026-07-14-action-recognition-training-design.md
T
iomgaa dec7346da3 feat(harness): add Action Recognition training experiment
- PerCategoryPoolStrategy: filter test pool by task_types
- RunConfig: add run_holdout_eval toggle (default true)
- load_config: fix YAML task_types list-to-tuple conversion
- Runner: conditionally skip _holdout_four_way when disabled
- CLI: add --no-run-holdout-eval flag
- New config/train_action_recognition.yaml (3 epochs, per_category)
- New scripts/train_action_recognition.sh (baseline + seed + train)
2026-07-14 00:58:54 -04:00

199 lines
7.6 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: action-recognition-training
title: Action Recognition 单题型首次训练实验设计
type: design
created: 2026-07-14
status: approved
---
# Action Recognition 单题型首次训练实验设计
## 1. 目标
用 Action Recognition 单题型验证训练管线端到端可用性。选择此题型因其:
- Video-MME 准确率 65.1%(倒数第三),提升空间大
- 属于 RETRIEVAL family(权重最高 0.30
- v2-360 有 30 道生成题可用于 train/val
## 2. 数据划分
| 池 | 来源 | 数量 | 用途 |
|----|------|------|------|
| train (diagnosis) | generated-v2-360 | 20 题 | 错误归因 + 进化 |
| val (validation) | generated-v2-360 | 10 题 | CE-Gate 验证 + best argmax |
| test | Video-MME benchmark | 63 题 | 训练结束后终评(epoch 内跳过四向 held-out |
切分方式:`PerCategoryPoolStrategy``train_ratio=0.667`,按 correctness 分层。
## 3. 前置步骤
```
步骤 1: baseline infer
main.py --mode infer \
--questions generated-v2-360 \
--task-types "Action Recognition" \
--run-id v2ar_baseline
→ workspaces/default/harness.db 新增 30 题 predictions
步骤 2: create seed
2a. extract_run_db(
src_db="workspaces/default/harness.db",
dst_db="/tmp/v2ar_baseline.db",
run_id="infer_v2ar_baseline")
2b. init_seed(
store_dir=Path("store"),
name="v2ar-baseline",
skills_dir=Path("store/skills/v1"),
prompts_dir=Path("store/prompts/v1"),
baseline_db=Path("/tmp/v2ar_baseline.db"),
baseline_run_id="infer_v2ar_baseline",
parent=None,
description="v2-360 Action Recognition 30 题 baseline (skills/v1)")
→ store/seeds/v2ar-baseline/
步骤 3: fresh workspace
main.py --mode train --fresh \
--seed v2ar-baseline \
--run-id train_ar_v1 \
--config config/train_action_recognition.yaml
→ workspaces/train-action-recognition/
前提: workspaces/default/ 已存在(含 harness.db),步骤 1 复用该 workspace。
```
## 4. 训练配置
| 参数 | 值 | 理由 |
|------|-----|------|
| workspace_dir | workspaces/train-action-recognition | 独立 workspace |
| mode | train | 训练模式 |
| run_id | train_ar_v1 | 显式命名,observation 可追溯 |
| questions | generated-v2-360 | v2-360 题目集 |
| task_types | ["Action Recognition"] | 单题型 |
| pool_split_mode | per_category | 按类切分 |
| train_ratio | 0.667 | 20 train / 10 val |
| test_questions | benchmarks/Video-MME | test 池来源(过滤后 63 题) |
| run_holdout_eval | false | epoch 内跳过四向评估 + shadow_gate |
| epochs | 3 | 6 step + 3 轮慢更新 |
| batch_size | 10 | 20 题 / 2 batch per epoch |
| min_class_per_batch | 2 | 最小值 |
| concurrency | 24 | 推理并发 |
| max_steps | 40 | 沿用默认 |
| early_stop_patience | 4 | 3 epoch 内有意义 |
| use_slow_momentum | true | 验证 momentum |
| skill_mode | auto | 自动加载 skill |
其余 gate 参数沿用 `config/default.yaml` 默认值。
## 5. 训练循环预期
```
Epoch 1-3 每轮:
├── build_batches: 20 题 → 2 batch
├── Step 0: rollout → diagnose → evolve → CE-Gate
├── Step 1: rollout → diagnose → evolve → CE-Gate
└── Slow Update:
├── 全 val 重跑 (10 题)
├── probation 结算
├── best argmax
├── momentum
├── system/tool 慢更新
└── 四向 held-out: 跳过 (run_holdout_eval=false)
→ 同时跳过 _pick_mixed_best 的 shadow val 评估
收尾:
├── _deliver_best: manifest 指向最佳版本
└── _final_test_eval: test 池 63 题终评 (保留,仅跑 1 次)
```
预计 LLM 调用 ~500-600 次(去掉每 epoch 四向 held-out 后大幅减少)。
## 6. 代码修改
### 6.1 PerCategoryPoolStrategy test 池按 task_types 过滤
**问题**: `PerCategoryPoolStrategy.build()` Phase 4 加载 test 池时调用
`load_benchmark(config.test_questions_dir)` 会加载全部题目(如 Video-MME 900 题),
不受 `config.task_types` 过滤。而 train/val 在 Phase 1 已按 task_types 过滤,
test 池应保持一致。
**修改位置**: `app/harness/pools.py` `PerCategoryPoolStrategy.build()` Phase 4
**修改内容**:
```python
# Phase 4: test 池(从外部目录加载,无则空)
test: list[GeneratedQuestion] = []
if config.test_questions_dir is not None:
from app.question_gen import load_benchmark
test = load_benchmark(config.test_questions_dir)
# 与 train/val 的 Phase 1 过滤保持一致
if config.task_types is not None:
allowed = set(config.task_types)
test = [q for q in test if q.task_type in allowed]
```
**边界情况**:
- `config.task_types=None`(全题型): 不过滤,行为不变
- 过滤后 test 为空: 不报错(test 池可为空,`_final_test_eval` 会拿到空列表并跳过)
- 过滤后 test 仅含目标题型: 本次为 63 道 Action Recognition
**对 pools.json 冻结的影响**: test 池过滤后的结果写入 pools.json
resume 时直接加载无需重新过滤。fresh workspace 每次从头构建。
**测试**: 新增单测验证 test_questions_dir 混合题型时过滤正确。
### 6.2 RunConfig 新增 run_holdout_eval
**修改位置**: `app/harness/config.py` RunConfig 字段区
```python
run_holdout_eval: bool = True
```
**YAML 暴露**: 实验 YAML 中配置(科研实验参数归 YAML)。
**CLI 覆盖**: `main.py` 新增 `--no-run-holdout-eval` 标志,符合 CLAUDE.md §4.5
"CLI 仅用于单次临时覆盖"。
**Runner 修改**: `app/harness/runner.py` `_slow_update_cycle` Phase 9
```python
# Phase 9: epoch_report(保留)+ 四向 held-out(可选)
write_epoch_report(...)
if self._config.run_holdout_eval:
await self._holdout_four_way(...)
```
**副作用说明**: `run_holdout_eval=false` 同时跳过 `_pick_mixed_best`
shadow val 评估(`best_mixed` 版本选择)。首次试跑只看 `best_hard`
shadow/mixed 指标不需要。
**不影响**: `_final_test_eval` 不受此开关控制,训练结束后仍跑一次终评。
**测试**: 新增 runner 单测验证 `run_holdout_eval=false` 时跳过 `_holdout_four_way`
## 7. 观测产出
| 产出 | 位置 | 内容 |
|------|------|------|
| step 报告 | analyses/step_reports/ | 每步 gate 决策(accept/reject/skip |
| epoch 报告 | analyses/epoch_reports/ | 慢更新结果、best 变化 |
| dual_metric | harness.db dual_metric 表 | val 准确率变化 |
| skill 版本链 | skills/v1→v2→... | 可 diff 查看改动 |
| checkpoint | checkpoint.json | 断点续训支持 |
| 终评 | analyses/final_test_eval.json | test 63 题最终准确率 |
## 8. 非功能性需求
| 维度 | 必答问题 | 设计 |
|------|---------|------|
| 持久化 | 何时落盘?崩溃丢多少?覆盖还是追加? | predictions 逐题 INSERT 即时落库(追加);checkpoint 每 step 结束后原子写入(覆盖);崩溃最多丢当前 step 的推理结果,resume 从上一 step 重跑 |
| 幂等性 | 重复执行安全吗? | 同 seed + 同配置 + fresh → 确定性结果(RNG seed 固定);predictions INSERT OR IGNORE 防重复 |
| 断点续跑 | 中断后如何恢复? | `--resume` 读 checkpoint.json 的 epoch/step_completed/phase,从断点下一 step 继续;epoch_done 阶段恢复到下一 epoch 开头 |
| 原子性 | 部分写入会损坏数据吗? | checkpoint.json 整文件写入(非追加);predictions 逐条 commit 无事务风险;skills 版本目录先 copytree 再改 manifest 指针 |
## 9. 新增文件
- `config/train_action_recognition.yaml` — 实验配置
- `scripts/train_action_recognition.sh` — 自包含实验脚本(写死参数,零参数复现)