You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Performance] Avoid dense zero work in stride-2 ConvTranspose3d on Metal #4341
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.
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.
Activity