call → compile_kernel
callcompile_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#include <vector>\n\ntorch::Tensor conv3d_forward(torch::Tensor x, torch::Tensor w, torch::Tensor bias,\n int stride, int padding, int dilation, int groups, bool has_bias);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <ATen/cuda/CUDAContext.h>\n\n#define PVAL 4\n\n__global__ __launch_bounds__(128, 2)\nvoid conv3d_c3k357_oc64_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n const float* __restrict__ b,\n float* __restrict__ y,\n int M, int OW, int OH, int OD,\n int IW, int IH, int ID,\n bool has_bias) {\n int ocg = threadIdx.x; // 0..15, each computes 4 output channels\n int ty = threadIdx.y; // 0..7 spatial groups\n int base_p = (blockIdx.x * (blockDim.y * PVAL)) + ty * PVAL;\n int oc0 = ocg * 4;\n\n float acc[PVAL][4];\n#pragma unroll\n for (int p=0; p<PVAL; ++p) {\n#pragma unroll\n for (int j=0; j<4; ++j) acc[p][j] = has_bias ? b[oc0+j] : 0.0f;\n }\n\n int in_base[PVAL];\n bool valid[PVAL];\n#pragma unroll\n for (int pp=0; pp<PVAL; ++pp) {\n int m = base_p + pp;\n valid[pp] = (m < M);\n int t = m;\n int ow = t % OW; t /= OW;\n int oh = t % OH; t /= OH;\n int od = t % OD; t /= OD;\n int n = t;\n in_base[pp] = ((n * 3 * ID + od) * IH + oh) * IW + ow;\n }\n\n const int IDHW = ID * IH * IW;\n const int IHW = IH * IW;\n // fixed C=3, KD=3, KH=5, KW=7, no padding/stride/dilation\n#pragma unroll\n for (int c=0; c<3; ++c) {\n#pragma unroll\n for (int kd=0; kd<3; ++kd) {\n#pragma unroll\n for (int kh=0; kh<5; ++kh) {\n#pragma unroll\n for (int kw=0; kw<7; ++kw) {\n int kk = ((c*3 + kd)*5 + kh)*7 + kw;\n float ww0 = __ldg(w + (oc0+0)*315 + kk);\n float ww1 = __ldg(w + (oc0+1)*315 + kk);\n float ww2 = __ldg(w + (oc0+2)*315 + kk);\n float ww3 = __ldg(w + (oc0+3)*315 + kk);\n#pragma unroll\n for (int pp=0; pp<PVAL; ++pp) {\n float xv = valid[pp] ? __ldg(x + in_base[pp] + c*IDHW + kd*IHW + kh*IW + kw) : 0.0f;\n acc[pp][0] = fmaf(xv, ww0, acc[pp][0]);\n acc[pp][1] = fmaf(xv, ww1, acc[pp][1]);\n acc[pp][2] = fmaf(xv, ww2, acc[pp][2]);\n acc[pp][3] = fmaf(xv, ww3, acc[pp][3]);\n }\n }\n }\n }\n }\n\n const long long plane = (long long)OD * OH * OW;\n#pragma unroll\n for (int pp=0; pp<PVAL; ++pp) {\n int m = base_p + pp;\n if (valid[pp]) {\n#pragma unroll\n for (int j=0; j<4; ++j) {\n int oc = oc0 + j;\n long long t = m;\n int spatial = (int)(t % plane);\n int n = (int)(t / plane);\n y[((long long)n * 64 + oc) * plane + spatial] = acc[pp][j];\n }\n }\n }\n}\n\n// slightly generic direct kernel for unexpected dimensions/params (still custom, no torch fallback)\n__global__ void conv3d_generic_kernel(const float* __restrict__ x, const float* __restrict__ w,\n const float* __restrict__ b, float* __restrict__ y,\n int N, int C, int OC, int ID, int IH, int IW,\n int KD, int KH, int KW, int OD, int OH, int OW,\n int stride, int pad, int dil, bool has_bias) {\n long long total = (long long)N*OC*OD*OH*OW;\n long long idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n int ow = idx % OW; long long t = idx / OW;\n int oh = t % OH; t /= OH;\n int od = t % OD; t /= OD;\n int oc = t % OC; int n = t / OC;\n float acc = has_bias ? b[oc] : 0.0f;\n for (int c=0;c<C;++c)\n for (int kd=0;kd<KD;++kd) {\n int id = od*stride + kd*dil - pad; if ((unsigned)id >= (unsigned)ID) continue;\n for (int kh=0;kh<KH;++kh) {\n int ih = oh*stride + kh*dil - pad; if ((unsigned)ih >= (unsigned)IH) continue;\n for (int kw=0;kw<KW;++kw) {\n int iw = ow*stride + kw*dil - pad; if ((unsigned)iw >= (unsigned)IW) continue;\n float xv = x[(((long long)n*C + c)*ID + id)*IH*IW + ih*IW + iw];\n float ww = w[(((long long)oc*C + c)*KD + kd)*KH*KW + kh*KW + kw];\n acc = fmaf(xv, ww, acc);\n }\n }\n }\n y[idx] = acc;\n}\n\ntorch::Tensor conv3d_forward(torch::Tensor x, torch::Tensor w, torch::Tensor bias,\n int stride, int padding, int dilation, int groups, bool has_bias) {\n TORCH_CHECK(x.is_cuda() && w.is_cuda(), \"x and w must be CUDA tensors\");\n TORCH_CHECK(x.scalar_type() == torch::kFloat32 && w.scalar_type() == torch::kFloat32, \"float32 only\");\n auto xc = x.contiguous();\n auto wc = w.contiguous();\n torch::Tensor bc = bias;\n if (has_bias) bc = bias.contiguous();\n int N = (int)xc.size(0), C = (int)xc.size(1), ID = (int)xc.size(2), IH = (int)xc.size(3), IW = (int)xc.size(4);\n int OC = (int)wc.size(0), KD = (int)wc.size(2), KH = (int)wc.size(3), KW = (int)wc.size(4);\n int OD = (ID + 2*padding - dilation*(KD-1) - 1) / stride + 1;\n int OH = (IH + 2*padding - dilation*(KH-1) - 1) / stride + 1;\n int OW = (IW + 2*padding - dilation*(KW-1) - 1) / stride + 1;\n auto y = torch::empty({N, OC, OD, OH, OW}, xc.options());\n const float* bp = has_bias ? bc.data_ptr<float>() : nullptr;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (N==16 && C==3 && OC==64 && ID==64 && IH==64 && IW==64 && KD==3 && KH==5 && KW==7 &&\n stride==1 && padding==0 && dilation==1 && groups==1) {\n int M = N*OD*OH*OW;\n dim3 block(16, 8, 1);\n dim3 grid((M + 8*PVAL - 1)/(8*PVAL));\n conv3d_c3k357_oc64_kernel<<<grid, block, 0, stream>>>(xc.data_ptr<float>(), wc.data_ptr<float>(), bp, y.data_ptr<float>(),\n M, OW, OH, OD, IW, IH, ID, has_bias);\n } else {\n long long total = (long long)N*OC*OD*OH*OW;\n int block = 256;\n int grid = (int)((total + block - 1)/block);\n conv3d_generic_kernel<<<grid, block, 0, stream>>>(xc.data_ptr<float>(), wc.data_ptr<float>(), bp, y.data_ptr<float>(),\n N,C,OC,ID,IH,IW,KD,KH,KW,OD,OH,OW,stride,padding,dilation,has_bias);\n }\n return y;\n}\n'''\n\n_ext = load_inline(name='conv3d_asym_ext_v1', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['conv3d_forward'], extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels: int, out_channels: int, kernel_size: tuple, 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, stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias)\n self.stride = stride if isinstance(stride, int) else stride[0]\n self.padding = padding if isinstance(padding, int) else padding[0]\n self.dilation = dilation if isinstance(dilation, int) else dilation[0]\n self.groups = groups\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n bias = self.conv3d.bias if self.conv3d.bias is not None else torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.conv3d_forward(x, self.conv3d.weight, bias, int(self.stride), int(self.padding), int(self.dilation), int(self.groups), self.conv3d.bias is not None)\n"
}