LeVJEPA README

The project's README from github.com/MLO-lab/LeVJEPA. As one markdown file: README.md.

LeVJEPA: Efficient & Scalable Video Pretraining without the Heuristics

Official implementation of LeVJEPA, the first video encoder trained under LeJEPA's collapse-free objective.

Lukas Kuhn, Lucas Maes, Giuseppe Serra, Quentin Le Lidec, Yann LeCun, Randall Balestriero, Florian Buettner

Paper on arXiv Project Page Model on Hugging Face

What is LeVJEPA?

Self-supervised video pretraining has so far relied on architectural machinery to avoid representation collapse: an EMA target encoder, a stop-gradient, a capacity-limited predictor (V-JEPA), or pixel-space reconstruction with a dedicated decoder (VideoMAE). LeVJEPA dispenses with all of it. A single encoder is trained with an invariance loss over global and local views of a clip, regularized by SIGReg (the Sketched Isotropic Gaussian Regularizer from LeJEPA), which constrains the embedding distribution to an isotropic Gaussian and thereby excludes collapse with a provable guarantee. The trainable architecture reduces to an encoder and a small projector, and the objective carries a single hyperparameter (λ = 0.02).

Because every operation contributes directly to the objective — there is no target-encoder forward pass and no predictor — the cost of a training step is governed only by the number of tokens the encoder observes. The paper develops two consequences of this:

Two further simplifications fall out of the same analysis: temporal patch aggregation at the input (tubelet 2) is unnecessary — per-frame tokenization matches or beats it at an equal token budget, including on motion-centric SSv2 — and dense, semantically organized patch representations emerge even though only the [cls] token is supervised, without the auxiliary patch-level objectives of prior work.

Results

All comparisons retrain the baselines on identical data with their official implementations, evaluated with frozen attentive probing following V-JEPA's protocol.

This repository contains the full pretraining recipe. The default configuration trains a ViT-B/16 on the Walking Tours dataset (Venkataramanan et al., Is ImageNet worth 1 video?, ICLR 2024), so you can reproduce video pretraining end to end from public data.

Pretrained checkpoint

If you just want features, skip the pretraining pipeline entirely: the ViT-L/16 from the data-scaling experiments is released as LeVJEPA-VideoMix-Large — 303M parameters, trained on VideoMix (1.8M clips from Kinetics-710, Something-Something v2, Walking Tours, and PE-Video) with tubelet 1, RoPE, and block-causal attention. It reaches 69.5% top-1 on ImageNet-1K and 55.0% on Something-Something-v2 under frozen attentive probing. The released tensors are the EMA copy of the encoder, which is what we evaluate.

import torch
from transformers import AutoModel

model = AutoModel.from_pretrained(
    "galilai-group/LeVJEPA-VideoMix-Large", trust_remote_code=True
).eval()

# (B, C, T, H, W), ImageNet-normalised, 16 frames at 224px
video = torch.randn(1, 3, 16, 224, 224)

with torch.no_grad():
    out = model(pixel_values=video)

out.last_hidden_state   # (1, 3137, 1024) -- CLS + 16*14*14 patch tokens
out["pooler_output"]    # (1, 1024)       -- the CLS token

trust_remote_code=True is required because the modeling code (RoPE + block-causal attention) ships with the weights. For a single image, repeat it along the temporal axis: image.unsqueeze(2).repeat(1, 1, 16, 1, 1). Two things to keep in mind: normalise with the ImageNet statistics (mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]; training sampled frames at ~7.5 fps, so 16 frames cover about two seconds), and leave config.attn_mode at its "block_causal" default — the weights were trained causal, and running them under full attention won't error but will quietly return worse features. The model card has the full usage guide and training details.

The checkpoint is intended for frozen feature extraction — attentive or linear probing, retrieval, or as a backbone for downstream heads; it is a self-supervised encoder with no classification head. Like module.py, the released weights are under CC BY-NC 4.0.

To see the features rather than just extract them, notebooks/feature_visualization.ipynb loads the checkpoint and reproduces the paper's dense-feature visualizations — patch-token PCA on images and query-patch cosine similarity on videos (uv sync --extra notebook, then uv run jupyter lab notebooks/feature_visualization.ipynb).

Setup

The project is managed with uv:

uv sync               # training environment (CUDA 12.8 wheels on Linux)
uv sync --extra data  # + decord/yt-dlp, needed only to build the dataset

Everything runs from the repo root; there is nothing to install as a package.

Getting Walking Tours

Walking Tours is 10 long (1-7 h) continuous first-person city walk videos. The HuggingFace dataset ships only the YouTube URLs, so the videos are downloaded from YouTube at 720p60 (25 GB) and then encoded into a frame-per-row Lance store at 15 fps, short edge 384, JPEG q90, in 128-frame episodes (33 GB):

# 1. download the 10 videos (needs outbound HTTPS; a login or data-transfer
#    node is fine, the step is network-bound)
bash scripts/download_walking_tours.sh

# 2. encode the Lance store (CPU-bound; use many cores)
uv run python scripts/build_lance_walking_tours.py --workers 16

On a slurm cluster, the same two steps as batch jobs (add your --partition/--account to the headers first):

dl=$(sbatch --parsable slurm/download_walking_tours.slurm)
sbatch --dependency=afterok:$dl slurm/build_walking_tours_lance.slurm

Both default to data/walking_tours/ under the repo root. To keep the data elsewhere, pass the paths explicitly and point training at it with LEVJEPA_DATA_ROOT=/path/to/data (the loader expects $LEVJEPA_DATA_ROOT/walking_tours/train.lance).

Training

If you'd rather start small, notebooks/training_workshop.ipynb walks through the whole method in miniature — building the model from this repo's components and training it inside the notebook on a few minutes of a Walking Tours video, with the same multi-crop transform and forward pass as the full pipeline. Both notebooks need only uv sync --extra notebook and run on a CUDA GPU, an Apple Silicon Mac (MPS), or plain CPU.

The full recipe lives in conf/config.yaml and follows our large-scale ViT-L video-mixture pretraining runs: ViT-B/16, 16-frame clips at stride 2 (7.5 fps), per-frame tokenization (tubelet 1) with 95% random token drop, block-causal attention, one global 224 crop + 10 local 96 crops, projector 256, SIGReg λ = 0.02 on the CLS token, effective batch 3072 clips (16 GPUs x 96 x grad-accum 2), lr 4e-4 with 1200-step warmup then flat, constant weight decay 0.04, and an EMA of the encoder saved into every checkpoint under state_dict_ema (evaluation checkpoint only — it plays no role in the objective). That is ~395 optimizer steps per epoch, so the default 26 epochs is ~10k steps; since the schedule is flat after warmup, trainer.max_epochs can be raised to train longer without changing anything else.

Token drop applies during training only — at 95% the encoder sees ~158 of the clip's 3137 tokens per step, which is what makes tubelet 1 affordable — while evaluation and inference always run on the full token set.

Slurm (2 nodes x 8 GPUs, matching the config defaults):

sbatch slurm/train_walking_tours_vitb.slurm

Single node x 8 GPUs — keep the effective batch by doubling the accumulation:

sbatch --nodes=1 slurm/train_walking_tours_vitb.slurm \
  trainer.num_nodes=1 accumulate_grad_batches=4

Locally (e.g. one GPU, for a smoke run — this changes the effective batch, so it is not the paper recipe):

uv run python main.py \
  trainer.devices=1 trainer.num_nodes=1 \
  loader.batch_size=8 loader.num_workers=6 accumulate_grad_batches=1

Any config key can be overridden the same way (optimizer.lr=2e-4, model.name=vit_large, ...). The encoder trains with the paper's block-causal attention by default; pass model.attn_mode=full for a fully bidirectional encoder. Hydra writes each run into outputs/<date>/<time>/, with checkpoints under checkpoints/ inside it. Logging goes to Weights & Biases when enabled: wandb.enabled=true wandb.config.entity=<you>.

To fine-tune or continue from a checkpoint with a fresh schedule, pass resume.ckpt_path=/path/to/last.ckpt (with the default resume.weights_only=true only the weights are loaded); set resume.weights_only=false to resume optimizer state and schedule as well.

Repository layout

Citation

@misc{kuhn2026levjepaefficientscalable,
      title={LeVJEPA: Efficient & Scalable Video Pretraining without the Heuristics}, 
      author={Lukas Kuhn and Lucas Maes and Giuseppe Serra and Quentin Le Lidec and Yann LeCun and Randall Balestriero and Florian Buettner},
      year={2026},
      eprint={2608.27395},
      archivePrefix={arXiv},
      primaryClass={cs.CV},
      url={https://arxiv.org/abs/2608.27395}, 
}

License

MIT (see LICENSE), except module.py, which is adapted from Meta's V-JEPA and remains under CC BY-NC 4.0.

LeVJEPA (MLO-lab/LeVJEPA)

Searching Database…

这是什么?LeVJEPA 的官方实现——一个用 LeJEPA 的无坍缩目标训练的自监督视频编码器。与 V-JEPA 或 VideoMAE 不同,它不需要 EMA 目标编码器、stop-gradient、预测器或像素重建解码器:只需要一个编码器、一个小投影头,以及一个损失超参数。
这是一个可以 pip 安装的库,还是需要自己运行的代码库?这是一个需要从仓库运行的研究代码库,不是可安装的包:环境由 uv 管理,训练通过 Hydra 入口(main.py)进行,另外还有两个 Jupyter 笔记本——一个用于特征可视化,另一个是带引导的迷你训练工作坊。
怎么把它跑起来?克隆仓库并运行 'uv sync'(需要笔记本就加上 '--extra notebook')。最快的上手方式是用已发布的权重:从 HuggingFace 加载 LeVJEPA-VideoMix-Large 并设置 trustremotecode=True,或者打开 notebooks/featurevisualization.ipynb 查看它的特征。
使用已发布的权重时有什么要注意的坑?有几个:由于建模代码随权重一起分发,需要设置 trustremotecode=True;输入是 16 帧(按 7.5 fps 算约 2 秒),使用 ImageNet 归一化,静态图像会沿时间轴重复;保留 blockcausal 注意力的默认设置——用全注意力虽然能跑,但会悄悄降低特征质量。
其中有不能商用的部分吗?仓库本身是 MIT,但 module.py(改编自 Meta 的 V-JEPA)和已发布的权重是 CC BY-NC 4.0——所以这几部分不能商用。
我可以不训练,直接下载预训练权重吗?可以——已发布 LeVJEPA-VideoMix-Large(ViT-L/16,3.03 亿参数),在来自 Kinetics-710、Something-Something v2、Walking Tours 和 PE-Video 的 180 万个片段上训练。在冻结注意力探测(frozen attentive probing)下,它在 ImageNet-1K 上达到 69.5% 的 top-1,在 SSv2 上达到 55.0%。它是为冻结特征提取设计的——没有分类头。
默认的训练配置用什么数据训练?默认配置用 Walking Tours 训练一个 ViT-B/16:从 YouTube 下载 10 段第一视角的城市漫步视频(每段 1-7 小时,720p60,约 25 GB),编码成约 33 GB 的 Lance 帧存储,因此预训练可以完全用公开数据端到端复现。换其他数据只需要在 conf/data/ 下加一个 yaml,做一个相同 schema 的 Lance 存储。
它和 V-JEPA 2 比怎么样?在相同轮数下,它在 ViT-S/B/L 上以少 5.6-20.8 倍的预训练总计算量持平或超越 V-JEPA 2——LeVJEPA 的 ViT-L 花的计算量不到 V-JEPA 2 的 ViT-S 的一半。在相同 FLOP 预算下(ViT-B),它在 ImageNet-1K 上领先 7.6 个百分点(61.0%),并拿下 Kinetics-400 线性探测的最佳成绩(44.6%)。
为什么训练时要丢掉 95% 的 patch token?在无坍缩目标下,丢 token 是一种数据增强而不是近似:均匀随机丢弃能单调提升冻结的 ImageNet 探测精度(保留全部 token 时是 33.9%,丢弃 95% 时升到 47.6%),同时把每步开销最多降低 20 倍;而结构化的 tube masking 反而有明显害处(从 50.7% 降到 39.6%)。
Creator
MLO-lab
Size
1.4 MB
Stars
270
Updated
CommitSep 02
Age
1mo
Commits · 90 Days