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>\ntorch::Tensor avg_pool3d_forward(torch::Tensor x, int64_t kernel_size, int64_t stride, int64_t padding);\n'''\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#define BD 4\n#define BH 8\n#define BW 32\n#define TD (2*BD+1)\n#define TH (2*BH+1)\n#define TW (2*BW+1)\n#define TSIZE (TD*TH*TW)\n\n__global__ __launch_bounds__(256, 4) void avgpool3d_k3s2p1_shared4_kernel(const float* __restrict__ x, float* __restrict__ y,\n int D, int H, int W, int Do, int Ho, int Wo, int C) {\n __shared__ float sh[TSIZE];\n int num_h_tiles = (Ho + BH - 1) / BH;\n int ht_dt = blockIdx.y;\n int ht = ht_dt % num_h_tiles;\n int dt = ht_dt / num_h_tiles;\n int ow_base = blockIdx.x * BW;\n int oh_base = ht * BH;\n int od_base = dt * BD;\n int nc = blockIdx.z;\n int iz0 = od_base * 2 - 1;\n int iy0 = oh_base * 2 - 1;\n int ix0 = ow_base * 2 - 1;\n long long nc_base = ((long long)nc) * D * H * W;\n bool full = (iz0 >= 0 && iy0 >= 0 && ix0 >= 0 && iz0 + TD <= D && iy0 + TH <= H && ix0 + TW <= W);\n for (int s = threadIdx.x; s < TSIZE; s += blockDim.x) {\n int lx = s % TW;\n int tmp = s / TW;\n int ly = tmp % TH;\n int lz = tmp / TH;\n int iz = iz0 + lz;\n int iy = iy0 + ly;\n int ix = ix0 + lx;\n float v = 0.0f;\n if (full || ((unsigned)iz < (unsigned)D && (unsigned)iy < (unsigned)H && (unsigned)ix < (unsigned)W)) {\n v = x[nc_base + ((long long)iz * H + iy) * W + ix];\n }\n sh[s] = v;\n }\n __syncthreads();\n\n int tid = threadIdx.x;\n int gw = tid & 7; // 0..7, four outputs each\n int tmp = tid >> 3;\n int lh = tmp & 7; // 0..7\n int ld = tmp >> 3; // 0..3\n int ow = ow_base + (gw << 2);\n int oh = oh_base + lh;\n int od = od_base + ld;\n if (od < Do && oh < Ho && ow < Wo) {\n int sx = gw << 3; // input/shared x offset = 2*local output w\n int sy = lh << 1;\n int sz = ld << 1;\n float s0=0.0f, s1=0.0f, s2=0.0f, s3=0.0f;\n #pragma unroll\n for (int dz = 0; dz < 3; ++dz) {\n #pragma unroll\n for (int dy = 0; dy < 3; ++dy) {\n const float* p = sh + ((sz + dz) * TH + (sy + dy)) * TW + sx;\n float a0=p[0], a1=p[1], a2=p[2], a3=p[3], a4=p[4], a5=p[5], a6=p[6], a7=p[7], a8=p[8];\n s0 += a0 + a1 + a2;\n s1 += a2 + a3 + a4;\n s2 += a4 + a5 + a6;\n s3 += a6 + a7 + a8;\n }\n }\n long long out = (((long long)nc * Do + od) * Ho + oh) * Wo + ow;\n const float scale = 1.0f / 27.0f;\n y[out] = s0 * scale;\n if (ow + 1 < Wo) y[out + 1] = s1 * scale;\n if (ow + 2 < Wo) y[out + 2] = s2 * scale;\n if (ow + 3 < Wo) y[out + 3] = s3 * scale;\n }\n}\n\n__global__ void avgpool3d_generic_kernel(const float* __restrict__ x, float* __restrict__ y,\n int N, int C, int D, int H, int W,\n int Do, int Ho, int Wo, int K, int S, int P, long long total) {\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n long long stride_grid = (long long)blockDim.x * gridDim.x;\n float inv = 1.0f / (float)(K*K*K);\n for (; idx < total; idx += stride_grid) {\n int ow = idx % Wo;\n long long t = idx / Wo;\n int oh = t % Ho; t /= Ho;\n int od = t % Do; t /= Do;\n int c = t % C; int n = t / C;\n int id0 = od * S - P;\n int ih0 = oh * S - P;\n int iw0 = ow * S - P;\n float sum = 0.0f;\n long long nc_base = (((long long)n * C + c) * D * H * W);\n for (int dz = 0; dz < K; ++dz) {\n int iz = id0 + dz;\n if ((unsigned)iz < (unsigned)D) {\n for (int dy = 0; dy < K; ++dy) {\n int iy = ih0 + dy;\n if ((unsigned)iy < (unsigned)H) {\n for (int dx = 0; dx < K; ++dx) {\n int ix = iw0 + dx;\n if ((unsigned)ix < (unsigned)W) {\n sum += x[nc_base + ((long long)iz * H + iy) * W + ix];\n }\n }\n }\n }\n }\n }\n y[idx] = sum * inv;\n }\n}\n\ntorch::Tensor avg_pool3d_forward(torch::Tensor x, int64_t kernel_size, int64_t stride, int64_t padding) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 supported\");\n TORCH_CHECK(x.dim() == 5, \"x must be 5D\");\n auto xc = x.contiguous();\n int N = (int)xc.size(0), C = (int)xc.size(1), D = (int)xc.size(2), H = (int)xc.size(3), W = (int)xc.size(4);\n int K = (int)kernel_size;\n int S = (int)stride;\n int P = (int)padding;\n int Do = (D + 2*P - K) / S + 1;\n int Ho = (H + 2*P - K) / S + 1;\n int Wo = (W + 2*P - K) / S + 1;\n auto y = torch::empty({N, C, Do, Ho, Wo}, xc.options());\n long long total = (long long)N * C * Do * Ho * Wo;\n if (total == 0) return y;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (K == 3 && S == 2 && P == 1) {\n dim3 block(256);\n dim3 grid((Wo + BW - 1) / BW, ((Ho + BH - 1) / BH) * ((Do + BD - 1) / BD), N * C);\n avgpool3d_k3s2p1_shared4_kernel<<<grid, block, 0, stream>>>(xc.data_ptr<float>(), y.data_ptr<float>(), D, H, W, Do, Ho, Wo, C);\n } else {\n int threads = 256;\n int blocks = (int)((total + threads - 1) / threads);\n if (blocks > 65535) blocks = 65535;\n avgpool3d_generic_kernel<<<blocks, threads, 0, stream>>>(xc.data_ptr<float>(), y.data_ptr<float>(), N, C, D, H, W, Do, Ho, Wo, K, S, P, total);\n }\n return y;\n}\n'''\n\n_ext = load_inline(name='avgpool3d_ext_v3', cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=['avg_pool3d_forward'], extra_cuda_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, kernel_size: int, stride: int = None, padding: int = 0):\n super(ModelNew, self).__init__()\n self.kernel_size = int(kernel_size)\n self.stride = int(stride) if stride is not None else int(kernel_size)\n self.padding = int(padding)\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.avg_pool3d_forward(x, self.kernel_size, self.stride, self.padding)\n"
}