apache / apache/tvm

[Bug] HardSigmoid returns 1.0 for NaN input (ONNX model mismatch with ORT)

Open
#17,999 0 comments 0 reactions 0 assignees View on GitHub
needs-triage type: bug
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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.