Files
icassp2027-experiment/docs/easycom_multiwindow_features.md
T

7.8 KiB
Raw Blame History

EasyCom:一次共享 AV 提取,多种独立 context cap

状态:实现和 CPU 合成测试已通过;未跑真实 Qwen GPU smoke、全量提取或训练。 入口:extract_easycom_multiwindow.py; 缓存实现:streaming_turn_multiwindow.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 不足以覆盖全部窗口。

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:

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 开销。

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 的固定四 epoch recipe;不要复用 8 s head 到其他 cap 当作训练对照。 audio 表示 G+A,不是纯 audio-only。LOCAL_ROOT 指向已验证的 1 s local sidecar。

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 回归命令:

python3 -m unittest test_streaming_multiwindow test_streaming_chunk_ablation \
  test_easycom_head_objectives test_local_turn_features test_encoder_only_workflow