wuyii8941 opened a new issue, #19694:
URL: https://github.com/apache/tvm/issues/19694

   
   ## Expected behavior
   
   `relax.op.nn.conv{1,2,3}d_transpose` accept `dilation` and `data_layout` /
   `kernel_layout` / `out_layout` parameters. PyTorch's `ConvTranspose{1,2,3}d`
   and ONNX `ConvTranspose` both support `dilation > 1`; TF/Keras and many
   mobile/accelerator paths use non-NCHW layouts.
   
   When a configuration is not yet implemented in the TOPI lowering, the 
legalize
   pass should raise a clear, actionable `OpNotImplemented` (or
   `NotImplementedError`) that mentions the operator and the unsupported 
attribute.
   
   ## Actual behavior
   
   For any unsupported attribute combination, the legalize logs an `INFO`-level
   message and **returns the call unchanged**. The unlegalized intrinsic then
   crashes during VM codegen with:
   
   ```
   tvm.error.InternalError: CodeGenVM cannot handle this intrinsic now:
   Op(relax.nn.conv2d_transpose)
   ```
   
   The user has no way to tell from this error which attribute caused the bail.
   The `INFO` log is hidden under default logging settings. This pattern affects
   **three independent code paths**:
   
   1. `dilation > 1` (1D / 2D / 3D)
   2. `data_layout` other than `NCHW` / `NCW` / `NCDHW` (or mismatched
      `kernel_layout`)
   3. `out_layout != data_layout`
   
   All three short-circuit to the same opaque codegen crash. Note that
   `#17890` (closed by `#17968`) fixed the basic case where the intrinsic was
   unhandled altogether, but did **not** touch any of these conditional bail-out
   branches — they remain.
   
   ## Reproduction
   
   ```python
   import numpy as np
   import tvm
   from tvm import relax
   
   def build_and_compile(builder):
       bb = relax.BlockBuilder()
       builder(bb)
       mod = bb.get()
       mod = relax.transform.LegalizeOps()(mod)
       return relax.build(mod, target="llvm")
   
   
   # === A. conv2d_transpose with dilation > 1 ===
   def case_dilation_2d():
       x = np.random.randn(1, 1, 5, 5).astype(np.float32)
       W = np.random.randn(1, 2, 3, 3).astype(np.float32)
       def builder(bb):
           X = relax.Var("X", relax.TensorStructInfo(x.shape, "float32"))
           Wv = relax.Var("W", relax.TensorStructInfo(W.shape, "float32"))
           with bb.function("main", [X, Wv]):
               with bb.dataflow():
                   y = bb.emit(relax.op.nn.conv2d_transpose(
                       X, Wv, strides=(1, 1), padding=(0, 0), dilation=(2, 2)))
                   gv = bb.emit_output(y)
               bb.emit_func_output(gv)
       return builder
   
   
   # === B. conv1d_transpose with dilation > 1 ===
   def case_dilation_1d():
       x = np.random.randn(1, 1, 5).astype(np.float32)
       W = np.random.randn(1, 2, 3).astype(np.float32)
       def builder(bb):
           X = relax.Var("X", relax.TensorStructInfo(x.shape, "float32"))
           Wv = relax.Var("W", relax.TensorStructInfo(W.shape, "float32"))
           with bb.function("main", [X, Wv]):
               with bb.dataflow():
                   y = bb.emit(relax.op.nn.conv1d_transpose(
                       X, Wv, strides=(1,), padding=(0,), dilation=(2,)))
                   gv = bb.emit_output(y)
               bb.emit_func_output(gv)
       return builder
   
   
   # === C. conv2d_transpose with NHWC layout ===
   def case_layout_nhwc():
       x = np.random.randn(1, 4, 4, 1).astype(np.float32)
       W = np.random.randn(1, 2, 3, 3).astype(np.float32)
       def builder(bb):
           X = relax.Var("X", relax.TensorStructInfo(x.shape, "float32"))
           Wv = relax.Var("W", relax.TensorStructInfo(W.shape, "float32"))
           with bb.function("main", [X, Wv]):
               with bb.dataflow():
                   y = bb.emit(relax.op.nn.conv2d_transpose(
                       X, Wv, strides=(1, 1), padding=(0, 0),
                       data_layout="NHWC", kernel_layout="IOHW"))
                   gv = bb.emit_output(y)
               bb.emit_func_output(gv)
       return builder
   
   
   for label, case in [("dilation_2d", case_dilation_2d),
                       ("dilation_1d", case_dilation_1d),
                       ("layout_nhwc",  case_layout_nhwc)]:
       try:
           build_and_compile(case())
           print(f"{label}: built OK (unexpected)")
       except Exception as e:
           msg = str(e).splitlines()[0]
           print(f"{label}: {type(e).__name__}: {msg}")
   
   # All three print:
   # InternalError: CodeGenVM cannot handle this intrinsic now:
   ```
   
   (`conv3d_transpose` with `dilation > 1` or `data_layout != "NCDHW"` 
reproduces
   the same crash; the legalize for it has the identical structure.)
   
   ## Root cause
   
   `python/tvm/relax/transform/legalize_ops/nn.py` — each of 
`_nn_conv1d_transpose`,
   `_nn_conv2d_transpose`, `_nn_conv3d_transpose` shares this pattern:
   
   ```python
   @register_legalize("relax.nn.conv2d_transpose")
   def _nn_conv2d_transpose(bb, call):
       if call.attrs.out_layout != call.attrs.data_layout:
           logging.info(
               "TOPI conv2d_transpose does not support different input-output "
               "layouts, and thus cannot be legalized by TOPI"
           )
           return call                          # <-- silent bail (1)
       if call.attrs.data_layout != "NCHW" or call.attrs.kernel_layout != 
"IOHW":
           logging.info(
               "TOPI conv2d_transpose does not support input layout other than 
NCHW, "
               "and kernel layout other than IOHW, so cannot be legalized by 
TOPI"
           )
           return call                          # <-- silent bail (2)
       dilation = call.attrs.dilation
       if len(dilation) != 2 or any(d != 1 for d in dilation):
           logging.info(
               "TOPI conv2d_transpose does not support dilations other than 1, "
               "and thus cannot be legalized by TOPI"
           )
           return call                          # <-- silent bail (3)
       return bb.call_te(topi.nn.group_conv2d_transpose_nchw, ...)
   ```
   
   Underlying TOPI primitives (`python/tvm/topi/nn/conv2d_transpose.py`,
   `conv1d_transpose.py`, `conv3d_transpose.py`) do not accept a `dilation`
   parameter and only target the NCHW / NCW / NCDHW data layouts.
   
   ## Suggested fix
   
   Two layers of fix, both useful independently:
   
   **(1) Short-term — fail loudly in the legalize.** Replace each silent bail
   with a structured error so users get an actionable message:
   
   ```python
   if any(d != 1 for d in dilation):
       raise tvm.error.OpNotImplemented(
           f"nn.conv2d_transpose with dilation={list(dilation)} is not yet "
           f"lowered by TOPI; please open an issue if you need this."
       )
   if call.attrs.data_layout != "NCHW" or call.attrs.kernel_layout != "IOHW":
       raise tvm.error.OpNotImplemented(
           f"nn.conv2d_transpose with data_layout={call.attrs.data_layout!r}, "
           f"kernel_layout={call.attrs.kernel_layout!r} is not yet lowered by 
TOPI."
       )
   if call.attrs.out_layout != call.attrs.data_layout:
       raise tvm.error.OpNotImplemented(
           f"nn.conv2d_transpose with out_layout != data_layout is not yet "
           f"lowered by TOPI."
       )
   ```
   
   This is a one-line-per-branch change and resolves the user-facing pain
   immediately. The same edit applies symmetrically to `_nn_conv1d_transpose`
   (NCW / IOW) and `_nn_conv3d_transpose` (NCDHW / IODHW).
   
   **(2) Longer-term — implement the missing configurations.**
   
   - **`dilation > 1`**: pre-dilate the kernel before calling the existing
     transposed-conv compute. Output spatial dim is
     `(in - 1) * stride - 2 * pad + dilation * (k - 1) + 1 + output_padding`.
     The change in TOPI is small (add a `dilation` parameter, dilate the
     kernel) and consistent across 1D / 2D / 3D.
   - **NHWC layout**: either add a layout-sandwich inside the legalize
     (`transpose → conv2d_transpose_nchw → transpose`) or extend TOPI directly.
   
   ## Environment
   
   - TVM: latest `main` (commit b172d5ea3)
   - Python: 3.11
   


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

Reply via email to