Add AeroJEPA model + SuperWing tutorial recipe (experimental) - #1690
Conversation
Greptile SummaryThis PR introduces the AeroJEPA model — a Joint-Embedding Predictive Architecture for 3D aerodynamic surrogate modeling — along with all its building blocks (encoders, decoder, predictor, layers, losses) under
Important Files Changed
|
|
Hi @fgiral000, thanks for the PR! To keep PR size reviewable, would it be possible to: a) split this PR up into two separate PRs, one of which adds the model ("PR 1"), and a later follow-on that adds the example ("PR 2"). b) In PR 1, please re-use shared PhysicsNeMo tooling where possible. (E.g., c) All functions should use d) In PR 2, if possible, please add AeroJEPA as an example within |
|
Actually, it might be worth splitting out a third PR as well for addition of the SuperWing dataset utils. |
The training loop stacked every sample's loss and ran a single backward on the batch mean, keeping all sample autograd graphs alive until then, so peak memory scaled with batch size. Backward each sample's loss divided by the batch size inside the loop instead: mathematically identical to the batch-mean backward but only one sample graph is alive at a time. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
review) Validation runs on the EMA shadow weights, but the checkpoint saved the live training weights (ema.restore had already run), so the selected best checkpoint did not reproduce the reported val metric. Persist ema.shadow as the model state when EMA is enabled; it shadows the full state_dict, so it is a complete model state. The live optimizer/EMA state is still saved for resuming. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
…DIA#1690 review) Move the per-call TokenSet import to the module top, and document that the flat-to-grid reshape assumes the eval_full_grid_query query_pos is emitted in row-major (H, W) order (which the SuperWing dataset guarantees). Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
Fix the epochs comment to match the actual 200-epoch schedule, note that relative_mse_mode is ignored by the active relative_l2_mse blend, and drop the unused mask loss block. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
The normalization stats saved per-channel target_min/target_max, but nothing consumes them (the dataset z-scores targets with mean/std). Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
…A#1690 review) The decoder out_dim comment named the channels Cp, Cf_x, Cf_y while the target encoder and dataset use Cp, Cf_tau, Cf_z. Same three quantities; align the decoder comment to the canonical names. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
Note that the recipe currently trains on a single GPU and that multi-GPU / multi-node distributed training is planned as a follow-up. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
compute_latent_loss detached its target, a leftover from older research code that slipped in while porting the recipe to the PhysicsNeMo implementation. AeroJEPA's anti-collapse mechanism is the SIGReg regularizer, not EMA and stop-gradient, so the latent alignment term is meant to flow gradients into both the predictor and the target encoder. With the stray detach the target encoder got no signal from the alignment loss (reconstruction flows through the predictor output), leaving it shaped only by SIGReg. Drop the detach so the predictor and target encoder are trained jointly to agree in latent space, with SIGReg preventing the trivial constant-collapse solution. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
Restore the original two-phase schedule as an opt-in config: phase 1 trains the context + target encoders and the predictor in latent space (latent + SIGReg, decoder frozen, reconstruction off); phase 2 freezes the encoders and predictor and trains only the decoder to reconstruct the field from the frozen latents. Freezing is done via requires_grad on the single optimizer, and the decoder forward is skipped when the reconstruction weight is zero. Also add an optional SIGReg regularizer on the context latents (a separate module from the target-latent SIGReg), defaulting to weight 0 so it is off unless explicitly enabled. Disabled by default the training is a single phase with all loss terms active and every parameter trainable, matching the prior behaviour. Tests cover the target-encoder gradient flow, phase-1/phase-2 freezing, phase weight gating, phase resolution, and the context-SIGReg wiring. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
train.py had no way to load a checkpoint at startup. Add two optional, mutually exclusive modes: - training.resume: restore model + optimizer + LR scheduler + EMA + epoch and best-val counters and continue the schedule from where a run stopped. - training.init_from_checkpoint: start a new run from pretrained weights, loading the model weights only (fresh optimizer, epoch 0). With strict=false a checkpoint holding only a subset of modules loads those and leaves the rest at initialization; combined with two-phase training this trains a decoder on top of frozen pretrained encoders + predictor. Checkpoints now also record best_val_loss so a resumed run keeps its model selection. Both modes are off by default. Tests cover the weights-only init, the full resume, the fresh-start default, and non-strict subset loading. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
For rank-3 input with no mask, masked_mean reduced with mean(dim=1) and no keepdim, returning (B, F) while the docstring and the masked path return (B, 1, F). Add keepdim=True so both paths agree with the documented shape. No current caller relied on the (B, F) form. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
…1690 review) get_autocast_context can enable fp16 autocast, but the training loop stepped the optimizer with no GradScaler, so fp16 gradients could overflow to inf/nan and silently corrupt the weights. Add a GradScaler enabled only for fp16 on CUDA; for bf16 / fp32 / CPU it is disabled and every scaler call is a transparent no-op, leaving the default bf16 path unchanged. Gradients are unscaled before clipping so the clip norm is computed on true gradients. A new test runs one _run_epoch train step end-to-end through the scaler path. Signed-off-by: fgiral000 <fa.giral@alumnos.upm.es>
15b6607 to
e9f53a1
Compare
mnabian
left a comment
There was a problem hiding this comment.
LGTM now. Thanks for addressing all the comments!
|
/ok to test b0566e8 |
|
/ok to test afca308 |
PhysicsNeMo Pull Request
Description
Adds the AeroJEPA model and a SuperWing tutorial recipe under
physicsnemo.experimentalandexamples/cfd/external_aerodynamics/.AeroJEPA is a Joint-Embedding Predictive Architecture for 3D
aerodynamic surrogate modeling: instead of mapping geometry directly to
a flow field, it predicts a latent representation of the flow from a
latent representation of the geometry and operating conditions, and
reconstructs the field through a continuous implicit decoder when
needed (Giral et al., arXiv:2605.05586).
What this PR delivers:
physicsnemo.experimental.models.aerojepa.AeroJEPAcomposes a context encoder, a target encoder, a query-tokenfield decoder (collectively
AeroJEPATrunk), and a JEPA predictorhead (
PrototypeTokenJEPAHead) into a singlephysicsnemo.core.module.Module. The training path takes contextpositions/features, independent target encoder surface/volume inputs,
and operating conditions; the predictor predicts target tokens, and
the decoder evaluates the field at user-supplied query points.
predictis a no-grad inference wrapper;decode_field_chunkedsupports memory-bounded evaluation over very large query sets.
Concrete encoders (
ContextTransformer,TargetTransformer,PointTransformer), theQueryTokenDecoder, and the encoder ABCsare all exposed as composable components.
physicsnemo.experimental.models.aerojepa.layers.TokenSetandEncoderOutputtoken dataclasses, a deterministicFourierPositionalEncoding,ResidualMLP, theLocalPointTransformerBlock/LocalTokenCrossAttentionBlockattention blocks (with optional AdaLN / AdaLN-Zero conditioning), the
PointCloudTokenizer(seven center-selection strategies with k-NNcluster pooling), token batching / mask / k-NN helpers, and prototype
anchor build / load utilities.
TokenSetandEncoderOutputarere-exported from the model package for convenience.
physicsnemo.experimental.models.aerojepa.losses.SIGRegandTokenLatentSIGReg(a sketch isotropic-Gaussianregularizer for latent-token distributions, with a padding-aware
wrapper), the
flatten_valid_token_features/reshape_token_features_for_sigregmasking helpers, and thereconstruction loss family (
MSELoss/RelativeL2Loss/RelativeMSELoss/RelativeL2MSELoss, each with functional andnn.Moduleforms, optional per-channel weights stored as apersistent buffer, optional per-point weights, and an optional
validity mask).
examples/cfd/external_aerodynamics/aerojepa. End-to-end Hydra-drivenworkflow on the public SuperWing dataset (Yang et al.,
arXiv:2512.14397): dataset download via the Hugging Face Hub
(
yunplus/SuperWing), automatic split-by-geometry manifest andper-channel normalization stats, JEPA training (reconstruction +
latent + SIGReg with linear warmups; AdamW +
warmup-cosine; optional EMA), checkpointed inference with chunked
decoding, three-panel
GT | Pred | |Error|field plots for the threesurface channels (
Cp,Cf_tau,Cf_z), per-channel relative-L2 /RMSE / MAE metrics on the test split, and a pressure-only CL/CD
post-processor that integrates the surface field and emits a per-case
CSV plus a parity scatter.
Checklist
Tests
test/experimental/models/aerojepa/(constructor + attribute checks, non-regression shape checks on the
encoders, decoder, predictor, trunk, top-level model, layers, and
losses).
pytest test/experimental/models/aerojepa/ -qpasseslocally on CPU (~20 s).
train.py -> inference.py -> superwing_metrics -> superwing_forces.Training losses decrease monotonically; inference produces field
plots, per-case field-error metrics, and a force-coefficient parity
scatter.
Dependencies
No new core dependencies. The example recipe adds optional
example-side dependencies in
examples/cfd/external_aerodynamics/aerojepa/requirements.txt(Hugging Face Hub for the dataset download, plotting and
post-processing utilities). Pre-commit hooks,
ruff,interrogate,markdownlint, and the SPDX license check pass on every file in thePR.