Skip to content

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,

L(θ)=λicLic(θ)+λbcLbc(θ)+λrLr(θ),

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.

Gradient norms before and after balancing

The fix: equalize gradient norms

Every f steps, compute the candidate weights (Expert's Guide, Eqs. 2.12–2.14):

λ^i=jθLj(θ)θLi(θ),i{ic,bc,r},

which guarantees that all weighted gradients have equal norm:

λ^icθLic=λ^bcθLbc=λ^rθLr=jθLj.

The actual weights are then smoothed with a moving average (Eq. 2.15):

λnew=αλold+(1α)λ^new,α=0.9.

The weights are treated as constants (no gradient flows through them), and the recommended update frequency is f1000 steps — the scheme costs one extra set of per-term gradients only when it fires.

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 1/n (equivalent to a global learning-rate factor):

python
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                                    # alpha

Every 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.

Released under the Apache 2.0 License.