siyiweigeHEW opened a new pull request, #20152:
URL: https://github.com/apache/tvm/pull/20152
Fixes: #20150
## Summary
The Relax ONNX frontend rejected legal **opset-18** Pad models using
`mode="wrap"` (circular padding) or the optional `axes` input. Both are
ONNX Pad-18 features, are accepted by `onnx.checker` / `onnx.reference` /
onnxruntime, and `topi.nn.circular_pad` already implements circular
padding — this is purely a frontend dispatch gap.
## Root cause
Upstream #19827 added `Pad._impl_v19` with `wrap`/`axes` support, but
`get_converter` dispatches on the highest `_impl_v{N}` with `N <= opset`,
so that method is only reached for models with **opset >= 19**. A model
with **opset 18** — the version that actually introduced `wrap` and
`axes` — still resolves to `_impl_v11`, which:
1. has a whitelist `["constant", "edge", "reflect"]`, so `mode="wrap"`
raises `OpAttributeInvalid("Value wrap ... is invalid for operator
Pad.")`;
2. never reads `inputs[3]` (the `axes` input), so an axes model is padded
on the full rank instead of the specified axes and fails with
`ValueError("Input dimension and pad_before dismatch ...")`.
## Fix
Add `Pad._impl_v18`, mirroring #19827's `_impl_v19` but for opset 18:
expand the `axes` input into full-rank pads via
`_get_known_tensor_rank` / `_normalize_constant_axes`, extend the mode
whitelist to include `"wrap"`, and dispatch `wrap` to
`topi.nn.circular_pad`:
```python
@classmethod
def _impl_v18(cls, bb, inputs, attr, params):
# ONNX Pad-18 introduces mode="wrap" and the optional axes input ...
...
axes_input = inputs[3] if len(inputs) > 3 else None
if axes_input is not None:
...
rank = _get_known_tensor_rank(inputs[0])
axes = _normalize_constant_axes([int(a) for a in axes], rank, "Pad")
full_before = [0] * rank
full_after = [0] * rank
for i, ax in enumerate(axes):
full_before[ax] = pad_before[i]
full_after[ax] = pad_after[i]
pad_before, pad_after = full_before, full_after
pad_mode = attr.get("mode", b"constant").decode("utf-8")
if pad_mode not in ["constant", "edge", "reflect", "wrap"]:
raise tvm.error.OpAttributeInvalid(...)
...
elif pad_mode == "wrap":
return bb.emit_te(topi.nn.circular_pad, inputs[0], pad_before,
pad_after)
```
`_impl_v2` (opset 2, pads as attribute) and `_impl_v11` (opset 11-17,
neither `wrap` nor `axes` legal) are left untouched.
## Validation
Differential test (Relax `from_onnx` + `relax.build` + `VirtualMachine`
vs onnxruntime) over 81 legal Pad models: 3 input shapes × all modes ×
positive/negative pads, plus `axes` cases. Verified on the familyfuzz
locked build `262c6d2e0` via runtime monkey-patch
(`results/.../onnx_Pad/verify_patch.py`, no source files modified).
| Category | Cases | Before | After |
|---|---|---|---|
| `constant` / `edge` / `reflect` (opset 11/13) | 41 | match onnxrt | match
onnxrt (no regression) |
| `constant` / `edge` opset-18, no axes | 8 | match | match |
| `wrap` positive pads (opset 18, 19) | 14 | **rejected**
(`OpAttributeInvalid`) | match onnxrt, `max\|diff\| = 0` |
| `constant` + `axes` (opset 18, incl. negative axis) | 5 | **rejected**
(`ValueError`) | match onnxrt, `max\|diff\| = 0` |
| negative pads (crop) | 8 | match | match |
| **Total** | **81** | 59 match / **22 rejected** | **76 match / 0
rejected** / 5 documented deviation |
The 5 documented deviations are `wrap` with **negative pads**, where the
implementations disagree: `onnx.reference` (`np.pad` mode `"wrap"`) errors
out entirely, onnxruntime uses its own crop-window semantics, and
`topi.nn.circular_pad` follows the ONNX mod formula
(`out[i] = in[(i - pad_before) mod dim]`), matching upstream #19827's
identical implementation. Positive-pad `wrap` (the actual use case)
agrees exactly across onnxrt / onnx.reference / TVM.
Run:
```bash
/home/shenqingchao/miniconda3/envs/tvm23/bin/python3 \
results/TVM/deepseek-v4-flash/prove_hum/onnx_Pad/verify_patch.py
```
## Files changed
- `python/tvm/relax/frontend/onnx/onnx_frontend.py` — add `Pad._impl_v18`
with `wrap`/`axes` support for opset 18 (same handling as #19827's
`_impl_v19`), closing the opset-18 gap.
--
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]