siyiweigeHEW opened a new issue, #20150: URL: https://github.com/apache/tvm/issues/20150
### Expected behavior A valid ONNX `Pad` model using the **opset-18+ features** — `mode="wrap"` (circular padding) and/or the optional `axes` input (pad only the specified dimensions) — should be imported successfully by `tvm.relax.frontend.onnx.from_onnx`. Both were added to the ONNX Pad spec in opset 18 (see [ONNX Pad spec](https://github.com/onnx/onnx/blob/main/docs/Operators.md#Pad)), are accepted by `onnx.checker`, and run correctly in onnxruntime and onnx.reference. ### Actual behavior `from_onnx` rejects both features: 1. **`mode="wrap"`** raises `OpAttributeInvalid`: ``` OpAttributeInvalid: Value wrap in attribute "mode" is invalid for operator Pad. ``` The frontend's mode whitelist only accepts `["constant", "edge", "reflect"]` (raised at `python/tvm/relax/frontend/onnx/onnx_frontend.py:1919` in `Pad._impl_v2` and `:1949` in `Pad._impl_v11`, class at line 1899), so a legal circular-padding model is misdiagnosed as invalid. 2. **`axes` input** is silently ignored — the pads are applied to the full-rank shape instead of the specified axes, so a model such as `X: (3, 4)`, `pads: [1, 2]`, `axes: [1]` (which pads only dim 1, output `(3, 7)`) fails with `ValueError: Input dimension and pad_before dismatch : 2 vs 1` because the frontend tries to apply the 1-axis pads to dim 0. Both failures are **frontend coverage gaps, not invalid models**: `onnx.checker` and `onnx.reference` accept them, onnxruntime runs them correctly, and `topi.nn.circular_pad` already implements circular padding — the frontend simply never dispatches to it. ### Environment - OS: Linux - TVM: v0.24.dev0 (main branch, commit `262c6d2e0`, built 2026-02-11) - Python: 3.11 - onnx: 1.20.1 - onnxruntime: 1.24.1 ### Steps to reproduce ```python """Repro: valid ONNX Pad (opset 18) with mode="wrap" and/or the axes input is rejected by the TVM relax ONNX frontend, while onnxruntime runs it correctly.""" import numpy as np import onnx, onnxruntime from onnx import helper, TensorProto from tvm.relax.frontend.onnx import from_onnx def make_v18_model(x_shape, pads, mode, axes=None): X = helper.make_tensor_value_info("X", TensorProto.FLOAT, list(x_shape)) Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, None) inits = [helper.make_tensor("pads", TensorProto.INT64, [len(pads)], pads)] node_in = ["X", "pads"] if axes is not None: # axes is positional input #3; provide constant_value too inits.append(helper.make_tensor("value", TensorProto.FLOAT, [], [0.0])) inits.append(helper.make_tensor("axes", TensorProto.INT64, [len(axes)], axes)) node_in += ["value", "axes"] g = helper.make_graph([helper.make_node("Pad", node_in, ["Y"], mode=mode)], "g", [X], [Y], inits) m = helper.make_model(g, opset_imports=[helper.make_opsetid("", 18)]) m.ir_version = 8 return m x = np.arange(12, dtype="float32").reshape(3, 4) # (1) mode="wrap" (opset 18+ circular padding) m1 = make_v18_model((3, 4), [1, 1, 2, 2], "wrap") onnx.checker.check_model(m1) # valid r = onnxruntime.InferenceSession(m1.SerializeToString()).run(None, {"X": x})[0] print("onnxruntime wrap ->", r.shape) # (6, 7) from_onnx(m1, shape_dict={"X": [3, 4]}) # rejected # (2) axes input: pads only dim 1 of X(3,4) m2 = make_v18_model((3, 4), [1, 2], "constant", axes=[1]) r = onnxruntime.InferenceSession(m2.SerializeToString()).run(None, {"X": x})[0] print("onnxruntime constant+axes ->", r.shape) # (3, 7) from_onnx(m2, shape_dict={"X": [3, 4]}) # rejected ``` Actual output: ``` onnxruntime wrap -> (6, 7) Traceback (most recent call last): ... File "tvm/relax/frontend/onnx/onnx_frontend.py", line 1949, in _impl_v11 raise tvm.error.OpAttributeInvalid( tvm.error.OpAttributeInvalid: Value wrap in attribute "mode" is invalid for operator Pad. onnxruntime constant+axes -> (3, 7) Traceback (most recent call last): ... File "tvm/relax/frontend/onnx/onnx_frontend.py", line 1954, in _impl_v11 return bb.emit_te(topi.nn.pad, inputs[0], pad_before, pad_after, constant_value) File "tvm/topi/nn/pad.py", line 88, in pad raise ValueError(f"Input dimension and pad_before dismatch : {n} vs {len(pad_before)}") ValueError: Input dimension and pad_before dismatch : 2 vs 1 ``` ### Additional context - The ONNX Pad spec (opset 18+) defines `mode` ∈ {`constant`, `reflect`, `edge`, **`wrap`**}, where `wrap` pads by wrapping around (circular), and adds an optional `axes` input restricting which dimensions are padded. Opset ≤ 17 has neither. - `topi.nn.circular_pad` already implements circular padding in TVM's core, so the capability exists — this is purely a frontend dispatch gap (mirroring the earlier `ConvTranspose3d` case where `topi.nn.conv3d_transpose` existed but `from_onnx` raised `NotImplementedError`). - A broader differential survey (3 input shapes × all modes × positive/negative pads, plus `axes` cases): of **81** legal Pad models accepted by onnxruntime / `onnx.checker`, TVM rejects **22** — `mode="wrap"` (19) and `constant` + `axes` (3). The 59 accepted models match onnxruntime exactly (`max|diff| = 0`), including **negative pads** (crop), so the gap is purely import coverage. Dynamic `pads` (graph input) are also rejected (`"Dynamic pads are not supported yet."`), an unrelated known limitation. - A fix was upstreamed in apache/tvm [#19827 "[Relax][Frontend][ONNX] Add support for Pad mode=wrap for opset 19"](https://github.com/apache/tvm/pull/19827) (merged 2026-07-09): it dispatches `mode="wrap"` to `topi.nn.circular_pad` and expands the `axes` input into full-rank pads. Its motivating case is exactly the `OpAttributeInvalid: Value wrap ... is invalid` failure described here — confirming the bug is real. This report covers the unfixed behavior in the v0.24.dev0 build at commit `262c6d2e0`, which predates that fix. ### Triage * needs-triage * bug * relax * frontend/onnx -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
