Files
icassp2027-experiment/docs/easycom_encoder_only.md
T

6.5 KiB
Raw Blame History

EasyCom:先跑 encoder-only A / V / AV 对照

复用已经提取的 Qwen 局部编码器特征,不输入 Thinker hidden states,不重提音频或视频, 不创建软链接。原 B1 的 audio / visual / av 分别是 G+A / G+V / G+A+V; 这里的新结果命名为 encoder_audio / encoder_visual / encoder_av,分别只有 A / V / AV。

固定训练 Session 4–12(升序,与原 B1 一致),测试 3/2/1;4 epochs、无 dev, 评测最后一轮。沿用原来的 5Hz 行索引、十个 horizon、LSTR-MCE 和 AP 协议,不改变标签。

已收到的 seed 0 结果与完整日志见 2026-08-28 实验记录。 其中完整曲线为 egospeak_full_timeline,此前主表为 causal_valid_only,两者分开记录。

1. 确定已经验证过的局部特征目录

用户已确认本次使用的实际目录是 /data1/yfzx/wangx/Datasets/easycom/omni_features/local_qwen_1s_encoded_tf4576, 不是早期默认的 local_qwen_1s;以下 checkpoint 读取方法可用于再次核对。

在 L20 机器更新本次代码后执行。下面从你之前跑完的 av_seed0.pth 读取实际路径, 避免猜错目录或混入 bbox 修正前的旧视觉特征;checkpoint 仅用于找路径,不作为新模型输入。

cd /data1/yfzx/wangx/Code/icassp2027-experiment
DATA_ROOT=/data1/yfzx/wangx/Datasets/easycom

LOCAL_ROOT=$(python - <<'PY'
from pathlib import Path
import torch

checkpoint = Path("checkpoints/easycom_local_b1_encoded_tf4576/av_seed0.pth")
p = torch.load(checkpoint, map_location="cpu", weights_only=False)
value = p["training_config"]["local_feature_root"]
if not value:
    raise ValueError("This checkpoint has no local-feature root")
root = Path(value).expanduser().resolve()
if not root.is_dir():
    raise FileNotFoundError(root)
print(root)
PY
) && printf 'LOCAL_ROOT=%s\n' "$LOCAL_ROOT"

如果 checkpoint 已移动,修改上述路径;也可以直接将 LOCAL_ROOT 设成以前 easycom_local_b1_encoded_tf4576 实验实际使用的局部特征目录。 必须包含完整的 Session_1.pt 到 Session_12.pt,不能用 local_smoke_encoded。 下面命令对空变量和缺文件会报错,不会自动重提特征或换成 Thinker 输入。

2. 先做 seed 0,三组前台顺序运行

单张空闲 L20 足够先跑这组小 head,无需启动八卡提取或安装新的依赖。 下面先 A、再 AV、最后 V;使用同一批冻结特征,仅改变输入模态。

(
  set -euo pipefail
  : "${DATA_ROOT:?Set DATA_ROOT first}"
  : "${LOCAL_ROOT:?Set the verified local-feature directory first}"
  export CUDA_VISIBLE_DEVICES=0
  export OMP_NUM_THREADS=4 MKL_NUM_THREADS=4 OPENBLAS_NUM_THREADS=4

  for modality in audio av visual
  do
    ENCODER_ROOT="${DATA_ROOT}/omni_features/encoder_only_${modality}_1s"

    python prepare_encoder_only_features.py \
      --dataset easycom \
      --data-root "$DATA_ROOT" \
      --local-feature-root "$LOCAL_ROOT" \
      --modalities "$modality" \
      --output-root "$ENCODER_ROOT"

    python run_easycom_encoder_only.py \
      --data-root "$DATA_ROOT" \
      --feature-root "$ENCODER_ROOT" \
      --modalities "$modality" \
      --seeds 0
  done
)

两条 Python 命令都支持 --dry-run。整理的 dry-run 只验证源文件,不生成训练输入; 训练的 dry-run 则需要已完成的导出目录,只打印训练/评测命令,不启动训练。

整理在 CPU 上完成:读取原生向量+有效性标志,校验全部 12 sessions、时间/索引、 配置一致性和 target 长度,逐文件保存,最后写出 complete.txt。 默认 target 是 $DATA_ROOT/easycom_target_frame,可用 --target-root 覆盖。 不使用 Ego4D manifest。新入口和 --dataset easycom 不影响已有 Ego4D 命令。

输出:

  • 特征:omni_features/encoder_only_audio_1s、encoder_only_av_1s、encoder_only_visual_1s。
  • 模型:checkpoints/easycom_encoder_only_1s/encoder_<modality>_seed0.pth。
  • 评测:results/easycom_encoder_only_1s/encoder_<modality>_seed0/metrics.json 和 pred/。

导出目录、checkpoint 或结果目录已存在时拒绝覆盖。不要重新跑整个循环来补 seeds; 保留已完成的导出,只运行下面的训练入口。 若某次导出中断、没有完成标记,请使用新的 --output-root,不要手动补标记。 训练中断后换新的 --checkpoint-root / --result-root;不会自动恢复半成品训练。

3. 打印结果,随后补 seed 1/2

python summarize_local_baselines.py \
  --root results/easycom_encoder_only_1s \
  --dataset easycom \
  --protocol causal_valid_only

请贴出三行 encoder_audio_seed0、encoder_av_seed0、encoder_visual_seed0。 原来的 81.72257 / 82.02661 / 73.47412 是 G+A / G+A+V / G+V 的 0.2s mAP, 不能标为 encoder-only。比较时使用相同 seed 和同一 causal_valid_only 协议。

第一轮确认能跑通后,补齐三个种子(不重新导出):

(
  set -euo pipefail
  : "${DATA_ROOT:?Set DATA_ROOT first}"
  export CUDA_VISIBLE_DEVICES=0
  export OMP_NUM_THREADS=4 MKL_NUM_THREADS=4 OPENBLAS_NUM_THREADS=4
  for modality in audio av visual
  do
    python run_easycom_encoder_only.py \
      --data-root "$DATA_ROOT" \
      --feature-root "${DATA_ROOT}/omni_features/encoder_only_${modality}_1s" \
      --modalities "$modality" \
      --seeds 1 2
  done
)

实验能回答什么

它测的是“Qwen 编码器近期 readout 本身的预测能力”,不是严格相同容量的 Thinker 消融。 3B 的 A/V 原生各 2048D;带有效性位后单模态 2049D、AV 4098D, 顺序是 [visual, visual_valid, audio, audio_valid]。不用 B1 的额外 256D 分支投影; 沿用原 MLP 类,隐藏宽度为输入维度整除 2,因此单模态 1024、AV 2049。 窗口、视觉 crop/视野和 head 参数量与原 Thinker 基线不同,应一起报告。

batch=512、lr=7e-5、weight_decay=5e-5、warmup_epochs=1.6、warmup_factor=0.3、 dropout=0.2、transition_objective=none。目录名 1s 不覆盖源文件的窗口配置, 真实窗口保存在导出 config.encoder_contract.config;时间含义完全沿用源特征。

本地 CPU 回归包括全部 12 sessions 的三模态导出、精确数值/时间对齐、缺文件和 partial 拒绝、 固定 split 顺序、无 Thinker 依赖,以及三个模态各 4 epochs 的合成数据训练/推理。 真实 EasyCom 精度和 L20 耗时由上述实验验证,不由这些测试推断。

python -m unittest -q test_easycom_encoder_only test_encoder_only_workflow