FW-GLM-5-1 · popcorn · pop_l123_st_gpt
compile_fail 36_InvariantPointAttention.py
model
FW-GLM-5-1
turns / max
1 / 1
tool calls
1
tokens (total)
10465
wall clock
152.0s
truncated
no
backend
cuda fp32
variant
popcorn
runtime
—
ref runtime
-1.00 μs
speedup
—
started
2026-05-11T10:06:03Z
compile error: Error building extension 'ipa_ops': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=ipa_ops -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -fPIC -std=c++17 -c /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp -o main.o FAILED: [cod
timingkernelbench.timing
kernel runtime
—
ref runtime
—
speedup
—
kernel mean / median / std
—
ref mean / median / std
—
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
import torch.nn.functional as F
import math


class Model(nn.Module):
    """
    Invariant Point Attention (IPA) from AlphaFold2's structure module.
    Combines sequence-space attention with 3-D geometric queries/keys/values
    expressed in local residue frames.  The attention logits incorporate
    Euclidean distances in global frame, making it SE(3)-equivariant.
    """

    def __init__(self, node_dim, pair_dim, num_heads, num_query_points, num_value_points):
        super().__init__()
        self.num_heads = num_heads
        self.head_dim = node_dim // num_heads
        self.num_query_points = num_query_points
        self.num_value_points = num_value_points
        assert node_dim % num_heads == 0

        d = self.head_dim
        self.q_proj = nn.Linear(node_dim, num_heads * d, bias=False)
        self.k_proj = nn.Linear(node_dim, num_heads * d, bias=False)
        self.v_proj = nn.Linear(node_dim, num_heads * d, bias=False)

        self.q_pts = nn.Linear(node_dim, num_heads * num_query_points * 3, bias=False)
        self.k_pts = nn.Linear(node_dim, num_heads * num_query_points * 3, bias=False)
        self.v_pts = nn.Linear(node_dim, num_heads * num_value_points * 3, bias=False)

        self.pair_bias = nn.Linear(pair_dim, num_heads, bias=False)

        self.head_weights = nn.Parameter(torch.zeros(num_heads))

        out_features = num_heads * d + num_heads * num_value_points * 3
        self.out_proj = nn.Linear(out_features, node_dim)

        self.layer_norm = nn.LayerNorm(node_dim)

    def _apply_frame(self, pts, rotations, translations):
        """Transform local-frame points to global frame."""
        # pts: (B, N, P, 3), rotations: (B, N, 3, 3), translations: (B, N, 3)
        global_pts = torch.einsum("bnpc,bncd->bnpd", pts, rotations) + translations.unsqueeze(2)
        return global_pts

    def _apply_inv_frame(self, pts, rotations, translations):
        """Transform global-frame points to local frame."""
        centered = pts - translations.unsqueeze(2)
        local_pts = torch.einsum("bnpc,bndc->bnpd", centered, rotations)
        return local_pts

    def forward(
        self,
        node_repr: torch.Tensor,
        pair_repr: torch.Tensor,
        translations: torch.Tensor,
        rotations: torch.Tensor,
    ) -> torch.Tensor:
        """
        Args:
            node_repr:    (B, N, node_dim)
            pair_repr:    (B, N, N, pair_dim)
            translations: (B, N, 3)
            rotations:    (B, N, 3, 3)
        Returns:
            updated node representation (B, N, node_dim)
        """
        B, N, D = node_repr.shape
        h = self.num_heads
        d = self.head_dim
        Qp = self.num_query_points
        Vp = self.num_value_points

        x = self.layer_norm(node_repr)

        q = self.q_proj(x).view(B, N, h, d)
        k = self.k_proj(x).view(B, N, h, d)
        v = self.v_proj(x).view(B, N, h, d)

        # Points in local frame, then transform to global
        q_pts_local = self.q_pts(x).view(B, N, h * Qp, 3)
        k_pts_local = self.k_pts(x).view(B, N, h * Qp, 3)
        v_pts_local = self.v_pts(x).view(B, N, h * Vp, 3)

        q_pts = self._apply_frame(q_pts_local, rotations, translations).view(B, N, h, Qp, 3)
        k_pts = self._apply_frame(k_pts_local, rotations, translations).view(B, N, h, Qp, 3)
        v_pts = self._apply_frame(v_pts_local, rotations, translations).view(B, N, h, Vp, 3)

        # Scalar attention logits
        attn_scalar = torch.einsum("bihd,bjhd->bhij", q, k) / math.sqrt(d)

        # Point attention: negative squared distance between query and key points
        # q_pts: (B, N_i, h, Qp, 3), k_pts: (B, N_j, h, Qp, 3)
        q_expand = q_pts.unsqueeze(2)  # (B, N, 1, h, Qp, 3)
        k_expand = k_pts.unsqueeze(1)  # (B, 1, N, h, Qp, 3)
        pt_dist = ((q_expand - k_expand) ** 2).sum(dim=(-1, -2))  # (B, N, N, h)

        w = F.softplus(self.head_weights)
        pt_attn = -(w.view(1, 1, 1, h) * pt_dist) / 2.0
        pt_attn = pt_attn.permute(0, 3, 1, 2)  # (B, h, N, N)

        # Pair bias
        pair_bias = self.pair_bias(pair_repr).permute(0, 3, 1, 2)  # (B, h, N, N)

        attn = attn_scalar + pt_attn + pair_bias
        attn = F.softmax(attn, dim=-1)  # (B, h, N_i, N_j)

        # Aggregate scalar values
        out_scalar = torch.einsum("bhij,bjhd->bihd", attn, v).reshape(B, N, h * d)

        # Aggregate point values in global frame, then transform back to local
        out_pts = torch.einsum("bhij,bjhpc->bihpc", attn, v_pts)  # (B, N, h, Vp, 3)
        out_pts = out_pts.reshape(B, N, h * Vp, 3)
        out_pts_local = self._apply_inv_frame(out_pts, rotations, translations)
        out_pts_flat = out_pts_local.reshape(B, N, h * Vp * 3)

        out = torch.cat([out_scalar, out_pts_flat], dim=-1)
        return self.out_proj(out)


node_dim = 64
pair_dim = 32
num_heads = 4
num_query_points = 4
num_value_points = 8
seq_len = 32
batch_size = 2


def get_inputs():
    p = popcorn_pri
    node_repr = torch.randn(p.jitter_int(batch_size), p.jitter_int(seq_len), node_dim)
    pair_repr = torch.randn(p.jitter_int(batch_size), p.jitter_int(seq_len), p.jitter_int(seq_len), pair_dim)
    translations = torch.randn(p.jitter_int(batch_size), p.jitter_int(seq_len), 3)
    rotations = torch.zeros(p.jitter_int(batch_size), p.jitter_int(seq_len), 3, 3)
    for b in range(p.jitter_int(batch_size)):
        for n in range(p.jitter_int(seq_len)):
            rotations[b, n] = torch.eye(3)
    return [node_repr, pair_repr, translations, rotations]


def get_init_inputs():
    return [node_dim, pair_dim, num_heads, num_query_points, num_value_points]
turn 0 · FINAL · 1 tool call(s) · 152.0s turn · 77.5s LLM · tokens in=2,400 · out=8,065 · total=10,465 · 54,716 chars (click to expand)
turn 0152.0s turn · 77.5s LLM · 74.5s tools · tokens in=2,400 · out=8,065 · total=10,465 · FINAL
reasoning
This is a complex task - I need to implement a custom CUDA kernel for the Invariant Point Attention (IPA) from AlphaFold2's structure module. Let me analyze the reference implementation carefully: 1. LayerNorm is applied to node_repr 2. Multiple projections are done: - q_proj, k_proj, v_proj for scalar attention - q_pts, k_pts, v_pts for point attention - pair_bias for pair representation 3. Point transformations: - Local to global frame transformation using rotations and translations - Inverse transformation at the end 4. Attention computation: - Scalar attention: einsum for q*k - Point attention: negative squared distances between query and key points - Pair bias contribution 5. Aggregation: - Scalar values aggregated via einsum - Point values aggregated and transformed back to local frame 6. Output projection This is quite complex. Let me think about how to optimize this with CUDA: Key operations that could benefit from CUDA: 1. The einsum operations (batched matrix multiplications) 2. Point transformations (applying rotation + translation) 3. Point distance computation 4. Softmax However, many of these are already well-optimized in PyTorch. The challenge is to fuse operations to reduce memory bandwidth. Let me think about what can be fused: 1. LayerNorm + projections could be fused 2. Point transformation + distance computation could be fused 3. Attention computation (scalar + point + pair bias) could be fused into one kernel 4. Value aggregation + inverse frame transformation could be fused Given the complexity, I'll focus on fusing the most memory-intensive parts: 1. Fusing attention computation (scalar logits + point logits + pair bias + softmax) 2. Fusing point value aggregation with inverse frame transformation Actually, let me start with a simpler approach - implement the whole thing as efficiently as possible in CUDA, fusing operations where it makes sense. The operations break down into: LayerNorm, projections (matrix multiplies), point transformations, attention computation combining multiple terms, value aggregation, inverse transformation, concatenation, and output projection. The point attention calculation with distance computation seems like the most promising target for fusion, along with combining the attention terms and value aggregation steps. I should focus on fusing point transformations with distance calculations, since that's where the geometric operations happen most intensively. The attention computation itself—combining scalar, point, and pair bias terms—could also benefit from kernel fusion to reduce memory transfers. Value aggregation might be fused with the inverse transformation to streamline the data flow. I'll start by implementing the point transformation in CUDA and then work toward fusing operations where the performance gains are clearest. The key is identifying which operations create unnecessary memory traffic versus which ones can be combined into single kernels without introducing computational overhead. The most expensive computations here are the N² attention matrix operations. Point transformations and point attention both scale quadratically with sequence length, while projections scale linearly. For the CUDA implementation, I'd prioritize fusing the attention computation steps—combining scalar logits, point logits, pair bias, and softmax into a single kernel would eliminate unnecessary memory traffic. Similarly, fusing value aggregation with inverse transformations would streamline the backward pass. The intermediate layers could also benefit from kernel fusion to reduce launch overhead and memory transfers. The most significant gains come from optimizing the N² operations: attention score calculation across O(BHN²) operations, the softmax over the same scale, and the final value aggregation. The inverse transformation at the end also presents a clear opportunity to fuse with the preceding computation step. I should build a fused attention kernel that handles the combined attention computation within a single CUDA kernel, then identify which transformation steps can be merged together to minimize memory transfers and kernel launch overhead.
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport math\nfrom torch.utils.cpp_extension import load_inline\n\n# Define CUDA kernel for fused attention computation\ncuda_source = \"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <c10/cuda/CUDAException.h>\n\n__device__ __forceinline__ float warpReduceSum(float val) {\n for (int offset = 16; offset > 0; offset /= 2)\n val += __shfl_xor_sync(0xffffffff, val, offset);\n return val;\n}\n\n__device__ __forceinline__ float blockReduceSum(float val, int tid) {\n __shared__ float shared[32];\n int lane = tid & 31;\n int wid = tid >> 5;\n \n val = warpReduceSum(val);\n \n if (lane == 0) shared[wid] = val;\n __syncthreads();\n \n val = (tid < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warpReduceSum(val);\n return val;\n}\n\n// Fused kernel: compute attention scores (scalar + point + pair_bias) and softmax\n// Grid: (B, H, N), Block: (N_j) - each block handles one query position\n__global__ void fused_attention_kernel(\n const float* __restrict__ q, // (B, N, H, D)\n const float* __restrict__ k, // (B, N, H, D)\n const float* __restrict__ q_pts, // (B, N, H, Qp, 3)\n const float* __restrict__ k_pts, // (B, N, H, Qp, 3)\n const float* __restrict__ pair_bias, // (B, H, N, N)\n const float* __restrict__ head_weights, // (H,)\n float* __restrict__ attn, // (B, H, N, N)\n int B, int N, int H, int D, int Qp, float inv_sqrt_d\n) {\n int b = blockIdx.x; // batch\n int h = blockIdx.y; // head\n int i = blockIdx.z; // query position\n \n if (b >= B || h >= H || i >= N) return;\n \n int tid = threadIdx.x;\n int j = tid; // key position\n \n // Load query vector for this head\n extern __shared__ float smem[];\n float* q_local = smem; // size D\n float* q_pts_local = smem + D; // size Qp * 3\n \n if (tid < D) {\n q_local[tid] = q[b * N * H * D + i * H * D + h * D + tid];\n }\n if (tid < Qp * 3) {\n q_pts_local[tid] = q_pts[b * N * H * Qp * 3 + i * H * Qp * 3 + h * Qp * 3 + tid];\n }\n __syncthreads();\n \n float hw = head_weights[h];\n \n // Each thread computes attention for one (i, j) pair\n // Compute scalar attention\n float scalar_attn = 0.0f;\n \n // Compute scalar product q_i * k_j\n for (int d = 0; d < D; d++) {\n float k_val = k[b * N * H * D + j * H * D + h * D + d];\n scalar_attn += q_local[d] * k_val;\n }\n scalar_attn *= inv_sqrt_d;\n \n // Compute point attention (negative squared distance)\n float pt_dist = 0.0f;\n for (int p = 0; p < Qp; p++) {\n for (int c = 0; c < 3; c++) {\n float q_pt = q_pts_local[p * 3 + c];\n float k_pt = k_pts[b * N * H * Qp * 3 + j * H * Qp * 3 + h * Qp * 3 + p * 3 + c];\n float diff = q_pt - k_pt;\n pt_dist += diff * diff;\n }\n }\n float pt_attn = -hw * pt_dist / 2.0f;\n \n // Get pair bias\n float pb = pair_bias[b * H * N * N + h * N * N + i * N + j];\n \n // Total attention score\n float score = scalar_attn + pt_attn + pb;\n \n // Store for softmax (need all scores first)\n __shared__ float scores[1024]; // Assuming N <= 1024\n scores[j] = score;\n __syncthreads();\n \n // Find max for numerical stability\n __shared__ float max_val;\n float local_max = scores[j];\n if (tid >= N) local_max = -1e30f;\n \n for (int offset = 16; offset > 0; offset /= 2) {\n float other = __shfl_xor_sync(0xffffffff, local_max, offset);\n local_max = fmaxf(local_max, other);\n }\n if (tid == 0) max_val = local_max;\n __syncthreads();\n \n // Compute exp(score - max)\n float exp_val = (tid < N) ? expf(scores[tid] - max_val) : 0.0f;\n \n // Reduce to get sum\n float sum = blockReduceSum(exp_val, tid);\n __shared__ float sum_val;\n if (tid == 0) sum_val = sum;\n __syncthreads();\n \n // Compute softmax\n float softmax_val = exp_val / sum_val;\n \n // Store result\n if (j < N) {\n attn[b * H * N * N + h * N * N + i * N + j] = softmax_val;\n }\n}\n\n// Fused kernel: aggregate values (scalar + point) and apply inverse frame\n__global__ void fused_aggregate_kernel(\n const float* __restrict__ attn, // (B, H, N, N)\n const float* __restrict__ v, // (B, N, H, D)\n const float* __restrict__ v_pts, // (B, N, H, Vp, 3)\n const float* __restrict__ rotations, // (B, N, 3, 3)\n const float* __restrict__ translations, // (B, N, 3)\n float* __restrict__ out_scalar, // (B, N, H, D)\n float* __restrict__ out_pts_local, // (B, N, H * Vp, 3)\n int B, int N, int H, int D, int Vp\n) {\n int b = blockIdx.x;\n int i = blockIdx.y; // output position\n int h = blockIdx.z; // head\n int d = threadIdx.x; // dimension within head\n \n if (b >= B || i >= N || h >= H || d >= D + Vp * 3) return;\n \n int N_total = N;\n \n if (d < D) {\n // Aggregate scalar values\n float sum = 0.0f;\n for (int j = 0; j < N_total; j++) {\n float a = attn[b * H * N * N + h * N * N + i * N + j];\n float v_val = v[b * N * H * D + j * H * D + h * D + d];\n sum += a * v_val;\n }\n out_scalar[b * N * H * D + i * H * D + h * D + d] = sum;\n } else {\n // Aggregate point values\n int pt_idx = d - D; // 0 to Vp*3-1\n int vp = pt_idx / 3;\n int c = pt_idx % 3;\n \n // First aggregate in global frame\n float sum = 0.0f;\n for (int j = 0; j < N_total; j++) {\n float a = attn[b * H * N * N + h * N * N + i * N + j];\n float v_pt = v_pts[b * N * H * Vp * 3 + j * H * Vp * 3 + h * Vp * 3 + vp * 3 + c];\n sum += a * v_pt;\n }\n \n // Apply inverse frame transformation\n // out_global - translations, then rotate by rotations^T\n float trans = translations[b * N * 3 + i * 3 + c];\n float centered = sum - trans;\n \n float local_val = 0.0f;\n for (int k = 0; k < 3; k++) {\n float rot = rotations[b * N * 3 * 3 + i * 9 + k * 3 + c]; // R^T = R col-major\n float coord = (k == 0) ? 0.0f : 0.0f; // Need all 3 coords\n }\n \n // Store intermediate for inverse transform (need all 3 coords)\n // This kernel needs revision for proper inverse transform\n }\n}\n\n// Separate kernel for inverse frame transformation\n__global__ void inverse_frame_kernel(\n const float* __restrict__ pts_global, // (B, N, H*Vp, 3)\n const float* __restrict__ rotations, // (B, N, 3, 3)\n const float* __restrict__ translations, // (B, N, 3)\n float* __restrict__ pts_local, // (B, N, H*Vp, 3)\n int B, int N, int total_pts\n) {\n int b = blockIdx.x;\n int n = blockIdx.y;\n int p = blockIdx.z; // point index\n int c = threadIdx.x; // coordinate (0, 1, 2)\n \n if (b >= B || n >= N || p >= total_pts || c >= 3) return;\n \n // Load translation for this coordinate\n float trans = translations[b * N * 3 + n * 3 + c];\n \n // Load point coordinates\n float pt[3];\n for (int i = 0; i < 3; i++) {\n pt[i] = pts_global[b * N * total_pts * 3 + n * total_pts * 3 + p * 3 + i];\n }\n \n // Center\n float centered[3];\n for (int i = 0; i < 3; i++) {\n centered[i] = pt[i] - translations[b * N * 3 + n * 3 + i];\n }\n \n // Apply rotation^T (rotation is stored row-major, so R^T[i,j] = R[j,i])\n float local_val = 0.0f;\n for (int k = 0; k < 3; k++) {\n // R^T[c,k] = R[k,c]\n float rot_T = rotations[b * N * 9 + n * 9 + k * 3 + c];\n local_val += rot_T * centered[k];\n }\n \n pts_local[b * N * total_pts * 3 + n * total_pts * 3 + p * 3 + c] = local_val;\n}\n\n// Point transformation kernel (local to global)\n__global__ void apply_frame_kernel(\n const float* __restrict__ pts_local, // (B, N, H*P, 3)\n const float* __restrict__ rotations, // (B, N, 3, 3)\n const float* __restrict__ translations, // (B, N, 3)\n float* __restrict__ pts_global, // (B, N, H*P, 3)\n int B, int N, int total_pts\n) {\n int b = blockIdx.x;\n int n = blockIdx.y;\n int p = blockIdx.z; // point index\n int c = threadIdx.x; // coordinate\n \n if (b >= B || n >= N || p >= total_pts || c >= 3) return;\n \n // Load point coordinates\n float pt[3];\n for (int i = 0; i < 3; i++) {\n pt[i] = pts_local[b * N * total_pts * 3 + n * total_pts * 3 + p * 3 + i];\n }\n \n // Apply rotation: R * pt\n float rotated = 0.0f;\n for (int k = 0; k < 3; k++) {\n float rot = rotations[b * N * 9 + n * 9 + c * 3 + k]; // row-major\n rotated += rot * pt[k];\n }\n \n // Add translation\n float result = rotated + translations[b * N * 3 + n * 3 + c];\n \n pts_global[b * N * total_pts * 3 + n * total_pts * 3 + p * 3 + c] = result;\n}\n\n// Optimized attention computation with better memory access\n__global__ void attention_forward_kernel(\n const float* __restrict__ q,\n const float* __restrict__ k,\n const float* __restrict__ q_pts,\n const float* __restrict__ k_pts,\n const float* __restrict__ pair_bias,\n const float* __restrict__ head_weights,\n float* __restrict__ attn_out,\n int B, int N, int H, int D, int Qp, float inv_sqrt_d\n) {\n // Each block handles one (batch, head, query_i) combination\n int b = blockIdx.x;\n int h = blockIdx.y;\n int i = blockIdx.z;\n \n if (b >= B || h >= H || i >= N) return;\n \n int tid = threadIdx.x;\n int lane = tid & 31;\n \n // Shared memory for query and query points\n extern __shared__ char smem_buf[];\n float* q_smem = reinterpret_cast<float*>(smem_buf);\n float* q_pts_smem = q_smem + D;\n float* scores_smem = q_pts_smem + Qp * 3;\n \n // Load q and q_pts into shared memory\n for (int idx = tid; idx < D; idx += blockDim.x) {\n q_smem[idx] = q[b * N * H * D + i * H * D + h * D + idx];\n }\n for (int idx = tid; idx < Qp * 3; idx += blockDim.x) {\n q_pts_smem[idx] = q_pts[b * N * H * Qp * 3 + i * H * Qp * 3 + h * Qp * 3 + idx];\n }\n __syncthreads();\n \n float hw = head_weights[h];\n \n // Compute attention scores for all j\n float local_max = -1e30f;\n \n for (int j = tid; j < N; j += blockDim.x) {\n // Scalar attention\n float scalar = 0.0f;\n for (int d = 0; d < D; d++) {\n scalar += q_smem[d] * k[b * N * H * D + j * H * D + h * D + d];\n }\n scalar *= inv_sqrt_d;\n \n // Point attention\n float pt_dist = 0.0f;\n for (int p = 0; p < Qp; p++) {\n for (int c = 0; c < 3; c++) {\n float diff = q_pts_smem[p * 3 + c] - \n k_pts[b * N * H * Qp * 3 + j * H * Qp * 3 + h * Qp * 3 + p * 3 + c];\n pt_dist += diff * diff;\n }\n }\n float pt_attn = -hw * pt_dist / 2.0f;\n \n // Pair bias\n float pb = pair_bias[b * H * N * N + h * N * N + i * N + j];\n \n float score = scalar + pt_attn + pb;\n scores_smem[j] = score;\n local_max = fmaxf(local_max, score);\n }\n \n // Block-level max reduction\n __shared__ float global_max;\n float reduced_max = blockReduceSum(local_max, tid); // Actually need max, not sum\n // Use separate max reduction\n for (int offset = blockDim.x / 2; offset > 0; offset /= 2) {\n float other = __shfl_xor_sync(0xffffffff, local_max, offset);\n local_max = fmaxf(local_max, other);\n }\n if (tid == 0) global_max = local_max;\n __syncthreads();\n \n // Compute exp and sum\n float local_sum = 0.0f;\n for (int j = tid; j < N; j += blockDim.x) {\n float exp_val = expf(scores_smem[j] - global_max);\n scores_smem[j] = exp_val;\n local_sum += exp_val;\n }\n \n __shared__ float global_sum;\n float reduced_sum = blockReduceSum(local_sum, tid);\n if (tid == 0) global_sum = reduced_sum;\n __syncthreads();\n \n // Normalize and store\n for (int j = tid; j < N; j += blockDim.x) {\n attn_out[b * H * N * N + h * N * N + i * N + j] = scores_smem[j] / global_sum;\n }\n}\n\n// Value aggregation kernel\n__global__ void value_aggregate_kernel(\n const float* __restrict__ attn,\n const float* __restrict__ v,\n const float* __restrict__ v_pts,\n float* __restrict__ out_scalar,\n float* __restrict__ out_pts_global,\n int B, int N, int H, int D, int Vp\n) {\n int b = blockIdx.x;\n int h = blockIdx.y;\n int i = blockIdx.z; // output position\n \n if (b >= B || h >= H || i >= N) return;\n \n int tid = threadIdx.x;\n \n // Each thread handles one output dimension\n // First D dimensions are scalar, then Vp*3 are point coordinates\n \n __shared__ float attn_smem[1024]; // Assuming N <= 1024\n \n // Load attention weights\n for (int j = tid; j < N; j += blockDim.x) {\n attn_smem[j] = attn[b * H * N * N + h * N * N + i * N + j];\n }\n __syncthreads();\n \n // Scalar aggregation\n if (tid < D) {\n float sum = 0.0f;\n for (int j = 0; j < N; j++) {\n sum += attn_smem[j] * v[b * N * H * D + j * H * D + h * D + tid];\n }\n out_scalar[b * N * H * D + i * H * D + h * D + tid] = sum;\n }\n \n // Point aggregation\n if (tid < Vp * 3) {\n int vp = tid / 3;\n int c = tid % 3;\n float sum = 0.0f;\n for (int j = 0; j < N; j++) {\n sum += attn_smem[j] * v_pts[b * N * H * Vp * 3 + j * H * Vp * 3 + h * Vp * 3 + vp * 3 + c];\n }\n out_pts_global[b * N * H * Vp * 3 + i * H * Vp * 3 + h * Vp * 3 + vp * 3 + c] = sum;\n }\n}\n\"\"\"\n\ncpp_source = \"\"\"\ntorch::Tensor apply_frame_cuda(\n torch::Tensor pts_local,\n torch::Tensor rotations,\n torch::Tensor translations,\n int total_pts\n);\n\ntorch::Tensor inverse_frame_cuda(\n torch::Tensor pts_global,\n torch::Tensor rotations,\n torch::Tensor translations,\n int total_pts\n);\n\ntorch::Tensor attention_forward_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor q_pts,\n torch::Tensor k_pts,\n torch::Tensor pair_bias,\n torch::Tensor head_weights,\n int B, int N, int H, int D, int Qp, float inv_sqrt_d\n);\n\ntorch::Tensor value_aggregate_cuda(\n torch::Tensor attn,\n torch::Tensor v,\n torch::Tensor v_pts,\n int B, int N, int H, int D, int Vp\n);\n\ntorch::Tensor value_aggregate_cuda(\n torch::Tensor attn,\n torch::Tensor v,\n torch::Tensor v_pts,\n int B, int N, int H, int D, int Vp\n) {\n auto options = torch::TensorOptions().dtype(torch::kFloat32).device(attn.device());\n auto out_scalar = torch::empty({B, N, H, D}, options);\n auto out_pts_global = torch::empty({B, N, H, Vp, 3}, options);\n \n int threads = std::max(D, Vp * 3);\n threads = std::min(threads, 256);\n \n dim3 grid(B, H, N);\n \n AT_DISPATCH_FLOATING_TYPES(attn.scalar_type(), \"value_aggregate\", ([&] {\n value_aggregate_kernel<<<grid, threads>>>(\n attn.data_ptr<float>(),\n v.data_ptr<float>(),\n v_pts.data_ptr<float>(),\n out_scalar.data_ptr<float>(),\n out_pts_global.data_ptr<float>(),\n B, N, H, D, Vp\n );\n }));\n \n return torch::cat({out_scalar.reshape({B, N, H * D}), \n out_pts_global.reshape({B, N, H * Vp * 3})}, -1);\n}\n\ntorch::Tensor apply_frame_cuda(\n torch::Tensor pts_local,\n torch::Tensor rotations,\n torch::Tensor translations,\n int total_pts\n) {\n TORCH_CHECK(pts_local.is_cuda(), \"pts_local must be CUDA tensor\");\n TORCH_CHECK(rotations.is_cuda(), \"rotations must be CUDA tensor\");\n TORCH_CHECK(translations.is_cuda(), \"translations must be CUDA tensor\");\n \n auto options = torch::TensorOptions().dtype(torch::kFloat32).device(pts_local.device());\n int B = pts_local.size(0);\n int N = pts_local.size(1);\n \n auto pts_global = torch::empty({B, N, total_pts, 3}, options);\n \n dim3 grid(B, N, total_pts);\n int threads = 3;\n \n AT_DISPATCH_FLOATING_TYPES(pts_local.scalar_type(), \"apply_frame\", ([&] {\n apply_frame_kernel<<<grid, threads>>>(\n pts_local.data_ptr<float>(),\n rotations.data_ptr<float>(),\n translations.data_ptr<float>(),\n pts_global.data_ptr<float>(),\n B, N, total_pts\n );\n }));\n \n return pts_global;\n}\n\ntorch::Tensor inverse_frame_cuda(\n torch::Tensor pts_global,\n torch::Tensor rotations,\n torch::Tensor translations,\n int total_pts\n) {\n TORCH_CHECK(pts_global.is_cuda(), \"pts_global must be CUDA tensor\");\n \n auto options = torch::TensorOptions().dtype(torch::kFloat32).device(pts_global.device());\n int B = pts_global.size(0);\n int N = pts_global.size(1);\n \n auto pts_local = torch::empty({B, N, total_pts, 3}, options);\n \n dim3 grid(B, N, total_pts);\n int threads = 3;\n \n AT_DISPATCH_FLOATING_TYPES(pts_global.scalar_type(), \"inverse_frame\", ([&] {\n inverse_frame_kernel<<<grid, threads>>>(\n pts_global.data_ptr<float>(),\n rotations.data_ptr<float>(),\n translations.data_ptr<float>(),\n pts_local.data_ptr<float>(),\n B, N, total_pts\n );\n }));\n \n return pts_local;\n}\n\ntorch::Tensor attention_forward_cuda(\n torch::Tensor q,\n torch::Tensor k,\n torch::Tensor q_pts,\n torch::Tensor k_pts,\n torch::Tensor pair_bias,\n torch::Tensor head_weights,\n int B, int N, int H, int D, int Qp, float inv_sqrt_d\n) {\n TORCH_CHECK(q.is_cuda(), \"q must be CUDA tensor\");\n \n auto options = torch::TensorOptions().dtype(torch::kFloat32).device(q.device());\n auto attn_out = torch::empty({B, H, N, N}, options);\n \n dim3 grid(B, H, N);\n int threads = std::min(N, 256);\n int smem_size = D * sizeof(float) + Qp * 3 * sizeof(float) + N * sizeof(float);\n \n AT_DISPATCH_FLOATING_TYPES(q.scalar_type(), \"attention_forward\", ([&] {\n attention_forward_kernel<<<grid, threads, smem_size>>>(\n q.data_ptr<float>(),\n k.data_ptr<float>(),\n q_pts.data_ptr<float>(),\n k_pts.data_ptr<float>(),\n pair_bias.data_ptr<float>(),\n head_weights.data_ptr<float>(),\n attn_out.data_ptr<float>(),\n B, N, H, D, Qp, inv_sqrt_d\n );\n }));\n \n return attn_out;\n}\n\"\"\"\n\n# Compile the extension\nipa_ops = load_inline(\n name='ipa_ops',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['apply_frame_cuda', 'inverse_frame_cuda', 'attention_forward_cuda', 'value_aggregate_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\n\nclass ModelNew(nn.Module):\n \"\"\"\n Invariant Point Attention (IPA) with custom CUDA kernels.\n \"\"\"\n\n def __init__(self, node_dim, pair_dim, num_heads, num_query_points, num_value_points):\n super().__init__()\n self.num_heads = num_heads\n self.head_dim = node_dim // num_heads\n self.num_query_points = num_query_points\n self.num_value_points = num_value_points\n assert node_dim % num_heads == 0\n\n d = self.head_dim\n self.q_proj = nn.Linear(node_dim, num_heads * d, bias=False)\n self.k_proj = nn.Linear(node_dim, num_heads * d, bias=False)\n self.v_proj = nn.Linear(node_dim, num_heads * d, bias=False)\n\n self.q_pts = nn.Linear(node_dim, num_heads * num_query_points * 3, bias=False)\n self.k_pts = nn.Linear(node_dim, num_heads * num_query_points * 3, bias=False)\n self.v_pts = nn.Linear(node_dim, num_heads * num_value_points * 3, bias=False)\n\n self.pair_bias = nn.Linear(pair_dim, num_heads, bias=False)\n\n self.head_weights = nn.Parameter(torch.zeros(num_heads))\n\n out_features = num_heads * d + num_heads * num_value_points * 3\n self.out_proj = nn.Linear(out_features, node_dim)\n\n self.layer_norm = nn.LayerNorm(node_dim)\n\n def forward(\n self,\n node_repr: torch.Tensor,\n pair_repr: torch.Tensor,\n translations: torch.Tensor,\n rotations: torch.Tensor,\n ) -> torch.Tensor:\n B, N, D = node_repr.shape\n h = self.num_heads\n d = self.head_dim\n Qp = self.num_query_points\n Vp = self.num_value_points\n\n x = self.layer_norm(node_repr)\n\n # Projections\n q = self.q_proj(x).view(B, N, h, d)\n k = self.k_proj(x).view(B, N, h, d)\n v = self.v_proj(x).view(B, N, h, d)\n\n # Point projections (local frame)\n q_pts_local = self.q_pts(x).view(B, N, h * Qp, 3)\n k_pts_local = self.k_pts(x).view(B, N, h * Qp, 3)\n v_pts_local = self.v_pts(x).view(B, N, h * Vp, 3)\n\n # Transform points to global frame using custom CUDA kernel\n if x.is_cuda:\n q_pts_global = ipa_ops.apply_frame_cuda(\n q_pts_local.contiguous().float(),\n rotations.contiguous().float(),\n translations.contiguous().float(),\n h * Qp\n )\n k_pts_global = ipa_ops.apply_frame_cuda(\n k_pts_local.contiguous().float(),\n rotations.contiguous().float(),\n translations.contiguous().float(),\n h * Qp\n )\n v_pts_global = ipa_ops.apply_frame_cuda(\n v_pts_local.contiguous().float(),\n rotations.contiguous().float(),\n translations.contiguous().float(),\n h * Vp\n )\n \n q_pts = q_pts_global.view(B, N, h, Qp, 3)\n k_pts = k_pts_global.view(B, N, h, Qp, 3)\n v_pts = v_pts_global.view(B, N, h, Vp, 3)\n \n # Compute pair bias\n pair_bias = self.pair_bias(pair_repr).permute(0, 3, 1, 2)\n \n # Compute head weights\n w = F.softplus(self.head_weights)\n \n # Fused attention computation\n inv_sqrt_d = 1.0 / math.sqrt(d)\n attn = ipa_ops.attention_forward_cuda(\n q.contiguous().float(),\n k.contiguous().float(),\n q_pts.contiguous().float(),\n k_pts.contiguous().float(),\n pair_bias.contiguous().float(),\n w.contiguous().float(),\n B, N, h, d, Qp, inv_sqrt_d\n )\n \n # Value aggregation\n out_combined = ipa_ops.value_aggregate_cuda(\n attn.contiguous().float(),\n v.contiguous().float(),\n v_pts.contiguous().float(),\n B, N, h, d, Vp\n )\n \n # Split scalar and point outputs\n out_scalar = out_combined[..., :h * d].view(B, N, h, d)\n out_pts_global = out_combined[..., h * d:].view(B, N, h * Vp, 3)\n \n # Transform points back to local frame\n out_pts_local = ipa_ops.inverse_frame_cuda(\n out_pts_global.contiguous().float(),\n rotations.contiguous().float(),\n translations.contiguous().float(),\n h * Vp\n )\n out_pts_flat = out_pts_local.view(B, N, h * Vp * 3)\n \n out = torch.cat([out_scalar.reshape(B, N, h * d), out_pts_flat], dim=-1)\n return self.out_proj(out)\n else:\n # CPU fallback - use original implementation\n q_pts = self._apply_frame(q_pts_local, rotations, translations).view(B, N, h, Qp, 3)\n k_pts = self._apply_frame(k_pts_local, rotations, translations).view(B, N, h, Qp, 3)\n v_pts = self._apply_frame(v_pts_local, rotations, translations).view(B, N, h, Vp, 3)\n\n attn_scalar = torch.einsum(\"bihd,bjhd->bhij\", q, k) / math.sqrt(d)\n\n q_expand = q_pts.unsqueeze(2)\n k_expand = k_pts.unsqueeze(1)\n pt_dist = ((q_expand - k_expand) ** 2).sum(dim=(-1, -2))\n\n w = F.softplus(self.head_weights)\n pt_attn = -(w.view(1, 1, 1, h) * pt_dist) / 2.0\n pt_attn = pt_attn.permute(0, 3, 1, 2)\n\n pair_bias = self.pair_bias(pair_repr).permute(0, 3, 1, 2)\n\n attn = attn_scalar + pt_attn + pair_bias\n attn = F.softmax(attn, dim=-1)\n\n out_scalar = torch.einsum(\"bhij,bjhd->bihd\", attn, v).reshape(B, N, h * d)\n\n out_pts = torch.einsum(\"bhij,bjhpc->bihpc\", attn, v_pts)\n out_pts = out_pts.reshape(B, N, h * Vp, 3)\n out_pts_local = self._apply_inv_frame(out_pts, rotations, translations)\n out_pts_flat = out_pts_local.reshape(B, N, h * Vp * 3)\n\n out = torch.cat([out_scalar, out_pts_flat], dim=-1)\n return self.out_proj(out)\n\n def _apply_frame(self, pts, rotations, translations):\n global_pts = torch.einsum(\"bnpc,bncd->bnpd\", pts, rotations) + translations.unsqueeze(2)\n return global_pts\n\n def _apply_inv_frame(self, pts, rotations, translations):\n centered = pts - translations.unsqueeze(2)\n local_pts = torch.einsum(\"bnpc,bndc->bnpd\", centered, rotations)\n return local_pts" }
result ← submit_kernel (fail)
failsubmit_kernel submit_kernel FAILED: kernel did not compile. Error building extension 'ipa_ops': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=ipa_ops -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -fPIC -std=c++17 -c /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp -o main.o FAILED: [code=1] main.o /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=ipa_ops -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -fPIC -std=c++17 -c /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp -o main.o /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In function 'at::Tensor value_aggregate_cuda(at::Tensor, at::Tensor, at::Tensor, int, int, int, int, int)': /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:47:5: error: 'dim3' was not declared in this scope 47 | dim3 grid(B, H, N); | ^~~~ In file included from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/Dispatch.h:10, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/ATen.h:12, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/types.h:4, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data/dataloader_options.h:5, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data/dataloader/base.h:4, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data/dataloader/stateful.h:5, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data/dataloader.h:4, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data.h:4, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/all.h:10, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/extension.h:6, from /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:1: /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In lambda function: /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:50:9: error: 'value_aggregate_kernel' was not declared in this scope; did you mean 'value_aggregate_cuda'? 50 | value_aggregate_kernel<<<grid, threads>>>( | ^~~~~~~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:50:33: error: expected primary-expression before '<' token 50 | value_aggregate_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:50:34: error: 'grid' was not declared in this scope; did you mean 'c10::attr::grid'? 50 | value_aggregate_kernel<<<grid, threads>>>( | ^~~~ In file included from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/jit/ir/ir.h:19, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/jit/api/function_impl.h:5, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/jit/api/method.h:8, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/jit/api/object.h:6, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/jit/api/module.h:5, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/serialize/input-archive.h:6, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/serialize/archive.h:4, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data/samplers/serialize.h:5, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data/samplers.h:9, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data/datasets/chunk.h:7, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data/datasets.h:5, from /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include/torch/data.h:5: /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/core/interned_strings.h:353:1: note: 'c10::attr::grid' declared here 353 | FORALL_NS_SYMBOLS(DEFINE_SYMBOL) | ^~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:50:49: error: expected primary-expression before '>' token 50 | value_aggregate_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In lambda function: /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:50:9: error: 'value_aggregate_kernel' was not declared in this scope; did you mean 'value_aggregate_cuda'? 50 | value_aggregate_kernel<<<grid, threads>>>( | ^~~~~~~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:50:33: error: expected primary-expression before '<' token 50 | value_aggregate_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:50:34: error: 'grid' was not declared in this scope; did you mean 'c10::attr::grid'? 50 | value_aggregate_kernel<<<grid, threads>>>( | ^~~~ /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/core/interned_strings.h:353:1: note: 'c10::attr::grid' declared here 353 | FORALL_NS_SYMBOLS(DEFINE_SYMBOL) | ^~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:50:49: error: expected primary-expression before '>' token 50 | value_aggregate_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In function 'at::Tensor apply_frame_cuda(at::Tensor, at::Tensor, at::Tensor, int)': /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:80:5: error: 'dim3' was not declared in this scope 80 | dim3 grid(B, N, total_pts); | ^~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In lambda function: /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:84:9: error: 'apply_frame_kernel' was not declared in this scope; did you mean 'apply_frame_cuda'? 84 | apply_frame_kernel<<<grid, threads>>>( | ^~~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:84:29: error: expected primary-expression before '<' token 84 | apply_frame_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:84:30: error: 'grid' was not declared in this scope; did you mean 'c10::attr::grid'? 84 | apply_frame_kernel<<<grid, threads>>>( | ^~~~ /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/core/interned_strings.h:353:1: note: 'c10::attr::grid' declared here 353 | FORALL_NS_SYMBOLS(DEFINE_SYMBOL) | ^~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:84:45: error: expected primary-expression before '>' token 84 | apply_frame_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In lambda function: /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:84:9: error: 'apply_frame_kernel' was not declared in this scope; did you mean 'apply_frame_cuda'? 84 | apply_frame_kernel<<<grid, threads>>>( | ^~~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:84:29: error: expected primary-expression before '<' token 84 | apply_frame_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:84:30: error: 'grid' was not declared in this scope; did you mean 'c10::attr::grid'? 84 | apply_frame_kernel<<<grid, threads>>>( | ^~~~ /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/core/interned_strings.h:353:1: note: 'c10::attr::grid' declared here 353 | FORALL_NS_SYMBOLS(DEFINE_SYMBOL) | ^~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:84:45: error: expected primary-expression before '>' token 84 | apply_frame_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In function 'at::Tensor inverse_frame_cuda(at::Tensor, at::Tensor, at::Tensor, int)': /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:110:5: error: 'dim3' was not declared in this scope 110 | dim3 grid(B, N, total_pts); | ^~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In lambda function: /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:114:9: error: 'inverse_frame_kernel' was not declared in this scope; did you mean 'inverse_frame_cuda'? 114 | inverse_frame_kernel<<<grid, threads>>>( | ^~~~~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:114:31: error: expected primary-expression before '<' token 114 | inverse_frame_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:114:32: error: 'grid' was not declared in this scope; did you mean 'c10::attr::grid'? 114 | inverse_frame_kernel<<<grid, threads>>>( | ^~~~ /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/core/interned_strings.h:353:1: note: 'c10::attr::grid' declared here 353 | FORALL_NS_SYMBOLS(DEFINE_SYMBOL) | ^~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:114:47: error: expected primary-expression before '>' token 114 | inverse_frame_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In lambda function: /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:114:9: error: 'inverse_frame_kernel' was not declared in this scope; did you mean 'inverse_frame_cuda'? 114 | inverse_frame_kernel<<<grid, threads>>>( | ^~~~~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:114:31: error: expected primary-expression before '<' token 114 | inverse_frame_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:114:32: error: 'grid' was not declared in this scope; did you mean 'c10::attr::grid'? 114 | inverse_frame_kernel<<<grid, threads>>>( | ^~~~ /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/core/interned_strings.h:353:1: note: 'c10::attr::grid' declared here 353 | FORALL_NS_SYMBOLS(DEFINE_SYMBOL) | ^~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:114:47: error: expected primary-expression before '>' token 114 | inverse_frame_kernel<<<grid, threads>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In function 'at::Tensor attention_forward_cuda(at::Tensor, at::Tensor, at::Tensor, at::Tensor, at::Tensor, at::Tensor, int, int, int, int, int, float)': /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:140:5: error: 'dim3' was not declared in this scope 140 | dim3 grid(B, H, N); | ^~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In lambda function: /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:145:9: error: 'attention_forward_kernel' was not declared in this scope; did you mean 'attention_forward_cuda'? 145 | attention_forward_kernel<<<grid, threads, smem_size>>>( | ^~~~~~~~~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:145:35: error: expected primary-expression before '<' token 145 | attention_forward_kernel<<<grid, threads, smem_size>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:145:36: error: 'grid' was not declared in this scope; did you mean 'c10::attr::grid'? 145 | attention_forward_kernel<<<grid, threads, smem_size>>>( | ^~~~ /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/core/interned_strings.h:353:1: note: 'c10::attr::grid' declared here 353 | FORALL_NS_SYMBOLS(DEFINE_SYMBOL) | ^~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:145:62: error: expected primary-expression before '>' token 145 | attention_forward_kernel<<<grid, threads, smem_size>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp: In lambda function: /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:145:9: error: 'attention_forward_kernel' was not declared in this scope; did you mean 'attention_forward_cuda'? 145 | attention_forward_kernel<<<grid, threads, smem_size>>>( | ^~~~~~~~~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:145:35: error: expected primary-expression before '<' token 145 | attention_forward_kernel<<<grid, threads, smem_size>>>( | ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:145:36: error: 'grid' was not declared in this scope; did you mean 'c10::attr::grid'? 145 | attention_forward_kernel<<<grid, threads, smem_size>>>( | ^~~~ /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/ATen/core/interned_strings.h:353:1: note: 'c10::attr::grid' declared here 353 | FORALL_NS_SYMBOLS(DEFINE_SYMBOL) | ^~~~~~~~~~~~~~~~~ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/main.cpp:145:62: error: expected primary-expression before '>' token 145 | attention_forward_kernel<<<grid, threads, smem_size>>>( | ^ [2/3] /usr/local/cuda/bin/nvcc -MD -MF cuda.cuda.o.d -ccbin /opt/conda/bin/x86_64-conda-linux-gnu-cc -DTORCH_EXTENSION_NAME=ipa_ops -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -D__CUDA_NO_HALF_OPERATORS__ -D__CUDA_NO_HALF_CONVERSIONS__ -D__CUDA_NO_BFLOAT16_CONVERSIONS__ -D__CUDA_NO_HALF2_OPERATORS__ --expt-relaxed-constexpr -gencode=arch=compute_90,code=compute_90 -gencode=arch=compute_90,code=sm_90 --compiler-options '-fPIC' -O3 -std=c++17 -c /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/cuda.cu -o cuda.cuda.o nvcc warning : incompatible redefinition for option 'compiler-bindir', the last value of this option was used /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/cuda.cu(181): warning #177-D: variable "rot" was declared but never referenced float rot = rotations[b * N * 3 * 3 + i * 9 + k * 3 + c]; ^ Remark: The warnings can be suppressed with "-diag-suppress <warning-number>" /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/cuda.cu(182): warning #177-D: variable "coord" was declared but never referenced float coord = (k == 0) ? 0.0f : 0.0f; ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/cuda.cu(177): warning #177-D: variable "centered" was declared but never referenced float centered = sum - trans; ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/cuda.cu(179): warning #177-D: variable "local_val" was declared but never referenced float local_val = 0.0f; ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/cuda.cu(206): warning #177-D: variable "trans" was declared but never referenced float trans = translations[b * N * 3 + n * 3 + c]; ^ /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/FW-GLM-5-1/level_2_problem_36_cache/k_306d91745e87/ipa_ops/cuda.cu(284): warning #177-D: variable "lane" was declared but never referenced int lane = tid & 31; ^ ninja: build stopped: subcommand failed.
final submitted kernel (747 lines, 25,143 chars) — full source, untruncated
import torch
import torch.nn as nn
import torch.nn.functional as F
import math
from torch.utils.cpp_extension import load_inline

# Define CUDA kernel for fused attention computation
cuda_source = """
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <c10/cuda/CUDAException.h>

__device__ __forceinline__ float warpReduceSum(float val) {
    for (int offset = 16; offset > 0; offset /= 2)
        val += __shfl_xor_sync(0xffffffff, val, offset);
    return val;
}

__device__ __forceinline__ float blockReduceSum(float val, int tid) {
    __shared__ float shared[32];
    int lane = tid & 31;
    int wid = tid >> 5;
    
    val = warpReduceSum(val);
    
    if (lane == 0) shared[wid] = val;
    __syncthreads();
    
    val = (tid < (blockDim.x >> 5)) ? shared[lane] : 0.0f;
    if (wid == 0) val = warpReduceSum(val);
    return val;
}

// Fused kernel: compute attention scores (scalar + point + pair_bias) and softmax
// Grid: (B, H, N), Block: (N_j) - each block handles one query position
__global__ void fused_attention_kernel(
    const float* __restrict__ q,        // (B, N, H, D)
    const float* __restrict__ k,        // (B, N, H, D)
    const float* __restrict__ q_pts,    // (B, N, H, Qp, 3)
    const float* __restrict__ k_pts,    // (B, N, H, Qp, 3)
    const float* __restrict__ pair_bias, // (B, H, N, N)
    const float* __restrict__ head_weights, // (H,)
    float* __restrict__ attn,           // (B, H, N, N)
    int B, int N, int H, int D, int Qp, float inv_sqrt_d
) {
    int b = blockIdx.x;  // batch
    int h = blockIdx.y;  // head
    int i = blockIdx.z;  // query position
    
    if (b >= B || h >= H || i >= N) return;
    
    int tid = threadIdx.x;
    int j = tid;  // key position
    
    // Load query vector for this head
    extern __shared__ float smem[];
    float* q_local = smem;  // size D
    float* q_pts_local = smem + D;  // size Qp * 3
    
    if (tid < D) {
        q_local[tid] = q[b * N * H * D + i * H * D + h * D + tid];
    }
    if (tid < Qp * 3) {
        q_pts_local[tid] = q_pts[b * N * H * Qp * 3 + i * H * Qp * 3 + h * Qp * 3 + tid];
    }
    __syncthreads();
    
    float hw = head_weights[h];
    
    // Each thread computes attention for one (i, j) pair
    // Compute scalar attention
    float scalar_attn = 0.0f;
    
    // Compute scalar product q_i * k_j
    for (int d = 0; d < D; d++) {
        float k_val = k[b * N * H * D + j * H * D + h * D + d];
        scalar_attn += q_local[d] * k_val;
    }
    scalar_attn *= inv_sqrt_d;
    
    // Compute point attention (negative squared distance)
    float pt_dist = 0.0f;
    for (int p = 0; p < Qp; p++) {
        for (int c = 0; c < 3; c++) {
            float q_pt = q_pts_local[p * 3 + c];
            float k_pt = k_pts[b * N * H * Qp * 3 + j * H * Qp * 3 + h * Qp * 3 + p * 3 + c];
            float diff = q_pt - k_pt;
            pt_dist += diff * diff;
        }
    }
    float pt_attn = -hw * pt_dist / 2.0f;
    
    // Get pair bias
    float pb = pair_bias[b * H * N * N + h * N * N + i * N + j];
    
    // Total attention score
    float score = scalar_attn + pt_attn + pb;
    
    // Store for softmax (need all scores first)
    __shared__ float scores[1024];  // Assuming N <= 1024
    scores[j] = score;
    __syncthreads();
    
    // Find max for numerical stability
    __shared__ float max_val;
    float local_max = scores[j];
    if (tid >= N) local_max = -1e30f;
    
    for (int offset = 16; offset > 0; offset /= 2) {
        float other = __shfl_xor_sync(0xffffffff, local_max, offset);
        local_max = fmaxf(local_max, other);
    }
    if (tid == 0) max_val = local_max;
    __syncthreads();
    
    // Compute exp(score - max)
    float exp_val = (tid < N) ? expf(scores[tid] - max_val) : 0.0f;
    
    // Reduce to get sum
    float sum = blockReduceSum(exp_val, tid);
    __shared__ float sum_val;
    if (tid == 0) sum_val = sum;
    __syncthreads();
    
    // Compute softmax
    float softmax_val = exp_val / sum_val;
    
    // Store result
    if (j < N) {
        attn[b * H * N * N + h * N * N + i * N + j] = softmax_val;
    }
}

// Fused kernel: aggregate values (scalar + point) and apply inverse frame
__global__ void fused_aggregate_kernel(
    const float* __restrict__ attn,      // (B, H, N, N)
    const float* __restrict__ v,         // (B, N, H, D)
    const float* __restrict__ v_pts,     // (B, N, H, Vp, 3)
    const float* __restrict__ rotations, // (B, N, 3, 3)
    const float* __restrict__ translations, // (B, N, 3)
    float* __restrict__ out_scalar,      // (B, N, H, D)
    float* __restrict__ out_pts_local,   // (B, N, H * Vp, 3)
    int B, int N, int H, int D, int Vp
) {
    int b = blockIdx.x;
    int i = blockIdx.y;  // output position
    int h = blockIdx.z;  // head
    int d = threadIdx.x; // dimension within head
    
    if (b >= B || i >= N || h >= H || d >= D + Vp * 3) return;
    
    int N_total = N;
    
    if (d < D) {
        // Aggregate scalar values
        float sum = 0.0f;
        for (int j = 0; j < N_total; j++) {
            float a = attn[b * H * N * N + h * N * N + i * N + j];
            float v_val = v[b * N * H * D + j * H * D + h * D + d];
            sum += a * v_val;
        }
        out_scalar[b * N * H * D + i * H * D + h * D + d] = sum;
    } else {
        // Aggregate point values
        int pt_idx = d - D;  // 0 to Vp*3-1
        int vp = pt_idx / 3;
        int c = pt_idx % 3;
        
        // First aggregate in global frame
        float sum = 0.0f;
        for (int j = 0; j < N_total; j++) {
            float a = attn[b * H * N * N + h * N * N + i * N + j];
            float v_pt = v_pts[b * N * H * Vp * 3 + j * H * Vp * 3 + h * Vp * 3 + vp * 3 + c];
            sum += a * v_pt;
        }
        
        // Apply inverse frame transformation
        // out_global - translations, then rotate by rotations^T
        float trans = translations[b * N * 3 + i * 3 + c];
        float centered = sum - trans;
        
        float local_val = 0.0f;
        for (int k = 0; k < 3; k++) {
            float rot = rotations[b * N * 3 * 3 + i * 9 + k * 3 + c];  // R^T = R col-major
            float coord = (k == 0) ? 0.0f : 0.0f;  // Need all 3 coords
        }
        
        // Store intermediate for inverse transform (need all 3 coords)
        // This kernel needs revision for proper inverse transform
    }
}

// Separate kernel for inverse frame transformation
__global__ void inverse_frame_kernel(
    const float* __restrict__ pts_global,  // (B, N, H*Vp, 3)
    const float* __restrict__ rotations,   // (B, N, 3, 3)
    const float* __restrict__ translations, // (B, N, 3)
    float* __restrict__ pts_local,         // (B, N, H*Vp, 3)
    int B, int N, int total_pts
) {
    int b = blockIdx.x;
    int n = blockIdx.y;
    int p = blockIdx.z;  // point index
    int c = threadIdx.x; // coordinate (0, 1, 2)
    
    if (b >= B || n >= N || p >= total_pts || c >= 3) return;
    
    // Load translation for this coordinate
    float trans = translations[b * N * 3 + n * 3 + c];
    
    // Load point coordinates
    float pt[3];
    for (int i = 0; i < 3; i++) {
        pt[i] = pts_global[b * N * total_pts * 3 + n * total_pts * 3 + p * 3 + i];
    }
    
    // Center
    float centered[3];
    for (int i = 0; i < 3; i++) {
        centered[i] = pt[i] - translations[b * N * 3 + n * 3 + i];
    }
    
    // Apply rotation^T (rotation is stored row-major, so R^T[i,j] = R[j,i])
    float local_val = 0.0f;
    for (int k = 0; k < 3; k++) {
        // R^T[c,k] = R[k,c]
        float rot_T = rotations[b * N * 9 + n * 9 + k * 3 + c];
        local_val += rot_T * centered[k];
    }
    
    pts_local[b * N * total_pts * 3 + n * total_pts * 3 + p * 3 + c] = local_val;
}

// Point transformation kernel (local to global)
__global__ void apply_frame_kernel(
    const float* __restrict__ pts_local,   // (B, N, H*P, 3)
    const float* __restrict__ rotations,   // (B, N, 3, 3)
    const float* __restrict__ translations, // (B, N, 3)
    float* __restrict__ pts_global,        // (B, N, H*P, 3)
    int B, int N, int total_pts
) {
    int b = blockIdx.x;
    int n = blockIdx.y;
    int p = blockIdx.z;  // point index
    int c = threadIdx.x; // coordinate
    
    if (b >= B || n >= N || p >= total_pts || c >= 3) return;
    
    // Load point coordinates
    float pt[3];
    for (int i = 0; i < 3; i++) {
        pt[i] = pts_local[b * N * total_pts * 3 + n * total_pts * 3 + p * 3 + i];
    }
    
    // Apply rotation: R * pt
    float rotated = 0.0f;
    for (int k = 0; k < 3; k++) {
        float rot = rotations[b * N * 9 + n * 9 + c * 3 + k];  // row-major
        rotated += rot * pt[k];
    }
    
    // Add translation
    float result = rotated + translations[b * N * 3 + n * 3 + c];
    
    pts_global[b * N * total_pts * 3 + n * total_pts * 3 + p * 3 + c] = result;
}

// Optimized attention computation with better memory access
__global__ void attention_forward_kernel(
    const float* __restrict__ q,
    const float* __restrict__ k,
    const float* __restrict__ q_pts,
    const float* __restrict__ k_pts,
    const float* __restrict__ pair_bias,
    const float* __restrict__ head_weights,
    float* __restrict__ attn_out,
    int B, int N, int H, int D, int Qp, float inv_sqrt_d
) {
    // Each block handles one (batch, head, query_i) combination
    int b = blockIdx.x;
    int h = blockIdx.y;
    int i = blockIdx.z;
    
    if (b >= B || h >= H || i >= N) return;
    
    int tid = threadIdx.x;
    int lane = tid & 31;
    
    // Shared memory for query and query points
    extern __shared__ char smem_buf[];
    float* q_smem = reinterpret_cast<float*>(smem_buf);
    float* q_pts_smem = q_smem + D;
    float* scores_smem = q_pts_smem + Qp * 3;
    
    // Load q and q_pts into shared memory
    for (int idx = tid; idx < D; idx += blockDim.x) {
        q_smem[idx] = q[b * N * H * D + i * H * D + h * D + idx];
    }
    for (int idx = tid; idx < Qp * 3; idx += blockDim.x) {
        q_pts_smem[idx] = q_pts[b * N * H * Qp * 3 + i * H * Qp * 3 + h * Qp * 3 + idx];
    }
    __syncthreads();
    
    float hw = head_weights[h];
    
    // Compute attention scores for all j
    float local_max = -1e30f;
    
    for (int j = tid; j < N; j += blockDim.x) {
        // Scalar attention
        float scalar = 0.0f;
        for (int d = 0; d < D; d++) {
            scalar += q_smem[d] * k[b * N * H * D + j * H * D + h * D + d];
        }
        scalar *= inv_sqrt_d;
        
        // Point attention
        float pt_dist = 0.0f;
        for (int p = 0; p < Qp; p++) {
            for (int c = 0; c < 3; c++) {
                float diff = q_pts_smem[p * 3 + c] - 
                            k_pts[b * N * H * Qp * 3 + j * H * Qp * 3 + h * Qp * 3 + p * 3 + c];
                pt_dist += diff * diff;
            }
        }
        float pt_attn = -hw * pt_dist / 2.0f;
        
        // Pair bias
        float pb = pair_bias[b * H * N * N + h * N * N + i * N + j];
        
        float score = scalar + pt_attn + pb;
        scores_smem[j] = score;
        local_max = fmaxf(local_max, score);
    }
    
    // Block-level max reduction
    __shared__ float global_max;
    float reduced_max = blockReduceSum(local_max, tid);  // Actually need max, not sum
    // Use separate max reduction
    for (int offset = blockDim.x / 2; offset > 0; offset /= 2) {
        float other = __shfl_xor_sync(0xffffffff, local_max, offset);
        local_max = fmaxf(local_max, other);
    }
    if (tid == 0) global_max = local_max;
    __syncthreads();
    
    // Compute exp and sum
    float local_sum = 0.0f;
    for (int j = tid; j < N; j += blockDim.x) {
        float exp_val = expf(scores_smem[j] - global_max);
        scores_smem[j] = exp_val;
        local_sum += exp_val;
    }
    
    __shared__ float global_sum;
    float reduced_sum = blockReduceSum(local_sum, tid);
    if (tid == 0) global_sum = reduced_sum;
    __syncthreads();
    
    // Normalize and store
    for (int j = tid; j < N; j += blockDim.x) {
        attn_out[b * H * N * N + h * N * N + i * N + j] = scores_smem[j] / global_sum;
    }
}

// Value aggregation kernel
__global__ void value_aggregate_kernel(
    const float* __restrict__ attn,
    const float* __restrict__ v,
    const float* __restrict__ v_pts,
    float* __restrict__ out_scalar,
    float* __restrict__ out_pts_global,
    int B, int N, int H, int D, int Vp
) {
    int b = blockIdx.x;
    int h = blockIdx.y;
    int i = blockIdx.z;  // output position
    
    if (b >= B || h >= H || i >= N) return;
    
    int tid = threadIdx.x;
    
    // Each thread handles one output dimension
    // First D dimensions are scalar, then Vp*3 are point coordinates
    
    __shared__ float attn_smem[1024];  // Assuming N <= 1024
    
    // Load attention weights
    for (int j = tid; j < N; j += blockDim.x) {
        attn_smem[j] = attn[b * H * N * N + h * N * N + i * N + j];
    }
    __syncthreads();
    
    // Scalar aggregation
    if (tid < D) {
        float sum = 0.0f;
        for (int j = 0; j < N; j++) {
            sum += attn_smem[j] * v[b * N * H * D + j * H * D + h * D + tid];
        }
        out_scalar[b * N * H * D + i * H * D + h * D + tid] = sum;
    }
    
    // Point aggregation
    if (tid < Vp * 3) {
        int vp = tid / 3;
        int c = tid % 3;
        float sum = 0.0f;
        for (int j = 0; j < N; j++) {
            sum += attn_smem[j] * v_pts[b * N * H * Vp * 3 + j * H * Vp * 3 + h * Vp * 3 + vp * 3 + c];
        }
        out_pts_global[b * N * H * Vp * 3 + i * H * Vp * 3 + h * Vp * 3 + vp * 3 + c] = sum;
    }
}
"""

cpp_source = """
torch::Tensor apply_frame_cuda(
    torch::Tensor pts_local,
    torch::Tensor rotations,
    torch::Tensor translations,
    int total_pts
);

torch::Tensor inverse_frame_cuda(
    torch::Tensor pts_global,
    torch::Tensor rotations,
    torch::Tensor translations,
    int total_pts
);

torch::Tensor attention_forward_cuda(
    torch::Tensor q,
    torch::Tensor k,
    torch::Tensor q_pts,
    torch::Tensor k_pts,
    torch::Tensor pair_bias,
    torch::Tensor head_weights,
    int B, int N, int H, int D, int Qp, float inv_sqrt_d
);

torch::Tensor value_aggregate_cuda(
    torch::Tensor attn,
    torch::Tensor v,
    torch::Tensor v_pts,
    int B, int N, int H, int D, int Vp
);

torch::Tensor value_aggregate_cuda(
    torch::Tensor attn,
    torch::Tensor v,
    torch::Tensor v_pts,
    int B, int N, int H, int D, int Vp
) {
    auto options = torch::TensorOptions().dtype(torch::kFloat32).device(attn.device());
    auto out_scalar = torch::empty({B, N, H, D}, options);
    auto out_pts_global = torch::empty({B, N, H, Vp, 3}, options);
    
    int threads = std::max(D, Vp * 3);
    threads = std::min(threads, 256);
    
    dim3 grid(B, H, N);
    
    AT_DISPATCH_FLOATING_TYPES(attn.scalar_type(), "value_aggregate", ([&] {
        value_aggregate_kernel<<<grid, threads>>>(
            attn.data_ptr<float>(),
            v.data_ptr<float>(),
            v_pts.data_ptr<float>(),
            out_scalar.data_ptr<float>(),
            out_pts_global.data_ptr<float>(),
            B, N, H, D, Vp
        );
    }));
    
    return torch::cat({out_scalar.reshape({B, N, H * D}), 
                       out_pts_global.reshape({B, N, H * Vp * 3})}, -1);
}

torch::Tensor apply_frame_cuda(
    torch::Tensor pts_local,
    torch::Tensor rotations,
    torch::Tensor translations,
    int total_pts
) {
    TORCH_CHECK(pts_local.is_cuda(), "pts_local must be CUDA tensor");
    TORCH_CHECK(rotations.is_cuda(), "rotations must be CUDA tensor");
    TORCH_CHECK(translations.is_cuda(), "translations must be CUDA tensor");
    
    auto options = torch::TensorOptions().dtype(torch::kFloat32).device(pts_local.device());
    int B = pts_local.size(0);
    int N = pts_local.size(1);
    
    auto pts_global = torch::empty({B, N, total_pts, 3}, options);
    
    dim3 grid(B, N, total_pts);
    int threads = 3;
    
    AT_DISPATCH_FLOATING_TYPES(pts_local.scalar_type(), "apply_frame", ([&] {
        apply_frame_kernel<<<grid, threads>>>(
            pts_local.data_ptr<float>(),
            rotations.data_ptr<float>(),
            translations.data_ptr<float>(),
            pts_global.data_ptr<float>(),
            B, N, total_pts
        );
    }));
    
    return pts_global;
}

torch::Tensor inverse_frame_cuda(
    torch::Tensor pts_global,
    torch::Tensor rotations,
    torch::Tensor translations,
    int total_pts
) {
    TORCH_CHECK(pts_global.is_cuda(), "pts_global must be CUDA tensor");
    
    auto options = torch::TensorOptions().dtype(torch::kFloat32).device(pts_global.device());
    int B = pts_global.size(0);
    int N = pts_global.size(1);
    
    auto pts_local = torch::empty({B, N, total_pts, 3}, options);
    
    dim3 grid(B, N, total_pts);
    int threads = 3;
    
    AT_DISPATCH_FLOATING_TYPES(pts_global.scalar_type(), "inverse_frame", ([&] {
        inverse_frame_kernel<<<grid, threads>>>(
            pts_global.data_ptr<float>(),
            rotations.data_ptr<float>(),
            translations.data_ptr<float>(),
            pts_local.data_ptr<float>(),
            B, N, total_pts
        );
    }));
    
    return pts_local;
}

torch::Tensor attention_forward_cuda(
    torch::Tensor q,
    torch::Tensor k,
    torch::Tensor q_pts,
    torch::Tensor k_pts,
    torch::Tensor pair_bias,
    torch::Tensor head_weights,
    int B, int N, int H, int D, int Qp, float inv_sqrt_d
) {
    TORCH_CHECK(q.is_cuda(), "q must be CUDA tensor");
    
    auto options = torch::TensorOptions().dtype(torch::kFloat32).device(q.device());
    auto attn_out = torch::empty({B, H, N, N}, options);
    
    dim3 grid(B, H, N);
    int threads = std::min(N, 256);
    int smem_size = D * sizeof(float) + Qp * 3 * sizeof(float) + N * sizeof(float);
    
    AT_DISPATCH_FLOATING_TYPES(q.scalar_type(), "attention_forward", ([&] {
        attention_forward_kernel<<<grid, threads, smem_size>>>(
            q.data_ptr<float>(),
            k.data_ptr<float>(),
            q_pts.data_ptr<float>(),
            k_pts.data_ptr<float>(),
            pair_bias.data_ptr<float>(),
            head_weights.data_ptr<float>(),
            attn_out.data_ptr<float>(),
            B, N, H, D, Qp, inv_sqrt_d
        );
    }));
    
    return attn_out;
}
"""

# Compile the extension
ipa_ops = load_inline(
    name='ipa_ops',
    cpp_sources=cpp_source,
    cuda_sources=cuda_source,
    functions=['apply_frame_cuda', 'inverse_frame_cuda', 'attention_forward_cuda', 'value_aggregate_cuda'],
    extra_cuda_cflags=['-O3'],
    verbose=False
)


class ModelNew(nn.Module):
    """
    Invariant Point Attention (IPA) with custom CUDA kernels.
    """

    def __init__(self, node_dim, pair_dim, num_heads, num_query_points, num_value_points):
        super().__init__()
        self.num_heads = num_heads
        self.head_dim = node_dim // num_heads
        self.num_query_points = num_query_points
        self.num_value_points = num_value_points
        assert node_dim % num_heads == 0

        d = self.head_dim
        self.q_proj = nn.Linear(node_dim, num_heads * d, bias=False)
        self.k_proj = nn.Linear(node_dim, num_heads * d, bias=False)
        self.v_proj = nn.Linear(node_dim, num_heads * d, bias=False)

        self.q_pts = nn.Linear(node_dim, num_heads * num_query_points * 3, bias=False)
        self.k_pts = nn.Linear(node_dim, num_heads * num_query_points * 3, bias=False)
        self.v_pts = nn.Linear(node_dim, num_heads * num_value_points * 3, bias=False)

        self.pair_bias = nn.Linear(pair_dim, num_heads, bias=False)

        self.head_weights = nn.Parameter(torch.zeros(num_heads))

        out_features = num_heads * d + num_heads * num_value_points * 3
        self.out_proj = nn.Linear(out_features, node_dim)

        self.layer_norm = nn.LayerNorm(node_dim)

    def forward(
        self,
        node_repr: torch.Tensor,
        pair_repr: torch.Tensor,
        translations: torch.Tensor,
        rotations: torch.Tensor,
    ) -> torch.Tensor:
        B, N, D = node_repr.shape
        h = self.num_heads
        d = self.head_dim
        Qp = self.num_query_points
        Vp = self.num_value_points

        x = self.layer_norm(node_repr)

        # Projections
        q = self.q_proj(x).view(B, N, h, d)
        k = self.k_proj(x).view(B, N, h, d)
        v = self.v_proj(x).view(B, N, h, d)

        # Point projections (local frame)
        q_pts_local = self.q_pts(x).view(B, N, h * Qp, 3)
        k_pts_local = self.k_pts(x).view(B, N, h * Qp, 3)
        v_pts_local = self.v_pts(x).view(B, N, h * Vp, 3)

        # Transform points to global frame using custom CUDA kernel
        if x.is_cuda:
            q_pts_global = ipa_ops.apply_frame_cuda(
                q_pts_local.contiguous().float(),
                rotations.contiguous().float(),
                translations.contiguous().float(),
                h * Qp
            )
            k_pts_global = ipa_ops.apply_frame_cuda(
                k_pts_local.contiguous().float(),
                rotations.contiguous().float(),
                translations.contiguous().float(),
                h * Qp
            )
            v_pts_global = ipa_ops.apply_frame_cuda(
                v_pts_local.contiguous().float(),
                rotations.contiguous().float(),
                translations.contiguous().float(),
                h * Vp
            )
            
            q_pts = q_pts_global.view(B, N, h, Qp, 3)
            k_pts = k_pts_global.view(B, N, h, Qp, 3)
            v_pts = v_pts_global.view(B, N, h, Vp, 3)
            
            # Compute pair bias
            pair_bias = self.pair_bias(pair_repr).permute(0, 3, 1, 2)
            
            # Compute head weights
            w = F.softplus(self.head_weights)
            
            # Fused attention computation
            inv_sqrt_d = 1.0 / math.sqrt(d)
            attn = ipa_ops.attention_forward_cuda(
                q.contiguous().float(),
                k.contiguous().float(),
                q_pts.contiguous().float(),
                k_pts.contiguous().float(),
                pair_bias.contiguous().float(),
                w.contiguous().float(),
                B, N, h, d, Qp, inv_sqrt_d
            )
            
            # Value aggregation
            out_combined = ipa_ops.value_aggregate_cuda(
                attn.contiguous().float(),
                v.contiguous().float(),
                v_pts.contiguous().float(),
                B, N, h, d, Vp
            )
            
            # Split scalar and point outputs
            out_scalar = out_combined[..., :h * d].view(B, N, h, d)
            out_pts_global = out_combined[..., h * d:].view(B, N, h * Vp, 3)
            
            # Transform points back to local frame
            out_pts_local = ipa_ops.inverse_frame_cuda(
                out_pts_global.contiguous().float(),
                rotations.contiguous().float(),
                translations.contiguous().float(),
                h * Vp
            )
            out_pts_flat = out_pts_local.view(B, N, h * Vp * 3)
            
            out = torch.cat([out_scalar.reshape(B, N, h * d), out_pts_flat], dim=-1)
            return self.out_proj(out)
        else:
            # CPU fallback - use original implementation
            q_pts = self._apply_frame(q_pts_local, rotations, translations).view(B, N, h, Qp, 3)
            k_pts = self._apply_frame(k_pts_local, rotations, translations).view(B, N, h, Qp, 3)
            v_pts = self._apply_frame(v_pts_local, rotations, translations).view(B, N, h, Vp, 3)

            attn_scalar = torch.einsum("bihd,bjhd->bhij", q, k) / math.sqrt(d)

            q_expand = q_pts.unsqueeze(2)
            k_expand = k_pts.unsqueeze(1)
            pt_dist = ((q_expand - k_expand) ** 2).sum(dim=(-1, -2))

            w = F.softplus(self.head_weights)
            pt_attn = -(w.view(1, 1, 1, h) * pt_dist) / 2.0
            pt_attn = pt_attn.permute(0, 3, 1, 2)

            pair_bias = self.pair_bias(pair_repr).permute(0, 3, 1, 2)

            attn = attn_scalar + pt_attn + pair_bias
            attn = F.softmax(attn, dim=-1)

            out_scalar = torch.einsum("bhij,bjhd->bihd", attn, v).reshape(B, N, h * d)

            out_pts = torch.einsum("bhij,bjhpc->bihpc", attn, v_pts)
            out_pts = out_pts.reshape(B, N, h * Vp, 3)
            out_pts_local = self._apply_inv_frame(out_pts, rotations, translations)
            out_pts_flat = out_pts_local.reshape(B, N, h * Vp * 3)

            out = torch.cat([out_scalar, out_pts_flat], dim=-1)
            return self.out_proj(out)

    def _apply_frame(self, pts, rotations, translations):
        global_pts = torch.einsum("bnpc,bncd->bnpd", pts, rotations) + translations.unsqueeze(2)
        return global_pts

    def _apply_inv_frame(self, pts, rotations, translations):
        centered = pts - translations.unsqueeze(2)
        local_pts = torch.einsum("bnpc,bndc->bnpd", centered, rotations)
        return local_pts