This is an automated email from the ASF dual-hosted git repository.
tlopex pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm.git
The following commit(s) were added to refs/heads/main by this push:
new ecf42c1234 [Relax][Frontend][ONNX] Fix LpPool conversion (#20053)
ecf42c1234 is described below
commit ecf42c123456270516eb6c745f45c80b2458cde7
Author: Ronald Nap <[email protected]>
AuthorDate: Sun Jul 26 22:08:26 2026 -0700
[Relax][Frontend][ONNX] Fix LpPool conversion (#20053)
## Summary
Fixes two issues in the Relax ONNX `LpPool` converter:
- Computes `|x|^p` instead of `x^p`, matching the [official ONNX
reference
implementation](https://github.com/onnx/onnx/blob/main/onnx/reference/ops/op_pool_common.py#L255).
- Passes the TVM dtype directly to `relax.const`, avoiding a NumPy dtype
conversion failure.
## Minimal reproduce
```python
python -m pytest \
tests/python/relax/test_frontend_onnx.py::test_pool \
-vv
```
conversion failed with:
```text
ValueError: Could not convert T.float32 to a NumPy dtype
```
---
python/tvm/relax/frontend/onnx/onnx_frontend.py | 6 +--
tests/python/relax/test_frontend_onnx.py | 56 ++++++++++++++++++++++---
2 files changed, 54 insertions(+), 8 deletions(-)
diff --git a/python/tvm/relax/frontend/onnx/onnx_frontend.py
b/python/tvm/relax/frontend/onnx/onnx_frontend.py
index 806d16f5a8..6d38d2b2ca 100644
--- a/python/tvm/relax/frontend/onnx/onnx_frontend.py
+++ b/python/tvm/relax/frontend/onnx/onnx_frontend.py
@@ -4016,12 +4016,12 @@ class LpPool(OnnxOpConverter):
dtype = inputs[0].ty.dtype
p = attr.get("p", 2.0)
reci_p = relax.const(1.0 / p, dtype=dtype)
- # emit for get ty
- data = bb.emit(relax.op.power(inputs[0], relax.const(p, dtype=dtype)))
+
+ data = bb.emit(relax.op.power(relax.op.abs(inputs[0]), relax.const(p,
dtype=dtype)))
attr.update({"count_include_pad": True})
avg_pool = AveragePool._impl_v1(bb, [data], attr, params)
kernels = attr["kernel_shape"]
- out = avg_pool * relax.const(_np.prod(kernels).astype(dtype))
+ out = avg_pool * relax.const(_np.prod(kernels), dtype=dtype)
return relax.op.power(out, reci_p)
diff --git a/tests/python/relax/test_frontend_onnx.py
b/tests/python/relax/test_frontend_onnx.py
index 3a0a4aa5b9..730a969b62 100644
--- a/tests/python/relax/test_frontend_onnx.py
+++ b/tests/python/relax/test_frontend_onnx.py
@@ -8326,9 +8326,10 @@ def test_pool():
def main(x: R.Tensor(input_shape, dtype="float32")):
R.func_attr({"num_input": 1})
with R.dataflow():
- lv = R.power(x, R.const(2.0, "float32"))
- lv1 = pool_op(
- lv,
+ lv = R.abs(x)
+ lv1 = R.power(lv, R.const(2.0, "float32"))
+ lv2 = pool_op(
+ lv1,
pool_size=pool_size,
strides=strides,
dilation=dilation,
@@ -8338,8 +8339,8 @@ def test_pool():
layout=layout,
out_layout=layout,
)
- lv2 = R.multiply(lv1, R.const(kernel_elements, "float32"))
- gv = R.power(lv2, R.const(0.5, "float32"))
+ lv3 = R.multiply(lv2, R.const(kernel_elements, "float32"))
+ gv = R.power(lv3, R.const(0.5, "float32"))
R.output(gv)
return gv
@@ -8379,6 +8380,51 @@ def test_pool():
)
[email protected]("p", [1, 3])
+def test_lppool_negative_input(p: int):
+ input_data = np.array([[[-1.0, 2.0, -3.0, 4.0]]], dtype="float32")
+
+ node = helper.make_node(
+ "LpPool",
+ ["x"],
+ ["y"],
+ kernel_shape=[2],
+ strides=[1],
+ p=p,
+ )
+
+ graph = helper.make_graph(
+ [node],
+ "lppool_negative_input_test",
+ inputs=[
+ helper.make_tensor_value_info(
+ "x",
+ TensorProto.FLOAT,
+ [1, 1, 4],
+ )
+ ],
+ outputs=[
+ helper.make_tensor_value_info(
+ "y",
+ TensorProto.FLOAT,
+ [1, 1, 3],
+ )
+ ],
+ )
+
+ model = helper.make_model(
+ graph,
+ producer_name="lppool_negative_input_test",
+ opset_imports=[helper.make_opsetid("", 18)],
+ )
+
+ check_correctness(
+ model,
+ inputs={"x": input_data},
+ opset=18,
+ )
+
+
def test_global_average_pool():
def verify_global_average_pool_ir(input_shape, expected):
output_shape = input_shape[:2] + [1] * (len(input_shape) - 2)