课程进度 课程大纲 已发布 34/34 课
第 0 部分——先拿到地图
第 1 部分——为什么简单目标会学会看视频
第 2 部分——把一段视频送进单编码器
第 3 部分——会读实验,才算读懂论文
第 4 部分——从官方仓库到自己的实验
第 5 部分——把表征接回世界模型路线
附录——随用随查的技术背包
长跑之前,先过五道小门
- 形状每个箱子贴尺寸
- 有限值拒绝 NaN/Inf
- 梯度参数真的在动
- 不偷看未来不改过去 token
- 资源账显存与吞吐留档
新玩具火车第一次上轨,只需先走两圈:数一数车厢,看看轮子会不会转,确认红灯亮时能够停下。两圈顺利并不证明它能横跨全国,却能在昂贵长跑前找出接反的电线。
第一关:箱子的尺寸
loader(数据加载器)默认输出全局 [B,16,3,224,224]、局部 [B,10,16,3,96,96];main.py 才把轴换成 encoder 所需的 [B,C,T,H,W]。训练模式保留 5% patch 时,全局 16×14×14=3136 个 patch 约留 157 个,加 [CLS] 得 158 tokens;每张局部 16×6×6=576,约留 29 个,加 [CLS] 得 30。
第二、三关:数值有限,梯度在走
pred_loss、sigreg_loss 和总 loss 都应是有限数,也就是没有 NaN(非数)或 Inf(无穷大)。执行一次 backward() 后,encoder 与 projector 应至少各有一个非零、有限的梯度,证明参数确实收到了更新信号。
两个 batch 内的 loss 上下抖动很正常:随机 crop、随机投影和小 batch 都会带来噪声。做小批过拟合检查时,把同一批数据和 seed 固定下来,同时记录表示方差;若只见 MSE 变小,常量表示造成的坍塌也可能伪装成进步。
dtype(数值类型)的交接也要查。默认 normalize_on_gpu=true 时,worker 发送 uint8,以减少约四倍 host/IPC 内存;main.to_float_normalized() 随后才除以 255,并做 ImageNet 归一化。若 loader 已经输出 float,再归一化一次会悄悄破坏输入。抽一批打印 dtype、min/max 和 shape:uint8 应落在 [0,255],进入 encoder 前则应是有限的浮点数。global crop 只有空间裁剪与归一化,local 还会加入颜色抖动、灰度和翻转;两者的时间索引保持完全相同。
第四关:未来有没有漏进过去
以下测试无需数据或预训练权重。它只改变后两帧;如果块因果 mask 正常,前两帧的 patch token 应保持一致。[CLS] 会读取完整 clip,因此有意不放进这项比较。
uv run python - <<'PY'
import torch
from module import vit_tiny
torch.manual_seed(0)
m = vit_tiny(img_size=32, patch_size=16, num_frames=4, tubelet_size=1,
use_rope=True, token_drop_rate=0, attn_mode="block_causal").eval()
x = torch.randn(1, 3, 4, 32, 32)
y = x.clone(); y[:, :, 2:] = torch.randn_like(y[:, :, 2:])
with torch.inference_mode():
a, b = m(x), m(y)
d = (a[:, 1:9] - b[:, 1:9]).abs().max().item() # 前2帧×每帧4 patch
print(f"causal prefix max diff: {d:.3g}")
assert d < 1e-5
PY
第五关:资源账与有用的失败
记录峰值显存、每步时间与实际 token 数。遇到 OOM(显存不足),可以先减 batch_size、局部 crop 数或换 vit_tiny 来定位;这些改动会改变实验,日志里也要随之改名。worker 卡死时可试 loader.num_workers=0;出现 NaN 时,依次检查输入究竟是 uint8 还是已归一化 float、学习率、混合精度、SIGReg batch 与多卡同步。官方 training_workshop.ipynb 提供了更完整的小规模检查,可在 CUDA、MPS 或 CPU 上走通视图、模型、两项 loss 与分布图。
建议把通过条件写成机器可判定的断言:shape 完全相等;所有 loss/grad finite;固定批次 50–100 步后总 loss 的滑动均值低于开头且每维标准差没有整体趋零;因果 prefix 差小于容差;两次相同 seed 的首步 loss 可复现。SIGReg 每步都会重新抽随机方向,单点数值不应与参考日志逐位相等;真正异常是持续爆炸、为 NaN,或嵌入谱缩成近零。
调试时打开的三份原件
冒烟测试的验收合同
- loader 是
[B,T,C,H,W],encoder 是[B,C,T,H,W]。 - 因果测试比较 patch 前缀;全局
[CLS]本来就能看完整 clip。 - 两批训练成功只是冒烟通过,不是精度复现或独立验证。
给故障找对入口
- 默认全局视图训练时约输出多少 token?
- 为什么 MSE 降低还要同时看表示方差或 SIGReg?
- 修改未来帧时,是否要求
[CLS]不变?
诊断结果
- 约 158:157 个保留 patch 加一个
[CLS]。 - 因为所有输入映到同一点也能降低不变性 MSE。
- 不要求;它是读取整个 clip 的汇总 token,patch 才遵守逐帧因果前缀。