Repository navigation
[Fix][Relax][Frontend][ONNX] Fix Softplus accuracy loss from hardcoded threshold - #20212
Merged
Merged
Conversation
…eshold The ONNX Softplus converter passed a hardcoded threshold (10.0 for float16, 20.0 otherwise) to relax.op.nn.softplus, whose topi lowering clamps the result to the linear function x once beta*x exceeds the threshold. The ONNX spec defines y = log(exp(x) + 1) with no threshold, so in float64 the clamp dropped the log(1 + exp(-x)) term and lost about 2e-9 at x = 20.1. Lower ONNX Softplus as the numerically stable form max(x, 0) + log(1 + exp(-|x|)) instead. It equals log(exp(x) + 1) for every finite x, matches onnxruntime on float32/float16 (both return a finite value near overflow where the naive formula overflows to inf), and keeps float64 exact across the whole representable range. Also add test_softplus_large_values (float32 up to x = 80, matches onnxruntime) and test_softplus_float64_accuracy (float64 against the mathematically exact value; failed before this fix).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes: #20184
Summary
The Relax ONNX frontend
Softplus._impl_v1passed a hardcodedthreshold(
10.0for float16,20.0otherwise) torelax.op.nn.softplus. ONNXSoftplusis defined asy = log(exp(x) + 1)with no thresholdattribute, but the topi lowering of
relax.op.nn.softplusclamps the resultto the linear function
xoncebeta * xexceeds the threshold:Root cause
The
thresholdis chosen once for every dtype, and20is far too small forfloat64:
log(exp(x) + 1) = x + log(1 + exp(-x))is fully representable infloat64 up to
x ≈ 709, so clamping atx = 20drops thelog(1 + exp(-x))term. Differential test vsonnx.referenceshowed anobservable absolute error of
1.87e-9atx = 20.1:onnx.reference(For float32/float16 the clamp is numerically invisible in ordinary ranges —
log(exp(x)+1)already rounds toxforx ≳ 15— and near overflow bothonnxruntime and TVM intentionally return a finite value, so the observable,
spec-relevant defect is the float64 case.)
Fix
Lower ONNX
Softplusas the numerically stable, threshold-free form:max(x, 0) + log(1 + exp(-|x|))equalslog(exp(x) + 1)mathematically forevery finite
x: it never overflows (both terms are bounded), it matchesonnxruntime on float32/float16 (including near overflow, where the naive
formula would overflow to
inf), and it keeps float64 exact across the wholerepresentable range. The torch frontend keeps using
relax.op.nn.softpluswith
beta/thresholdsince PyTorch'snn.Softplusgenuinely has thoseparameters.
Validation
Differential test: Relax (build +
VirtualMachine) vs onnxruntime(float32/float16) and the mathematically exact stable form cross-checked with
onnx.reference(float64; onnxruntime's CPU EP has no float64 Softplus), across3 dtypes × full value range (incl. the old failure region
x ∈ (20, 30]andnear-overflow) × multiple shapes and opsets.
[60..100]x ∈ (19..50](old failure region) /[600..1000][10..12]x = 20.1 / 25 / 30(pre-fix failures)Total: 19 differential cases, 19 OK, 0 rejected, 0 numeric mismatches.
In-tree tests
test_softplus_large_values(float32 up tox = 80vsonnxruntime) and
test_softplus_float64_accuracy(float64 vs exact, failsbefore this fix) were added; the existing
test_unary[Softplus]still passes.Files changed
python/tvm/relax/frontend/onnx/onnx_frontend.py—Softplus._impl_v1:lower numerically stable
max(x, 0) + log(1 + exp(-|x|))instead ofrelax.op.nn.softpluswith a hardcodedthreshold.tests/python/relax/test_frontend_onnx.py— addtest_softplus_large_valuesandtest_softplus_float64_accuracy.Base
Based on current upstream
main(ad0a225074, 2026-08-28) using the currentx.ty.dtypeAPI (vs the olderstruct_info.dtype). The single commite5eede1b5dapplies cleanly onmainwithgit am/git apply.