API Reference¶
Hybrid Model¶
Ensemble module: HybridModel combining neural networks and physics solvers.
- class adeptml.ensemble.HybridModel(*args: Any, **kwargs: Any)[source]¶
Torch module for serial hybrid physics-informed models.
Combines neural network modules (MLPs, custom
torch.nn.Modulesubclasses) with non-differentiable physics models in a single differentiable computation graph. Models are executed in the insertion order ofconfig.models.- Parameters:
config (HybridConfig) – Configuration object specifying all sub-models and optional input routing. See
HybridConfigfor details.
Examples
Serial NN → physics pipeline:
cfg = HybridConfig(models={"nn": mlp_cfg, "physics": phy_cfg}) model = HybridModel(cfg) out = model(x, phy_args=[arg1, arg2])
Custom input routing — pass original input to the physics model regardless of what the NN outputs:
cfg = HybridConfig( models={"nn": mlp_cfg, "physics": phy_cfg}, model_inputs={"physics": {"Input": None, "nn": None}}, )
- forward(x, phy_args=None)[source]¶
Run inference on the hybrid model.
- Parameters:
x (torch.Tensor) – Input tensor
(batch, in_dim).phy_args – Extra positional arguments forwarded to physics sub-models (e.g.
[arg1, arg2]). May be a list of tensors orNone.
- Returns:
Output of the final model in the pipeline.
- Return type:
torch.Tensor
Models¶
AdePT-ML provides three autograd-compatible wrappers for non-differentiable physics functions, differentiated by how gradients are computed during the backward pass:
Class |
|
|
|---|---|---|
|
|
|
|
|
|
|
not used |
When to use each:
Use
Physicswhen the full Jacobian is cheap or already available (e.g. small output dimension, analytical Jacobian).Use
Physics_VJPwhen a manual VJP avoids materialising the full Jacobian (e.g. adjoint method, large output dim).Use
Physics_SplitVJPwhen the physics solver already produces a pullback closure during the forward pass (e.g. viajax.vjp). This is the most memory-efficient option because no part of the physics forward is re-run during backpropagation.Example with a JAX solver:
from my_physics import physics_forward # physics_forward(x, *args) -> (y, pullback_fn) phy_cfg = PhysicsConfig( forward_func=physics_forward, use_split_vjp=True, )
- class adeptml.models.MLP(*args: Any, **kwargs: Any)[source]¶
Multilayer Perceptron (MLP) neural network model.
Note
This class implements a Multilayer Perceptron (MLP) neural network model. It takes a configuration dataclass with parameters such as hidden layer size, input and output dimensions, number of hidden layers, and activation functions.
- class adeptml.models.Physics(*args: Any, **kwargs: Any)[source]¶
Custom autograd function wrapping a physics model with a full Jacobian.
The backward pass materialises the full
(batch, out, in)Jacobian and contracts it with the upstream gradient via a batched matrix-vector product. UsePhysics_VJPwhen a manual VJP is cheaper than the full Jacobian, orPhysics_SplitVJPwhen the physics solver already produces a pullback closure (e.g. viajax.vjp).See also
- static forward(ctx, x: torch.Tensor, forward_fun: Callable, jacobian_fun: Callable, args: List[torch.Tensor] | None = None)[source]¶
Run the physics forward pass.
- Parameters:
ctx – PyTorch autograd context.
x – Input tensor
(batch, in_dim).forward_fun – Physics function
(x_np, *args_np) -> ndarray.jacobian_fun – Jacobian function
(x_np, *args_np) -> ndarraywith shape(batch, out_dim, in_dim).args – Extra positional arguments passed to
forward_funandjacobian_fun. Gradients are not computed w.r.t. these.
- Returns:
Output tensor
(batch, out_dim).- Return type:
torch.Tensor
- class adeptml.models.Physics_SplitVJP(*args: Any, **kwargs: Any)[source]¶
Custom autograd function for physics models that expose a pullback closure.
This mode supports
forward_funcfunctions that return both the output and a pullback closure — the pattern produced byjax.vjp:y, pullback_fn = forward_func(x, *args) # later, during backward: (dx, *_) = pullback_fn(grad_output)
The pullback closure is stored in the autograd context during the forward pass and invoked during the backward pass. No part of the physics forward is re-executed during backpropagation, making this the most memory-efficient mode when the solver is expensive and already caches its intermediates (e.g. via
jax.checkpointinsidejax.vjp).jacobian_funcis not used in this mode and should be omitted fromPhysicsConfig.Example
Given the JAX physics module:
from Funcs import physics # physics(x)-> (y_normalized, pullback_fn)
Configure and use as:
from adeptml.configs import PhysicsConfig, HybridConfig from adeptml.ensemble import HybridModel phy_cfg = PhysicsConfig( forward_func=physics, use_split_vjp=True, ) hybrid_cfg = HybridConfig(models={"nn": mlp_cfg, "physics": phy_cfg}) model = HybridModel(hybrid_cfg) # During training the pullback is cached automatically; no extra code # is needed in the training loop.
See also
- static backward(ctx, grad_output)[source]¶
Call the stored pullback closure with the upstream gradient.
The cotangent for
xispullback_fn(grad_output)[0]; cotangents forforward_funandargsareNone.
- static forward(ctx, x: torch.Tensor, forward_fun: Callable, args: List[torch.Tensor] | None = None)[source]¶
Run the split-VJP physics forward pass.
Calls
forward_fun(x_np, *args_np)which must return(output_np, pullback_fn). The pullback is stored inctxfor use duringbackward().- Parameters:
ctx – PyTorch autograd context.
x – Input tensor
(batch, in_dim).forward_fun – Split-VJP physics function
(x_np, *args_np) -> (ndarray, callable).args – Extra positional arguments (e.g. boundary conditions, initial conditions, simulation time). Gradients are not computed w.r.t. these.
- Returns:
Output tensor
(batch, out_dim).- Return type:
torch.Tensor
- class adeptml.models.Physics_VJP(*args: Any, **kwargs: Any)[source]¶
Custom autograd function wrapping a physics model with a manual VJP.
Unlike
Physics, the backward pass delegates to a user-suppliedjacobian_func(x, grad_output, *args) -> ndarraythat returns the VJP directly, avoiding explicit Jacobian materialisation.See also
- static backward(ctx, grad_output)[source]¶
Compute VJP by calling the user-supplied VJP function directly.
- static forward(ctx, x: torch.Tensor, forward_fun: Callable, jacobian_fun: Callable, args: List[torch.Tensor] | None = None)[source]¶
Run the physics forward pass.
- Parameters:
ctx – PyTorch autograd context.
x – Input tensor
(batch, in_dim).forward_fun – Physics function
(x_np, *args_np) -> ndarray.jacobian_fun – VJP function
(x_np, grad_output_np, *args_np) -> ndarraywith shape(batch, in_dim).args – Extra positional arguments. Gradients are not computed w.r.t. these.
- Returns:
Output tensor
(batch, out_dim).- Return type:
torch.Tensor
Configs¶
- class adeptml.configs.HybridConfig(models: dict[str, MLPConfig | PhysicsConfig | torch.nn.Module], model_inputs: dict[str, dict[str, list[int] | None]] | None = None)[source]¶
Configuration for Hybrid (ensemble) models.
- models¶
Maps model names (str) to a
ModelConfigor an existingtorch.nn.Module. Models are executed in insertion order.- Type:
dict
- model_inputs¶
By default the ensemble runs sequentially — the output of each model becomes the input of the next. Setting this dict overrides that behaviour for specific models.
Keys are model names; values are dicts mapping source model names to dimension selectors:
None— pass the entire source tensor.[int, ...]— pass only the listed dimensions (tensor[:, dims]).
Use the special key
"Input"to reference the original input toHybridModel.forward().Example — concatenate dims 0-3 of the original input with the full output of
"mlp1":model_inputs={ "physics": { "Input": [0, 1, 2, 3], "mlp1": None, } }
- Type:
dict, optional
- class adeptml.configs.MLPConfig(num_input_dim: int, num_hidden_dim: int, num_output_dim: int, num_hidden_layers: int, hidden_activation: str, output_activation: str)[source]¶
Configuration class for the Multilayer Perceptron (MLP) model.
- num_input_dim¶
Number of input dimensions to the MLP.
- Type:
int
Number of hidden dimensions in each hidden layer.
- Type:
int
- num_output_dim¶
Number of output dimensions from the MLP.
- Type:
int
Number of hidden layers in the MLP.
- Type:
int
Activation function for hidden layers. Choices are
"identity","relu","leakyrelu","elu","sigmoid","tanh","sin","softplus","swish".- Type:
str
- output_activation¶
Activation function for the output layer. Choices are
"identity","relu","leakyrelu","elu","sigmoid","tanh","sin","softplus","swish".- Type:
str
- class adeptml.configs.PhysicsConfig(forward_func: Callable, jacobian_func: Callable | None = None, use_vjp: bool = False, use_split_vjp: bool = False)[source]¶
Configuration class for physics-related functions.
Three backpropagation modes are supported, selected via
use_vjpanduse_split_vjp:- Jacobian mode (default,
use_vjp=False,use_split_vjp=False) forward_func(x, *args) -> ndarrayjacobian_func(x, *args) -> ndarrayshape(batch, out, in)backwardforms the VJP by multiplyinggrad_output @ jacobian. Use when the full Jacobian is cheap or already available.- VJP mode (
use_vjp=True,use_split_vjp=False) forward_func(x, *args) -> ndarrayjacobian_func(x, grad_output, *args) -> ndarrayshape(batch, in)backwardcallsjacobian_funcwith the upstream gradient directly, avoiding explicit Jacobian materialisation. Use when a manual VJP is cheaper than the full Jacobian.- Split-VJP mode (
use_split_vjp=True) forward_func(x, *args) -> (ndarray, pullback_fn)forward_funcreturns both the output and a pullback closure (e.g. the result ofjax.vjp). The closure is stored during the forward pass and called withgrad_outputduring the backward pass without re-running any part of the physics.jacobian_funcis not used and may be omitted.This is the most memory-efficient mode when the physics solver is expensive and intermediates are already cached by the underlying framework (e.g. JAX checkpointing via
jax.checkpoint).Example usage with a JAX physics function:
from my_physics import physics_forward # physics_forward(x, *args) -> (y, pullback_fn) phy_cfg = PhysicsConfig( forward_func=physics_forward, use_split_vjp=True, )
- forward_func¶
Physics forward function. Signature depends on the chosen mode — see above.
- Type:
Callable
- jacobian_func¶
Jacobian or VJP function. Required for Jacobian and VJP modes; not used in split-VJP mode.
- Type:
Callable, optional
- use_vjp¶
Enable VJP mode. Ignored when
use_split_vjp=True.- Type:
bool
- use_split_vjp¶
Enable split-VJP mode. Takes precedence over
use_vjp.- Type:
bool
- Jacobian mode (default,
Training Utils¶
Training utilities: batch step helper and full training loop.
- adeptml.train_utils.train(model, train_loader, test_loader, optimizer, loss_fn, scheduler, filename, epochs, print_training_loss=True, save_frequency=50, grad_clip: float | None = None)[source]¶
Full training loop with TensorBoard logging and checkpointing.
- Parameters:
model (HybridModel) – The hybrid model to train.
train_loader (torch.utils.data.DataLoader) – DataLoader yielding
(x, y)or(x, y, *args)batches.test_loader (torch.utils.data.DataLoader) – DataLoader yielding validation batches in the same format.
optimizer (torch.optim.Optimizer) – Initialized optimizer.
loss_fn (callable) – Loss function
(y_pred, y_true) -> scalar tensor.scheduler (torch.optim.lr_scheduler) – Learning rate scheduler.
filename (str) – Base directory name for saving runs and TensorBoard logs. A sub-directory
run_Nis created automatically (N auto-increments).epochs (int) – Number of training epochs.
print_training_loss (bool) – Print epoch loss to stdout when
True.save_frequency (int) – Save a model checkpoint every this many epochs.
grad_clip (float, optional) – Maximum L2 norm for gradient clipping.
Nonedisables clipping.
- Returns:
The trained model (same object, modified in place).
- Return type:
- adeptml.train_utils.train_step(model: HybridModel, optimizer: torch.optim.Optimizer, loss_fn, scheduler=None, grad_clip: float | None = None)[source]¶
Build and return a single-batch training step closure.
- Parameters:
model (HybridModel) – The hybrid model to train.
optimizer (torch.optim.Optimizer) – Initialized optimizer.
loss_fn (callable) – Loss function
(y_pred, y_true) -> scalar tensor.scheduler (torch.optim.lr_scheduler, optional) – Learning rate scheduler stepped after each batch.
grad_clip (float, optional) – If set, gradients are clipped to this maximum L2 norm before the optimizer step. Useful for physics-informed training where gradient spikes can occur.
- Returns:
_batch_step(x, y, args, test=False) -> float— runs one forward (and optionally backward) pass and returns the scalar loss.- Return type:
callable