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 fused_conv_gn(torch::Tensor x,\n torch::Tensor weight,\n torch::Tensor gamma,\n torch::Tensor beta,\n int64_t num_groups,\n double eps,\n int64_t stride,\n int64_t padding,\n int64_t dilation);\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\n// Specialized fast path for the benchmark's Conv1d parameters:\n// kernel=3, stride=1, padding=1, dilation=1, fp32, contiguous NCT layout.\n// One block computes a 16 (time) x 16 (output-channel) tile for one batch item.\n__global__ void conv1d_k3s1p1_tile_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n float* __restrict__ y,\n int N, int Cin, int Cout, int T, int Tout) {\n const int tx = threadIdx.x; // 0..15 time within tile\n const int ty = threadIdx.y; // 0..15 output channel within tile\n const int tid = ty * 16 + tx;\n const int t0 = blockIdx.x * 16;\n const int co = blockIdx.y * 16 + ty;\n const int n = blockIdx.z;\n const int t = t0 + tx;\n\n __shared__ float sx[18]; // x[n, ci, t0-1 : t0+16]\n __shared__ float sw[16][3]; // w[co_tile, ci, k]\n\n float acc = 0.0f;\n for (int ci = 0; ci < Cin; ++ci) {\n if (tid < 18) {\n const int tt = t0 + tid - 1;\n float v = 0.0f;\n if ((unsigned)tt < (unsigned)T) {\n v = x[(n * Cin + ci) * T + tt];\n }\n sx[tid] = v;\n }\n if (tx < 3) {\n const int c = co;\n if (c < Cout) {\n sw[ty][tx] = w[(c * Cin + ci) * 3 + tx];\n }\n }\n __syncthreads();\n if (co < Cout && t < Tout) {\n acc = fmaf(sw[ty][0], sx[tx], acc);\n acc = fmaf(sw[ty][1], sx[tx + 1], acc);\n acc = fmaf(sw[ty][2], sx[tx + 2], acc);\n }\n __syncthreads();\n }\n if (co < Cout && t < Tout) {\n y[(n * Cout + co) * Tout + t] = acc;\n }\n}\n\n// Generic direct Conv1d fallback for unusual constructor arguments. It is mainly\n// for correctness outside the benchmark shape; the specialized path above is used\n// for the provided case.\n__global__ void conv1d_generic_kernel(const float* __restrict__ x,\n const float* __restrict__ w,\n float* __restrict__ y,\n int N, int Cin, int Cout, int T, int K,\n int Tout, int stride, int padding, int dilation) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = N * Cout * Tout;\n for (; idx < total; idx += blockDim.x * gridDim.x) {\n int t = idx % Tout;\n int co = (idx / Tout) % Cout;\n int n = idx / (Tout * Cout);\n float acc = 0.0f;\n int base = t * stride - padding;\n for (int ci = 0; ci < Cin; ++ci) {\n #pragma unroll\n for (int k = 0; k < 8; ++k) {\n if (k >= K) break;\n int ti = base + k * dilation;\n if ((unsigned)ti < (unsigned)T) {\n acc = fmaf(w[(co * Cin + ci) * K + k], x[(n * Cin + ci) * T + ti], acc);\n }\n }\n for (int k = 8; k < K; ++k) {\n int ti = base + k * dilation;\n if ((unsigned)ti < (unsigned)T) {\n acc = fmaf(w[(co * Cin + ci) * K + k], x[(n * Cin + ci) * T + ti], acc);\n }\n }\n }\n y[idx] = acc;\n }\n}\n\n// One block per (sample, group). Reduces over C_per_group * T, then writes the\n// normalized and affine-transformed output.\n__global__ void groupnorm_forward_kernel(const float* __restrict__ inp,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ out,\n int N, int C, int T, int G,\n float eps, bool affine) {\n extern __shared__ float smem[];\n float* ssum = smem;\n float* ssq = smem + blockDim.x;\n const int tid = threadIdx.x;\n const int ng = blockIdx.x;\n const int n = ng / G;\n const int g = ng - n * G;\n const int cpg = C / G;\n const int elems = cpg * T;\n const int cbase = g * cpg;\n\n float sum = 0.0f;\n float sumsq = 0.0f;\n for (int i = tid; i < elems; i += blockDim.x) {\n int c = cbase + i / T;\n int t = i - (i / T) * T;\n float v = inp[(n * C + c) * T + t];\n sum += v;\n sumsq = fmaf(v, v, sumsq);\n }\n ssum[tid] = sum;\n ssq[tid] = sumsq;\n __syncthreads();\n\n for (int offset = blockDim.x >> 1; offset > 0; offset >>= 1) {\n if (tid < offset) {\n ssum[tid] += ssum[tid + offset];\n ssq[tid] += ssq[tid + offset];\n }\n __syncthreads();\n }\n\n const float mean = ssum[0] / (float)elems;\n float var = ssq[0] / (float)elems - mean * mean;\n var = var < 0.0f ? 0.0f : var;\n const float rstd = rsqrtf(var + eps);\n\n for (int i = tid; i < elems; i += blockDim.x) {\n int c_local = i / T;\n int c = cbase + c_local;\n int t = i - c_local * T;\n float v = inp[(n * C + c) * T + t];\n float z = (v - mean) * rstd;\n if (affine) z = z * gamma[c] + beta[c];\n out[(n * C + c) * T + t] = z;\n }\n}\n\ntorch::Tensor fused_conv_gn(torch::Tensor x,\n torch::Tensor weight,\n torch::Tensor gamma,\n torch::Tensor beta,\n int64_t num_groups,\n double eps,\n int64_t stride,\n int64_t padding,\n int64_t dilation) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(weight.is_cuda(), \"weight must be CUDA\");\n TORCH_CHECK(x.scalar_type() == torch::kFloat32, \"only fp32 is supported\");\n TORCH_CHECK(weight.scalar_type() == torch::kFloat32, \"only fp32 weights are supported\");\n\n x = x.contiguous();\n weight = weight.contiguous();\n if (gamma.defined()) gamma = gamma.contiguous();\n if (beta.defined()) beta = beta.contiguous();\n\n const int N = (int)x.size(0);\n const int Cin = (int)x.size(1);\n const int T = (int)x.size(2);\n const int Cout = (int)weight.size(0);\n const int K = (int)weight.size(2);\n const int Tout = (int)((T + 2 * padding - dilation * (K - 1) - 1) / stride + 1);\n\n auto conv = torch::empty({N, Cout, Tout}, x.options());\n auto out = torch::empty({N, Cout, Tout}, x.options());\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n\n if (K == 3 && stride == 1 && padding == 1 && dilation == 1) {\n dim3 block(16, 16, 1);\n dim3 grid((Tout + 15) / 16, (Cout + 15) / 16, N);\n conv1d_k3s1p1_tile_kernel<<<grid, block, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), conv.data_ptr<float>(),\n N, Cin, Cout, T, Tout);\n } else {\n int total = N * Cout * Tout;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n if (blocks > 4096) blocks = 4096;\n conv1d_generic_kernel<<<blocks, threads, 0, stream>>>(\n x.data_ptr<float>(), weight.data_ptr<float>(), conv.data_ptr<float>(),\n N, Cin, Cout, T, K, Tout, (int)stride, (int)padding, (int)dilation);\n }\n\n const bool affine = gamma.defined() && gamma.numel() == Cout && beta.defined() && beta.numel() == Cout;\n const float* gptr = affine ? gamma.data_ptr<float>() : nullptr;\n const float* bptr = affine ? beta.data_ptr<float>() : nullptr;\n int threads = 256;\n size_t shmem = 2 * threads * sizeof(float);\n groupnorm_forward_kernel<<<N * (int)num_groups, threads, shmem, stream>>>(\n conv.data_ptr<float>(), gptr, bptr, out.data_ptr<float>(),\n N, Cout, Tout, (int)num_groups, (float)eps, affine);\n\n return out;\n}\n'''\n\n_ext = load_inline(\n name=\"fused_conv1d_groupnorm_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"fused_conv_gn\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n verbose=False,\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(\n self,\n in_channels: int,\n out_channels: int,\n num_groups: int,\n kernel_size: int = 3,\n stride: int = 1,\n padding: int = 1,\n dilation: int = 1,\n eps: float = 1e-5,\n affine: bool = True,\n ):\n super().__init__()\n assert out_channels % num_groups == 0\n self.conv = nn.Conv1d(\n in_channels,\n out_channels,\n kernel_size,\n stride=stride,\n padding=padding,\n dilation=dilation,\n bias=False,\n )\n self.norm = nn.GroupNorm(\n num_groups=num_groups,\n num_channels=out_channels,\n eps=eps,\n affine=affine,\n )\n self.num_groups = num_groups\n self.eps = eps\n self.stride = stride\n self.padding = padding\n self.dilation = dilation\n self.affine = affine\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n if self.affine:\n gamma = self.norm.weight\n beta = self.norm.bias\n else:\n gamma = torch.empty(0, device=x.device, dtype=x.dtype)\n beta = torch.empty(0, device=x.device, dtype=x.dtype)\n return _ext.fused_conv_gn(\n x,\n self.conv.weight,\n gamma,\n beta,\n self.num_groups,\n float(self.eps),\n int(self.stride),\n int(self.padding),\n int(self.dilation),\n )\n"
}