call → submit_kernel
callsubmit_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\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\n\ntorch::Tensor opm_outer_cuda(torch::Tensor a, torch::Tensor b);\ntorch::Tensor sigmoid_mul_cuda(torch::Tensor x, torch::Tensor g);\ntorch::Tensor tri_einsum_cuda(torch::Tensor a, torch::Tensor b);\ntorch::Tensor gate_residual_cuda(torch::Tensor pair, torch::Tensor gate, torch::Tensor o);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void opm_outer_kernel(const float* __restrict__ a,\n const float* __restrict__ b,\n float* __restrict__ out,\n int B, int S, int N, int H) {\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n long long total = (long long)B * N * N * H * H;\n if (idx >= total) return;\n\n int hh = idx % (H * H);\n int h2 = hh % H;\n int h1 = hh / H;\n long long t = idx / (H * H);\n int j = t % N;\n t /= N;\n int i = t % N;\n int bb = t / N;\n\n float sum = 0.0f;\n // a,b are contiguous [B,S,N,H]\n long long base_a = ((long long)bb * S * N + i) * H + h1;\n long long base_b = ((long long)bb * S * N + j) * H + h2;\n int stride_s = N * H;\n #pragma unroll\n for (int s = 0; s < 8; ++s) {\n if (s < S) sum += a[base_a + (long long)s * stride_s] * b[base_b + (long long)s * stride_s];\n }\n out[idx] = sum / (float)S;\n}\n\n__global__ void sigmoid_mul_kernel(const float* __restrict__ x,\n const float* __restrict__ g,\n float* __restrict__ out,\n long long total) {\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n float gv = g[idx];\n float sig = 1.0f / (1.0f + expf(-gv));\n out[idx] = x[idx] * sig;\n}\n\n__global__ void tri_einsum_kernel(const float* __restrict__ a,\n const float* __restrict__ b,\n float* __restrict__ out,\n int B, int N, int H) {\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n long long total = (long long)B * N * N * H;\n if (idx >= total) return;\n int h = idx % H;\n long long t = idx / H;\n int j = t % N;\n t /= N;\n int i = t % N;\n int bb = t / N;\n\n float sum = 0.0f;\n // a is [B,i,k,h], b is [B,j,k,h], both contiguous [B,N,N,H]\n long long base_a = ((long long)bb * N * N + (long long)i * N) * H + h;\n long long base_b = ((long long)bb * N * N + (long long)j * N) * H + h;\n #pragma unroll\n for (int k = 0; k < 32; ++k) {\n if (k < N) sum += a[base_a + (long long)k * H] * b[base_b + (long long)k * H];\n }\n out[idx] = sum;\n}\n\n__global__ void gate_residual_kernel(const float* __restrict__ pair,\n const float* __restrict__ gate,\n const float* __restrict__ o,\n float* __restrict__ out,\n long long total) {\n long long idx = (long long)blockIdx.x * blockDim.x + threadIdx.x;\n if (idx >= total) return;\n float gv = gate[idx];\n float sig = 1.0f / (1.0f + expf(-gv));\n out[idx] = pair[idx] + sig * o[idx];\n}\n\ntorch::Tensor opm_outer_cuda(torch::Tensor a, torch::Tensor b) {\n const at::cuda::OptionalCUDAGuard device_guard(device_of(a));\n int B = (int)a.size(0);\n int S = (int)a.size(1);\n int N = (int)a.size(2);\n int H = (int)a.size(3);\n auto out = torch::empty({B, N, N, H * H}, a.options());\n long long total = (long long)B * N * N * H * H;\n int threads = 256;\n int blocks = (int)((total + threads - 1) / threads);\n opm_outer_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n a.data_ptr<float>(), b.data_ptr<float>(), out.data_ptr<float>(), B, S, N, H);\n return out;\n}\n\ntorch::Tensor sigmoid_mul_cuda(torch::Tensor x, torch::Tensor g) {\n const at::cuda::OptionalCUDAGuard device_guard(device_of(x));\n auto out = torch::empty_like(x);\n long long total = x.numel();\n int threads = 256;\n int blocks = (int)((total + threads - 1) / threads);\n sigmoid_mul_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n x.data_ptr<float>(), g.data_ptr<float>(), out.data_ptr<float>(), total);\n return out;\n}\n\ntorch::Tensor tri_einsum_cuda(torch::Tensor a, torch::Tensor b) {\n const at::cuda::OptionalCUDAGuard device_guard(device_of(a));\n int B = (int)a.size(0);\n int N = (int)a.size(1);\n int H = (int)a.size(3);\n auto out = torch::empty({B, N, N, H}, a.options());\n long long total = (long long)B * N * N * H;\n int threads = 256;\n int blocks = (int)((total + threads - 1) / threads);\n tri_einsum_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n a.data_ptr<float>(), b.data_ptr<float>(), out.data_ptr<float>(), B, N, H);\n return out;\n}\n\ntorch::Tensor gate_residual_cuda(torch::Tensor pair, torch::Tensor gate, torch::Tensor o) {\n const at::cuda::OptionalCUDAGuard device_guard(device_of(pair));\n auto out = torch::empty_like(pair);\n long long total = pair.numel();\n int threads = 256;\n int blocks = (int)((total + threads - 1) / threads);\n gate_residual_kernel<<<blocks, threads, 0, at::cuda::getCurrentCUDAStream()>>>(\n pair.data_ptr<float>(), gate.data_ptr<float>(), o.data_ptr<float>(), out.data_ptr<float>(), total);\n return out;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"evoformer_small_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"opm_outer_cuda\", \"sigmoid_mul_cuda\", \"tri_einsum_cuda\", \"gate_residual_cuda\"],\n extra_cuda_cflags=[\"-O3\"],\n extra_cflags=[\"-O3\"],\n verbose=False,\n)\n\n\nclass MSARowSelfAttention(nn.Module):\n def __init__(self, msa_dim, num_heads):\n super().__init__()\n self.num_heads = num_heads\n self.head_dim = msa_dim // num_heads\n self.norm = nn.LayerNorm(msa_dim)\n self.q = nn.Linear(msa_dim, msa_dim, bias=False)\n self.k = nn.Linear(msa_dim, msa_dim, bias=False)\n self.v = nn.Linear(msa_dim, msa_dim, bias=False)\n self.out = nn.Linear(msa_dim, msa_dim)\n\n\nclass OuterProductMeanSmall(nn.Module):\n def __init__(self, msa_dim, pair_dim, hidden=32):\n super().__init__()\n self.norm = nn.LayerNorm(msa_dim)\n self.a = nn.Linear(msa_dim, hidden)\n self.b = nn.Linear(msa_dim, hidden)\n self.out = nn.Linear(hidden * hidden, pair_dim)\n\n\nclass TriMulOut(nn.Module):\n def __init__(self, pair_dim, hidden):\n super().__init__()\n self.norm = nn.LayerNorm(pair_dim)\n self.pa = nn.Linear(pair_dim, hidden)\n self.pb = nn.Linear(pair_dim, hidden)\n self.ga = nn.Linear(pair_dim, hidden)\n self.gb = nn.Linear(pair_dim, hidden)\n self.norm_out = nn.LayerNorm(hidden)\n self.out = nn.Linear(hidden, pair_dim)\n self.gate_out = nn.Linear(pair_dim, pair_dim)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, msa_dim, pair_dim, num_heads, tri_hidden):\n super().__init__()\n self.msa_attn = MSARowSelfAttention(msa_dim, num_heads)\n self.opm = OuterProductMeanSmall(msa_dim, pair_dim)\n self.tri_mul = TriMulOut(pair_dim, tri_hidden)\n\n def forward(self, msa_repr: torch.Tensor, pair_repr: torch.Tensor) -> tuple:\n B, S, N, D = msa_repr.shape\n h = self.msa_attn.num_heads\n d = self.msa_attn.head_dim\n\n # MSA row self-attention. Use PyTorch's fused SDPA for the softmax attention core,\n # while keeping the same parameterization and tensor layout as the reference.\n x = F.layer_norm(msa_repr, (D,), self.msa_attn.norm.weight, self.msa_attn.norm.bias)\n q = F.linear(x, self.msa_attn.q.weight, None).view(B, S, N, h, d).permute(0, 1, 3, 2, 4).contiguous()\n k = F.linear(x, self.msa_attn.k.weight, None).view(B, S, N, h, d).permute(0, 1, 3, 2, 4).contiguous()\n v = F.linear(x, self.msa_attn.v.weight, None).view(B, S, N, h, d).permute(0, 1, 3, 2, 4).contiguous()\n attn_out = F.scaled_dot_product_attention(q, k, v, dropout_p=0.0, is_causal=False)\n attn_out = attn_out.permute(0, 1, 3, 2, 4).reshape(B, S, N, D)\n attn_out = F.linear(attn_out, self.msa_attn.out.weight, self.msa_attn.out.bias)\n msa_repr = msa_repr + attn_out\n\n # Outer-product mean: custom CUDA computes the small reduction over MSA depth and\n # materializes the compact [B,N,N,32*32] buffer consumed by the output projection.\n x = F.layer_norm(msa_repr, (D,), self.opm.norm.weight, self.opm.norm.bias)\n aa = F.linear(x, self.opm.a.weight, self.opm.a.bias).contiguous()\n bb = F.linear(x, self.opm.b.weight, self.opm.b.bias).contiguous()\n outer = _ext.opm_outer_cuda(aa, bb)\n opm_update = F.linear(outer, self.opm.out.weight, self.opm.out.bias)\n pair_repr = pair_repr + opm_update\n\n # Triangular multiplicative outgoing update.\n C = pair_repr.shape[-1]\n th = self.tri_mul.pa.out_features\n x = F.layer_norm(pair_repr, (C,), self.tri_mul.norm.weight, self.tri_mul.norm.bias)\n pa = F.linear(x, self.tri_mul.pa.weight, self.tri_mul.pa.bias).contiguous()\n pb = F.linear(x, self.tri_mul.pb.weight, self.tri_mul.pb.bias).contiguous()\n ga = F.linear(x, self.tri_mul.ga.weight, self.tri_mul.ga.bias).contiguous()\n gb = F.linear(x, self.tri_mul.gb.weight, self.tri_mul.gb.bias).contiguous()\n a = _ext.sigmoid_mul_cuda(pa, ga)\n b = _ext.sigmoid_mul_cuda(pb, gb)\n o = _ext.tri_einsum_cuda(a, b)\n o = F.layer_norm(o, (th,), self.tri_mul.norm_out.weight, self.tri_mul.norm_out.bias)\n o = F.linear(o, self.tri_mul.out.weight, self.tri_mul.out.bias)\n gate = F.linear(pair_repr, self.tri_mul.gate_out.weight, self.tri_mul.gate_out.bias).contiguous()\n pair_repr = _ext.gate_residual_cuda(pair_repr.contiguous(), gate, o.contiguous())\n return msa_repr, pair_repr\n"
}