FW-GLM-5-1 · popcorn · pop_l123_default_gpt
correct 20_RotaryPositionEmbeddingBio.py
model
FW-GLM-5-1
turns / max
12 / 12
tool calls
12
tokens (total)
112734
wall clock
3779.8s
truncated
no
backend
cuda fp32
variant
popcorn
runtime
0.02 μs
ref runtime
0.11 μs
speedup
7.16x
started
2026-05-11T14:18:12Z
timingkernelbench.timing
kernel runtime
0.02 μs
ref runtime
0.11 μs
speedup
7.16x
kernel mean / median / std
0.02 / — / 5.11e-04 μs
ref mean / median / std
0.11 / — / 0.08 μs
numerical precisioneval_kernel_against_ref
max abs error
4.77e-07
mean abs error
1.43e-08
max rel error
0.01
mean rel error
5.94e-08
gpu memoryextended_metrics.measure_memory
kernel peak
45.00 MB
ref peak
45.13 MB
kernel / ref
1.00x
kernel launches / fusiontorch.profiler
kernel launches
11
ref launches
45
fusion ratio (ref / kernel)
4.09x
total cuda time
254 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.384
dram util %
38.4%
compute util %
35.2%
bottleneck
memory-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
1286.28 GB/s
dram util %
38.4%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
146.4%
bottleneck
memory-bound
dominant pipe %
35.2%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
112.0%
ld sectors / req
20.00
st sectors / req
—
regs / thread
48
smem / block
2048 B
block size
384
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
5845.8%
mio_throttle
1790.3%
short_scoreboard
1041.1%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
import math


class Model(nn.Module):
    """
    Rotary Position Embedding (RoPE) applied to protein residue sequences.
    Used in ESM-2 and similar protein language models.  Encodes absolute
    position via rotation of query/key pairs in 2-D subspaces, preserving
    relative-position information in dot-product attention.
    """

    def __init__(self, dim, max_seq_len=2048, base=10000.0):
        super().__init__()
        inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
        self.register_buffer("inv_freq", inv_freq)
        self.max_seq_len = max_seq_len
        self.dim = dim

    def _build_cos_sin(self, seq_len: int, device: torch.device):
        t = torch.arange(seq_len, device=device, dtype=self.inv_freq.dtype)
        freqs = torch.outer(t, self.inv_freq)
        emb = torch.cat([freqs, freqs], dim=-1)
        return emb.cos(), emb.sin()

    @staticmethod
    def _rotate_half(x: torch.Tensor) -> torch.Tensor:
        x1, x2 = x.chunk(2, dim=-1)
        return torch.cat([-x2, x1], dim=-1)

    def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:
        """
        Args:
            q: (B, H, N, D)  – queries
            k: (B, H, N, D)  – keys
        Returns:
            (q_rot, k_rot) each (B, H, N, D) with RoPE applied
        """
        N = q.shape[2]
        cos, sin = self._build_cos_sin(N, q.device)  # (N, D)
        cos = cos.unsqueeze(0).unsqueeze(0)
        sin = sin.unsqueeze(0).unsqueeze(0)
        q_rot = q * cos + self._rotate_half(q) * sin
        k_rot = k * cos + self._rotate_half(k) * sin
        return q_rot, k_rot


dim = 64
num_heads = 8
seq_len = 256
batch_size = 4


def get_inputs():
    p = popcorn_pri
    bs = p.jitter_int(batch_size)
    nh = p.jitter_int(num_heads)
    sl = p.jitter_int(seq_len)
    q = torch.randn(bs, nh, sl, dim)
    k = torch.randn(bs, nh, sl, dim)
    return [q, k]


def get_init_inputs():
    return [dim]
turn 0363.7s turn · 2.9s LLM · 360.8s tools · tokens in=1,775 · out=119 · total=1,894
reasoning
Let me analyze the task. I need to implement a Rotary Position Embedding (RoPE) kernel in CUDA that: 1. Takes query and key tensors of shape (B, H, N, D) 2. Builds cos/sin tables based on sequence length 3. Applies rotation: q_rot = q * cos + rotate_half(q) * sin The rotation operation: - split x into x1, x2 along last dimension - return concat([-x2, x1]) Let me first get GPU specs to understand the hardware constraints.
call → get_gpu_specs
callget_gpu_specs {}
result ← get_gpu_specs (ok)
okget_gpu_specs GPU specs for NVIDIA H100 80GB HBM3: total memory (runtime): 79.1 GB spec entry: H100 GPU Architecture: Hopper GPU Memory: 80GB Memory Bandwidth: 3.35 TB/s FP64 TFLOPS: 34 FP64 Tensor Core TFLOPS: 67 FP32 TFLOPS: 67 TF32 Tensor Core TFLOPS: 989 with sparsity BFLOAT16 Tensore Core TFLOPS: 1979 with sparsity FP16 Tensor Core TFLOPS: 1979 with sparsity FP8 Tensor Core TFLOPS: 3958 with sparsity INT8 Tensor Core TOPS: 3958 with sparsity Register File Size: 64K 32-bit registers per SM Maximum number of registers per thread: 255 Maximum number of thread blocks per SM: 32 Shared memory capacity per SM: 228 KB Maximum shared memory per thread block: 227 KB
turn 1 · 1 tool call(s) · 274.9s turn · 16.0s LLM · tokens in=2,023 · out=1,545 · total=3,568 · 6,812 chars (click to expand)
turn 1274.9s turn · 16.0s LLM · 258.8s tools · tokens in=2,023 · out=1,545 · total=3,568
reasoning
Now let me write an initial CUDA kernel for the RoPE operation. The key operations are: 1. Build cos/sin tables (N, D) from inv_freq 2. Broadcast to (1, 1, N, D) and apply rotation The rotation formula is: q_rot = q * cos + rotate_half(q) * sin where rotate_half concatenates [-x2, x1] after splitting x into [x1, x2]. Let me write a fused kernel that: 1. Pre-computes cos/sin tables (or loads them if precomputed) 2. Applies the rotation to both q and k I'll start with a straightforward implementation and optimize from there.
assistantLet me write an initial CUDA kernel implementation for RoPE. I'll fuse the cos/sin table computation and the rotation operation.
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__device__ __forceinline__ float get_inv_freq(int i, int dim, float base) {\n // inv_freq[i] = 1.0 / (base ** (2*i / dim)) where i goes from 0 to dim/2-1\n float exponent = (2.0f * (float)i) / (float)dim;\n return 1.0f / powf(base, exponent);\n}\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim, float base\n) {\n // Each thread handles one element of the output\n // Grid: (batch_size * num_heads * seq_len) blocks, each with (dim) threads\n // Or we can use 2D grid\n \n int b = blockIdx.z; // batch\n int h = blockIdx.y; // head\n int n = blockIdx.x; // sequence position\n \n if (b >= batch_size || h >= num_heads || n >= seq_len) return;\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n // Compute cos/sin for this position n\n // We need cos and sin for all dim/2 frequencies\n // Each thread handles one element\n \n for (int d = threadIdx.x; d < dim; d += blockDim.x) {\n int half_d = dim / 2;\n \n // Determine which frequency index and cos/sin value to use\n int freq_idx;\n float cos_val, sin_val;\n \n if (d < half_d) {\n // First half: use inv_freq[d], angle = n * inv_freq[d]\n freq_idx = d;\n } else {\n // Second half: use inv_freq[d - half_d], angle = n * inv_freq[d - half_d]\n freq_idx = d - half_d;\n }\n \n // Compute angle = n * inv_freq[freq_idx]\n float inv_f = inv_freq[freq_idx];\n float angle = (float)n * inv_f;\n cos_val = cosf(angle);\n sin_val = sinf(angle);\n \n // Apply rotation\n float q_val = q[base_idx + d];\n float k_val = k[base_idx + d];\n \n float q_rot, k_rot;\n \n if (d < half_d) {\n // x1 part: x1 * cos - x2 * sin\n // Need x2 value\n float q_x2 = q[base_idx + d + half_d];\n float k_x2 = k[base_idx + d + half_d];\n q_rot = q_val * cos_val - q_x2 * sin_val;\n k_rot = k_val * cos_val - k_x2 * sin_val;\n } else {\n // x2 part: x2 * cos + x1 * sin\n // Need x1 value\n float q_x1 = q[base_idx + d - half_d];\n float k_x1 = k[base_idx + d - half_d];\n q_rot = q_val * cos_val + q_x1 * sin_val;\n k_rot = k_val * cos_val + k_x1 * sin_val;\n }\n \n q_out[base_idx + d] = q_rot;\n k_out[base_idx + d] = k_rot;\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n \n dim3 grid(seq_len, num_heads, batch_size);\n dim3 block(std::min(dim, 1024));\n \n rope_kernel<<<grid, block>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim, (float)base\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n q: (B, H, N, D) \u2013 queries\n k: (B, H, N, D) \u2013 keys\n Returns:\n (q_rot, k_rot) each (B, H, N, D) with RoPE applied\n \"\"\"\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 2 · 1 tool call(s) · 577.8s turn · 11.9s LLM · tokens in=3,437 · out=1,389 · total=4,826 · 6,240 chars (click to expand)
turn 2577.8s turn · 11.9s LLM · 565.9s tools · tokens in=3,437 · out=1,389 · total=4,826
reasoning
The kernel compiled successfully. Now let me run the correctness check.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__device__ __forceinline__ float get_inv_freq(int i, int dim, float base) {\n // inv_freq[i] = 1.0 / (base ** (2*i / dim)) where i goes from 0 to dim/2-1\n float exponent = (2.0f * (float)i) / (float)dim;\n return 1.0f / powf(base, exponent);\n}\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim, float base\n) {\n // Each thread handles one element of the output\n // Grid: (batch_size * num_heads * seq_len) blocks, each with (dim) threads\n // Or we can use 2D grid\n \n int b = blockIdx.z; // batch\n int h = blockIdx.y; // head\n int n = blockIdx.x; // sequence position\n \n if (b >= batch_size || h >= num_heads || n >= seq_len) return;\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n // Compute cos/sin for this position n\n // We need cos and sin for all dim/2 frequencies\n // Each thread handles one element\n \n for (int d = threadIdx.x; d < dim; d += blockDim.x) {\n int half_d = dim / 2;\n \n // Determine which frequency index and cos/sin value to use\n int freq_idx;\n float cos_val, sin_val;\n \n if (d < half_d) {\n // First half: use inv_freq[d], angle = n * inv_freq[d]\n freq_idx = d;\n } else {\n // Second half: use inv_freq[d - half_d], angle = n * inv_freq[d - half_d]\n freq_idx = d - half_d;\n }\n \n // Compute angle = n * inv_freq[freq_idx]\n float inv_f = inv_freq[freq_idx];\n float angle = (float)n * inv_f;\n cos_val = cosf(angle);\n sin_val = sinf(angle);\n \n // Apply rotation\n float q_val = q[base_idx + d];\n float k_val = k[base_idx + d];\n \n float q_rot, k_rot;\n \n if (d < half_d) {\n // x1 part: x1 * cos - x2 * sin\n // Need x2 value\n float q_x2 = q[base_idx + d + half_d];\n float k_x2 = k[base_idx + d + half_d];\n q_rot = q_val * cos_val - q_x2 * sin_val;\n k_rot = k_val * cos_val - k_x2 * sin_val;\n } else {\n // x2 part: x2 * cos + x1 * sin\n // Need x1 value\n float q_x1 = q[base_idx + d - half_d];\n float k_x1 = k[base_idx + d - half_d];\n q_rot = q_val * cos_val + q_x1 * sin_val;\n k_rot = k_val * cos_val + k_x1 * sin_val;\n }\n \n q_out[base_idx + d] = q_rot;\n k_out[base_idx + d] = k_rot;\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n \n dim3 grid(seq_len, num_heads, batch_size);\n dim3 block(std::min(dim, 1024));\n \n rope_kernel<<<grid, block>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim, (float)base\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n q: (B, H, N, D) \u2013 queries\n k: (B, H, N, D) \u2013 keys\n Returns:\n (q_rot, k_rot) each (B, H, N, D) with RoPE applied\n \"\"\"\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.77e-07 mean_abs_err=1.43e-08 max_rel_err=8.85e-03
turn 3 · 1 tool call(s) · 273.5s turn · 13.0s LLM · tokens in=4,870 · out=1,387 · total=6,257 · 6,302 chars (click to expand)
turn 3273.5s turn · 13.0s LLM · 260.4s tools · tokens in=4,870 · out=1,387 · total=6,257
reasoning
The kernel passes correctness. Now let me optimize it further. The current implementation: 1. Each thread block handles one (batch, head, seq_pos) tuple 2. Threads in the block iterate over the dim dimension 3. Each thread computes cos/sin values which is redundant Optimizations I can apply: 1. Precompute cos/sin tables for all positions and store in shared memory 2. Use vectorized loads/stores for better memory bandwidth 3. Reduce the number of cos/sin computations by having threads cooperate 4. Use a more efficient grid/block arrangement Let me try a version where we precompute cos/sin in shared memory within each block.
assistantThe kernel passes correctness. Let me optimize it further by using shared memory to compute cos/sin values once per position, and use vectorized memory access.
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim\n) {\n // Each thread handles one (b, h, n, d) element\n // Flatten: total elements = batch_size * num_heads * seq_len * dim\n \n int half_dim = dim / 2;\n int total = batch_size * num_heads * seq_len * dim;\n \n for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += blockDim.x * gridDim.x) {\n int d = idx % dim;\n int n = (idx / dim) % seq_len;\n int h = (idx / (dim * seq_len)) % num_heads;\n int b = idx / (dim * seq_len * num_heads);\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n // Determine frequency index\n int freq_idx = (d < half_dim) ? d : (d - half_dim);\n \n // Compute angle = n * inv_freq[freq_idx]\n float inv_f = inv_freq[freq_idx];\n float angle = (float)n * inv_f;\n float cos_val = cosf(angle);\n float sin_val = sinf(angle);\n \n // Apply rotation\n if (d < half_dim) {\n // x1 part: x1 * cos - x2 * sin\n float q_x1 = q[base_idx + d];\n float k_x1 = k[base_idx + d];\n float q_x2 = q[base_idx + d + half_dim];\n float k_x2 = k[base_idx + d + half_dim];\n q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;\n k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;\n } else {\n // x2 part: x2 * cos + x1 * sin\n float q_x2 = q[base_idx + d];\n float k_x2 = k[base_idx + d];\n float q_x1 = q[base_idx + d - half_dim];\n float k_x1 = k[base_idx + d - half_dim];\n q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;\n k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;\n }\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n \n int total = batch_size * num_heads * seq_len * dim;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n blocks = std::min(blocks, 65535);\n \n rope_kernel<<<blocks, threads>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension_v2',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n q: (B, H, N, D) \u2013 queries\n k: (B, H, N, D) \u2013 keys\n Returns:\n (q_rot, k_rot) each (B, H, N, D) with RoPE applied\n \"\"\"\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 4285.0s turn · 10.3s LLM · 274.8s tools · tokens in=6,131 · out=1,224 · total=7,355
reasoning
Let me check correctness again.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim\n) {\n // Each thread handles one (b, h, n, d) element\n // Flatten: total elements = batch_size * num_heads * seq_len * dim\n \n int half_dim = dim / 2;\n int total = batch_size * num_heads * seq_len * dim;\n \n for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += blockDim.x * gridDim.x) {\n int d = idx % dim;\n int n = (idx / dim) % seq_len;\n int h = (idx / (dim * seq_len)) % num_heads;\n int b = idx / (dim * seq_len * num_heads);\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n // Determine frequency index\n int freq_idx = (d < half_dim) ? d : (d - half_dim);\n \n // Compute angle = n * inv_freq[freq_idx]\n float inv_f = inv_freq[freq_idx];\n float angle = (float)n * inv_f;\n float cos_val = cosf(angle);\n float sin_val = sinf(angle);\n \n // Apply rotation\n if (d < half_dim) {\n // x1 part: x1 * cos - x2 * sin\n float q_x1 = q[base_idx + d];\n float k_x1 = k[base_idx + d];\n float q_x2 = q[base_idx + d + half_dim];\n float k_x2 = k[base_idx + d + half_dim];\n q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;\n k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;\n } else {\n // x2 part: x2 * cos + x1 * sin\n float q_x2 = q[base_idx + d];\n float k_x2 = k[base_idx + d];\n float q_x1 = q[base_idx + d - half_dim];\n float k_x1 = k[base_idx + d - half_dim];\n q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;\n k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;\n }\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n \n int total = batch_size * num_heads * seq_len * dim;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n blocks = std::min(blocks, 65535);\n \n rope_kernel<<<blocks, threads>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension_v2',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n q: (B, H, N, D) \u2013 queries\n k: (B, H, N, D) \u2013 keys\n Returns:\n (q_rot, k_rot) each (B, H, N, D) with RoPE applied\n \"\"\"\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.77e-07 mean_abs_err=1.43e-08 max_rel_err=8.85e-03
turn 5 · 1 tool call(s) · 416.7s turn · 13.0s LLM · tokens in=7,406 · out=1,401 · total=8,807 · 6,342 chars (click to expand)
turn 5416.7s turn · 13.0s LLM · 403.7s tools · tokens in=7,406 · out=1,401 · total=8,807
reasoning
Let me try a more optimized version that uses shared memory to precompute cos/sin values per position, reducing redundant computation across heads and batches. Also, I can use float4 vectorized loads/stores.
assistantLet me try a more optimized version using shared memory to precompute cos/sin values per position:
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim\n) {\n // Use shared memory for cos/sin values per position\n // Each block handles one (n) position, with threads for different (b, h, d)\n int half_dim = dim / 2;\n \n // Shared memory for cos/sin values for this position\n extern __shared__ float shared_cos_sin[];\n float* cos_vals = shared_cos_sin;\n float* sin_vals = shared_cos_sin + half_dim;\n \n int n = blockIdx.x; // Each block handles one sequence position\n int tid = threadIdx.x;\n \n // Load inv_freq and compute cos/sin for this position\n // Threads cooperate to compute all half_dim cos/sin values\n for (int i = tid; i < half_dim; i += blockDim.x) {\n float angle = (float)n * inv_freq[i];\n cos_vals[i] = cosf(angle);\n sin_vals[i] = sinf(angle);\n }\n __syncthreads();\n \n // Now each thread handles one output element\n // Thread and block mapping: each thread handles a specific (b, h, d)\n // Total work: batch_size * num_heads * dim per position\n \n int total_per_pos = batch_size * num_heads * dim;\n \n for (int idx = tid; idx < total_per_pos; idx += blockDim.x) {\n int d = idx % dim;\n int h = (idx / dim) % num_heads;\n int b = idx / (dim * num_heads);\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n int freq_idx = (d < half_dim) ? d : (d - half_dim);\n float cos_val = cos_vals[freq_idx];\n float sin_val = sin_vals[freq_idx];\n \n if (d < half_dim) {\n // x1 part: x1 * cos - x2 * sin\n float q_x1 = q[base_idx + d];\n float k_x1 = k[base_idx + d];\n float q_x2 = q[base_idx + d + half_dim];\n float k_x2 = k[base_idx + d + half_dim];\n q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;\n k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;\n } else {\n // x2 part: x2 * cos + x1 * sin\n float q_x2 = q[base_idx + d];\n float k_x2 = k[base_idx + d];\n float q_x1 = q[base_idx + d - half_dim];\n float k_x1 = k[base_idx + d - half_dim];\n q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;\n k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;\n }\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n int half_dim = dim / 2;\n \n int threads = 256;\n int blocks = seq_len;\n int shared_mem = half_dim * 2 * sizeof(float);\n \n rope_kernel<<<blocks, threads, shared_mem>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension_v3',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n q: (B, H, N, D) \u2013 queries\n k: (B, H, N, D) \u2013 keys\n Returns:\n (q_rot, k_rot) each (B, H, N, D) with RoPE applied\n \"\"\"\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 6 · 1 tool call(s) · 396.8s turn · 11.7s LLM · tokens in=8,778 · out=1,350 · total=10,128 · 6,121 chars (click to expand)
turn 6396.8s turn · 11.7s LLM · 385.0s tools · tokens in=8,778 · out=1,350 · total=10,128
reasoning
Let me check correctness for this shared memory version.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim\n) {\n // Use shared memory for cos/sin values per position\n // Each block handles one (n) position, with threads for different (b, h, d)\n int half_dim = dim / 2;\n \n // Shared memory for cos/sin values for this position\n extern __shared__ float shared_cos_sin[];\n float* cos_vals = shared_cos_sin;\n float* sin_vals = shared_cos_sin + half_dim;\n \n int n = blockIdx.x; // Each block handles one sequence position\n int tid = threadIdx.x;\n \n // Load inv_freq and compute cos/sin for this position\n // Threads cooperate to compute all half_dim cos/sin values\n for (int i = tid; i < half_dim; i += blockDim.x) {\n float angle = (float)n * inv_freq[i];\n cos_vals[i] = cosf(angle);\n sin_vals[i] = sinf(angle);\n }\n __syncthreads();\n \n // Now each thread handles one output element\n // Thread and block mapping: each thread handles a specific (b, h, d)\n // Total work: batch_size * num_heads * dim per position\n \n int total_per_pos = batch_size * num_heads * dim;\n \n for (int idx = tid; idx < total_per_pos; idx += blockDim.x) {\n int d = idx % dim;\n int h = (idx / dim) % num_heads;\n int b = idx / (dim * num_heads);\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n int freq_idx = (d < half_dim) ? d : (d - half_dim);\n float cos_val = cos_vals[freq_idx];\n float sin_val = sin_vals[freq_idx];\n \n if (d < half_dim) {\n // x1 part: x1 * cos - x2 * sin\n float q_x1 = q[base_idx + d];\n float k_x1 = k[base_idx + d];\n float q_x2 = q[base_idx + d + half_dim];\n float k_x2 = k[base_idx + d + half_dim];\n q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;\n k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;\n } else {\n // x2 part: x2 * cos + x1 * sin\n float q_x2 = q[base_idx + d];\n float k_x2 = k[base_idx + d];\n float q_x1 = q[base_idx + d - half_dim];\n float k_x1 = k[base_idx + d - half_dim];\n q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;\n k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;\n }\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n int half_dim = dim / 2;\n \n int threads = 256;\n int blocks = seq_len;\n int shared_mem = half_dim * 2 * sizeof(float);\n \n rope_kernel<<<blocks, threads, shared_mem>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension_v3',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n q: (B, H, N, D) \u2013 queries\n k: (B, H, N, D) \u2013 keys\n Returns:\n (q_rot, k_rot) each (B, H, N, D) with RoPE applied\n \"\"\"\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.77e-07 mean_abs_err=1.43e-08 max_rel_err=8.85e-03
turn 7 · 1 tool call(s) · 330.4s turn · 11.6s LLM · tokens in=10,175 · out=1,338 · total=11,513 · 6,023 chars (click to expand)
turn 7330.4s turn · 11.6s LLM · 318.7s tools · tokens in=10,175 · out=1,338 · total=11,513
reasoning
Good, correctness passes. Now let me try to further optimize using float4 vectorized loads/stores to improve memory throughput. This is key for getting good performance on H100.
assistantLet me try to optimize further using float4 vectorized loads/stores for better memory throughput:
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__device__ __forceinline__ void sincosf_fast(float x, float* s, float* c) {\n // Use built-in sincosf which is often faster\n sincosf(x, s, c);\n}\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim\n) {\n // Each thread handles one (b, h, n, d) element - simple, for good memory coalescing\n // dim is typically 64, so we can have good memory access patterns\n \n int half_dim = dim / 2;\n int total = batch_size * num_heads * seq_len * dim;\n \n for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += blockDim.x * gridDim.x) {\n int d = idx % dim;\n int n = (idx / dim) % seq_len;\n int h = (idx / (dim * seq_len)) % num_heads;\n int b = idx / (dim * seq_len * num_heads);\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n // Determine frequency index\n int freq_idx = (d < half_dim) ? d : (d - half_dim);\n \n // Compute angle = n * inv_freq[freq_idx]\n float inv_f = inv_freq[freq_idx];\n float angle = (float)n * inv_f;\n float cos_val, sin_val;\n sincosf_fast(angle, &sin_val, &cos_val);\n \n // Apply rotation\n if (d < half_dim) {\n // x1 part: x1 * cos - x2 * sin\n float q_x1 = q[base_idx + d];\n float k_x1 = k[base_idx + d];\n float q_x2 = q[base_idx + d + half_dim];\n float k_x2 = k[base_idx + d + half_dim];\n q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;\n k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;\n } else {\n // x2 part: x2 * cos + x1 * sin\n float q_x2 = q[base_idx + d];\n float k_x2 = k[base_idx + d];\n float q_x1 = q[base_idx + d - half_dim];\n float k_x1 = k[base_idx + d - half_dim];\n q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;\n k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;\n }\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n \n int total = batch_size * num_heads * seq_len * dim;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n blocks = std::min(blocks, 65535);\n \n rope_kernel<<<blocks, threads>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension_v4',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n q: (B, H, N, D) \u2013 queries\n k: (B, H, N, D) \u2013 keys\n Returns:\n (q_rot, k_rot) each (B, H, N, D) with RoPE applied\n \"\"\"\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 8615.2s turn · 11.0s LLM · 604.2s tools · tokens in=11,490 · out=1,296 · total=12,786
reasoning
Let me run correctness and see if we can improve further.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__device__ __forceinline__ void sincosf_fast(float x, float* s, float* c) {\n // Use built-in sincosf which is often faster\n sincosf(x, s, c);\n}\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim\n) {\n // Each thread handles one (b, h, n, d) element - simple, for good memory coalescing\n // dim is typically 64, so we can have good memory access patterns\n \n int half_dim = dim / 2;\n int total = batch_size * num_heads * seq_len * dim;\n \n for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += blockDim.x * gridDim.x) {\n int d = idx % dim;\n int n = (idx / dim) % seq_len;\n int h = (idx / (dim * seq_len)) % num_heads;\n int b = idx / (dim * seq_len * num_heads);\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n // Determine frequency index\n int freq_idx = (d < half_dim) ? d : (d - half_dim);\n \n // Compute angle = n * inv_freq[freq_idx]\n float inv_f = inv_freq[freq_idx];\n float angle = (float)n * inv_f;\n float cos_val, sin_val;\n sincosf_fast(angle, &sin_val, &cos_val);\n \n // Apply rotation\n if (d < half_dim) {\n // x1 part: x1 * cos - x2 * sin\n float q_x1 = q[base_idx + d];\n float k_x1 = k[base_idx + d];\n float q_x2 = q[base_idx + d + half_dim];\n float k_x2 = k[base_idx + d + half_dim];\n q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;\n k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;\n } else {\n // x2 part: x2 * cos + x1 * sin\n float q_x2 = q[base_idx + d];\n float k_x2 = k[base_idx + d];\n float q_x1 = q[base_idx + d - half_dim];\n float k_x1 = k[base_idx + d - half_dim];\n q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;\n k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;\n }\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n \n int total = batch_size * num_heads * seq_len * dim;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n blocks = std::min(blocks, 65535);\n \n rope_kernel<<<blocks, threads>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension_v4',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n q: (B, H, N, D) \u2013 queries\n k: (B, H, N, D) \u2013 keys\n Returns:\n (q_rot, k_rot) each (B, H, N, D) with RoPE applied\n \"\"\"\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=1.46e-04 mean_abs_err=1.09e-06 max_rel_err=4.60e+00
turn 9170.6s turn · 11.9s LLM · 158.7s tools · tokens in=12,863 · out=1,315 · total=14,178
reasoning
The kernel is correct, but I notice the fast math version has slightly higher numerical error (max_abs_err=1.46e-04 vs 4.77e-07), which is still within tolerance (fp32 uses atol=rtol=1e-4). However, I should consider whether this is acceptable. Let me think about whether I should submit or try more optimizations. The current kernel: 1. Is correct (passes all tests) 2. Uses fast math for sincos which should be faster But the error is a bit higher. Let me try a version without fast math but with the sincos optimization, or perhaps I should submit the version that had lower error. Actually, looking at the error: max_abs_err=1.46e-04 is right at the edge of the tolerance (atol=1e-4). This could potentially fail on some inputs. Let me try a version that uses sincos (which is still faster than separate sin/cos) but without --use_fast_math to preserve numerical accuracy.
assistantThe fast math version has higher numerical error (1.46e-04 is close to the tolerance limit). Let me try a version that uses sincos optimization but without fast math:
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim\n) {\n int half_dim = dim / 2;\n int total = batch_size * num_heads * seq_len * dim;\n \n for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += blockDim.x * gridDim.x) {\n int d = idx % dim;\n int n = (idx / dim) % seq_len;\n int h = (idx / (dim * seq_len)) % num_heads;\n int b = idx / (dim * seq_len * num_heads);\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n int freq_idx = (d < half_dim) ? d : (d - half_dim);\n \n float inv_f = inv_freq[freq_idx];\n float angle = (float)n * inv_f;\n float cos_val, sin_val;\n sincosf(angle, &sin_val, &cos_val);\n \n if (d < half_dim) {\n float q_x1 = q[base_idx + d];\n float k_x1 = k[base_idx + d];\n float q_x2 = q[base_idx + d + half_dim];\n float k_x2 = k[base_idx + d + half_dim];\n q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;\n k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;\n } else {\n float q_x2 = q[base_idx + d];\n float k_x2 = k[base_idx + d];\n float q_x1 = q[base_idx + d - half_dim];\n float k_x1 = k[base_idx + d - half_dim];\n q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;\n k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;\n }\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n \n int total = batch_size * num_heads * seq_len * dim;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n blocks = std::min(blocks, 65535);\n \n rope_kernel<<<blocks, threads>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension_v5',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 109.9s turn · 9.2s LLM · 0.7s tools · tokens in=14,010 · out=1,086 · total=15,096
reasoning
The kernel is compiled. Let me run a correctness check to ensure it passes, then submit it.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim\n) {\n int half_dim = dim / 2;\n int total = batch_size * num_heads * seq_len * dim;\n \n for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += blockDim.x * gridDim.x) {\n int d = idx % dim;\n int n = (idx / dim) % seq_len;\n int h = (idx / (dim * seq_len)) % num_heads;\n int b = idx / (dim * seq_len * num_heads);\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n int freq_idx = (d < half_dim) ? d : (d - half_dim);\n \n float inv_f = inv_freq[freq_idx];\n float angle = (float)n * inv_f;\n float cos_val, sin_val;\n sincosf(angle, &sin_val, &cos_val);\n \n if (d < half_dim) {\n float q_x1 = q[base_idx + d];\n float k_x1 = k[base_idx + d];\n float q_x2 = q[base_idx + d + half_dim];\n float k_x2 = k[base_idx + d + half_dim];\n q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;\n k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;\n } else {\n float q_x2 = q[base_idx + d];\n float k_x2 = k[base_idx + d];\n float q_x1 = q[base_idx + d - half_dim];\n float k_x1 = k[base_idx + d - half_dim];\n q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;\n k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;\n }\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n \n int total = batch_size * num_heads * seq_len * dim;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n blocks = std::min(blocks, 65535);\n \n rope_kernel<<<blocks, threads>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension_v5',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.77e-07 mean_abs_err=1.43e-08 max_rel_err=8.85e-03
turn 1165.4s turn · 9.3s LLM · 56.2s tools · tokens in=15,222 · out=1,104 · total=16,326 · FINAL
reasoning
The kernel is correct with good numerical precision (max_abs_err=4.77e-07, well within the 1e-4 tolerance for fp32). Let me submit this version.
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\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 <cmath>\n\n__global__ void rope_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n float* __restrict__ q_out,\n float* __restrict__ k_out,\n const float* __restrict__ inv_freq,\n int batch_size, int num_heads, int seq_len, int dim\n) {\n int half_dim = dim / 2;\n int total = batch_size * num_heads * seq_len * dim;\n \n for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += blockDim.x * gridDim.x) {\n int d = idx % dim;\n int n = (idx / dim) % seq_len;\n int h = (idx / (dim * seq_len)) % num_heads;\n int b = idx / (dim * seq_len * num_heads);\n \n int base_idx = ((b * num_heads + h) * seq_len + n) * dim;\n \n int freq_idx = (d < half_dim) ? d : (d - half_dim);\n \n float inv_f = inv_freq[freq_idx];\n float angle = (float)n * inv_f;\n float cos_val, sin_val;\n sincosf(angle, &sin_val, &cos_val);\n \n if (d < half_dim) {\n float q_x1 = q[base_idx + d];\n float k_x1 = k[base_idx + d];\n float q_x2 = q[base_idx + d + half_dim];\n float k_x2 = k[base_idx + d + half_dim];\n q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;\n k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;\n } else {\n float q_x2 = q[base_idx + d];\n float k_x2 = k[base_idx + d];\n float q_x1 = q[base_idx + d - half_dim];\n float k_x1 = k[base_idx + d - half_dim];\n q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;\n k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;\n }\n }\n}\n\ntorch::Tensor apply_rope_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor inv_freq,\n int64_t max_seq_len,\n double base\n) {\n auto q_out = torch::empty_like(q);\n auto k_out = torch::empty_like(k);\n \n int batch_size = q.size(0);\n int num_heads = q.size(1);\n int seq_len = q.size(2);\n int dim = q.size(3);\n \n int total = batch_size * num_heads * seq_len * dim;\n int threads = 256;\n int blocks = (total + threads - 1) / threads;\n blocks = std::min(blocks, 65535);\n \n rope_kernel<<<blocks, threads>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_out.data_ptr<float>(),\n k_out.data_ptr<float>(),\n inv_freq.data_ptr<float>(),\n batch_size, num_heads, seq_len, dim\n );\n \n return torch::stack({q_out, k_out}, 0);\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);\n\"\"\"\n\nrope_extension = load_inline(\n name='rope_extension_v5',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_rope_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Rotary Position Embedding (RoPE) applied to protein residue sequences.\n Optimized CUDA implementation.\n \"\"\"\n\n def __init__(self, dim, max_seq_len=2048, base=10000.0):\n super().__init__()\n inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))\n self.register_buffer(\"inv_freq\", inv_freq)\n self.max_seq_len = max_seq_len\n self.dim = dim\n self.base = base\n\n def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:\n result = rope_extension.apply_rope_cuda(\n q.contiguous(), \n k.contiguous(), \n self.inv_freq,\n self.max_seq_len,\n self.base\n )\n return result[0], result[1]" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 0.02 μs Runtime stats: mean=0.02μs median=?μs std=0.00μs Numerical precision: max_abs_err=4.77e-07 mean_abs_err=1.43e-08 max_rel_err=8.85e-03 Memory: 45.0 MB peak (ref: 45.13 MB, ratio: 0.9972x) Kernel launches: 11 (ref: 45, fusion ratio: 4.0909) SOL score: 0.384
final submitted kernel (125 lines, 3,791 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
import math

cuda_source = """
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <cmath>

__global__ void rope_kernel(
    const float* __restrict__ q,
    const float* __restrict__ k,
    float* __restrict__ q_out,
    float* __restrict__ k_out,
    const float* __restrict__ inv_freq,
    int batch_size, int num_heads, int seq_len, int dim
) {
    int half_dim = dim / 2;
    int total = batch_size * num_heads * seq_len * dim;
    
    for (int idx = blockIdx.x * blockDim.x + threadIdx.x; idx < total; idx += blockDim.x * gridDim.x) {
        int d = idx % dim;
        int n = (idx / dim) % seq_len;
        int h = (idx / (dim * seq_len)) % num_heads;
        int b = idx / (dim * seq_len * num_heads);
        
        int base_idx = ((b * num_heads + h) * seq_len + n) * dim;
        
        int freq_idx = (d < half_dim) ? d : (d - half_dim);
        
        float inv_f = inv_freq[freq_idx];
        float angle = (float)n * inv_f;
        float cos_val, sin_val;
        sincosf(angle, &sin_val, &cos_val);
        
        if (d < half_dim) {
            float q_x1 = q[base_idx + d];
            float k_x1 = k[base_idx + d];
            float q_x2 = q[base_idx + d + half_dim];
            float k_x2 = k[base_idx + d + half_dim];
            q_out[base_idx + d] = q_x1 * cos_val - q_x2 * sin_val;
            k_out[base_idx + d] = k_x1 * cos_val - k_x2 * sin_val;
        } else {
            float q_x2 = q[base_idx + d];
            float k_x2 = k[base_idx + d];
            float q_x1 = q[base_idx + d - half_dim];
            float k_x1 = k[base_idx + d - half_dim];
            q_out[base_idx + d] = q_x2 * cos_val + q_x1 * sin_val;
            k_out[base_idx + d] = k_x2 * cos_val + k_x1 * sin_val;
        }
    }
}

torch::Tensor apply_rope_cuda(
    torch::Tensor q,
    torch::Tensor k,
    torch::Tensor inv_freq,
    int64_t max_seq_len,
    double base
) {
    auto q_out = torch::empty_like(q);
    auto k_out = torch::empty_like(k);
    
    int batch_size = q.size(0);
    int num_heads = q.size(1);
    int seq_len = q.size(2);
    int dim = q.size(3);
    
    int total = batch_size * num_heads * seq_len * dim;
    int threads = 256;
    int blocks = (total + threads - 1) / threads;
    blocks = std::min(blocks, 65535);
    
    rope_kernel<<<blocks, threads>>>(
        q.data_ptr<float>(),
        k.data_ptr<float>(),
        q_out.data_ptr<float>(),
        k_out.data_ptr<float>(),
        inv_freq.data_ptr<float>(),
        batch_size, num_heads, seq_len, dim
    );
    
    return torch::stack({q_out, k_out}, 0);
}
"""

cpp_source = """
torch::Tensor apply_rope_cuda(torch::Tensor q, torch::Tensor k, torch::Tensor inv_freq, int64_t max_seq_len, double base);
"""

rope_extension = load_inline(
    name='rope_extension_v5',
    cpp_sources=cpp_source,
    cuda_sources=cuda_source,
    functions=['apply_rope_cuda'],
    extra_cuda_cflags=['-O3'],
    verbose=False
)


class ModelNew(nn.Module):
    """
    Rotary Position Embedding (RoPE) applied to protein residue sequences.
    Optimized CUDA implementation.
    """

    def __init__(self, dim, max_seq_len=2048, base=10000.0):
        super().__init__()
        inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
        self.register_buffer("inv_freq", inv_freq)
        self.max_seq_len = max_seq_len
        self.dim = dim
        self.base = base

    def forward(self, q: torch.Tensor, k: torch.Tensor) -> tuple:
        result = rope_extension.apply_rope_cuda(
            q.contiguous(), 
            k.contiguous(), 
            self.inv_freq,
            self.max_seq_len,
            self.base
        )
        return result[0], result[1]