144 lines
6.1 KiB
Markdown
144 lines
6.1 KiB
Markdown
# 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 协议,不改变标签。
|
|||
|
|
|
|||
|
|
## 1. 确定已经验证过的局部特征目录
|
|||
|
|
|
|||
|
|
在 L20 机器更新本次代码后执行。下面从你之前跑完的 `av_seed0.pth` 读取实际路径,
|
|||
|
|
避免猜错目录或混入 bbox 修正前的旧视觉特征;checkpoint 仅用于找路径,不作为新模型输入。
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
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;使用同一批冻结特征,仅改变输入模态。
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
(
|
|||
|
|
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
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
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` 协议。
|
|||
|
|
|
|||
|
|
第一轮确认能跑通后,补齐三个种子(不重新导出):
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
(
|
|||
|
|
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 耗时由上述实验验证,不由这些测试推断。
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python -m unittest -q test_easycom_encoder_only test_encoder_only_workflow
|
|||
|
|
```
|