Why this project
I wanted to understand JEPA (Joint-Embedding Predictive Architecture) by building one end to end, not by reading about it. Ball-in-cup was a deliberately unimportant proxy task. The point was the whole loop: self-supervised pretraining on pixels, checking what the latent space actually knows, and planning through the learned model. Solving the task at 97% was a bonus.
Architecture
z. Purely spatial.z for the cost.The loss is VICReg-style: prediction error plus variance and covariance terms against collapse, with no EMA target and no stop-gradient. Numerical gradient checks found a vanishing-gradient-at-collapse bug in the covariance term, fixed by square-rooting it before the penalty.
The drift problem
Planning needs long horizons, since the swing has to be pumped over 100+ steps. But feeding the predictor its own outputs made rollout error explode past 30–50 steps. The model had only ever been trained on real context windows (exposure bias).
Two changes fixed it together:
- Unrolled training loss. P is supervised on 5 successive self-fed predictions, not just one.
- Predictor stride. One P call advances 5 real control steps under a held action. This needed new action-repeat data, because the original data changed action every step.
After that, ball-position error stayed flat at about 0.08–0.11 m across the full 150-step horizon, with no compounding.
Results: 60% → 97%
Real closed-loop episodes against the simulator, random initial conditions, n=30 unless noted.
Three findings that mattered
- A better probe didn't help. The MLP probe cut per-frame position error from 0.083 m to 0.007 m, and closed-loop success didn't move (63% vs 67%, same at n=30). The cost only uses the difference between ball and cup positions, so shared decoding bias largely cancels.
- Failures weren't near-misses. Filmstrips of every failure showed the same thing: the ball still mid-swing at the cutoff. The planner re-randomised each step and kept abandoning damping trajectories. Carrying forward a slice of elites from every CEM iteration kept diversity and fixed most of it.
- The honest kind of retry. A real robot can't reroll an easier start. It can only keep acting from where it is. Doubling the time budget showed most "failures" were slow, not stuck. Several solved only after 12 s, some as late as 21.7 s.
What came next
A Gromov δ-hyperbolicity test on the trained latent space came out low (relative δ ≈ 0.15–0.27), even though it was trained with a plain Euclidean loss. That suggested the latent space already has tree-like structure, and led to the hyperbolic latent-space work.