Skip to content

fix(losses): avoid NaN gradient in weighted_logsoftmax at -inf logits - #1762

Open
jaideeppyne wants to merge 1 commit into
google-deepmind:mainfrom
jaideeppyne:fix/weighted-logsoftmax-jvp-nan
Open

fix(losses): avoid NaN gradient in weighted_logsoftmax at -inf logits#1762
jaideeppyne wants to merge 1 commit into
google-deepmind:mainfrom
jaideeppyne:fix/weighted-logsoftmax-jvp-nan

Conversation

@jaideeppyne

Copy link
Copy Markdown

What

The custom JVP of weighted_logsoftmax (used by safe_softmax_cross_entropy) multiplies weights_dot by log_softmax(x). At a masked class where x_i = -inf, log_softmax(x)_i = -inf, so this term becomes weights_dot * -inf, producing NaN tangents — even for a zero tangent direction.

Why it's a bug

The primal already implements the 0 log 0 = 0 convention so masked -inf entries stay finite (per its docstring). The gradient rule did not, so jax.jvp(weighted_logsoftmax, primals, (0, 0)) and jax.jacfwd(safe_softmax_cross_entropy) return NaN on inputs with -inf logits.

import jax, jax.numpy as jnp, optax
logits = jnp.array([-jnp.inf, 0., 0.]); labels = jnp.array([0., 1., 0.])
_, t = jax.jvp(optax.losses.weighted_logsoftmax, (logits, labels),
               (jnp.zeros_like(logits), jnp.zeros_like(labels)))
print(t)  # before: [nan 0. 0.]   after: [0. 0. 0.]

Fix

Substitute a finite value for -inf entries of log_softmax(x) in the weights_dot term. This leaves the gradient unchanged wherever log_softmax is finite and removes the spurious NaN otherwise.

Tests

Adds a forward-mode regression test over inputs with -inf logits (fails before, passes after). All existing _classification tests pass; ruff clean.

The custom JVP of `weighted_logsoftmax` multiplied `weights_dot` by
`log_softmax(x)`, which is `-inf` at masked classes (`x_i = -inf`). This
yielded `nan` output tangents even for a zero tangent direction (e.g.
`jax.jvp(..., (0, 0))` or `jax.jacfwd`), contradicting the documented
`0 log 0 = 0` convention that keeps the primal finite there.

Substitute a finite value for the `-inf` entries of `log_softmax(x)` in the
`weights_dot` term. This leaves the gradient unchanged wherever
`log_softmax` is finite and removes the spurious NaN otherwise. Adds a
forward-mode regression test over inputs with `-inf` logits.
@jaideeppyne
jaideeppyne force-pushed the fix/weighted-logsoftmax-jvp-nan branch from c64cadf to 52b6742 Compare August 31, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant