gate 验证提速设计(v3):连续并发 gate + Redis 复用
2026-07-16。背景:Video-MME 900 训练实测,epoch 1 单题型 gate 双臂验证 ~3h(两臂串行 × 块串行 × 题型串行三重串行,~6 题型/step)→ step ~18h,3 epochs 不可行。v1 设计的"预灌 BaselineCache"经 Codex 审查发现统计致命伤已废弃(见 §7)。本版方案:②″ 连续并发 gate(题型并行 + 双臂并行 + 逐对连续早停,一次调度重构)+ ③ Redis 复用保障。统计内核(e-值公式、四出口、配对翻转、信息量阶梯、题尽/试用期通道)一行不动。
1. 统计合法性(②″ 的前提)
| 论点 |
依据 |
| 块=8 不是统计需要 |
TRM4 注释原文"块大小=推理并发度,块内跑满"——并发 8 时代的工程遗迹。e-process 为 anytime-valid 上鞅(Ville 不等式),在预先声明的样本顺序下任意时刻停下判定假阳率仍 ≤ 1/e_confirm;逐对判定是比逐块更细的合法 optional stopping |
| 统计消费必须按固定阶梯序前缀,不得按完成到达序(Codex v2 复审 C1) |
到达序消费不合法:base 臂可缓存命中瞬间返回、cand 臂必新鲜跑,两臂延迟不对称,配对完成时间由 cand 延迟主导;若 cand 延迟与对错相关(走满 40 步的慢轨迹更易错),早到翻转对系统性偏向 W 型 → e-值虚高 → 假接受。修法:推理全并发乱序执行,但 (W,L) 更新与 gate_decision 只在"阶梯序最长已配齐前缀"延伸时推进——判定顺序回到预先声明的阶梯序,无条件合法;INFRA 单元视为"已解决(剔除)"不阻塞前缀推进 |
| 冻结后 in-flight 结果丢弃合法 |
在固定前缀消费下,停止时刻 τ 之后的样本不进入统计是标准 optional stopping;丢弃不引入偏差(到达序消费下则不成立,故必须配合上一条) |
| 题型间并行无实质依赖 |
各题型 agent 只加载自己的 skill 文件(12 题型各有专属 .md),A 型 accept 改 A 的文件,对 B 型推理内容零影响。现行字母序滚动版本只是记账先后,非实质依赖。唯一共享文件 default-strategy.md 仅在题型缺专属文件时 fallback——本次 12 型全有专属文件,不触发;启动时 fail-fast 断言:同 step 内多个题型不得映射同一 target_file,违反即中止(RuntimeError,防未来配置漂移) |
2. 改动 ②″:连续并发 gate 调度器
2.1 新流程(替换 _gate_batch_skills 串行 for + validate.py 块循环)
2.2 保留与消解
| 项 |
处置 |
| e-值公式 / 四出口 / w_net_min / delta_min / lambda_dir / futility |
不动(判定函数 gate_decision 原样,只是调用时机从"每块末"变"每对完成") |
| 信息量阶梯出题 + 案例单元排除 + n_max=40 |
不动(发射顺序即阶梯序) |
| BaselineCache(miss 新鲜跑、INFRA 不写、内容寻址) |
不动(无预灌;epoch 1 冷缓存,base 臂新鲜跑但与所有臂共享并发池) |
| provisional → probation 试用 / epoch 末结算回滚 / cooldown / 黑名单 |
不动 |
gate_block=8 分块 |
消解删除(config 键与 validate 块循环一并移除;CLAUDE.md §4.7 #6 需在 commit 标注本次语义修订:块序贯 → 阶梯序前缀逐对序贯,判据不变) |
每块两个 run_id(_b{i}_base/_cand) |
替换为每臂一个 run_id(..._gate_{slug}_base / _cand)。溯源口径变化:predictions 不再携带块信息,gate_evidence 行以 ladder_rank(阶梯序号)替代 block_idx 补足调度溯源 |
| step 重跑幂等(修复现行潜伏 bug) |
现行 _run_step 只清 rollout run_id,gate 派生 run_id 的旧行从不清理,崩溃重跑会累积重复 predictions(HarnessLog 无主键去重)。新增:step 开始时一并清理 {step_run_id}_gate_% 的 predictions/traces 及该 (epoch, step) 的 gate_evidence / quadrant_pairs / step_report 旧行 |
| 断点粒度 |
明确声明:gate 内无断点(与现行块方案一致),checkpoint 仍为 step 粒度;崩溃重跑该 step 时由上一行的清理保证干净重放,Redis/BaselineCache 命中使重放近零成本 |
| n_remaining 口径 |
等价迁移:= 阶梯计划中前缀尚未消费的单元数;题尽判定与现行一致 |
2.3 INFRA 护栏(并行下的等价迁移)
现行:跨块累计 error 率,分母 ≥10 且 > gate_guard_err(0.10) → 中止训练。迁移为每题型运行时计数器:分子=该题型 INFRA 单元数(任一臂),分母=该题型已完成推理的单元次数(两臂各计,缓存命中不计),阈值与中止行为不变。判定在每次单元完成事件时检查,先于配对更新。
2.4 并发与调度事实
- 实现级约束(Codex I1):并发控制为 gate 调度器持有的单一共享
asyncio.Semaphore(concurrency),单元级推理任务在该信号量下执行;不得沿用"每次 run_inference 各建信号量"(否则并行臂叠加超限)。峰值在飞请求恒 ≤32
- 公平调度(Codex I2):任务发射严格按题型 round-robin 轮转(题型内按阶梯序),防止大题型占满槽饿死小题型;冻结题型立即停止补发
- 进化并行的并发契约(Codex I3):
GovernedLLMClient 已在 rollout 中承受 32 路并发调用(治理栈全线程/协程安全),6 路 gather 进化无新增风险;设计约束:Phase A-C 只读训练 state,Phase D 是唯一写 state 的阶段(probation/cooldown/rejected_buffer/changed_task_types 均在 Phase D 按字母序串行落账)
- 浪费上界:每题型判定瞬间 in-flight 的任务 ≤ 并发宽度;排队未启动的全部省下。相比"全发不早停"省 ~50-70% token,相比现行块早停多耗 ≤32 题次/题型
3. 改动 ③:Redis 复用保障
| 措施 |
说明 |
| 缓存键成分不动 |
消息内容(skills/prompts v1 正文、冻结题池、build_batches(seed=epoch) 确定性批次)与盐(run_id 派生自 infer_adhoc)零变化 → 重启后 rollout / 诊断 / 进化调用命中已写缓存 |
| gate 臂 run_id 变化的影响 |
②″ 将 _b{i}_base 改为 _base,今日旧 gate 调用(仅 Action Reasoning 部分块)的盐失配不复用——量小(~100 题次),可接受,如实记录 |
.env REDIS_CACHE_TTL 86400→604800 |
仅一行;只影响未来写入,保障多天训练中断重启后早期调用仍在 |
| 一次性续期今日键 |
重启前运行一次(运维动作,不入库代码):conda run -n Video-Tree-TRM python -c 连 .env 的 REDIS_URL,for k in scan_iter('llm_cache:*'): 0 < ttl(k) < 604800 and expire(k, 604800) |
| 复用边界(诚实声明) |
Agent 逐步追加 messages,某步 miss(如原调用 503 未入缓存 / TTL 过期)后该轨迹后续全 miss 并可能分叉——复用是"命中前缀零成本"的尽力而为,非全量保证。今日实测命中率 42% 佐证机制有效 |
4. 非功能四维
| 维度 |
保障 |
| 持久化 |
predictions/traces 逐题落库(HarnessLog 单连接+锁,不变);BaselineCache 逐条原子写(不变);判定即写 gate_evidence/step_report |
| 幂等 |
step 重跑前清 rollout run_id 及全部 gate 派生行(§2.2 修复项,现行代码只清前者);BaselineCache 同键同值重写无害 |
| 断点续跑 |
checkpoint 粒度仍为 step(gate 中途崩溃 → 重启重跑该 step,与现行一致);Redis/BaselineCache 命中使重跑近零成本 |
| 原子性 |
判定冻结为内存事件,落库单条原子;无跨文件半写窗口 |
5. 前序行为审计
| 现有行为 |
处置 |
| 题型串行 for(字母序滚动版本) |
替换:题型并行,accepts 按字母序统一合并(内容等价,记账顺序确定) |
| 进化串行 |
替换:题型间 gather 并行(rejected_buffer / budget per-type 独立,无共享) |
| 块序贯(8/块)+ 两臂串行 |
替换:逐对连续序贯 + 全臂共享并发池 |
| base 臂缓存 miss 新鲜跑 / INFRA 不写缓存 |
保留 |
| INFRA 护栏(分母≥10 且 >10% 中止) |
等价迁移(§2.3) |
| cooldown / skipped / 无改动跳过 + step_report |
保留 |
| gate_evidence / quadrant_pairs / candidate_correctness 增量合并 |
保留 |
| e-process 判定与四出口、题尽通道、probation |
不动 |
6. 测试
- 单测(调度器,注入假 run_inference 与可控延迟):
- 前缀有序性(核心):构造"阶梯尾部单元先完成"的乱序到达,断言 (W,L) 更新顺序严格等于阶梯序、前缀未齐时不判定;
- 同一组固定对错序列下,前缀逐对判定结果(action/W/L/E)与旧块序贯逐块判定一致(早停点可更早,判定方向一致);
- 过线后排队任务不再启动(计数断言),in-flight 结果不改变已冻结 (W,L);
- step 重跑幂等:预插旧 gate 行 → 重跑 step → 断言无重复行(C2 修复);
- fail-fast:两题型映射同一 target_file 时启动即报错;
- 题尽路径:单元耗尽 → 第四出口与现行一致;
- INFRA:单臂 INFRA 单元剔除不入配对,护栏计数阈值触发中止;
- 题型并行:两题型交错完成,互不污染彼此 (W,L) 与判定。
- 单测(进化并行):两题型 gather 进化,rejected_buffer 各自独立生效。
- 集成:小型真实 workspace 跑一个 step,断言 gate_evidence/step_report/quadrant_pairs 落库完整、accepts 正确推进版本。
- 回归:validate/gate_ladder/runner 现有测试全绿(块相关测试改写为连续语义)。
7. 已否决备选(含 v1 失败记录)
- ①(v1)预灌 BaselineCache:❌ 两个致命伤。(a) 统计:冷启动阶梯按 seed 基线"错题优先"选题,预灌使 base 臂 = 选题依据的同一份旧样本;对选中的 seed 错题 base 被钉死为错、新鲜 cand 以概率 p 答对 → W 系统性膨胀,候选无改进也会假接受。现行"miss 后新鲜跑"的测量-选题独立性是刻意设计,不可省。(b) resume 污染:预灌用"当前"skill 内容算 hash,resume 时已进化题型会把 v1 旧预测灌到新内容 hash 下,base 臂错误命中(Codex Critical ×2,均已验证)。
- 到达序消费配对(②″ 初稿):❌ base 缓存命中/cand 必新鲜跑的延迟不对称 + 对错-延迟相关,使早到翻转对偏向 W 型,e-值虚高假接受;改为阶梯序前缀消费(§1)。
- B. 小题型合并进化 default-strategy.md:future work。合并 gate 池(9+14+17+23=63 单元)可达正式接受线且信号更密,但存在子群伤害风险(平均变好掩盖单型受损)且叠加变量;本轮跑 A(小题型走 provisional+probation 通道),其结果作为 B 的对照证据。
- top-K 题型/step:用户否决,保留全部有错题型进化。
- 砍 gate_n_max / 放宽 e 阈值:动统计参数,收益已被 ②″ 覆盖。
- 块轮次锁步(②′):被更优的连续监控取代(锁步有轮末空转,连续无)。
8. 预期收益
| 项 |
现状 |
②″ 后 |
| step 内 gate(~6 题型) |
三重串行 ~9-18h |
共享 32 并发连续跑,~1.5-2.5h(≈总需题次×单题时长/32) |
| 进化阶段(~6 次 LLM) |
串行 ~30-60min |
并行 ~10min |
| 3 epochs(5 step/epoch + epoch 末 val/holdout) |
数天-一周 |
~1.5-2.5 天 |
改动面:app/harness/validate.py(块循环→连续调度器)、app/harness/runner.py(_gate_batch_skills 并行装配)、config(删 gate_block)、.env 一行、运维一次性续期。