vjepa2-cac / README.md
dobri420's picture
Update to iter-16300 (default) + iter-6200 best-val; new planning eval, training chart
f6ed49d verified
|
Raw
History Blame Contribute Delete
4.96 kB
---
library_name: vjepa2
tags:
- vjepa2
- world-model
- robotics
- droid
- action-conditioned
---
# CAC β€” from-scratch V-JEPA 2-AC predictor
A from-scratch reproduction of Meta's V-JEPA 2-AC action-conditioned predictor,
trained on H100s. This repo holds only the trained **predictor**; the frozen
V-JEPA 2 ViT-g encoder is not included β€” use Meta's `vjepa2_ac_vit_giant`
(torch.hub) for the encoder.
## Architecture
Meta's exact `src.models.ac_predictor.vit_ac_predictor` (from
[facebookresearch/vjepa2](https://github.com/facebookresearch/vjepa2)): 24
layers, 1024 dim, 16 heads, ~305M params, RoPE, frame-causal block attention,
action + state token conditioning (7-dim each). Identical to the shipped AC.
## Checkpoints
**Two** checkpoints are published from one continued run toward Meta's
94,500-iter recipe (still a snapshot, not the finished run):
| file | iter | held-out val cosine | note |
|---|---|---|---|
| `cac_fp32.safetensors` | **16,300** | 0.818 | default β€” the most-trained checkpoint |
| `cac_bestval_fp32.safetensors` | 6,200 | **0.824** | peak held-out val cosine of the run |
`--predictor cac` / `download_cac()` resolve to `cac_fp32.safetensors` (the
iter-16,300 model). Why both are published: see the val-cosine decline below.
## Training
Effective batch 256, LR 7.5e-5 β†’ 4.25e-4 β†’ 0 (WSD, scheduled over the full 94.5k
horizon), AdamW wd 0.04, bf16, `torch.compile`. Loss: L1 teacher-forcing + 2-step
autoregressive rollout (faithful port of Meta's `app/vjepa_droid/train.py`).
Data: ~51,000 DROID left-cam episodes (~58 h footage β€” essentially the full DROID
1.0.1 raw corpus), 8 frames @ 4 fps, 256 px; first 240 held out for eval.
Trained across three seamless resume segments: **1Γ—H100 to iter 2,800**, then
**2Γ—H100 DDP** to 5,800 and on to 16,300 (5.82 s/iter, ~1.98Γ— single-GPU β€” near
linear over NVLink). No loss spike across either resume boundary; the WSD LR
schedule continued on the 94.5k horizon throughout.
### The val-cosine decline (why two checkpoints)
![CAC combined training across 3 resume runs](cac-combined-16k.png)
Training L1 (teacher-forced + rollout) falls smoothly **1.02 β†’ ~0.28** across all
three runs. But held-out val cosine **peaks ~0.823 around iter 6,000 then slowly
declines to ~0.818 by iter 16,300**, while val held-out L1 drifts *up* β€” mild
overfitting on the encoder-dominated cosine metric. Cosine is a lenient proxy,
though; planning is the real test, and there the iter-6,200 and iter-16,300
checkpoints are **statistically indistinguishable** (see below). So the extra
~10k iters regressed the cheap metric at **no measurable planning cost** β€” hence
both checkpoints are shipped, for anyone who wants to probe the trade-off.
## Evaluation (240 held-out DROID episodes, frozen ViT-g)
Offline CEM planning gate (`plan --random-step`: CEM-planned action vs the true
logged action `a_t` from a random step), identical protocol for all three:
| model | plan L2 β†’ true ↓ | cos(plan, true) ↑ | beats random | points right |
|---|---|---|---|---|
| V-JEPA 2-AC (Meta) | **0.0396** | +0.650 | 93% | 90% |
| CAC iter 16,300 (this, default) | 0.0418 | +0.644 | 94% | 88% |
| CAC iter 6,200 (best-val) | 0.0446 | +0.648 | 92% | 87% |
- **CAC 16,300 vs 6,200**: paired Wilcoxon *p*=0.065 (L2), *p*=0.40 (cosine) over
238 paired episodes β€” a statistical tie. CEM's own sampling noise (~0.0003 on
L2 run-to-run) is a meaningful fraction of the gap.
- **vs Meta's AC** (trained ~16Γ— longer): AC still leads on plan L2, but the gap
is small and CAC matches it on direction cosine.
- Open-loop **prediction** cosine is β‰ˆ0.79 for CAC (mean over horizons) β€” it
plateaus early and, as the chart shows, is *not* a reliable planning proxy.
## Files
- `cac_fp32.safetensors` β€” predictor state_dict, fp32, 305M params, 300 tensors,
iter 16,300 (default). Safetensors metadata: `iter`, `architecture`.
- `cac_bestval_fp32.safetensors` β€” same format, iter 6,200 (peak val cosine).
Both load `strict=True` into `vit_ac_predictor(...)`.
## Load
```python
import torch
from huggingface_hub import hf_hub_download
from safetensors.torch import load_file
from src.models.ac_predictor import vit_ac_predictor
predictor = vit_ac_predictor(img_size=(256, 256), patch_size=16, num_frames=64,
tubelet_size=2, embed_dim=1408)
sd = load_file(hf_hub_download("dobri420/vjepa2-cac", "cac_fp32.safetensors"))
predictor.load_state_dict(sd, strict=True)
```
## Caveats
- Planning numbers are from a `--random-step` CEM gate on 240 held-out episodes;
they are a custom intermediate probe, not Meta's downstream real-robot success
metric.
- Train/eval split is index-based on DROID's deterministic institution ordering
(first 240 held out), so the eval set is institution-concentrated, not random.
- Trained on public DROID data using Meta's published recipe; independent
reproduction, not affiliated with Meta.