Migrating to 0.2¶
This release collects the numerical, inference, neural-network and kernel
refactors since v0.1.1. It includes breaking API changes. The website follows
main; use documentation from the matching Git tag when reproducing an older
experiment.
Environment¶
Use Python 3.11–3.13 and JAX >=0.9.0,<0.12. The package requires Flax
>=0.12.6 and pins BlackJAX to 1.7.1. Install accelerator dependencies through
the cuda13 or metal extras and check jax.devices(). Accelerator kernels
have additional hardware constraints; CPU tests do not certify GPU performance.
Required changes¶
| Previous usage | Current usage |
|---|---|
AutoregressiveModel |
Autoregressive; the old name has no compatibility alias |
Sampling from EDM(net), VP(net), VE(net), or LinearFlow(net) |
Supply event_spec at construction or to as_dist(event_spec=...) |
LinearMeanFlow(net) |
Supply event_spec at construction |
| Categorical diffusion without event metadata | Supply token-position shape, excluding the class axis |
Imports from probjax.nn.pallas_kernels.old_pallas |
Use probjax.nn.pallas_kernels; the legacy implementation was removed |
Inspecting named sites with raw jax.make_jaxpr(model) |
Trace inside probjax.enable_rv_tracing() |
| Drift/diffusion keyword arguments passed to solvers | Pass positional arguments, or bind configuration in the callable |
LinearOperator(fn, in_dim, out_dim) |
Function(fn, in_shape); Dense(matrix) and Diagonal(diag, shape) keep structure |
LinearOperator.from_array(m) / op.operator |
Dense(m) / op.mv |
op * vector (row scaling) |
Diagonal(vector) @ op; * and / accept scalars only |
op.solve(b, method=..., dense_mem_limit=..., assume_a="pos") |
op.solve(b, solver="auto", psd=True); materialize with op.as_dense() to force a dense solve |
op.logdet(method=..., dense_mem_limit=...) |
op.logdet(psd=True); matrix-free operators require psd=True |
An event shape excludes all sample and batch axes. event_spec=3 means a
three-feature vector; (16, 3) means sixteen tokens with three features.
as_dist(event_spec=...) overrides one distribution view;
model.set_event_spec(...) changes future defaults. Existing views keep their
bound shapes, and changing metadata does not resize a network's params.
See event specifications.
Training and checkpoints¶
Neural configuration defaults¶
Transformer stacks and AR/flow transformer conditioners now default to model
width 256, eight 32D heads, four layers, and 4× FFN expansion. Explicit smaller
profiles remain supported. Reconstruct older checkpoints with their original
model_dim, num_heads, attn_size, num_layers, and widening_factor;
previously implicit adaptive widths should be supplied explicitly or through
the original callable width rule. See profile comparisons.
| Conditioner | Old defaults (model_dim, num_heads, num_layers, attn_size, widening_factor) |
New defaults |
|---|---|---|
CouplingTransformer |
32, 2, 2, 8, 2 | 256, 8, 4, 32, 4 |
AutoregressiveTransformer |
64, 4, 4, 8, 2 | 256, 8, 4, 32, 4 |
Input-adaptive induced and spatial attention now pass the full input width as
total QKV width, fixing a second division by the head count. For an accepted
old adaptive projection, pass attn_size=in_features // num_heads**2 explicitly
to reproduce its smaller head dimensions.
Categorical linear/sigmoid defaults now use continuous replacement rates 0.1
to 20. To reproduce the old weak-noise process, pass beta_start=1e-4 and
beta_end=0.1. Cosine's continuous rate cap is now 50; pass max_beta=0.999
to reproduce the old cap. The categorical control
records the resulting prior-mismatch correction.
Spline flow boundary-slope logits now use tail_logit_scale=0.1 by default.
The tails remain learnable and start at unit slope; interior knot slopes are
unchanged. Pass tail_logit_scale=1.0 to reproduce the previous undamped
behavior, including when reconstructing a flow for an older checkpoint.
SplineAutoregressive and ARFamily.spline expose the same damping option for
their distribution-head boundary slopes.
Existing module fit calls still return losses; functional fit returns
(params, losses). Request return_result=True for FitState, FitInfo,
metrics and resume state. EMA is opt-in with ema_decay; use_ema=True installs
averaged parameters after fitting while the result retains the raw parameters.
Resume with initial_state=result.state and the same optimizer/kernel setup.
The snapshot does not include a data-loader position or optimizer configuration.
General callbacks run between compiled chunks. Under JIT they require explicit
callback_mode="io"; ordered IO effects cannot be differentiated or vmapped.
Use result.valid or valid_steps to ignore padded histories after stopping
inside JIT. See training and EMA.
Changes that affect numerical results¶
- Mean-flow training defaults to Improved MeanFlow (
imf=True) and uses corrected time-pair sampling. Selectloss_kwargs={"imf": False}for the older loss; this does not restore the old time-pair distribution. - VP/cosine diffusion preconditioning and SDE coefficients were corrected.
Existing checkpoints may need retraining.
VSolverConfig(mode="sde")now uses stochastic reverse dynamics; explicit DDIM remains deterministic. - Transformer autoregressive full-forward evaluation is now causal, matching cached decoding. Earlier likelihoods from the noncausal path were invalid.
- Upper-tail beta/gamma quantiles avoid forming
1 - q. Tail values can change substantially where that subtraction previously rounded to one. - Rectangular
LinearOperatorshape metadata and multiplication order now match dense linear algebra, including under JIT. - Linear operators choose solvers by structure rather than size: Diagonal
divides elementwise, Dense uses Cholesky (
psd=True) or LU, and matrix-free Function operators use CG (psd=True) or GMRES. Passsolver=to override, including any lineax solver (pip install 'probjax[lineax]'). Operators map arrays ofin_shapetoout_shape;shapeis the flattened matrix shape.
ODE/SDE gradient behavior is described in the solver guide. In particular, adaptive ODEs still use a custom reverse-mode adjoint, and there is currently no selectable checkpointed adaptive ODE gradient mode. The backward path is unreliable for adaptive gradients; use a converged fixed-grid solve when you need differentiable integration.
Sampling traces and kernels¶
Prefer condition, do, and log_joint_fn for probabilistic-program
transformations. Their legacy aliases observe, intervene,
log_potential_fn, and log_prob_fn still work but emit DeprecationWarning.
Use trace(..., kind_labels="probabilistic") instead of the deprecated
kind_labels="legacy" option.
Ordinary distribution sampling no longer emits random-variable primitives.
ProbJax PPL transformations enable tracing automatically. Opt in explicitly only
when inspecting sampling jaxprs or writing a custom interpreter; the flag is
read at tracing time. PROBJAX_RV_TRACING=1 restores global tracing behavior.
The Pallas migration preserves supported features, with JAX fallbacks where needed. Multi-tile GPU Mamba uses an associative scan; its GPU runtime has not been benchmarked. See kernel coverage before choosing a backend for an existing experiment.
Special function accuracy and domain notes¶
betainccinv(a, b, q) and gammainccinv(a, q) invert the complementary
regularized incomplete beta and gamma functions. They accept the upper-tail
probability directly, avoiding the loss of tiny probabilities when forming
1 - q. Beta and gamma distribution isf methods use them directly.
from probjax.utils import gammainccinv, log1mexp, logdiffexp
x = gammainccinv(1.0, 1e-30) # Approximately 69.07755, including in float32.
log_survival = log1mexp(-1e-8)
log_difference = logdiffexp(1000.0, 999.0)
Inverse functions require finite positive shapes and clip probabilities to [0, 1]. Invalid shapes return NaN. At upper-tail probabilities zero and one, beta returns one and zero; gamma returns infinity and zero.
Beta inversion uses cached safeguarded Halley solvers, reflecting according
to the root's location. Its total iteration budget is
2 + max_halley_steps + max_bisection_steps. Reverse differentiation uses the
inverse density for probability gradients and central differences for shape
gradients; forward AD and higher shape derivatives are unsupported.
Gamma uses log-space initialization and an implicit JVP, avoiding differentiation
through solver iterations. Higher shape derivatives depend on JAX's
igamma_grad_a support.
FP32 accuracy remains limited by the underlying CDF for some extremely unequal
beta shapes: the seeded stress test includes a case near a=0.051, b=784 with
about 2% relative quantile error. Increasing the iteration budget does not fix
that case. Use FP64 for demanding tail calculations. The originally identified
FP32 regression near a=0.070, b=626 is covered separately at 0.5% tolerance.
log1mexp(x) computes log(1-exp(x)) for x <= 0; logdiffexp(a, b) computes
log(exp(a)-exp(b)) for a >= b. They avoid cancellation and intermediate
overflow, support broadcasting, and differentiate on the finite interior.
Zero differences return negative infinity; invalid domains return NaN.
Continuous diffusion schedule audit¶
EDM, VE, VP and cosine are checked against their forward marginal/SDE identities,
inverse effective-noise maps, all three training targets and Gaussian-oracle
reverse ODE/SDE sampling. VP now includes the time-domain rescaling in its SDE
coefficients. VP/cosine low-noise calculations avoid float32 cancellation.
Generic schedules use g² = d(std²)/dt - 2 (scale′/scale) std².
EDM preconditioning now normalizes by the signal scale for VP/cosine, including the denoiser skip connection. Existing VP/cosine checkpoints used different coefficients and may need retraining. Cosine's singular endpoint is bounded; use the preset's finite effective-noise bounds for sampling. Numerical checks with an exact Gaussian denoiser validate solver behavior, not learned sample quality on arbitrary datasets.
VSolverConfig now uses the reverse SDE for mode="sde"; previously that path
had zero diffusion and was deterministic. Explicit DDIM remains deterministic.
Categorical linear, cosine, sigmoid and log-SNR schedules are also checked for
monotone retention and normalized, nonnegative transition probabilities.
The categorical linear/sigmoid factory defaults retain about 95% of the initial
signal at terminal time; choose stronger rates when a nearly independent base
prior is required. Their probability checks alone do not establish mixing.
Further sampling fixes: an overridden t_max now also selects the base-noise
scale. sample_with_state uses the supplied state for both initialization and
integration, and model_state() handles Python scalar leaves. Call
dist.compile() before wrapping sampling in an outer jax.jit; constructing
an export lazily during tracing is currently unsupported.
Exponential AB2 now handles nonuniform step sizes and uses the correct phi-function weights and midpoint linear coefficient. Gaussian and nonlinear mixture benchmarks, transformer scaling measurements, and remaining limitations are recorded in the diffusion audit.