Fix numerical stability of TorchLib erfcx - #3038
Conversation
|
|
||
| _MATH_PI = math.pi | ||
|
|
||
| # Coefficients adapted from SciPy XSF's Cephes ``ndtr.h`` (pinned source revision |
There was a problem hiding this comment.
Thanks. Is there a version that comes from pytorch?
There was a problem hiding this comment.
Codex-assisted response: yes. PyTorch has Steven G. Johnson's erfcx_y100 / calc_erfcx implementation. It uses a 100-region polynomial table for the central positive range and a continued-fraction tail. The CPU kernel calls it; CUDA uses either the corresponding Jiterator implementation or the same helper.
Those are different coefficients from the Cephes rational approximation used here. A PyTorch-sourced ONNX translation is feasible using coefficient lookup and Horner evaluation, but it would replace this approximation with the 700-coefficient table and its tail rules. I chose the current 42-coefficient rational form to avoid that lookup table in the export graph. Its SciPy provenance is explicit in the source/notice, and the focused erfcx tests still pass against PyTorch (20 passed, four expected skips). No performance comparison between the two ONNX representations has been established.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #3038 +/- ##
==========================================
+ Coverage 72.70% 72.73% +0.03%
==========================================
Files 265 265
Lines 32298 32345 +47
Branches 3059 3063 +4
==========================================
+ Hits 23481 23525 +44
- Misses 7779 7782 +3
Partials 1038 1038 ☔ View full report in Codecov by Harness. |
|
Codex-assisted CI follow-up for the unchanged head
The comparison artifacts include source/import identity, dependency freeze, JUnit and logs. It pins ONNX IR to |
Fixes #1223.
The current
exp(x*x) * (1 - erf(x))decomposition loses the small erf complement for positive inputs and can combine overflow with underflow. For example, the existing OpInfo inputs around 6.8 return zero instead of approximately 0.08. This change uses piecewise Cephes rational approximations, a reciprocal positive tail, and the negative-input reflection formula. It promotes half inputs for the calculation, preserves float64 constants, and masks inactive approximation inputs because ONNXWhereevaluates both branches. Exported graphs need neitherErfnorLoop.The existing erfcx xfail is removed without relaxing its tolerance. New tests cover interval boundaries, tails, special values, dtypes, shapes and empty inputs. The coefficient provenance and BSD notice are included in both wheel and source distributions.
Validation:
torch.onnx.exportand ONNX Runtime execution passed for float32 and float64; lint, formatting, wheel and source-distribution checks passed.The runtime validation was on macOS arm64. BFloat16 dispatch is included but was not executed in these runtime checks; no GPU or throughput claim is made.
AI disclosure: OpenAI Codex assisted with the implementation, regression tests, validation tooling and this PR description. The numerical coefficients are adapted from the attributed SciPy/XSF source, not presented as newly derived approximations.