Skip to content

[Bug] parse the output number of MaxPool incorrectly #14614

Closed as not planned
Closed as not planned

Description

@jikechao

For the following ONNX model, ONNXConverter will mistakenly parse the output number and thus triggered an assertion failure.

The ONNX structure:

image
You can download the model by this link: https://github.com/jikechao/onnx_models/blob/main/model.onnx

Crash message:

Traceback (most recent call last):    
...
    irmod, params = relay.frontend.from_onnx(predict_model, shape_dict, freeze_params=True)
  File "/workplace/software/tvm/tvm/python/tvm/relay/frontend/onnx.py", line 7346, in from_onnx
    mod, params = g.from_onnx(graph, opset)
  File "/workplace/software/tvm/tvm/python/tvm/relay/frontend/onnx.py", line 6963, in from_onnx
    self._construct_nodes(graph)
  File "/workplace/software/tvm/tvm/python/tvm/relay/frontend/onnx.py", line 7120, in _construct_nodes
    len(node_output), outputs_num, op_name
AssertionError: Number of output mismatch 2 vs 1 in MaxPool.

reproducible script:

import onnx
from tvm import relay

onnx_model_path = "model.onnx"
model = onnx.load(onnx_model_path)
irmod, params = relay.frontend.from_onnx(model, {'x': (1, 1, 5, 5)}, freeze_params=True)

Activity

  1. added
    needs-triagePRs or issues that need to be investigated by maintainers to find the right assignees to address it
    on Apr 13, 2023
  2. jikechao commented on Apr 14, 2023

    @jikechao
    MemberAuthor

    @masahi @jwfromm @vvchernov Could you help me check this crash? Thanks a lot!

  3. vvchernov commented on Apr 14, 2023

    @vvchernov
    Contributor

    Hello @jikechao! It is simply not supported on ONNX front-end of TVM. The implementation of MaxPool (AveragePool as well) was done for onnx opset = 1, but optional second output (Indices) appeared only since opset = 8. It needs to extend implementation for the op, if you do it, it will be good

  4. jikechao commented on Apr 15, 2023

    @jikechao
    MemberAuthor

    @vvchernov Thanks for your comments! Indeed, this crash was caused by Indices appearing since opset=8. However, this feature existing about 5 years. Thus, Supporting Indices to avoid this crash may not be trivial. Thus, I'll try to fix it.

  5. vvchernov commented on Apr 18, 2023

    @vvchernov
    Contributor

    Hello @jikechao! Some nits may be help you to fix. There can be problems with optional output and indices calculation, in both cases you can see how it was implemented for scatter_elements (ScatterElements class)

  6. sunni13830 commented on Nov 7, 2026

    @sunni13830

    This also affects the Relax ONNX frontend in TVM 0.28.dev0. A one-output MaxPool executes correctly, but requesting the legal optional indices output fails with Missing outputs during conversion. Expected 2 but Got 1 in MaxPool. I am adding a self-contained Relax reproducer here rather than opening a duplicate report.

    Tested on Linux x86_64, LLVM CPU, TVM 0.28.dev0 (installed binary revision unknown); no current-main rebuild.

    import numpy as np
    import onnx
    import tvm
    from onnx import TensorProto as T, helper as h
    from onnx.reference import ReferenceEvaluator
    from tvm import relax
    from tvm.relax.frontend.onnx import from_onnx
    
    x = np.arange(16, dtype="float32").reshape(1, 1, 4, 4)
    for indices in [False, True]:
        outputs = [h.make_tensor_value_info("y", T.FLOAT, [1, 1, 2, 2])]
        if indices:
            outputs.append(h.make_tensor_value_info("i", T.INT64, [1, 1, 2, 2]))
        model = h.make_model(h.make_graph([
            h.make_node("MaxPool", ["x"], [v.name for v in outputs], kernel_shape=[2, 2], strides=[2, 2])],
            "pool", [h.make_tensor_value_info("x", T.FLOAT, x.shape)], outputs),
            opset_imports=[h.make_opsetid("", 13)], ir_version=10)
        onnx.checker.check_model(model, full_check=True)
        expected = ReferenceEvaluator(model).run(None, {"x": x})
        np.testing.assert_array_equal(expected[0], [[[[5, 7], [13, 15]]]])
        if indices:
            np.testing.assert_array_equal(expected[1], [[[[5, 7], [13, 15]]]])
        try:
            mod = from_onnx(model, keep_params_in_input=False)
            vm = relax.VirtualMachine(relax.build(mod, target="llvm"), tvm.cpu())
            actual = vm["main"](tvm.runtime.tensor(x))
            if indices:
                raise AssertionError("Expected the optional-output failure")
            np.testing.assert_array_equal(actual.numpy(), expected[0])
            print("single-output control passed")
        except Exception as error:
            if not indices:
                raise
            assert "MaxPool" in str(error) and ("output" in str(error).lower() or "Output" in str(error))
            print("indices failure:", type(error).__name__, str(error).splitlines()[-1])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-triagePRs or issues that need to be investigated by maintainers to find the right assignees to address ittype: bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions