[Bug] HardSigmoid returns 1.0 for NaN input (ONNX model mismatch with ORT)
- Dominant language
- Python
- Stars
- 13.7k
- Forks
- 4k
- Avg merge
- 2d 1h
- Merged PRs (30d)
- 112
Description
### Expected behavior
HardSigmoid(NaN) should return NaN
### Actual behavior
`––––– MISMATCH DETECTED –––––
Not equal to tolerance rtol=0.01, atol=0.001
x and y nan location mismatch:
x: array([[[[ nan, 0.481528, 0.363083, ..., nan, 0.508347,
0.159798],
[0.325104, 0.460197, 0.420308, ..., nan, nan,...
y: array([[[[1. , 0.481528, 0.363083, ..., 1. , 0.508347,
0.159798],
[0.325104, 0.460197, 0.420308, ..., 1. , 1. ,...`
### Environment
TVM:0.17.0
ONNXRuntime: 1.16.3
### Steps to reproduce
```python
import sys, os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
import torch
import torch.nn as nn
import torch.nn.functional as F
import tempfile
import onnx
import onnxruntime as ort
from numpy.testing import assert_allclose
import tvm
from tvm import relay
from tvm.contrib import graph_executor
import numpy as np
import nas_model_2
class SimpleBugModel(nn.Module):
def __init__(self):
super().__init__()
self.input_conv = torch.nn.modules.conv.Conv2d(in_channels=3, out_channels=16, kernel_size=1)
self.block2 = nas_model_2.LogWrapper()
self.block9 = nas_model_2.HardSigmoidWrapper()
def forward(self, x):
__input_conv = self.input_conv(x)
__blocks__2 = self.block2(__input_conv)
__blocks__9 = self.block9(__blocks__2)
return __blocks__9
def main():
model = SimpleBugModel()
model.eval()
dummy = torch.randn(1, 3, 32, 32, dtype=torch.float32)
with tempfile.NamedTemporaryFile(suffix='.onnx', delete=False) as tmp:
onnx_path = tmp.name
torch.onnx.export(model, dummy, onnx_path, opset_version=19, input_names=['input'], output_names=['output'])
ort_sess = ort.InferenceSession(onnx_path, providers=['CPUExecutionProvider'])
ort_out = ort_sess.run(None, {'input': dummy.numpy()})[0]
onnx_model = onnx.load(onnx_path)
shape_dict = {'input': dummy.numpy().shape}
mod, params = relay.frontend.from_onnx(onnx_model, shape_dict, freeze_params=True)
with tvm.transform.PassContext(opt_level=4):
lib = relay.build(mod, target='llvm', params=params)
m = graph_executor.GraphModule(lib['default'](tvm.cpu()))
m.set_input('input', tvm.nd.array(dummy.numpy()))
m.run()
tvm_out = m.get_output(0)
tvm_out = tvm_out.numpy()
try:
assert_allclose(ort_out, tvm_out, rtol=1e-2, atol=1e-3, equal_nan=True)
except AssertionError as e:
print('––––– MISMATCH DETECTED –––––')
print(e)
except Exception as e:
print('––––– UNEXPECTED ERROR DURING COMPARISON –––––')
print(f'{type(e).__name__}: {e}')
if __name__ == '__main__':
main()
```
```python
## nas_model_2
@basic_unit
class LogWrapper(nni_nn.Module):
def forward(self, x):
return torch.log(x)
@basic_unit
class HardSigmoidWrapper(nni_nn.Module):
def forward(self, x):
return F.hardsigmoid(x)
```
### Triage
* needs-triage
Contributor guide
No contributing guide indexed for this repository
Research direction
Reproduce the mismatch with the provided PyTorch, ONNX Runtime, and TVM script, starting at relay.frontend.from_onnx and the HardSigmoid conversion path. Trace how NaN values are handled through Relay and relay.build, then verify that the compiled output preserves NaN like ONNX Runtime.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, pytorch
- Domain
- compilers, machine-learning
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100