Self-Adaptive Loss Balancing
TL;DR
PINN losses have several terms with wildly different gradient scales. JAXPI periodically rescales each term so that all weighted gradients have equal norm — no manual weight tuning. Based on Wang, Teng & Perdikaris (2021) and Algorithm 1 of the Expert's Guide (2023).
The problem: one gradient drowns the others
A PINN minimizes a composite objective,
where the residual term involves PDE derivatives of the network and typically produces gradients orders of magnitude larger (or smaller) than the data-fit terms. With uniform weights, gradient descent effectively optimizes only the dominant term — the classic "gradient pathology" of PINNs.
The fix: equalize gradient norms
Every
which guarantees that all weighted gradients have equal norm:
The actual weights are then smoothed with a moving average (Eq. 2.15):
The weights are treated as constants (no gradient flows through them), and the recommended update frequency is
In JAXPI
compute_loss_weights implements the scheme with one harmless deviation: it normalizes by the mean of the gradient norms rather than the sum, which rescales all weights by the same constant
loss_weighting.strategy = "dynamic"
loss_weighting.loss_weights = {"ics": 1.0, "res": 1.0} # initial values
loss_weighting.update_schedule = {"start": 100, "every": 1000} # f
loss_weighting.momentum = 0.9 # alphaEvery loss term returned by your model's losses() dict gets its own weight — including each named residual loss ("u_res", "v_res", "p_res", ...). Under multi-GPU sharding the per-term gradients are averaged across devices before the norms are taken, so the weights are identical on every device.
Where it's used
Enabled in the baseline config of every example — it is the single most broadly useful trick in the toolbox. See it interact with the other techniques in Training Techniques.