Skip to content

Add stable decomposition clarification - #957

Merged
fdwr merged 2 commits into
webmachinelearning:mainfrom
mklimenko-nv:stable-decompositions
Oct 10, 2026
Merged

fdwr merged 2 commits into
webmachinelearning:mainfrom
mklimenko-nv:stable-decompositions

Conversation

@mklimenko-nv

@mklimenko-nv mklimenko-nv commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Implements the WG resolution of 2026-09-10 to "update the spec to use numerically more stable reduceLogSumExp decomposition" (https://www.w3.org/2026/09/10-webmachinelearning-minutes.html#214b).

Changes

  • reduceLogSumExp: log(reduceSum(exp(x - max))) + max.
  • softplus: max(0, x) + log(1 + exp(-|x|))
  • tanh: sign(x) * (1 - e) / (1 + e) with e = exp(-2|x|).
  • EMULATED note text: adds a note to specify that reference decompositions aren't necessarily reference implementations.

Justification

The previous forms return Infinity or NaN for inputs that the WPT conformance tests expect to succeed, more details in #947. reduce_log_sum_exp.https.any.js has the explicit 100.0 overflow and -100.0 underflow cases, and the float16 tanh cases contain inputs of 5.586 and 5.957, beyond the point where exp(2x) overflows binary16, so the old tanh sample cannot pass them.

Input Previous This PR Exact
reduceLogSumExp([100]) float32 Infinity 100 100
reduceLogSumExp([-100]) float16 -Infinity -100 -100
softplus(100) float32 Infinity 100 100
softplus(12) float16 Infinity 12 12
tanh(45) float32 NaN 1 1
tanh(5.957) float16 NaN 1 0.99999

Inputs well inside range are unchanged to within one ULP. The stable forms match what frameworks and backends already do. rustnn/rustnn#213 uses the same max-shift for the CoreML lowering and passes the float32 and float16 WPT overflow and underflow cases.

Other decompositions

All 29 decomposition blocks were reviewed. softmax already subtracts the max, sigmoid saturates to 0 and 1 without NaN, elu exponentiates min(0, x), and the three normalizations use the two-pass variance.


Preview | Diff

@fdwr fdwr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃憤 Minor thought, else LGTM.

Comment thread index.bs
const sumExpX =
builder.reduceSum(builder.exp(builder.sub(input, maxX)), options);
return builder.add(
builder.log(sumExpX), builder.reshape(maxX, sumExpX.shape));

@fdwr fdwr Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel like adding some comment explaining how a "reduce log sum" became a "reduceMax" would be enlightening. e.g.

// This is more numerically stable than a direct decomposition:
// return builder.log(builder.reduceSum(builder.exp(input), options));

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, added a comment in 42a3dc4

@huningxin huningxin left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM % other reviewers' comments

@fdwr fdwr left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

鉁岋笍

@fdwr
fdwr merged commit a89427e into webmachinelearning:main Oct 10, 2026
2 checks passed
github-actions Bot added a commit that referenced this pull request Oct 10, 2026
SHA: a89427e
Reason: push, by fdwr

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.

3 participants