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\nimport math\n\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <vector>\n\nconstexpr int BLOCK_SIZE = 16;\n\n// LayerNorm kernel\ntemplate <typename scalar_t>\n__global__ void layer_norm_kernel(\n const scalar_t* __restrict__ input,\n scalar_t* __restrict__ output,\n const scalar_t* __restrict__ weight,\n const scalar_t* __restrict__ bias,\n int N, int dim, int stride) {\n \n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= N) return;\n \n const scalar_t* in_ptr = input + idx * stride;\n scalar_t* out_ptr = output + idx * stride;\n \n // Compute mean\n scalar_t mean = 0;\n for (int i = 0; i < dim; i++) {\n mean += in_ptr[i];\n }\n mean /= dim;\n \n // Compute variance\n scalar_t var = 0;\n for (int i = 0; i < dim; i++) {\n scalar_t diff = in_ptr[i] - mean;\n var += diff * diff;\n }\n var /= dim;\n \n scalar_t inv_std = rsqrt(var + scalar_t(1e-5));\n \n // Normalize and apply affine transform\n for (int i = 0; i < dim; i++) {\n out_ptr[i] = (in_ptr[i] - mean) * inv_std * weight[i] + bias[i];\n }\n}\n\n// Linear + sigmoid gating kernel\ntemplate <typename scalar_t>\n__global__ void linear_gated_kernel(\n const scalar_t* __restrict__ input,\n const scalar_t* __restrict__ proj_weight,\n const scalar_t* __restrict__ proj_bias,\n const scalar_t* __restrict__ gate_weight,\n const scalar_t* __restrict__ gate_bias,\n scalar_t* __restrict__ output,\n const scalar_t* __restrict__ mask,\n int batch_size, int N, int in_dim, int out_dim) {\n \n int b = blockIdx.x;\n int ij = blockIdx.y * blockDim.x + threadIdx.x;\n int i = ij / N;\n int j = ij % N;\n \n if (i >= N || j >= N) return;\n \n int input_offset = ((b * N + i) * N + j) * in_dim;\n int output_offset = ((b * N + i) * N + j) * out_dim;\n \n scalar_t mask_val = mask ? mask[(b * N + i) * N + j] : scalar_t(1.0);\n \n for (int h = 0; h < out_dim; h++) {\n scalar_t proj_val = proj_bias[h];\n scalar_t gate_val = gate_bias[h];\n \n for (int d = 0; d < in_dim; d++) {\n scalar_t x = input[input_offset + d];\n proj_val += x * proj_weight[d * out_dim + h];\n gate_val += x * gate_weight[d * out_dim + h];\n }\n \n // Sigmoid\n gate_val = scalar_t(1.0) / (scalar_t(1.0) + exp(-gate_val));\n \n output[output_offset + h] = proj_val * gate_val * mask_val;\n }\n}\n\n// Einsum kernel: bkih,bkjh->bijh\ntemplate <typename scalar_t>\n__global__ void einsum_incoming_kernel(\n const scalar_t* __restrict__ a,\n const scalar_t* __restrict__ b,\n scalar_t* __restrict__ out,\n int batch_size, int N, int H) {\n \n int b_idx = blockIdx.z;\n int h = blockIdx.y;\n int ij = blockIdx.x * blockDim.x + threadIdx.x;\n int i = ij / N;\n int j = ij % N;\n \n if (i >= N || j >= N) return;\n \n scalar_t sum = 0;\n for (int k = 0; k < N; k++) {\n int a_idx = ((b_idx * N + k) * N + i) * H + h;\n int b_idx_local = ((b_idx * N + k) * N + j) * H + h;\n sum += a[a_idx] * b[b_idx_local];\n }\n \n out[((b_idx * N + i) * N + j) * H + h] = sum;\n}\n\n// Output projection kernel\ntemplate <typename scalar_t>\n__global__ void output_proj_kernel(\n const scalar_t* __restrict__ pair_repr,\n const scalar_t* __restrict__ norm_out,\n const scalar_t* __restrict__ proj_weight,\n const scalar_t* __restrict__ proj_bias,\n const scalar_t* __restrict__ gate_weight,\n const scalar_t* __restrict__ gate_bias,\n scalar_t* __restrict__ output,\n int batch_size, int N, int in_dim, int out_dim) {\n \n int b = blockIdx.x;\n int ij = blockIdx.y * blockDim.x + threadIdx.x;\n int i = ij / N;\n int j = ij % N;\n \n if (i >= N || j >= N) return;\n \n int input_offset = ((b * N + i) * N + j) * in_dim;\n int pair_offset = ((b * N + i) * N + j) * out_dim;\n int output_offset = pair_offset;\n \n // Compute projection\n for (int h = 0; h < out_dim; h++) {\n scalar_t proj_val = proj_bias[h];\n for (int d = 0; d < in_dim; d++) {\n proj_val += norm_out[input_offset + d] * proj_weight[d * out_dim + h];\n }\n \n // Compute gate\n scalar_t gate_val = gate_bias[h];\n for (int d = 0; d < out_dim; d++) {\n gate_val += pair_repr[pair_offset + d] * gate_weight[d * out_dim + h];\n }\n gate_val = scalar_t(1.0) / (scalar_t(1.0) + exp(-gate_val));\n \n output[output_offset + h] = gate_val * proj_val;\n }\n}\n\n// Host functions\ntorch::Tensor layer_norm_cuda(torch::Tensor input, torch::Tensor weight, torch::Tensor bias) {\n auto sizes = input.sizes();\n int total = 1;\n for (int i = 0; i < sizes.size() - 1; i++) total *= sizes[i];\n int dim = sizes[sizes.size() - 1];\n \n auto output = torch::empty_like(input);\n \n const int threads = 256;\n const int blocks = (total + threads - 1) / threads;\n \n AT_DISPATCH_FLOATING_TYPES(input.scalar_type(), \"layer_norm_cuda\", ([&] {\n layer_norm_kernel<scalar_t><<<blocks, threads>>>(\n input.data_ptr<scalar_t>(),\n output.data_ptr<scalar_t>(),\n weight.data_ptr<scalar_t>(),\n bias.data_ptr<scalar_t>(),\n total, dim, dim);\n }));\n \n return output;\n}\n\ntorch::Tensor linear_gated_cuda(\n torch::Tensor input,\n torch::Tensor proj_weight, torch::Tensor proj_bias,\n torch::Tensor gate_weight, torch::Tensor gate_bias,\n torch::Tensor mask, int out_dim) {\n \n auto sizes = input.sizes();\n int batch_size = sizes[0];\n int N = sizes[1];\n int in_dim = sizes[3];\n \n auto output = torch::zeros({batch_size, N, N, out_dim}, input.options());\n \n dim3 blocks(batch_size, (N * N + 255) / 256);\n const int threads = 256;\n \n bool has_mask = mask.defined() && mask.numel() > 0;\n \n AT_DISPATCH_FLOATING_TYPES(input.scalar_type(), \"linear_gated_cuda\", ([&] {\n linear_gated_kernel<scalar_t><<<blocks, threads>>>(\n input.data_ptr<scalar_t>(),\n proj_weight.data_ptr<scalar_t>(),\n proj_bias.data_ptr<scalar_t>(),\n gate_weight.data_ptr<scalar_t>(),\n gate_bias.data_ptr<scalar_t>(),\n output.data_ptr<scalar_t>(),\n has_mask ? mask.data_ptr<scalar_t>() : nullptr,\n batch_size, N, in_dim, out_dim);\n }));\n \n return output;\n}\n\ntorch::Tensor einsum_incoming_cuda(torch::Tensor a, torch::Tensor b) {\n auto sizes = a.sizes();\n int batch_size = sizes[0];\n int N = sizes[1];\n int H = sizes[3];\n \n auto output = torch::zeros({batch_size, N, N, H}, a.options());\n \n dim3 blocks((N * N + 255) / 256, H, batch_size);\n const int threads = 256;\n \n AT_DISPATCH_FLOATING_TYPES(a.scalar_type(), \"einsum_incoming_cuda\", ([&] {\n einsum_incoming_kernel<scalar_t><<<blocks, threads>>>(\n a.data_ptr<scalar_t>(),\n b.data_ptr<scalar_t>(),\n output.data_ptr<scalar_t>(),\n batch_size, N, H);\n }));\n \n return output;\n}\n\ntorch::Tensor output_proj_cuda(\n torch::Tensor pair_repr,\n torch::Tensor norm_out,\n torch::Tensor proj_weight, torch::Tensor proj_bias,\n torch::Tensor gate_weight, torch::Tensor gate_bias,\n int out_dim) {\n \n auto sizes = norm_out.sizes();\n int batch_size = sizes[0];\n int N = sizes[1];\n int in_dim = sizes[3];\n \n auto output = torch::zeros({batch_size, N, N, out_dim}, norm_out.options());\n \n dim3 blocks(batch_size, (N * N + 255) / 256);\n const int threads = 256;\n \n AT_DISPATCH_FLOATING_TYPES(norm_out.scalar_type(), \"output_proj_cuda\", ([&] {\n output_proj_kernel<scalar_t><<<blocks, threads>>>(\n pair_repr.data_ptr<scalar_t>(),\n norm_out.data_ptr<scalar_t>(),\n proj_weight.data_ptr<scalar_t>(),\n proj_bias.data_ptr<scalar_t>(),\n gate_weight.data_ptr<scalar_t>(),\n gate_bias.data_ptr<scalar_t>(),\n output.data_ptr<scalar_t>(),\n batch_size, N, in_dim, out_dim);\n }));\n \n return output;\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor layer_norm_cuda(torch::Tensor input, torch::Tensor weight, torch::Tensor bias);\ntorch::Tensor linear_gated_cuda(torch::Tensor input, torch::Tensor proj_weight, torch::Tensor proj_bias, torch::Tensor gate_weight, torch::Tensor gate_bias, torch::Tensor mask, int out_dim);\ntorch::Tensor einsum_incoming_cuda(torch::Tensor a, torch::Tensor b);\ntorch::Tensor output_proj_cuda(torch::Tensor pair_repr, torch::Tensor norm_out, torch::Tensor proj_weight, torch::Tensor proj_bias, torch::Tensor gate_weight, torch::Tensor gate_bias, int out_dim);\n\"\"\"\n\nmodule = load_inline(\n name='tri_mul_cuda',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['layer_norm_cuda', 'linear_gated_cuda', 'einsum_incoming_cuda', 'output_proj_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, pair_dim, hidden_dim):\n super().__init__()\n self.layer_norm_in = nn.LayerNorm(pair_dim)\n self.proj_a = nn.Linear(pair_dim, hidden_dim)\n self.gate_a = nn.Linear(pair_dim, hidden_dim)\n self.proj_b = nn.Linear(pair_dim, hidden_dim)\n self.gate_b = nn.Linear(pair_dim, hidden_dim)\n self.layer_norm_out = nn.LayerNorm(hidden_dim)\n self.out_proj = nn.Linear(hidden_dim, pair_dim)\n self.out_gate = nn.Linear(pair_dim, pair_dim)\n \n self.pair_dim = pair_dim\n self.hidden_dim = hidden_dim\n\n def forward(self, pair_repr: torch.Tensor, pair_mask: torch.Tensor) -> torch.Tensor:\n pair_repr = pair_repr.contiguous()\n pair_mask = pair_mask.contiguous()\n \n # LayerNorm input\n x = module.layer_norm_cuda(\n pair_repr,\n self.layer_norm_in.weight,\n self.layer_norm_in.bias\n )\n \n # Linear + gated for a\n a = module.linear_gated_cuda(\n x,\n self.proj_a.weight.transpose(0, 1).contiguous(),\n self.proj_a.bias,\n self.gate_a.weight.transpose(0, 1).contiguous(),\n self.gate_a.bias,\n pair_mask,\n self.hidden_dim\n )\n \n # Linear + gated for b\n b = module.linear_gated_cuda(\n x,\n self.proj_b.weight.transpose(0, 1).contiguous(),\n self.proj_b.bias,\n self.gate_b.weight.transpose(0, 1).contiguous(),\n self.gate_b.bias,\n pair_mask,\n self.hidden_dim\n )\n \n # Einsum incoming\n out = module.einsum_incoming_cuda(a, b)\n \n # LayerNorm output\n out = module.layer_norm_cuda(\n out,\n self.layer_norm_out.weight,\n self.layer_norm_out.bias\n )\n \n # Output projection with gate\n result = module.output_proj_cuda(\n pair_repr,\n out,\n self.out_proj.weight.transpose(0, 1).contiguous(),\n self.out_proj.bias,\n self.out_gate.weight.transpose(0, 1).contiguous(),\n self.out_gate.bias,\n self.pair_dim\n )\n \n return result"
}