Add shared-AV multiwindow Qwen feature extraction

This commit is contained in:
Xin Wang
2026-09-17 03:00:05 +08:00
parent a9f748d6a6
commit 9bc89b556f
8 changed files with 971 additions and 6 deletions

View File

@@ -23,6 +23,7 @@ tests.
| Document | Use when |
|---|---|
| [`easycom_multiwindow_features.md`](easycom_multiwindow_features.md) | Shared-AV extraction of independent Qwen 2/4/6/8/10/12-second context banks, GPU smoke and matched head training |
| [`local_feature_baseline.md`](local_feature_baseline.md) | Extracting/validating EasyCom pooled local Qwen visual and audio sidecars |
| [`easycom_encoder_only.md`](easycom_encoder_only.md) | Comparing EasyCom Qwen encoder-only A/V/AV representations |
| [`ego4d_encoder_only.md`](ego4d_encoder_only.md) | Preparing and running the Ego4D encoder-only comparison |

View File

@@ -0,0 +1,151 @@
# EasyCom:一次共享 AV 提取,多种独立 context cap
状态:实现和 CPU 合成测试已通过;**未跑真实 Qwen GPU smoke、全量提取或训练**。
入口:[extract_easycom_multiwindow.py](../extract_easycom_multiwindow.py);
缓存实现:[streaming_turn_multiwindow.py](../streaming_turn_multiwindow.py)。
既有 [streaming_turn_model_directly.py](../streaming_turn_model_directly.py)
单窗口命令不变,也可直接传入 `--memory-seconds-list`。
## 实验契约
默认导出 2/4/6/8/10/12 s;2 s native block、5 Hz 截止时间、2 FPS 因果视觉网格、
observed partial tail;默认保存 last4 stack `[T,4,D]`。必须使用现有 Thinker replay
要求的 `transformers==4.52.3`,不能用局部 encoder 对 4.57.6 的兼容性替代它。
- 一次 session reader,共享每个截止点的 preprocessing、AV block/tail embeddings。
模型在所选 sessions 间只加载一次,所有缓存在 session 边界清空。
- **每个 cap 有独立 Thinker KV、滚动重建和 readout**。旧历史移出后,用缓存的
encoder embeddings 从空 Thinker KV 重放留下的完整 blocks。
不裁剪长窗口 KV 或 pooled state 来假装短窗口。
- 同一尾块仍随 200 ms 截止点增长并重编码;不是整个视频只编码一次。
六窗口生产 AV preparation 为 `T` 次,不是 `6T` 次;Thinker 成本仍按窗口增加。
`--verify-every` 额外从原媒体独立重放,不计入生产调用计数。
- Cap 是**最大呈现预算**,不是每行精确固定长度的滑窗。稳态 span 为
`cap - 2s + 当前 tail phase`,phase 在 0.2--2.0 s;startup 少于 cap。
例如 cutoff=20.6 s:cap=2/4/8/12 s 分别读取
`[20,20.6)` / `[18,20.6)` / `[14,20.6)` / `[10,20.6)`。
局部 A 都是 `[19.6,20.6)`;0.2 s horizon 都指向 20.8 s。
- Sessions 4--12 训练、1--3 测试。当前测试已多次查看,曲线如实标 exploratory;
不按测试涨点选择窗口、训练 epoch 或 early stopping。
- 同一份 1 s local sidecar 可复用,但其 dense rows、times、label indices、源媒体和
encoder contract 必须一致;加载失败不得 padding/clamp。
- 联合提取 wall time/显存不是单窗口流式效率。后者需单独运行所选 cap,测整个流水线。
## 1. 先跑 Session 4 的 24 s GPU smoke
从仓库根目录执行,路径自行设置,不使用某台机器的固定挂载。
24 s 会触发最大 12 s cap 的滚动重建;4 s smoke 不足以覆盖全部窗口。
```bash
MODEL_ID=/path/to/Qwen2.5-Omni-3B
VIDEO_ROOT=/path/to/easycom/Main/Video_Compressed
TARGET_ROOT=/path/to/EasyCom/target_perframe
MULTI_ROOT=/path/to/omni_features/qwen_multiwindow_2fps_last4_stack
CUDA_VISIBLE_DEVICES=0 python3 -u extract_easycom_multiwindow.py \
--model-id "$MODEL_ID" \
--easycom-video-root "$VIDEO_ROOT" \
--sessions Session_4 \
--memory-seconds-list 2 4 6 8 10 12 \
--end 24 --verify-every 11 \
--flash-attention-2 \
--output-root features/easycom_multiwindow_smoke
```
也可用 `--dataset-root /path/to/easycom` 代替 `--easycom-video-root`。
`--media-only` 只检验媒体/decoder、不加载模型、不写 features。
`--end` 是 bounded smoke,故即便给了 target root 也不附加整段 target;输出标记
`partial_extraction=true`,不能与整段 target/local sidecar 混用。
检查 shape、时间、freshness、预算、commit schedule 和独立 replay:
```bash
python3 - <<'PY'
from pathlib import Path
import torch
from local_turn_features import reference_alignment
root = Path("features/easycom_multiwindow_smoke")
for cap in (2, 4, 6, 8, 10, 12):
p = torch.load(root / f"context_{cap}s/Session_4.pt", map_location="cpu", weights_only=False)
times, indices = reference_alignment(p)
d = p["extraction_diagnostics"]
assert p["states"].ndim == 3 and p["states"].shape[:2] == (120, 4)
assert torch.isfinite(p["states"]).all()
assert torch.equal(times, d["state_source_times"])
assert d["state_age_seconds"].eq(0).all()
assert (d["actual_context_seconds"] <= cap + 1e-6).all()
assert d["payload_commit_mask"].nonzero().flatten().tolist() == list(range(9,120,10))
valid = indices[:, None] + torch.arange(1,11)[None, :] < len(times)
assert int(valid.all(dim=1).sum()) == p["valid_10_horizon_steps"] == 110
checks = [c for c in p["verification"] if c["kind"] == "cache_replay"]
assert len(checks) == 10
print(cap, tuple(p["states"].shape), "shared AV calls=", d["production_processor_calls_shared"],
"max_abs=", max(c["max_abs"] for c in checks),
"min_cosine=", min(c["cosine"] for c in checks))
PY
```
Same-segmentation `cache_replay` 应 exact/effectively exact;显著差异先排查,不开始全量。
若要核对既有单窗口生产路径,再运行相同媒体/参数的 `--memory-seconds 8 --end 24`
到另一目录,逐行比较其 states 与 `context_8s/Session_4.pt`。
CPU 测试已覆盖 >12 s 的滚动重建、可变 KV、从头 replay、future-only 合成输入改动、
跨调用 reset、last4/mean、CLI 单窗口兼容及 head/local 加载成功和失败路径;
这不能替代真实模型/媒体的因果 GPU 审计。
## 2. Smoke 审计通过后,一条命令提取所有 sessions
去掉 `--end`;完整目标长度和原始 20 FPS 视频帧数必须匹配。
默认 sessions 为 1--12,也可以先只提取训练侧。验证关闭以避免额外 reference 开销。
```bash
CUDA_VISIBLE_DEVICES=0 python3 -u extract_easycom_multiwindow.py \
--model-id "$MODEL_ID" \
--easycom-video-root "$VIDEO_ROOT" \
--target-root "$TARGET_ROOT" \
--memory-seconds-list 2 4 6 8 10 12 \
--flash-attention-2 \
--output-root "$MULTI_ROOT"
```
输出结构:每个 `context_2s/` ... `context_12s/` 含独立 `Session_1.pt` ...
`Session_12.pt`。每个 payload 仍是 `mode=open-stream-replay`,保留 model、source、
target、readout 和 sampling provenance,并记录 actual history range、phase boundary
和共享生产计数。`extraction_summary.json` 每完成一个 session 原子更新,记录本次调用的
sessions、输出 shape、cap、运行 commit/dirty 状态、依赖版本及联合耗时。
默认拒绝覆盖任一已有 bank。中断后检查文件;可用 `--sessions` 选择未完成 sessions,
或换新输出目录。**不实现 checkpoint resume**;显式 `--overwrite` 才会重跑/替换。
Summary 只描述本次调用,不能将上次与本次不同配置的输出默认为同一个实验。
联合保存每个文件原子替换,但六个文件不是跨文件事务;异常后仍需核查是否齐全。
## 3. 每种 cap 独立训练 G 或 G+A head
复用 [run_easycom_local_baselines.sh](../run_easycom_local_baselines.sh) 的固定四 epoch
recipe;不要复用 8 s head 到其他 cap 当作训练对照。
`audio` 表示 **G+A**,不是纯 audio-only。`LOCAL_ROOT` 指向已验证的 1 s local sidecar。
```bash
export TARGET_ROOT
export LOCAL_ROOT=/path/to/omni_features/local_qwen_1s
for cap in 2 4 6 8 10 12; do
CUDA_VISIBLE_DEVICES=0 \
FEATURE_ROOT="$MULTI_ROOT/context_${cap}s" \
CHECKPOINT_ROOT="checkpoints/easycom_context_${cap}s_2026-09-17" \
RESULT_ROOT="results/easycom_context_${cap}s_2026-09-17" \
bash run_easycom_local_baselines.sh audio 0 1 2
done
```
要检验 local A 是否缓解 context 敏感性,在相同 roots 下另外运行 `baseline 0 1 2`
(G-only);不要在已生成的 `audio_seedN` 路径重复启动。局部 V 是独立条件追加对照。
现有 driver 训练 4--12 后立即推理 1--3,因此开始整组运行前冻结分析方案。
报告完整预指定六-cap 曲线、dense 三类 AP/mAP、raw wearer endpoint onset/offset AP、
prevalence 和 common valid pairs;semantic ENTRY/YIELD 仍等标注审计。
CPU 回归命令:
```bash
python3 -m unittest test_streaming_multiwindow test_streaming_chunk_ablation \
test_easycom_head_objectives test_local_turn_features test_encoder_only_workflow
```

View File

@@ -1,7 +1,8 @@
# Local evidence analysis:待做实验日志
日期:2026-09-17。状态:**设计已记录,以下实验均未在本轮执行**。
只修改日志与手稿占位,不新增训练、提取或 evaluator 实现;未产生新的实测结果。
日期:2026-09-17。状态:**设计已记录,以下 GPU 实验均未在本轮执行**。
初始记录只修改日志与手稿占位;同日已追加多窗口提取实现和 CPU 测试,见文末。
未产生新的模型性能或 GPU 效率实测结果。
当前稿件边界见 [四页稿结构决策](manuscript_local_evidence_structure_2026-09-17.md)。
## 本轮决定与篇幅
@@ -47,7 +48,7 @@ MiniROADA stage-two continuation 不是 Omni LoRA,也不替代其适配对照
| L4 | 因果 current-activity classifier,当前预测概率重复至十个 horizon | Dense 收益是否主要是更好的当前状态识别? | Main Comparison TODO |
| T1 | 8-s cap 下 tail refresh × local A 的四组训练对照 | 两条最新证据路径互补,还是冗余? | Streaming 表上半部 |
| T2 | 同 block decomposition 从头 replay、future-only media intervention、cache reset;按十档 phase 分层 | cache 正确性与 tail-length dependence 是否成立? | Streaming TODO |
| C1 | 4/8/16-s cap 的 tail-aware G+A;按 cap 重提取并分别训练 | 历史长度是否影响主方法,8 s 是否是合理折中? | Streaming 表下半部 |
| C1 | 初始 4/8/16-s 计划已扩展为 2/4/6/8/10/12-s 共享提取、独立 tail-aware G+A 训练;16 s 暂不执行 | 历史长度是否影响主方法,8 s 是否是合理折中? | Streaming 表下半部;完整曲线留日志 |
| C2 | 仅当要声称 local 分支缓解窗口敏感性时,在各 cap 增加 G 对照 | 窗口能否替代近期证据?融合是否对 cap 更稳定? | 条件追加,不新增正文小节 |
| B0 | 审计各骨干的 causal readout、维度、刷新与实际历史范围;先短片 GPU smoke | 跨骨干样本和接口是否可比? | Setup / Backbone transfer 说明 |
| B1 | Qwen2.5-Omni 3B/7B 各跑 G 与 G+A,保持同一份 local A | 增量是否在同系列不同规模下保留? | Local Evidence + compact 表末三行 |
@@ -88,7 +89,8 @@ completed-only 未得到首个 state 的行在全部条件中统一处理并报
## 窗口与运行代价
C1 中 local A/V 固定 1 s,Omni cap 为预先指定的 4/8/16 s。各 cap 的 global state
C1 中 local A/V 固定 1 s;同日按用户确认将 Omni cap 改为 2/4/6/8/10/12 s,
暂不跑初始计划中的 16 s。六个 cap 均保留,不按测试 AP 再挑选长度。各 cap 的 global state
必须从对应因果输入提取,不能通过裁剪缓存向量伪造窗口。8-s cap 行与 T1-T-GA
复用同一个确切 run,不重复训练后择优填写两处。
固定 checkpoint 改 cap 若执行,单独标成 distribution-shift sensitivity;不能混入
@@ -197,3 +199,30 @@ metrics.csv,保留 provenance 与协议。正文替换 TODO/--,不要把 pen
同日追加 backbone-transfer 短段和三行增量空位后重新编译、渲染检查全部四页,
仍为四页含参考文献;链接、TeX/bib keys、单展示公式与 `git diff --check` 再次通过。
未修改旧运行或宣称跨骨干提取/对照已完成。
## 同日追加:C1 多窗口提取实现,GPU 实验仍 pending
用户确认“一条提取命令得到六个 cap 的特征,再分别训练”,已实现
[extract_easycom_multiwindow.py](../extract_easycom_multiwindow.py),
底层 [streaming_turn_multiwindow.py](../streaming_turn_multiwindow.py)。
共享 session reader、各 200 ms cutoff 的 AV preprocessing/encoder embeddings,
但每个 cap 独立 Thinker KV、滚动重建和 readout;绝不裁剪长窗口高层 KV 代替短窗口。
每个 `context_Cs/Session_N.pt` 是正常 `open-stream-replay` dense bank,
可复用同一份已验证的 1 s local sidecar 和现有四 epoch 训练脚本。
CPU 合成测试覆盖 24 s(含所有 cap 的滚动重建),逐点匹配六次单窗口生产提取;
AV 生产调用从 `6T` 降为共享 `T`,Thinker 仍逐 cap 执行。验证调用不计入该生产统计。
同时检查从原输入从头 replay、可变 KV 隔离、未来输入干预不回填过去、session reset、
last4 stack/mean、单窗口 CLI 兼容、head/local 成功与失败加载、输出覆盖防护。
既有 head objective、local feature、encoder-only 和 chunk-ablation CPU 回归通过。
实际时间轴 cutoff=20.6 s:cap=2/4/6/8/10/12 s 的 global history start 分别为
20/18/16/14/12/10 s;所有状态 source time=20.6 s,local A=[19.6,20.6),
0.2 s target=20.8 s。Cap 是 native-block 最大预算而非逐行精确固定长度滑窗;
必须同时记录 phase 和 actual context span。
尚未执行真实 Qwen/媒体 GPU smoke、全量提取、六-cap head 训练或吞吐/显存测量。
先用 Session 4 的 24 s smoke 检查六 bank shape/time/valid 与 independent replay,
再按 [多窗口运行手册](easycom_multiwindow_features.md) 提取所有 sessions。
联合多-bank 耗时不是单窗口在线效率;不能据 CPU 调用计数写性能增益或实时结论。
本次不修改 manuscript 数值或将 C1/T2/S1 标为 measured。