call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.cpp_extension import load_inline\n\nmamba_cuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cmath>\n#include <cfloat>\n\n// RMSNorm kernel - one block per (batch, seq) position\n__global__ void __launch_bounds__(256) rmsnorm_kernel(\n const float* __restrict__ input,\n const float* __restrict__ weight,\n float* __restrict__ output,\n int B, int L, int D,\n float eps\n) {\n int b = blockIdx.x;\n int l = blockIdx.y;\n if (b >= B || l >= L) return;\n \n const float* in_ptr = input + (b * L + l) * D;\n float* out_ptr = output + (b * L + l) * D;\n \n // Compute sum of squares using parallel reduction\n float local_sum = 0.0f;\n for (int d = threadIdx.x; d < D; d += blockDim.x) {\n float val = in_ptr[d];\n local_sum += val * val;\n }\n \n // Warp-level reduction\n for (int offset = 16; offset > 0; offset >>= 1) {\n local_sum += __shfl_down_sync(0xffffffff, local_sum, offset);\n }\n \n // Shared memory for cross-warp reduction\n __shared__ float s_sum[8];\n int warp_id = threadIdx.x / 32;\n int lane_id = threadIdx.x % 32;\n \n if (lane_id == 0) {\n s_sum[warp_id] = local_sum;\n }\n __syncthreads();\n \n // First warp reduces across warps\n float total_sum = 0.0f;\n int num_warps = (blockDim.x + 31) / 32;\n if (warp_id == 0) {\n if (lane_id < num_warps) {\n total_sum = s_sum[lane_id];\n }\n for (int offset = 16; offset > 0; offset >>= 1) {\n total_sum += __shfl_down_sync(0xffffffff, total_sum, offset);\n }\n if (lane_id == 0) {\n s_sum[0] = total_sum;\n }\n }\n __syncthreads();\n \n float rms = rsqrtf(s_sum[0] / D + eps);\n \n // Apply normalization\n for (int d = threadIdx.x; d < D; d += blockDim.x) {\n out_ptr[d] = in_ptr[d] * rms * weight[d];\n }\n}\n\n// Selective scan kernel - processes one (batch, channel) pair per thread block\n// Each thread handles one state dimension\n__global__ void selective_scan_kernel(\n const float* __restrict__ x_branch, // (B, L, d_inner)\n const float* __restrict__ delta, // (B, L, d_inner)\n const float* __restrict__ B_t, // (B, L, d_state)\n const float* __restrict__ C_t, // (B, L, d_state)\n const float* __restrict__ A, // (d_inner, d_state) - already negated exp\n const float* __restrict__ D_param, // (d_inner,)\n float* __restrict__ output, // (B, L, d_inner)\n int B, int L, int d_inner, int d_state\n) {\n int b = blockIdx.x;\n int c = blockIdx.y; // channel in d_inner\n \n if (b >= B || c >= d_inner) return;\n \n int tid = threadIdx.x;\n int state_idx = tid;\n \n // Initialize state\n float h = 0.0f;\n \n // Pointers for this batch and channel\n const float* x_ptr = x_branch + b * L * d_inner + c;\n const float* delta_ptr = delta + b * L * d_inner + c;\n \n // Output pointer\n float* out_ptr = output + b * L * d_inner + c;\n \n // Shared memory for reduction - pad to avoid bank conflicts\n extern __shared__ float shared_mem[];\n float* y_shared = shared_mem;\n \n for (int t = 0; t < L; t++) {\n float x_val = x_ptr[t * d_inner];\n float delta_val = delta_ptr[t * d_inner];\n \n float y_t = 0.0f;\n \n if (state_idx < d_state) {\n const float* B_ptr = B_t + (b * L + t) * d_state;\n const float* C_ptr = C_t + (b * L + t) * d_state;\n const float* A_ptr = A + c * d_state;\n \n float a = A_ptr[state_idx];\n float b_val = B_ptr[state_idx];\n float c_val = C_ptr[state_idx];\n \n float dA = expf(delta_val * a);\n float dB = delta_val * b_val;\n \n h = dA * h + x_val * dB;\n \n y_t = h * c_val;\n }\n \n y_shared[state_idx] = y_t;\n __syncthreads();\n \n // Reduce y_t across state dimensions - use parallel reduction\n if (state_idx == 0) {\n float sum_y = 0.0f;\n // Unrolled loop for small d_state\n #pragma unroll 16\n for (int s = 0; s < d_state; s++) {\n sum_y += y_shared[s];\n }\n // Add skip connection: y = sum(h*C) + x*D\n sum_y += x_val * D_param[c];\n out_ptr[t * d_inner] = sum_y;\n }\n __syncthreads();\n }\n}\n\n// Fused kernel: silu(z) * y -> out_proj -> residual add\n// One block per (batch, seq) position, threads process d_inner dimension\n__global__ void __launch_bounds__(512) fused_output_kernel(\n const float* __restrict__ y, // (B, L, d_inner)\n const float* __restrict__ z, // (B, L, d_inner)\n const float* __restrict__ out_proj_w, // (D, d_inner)\n const float* __restrict__ residual, // (B, L, D)\n float* __restrict__ output, // (B, L, D)\n int B, int L, int d_inner, int D\n) {\n int b = blockIdx.x;\n int l = blockIdx.y;\n int d = threadIdx.x;\n \n if (b >= B || l >= L || d >= D) return;\n \n // Shared memory for reduction across d_inner\n __shared__ float s_gated[1024]; // d_inner elements\n \n float sum = 0.0f;\n for (int c = threadIdx.x; c < d_inner; c += blockDim.x) {\n int idx = b * L * d_inner + l * d_inner + c;\n float z_val = z[idx];\n float y_val = y[idx];\n \n // SiLU activation: x * sigmoid(x)\n float silu_z = z_val * (1.0f / (1.0f + expf(-z_val)));\n float gated = silu_z * y_val;\n \n s_gated[c] = gated;\n }\n __syncthreads();\n \n // Compute projection for output dimension d\n sum = 0.0f;\n for (int c = 0; c < d_inner; c++) {\n sum += s_gated[c] * out_proj_w[d * d_inner + c];\n }\n \n // Add residual and write output\n int out_idx = b * L * D + l * D + d;\n output[out_idx] = sum + residual[out_idx];\n}\n\n// Entry points\ntorch::Tensor rmsnorm_entry(torch::Tensor input, torch::Tensor weight) {\n int B = input.size(0);\n int L = input.size(1);\n int D = input.size(2);\n auto output = torch::empty_like(input);\n \n float eps = 1e-5f;\n dim3 grid(B, L);\n int threads = 256;\n \n rmsnorm_kernel<<<grid, threads>>>(\n input.data_ptr<float>(),\n weight.data_ptr<float>(),\n output.data_ptr<float>(),\n B, L, D, eps\n );\n return output;\n}\n\ntorch::Tensor selective_scan_entry(\n torch::Tensor x_branch,\n torch::Tensor delta,\n torch::Tensor B_t,\n torch::Tensor C_t,\n torch::Tensor A,\n torch::Tensor D_param\n) {\n int B = x_branch.size(0);\n int L = x_branch.size(1);\n int d_inner = x_branch.size(2);\n int d_state = B_t.size(2);\n auto output = torch::empty_like(x_branch);\n \n dim3 grid(B, d_inner);\n int threads = max(d_state, 32);\n int shared_mem = threads * sizeof(float);\n \n selective_scan_kernel<<<grid, threads, shared_mem>>>(\n x_branch.data_ptr<float>(),\n delta.data_ptr<float>(),\n B_t.data_ptr<float>(),\n C_t.data_ptr<float>(),\n A.data_ptr<float>(),\n D_param.data_ptr<float>(),\n output.data_ptr<float>(),\n B, L, d_inner, d_state\n );\n return output;\n}\n\ntorch::Tensor fused_output_entry(\n torch::Tensor y,\n torch::Tensor z,\n torch::Tensor out_proj_w,\n torch::Tensor residual\n) {\n int B = y.size(0);\n int L = y.size(1);\n int d_inner = y.size(2);\n int D = residual.size(2);\n auto output = torch::empty_like(residual);\n \n dim3 grid(B, L);\n int threads = min(D, 512);\n \n fused_output_kernel<<<grid, threads>>>(\n y.data_ptr<float>(),\n z.data_ptr<float>(),\n out_proj_w.data_ptr<float>(),\n residual.data_ptr<float>(),\n output.data_ptr<float>(),\n B, L, d_inner, D\n );\n return output;\n}\n\"\"\"\n\nmamba_cpp_source = \"\"\"\ntorch::Tensor rmsnorm_entry(torch::Tensor input, torch::Tensor weight);\ntorch::Tensor selective_scan_entry(\n torch::Tensor x_branch,\n torch::Tensor delta,\n torch::Tensor B_t,\n torch::Tensor C_t,\n torch::Tensor A,\n torch::Tensor D_param\n);\ntorch::Tensor fused_output_entry(\n torch::Tensor y,\n torch::Tensor z,\n torch::Tensor out_proj_w,\n torch::Tensor residual\n);\n\"\"\"\n\n# Load the extension\nmamba_extension = load_inline(\n name='mamba_extension_v4',\n cpp_sources=mamba_cpp_source,\n cuda_sources=mamba_cuda_source,\n functions=['rmsnorm_entry', 'selective_scan_entry', 'fused_output_entry'],\n extra_cuda_cflags=['-O3', '-use_fast_math', '-lineinfo'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, d_model: int, d_state: int, d_conv: int, expand: int):\n super(ModelNew, self).__init__()\n self.d_model = d_model\n self.d_inner = d_model * expand\n self.d_state = d_state\n self.d_conv = d_conv\n\n self.norm = nn.RMSNorm(d_model)\n self.in_proj = nn.Linear(d_model, self.d_inner * 2, bias=False)\n self.conv1d = nn.Conv1d(self.d_inner, self.d_inner, d_conv,\n padding=d_conv - 1, groups=self.d_inner, bias=True)\n self.activation = nn.SiLU()\n\n self.A_log = nn.Parameter(torch.randn(self.d_inner, d_state))\n self.proj_B = nn.Linear(self.d_inner, d_state, bias=False)\n self.proj_C = nn.Linear(self.d_inner, d_state, bias=False)\n self.proj_delta = nn.Linear(self.d_inner, self.d_inner, bias=True)\n self.D = nn.Parameter(torch.ones(self.d_inner))\n\n self.out_proj = nn.Linear(self.d_inner, d_model, bias=False)\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n B, L, D = x.shape\n residual = x\n \n # Custom RMSNorm\n x = mamba_extension.rmsnorm_entry(x.contiguous(), self.norm.weight.contiguous())\n\n xz = self.in_proj(x)\n x_branch, z = xz.chunk(2, dim=-1)\n\n x_branch = x_branch.transpose(1, 2)\n x_branch = self.conv1d(x_branch)[..., :L]\n x_branch = x_branch.transpose(1, 2)\n x_branch = self.activation(x_branch)\n\n N = self.d_state\n delta = torch.nn.functional.softplus(self.proj_delta(x_branch))\n B_t = self.proj_B(x_branch)\n C_t = self.proj_C(x_branch)\n\n A = -torch.exp(self.A_log)\n \n # Use custom selective scan kernel\n y = mamba_extension.selective_scan_entry(\n x_branch.contiguous(),\n delta.contiguous(),\n B_t.contiguous(),\n C_t.contiguous(),\n A.contiguous(),\n self.D.contiguous()\n )\n\n # Use fused output kernel\n output = mamba_extension.fused_output_entry(\n y.contiguous(),\n z.contiguous(),\n self.out_proj.weight.contiguous(),\n residual.contiguous()\n )\n return output"
}