Skip to content

Commit 1faaf6a

Browse files
paragaoKeitaW
andauthored
Add V-JEPA 2 (Meta FAIR) distributed training test case (#1035)
* Add V-JEPA 2 distributed training test case for p5en (H200) Add V-JEPA 2 (Meta FAIR) ViT-g/16 1B-param self-supervised video model as a new PyTorch test case with Slurm and Kubernetes support. Includes: - Dockerfile based on nvcr.io/nvidia/pytorch:25.03-py3 (CUDA 13 + Python 3.11) - Slurm sbatch scripts for benchmark (200 iters) and full pre-training (800 epochs) - Kubernetes PyTorchJob manifest for EKS clusters - Thin srun-compatible launcher (run_train.py) that calls app.vjepa.train.main() directly, avoiding the subprocess world_size=1 bug in app/main.py - Synthetic dataset generator for benchmarking without SSv2 download - SSv2 dataset preparation scripts and decord verification - YAML configs for ViT-g/16 with DDP, BF16, and activation checkpointing * Add V-JEPA 2.1 distributed training test case with image+video co-training Add V-JEPA 2.1 (Meta FAIR) ViT-g/16 1B-param benchmark alongside the existing V-JEPA 2 test case. V-JEPA 2.1 introduces Dense Predictive Loss, Deep Self-Supervision (4 intermediate layers), doubled predictor depth (24 vs 12), and image+video co-training with 50/50 rank split. Includes: - Dockerfile and Enroot container setup (shared base with V-JEPA 2) - Slurm sbatch scripts with /workspace code overlay for latest vjepa2 repo - Kubernetes PyTorchJob manifest for EKS clusters - Synthetic image generator for co-training benchmarks - run_train.py launcher using app.scaffold.main() for dynamic dispatch - YAML configs with img_data, img_mask, and rank_ratio settings Key discovery: the container must have the latest vjepa2 repo code (post March 2026) for app/vjepa_2_1/ to be available. The sbatch scripts mount updated code at /workspace to overlay the container's stale PYTHONPATH. * Add B200 (Blackwell) benchmark sbatch scripts for V-JEPA 2 and 2.1 The Dockerfile-based container (pytorch:25.03-py3) ships NCCL 2.25 and an older aws-ofi-nccl plugin that are incompatible with B200 EFA networking. The B200 scripts use a NeMo container with NCCL 2.29+ and a matching OFI/EFA/libfabric stack instead, with V-JEPA dependencies installed to shared storage and added to PYTHONPATH at runtime. * Increase synthetic dataset default to 50K for accurate benchmarks Benchmarking on B200 revealed that 5,000 synthetic samples caused frequent data loader re-initialization between epochs, inflating V-JEPA 2.1 iteration times by up to 4x (15,300ms vs 4,075ms with 50K samples). V-JEPA 2 was less affected but still improved from 1,637ms to 1,457ms. Changes: - Default synthetic video count: 5,000 -> 50,000 (both V-JEPA 2 and 2.1) - Default synthetic image count: 5,000 -> 50,000 (V-JEPA 2.1) - Add OpenCV (cv2) fallback for video generation in environments without ffmpeg - Add dataset sizing guidance to benchmark configs and READMEs * Add nsys profiling scripts for V-JEPA 2 and 2.1 on B200 Add rank-selective nsys profiling infrastructure: - nsys_wrapper.sh: profiles only rank 0 via SLURM_PROCID check - nsys_profile_b200.sbatch: configurable via NSYS_PROFILE_DIR and CONFIG env vars to save each optimization phase to a separate folder - Document profiling workflow in both READMEs * Add optimized config for V-JEPA 2 with torch.compile and no activation checkpointing Provide an optimized benchmark config for B200 GPUs: - compile_model: true for fused kernels (~20% GPU speedup) - use_activation_checkpointing: false (trades ~95 GB vs ~33 GB memory) - num_workers: 20 for higher data prefetch Tested at 1,125 ms/iter vs 1,457 ms baseline (23% improvement). * Disable GradScaler for BF16 training to remove unnecessary overhead BF16 has the same dynamic range as FP32, so GradScaler's loss scaling is pure overhead. Monkey-patch GradScaler to enabled=False in both run_train.py launchers when meta.dtype is bfloat16, eliminating the scale/unscale/step/update cycle per iteration. * Add FSDP training variant for V-JEPA 2.1 to reduce memory and enable higher throughput Replace DDP with FSDP (SHARD_GRAD_OP / ZeRO-2) for the encoder and target_encoder in V-JEPA 2.1, sharding gradients and optimizer states across ranks. This saves ~15 GB/GPU, enabling activation checkpointing to be disabled on B200 GPUs for higher throughput. The predictor remains DDP-wrapped (small model, needs find_unused_parameters). * Add optimization sweep, fix compile_model config bug, and enhance run_train.py - Fix compile_model placement: move from meta: to model: section where upstream train.py actually reads it (was silently never enabled) - Add env-var-driven optimizations to run_train.py: fused AdamW, TF32, compile mode override, gradient_as_bucket_view, prefetch_factor - Add B200 optimization sweep sbatch (Phase A-D with nsys profiling) - Add nsys profiling sbatch scripts for H200 (vjepa2 and vjepa2.1) - Fix container-workdir from /vjepa2 to /workspace in benchmark sbatch - Add .gitignore to exclude benchmarks/ and profiling/ from repo * Parallelize synthetic dataset generation scripts with --workers flag * Add V-JEPA 2.1 optimization sweep with phased configs and env-var hooks * Fix V-JEPA 2.1 batch sizes for rank_ratio=0.5 scaling and sbatch log paths * Remove incorrect MFU calculation from parse_benchmark.py and add --gpu_type flag The 6*N*D FLOP formula overestimates training FLOPs by ~2x for JEPA architectures because the context encoder only processes visible tokens (~15% of the sequence) while the target encoder runs forward-only (no backward pass). Replace with samples/sec as the primary throughput metric. Add --gpu_type flag (h200/b200) with correct BF16 peak specs (989.4 / 2250 TFLOPS). Fix V-JEPA 2.1 script title and update README parse examples to use new flag. * Fix PR review issues: NCCL_SOCKET_IFNAME, license headers, shell strictness, pinned versions - Remove ,eth from NCCL_SOCKET_IFNAME exclusion list for correct TCP bootstrap - Add missing MIT-0 license headers to .gitignore, README.md, and config YAMLs - Change set -ex to set -euo pipefail in all sbatch and shell scripts - Pin EFA_INSTALLER_VERSION to 1.47.0 in both Dockerfiles (was 'latest') - Replace :latest image tags with :vjepa2 and :vjepa2.1 in K8s manifests - Use yaml.SafeLoader instead of yaml.FullLoader in run_train.py and run_train_fsdp.py * Pin Dockerfile dependencies, fix stale repo URL, and pin vjepa2 git clone - Pin all pip packages to tested versions from cluster container freeze - Pin vjepa2 git clone to commit 204698b4 (latest as of Mar 23, 2026) - Fix stale repository URL from aws-samples to awslabs in both READMEs * Update 3.test_cases/pytorch/vjepa2.1/slurm/optim_sweep_b200.sbatch * Address PR review: deduplicate scripts, fix PYTHONPATH bug, move FSDP to experimental - Fix ${PYTHONPATH:-} in all B200 sbatch scripts to prevent unbound variable errors - Deduplicate shared scripts (5 files) in vjepa2.1/ with symlinks to vjepa2/ - Parameterize parse_benchmark.py with --model_name flag for both V-JEPA 2/2.1 - Remove optim_sweep_b200.sbatch (developer tooling with hardcoded internal paths) - Move FSDP code to experimental/ subdirectories (documented as ~2x slower than DDP) - Add explanatory comments to Dockerfile || true for libnccl-dev - Add B200 GPU setup prerequisites to both READMEs - Fix dead references to gitignored benchmarks/ directory * fix: address PR review - remove experimental FSDP, orphan configs, fix Dockerfiles - Remove experimental/ FSDP path (scripts, configs, slurm) from vjepa2.1 FSDP was benchmarked at ~2x slower than DDP; removed per reviewer request - Remove orphan phase configs (phase1, phase4) no longer used by any workflow - Fix Dockerfiles: remove || true on libnccl-dev install, add B200 note - Fix K8s image tags: use pinned commit hash (204698b4) instead of confusing repo:variant naming - Add mkdir -p for log directories in all sbatch scripts for consistency - Add directory structure note explaining vjepa2/ and vjepa2.1/ separation mirrors upstream facebookresearch/vjepa2 app structure - Fix README inconsistencies: remove benchmarks/ dir references (not committed), fix section numbering, fix batch size claim, update nsys examples --------- Co-authored-by: Keita Watanabe <mlkeita@amazon.com>
1 parent 45e8f55 commit 1faaf6a

39 files changed

Lines changed: 4088 additions & 0 deletions
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
# SPDX-License-Identifier: MIT-0
3+
4+
# Benchmark results and profiling data (published separately)
5+
benchmarks/
6+
profiling/
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
<!-- Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -->
2+
<!-- SPDX-License-Identifier: MIT-0 -->
3+
4+
# V-JEPA 2.1: Distributed Self-Supervised Video Pre-training
5+
6+
This test case demonstrates distributed pre-training of [V-JEPA 2.1](https://github.com/facebookresearch/vjepa2) (Meta FAIR) on AWS GPU clusters. V-JEPA 2.1 improves upon V-JEPA 2 with Dense Predictive Loss, Deep Self-Supervision, and image+video co-training to learn high-quality, temporally consistent dense features.
7+
8+
We benchmark the **ViT-g/16 (1B parameters)** encoder variant across 8 nodes of p5en.48xlarge instances (64 x NVIDIA H200 GPUs), with 50/50 image/video co-training.
9+
10+
> **Directory Structure Note**: V-JEPA 2 and V-JEPA 2.1 are maintained as
11+
> separate test case directories (`vjepa2/` and `vjepa2.1/`) to mirror the
12+
> upstream [facebookresearch/vjepa2](https://github.com/facebookresearch/vjepa2)
13+
> repository structure, where `app/vjepa/` and `app/vjepa_2_1/` are distinct
14+
> training applications with different model architectures, loss functions, and
15+
> data pipelines. They share the same codebase and container image, but their
16+
> configs, benchmarks, and launch patterns differ. Shared utility scripts are
17+
> symlinked from `vjepa2/scripts/` to avoid duplication.
18+
19+
| | |
20+
|---|---|
21+
| **Model** | V-JEPA 2.1 ViT-g/16 (1B params) |
22+
| **Framework** | PyTorch + DDP |
23+
| **Precision** | BF16 |
24+
| **Paper** | [arXiv:2603.14482](https://arxiv.org/abs/2603.14482) |
25+
| **Code** | [facebookresearch/vjepa2](https://github.com/facebookresearch/vjepa2) |
26+
27+
## What's New in V-JEPA 2.1 vs V-JEPA 2
28+
29+
| Feature | V-JEPA 2 | V-JEPA 2.1 |
30+
|---------|----------|------------|
31+
| Training data | Video only | Image + Video co-training (50/50 rank split) |
32+
| Loss | Masked-token prediction only | Dense Predictive Loss (all tokens contribute) |
33+
| Self-supervision | Single output layer | Deep: 4 intermediate layers concatenated |
34+
| Predictor depth | 12 | 24 (doubled) |
35+
| Context loss | None | Progressive warmup (0 -> 0.5 over iters 15k-30k) |
36+
| Modality embeddings | None | Separate image vs video embeddings |
37+
| Learning rate | 0.000525 | 0.0006 |
38+
39+
See also the [V-JEPA 2 test case](../vjepa2/) for the baseline benchmark.
40+
41+
## Prerequisites
42+
43+
- **Slurm cluster** on AWS with [Pyxis](https://github.com/NVIDIA/pyxis) and [Enroot](https://github.com/NVIDIA/enroot) for container support
44+
- **p5en.48xlarge** instances (or similar GPU instances with NVIDIA H200)
45+
- **EFA** (Elastic Fabric Adapter) networking enabled
46+
- **FSx for Lustre** shared filesystem mounted at `/fsx`
47+
- **Docker** installed on the cluster for building container images
48+
49+
## Shared Scripts
50+
51+
Several utility scripts (`generate_synthetic_dataset.py`, `nsys_wrapper.sh`, `prepare_ssv2.py`, `test_decord.py`) are shared with the [V-JEPA 2 test case](../vjepa2/) and symlinked from `../vjepa2/scripts/`. Ensure both directories are present when cloning.
52+
53+
## 1. Clone this repository
54+
55+
```bash
56+
git clone https://github.com/awslabs/awsome-distributed-training.git
57+
cd awsome-distributed-training/3.test_cases/pytorch/vjepa2.1
58+
```
59+
60+
## 2. Datasets
61+
62+
V-JEPA 2.1 co-trains on images and video simultaneously. With `rank_ratio: 0.5`, half the GPU ranks process images and half process video.
63+
64+
### Video: Something-Something v2 (SSv2)
65+
66+
See the [V-JEPA 2 test case](../vjepa2/README.md#2-dataset-something-something-v2-ssv2) for SSv2 download and preparation instructions.
67+
68+
### Images: ImageNet-1K
69+
70+
For full pre-training, V-JEPA 2.1 uses ImageNet-1K images. Prepare a CSV with `<image_path> <label>` format:
71+
72+
```
73+
/fsx/<your_username>/datasets/imagenet/train/n01440764/n01440764_18.JPEG 0
74+
/fsx/<your_username>/datasets/imagenet/train/n01440764/n01440764_36.JPEG 0
75+
...
76+
```
77+
78+
### Alternative: Synthetic Datasets (for benchmarking)
79+
80+
For benchmarking without real datasets, generate synthetic data for both modalities:
81+
82+
```bash
83+
# Synthetic video (reuse from V-JEPA 2 or generate new)
84+
srun -N1 --ntasks=1 --cpus-per-task=48 -p p5en \
85+
--container-image /fsx/<your_username>/vjepa2.1/vjepa2.sqsh \
86+
--container-mounts /fsx:/fsx \
87+
python /vjepa2/scripts/generate_synthetic_dataset.py \
88+
--output_dir /fsx/<your_username>/vjepa2.1/datasets/synthetic \
89+
--num_videos 50000
90+
91+
# Synthetic images
92+
srun -N1 --ntasks=1 --cpus-per-task=48 -p p5en \
93+
--container-image /fsx/<your_username>/vjepa2.1/vjepa2.sqsh \
94+
--container-mounts /fsx:/fsx \
95+
python /fsx/<your_username>/vjepa2.1/scripts/generate_synthetic_images.py \
96+
--output_dir /fsx/<your_username>/vjepa2.1/datasets/synthetic_images \
97+
--num_images 50000
98+
```
99+
100+
> **Note**: Use at least 50,000 videos and 50,000 images for reliable benchmark
101+
> numbers. With V-JEPA 2.1's rank_ratio=0.5 split, each rank sees only half
102+
> the dataset; smaller datasets (e.g. 5,000) cause frequent data loader
103+
> re-initialization that can inflate iteration times by up to 4x.
104+
105+
## 3. Build Container
106+
107+
V-JEPA 2.1 uses the **same container** as V-JEPA 2 (both apps live in the same repository). If you already have the V-JEPA 2 container, you can reuse it directly.
108+
109+
```bash
110+
docker build -t vjepa2 -f vjepa2_1.Dockerfile .
111+
enroot import dockerd://vjepa2
112+
mv vjepa2.sqsh /fsx/<your_username>/vjepa2.1/
113+
```
114+
115+
## 4. Update Configuration
116+
117+
Edit the config files under `configs/` to set paths for your environment:
118+
119+
```bash
120+
# In configs/benchmark-vitg-8nodes.yaml:
121+
# Update these paths:
122+
# folder: /fsx/<your_username>/vjepa2.1/benchmark/...
123+
# datasets: video CSV path
124+
# img_data.datasets: image CSV path
125+
126+
# Copy configs and scripts to shared storage:
127+
mkdir -p /fsx/<your_username>/vjepa2.1/{configs,scripts}
128+
cp configs/*.yaml /fsx/<your_username>/vjepa2.1/configs/
129+
cp scripts/run_train.py /fsx/<your_username>/vjepa2.1/scripts/
130+
```
131+
132+
The sbatch scripts use `${USER}` to construct paths automatically. If your layout differs, update `VJEPA21_DIR` in the sbatch files.
133+
134+
## 5. Run Benchmark
135+
136+
### Slurm
137+
138+
```bash
139+
mkdir -p logs/vjepa21_benchmark
140+
sbatch slurm/benchmark_training.sbatch
141+
```
142+
143+
Monitor the job:
144+
145+
```bash
146+
squeue -u $USER
147+
tail -f logs/vjepa21_benchmark/<JOB_ID>.out
148+
```
149+
150+
The benchmark runs 200 iterations across 8 nodes (64 GPUs). With `rank_ratio=0.5`, ranks 0-31 process images (batch size 72 per GPU) and ranks 32-63 process video (batch size 24 per GPU).
151+
152+
### Kubernetes
153+
154+
```bash
155+
kubectl apply -f kubernetes/vjepa2-1-benchmark.yaml
156+
kubectl logs -f pytorchjob/vjepa2-1-benchmark-worker-0
157+
```
158+
159+
## 6. B200 GPU Setup
160+
161+
The standard container (based on `pytorch:25.03-py3`) ships NCCL 2.25 and an older aws-ofi-nccl plugin that are **incompatible with B200 EFA networking**. B200 scripts use a NeMo container with NCCL >= 2.29 instead. See the [V-JEPA 2 B200 setup](../vjepa2/README.md#7-b200-gpu-setup) for full prerequisite instructions.
162+
163+
## 7. Parse Results
164+
165+
```bash
166+
python scripts/parse_benchmark.py \
167+
--log_file logs/vjepa21_benchmark/<JOB_ID>.out \
168+
--warmup_iters 20 \
169+
--batch_size_per_gpu 24 \
170+
--num_gpus 64 \
171+
--gpu_type h200
172+
```
173+
174+
## Architecture Notes
175+
176+
### Launch pattern
177+
178+
Same as V-JEPA 2: **`srun` directly** (not `srun + torchrun`). The `run_train.py` launcher uses `app.scaffold.main()` which reads the `app: vjepa_2_1` field from the config to dispatch to `app.vjepa_2_1.train.main()`.
179+
180+
### Image/Video co-training rank split
181+
182+
With `img_data.rank_ratio: 0.5` on 64 GPUs:
183+
- **Ranks 0-31** (32 GPUs): process images, batch size 72/GPU = 2,304 images/step
184+
- **Ranks 32-63** (32 GPUs): process video, batch size 24/GPU = 768 videos/step
185+
186+
The code automatically adjusts the per-GPU video batch size to maintain the configured global batch size across the reduced number of video ranks. Each rank creates a single data loader for its assigned modality.
187+
188+
### GradScaler and BF16
189+
190+
The upstream V-JEPA 2/2.1 code unconditionally creates a `torch.cuda.amp.GradScaler()` for mixed-precision training. GradScaler is designed for FP16, where the narrow dynamic range can cause gradient underflow. BF16 has the same dynamic range as FP32, making the scale/unscale/step/update cycle pure overhead. The `run_train.py` launcher monkey-patches `GradScaler` to a no-op (`enabled=False`) when BF16 is configured, removing this unnecessary work.
191+
192+
### Model architecture
193+
194+
V-JEPA 2.1 ViT-g/16:
195+
- **Encoder**: ViT-giant with `embed_dim=1408, depth=40, num_heads=22`
196+
- **Predictor**: `depth=24, embed_dim=384, num_heads=12` (doubled from V-JEPA 2)
197+
- **Deep Self-Supervision**: 4 intermediate layers (9, 19, 29, 39) concatenated -> `[B, N, 5632]`
198+
- **Input**: 16 frames at 256x256 (video) or 1 frame at 256x256 (image)
199+
- Uses `DistributedDataParallel` with EMA target encoder
200+
- Activation checkpointing and BF16 mixed precision enabled
201+
202+
## 8. Profiling with nsys
203+
204+
Profile the training loop with NVIDIA Nsight Systems to identify GPU kernel bottlenecks, memory allocation patterns, and communication overhead. Only rank 0 is profiled to keep output sizes manageable.
205+
206+
```bash
207+
mkdir -p logs/vjepa21_nsys
208+
209+
# Baseline profile
210+
sbatch slurm/nsys_profile_b200.sbatch
211+
212+
# Profile a specific config (e.g. optimized)
213+
NSYS_PROFILE_DIR=optimized \
214+
CONFIG=/fsx/${USER}/vjepa2.1/configs/benchmark-vitg-8nodes-optimized.yaml \
215+
sbatch slurm/nsys_profile_b200.sbatch
216+
```
217+
218+
Profiles are saved to `/fsx/${USER}/vjepa2.1/nsys/<profile_dir>/rank0.nsys-rep`. Open them with `nsys-ui` or download locally for analysis. Each optimization phase should use a different `NSYS_PROFILE_DIR` to keep profiles organized:
219+
220+
```
221+
nsys/
222+
├── baseline/ # Un-optimized baseline
223+
├── optimized/ # torch.compile + no activation checkpointing
224+
└── ...
225+
```
226+
227+
## Benchmark Results
228+
229+
Use `scripts/parse_benchmark.py` to produce benchmark results from training logs. See Section 7 (Parse Results) for usage examples.
230+
231+
### Data Loading Optimization (TorchCodec)
232+
233+
The TorchCodec data loading optimization developed for V-JEPA 2 applies directly to V-JEPA 2.1 — both models use the same `run_train.py` launcher with environment-variable-controlled patches. On B200, where data loading accounts for 44% of iteration time, this optimization is critical.
234+
235+
Enable in your sbatch script:
236+
237+
```bash
238+
export VJEPA_USE_TORCHCODEC=1 # Replace decord with TorchCodec
239+
export VJEPA_CYCLING_SAMPLER=1 # Eliminate epoch boundary stalls (36.5% wall time improvement on B200)
240+
```
241+
242+
The cycling sampler alone (without TorchCodec) already provides a **36.5% reduction** in per-iteration wall time on B200 by eliminating epoch boundary stalls where ranks wait for the slowest data loader to reinitialize. Combined with TorchCodec and increased workers (`num_workers: 16`), data loading time is expected to drop by 80%+ on B200.
243+
244+
See the [V-JEPA 2 README Section 10](../vjepa2/README.md#10-data-loading-optimization-torchcodec) for installation instructions and full details.
245+
246+
## References
247+
248+
- **V-JEPA 2.1 Paper**: [Unlocking Dense Features in Video Self-Supervised Learning](https://arxiv.org/abs/2603.14482)
249+
- **V-JEPA 2 Paper**: [Self-Supervised Video Models Enable Understanding, Prediction and Planning](https://arxiv.org/abs/2506.09985)
250+
- **Code**: [github.com/facebookresearch/vjepa2](https://github.com/facebookresearch/vjepa2)
251+
- **Blog**: [ai.meta.com/blog/v-jepa-2-world-model-benchmarks](https://ai.meta.com/blog/v-jepa-2-world-model-benchmarks)

0 commit comments

Comments
 (0)