Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[Bug] [Relax][ONNX] Resize produces wrong results with half_pixel/pytorch_half_pixel coordinate transformation and non-integer scales #19570

Copy link
Copy link

Description

@wuyii8941
Issue body actions

Expected behavior

Resize with coordinate_transformation_mode=half_pixel (or pytorch_half_pixel, asymmetric) and non-integer scale factors (e.g., 2.5x) should compute source coordinates as:

src = (dst + 0.5) / scale - 0.5

and produce results matching ONNX Runtime.

Actual behavior

TVM computes incorrect source coordinates, leading to wrong pixel mapping. For a 3×3 input with scale=2.5, the max absolute difference vs ORT is 4.0 (nearest mode) and 0.63 (linear mode).

Reproduction

import numpy as np
import onnx
from onnx import helper, TensorProto, numpy_helper
import onnxruntime as ort
import tvm
from tvm import relax
from tvm.relax.frontend.onnx import from_onnx

x = np.arange(9, dtype=np.float32).reshape(1, 1, 3, 3)

X = helper.make_tensor_value_info("X", TensorProto.FLOAT, [1, 1, 3, 3])
Y = helper.make_tensor_value_info("Y", TensorProto.FLOAT, None)
roi = numpy_helper.from_array(np.array([], dtype=np.float32), "roi")
sc = numpy_helper.from_array(np.array([1, 1, 2.5, 2.5], dtype=np.float32), "scales")
node = helper.make_node("Resize", ["X", "roi", "scales"], ["Y"],
                        mode="nearest",
                        coordinate_transformation_mode="half_pixel",
                        nearest_mode="floor")
graph = helper.make_graph([node], "test", [X], [Y], initializer=[roi, sc])
model = helper.make_model(graph, opset_imports=[helper.make_opsetid("", 18)])
model = onnx.shape_inference.infer_shapes(model)

# ORT
sess = ort.InferenceSession(model.SerializeToString())
ort_out = sess.run(None, {"X": x})[0]

# TVM
mod = from_onnx(model)
exe = tvm.relax.build(
    tvm.ir.transform.Sequential([relax.transform.LegalizeOps()])(mod), target="llvm")
vm = tvm.relax.VirtualMachine(exe, device=tvm.cpu())
tvm_out = vm["main"](tvm.runtime.tensor(x, device=tvm.cpu())).numpy()

print("Max diff:", np.abs(ort_out - tvm_out).max())  # 4.0

Affected configurations

mode coordinate_transformation_mode max_diff vs ORT
nearest half_pixel 4.0
nearest pytorch_half_pixel 4.0
linear half_pixel 0.63
linear asymmetric 0.46
linear pytorch_half_pixel 0.63

Trigger condition: non-integer scale factor (e.g., 2.5) on odd spatial dims (e.g., 3×3). Integer scales (2x, 3x) appear correct.

Root cause

The coordinate transformation for half_pixel mode applies floor((dst + 0.5) / scale - 0.5) but the implementation appears to use a different rounding or offset, causing the source index to be off by one pixel for certain output positions.

Environment

  • TVM: 0.24.dev0, commit 0b0afd8 (2026-04-24)
  • Python: 3.11
  • OS: Linux

cc @KJlaccHoeUM9l @junrushao

Reactions are currently unavailable

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 itPRs 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

    Morty Proxy This is a proxified and sanitized view of the page, visit original site.