pytorch / tutorials

PyTorch tutorials.
https://pytorch.org/tutorials/
BSD 3-Clause "New" or "Revised" License
7.96k stars 3.98k forks source link

Convert Pytorch model to ONNX AssertionError: Not equal to tolerance rtol=0.001, atol=1e-05 #675

Open earlysleepearlyup opened 4 years ago

earlysleepearlyup commented 4 years ago

Demo code:

# Some standard imports
import io
import numpy as np

from torch import nn
import torch.utils.model_zoo as model_zoo
import torch.onnx
import onnx
import onnxruntime

# Super Resolution model definition in PyTorch
import torch.nn as nn
import torch.nn.init as init

class SuperResolutionNet(nn.Module):
    def __init__(self, upscale_factor, inplace=False):
        super(SuperResolutionNet, self).__init__()

        self.relu = nn.ReLU(inplace=inplace)
        self.conv1 = nn.Conv2d(1, 64, (5, 5), (1, 1), (2, 2))
        self.conv2 = nn.Conv2d(64, 64, (3, 3), (1, 1), (1, 1))
        self.conv3 = nn.Conv2d(64, 32, (3, 3), (1, 1), (1, 1))
        self.conv4 = nn.Conv2d(32, upscale_factor ** 2, (3, 3), (1, 1), (1, 1))
        self.pixel_shuffle = nn.PixelShuffle(upscale_factor)

        self._initialize_weights()

    def forward(self, x):
        x = self.relu(self.conv1(x))
        x = self.relu(self.conv2(x))
        x = self.relu(self.conv3(x))
        x = self.pixel_shuffle(self.conv4(x))
        return x

    def _initialize_weights(self):
        init.orthogonal_(self.conv1.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv2.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv3.weight, init.calculate_gain('relu'))
        init.orthogonal_(self.conv4.weight)

# Create the super-resolution model by using the above model definition.
torch_model = SuperResolutionNet(upscale_factor=3)

# Load pretrained model weights
model_url = 'https://s3.amazonaws.com/pytorch/test_data/export/superres_epoch100-44c6958e.pth'
batch_size = 1    # just a random number

# Initialize model with the pretrained weights
map_location = lambda storage, loc: storage
if torch.cuda.is_available():
    map_location = None
torch_model.load_state_dict(model_zoo.load_url(model_url, map_location=map_location))

# set the model to inference mode
torch_model.eval()

# Input to the model
x = torch.randn(batch_size, 1, 224, 224, requires_grad=True)
torch_out = torch_model(x)

# Export the model
# torch.onnx.export(torch_model,               # model being run
#                   x,                         # model input (or a tuple for multiple inputs)
#                   "super_resolution.onnx",   # where to save the model (can be a file or file-like object)
#                   export_params=True,        # store the trained parameter weights inside the model file
#                   opset_version=10,          # the ONNX version to export the model to
#                   do_constant_folding=True,  # wether to execute constant folding for optimization
#                   input_names = ['input'],   # the model's input names
#                   output_names = ['output'], # the model's output names
#                   dynamic_axes={'input' : {0 : 'batch_size'},    # variable lenght axes
#                                 'output' : {0 : 'batch_size'}})
torch.onnx.export(torch_model,               # model being run
                  x,                         # model input (or a tuple for multiple inputs)
                  "super_resolution.onnx",   # where to save the model (can be a file or file-like object)
                  export_params=True,        # store the trained parameter weights inside the model file
                  opset_version=10,          # the ONNX version to export the model to
                  do_constant_folding=True,  # wether to execute constant folding for optimization
                  input_names = ['input'],   # the model's input names
                  output_names = ['output']) # the model's output names

onnx_model = onnx.load("super_resolution.onnx")
onnx.checker.check_model(onnx_model)

ort_session = onnxruntime.InferenceSession("super_resolution.onnx")

def to_numpy(tensor):
    return tensor.detach().cpu().numpy() if tensor.requires_grad else tensor.cpu().numpy()

# compute ONNX Runtime output prediction
ort_inputs = {ort_session.get_inputs()[0].name: to_numpy(x)}
ort_outs = ort_session.run(None, ort_inputs)

# compare ONNX Runtime and PyTorch results
np.testing.assert_allclose(to_numpy(torch_out), ort_outs[0], rtol=1e-03, atol=1e-05)

Environment: Ubuntu 16.04+CUDA10+python3.5+pytorch1.1.0

when I run this demo,there is the error:

Traceback (most recent call last): File "/home/liying/ResnetPytorch-cifar/pytorch2onnxdemo.py", line 97, in np.testing.assert_allclose(to_numpy(torch_out), ort_outs[0], rtol=1e-03, atol=1e-05) File "/home/liying/.local/lib/python3.5/site-packages/numpy/testing/_private/utils.py", line 1501, in assert_allclose verbose=verbose, header=header, equal_nan=equal_nan) File "/home/liying/.local/lib/python3.5/site-packages/numpy/testing/_private/utils.py", line 827, in assert_array_compare raise AssertionError(msg) AssertionError: Not equal to tolerance rtol=0.001, atol=1e-05

Mismatch: 100% Max absolute difference: 6.177497 Max relative difference: 919606.25 x: array([[[[-0.354708, -0.506135, -0.137587, ..., -0.290842, -0.157161, 0.015645], [-0.555938, -0.780708, -0.090645, ..., 0.167254, 0.222404,... y: array([[[[-0.354708, 0.186699, -0.269224, ..., -0.239109, -0.647123, 0.015645], [ 0.173687, 3.032386, -0.229604, ..., 1.092109, 2.304202,...

I think it's the pytorch result mismatch the onnx reault. Maybe there is some bug in my onnx export .

carlin314 commented 4 years ago

same problem, is it solved now?

carlin314 commented 4 years ago

My situation is using pytorch 1.1.0, when I upgrade to pytorch 1.4.0, the problem disappear, FYI

JoeHsiao commented 4 years ago

The versions that work for me:

I have to downgrade from onnx 1.6.0, otherwise I'd see Segmentation fault (core dumped) on onnx.checker.check_model(onnx_model). OS is Ubuntu 19.04.