Add EasyCom encoder-only comparison workflow
This commit is contained in:
143
docs/easycom_encoder_only.md
Normal file
143
docs/easycom_encoder_only.md
Normal file
@@ -0,0 +1,143 @@
|
||||
# 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
|
||||
```
|
||||
Reference in New Issue
Block a user