gpt-5.5-priority · original · l123_single_gpt
incorrect 70_conv_transposed_3D__asymmetric_input__square_kernel.py
model
gpt-5.5-priority
turns / max
1 / 1
tool calls
1
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
original
runtime
—
ref runtime
31.00 μs
speedup
—
started
2026-05-05T00:02:03Z
correctness issue: Output mismatch
timingkernelbench.timing
kernel runtime
—
ref runtime
31.00 μs
speedup
—
kernel mean / median / std
—
ref mean / median / std
31.00 / — / 5.65 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.298
dram util %
5.4%
compute util %
29.8%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
180.00 GB/s
dram util %
5.4%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
49.3%
bottleneck
compute-bound
dominant pipe %
29.8%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
73.7%
ld sectors / req
1.74
st sectors / req
—
regs / thread
64
smem / block
1024 B
block size
256
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
383.6%
short_scoreboard
12.2%
mio_throttle
0.3%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn

class Model(nn.Module):
    """
    Performs a transposed 3D convolution operation with asymmetric input and a square kernel.

    Args:
        in_channels (int): Number of channels in the input tensor.
        out_channels (int): Number of channels produced by the convolution.
        kernel_size (int): Size of the square convolution kernel.
        stride (int or tuple, optional): Stride of the convolution. Defaults to 1.
        padding (int or tuple, optional): Padding applied to the input. Defaults to 0.
        output_padding (int or tuple, optional): Additional size added to one side of each dimension in the output shape. 
                                                  Defaults to 0.
        dilation (int or tuple, optional): Spacing between kernel elements. Defaults to 1.
        groups (int, optional): Number of blocked connections from input channels to output channels. Defaults to 1.
        bias (bool, optional): If `True`, adds a learnable bias to the output. Defaults to `False`.
    """
    def __init__(self, in_channels: int, out_channels: int, kernel_size: int, stride: int = 1, padding: int = 0, output_padding: int = 0, 
                 dilation: int = 1, groups: int = 1, bias: bool = False):
        super(Model, self).__init__()
        self.conv_transpose3d = nn.ConvTranspose3d(in_channels, out_channels, (kernel_size, kernel_size, kernel_size), 
                                                stride=stride, padding=padding, output_padding=output_padding, 
                                                dilation=dilation, groups=groups, bias=bias)
        
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """
        Performs the transposed 3D convolution.

        Args:
            x (torch.Tensor): Input tensor of shape (batch_size, in_channels, depth, height, width).

        Returns:
            torch.Tensor: Output tensor of shape (batch_size, out_channels, depth_out, height_out, width_out).
        """
        return self.conv_transpose3d(x)

# Test code
batch_size = 8
in_channels = 48
out_channels = 24
kernel_size = 3
depth = 96
height = 96
width = 96

def get_inputs():
    x = torch.rand(batch_size, in_channels, depth, height, width)
    return [x]

def get_init_inputs():
    return [in_channels, out_channels, kernel_size]  # Provide in_channels, out_channels, kernel_size for initialization
turn 0 · FINAL · 1 tool call(s) · 232.6s turn · 232.6s LLM · 12,494 chars (click to expand)
turn 0232.6s turn · 232.6s LLM · 0.0s tools · FINAL
reasoning
**Evaluating model instantiation** I'm thinking about whether the evaluation process creates both Model and ModelNew separately, then copies the state_dict. In tasks like these, it seems they instantiate new models and copy weights. Do I need to ensure that the attribute names are the same? Like, if our state_dict has conv_transpose3d.weight, should I be careful about how I handle those names? It's a tricky process, and I want to get it right!
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r'''\n#include <torch/extension.h>\n\ntorch::Tensor conv_transpose3d_forward(torch::Tensor x,\n torch::Tensor weight,\n torch::Tensor bias,\n int64_t stride,\n int64_t padding,\n int64_t output_padding,\n int64_t dilation,\n int64_t groups);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n\n#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x \" must be a CUDA tensor\")\n#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x \" must be contiguous\")\n\n__global__ __launch_bounds__(256, 2)\nvoid deconv3d_k3s1p0_48_24_oc4_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int N, int D, int H, int W,\n int has_bias) {\n constexpr int IC = 48;\n constexpr int OC = 24;\n constexpr int K = 3;\n const int Do = D + 2;\n const int Ho = H + 2;\n const int Wo = W + 2;\n const int spatial_total = N * Do * Ho * Wo;\n int p = blockIdx.x * blockDim.x + threadIdx.x;\n if (p >= spatial_total) return;\n const int oc0 = blockIdx.y * 4;\n\n int t = p;\n const int ow = t % Wo; t /= Wo;\n const int oh = t % Ho; t /= Ho;\n const int od = t % Do; t /= Do;\n const int n = t;\n\n float a0 = has_bias ? __ldg(b + oc0 + 0) : 0.0f;\n float a1 = has_bias ? __ldg(b + oc0 + 1) : 0.0f;\n float a2 = has_bias ? __ldg(b + oc0 + 2) : 0.0f;\n float a3 = has_bias ? __ldg(b + oc0 + 3) : 0.0f;\n\n const int kd_min = max(0, od - (D - 1));\n const int kd_max = min(2, od);\n const int kh_min = max(0, oh - (H - 1));\n const int kh_max = min(2, oh);\n const int kw_min = max(0, ow - (W - 1));\n const int kw_max = min(2, ow);\n\n const int x_n_base = n * IC * D * H * W;\n\n for (int ic = 0; ic < IC; ++ic) {\n const int x_ic_base = x_n_base + ic * D * H * W;\n const int w_ic_base = ic * OC * K * K * K;\n for (int kd = kd_min; kd <= kd_max; ++kd) {\n const int iz = od - kd;\n const int x_d_base = x_ic_base + iz * H * W;\n const int wk_d = kd * 9;\n for (int kh = kh_min; kh <= kh_max; ++kh) {\n const int iy = oh - kh;\n const int x_h_base = x_d_base + iy * W;\n const int wk_dh = wk_d + kh * 3;\n#pragma unroll\n for (int kw = 0; kw < 3; ++kw) {\n if (kw < kw_min || kw > kw_max) continue;\n const int ix = ow - kw;\n const float xv = __ldg(x + x_h_base + ix);\n const int wk = wk_dh + kw;\n const int wb0 = w_ic_base + (oc0 + 0) * 27 + wk;\n a0 = fmaf(xv, __ldg(w + wb0), a0);\n a1 = fmaf(xv, __ldg(w + wb0 + 27), a1);\n a2 = fmaf(xv, __ldg(w + wb0 + 54), a2);\n a3 = fmaf(xv, __ldg(w + wb0 + 81), a3);\n }\n }\n }\n }\n\n const int out_sp = Do * Ho * Wo;\n const int y_base = (n * OC + oc0) * out_sp + od * Ho * Wo + oh * Wo + ow;\n y[y_base] = a0;\n y[y_base + out_sp] = a1;\n y[y_base + 2 * out_sp] = a2;\n y[y_base + 3 * out_sp] = a3;\n}\n\n__global__ void deconv3d_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int N, int IC, int D, int H, int W,\n int OC, int K, int stride, int padding,\n int dilation, int groups,\n int Do, int Ho, int Wo,\n int has_bias) {\n int64_t idx = (int64_t)blockIdx.x * blockDim.x + threadIdx.x;\n int64_t total = (int64_t)N * OC * Do * Ho * Wo;\n if (idx >= total) return;\n\n int t0 = (int)idx;\n const int ow = t0 % Wo; t0 /= Wo;\n const int oh = t0 % Ho; t0 /= Ho;\n const int od = t0 % Do; t0 /= Do;\n const int oc = t0 % OC; t0 /= OC;\n const int n = t0;\n\n const int OCg = OC / groups;\n const int ICg = IC / groups;\n const int g = oc / OCg;\n const int ocg = oc - g * OCg;\n float acc = has_bias ? __ldg(b + oc) : 0.0f;\n\n for (int ii = 0; ii < ICg; ++ii) {\n const int ic = g * ICg + ii;\n for (int kd = 0; kd < K; ++kd) {\n int zd = od + padding - kd * dilation;\n if (zd < 0 || zd % stride) continue;\n int iz = zd / stride;\n if (iz < 0 || iz >= D) continue;\n for (int kh = 0; kh < K; ++kh) {\n int yh = oh + padding - kh * dilation;\n if (yh < 0 || yh % stride) continue;\n int iy = yh / stride;\n if (iy < 0 || iy >= H) continue;\n for (int kw = 0; kw < K; ++kw) {\n int xw = ow + padding - kw * dilation;\n if (xw < 0 || xw % stride) continue;\n int ix = xw / stride;\n if (ix < 0 || ix >= W) continue;\n int64_t xo = (((int64_t)n * IC + ic) * D + iz) * H * W + iy * W + ix;\n int64_t wo = ((((int64_t)ic * OCg + ocg) * K + kd) * K + kh) * K + kw;\n acc = fmaf(__ldg(x + xo), __ldg(w + wo), acc);\n }\n }\n }\n }\n y[idx] = acc;\n}\n\ntorch::Tensor conv_transpose3d_forward(torch::Tensor x,\n torch::Tensor weight,\n torch::Tensor bias,\n int64_t stride,\n int64_t padding,\n int64_t output_padding,\n int64_t dilation,\n int64_t groups) {\n CHECK_CUDA(x); CHECK_CUDA(weight); CHECK_CUDA(bias);\n CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(weight); CHECK_CONTIGUOUS(bias);\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 is supported\");\n TORCH_CHECK(weight.scalar_type() == at::kFloat, \"only float32 is supported\");\n const c10::cuda::CUDAGuard device_guard(x.device());\n\n const int N = (int)x.size(0);\n const int IC = (int)x.size(1);\n const int D = (int)x.size(2);\n const int H = (int)x.size(3);\n const int W = (int)x.size(4);\n const int OCg = (int)weight.size(1);\n const int K = (int)weight.size(2);\n const int OC = OCg * (int)groups;\n const int Do = (D - 1) * (int)stride - 2 * (int)padding + (int)dilation * (K - 1) + (int)output_padding + 1;\n const int Ho = (H - 1) * (int)stride - 2 * (int)padding + (int)dilation * (K - 1) + (int)output_padding + 1;\n const int Wo = (W - 1) * (int)stride - 2 * (int)padding + (int)dilation * (K - 1) + (int)output_padding + 1;\n\n auto y = torch::empty({N, OC, Do, Ho, Wo}, x.options());\n const int has_bias = (bias.numel() > 0) ? 1 : 0;\n const float* bp = has_bias ? bias.data_ptr<float>() : bias.data_ptr<float>();\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (IC == 48 && OC == 24 && K == 3 && stride == 1 && padding == 0 && output_padding == 0 && dilation == 1 && groups == 1) {\n const int spatial_total = N * Do * Ho * Wo;\n dim3 block(256);\n dim3 grid((spatial_total + block.x - 1) / block.x, 6);\n deconv3d_k3s1p0_48_24_oc4_kernel<<<grid, block, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(), N, D, H, W, has_bias);\n } else {\n int64_t total = (int64_t)N * OC * Do * Ho * Wo;\n dim3 block(256);\n dim3 grid((unsigned int)((total + block.x - 1) / block.x));\n deconv3d_generic_kernel<<<grid, block, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(),\n N, IC, D, H, W, OC, K, (int)stride, (int)padding, (int)dilation, (int)groups,\n Do, Ho, Wo, has_bias);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='deconv3d_transpose_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['conv_transpose3d_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels: int, out_channels: int, kernel_size: int, stride: int = 1, padding: int = 0, output_padding: int = 0,\n dilation: int = 1, groups: int = 1, bias: bool = False):\n super(ModelNew, self).__init__()\n self.conv_transpose3d = nn.ConvTranspose3d(in_channels, out_channels, (kernel_size, kernel_size, kernel_size),\n stride=stride, padding=padding, output_padding=output_padding,\n dilation=dilation, groups=groups, bias=bias)\n self.stride = stride[0] if isinstance(stride, tuple) else stride\n self.padding = padding[0] if isinstance(padding, tuple) else padding\n self.output_padding = output_padding[0] if isinstance(output_padding, tuple) else output_padding\n self.dilation = dilation[0] if isinstance(dilation, tuple) else dilation\n self.groups = groups\n self.register_buffer('_empty_bias', torch.empty(0), persistent=False)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if not x.is_contiguous():\n x = x.contiguous()\n w = self.conv_transpose3d.weight.contiguous()\n b = self.conv_transpose3d.bias if self.conv_transpose3d.bias is not None else self._empty_bias\n if b.device != x.device:\n b = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.conv_transpose3d_forward(x, w, b.contiguous(), int(self.stride), int(self.padding),\n int(self.output_padding), int(self.dilation), int(self.groups))\n" }
result ← submit_kernel (fail)
failsubmit_kernel submit_kernel FAILED: correctness check did not pass ((0 / 5) trials). correctness_issue: Output mismatch max_difference: ['0.000752', '0.000722', '0.000763', '0.000787', '0.000715'] avg_difference: ['0.000099', '0.000099', '0.000099', '0.000099', '0.000099']
final submitted kernel (236 lines, 10,443 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

_cpp_src = r'''
#include <torch/extension.h>

torch::Tensor conv_transpose3d_forward(torch::Tensor x,
                                      torch::Tensor weight,
                                      torch::Tensor bias,
                                      int64_t stride,
                                      int64_t padding,
                                      int64_t output_padding,
                                      int64_t dilation,
                                      int64_t groups);
'''

_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAGuard.h>

#define CHECK_CUDA(x) TORCH_CHECK(x.is_cuda(), #x " must be a CUDA tensor")
#define CHECK_CONTIGUOUS(x) TORCH_CHECK(x.is_contiguous(), #x " must be contiguous")

__global__ __launch_bounds__(256, 2)
void deconv3d_k3s1p0_48_24_oc4_kernel(const float* __restrict__ x,
                                       const float* __restrict__ w,
                                       const float* __restrict__ b,
                                       float* __restrict__ y,
                                       int N, int D, int H, int W,
                                       int has_bias) {
    constexpr int IC = 48;
    constexpr int OC = 24;
    constexpr int K = 3;
    const int Do = D + 2;
    const int Ho = H + 2;
    const int Wo = W + 2;
    const int spatial_total = N * Do * Ho * Wo;
    int p = blockIdx.x * blockDim.x + threadIdx.x;
    if (p >= spatial_total) return;
    const int oc0 = blockIdx.y * 4;

    int t = p;
    const int ow = t % Wo; t /= Wo;
    const int oh = t % Ho; t /= Ho;
    const int od = t % Do; t /= Do;
    const int n = t;

    float a0 = has_bias ? __ldg(b + oc0 + 0) : 0.0f;
    float a1 = has_bias ? __ldg(b + oc0 + 1) : 0.0f;
    float a2 = has_bias ? __ldg(b + oc0 + 2) : 0.0f;
    float a3 = has_bias ? __ldg(b + oc0 + 3) : 0.0f;

    const int kd_min = max(0, od - (D - 1));
    const int kd_max = min(2, od);
    const int kh_min = max(0, oh - (H - 1));
    const int kh_max = min(2, oh);
    const int kw_min = max(0, ow - (W - 1));
    const int kw_max = min(2, ow);

    const int x_n_base = n * IC * D * H * W;

    for (int ic = 0; ic < IC; ++ic) {
        const int x_ic_base = x_n_base + ic * D * H * W;
        const int w_ic_base = ic * OC * K * K * K;
        for (int kd = kd_min; kd <= kd_max; ++kd) {
            const int iz = od - kd;
            const int x_d_base = x_ic_base + iz * H * W;
            const int wk_d = kd * 9;
            for (int kh = kh_min; kh <= kh_max; ++kh) {
                const int iy = oh - kh;
                const int x_h_base = x_d_base + iy * W;
                const int wk_dh = wk_d + kh * 3;
#pragma unroll
                for (int kw = 0; kw < 3; ++kw) {
                    if (kw < kw_min || kw > kw_max) continue;
                    const int ix = ow - kw;
                    const float xv = __ldg(x + x_h_base + ix);
                    const int wk = wk_dh + kw;
                    const int wb0 = w_ic_base + (oc0 + 0) * 27 + wk;
                    a0 = fmaf(xv, __ldg(w + wb0),      a0);
                    a1 = fmaf(xv, __ldg(w + wb0 + 27), a1);
                    a2 = fmaf(xv, __ldg(w + wb0 + 54), a2);
                    a3 = fmaf(xv, __ldg(w + wb0 + 81), a3);
                }
            }
        }
    }

    const int out_sp = Do * Ho * Wo;
    const int y_base = (n * OC + oc0) * out_sp + od * Ho * Wo + oh * Wo + ow;
    y[y_base] = a0;
    y[y_base + out_sp] = a1;
    y[y_base + 2 * out_sp] = a2;
    y[y_base + 3 * out_sp] = a3;
}

__global__ void deconv3d_generic_kernel(const float* __restrict__ x,
                                        const float* __restrict__ w,
                                        const float* __restrict__ b,
                                        float* __restrict__ y,
                                        int N, int IC, int D, int H, int W,
                                        int OC, int K, int stride, int padding,
                                        int dilation, int groups,
                                        int Do, int Ho, int Wo,
                                        int has_bias) {
    int64_t idx = (int64_t)blockIdx.x * blockDim.x + threadIdx.x;
    int64_t total = (int64_t)N * OC * Do * Ho * Wo;
    if (idx >= total) return;

    int t0 = (int)idx;
    const int ow = t0 % Wo; t0 /= Wo;
    const int oh = t0 % Ho; t0 /= Ho;
    const int od = t0 % Do; t0 /= Do;
    const int oc = t0 % OC; t0 /= OC;
    const int n = t0;

    const int OCg = OC / groups;
    const int ICg = IC / groups;
    const int g = oc / OCg;
    const int ocg = oc - g * OCg;
    float acc = has_bias ? __ldg(b + oc) : 0.0f;

    for (int ii = 0; ii < ICg; ++ii) {
        const int ic = g * ICg + ii;
        for (int kd = 0; kd < K; ++kd) {
            int zd = od + padding - kd * dilation;
            if (zd < 0 || zd % stride) continue;
            int iz = zd / stride;
            if (iz < 0 || iz >= D) continue;
            for (int kh = 0; kh < K; ++kh) {
                int yh = oh + padding - kh * dilation;
                if (yh < 0 || yh % stride) continue;
                int iy = yh / stride;
                if (iy < 0 || iy >= H) continue;
                for (int kw = 0; kw < K; ++kw) {
                    int xw = ow + padding - kw * dilation;
                    if (xw < 0 || xw % stride) continue;
                    int ix = xw / stride;
                    if (ix < 0 || ix >= W) continue;
                    int64_t xo = (((int64_t)n * IC + ic) * D + iz) * H * W + iy * W + ix;
                    int64_t wo = ((((int64_t)ic * OCg + ocg) * K + kd) * K + kh) * K + kw;
                    acc = fmaf(__ldg(x + xo), __ldg(w + wo), acc);
                }
            }
        }
    }
    y[idx] = acc;
}

torch::Tensor conv_transpose3d_forward(torch::Tensor x,
                                      torch::Tensor weight,
                                      torch::Tensor bias,
                                      int64_t stride,
                                      int64_t padding,
                                      int64_t output_padding,
                                      int64_t dilation,
                                      int64_t groups) {
    CHECK_CUDA(x); CHECK_CUDA(weight); CHECK_CUDA(bias);
    CHECK_CONTIGUOUS(x); CHECK_CONTIGUOUS(weight); CHECK_CONTIGUOUS(bias);
    TORCH_CHECK(x.scalar_type() == at::kFloat, "only float32 is supported");
    TORCH_CHECK(weight.scalar_type() == at::kFloat, "only float32 is supported");
    const c10::cuda::CUDAGuard device_guard(x.device());

    const int N = (int)x.size(0);
    const int IC = (int)x.size(1);
    const int D = (int)x.size(2);
    const int H = (int)x.size(3);
    const int W = (int)x.size(4);
    const int OCg = (int)weight.size(1);
    const int K = (int)weight.size(2);
    const int OC = OCg * (int)groups;
    const int Do = (D - 1) * (int)stride - 2 * (int)padding + (int)dilation * (K - 1) + (int)output_padding + 1;
    const int Ho = (H - 1) * (int)stride - 2 * (int)padding + (int)dilation * (K - 1) + (int)output_padding + 1;
    const int Wo = (W - 1) * (int)stride - 2 * (int)padding + (int)dilation * (K - 1) + (int)output_padding + 1;

    auto y = torch::empty({N, OC, Do, Ho, Wo}, x.options());
    const int has_bias = (bias.numel() > 0) ? 1 : 0;
    const float* bp = has_bias ? bias.data_ptr<float>() : bias.data_ptr<float>();
    cudaStream_t stream = at::cuda::getCurrentCUDAStream();

    if (IC == 48 && OC == 24 && K == 3 && stride == 1 && padding == 0 && output_padding == 0 && dilation == 1 && groups == 1) {
        const int spatial_total = N * Do * Ho * Wo;
        dim3 block(256);
        dim3 grid((spatial_total + block.x - 1) / block.x, 6);
        deconv3d_k3s1p0_48_24_oc4_kernel<<<grid, block, 0, stream>>>(
            x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(), N, D, H, W, has_bias);
    } else {
        int64_t total = (int64_t)N * OC * Do * Ho * Wo;
        dim3 block(256);
        dim3 grid((unsigned int)((total + block.x - 1) / block.x));
        deconv3d_generic_kernel<<<grid, block, 0, stream>>>(
            x.data_ptr<float>(), weight.data_ptr<float>(), bp, y.data_ptr<float>(),
            N, IC, D, H, W, OC, K, (int)stride, (int)padding, (int)dilation, (int)groups,
            Do, Ho, Wo, has_bias);
    }
    C10_CUDA_KERNEL_LAUNCH_CHECK();
    return y;
}
'''

_ext = load_inline(
    name='deconv3d_transpose_ext_v1',
    cpp_sources=_cpp_src,
    cuda_sources=_cuda_src,
    functions=['conv_transpose3d_forward'],
    extra_cflags=['-O3'],
    extra_cuda_cflags=['-O3', '--use_fast_math'],
    verbose=False,
)

class ModelNew(nn.Module):
    def __init__(self, in_channels: int, out_channels: int, kernel_size: int, stride: int = 1, padding: int = 0, output_padding: int = 0,
                 dilation: int = 1, groups: int = 1, bias: bool = False):
        super(ModelNew, self).__init__()
        self.conv_transpose3d = nn.ConvTranspose3d(in_channels, out_channels, (kernel_size, kernel_size, kernel_size),
                                                   stride=stride, padding=padding, output_padding=output_padding,
                                                   dilation=dilation, groups=groups, bias=bias)
        self.stride = stride[0] if isinstance(stride, tuple) else stride
        self.padding = padding[0] if isinstance(padding, tuple) else padding
        self.output_padding = output_padding[0] if isinstance(output_padding, tuple) else output_padding
        self.dilation = dilation[0] if isinstance(dilation, tuple) else dilation
        self.groups = groups
        self.register_buffer('_empty_bias', torch.empty(0), persistent=False)

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        if not x.is_contiguous():
            x = x.contiguous()
        w = self.conv_transpose3d.weight.contiguous()
        b = self.conv_transpose3d.bias if self.conv_transpose3d.bias is not None else self._empty_bias
        if b.device != x.device:
            b = torch.empty(0, device=x.device, dtype=x.dtype)
        return _ext.conv_transpose3d_forward(x, w, b.contiguous(), int(self.stride), int(self.padding),
                                             int(self.output_padding), int(self.dilation), int(self.groups))