# 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 ```