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 conv3d_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride, int64_t padding, int64_t dilation, int64_t groups);\n\ntorch::Tensor conv3d_forward(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride, int64_t padding, int64_t dilation, int64_t groups) {\n return conv3d_forward_cuda(x, weight, bias, stride, padding, dilation, groups);\n}\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAException.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__constant__ float c_weight[8192];\n__constant__ float c_bias[1024];\n\n__global__ __launch_bounds__(256, 4)\nvoid conv3d_k3_c3_kernel(const float* __restrict__ x, float* __restrict__ y,\n int N, int OC, int D, int H, int W,\n int Do, int Ho, int Wo, int has_bias, int total) {\n const int S = Do * Ho * Wo;\n const int HW = H * W;\n const int stride_grid = blockDim.x * gridDim.x;\n for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += stride_grid) {\n int t = idx;\n const int s = t % S; t /= S;\n const int oc = t % OC;\n const int n = t / OC;\n\n int r = s;\n const int ow = r % Wo; r /= Wo;\n const int oh = r % Ho;\n const int od = r / Ho;\n\n const float* base0 = x + ((n * 3) * D + od) * HW + oh * W + ow;\n const float* base1 = base0 + D * HW;\n const float* base2 = base1 + D * HW;\n const int wo = oc * 81;\n float acc = 0.0f;\n\n #pragma unroll\n for (int kd = 0; kd < 3; ++kd) {\n const int zoff = kd * HW;\n #pragma unroll\n for (int kh = 0; kh < 3; ++kh) {\n const int off = zoff + kh * W;\n const float x00 = base0[off + 0];\n const float x01 = base0[off + 1];\n const float x02 = base0[off + 2];\n const int w0 = wo + kd * 9 + kh * 3;\n acc = fmaf(x00, c_weight[w0 + 0], acc);\n acc = fmaf(x01, c_weight[w0 + 1], acc);\n acc = fmaf(x02, c_weight[w0 + 2], acc);\n }\n }\n #pragma unroll\n for (int kd = 0; kd < 3; ++kd) {\n const int zoff = kd * HW;\n #pragma unroll\n for (int kh = 0; kh < 3; ++kh) {\n const int off = zoff + kh * W;\n const float x00 = base1[off + 0];\n const float x01 = base1[off + 1];\n const float x02 = base1[off + 2];\n const int w0 = wo + 27 + kd * 9 + kh * 3;\n acc = fmaf(x00, c_weight[w0 + 0], acc);\n acc = fmaf(x01, c_weight[w0 + 1], acc);\n acc = fmaf(x02, c_weight[w0 + 2], acc);\n }\n }\n #pragma unroll\n for (int kd = 0; kd < 3; ++kd) {\n const int zoff = kd * HW;\n #pragma unroll\n for (int kh = 0; kh < 3; ++kh) {\n const int off = zoff + kh * W;\n const float x00 = base2[off + 0];\n const float x01 = base2[off + 1];\n const float x02 = base2[off + 2];\n const int w0 = wo + 54 + kd * 9 + kh * 3;\n acc = fmaf(x00, c_weight[w0 + 0], acc);\n acc = fmaf(x01, c_weight[w0 + 1], acc);\n acc = fmaf(x02, c_weight[w0 + 2], acc);\n }\n }\n if (has_bias) acc += c_bias[oc];\n y[idx] = acc;\n }\n}\n\n__global__ __launch_bounds__(256, 3)\nvoid conv3d_generic_kernel(const float* __restrict__ x, const float* __restrict__ wgt,\n const float* __restrict__ bias, float* __restrict__ y,\n int N, int C, int D, int H, int W, int OC, int K,\n int stride, int pad, int dil, int groups,\n int Do, int Ho, int Wo, int has_bias, long long total) {\n const int S = Do * Ho * Wo;\n const int Cg = C / groups;\n const int Og = OC / groups;\n const int HW = H * W;\n const long long step = (long long)blockDim.x * gridDim.x;\n for (long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += step) {\n long long t = idx;\n int s = (int)(t % S); t /= S;\n int oc = (int)(t % OC);\n int n = (int)(t / OC);\n int r = s;\n int ow = r % Wo; r /= Wo;\n int oh = r % Ho;\n int od = r / Ho;\n int g = oc / Og;\n float acc = 0.0f;\n for (int icg = 0; icg < Cg; ++icg) {\n int ic = g * Cg + icg;\n for (int kd = 0; kd < K; ++kd) {\n int id = od * stride - pad + kd * dil;\n if ((unsigned)id >= (unsigned)D) continue;\n for (int kh = 0; kh < K; ++kh) {\n int ih = oh * stride - pad + kh * dil;\n if ((unsigned)ih >= (unsigned)H) continue;\n for (int kw = 0; kw < K; ++kw) {\n int iw = ow * stride - pad + kw * dil;\n if ((unsigned)iw >= (unsigned)W) continue;\n float xv = x[((n * C + ic) * D + id) * HW + ih * W + iw];\n float wv = wgt[(((oc * Cg + icg) * K + kd) * K + kh) * K + kw];\n acc = fmaf(xv, wv, acc);\n }\n }\n }\n }\n if (has_bias) acc += bias[oc];\n y[idx] = acc;\n }\n}\n\ntorch::Tensor conv3d_forward_cuda(torch::Tensor x, torch::Tensor weight, torch::Tensor bias,\n int64_t stride64, int64_t padding64, int64_t dilation64, int64_t groups64) {\n const int N = (int)x.size(0);\n const int C = (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 OC = (int)weight.size(0);\n const int K = (int)weight.size(2);\n const int stride = (int)stride64;\n const int pad = (int)padding64;\n const int dil = (int)dilation64;\n const int groups = (int)groups64;\n const int Do = (D + 2 * pad - dil * (K - 1) - 1) / stride + 1;\n const int Ho = (H + 2 * pad - dil * (K - 1) - 1) / stride + 1;\n const int Wo = (W + 2 * pad - dil * (K - 1) - 1) / stride + 1;\n auto y = torch::empty({N, OC, Do, Ho, Wo}, x.options());\n const int has_bias = (bias.numel() != 0);\n const int threads = 256;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream().stream();\n\n if (C == 3 && K == 3 && stride == 1 && pad == 0 && dil == 1 && groups == 1 && weight.numel() <= 8192 && OC <= 1024) {\n size_t bytes = (size_t)weight.numel() * sizeof(float);\n C10_CUDA_CHECK(cudaMemcpyToSymbolAsync(c_weight, weight.data_ptr<float>(), bytes, 0, cudaMemcpyDeviceToDevice, stream));\n if (has_bias) {\n C10_CUDA_CHECK(cudaMemcpyToSymbolAsync(c_bias, bias.data_ptr<float>(), (size_t)OC * sizeof(float), 0, cudaMemcpyDeviceToDevice, stream));\n }\n int total = N * OC * Do * Ho * Wo;\n int blocks = (total + threads - 1) / threads;\n if (blocks > 65535) blocks = 65535;\n conv3d_k3_c3_kernel<<<blocks, threads, 0, stream>>>(x.data_ptr<float>(), y.data_ptr<float>(), N, OC, D, H, W, Do, Ho, Wo, has_bias, total);\n } else {\n long long total = (long long)N * OC * Do * Ho * Wo;\n int blocks = (int)((total + threads - 1) / threads);\n if (blocks > 65535) blocks = 65535;\n const float* bptr = has_bias ? bias.data_ptr<float>() : nullptr;\n conv3d_generic_kernel<<<blocks, threads, 0, stream>>>(x.data_ptr<float>(), weight.data_ptr<float>(), bptr, y.data_ptr<float>(),\n N, C, D, H, W, OC, K, stride, pad, dil, groups, Do, Ho, Wo, has_bias, total);\n }\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return y;\n}\n'''\n\n_ext = load_inline(\n name='conv3d_direct_k3c3_ext_v1',\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=['conv3d_forward'],\n extra_cflags=['-O3'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n with_cuda=True,\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, dilation: int = 1, groups: int = 1, bias: bool = False):\n super(ModelNew, self).__init__()\n self.conv3d = nn.Conv3d(in_channels, out_channels, (kernel_size, kernel_size, kernel_size), stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias)\n self._stride = stride\n self._padding = padding\n self._dilation = dilation\n self._groups = groups\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n # Inputs in the benchmark are contiguous CUDA fp32 tensors; keep the module state_dict-compatible with nn.Conv3d.\n b = self.conv3d.bias\n if b is None:\n b = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.conv3d_forward(x.contiguous(), self.conv3d.weight.contiguous(), b, self._stride, self._padding, self._dilation, self._groups)\n"
}