Skip to content

[Performance] Avoid dense zero work in stride-2 ConvTranspose3d on Metal #4341

Closed

Description

@ternaus

Problem

On the Metal backend, conv_transpose3d with the common kernel_size=stride=(2, 2, 2), dilation=1, padding=0, output_padding=0, and groups=1 is routed through the explicit GEMM convolution path. conv_transpose_general represents the operation as conv_general with input_dilation=(2, 2, 2) and flip=true; the 3D dispatch has no implicit path for input dilation.

The resulting naive_unfold_transpose_nd buffer is dense, although each output coordinate has only one valid kernel phase. For this configuration, 7/8 of the unfolded values are zeros. The subsequent GEMM still reads and multiplies those zeros.

This is separate from #3082 and #3845: those changes fix the maxBufferLength failure by tiling the unfold buffer, but the tiled path still performs the same dense zero work.

Reproduction

import mlx.core as mx

mx.random.seed(0)
x = mx.random.normal((1, 32, 64, 64, 60), dtype=mx.float16)
w = mx.random.normal((60, 2, 2, 2, 60), dtype=mx.float16)
y = mx.conv_transpose3d(x, w, stride=(2, 2, 2), padding=(0, 0, 0))
mx.eval(y)
print(y.shape)  # (1, 64, 128, 128, 60)

The exact path can be confirmed from mlx/ops.cpp (conv_transpose_general) and mlx/backend/metal/conv.cpp (dispatch_conv_3D_gpu): the input-dilated case falls through to explicit_gemm_conv_ND_gpu and naive_unfold_transpose_nd_*.3.

Expected behavior

For the exact stride-2/kernel-2 case, MLX should use a phase-aware Metal implementation that computes the eight valid kernel phases directly (or an equivalent fused kernel), without materializing the zero-filled unfold matrix. All other transposed-convolution configurations should keep the existing fallback until they have a dedicated implementation.

A first implementation can be narrowly gated to groups=1, flip=true, input_dilation=(2,2,2), kernel_dilation=(1,1,1), stride=(1,1,1), kernel=(2,2,2), and the padding produced by the public conv_transpose3d(..., padding=0, output_padding=0) API.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions