Files
icassp2027-experiment/docs/easycom_multiwindow_features.md

152 lines
7.8 KiB
Markdown
Raw Permalink 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.
# 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
```