JEPA4Japan · 教程

第 22 章——Walking Tours:十段长视频怎样变成训练数据

1,252字 4分钟阅读 #LeVJEPA#JEPA#视频自监督学习#SIGReg

理解下载、15 fps 抽帧、Lance 存储、episode 边界、随机 clip 与数据成本。

课程进度 课程大纲 已发布 34/34 课

第 0 部分——先拿到地图

  1. 01 第 0 章——开始之前:这门课承诺什么 已发布
  2. 02 第 1 章——同一段视频,两扇不同的窗 已发布
  3. 03 第 2 章——沿着 Yann LeCun 的科研路线走一遍 已发布
  4. 04 第 3 章——别被名字绕晕:JEPA 家族树 已发布

第 1 部分——为什么简单目标会学会看视频

  1. 05 第 4 章——视频可以自己出题 已发布
  2. 06 第 5 章——保留意思,不重画每个像素 已发布
  3. 07 第 6 章——两张卡要相同,但不能全变成白纸 已发布
  4. 08 第 7 章——SIGReg:从许多影子检查一团点云 已发布
  5. 09 第 8 章——只用一行目标函数读懂 LeVJEPA 已发布

第 2 部分——把一段视频送进单编码器

  1. 10 第 9 章——全局视图与局部视图怎样配对 已发布
  2. 11 第 10 章——把视频切成时空小方块 已发布
  3. 12 第 11 章——一台编码器、一个投影头、一张摘要卡 已发布
  4. 13 第 12 章——一次完整前向传播 已发布
  5. 14 第 13 章——为什么扔掉 95% 反而更会看 已发布
  6. 15 第 14 章——块因果注意力:同一帧互看,未来不能偷看 已发布
  7. 16 第 15 章——RoPE、逐帧 token 与意外长出的密集特征 已发布

第 3 部分——会读实验,才算读懂论文

  1. 17 第 16 章——四组消融究竟回答了什么 已发布
  2. 18 第 17 章——相同轮数不等于相同花费 已发布
  3. 19 第 18 章——ImageNet、K400、SSv2 各考什么 已发布
  4. 20 第 19 章——把论文结果记成一本账 已发布
  5. 21 第 20 章——哪些结论现在还不能说 已发布

第 4 部分——从官方仓库到自己的实验

  1. 22 第 21 章——官方仓库地图 已发布
  2. 23 第 22 章——Walking Tours:十段长视频怎样变成训练数据 当前课程
  3. 24 第 23 章——读懂默认配置并启动训练 已发布
  4. 25 第 24 章——先跑一个不会骗人的冒烟测试 已发布
  5. 26 第 25 章——不用训练:加载公开权重提取特征 已发布
  6. 27 第 26 章——在自己的视频上做冻结评估 已发布

第 5 部分——把表征接回世界模型路线

  1. 28 第 27 章——重要边界:LeVJEPA 不是规划器 已发布
  2. 29 第 28 章——怎样把 LeVJEPA 接到下一代世界模型 已发布
  3. 30 第 29 章——十个从入门到论文级的研究项目 已发布

附录——随用随查的技术背包

  1. 31 附录 A——最低限度数学工具箱 已发布
  2. 32 附录 B——完整张量形状表 已发布
  3. 33 附录 C——术语表与论文时间线 已发布
  4. 34 附录 D——复现与审阅检查清单 已发布

十段长视频怎样变成两秒小片段

  1. 10 个链接长时城市漫步
  2. 下载720p 视频约 25 GB
  3. 抽帧15 fps、短边 384
  4. Lance约 33 GB 帧仓库
  5. 随机 clip16 帧约 2.1 秒
长视频不是直接塞给模型:先做有边界的帧仓库,训练时才抽一小段。

先装抽屉,再从抽屉里取照片

十本很厚的旅行相册不适合每次整本搬上桌。先按顺序把照片装进抽屉,每 128 张贴一个“同一段旅程”的标签。训练时随机选一个抽屉,隔一张取一张,共拿 16 张;这样既快,也不会误跨到下一段视频。

从十个 URL 走到 Lance 帧仓库

Walking Tours 数据集发布的是 YouTube URL,不是视频文件。冻结脚本下载十段约 1–7 小时的第一视角视频,优先取 720p60、无音频,总量约 25 GB。网络内容可能下架或受地区限制;下载前应确认来源条款、研究用途和本地剩余空间,建议为下载与约 33 GB 的 Lance 成品预留至少 70 GB。

uv sync --extra data
bash scripts/download_walking_tours.sh
uv run python scripts/build_lance_walking_tours.py --workers 16

第二步按每个源视频的实际帧率计算步长:九段约 60 fps,Wildlife 约 30 fps,统一存为约 15 fps。每帧缩到短边 384、JPEG quality 90;连续 128 帧成为约 8.5 秒的 episode。Lance 每行字段为 episode_idx:int32、step_idx:int32、frame:binary、h/w:int16、label:int16,无标签所以 label=-1。loader 靠连续的 episode 编号识别边界,因此行序一旦打乱,片段也会被错误合并或拆开。

构建器只写完整的 128 帧 episode,每段视频末尾不足 128 帧的尾巴不会写入。某个 episode 解码失败时会计入 failed 并跳过,成功 episode 再连续编号。因此“脚本退出码为 0”之外,还应保存十个下载文件的大小、源 URL、实际 fps、每视频 episode 数和最终 failed。日后源视频被替换时,这些就是判断数据是否还是同一份的指纹。

默认训练从 15 fps 仓库中取 num_frames=16、frame_stride=2,等效约 7.5 fps、覆盖约 2.1 秒。loader 把随机起点限制在同一个 episode 内,只读取被选中的行。配置注释记录作者当时构建得到 6,067 个 episode;网络源可能变化,所以本地日志才是这次数据版本的实际计数。

具体索引是 start + [0,2,4,…,30]。实现用 span=16×2=32 判断 episode 是否够长,默认 pad_short=false 会丢弃过短 episode;启用 padding 则重复最后一帧。每个有效 episode 在一个 epoch 被随机抽 clips_per_video=200 次,这扩充的是抽样次数,不是新增 200 个独立视频。近邻 clip 高度相关,若监督评估按 clip 随机切分,同一场景就可能同时出现在训练与测试;按源视频分组可以挡住这类泄漏。

数据放在别处时,可用环境变量告诉 loader 地址:

LEVJEPA_DATA_ROOT=/mnt/levjepa-data uv run python main.py --cfg job

loader 将寻找 $LEVJEPA_DATA_ROOT/walking_tours/train.lance。若输出目录已存在,构建脚本会主动停止;保留旧数据并换一个 --out 路径,比盲目删除安全。

打开仓库,数一数抽屉

uv run python - <<'PY'
import lance
ds = lance.dataset("data/walking_tours/train.lance")
print(ds.count_rows())
print(ds.schema)
PY

预期行数大于 0,schema 含上述六列。还要核对构建日志的 failed 为 0、episode_idx 有多个取值;仅看到一个巨大 episode 表示排序或索引坏了。

下载、构建与读取的路线图

把数据卡夹进实验记录

  1. Walking Tours 页面给 URL,下载脚本才取得约 25 GB 视频。
  2. 仓库按 15 fps、128 帧 episode 写 Lance;训练再以 stride 2 抽 16 帧。
  3. 约 33 GB 和 6,067 episodes 是作者快照,不是永远不变的保证。

检查有没有跨错抽屉

  1. 为什么 Wildlife 不能与 60 fps 视频使用同一个固定抽帧步长?
  2. 默认 16 帧训练 clip 大约覆盖多久?
  3. 为什么不能先把 Lance 行打乱再写入?
查看答案
  1. 它约为 30 fps;固定步长会让其存储帧率减半。
  2. 约 2.1 秒。
  3. loader 通过连续的 episode_idx 变化找边界,乱序会错误合并或拆分 episode。