gpt-5.5-priority · popcorn · l12_all_gpt
correct 10_GFVLA_FusedPairwiseNodeAggregate.py
model
gpt-5.5-priority
turns / max
14 / 15
tool calls
14
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
popcorn
runtime
0.08 μs
ref runtime
0.11 μs
speedup
1.28x
started
2026-05-04T09:53:31Z
timingkernelbench.timing
kernel runtime
0.08 μs
ref runtime
0.11 μs
speedup
1.28x
kernel mean / median / std
0.08 / — / 8.73e-04 μs
ref mean / median / std
0.11 / — / 0.02 μs
numerical precisioneval_kernel_against_ref
max abs error
4.17e-06
mean abs error
4.75e-07
max rel error
0.02
mean rel error
2.62e-06
gpu memoryextended_metrics.measure_memory
kernel peak
36.38 MB
ref peak
38.84 MB
kernel / ref
0.94x
kernel launches / fusiontorch.profiler
kernel launches
7
ref launches
50
fusion ratio (ref / kernel)
7.14x
total cuda time
77 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.278
dram util %
7.9%
compute util %
27.8%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
263.16 GB/s
dram util %
7.9%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
237.2%
bottleneck
compute-bound
dominant pipe %
27.8%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
449.9%
ld sectors / req
58.36
st sectors / req
—
regs / thread
132
smem / block
6144 B
block size
1024
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
long_scoreboard
10599.2%
mio_throttle
1217.0%
short_scoreboard
1066.6%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
import torch.nn.functional as F

# Default ModelNew is PyTorch-only. run_and_check: use check_kernel=False with backend=cuda
# until the candidate file contains a real CUDA kernel (see kernel_static_checker).


class Model(nn.Module):
    """
    GF-VLA style **fused pairwise → node** scene-graph readout.

    For every ordered pair (i, j), fuse ``[node_i || node_j || pair_feat_ij]`` with
    an MLP, mask invalid graph edges, then **max-pool over outgoing neighbors j**
    to produce an updated per-object signal (object-centric scene graph refresh).

    Complements ``7_GFVLA_FusedSceneGraphUpdate`` (attention) with an MLP + reduce
    fusion pattern common for relation classifiers and affordance heads.
    """

    def __init__(self, dim: int, pair_dim: int, hidden: int):
        super().__init__()
        self.dim = dim
        self.pair_dim = pair_dim
        self.fuse = nn.Sequential(
            nn.Linear(2 * dim + pair_dim, hidden),
            nn.SiLU(),
            nn.Linear(hidden, dim),
        )
        self.out_norm = nn.LayerNorm(dim)

    def forward(
        self,
        nodes: torch.Tensor,
        pair_feats: torch.Tensor,
        edge_mask: torch.Tensor,
    ) -> torch.Tensor:
        """
        Args:
            nodes: (B, N, D)
            pair_feats: (B, N, N, P)
            edge_mask: (B, N, N) float {0,1}
        Returns:
            (B, N, D) residual ``nodes + LN( max_j fuse(...) )``
        """
        B, N, D = nodes.shape
        assert pair_feats.shape == (B, N, N, self.pair_dim)

        hi = nodes.unsqueeze(2).expand(-1, -1, N, -1)
        hj = nodes.unsqueeze(1).expand(-1, N, -1, -1)
        fused = self.fuse(torch.cat([hi, hj, pair_feats], dim=-1))

        neg = torch.finfo(fused.dtype).min
        fused = fused.masked_fill(edge_mask.unsqueeze(-1) < 0.5, neg)
        pooled, _ = fused.max(dim=2)
        return nodes + self.out_norm(pooled)


class ModelNew(nn.Module):
    """KernelBench candidate entry point; default delegates to ``Model``."""

    def __init__(self, dim: int, pair_dim: int, hidden: int):
        super().__init__()
        self._impl = Model(dim, pair_dim, hidden)

    def forward(
        self,
        nodes: torch.Tensor,
        pair_feats: torch.Tensor,
        edge_mask: torch.Tensor,
    ) -> torch.Tensor:
        return self._impl(nodes, pair_feats, edge_mask)


batch_size = 4
num_objects = 24
dim = 96
pair_dim = 16
hidden = 192


def get_inputs():
    p = popcorn_pri
    nodes = torch.randn(p.jitter_int(batch_size), p.jitter_int(num_objects), dim)
    pair_feats = torch.randn(p.jitter_int(batch_size), p.jitter_int(num_objects), p.jitter_int(num_objects), pair_dim)
    edge_mask = torch.ones(p.jitter_int(batch_size), p.jitter_int(num_objects), p.jitter_int(num_objects))
    return [nodes, pair_feats, edge_mask]


def get_init_inputs():
    return [dim, pair_dim, hidden]
turn 09.5s turn · 9.5s LLM · 0.0s tools
reasoning
**Considering implementation methods** I'm thinking about using torch.matmul as a reference. Should I consider that a custom implementation isn't necessarily faster? I really want to be efficient here, so I might need to dig deeper into using the torch extension. I'm wondering if I can call torch::linear, but I’m not quite sure if that’s allowed. I definitely don't want to run into any issues here while trying to optimize!
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) · 32.8s turn · 32.8s LLM · 10,385 chars (click to expand)
turn 132.8s turn · 32.8s LLM · 0.0s tools
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void hidden_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pair_feats,\n const float* __restrict__ w1,\n const float* __restrict__ b1,\n float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n const float* wi = w1 + h * (2 * D + P);\n float acc = b1[h];\n const float* ni = nodes + ((b * N + i) * D);\n const float* nj = nodes + ((b * N + j) * D);\n #pragma unroll 4\n for (int k = 0; k < D; ++k) acc = fmaf(ni[k], wi[k], acc);\n #pragma unroll 4\n for (int k = 0; k < D; ++k) acc = fmaf(nj[k], wi[D + k], acc);\n const float* pf = pair_feats + (((b * N + i) * N + j) * P);\n #pragma unroll 4\n for (int k = 0; k < P; ++k) acc = fmaf(pf[k], wi[2 * D + k], acc);\n float sig = 1.0f / (1.0f + __expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_max(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) {\n v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));\n }\n return v;\n}\n\n__global__ void pooled_kernel(const float* __restrict__ hidden,\n const float* __restrict__ edge_mask,\n const float* __restrict__ w2,\n const float* __restrict__ b2,\n float* __restrict__ pooled,\n int B, int N, int D, int H) {\n int row = blockIdx.y; // b*N+i\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 4 + warp;\n if (d >= D) return;\n int b = row / N;\n int i = row - b * N;\n float val = -FLT_MAX;\n if (lane < N) {\n int j = lane;\n float m = edge_mask[(row * N) + j];\n if (m >= 0.5f) {\n int pair = (row * N + j);\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float acc = b2[d];\n #pragma unroll 4\n for (int h = 0; h < H; ++h) acc = fmaf(hp[h], wd[h], acc);\n val = acc;\n }\n }\n val = warp_max(val);\n if (lane == 0) pooled[row * D + d] = val;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pooled,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ out,\n int rows, int D) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f;\n float sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d];\n sum += x;\n sumsq = fmaf(x, x, sumsq);\n }\n __shared__ float smem[256];\n smem[tid] = sum;\n smem[tid + blockDim.x] = sumsq;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) {\n smem[tid] += smem[tid + s];\n smem[tid + blockDim.x] += smem[tid + blockDim.x + s];\n }\n __syncthreads();\n }\n float mean = smem[0] / (float)D;\n float var = smem[blockDim.x] / (float)D - mean * mean;\n float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d];\n float y = (x - mean) * inv;\n out[row * D + d] = nodes[row * D + d] + y * gamma[d] + beta[d];\n }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0);\n int N = nodes.size(1);\n int D = nodes.size(2);\n int P = pair_feats.size(3);\n int H = w1.size(0);\n auto hidden = torch::empty({B, N, N, H}, nodes.options());\n auto pooled = torch::empty({B, N, D}, nodes.options());\n auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n int total_pairs = B * N * N;\n hidden_kernel<<<total_pairs, 256, 0, stream>>>(nodes.data_ptr<float>(), pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n dim3 grid2((D + 3) / 4, B * N);\n pooled_kernel<<<grid2, 128, 0, stream>>>(hidden.data_ptr<float>(), edge_mask.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D, H);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n\n_ext = load_inline(name='gf_vla_fused_ext_v1', cpp_sources='', cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3', '--use_fast_math'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__()\n self.dim = dim\n self.pair_dim = pair_dim\n self.fuse = nn.Sequential(\n nn.Linear(2 * dim + pair_dim, hidden),\n nn.SiLU(),\n nn.Linear(hidden, dim),\n )\n self.out_norm = nn.LayerNorm(dim)\n\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← compile_kernel (fail)
failcompile_kernel compile_kernel FAILED: RuntimeError. RuntimeError: Error building extension 'gf_vla_fused_ext_v1': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=gf_vla_fused_ext_v1 -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 -O3 -c /scratch/abaner/KernelBench/runs/l12_all_gpt/popcorn/gpt-5.5-priority/level_2_problem_10_cache/k_c1435e416290/gf_vla_fused_ext_v1/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=gf_vla_fused_ext_v1 -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 -O3 -c /scratch/abaner/KernelBench/runs/l12_all_gpt/popcorn/gpt-5.5-priority/level_2_problem_10_cache/k_c1435e416290/gf_vla_fused_ext_v1/main.cpp -o main.o /scratch/abaner/KernelBench/runs/l12_all_gpt/popcorn/gpt-5.5-priority/level_2_problem_10_cache/k_c1435e416290/gf_vla_fused_ext_v1/main.cpp: In function 'void pybind11_init_gf_vla_fused_ext_v1(pybind11::module_&)': /scratch/abaner/KernelBench/runs/l12_all_gpt/popcorn/gpt-5.5-priority/level_2_problem_10_cache/k_c1435e416290/gf_vla_fused_ext_v1/main.cpp:4:52: error: 'fused_forward' was not declared in this scope 4 | m.def("fused_forward", torch::wrap_pybind_function(fused_forward), "fused_forward"); | ^~~~~~~~~~~~~ [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=gf_vla_fused_ext_v1 -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 --use_fast_math -std=c++17 -c /scratch/abaner/KernelBench/runs/l12_all_gpt/popcorn/gpt-5.5-priority/level_2_problem_10_cache/k_c1435e416290/gf_vla_fused_ext_v1/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/l12_all_gpt/popcorn/gpt-5.5-priority/level_2_problem_10_cache/k_c1435e416290/gf_vla_fused_ext_v1/cuda.cu(59): warning #177-D: variable "i" was declared but never referenced int i = row - b * N; ^ Remark: The warnings can be suppressed with "-diag-suppress <warning-number>" ninja: build stopped: subcommand failed.
turn 2 · 1 tool call(s) · 13.5s turn · 13.5s LLM · 7,639 chars (click to expand)
turn 213.5s turn · 13.5s LLM · 0.0s tools
reasoning
**Evaluating C++ declarations** I'm considering whether I need to include declarations in cpp_sources. It seems like load_inline functions look into cpp source instead of CUDA. Usually, I think cpp_sources require a declaration. I should provide a C++ prototype. It looks like I can't pybind directly in CUDA, so I might need to use cpp_sources with something like torch::Tensor fused_forward(...). That's a good approach to take!
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void hidden_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pair_feats,\n const float* __restrict__ w1,\n const float* __restrict__ b1,\n float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n const float* wi = w1 + h * (2 * D + P);\n float acc = b1[h];\n const float* ni = nodes + ((b * N + i) * D);\n const float* nj = nodes + ((b * N + j) * D);\n #pragma unroll 4\n for (int k = 0; k < D; ++k) acc = fmaf(ni[k], wi[k], acc);\n #pragma unroll 4\n for (int k = 0; k < D; ++k) acc = fmaf(nj[k], wi[D + k], acc);\n const float* pf = pair_feats + (((b * N + i) * N + j) * P);\n #pragma unroll 4\n for (int k = 0; k < P; ++k) acc = fmaf(pf[k], wi[2 * D + k], acc);\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_max(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) {\n v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));\n }\n return v;\n}\n\n__global__ void pooled_kernel(const float* __restrict__ hidden,\n const float* __restrict__ edge_mask,\n const float* __restrict__ w2,\n const float* __restrict__ b2,\n float* __restrict__ pooled,\n int B, int N, int D, int H) {\n int row = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 4 + warp;\n if (d >= D) return;\n float val = -FLT_MAX;\n if (lane < N) {\n int j = lane;\n float m = edge_mask[row * N + j];\n if (m >= 0.5f) {\n int pair = row * N + j;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float acc = b2[d];\n #pragma unroll 4\n for (int h = 0; h < H; ++h) acc = fmaf(hp[h], wd[h], acc);\n val = acc;\n }\n }\n val = warp_max(val);\n if (lane == 0) pooled[row * D + d] = val;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pooled,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ out,\n int rows, int D) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d];\n sum += x;\n sumsq = fmaf(x, x, sumsq);\n }\n __shared__ float smem[256];\n smem[tid] = sum;\n smem[tid + blockDim.x] = sumsq;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) {\n smem[tid] += smem[tid + s];\n smem[tid + blockDim.x] += smem[tid + blockDim.x + s];\n }\n __syncthreads();\n }\n float mean = smem[0] / (float)D;\n float var = smem[blockDim.x] / (float)D - mean * mean;\n float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d];\n float y = (x - mean) * inv;\n out[row * D + d] = nodes[row * D + d] + y * gamma[d] + beta[d];\n }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0);\n auto hidden = torch::empty({B, N, N, H}, nodes.options());\n auto pooled = torch::empty({B, N, D}, nodes.options());\n auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n hidden_kernel<<<B*N*N, 256, 0, stream>>>(nodes.data_ptr<float>(), pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n dim3 grid2((D + 3) / 4, B * N);\n pooled_kernel<<<grid2, 128, 0, stream>>>(hidden.data_ptr<float>(), edge_mask.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D, H);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n\n_ext = load_inline(name='gf_vla_fused_ext_v2', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__()\n self.dim = dim\n self.pair_dim = pair_dim\n self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim))\n self.out_norm = nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 3 · 1 tool call(s) · 11.7s turn · 11.7s LLM · 7,080 chars (click to expand)
turn 311.7s turn · 11.7s LLM · 0.0s tools
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void hidden_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pair_feats,\n const float* __restrict__ w1,\n const float* __restrict__ b1,\n float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n const float* wi = w1 + h * (2 * D + P);\n float acc = b1[h];\n const float* ni = nodes + ((b * N + i) * D);\n const float* nj = nodes + ((b * N + j) * D);\n #pragma unroll 4\n for (int k = 0; k < D; ++k) acc = fmaf(ni[k], wi[k], acc);\n #pragma unroll 4\n for (int k = 0; k < D; ++k) acc = fmaf(nj[k], wi[D + k], acc);\n const float* pf = pair_feats + (((b * N + i) * N + j) * P);\n #pragma unroll 4\n for (int k = 0; k < P; ++k) acc = fmaf(pf[k], wi[2 * D + k], acc);\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_max(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));\n return v;\n}\n\n__global__ void pooled_kernel(const float* __restrict__ hidden,\n const float* __restrict__ edge_mask,\n const float* __restrict__ w2,\n const float* __restrict__ b2,\n float* __restrict__ pooled,\n int B, int N, int D, int H) {\n int row = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 4 + warp;\n if (d >= D) return;\n float val = -FLT_MAX;\n if (lane < N) {\n int j = lane;\n float m = edge_mask[row * N + j];\n if (m >= 0.5f) {\n int pair = row * N + j;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float acc = b2[d];\n #pragma unroll 4\n for (int h = 0; h < H; ++h) acc = fmaf(hp[h], wd[h], acc);\n val = acc;\n }\n }\n val = warp_max(val);\n if (lane == 0) pooled[row * D + d] = val;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pooled,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ out,\n int rows, int D) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d]; sum += x; sumsq = fmaf(x, x, sumsq);\n }\n __shared__ float smem[256];\n smem[tid] = sum; smem[tid + blockDim.x] = sumsq;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) { smem[tid] += smem[tid + s]; smem[tid + blockDim.x] += smem[tid + blockDim.x + s]; }\n __syncthreads();\n }\n float mean = smem[0] / (float)D;\n float var = smem[blockDim.x] / (float)D - mean * mean;\n float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d];\n out[row * D + d] = nodes[row * D + d] + (x - mean) * inv * gamma[d] + beta[d];\n }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0);\n auto hidden = torch::empty({B, N, N, H}, nodes.options());\n auto pooled = torch::empty({B, N, D}, nodes.options());\n auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n hidden_kernel<<<B*N*N, 256, 0, stream>>>(nodes.data_ptr<float>(), pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n pooled_kernel<<<dim3((D + 3) / 4, B * N), 128, 0, stream>>>(hidden.data_ptr<float>(), edge_mask.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D, H);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_v2c', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__()\n self.dim = dim; self.pair_dim = pair_dim\n self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim))\n self.out_norm = nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=3.58e-06 mean_abs_err=4.09e-07 max_rel_err=9.66e-03
turn 410.3s turn · 10.3s LLM · 0.0s tools
call → profile_kernel
callprofile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n__global__ void hidden_kernel(const float* __restrict__ nodes,const float* __restrict__ pair_feats,const float* __restrict__ w1,const float* __restrict__ b1,float* __restrict__ hidden,int B,int N,int D,int P,int H){int pair=blockIdx.x;int h=threadIdx.x;if(h>=H)return;int j=pair%N;int tmp=pair/N;int i=tmp%N;int b=tmp/N;const float* wi=w1+h*(2*D+P);float acc=b1[h];const float* ni=nodes+((b*N+i)*D);const float* nj=nodes+((b*N+j)*D);#pragma unroll 4\nfor(int k=0;k<D;++k)acc=fmaf(ni[k],wi[k],acc);#pragma unroll 4\nfor(int k=0;k<D;++k)acc=fmaf(nj[k],wi[D+k],acc);const float* pf=pair_feats+(((b*N+i)*N+j)*P);#pragma unroll 4\nfor(int k=0;k<P;++k)acc=fmaf(pf[k],wi[2*D+k],acc);float sig=1.0f/(1.0f+expf(-acc));hidden[pair*H+h]=acc*sig;}\n__inline__ __device__ float warp_max(float v){#pragma unroll\nfor(int o=16;o>0;o>>=1)v=fmaxf(v,__shfl_down_sync(0xffffffff,v,o));return v;}\n__global__ void pooled_kernel(const float* __restrict__ hidden,const float* __restrict__ edge_mask,const float* __restrict__ w2,const float* __restrict__ b2,float* __restrict__ pooled,int B,int N,int D,int H){int row=blockIdx.y;int warp=threadIdx.x>>5;int lane=threadIdx.x&31;int d=blockIdx.x*4+warp;if(d>=D)return;float val=-FLT_MAX;if(lane<N){int j=lane;float m=edge_mask[row*N+j];if(m>=0.5f){int pair=row*N+j;const float* hp=hidden+pair*H;const float* wd=w2+d*H;float acc=b2[d];#pragma unroll 4\nfor(int h=0;h<H;++h)acc=fmaf(hp[h],wd[h],acc);val=acc;}}val=warp_max(val);if(lane==0)pooled[row*D+d]=val;}\n__global__ void layernorm_kernel(const float* __restrict__ nodes,const float* __restrict__ pooled,const float* __restrict__ gamma,const float* __restrict__ beta,float* __restrict__ out,int rows,int D){int row=blockIdx.x;int tid=threadIdx.x;float sum=0.0f,sumsq=0.0f;for(int d=tid;d<D;d+=blockDim.x){float x=pooled[row*D+d];sum+=x;sumsq=fmaf(x,x,sumsq);}__shared__ float smem[256];smem[tid]=sum;smem[tid+blockDim.x]=sumsq;__syncthreads();for(int s=blockDim.x>>1;s>0;s>>=1){if(tid<s){smem[tid]+=smem[tid+s];smem[tid+blockDim.x]+=smem[tid+blockDim.x+s];}__syncthreads();}float mean=smem[0]/(float)D;float var=smem[blockDim.x]/(float)D-mean*mean;float inv=rsqrtf(var+1.0e-5f);for(int d=tid;d<D;d+=blockDim.x){float x=pooled[row*D+d];out[row*D+d]=nodes[row*D+d]+(x-mean)*inv*gamma[d]+beta[d];}}\ntorch::Tensor fused_forward(torch::Tensor nodes,torch::Tensor pair_feats,torch::Tensor edge_mask,torch::Tensor w1,torch::Tensor b1,torch::Tensor w2,torch::Tensor b2,torch::Tensor gamma,torch::Tensor beta){int B=nodes.size(0),N=nodes.size(1),D=nodes.size(2),P=pair_feats.size(3),H=w1.size(0);auto hidden=torch::empty({B,N,N,H},nodes.options());auto pooled=torch::empty({B,N,D},nodes.options());auto out=torch::empty_like(nodes);cudaStream_t stream=at::cuda::getCurrentCUDAStream();hidden_kernel<<<B*N*N,256,0,stream>>>(nodes.data_ptr<float>(),pair_feats.data_ptr<float>(),w1.data_ptr<float>(),b1.data_ptr<float>(),hidden.data_ptr<float>(),B,N,D,P,H);pooled_kernel<<<dim3((D+3)/4,B*N),128,0,stream>>>(hidden.data_ptr<float>(),edge_mask.data_ptr<float>(),w2.data_ptr<float>(),b2.data_ptr<float>(),pooled.data_ptr<float>(),B,N,D,H);layernorm_kernel<<<B*N,128,0,stream>>>(nodes.data_ptr<float>(),pooled.data_ptr<float>(),gamma.data_ptr<float>(),beta.data_ptr<float>(),out.data_ptr<float>(),B*N,D);return out;}\n'''\n_ext=load_inline(name='gf_vla_fused_ext_prof',cpp_sources=_cpp_src,cuda_sources=_cuda_src,functions=['fused_forward'],extra_cuda_cflags=['-O3'],extra_cflags=['-O3'],verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self,dim:int,pair_dim:int,hidden:int):\n super().__init__();self.dim=dim;self.pair_dim=pair_dim;self.fuse=nn.Sequential(nn.Linear(2*dim+pair_dim,hidden),nn.SiLU(),nn.Linear(hidden,dim));self.out_norm=nn.LayerNorm(dim)\n def forward(self,nodes,pair_feats,edge_mask):\n return _ext.fused_forward(nodes,pair_feats,edge_mask,self.fuse[0].weight,self.fuse[0].bias,self.fuse[2].weight,self.fuse[2].bias,self.out_norm.weight,self.out_norm.bias)\n" }
result ← profile_kernel (fail)
failprofile_kernel profile_kernel FAILED: worker exited with code 1. ^ 10 errors detected in the compilation of "/scratch/abaner/KernelBench/runs/l12_all_gpt/popcorn/gpt-5.5-priority/level_2_problem_10_cache/k_2af20115d11e/gf_vla_fused_ext_prof/cuda.cu". ninja: build stopped: subcommand failed.
turn 5 · 1 tool call(s) · 10.7s turn · 10.7s LLM · 9,188 chars (click to expand)
turn 510.7s turn · 10.7s LLM · 0.0s tools
reasoning
**Optimizing code profile** I’ve compacted the pragmas, but it seems I’ve done it incorrectly. My previous full code appears to be okay, so I’m considering whether I need to maintain a final version of this code. I might be able to skip that step, but I know I should optimize it further. It could be beneficial to profile what I have now and maybe create a correct copy. Let's explore that!
call → profile_kernel
callprofile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void hidden_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pair_feats,\n const float* __restrict__ w1,\n const float* __restrict__ b1,\n float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n const float* wi = w1 + h * (2 * D + P);\n float acc = b1[h];\n const float* ni = nodes + ((b * N + i) * D);\n const float* nj = nodes + ((b * N + j) * D);\n #pragma unroll 4\n for (int k = 0; k < D; ++k) acc = fmaf(ni[k], wi[k], acc);\n #pragma unroll 4\n for (int k = 0; k < D; ++k) acc = fmaf(nj[k], wi[D + k], acc);\n const float* pf = pair_feats + (((b * N + i) * N + j) * P);\n #pragma unroll 4\n for (int k = 0; k < P; ++k) acc = fmaf(pf[k], wi[2 * D + k], acc);\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_max(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));\n return v;\n}\n\n__global__ void pooled_kernel(const float* __restrict__ hidden,\n const float* __restrict__ edge_mask,\n const float* __restrict__ w2,\n const float* __restrict__ b2,\n float* __restrict__ pooled,\n int B, int N, int D, int H) {\n int row = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 4 + warp;\n if (d >= D) return;\n float val = -FLT_MAX;\n if (lane < N) {\n int j = lane;\n float m = edge_mask[row * N + j];\n if (m >= 0.5f) {\n int pair = row * N + j;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float acc = b2[d];\n #pragma unroll 4\n for (int h = 0; h < H; ++h) acc = fmaf(hp[h], wd[h], acc);\n val = acc;\n }\n }\n val = warp_max(val);\n if (lane == 0) pooled[row * D + d] = val;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pooled,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ out,\n int rows, int D) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d]; sum += x; sumsq = fmaf(x, x, sumsq);\n }\n __shared__ float smem[256];\n smem[tid] = sum; smem[tid + blockDim.x] = sumsq;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) { smem[tid] += smem[tid + s]; smem[tid + blockDim.x] += smem[tid + blockDim.x + s]; }\n __syncthreads();\n }\n float mean = smem[0] / (float)D;\n float var = smem[blockDim.x] / (float)D - mean * mean;\n float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d];\n out[row * D + d] = nodes[row * D + d] + (x - mean) * inv * gamma[d] + beta[d];\n }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0);\n auto hidden = torch::empty({B, N, N, H}, nodes.options());\n auto pooled = torch::empty({B, N, D}, nodes.options());\n auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n hidden_kernel<<<B*N*N, 256, 0, stream>>>(nodes.data_ptr<float>(), pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n pooled_kernel<<<dim3((D + 3) / 4, B * N), 128, 0, stream>>>(hidden.data_ptr<float>(), edge_mask.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D, H);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_prof2', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__()\n self.dim = dim; self.pair_dim = pair_dim\n self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim))\n self.out_norm = nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← profile_kernel (ok)
okprofile_kernel profile_kernel PASSED: profiling complete. === Kernel Profile Summary === --- Kernel Breakdown (by GPU time) --- #1: aten::empty 2773.0μs (98%) calls=1 #2: aten::empty_like 25.0μs (1%) calls=1 #3: aten::empty 13.0μs (0%) calls=1 #4: aten::empty_strided 12.0μs (0%) calls=1 --- Timing --- GPU time: 411.30 μs --- Memory Bandwidth --- DRAM BW: 30.3/3350 GB/s (0.9%) read=30.3 write=0.0 GB/s Hit rates: L2=288.6% --- Compute Throughput --- Dominant pipe: FP32 util=7.4% Pipe util: FMA=7.4%, Tensor=0.0% --- Roofline Analysis --- Ridge point (FP32): 20.00 FLOPs/byte Classification: COMPUTE-BOUND --- Occupancy --- Achieved: 142.8% Eligible warps/cycle: 0.55 WARNING: <1 eligible warp/cycle = latency-bound, needs more parallelism Launch: regs/thread=84, smem/blk=4096B, block=512, grid=4704 --- Memory Access Quality --- Global ld coalescing: 32.92 sectors/req (32.9x wasted BW) --- Warp Stall Reasons (% of issue cycles) --- long_scoreboard 9080.2% #################### mio_throttle 1173.9% #################### short_scoreboard 406.3% #################### --- Optimization Hints --- -> 9080% stalls: global memory latency (waiting for DRAM/L2). + sectors/req=32.9 -> uncoalesced global loads, restructure access pattern or use __ldg Try shared-memory tiling, prefetching, or reducing working set. -> Global load coalescing=32.9x (ideal=1.0) -> 33x wasted DRAM BW. Make per-warp accesses contiguous. -> Low eligible warps + low BW% + low compute% = LATENCY-BOUND. Need more parallelism (larger grid, more ILP, prefetching). -> Compute-bound but NOT using tensor cores. If applicable, use FP16/BF16 with torch.matmul or WMMA intrinsics.
turn 6 · 1 tool call(s) · 25.8s turn · 25.8s LLM · 8,081 chars (click to expand)
turn 625.8s turn · 25.8s LLM · 0.0s tools
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void pre_node_kernel(const float* __restrict__ nodes,\n const float* __restrict__ w1,\n float* __restrict__ pre_i,\n float* __restrict__ pre_j,\n int rows, int D, int P, int H) {\n int row = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n const float* n = nodes + row * D;\n const float* wi = w1 + h * (2 * D + P);\n float ai = 0.0f, aj = 0.0f;\n #pragma unroll 4\n for (int k = 0; k < D; ++k) {\n float x = n[k];\n ai = fmaf(x, wi[k], ai);\n aj = fmaf(x, wi[D + k], aj);\n }\n pre_i[row * H + h] = ai;\n pre_j[row * H + h] = aj;\n}\n\n__global__ void hidden_pair_kernel(const float* __restrict__ pair_feats,\n const float* __restrict__ w1,\n const float* __restrict__ b1,\n const float* __restrict__ pre_i,\n const float* __restrict__ pre_j,\n float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n int row_i = b * N + i;\n int row_j = b * N + j;\n const float* wi = w1 + h * (2 * D + P) + 2 * D;\n float acc = b1[h] + pre_i[row_i * H + h] + pre_j[row_j * H + h];\n const float* pf = pair_feats + pair * P;\n #pragma unroll\n for (int k = 0; k < 16; ++k) {\n if (k < P) acc = fmaf(pf[k], wi[k], acc);\n }\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_max(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));\n return v;\n}\n\n__global__ void pooled_kernel(const float* __restrict__ hidden,\n const float* __restrict__ edge_mask,\n const float* __restrict__ w2,\n const float* __restrict__ b2,\n float* __restrict__ pooled,\n int B, int N, int D, int H) {\n int row = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 4 + warp;\n if (d >= D) return;\n float val = -FLT_MAX;\n if (lane < N) {\n float m = edge_mask[row * N + lane];\n if (m >= 0.5f) {\n int pair = row * N + lane;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float acc = b2[d];\n #pragma unroll 4\n for (int h = 0; h < H; ++h) acc = fmaf(hp[h], wd[h], acc);\n val = acc;\n }\n }\n val = warp_max(val);\n if (lane == 0) pooled[row * D + d] = val;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pooled,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ out,\n int rows, int D) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d]; sum += x; sumsq = fmaf(x, x, sumsq);\n }\n __shared__ float smem[256];\n smem[tid] = sum; smem[tid + blockDim.x] = sumsq;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) { smem[tid] += smem[tid + s]; smem[tid + blockDim.x] += smem[tid + blockDim.x + s]; }\n __syncthreads();\n }\n float mean = smem[0] / (float)D;\n float var = smem[blockDim.x] / (float)D - mean * mean;\n float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d];\n out[row * D + d] = nodes[row * D + d] + (x - mean) * inv * gamma[d] + beta[d];\n }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0);\n auto opts = nodes.options();\n auto pre_i = torch::empty({B, N, H}, opts);\n auto pre_j = torch::empty({B, N, H}, opts);\n auto hidden = torch::empty({B, N, N, H}, opts);\n auto pooled = torch::empty({B, N, D}, opts);\n auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n pre_node_kernel<<<B*N, 256, 0, stream>>>(nodes.data_ptr<float>(), w1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), B*N, D, P, H);\n hidden_pair_kernel<<<B*N*N, 256, 0, stream>>>(pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n pooled_kernel<<<dim3((D + 3) / 4, B * N), 128, 0, stream>>>(hidden.data_ptr<float>(), edge_mask.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D, H);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_v3', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__()\n self.dim = dim; self.pair_dim = pair_dim\n self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim))\n self.out_norm = nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=3.22e-06 mean_abs_err=4.72e-07 max_rel_err=9.66e-03
turn 7 · 1 tool call(s) · 13.9s turn · 13.9s LLM · 8,182 chars (click to expand)
turn 713.9s turn · 13.9s LLM · 0.0s tools
call → profile_kernel
callprofile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void pre_node_kernel(const float* __restrict__ nodes,\n const float* __restrict__ w1,\n float* __restrict__ pre_i,\n float* __restrict__ pre_j,\n int rows, int D, int P, int H) {\n int row = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n const float* n = nodes + row * D;\n const float* wi = w1 + h * (2 * D + P);\n float ai = 0.0f, aj = 0.0f;\n #pragma unroll 4\n for (int k = 0; k < D; ++k) { float x = n[k]; ai = fmaf(x, wi[k], ai); aj = fmaf(x, wi[D + k], aj); }\n pre_i[row * H + h] = ai;\n pre_j[row * H + h] = aj;\n}\n\n__global__ void hidden_pair_kernel(const float* __restrict__ pair_feats,\n const float* __restrict__ w1,\n const float* __restrict__ b1,\n const float* __restrict__ pre_i,\n const float* __restrict__ pre_j,\n float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n int row_i = b * N + i;\n int row_j = b * N + j;\n const float* wi = w1 + h * (2 * D + P) + 2 * D;\n float acc = b1[h] + pre_i[row_i * H + h] + pre_j[row_j * H + h];\n const float* pf = pair_feats + pair * P;\n #pragma unroll\n for (int k = 0; k < 16; ++k) { if (k < P) acc = fmaf(pf[k], wi[k], acc); }\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_max(float v) { #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset)); return v; }\n\n__global__ void pooled_kernel(const float* __restrict__ hidden,\n const float* __restrict__ edge_mask,\n const float* __restrict__ w2,\n const float* __restrict__ b2,\n float* __restrict__ pooled,\n int B, int N, int D, int H) {\n int row = blockIdx.y; int warp = threadIdx.x >> 5; int lane = threadIdx.x & 31; int d = blockIdx.x * 4 + warp; if (d >= D) return;\n float val = -FLT_MAX;\n if (lane < N) { float m = edge_mask[row * N + lane]; if (m >= 0.5f) { int pair = row * N + lane; const float* hp = hidden + pair * H; const float* wd = w2 + d * H; float acc = b2[d];\n #pragma unroll 4\n for (int h = 0; h < H; ++h) acc = fmaf(hp[h], wd[h], acc); val = acc; } }\n val = warp_max(val); if (lane == 0) pooled[row * D + d] = val;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes,\n const float* __restrict__ pooled,\n const float* __restrict__ gamma,\n const float* __restrict__ beta,\n float* __restrict__ out,\n int rows, int D) {\n int row = blockIdx.x; int tid = threadIdx.x; float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) { float x = pooled[row * D + d]; sum += x; sumsq = fmaf(x, x, sumsq); }\n __shared__ float smem[256]; smem[tid] = sum; smem[tid + blockDim.x] = sumsq; __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) { if (tid < s) { smem[tid] += smem[tid + s]; smem[tid + blockDim.x] += smem[tid + blockDim.x + s]; } __syncthreads(); }\n float mean = smem[0] / (float)D; float var = smem[blockDim.x] / (float)D - mean * mean; float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) { float x = pooled[row * D + d]; out[row * D + d] = nodes[row * D + d] + (x - mean) * inv * gamma[d] + beta[d]; }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0); auto opts = nodes.options();\n auto pre_i = torch::empty({B, N, H}, opts); auto pre_j = torch::empty({B, N, H}, opts); auto hidden = torch::empty({B, N, N, H}, opts); auto pooled = torch::empty({B, N, D}, opts); auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n pre_node_kernel<<<B*N, 256, 0, stream>>>(nodes.data_ptr<float>(), w1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), B*N, D, P, H);\n hidden_pair_kernel<<<B*N*N, 256, 0, stream>>>(pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n pooled_kernel<<<dim3((D + 3) / 4, B * N), 128, 0, stream>>>(hidden.data_ptr<float>(), edge_mask.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D, H);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_v3p', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__(); self.dim = dim; self.pair_dim = pair_dim; self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim)); self.out_norm = nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← profile_kernel (fail)
failprofile_kernel profile_kernel FAILED: worker exited with code 1. ner/KernelBench/runs/l12_all_gpt/popcorn/gpt-5.5-priority/level_2_problem_10_cache/k_ff06ec961a56/gf_vla_fused_ext_v3p/cuda.cu(53): error: expected an expression float warp_max(float v) { #pragma unroll ^ 2 errors detected in the compilation of "/scratch/abaner/KernelBench/runs/l12_all_gpt/popcorn/gpt-5.5-priority/level_2_problem_10_cache/k_ff06ec961a56/gf_vla_fused_ext_v3p/cuda.cu". ninja: build stopped: subcommand failed.
turn 8 · 1 tool call(s) · 20.4s turn · 20.4s LLM · 8,460 chars (click to expand)
turn 820.4s turn · 20.4s LLM · 0.0s tools
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void pre_node_kernel(const float* __restrict__ nodes, const float* __restrict__ w1,\n float* __restrict__ pre_i, float* __restrict__ pre_j,\n int rows, int D, int P, int H) {\n int row = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n const float* n = nodes + row * D;\n const float* wi = w1 + h * (2 * D + P);\n float ai = 0.0f, aj = 0.0f;\n #pragma unroll 4\n for (int k = 0; k < D; ++k) {\n float x = n[k]; ai = fmaf(x, wi[k], ai); aj = fmaf(x, wi[D + k], aj);\n }\n pre_i[row * H + h] = ai;\n pre_j[row * H + h] = aj;\n}\n\n__global__ void hidden_pair_kernel(const float* __restrict__ pair_feats, const float* __restrict__ w1,\n const float* __restrict__ b1, const float* __restrict__ pre_i,\n const float* __restrict__ pre_j, float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n int row_i = b * N + i;\n int row_j = b * N + j;\n const float* wi = w1 + h * (2 * D + P) + 2 * D;\n float acc = b1[h] + pre_i[row_i * H + h] + pre_j[row_j * H + h];\n const float* pf = pair_feats + pair * P;\n #pragma unroll\n for (int k = 0; k < 16; ++k) { if (k < P) acc = fmaf(pf[k], wi[k], acc); }\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n__inline__ __device__ float warp_max(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));\n return v;\n}\n\n__global__ void second_pair_kernel(const float* __restrict__ hidden, const float* __restrict__ w2,\n const float* __restrict__ b2, float* __restrict__ pair_out,\n int total_pairs, int D, int H) {\n int pair = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 8 + warp;\n if (d >= D) return;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float sum = 0.0f;\n for (int h = lane; h < H; h += 32) sum = fmaf(hp[h], wd[h], sum);\n sum = warp_sum(sum);\n if (lane == 0) pair_out[pair * D + d] = sum + b2[d];\n}\n\n__global__ void reduce_pool_kernel(const float* __restrict__ pair_out, const float* __restrict__ edge_mask,\n float* __restrict__ pooled, int B, int N, int D) {\n int row = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 4 + warp;\n if (d >= D) return;\n float v = -FLT_MAX;\n if (lane < N && edge_mask[row * N + lane] >= 0.5f) {\n int pair = row * N + lane;\n v = pair_out[pair * D + d];\n }\n v = warp_max(v);\n if (lane == 0) pooled[row * D + d] = v;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes, const float* __restrict__ pooled,\n const float* __restrict__ gamma, const float* __restrict__ beta,\n float* __restrict__ out, int rows, int D) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) { float x = pooled[row * D + d]; sum += x; sumsq = fmaf(x, x, sumsq); }\n __shared__ float smem[256];\n smem[tid] = sum; smem[tid + blockDim.x] = sumsq;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) { smem[tid] += smem[tid + s]; smem[tid + blockDim.x] += smem[tid + blockDim.x + s]; }\n __syncthreads();\n }\n float mean = smem[0] / (float)D;\n float var = smem[blockDim.x] / (float)D - mean * mean;\n float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d]; out[row * D + d] = nodes[row * D + d] + (x - mean) * inv * gamma[d] + beta[d];\n }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0);\n auto opts = nodes.options();\n auto pre_i = torch::empty({B, N, H}, opts);\n auto pre_j = torch::empty({B, N, H}, opts);\n auto hidden = torch::empty({B, N, N, H}, opts);\n auto pair_out = torch::empty({B, N, N, D}, opts);\n auto pooled = torch::empty({B, N, D}, opts);\n auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n int total_pairs = B * N * N;\n pre_node_kernel<<<B*N, 256, 0, stream>>>(nodes.data_ptr<float>(), w1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), B*N, D, P, H);\n hidden_pair_kernel<<<total_pairs, 256, 0, stream>>>(pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n second_pair_kernel<<<dim3((D + 7) / 8, total_pairs), 256, 0, stream>>>(hidden.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pair_out.data_ptr<float>(), total_pairs, D, H);\n reduce_pool_kernel<<<dim3((D + 3) / 4, B * N), 128, 0, stream>>>(pair_out.data_ptr<float>(), edge_mask.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_v4', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__(); self.dim = dim; self.pair_dim = pair_dim\n self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim)); self.out_norm = nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.17e-06 mean_abs_err=4.75e-07 max_rel_err=1.69e-02
turn 9 · 1 tool call(s) · 14.6s turn · 14.6s LLM · 10,319 chars (click to expand)
turn 914.6s turn · 14.6s LLM · 0.0s tools
call → profile_kernel
callprofile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void pre_node_kernel(const float* __restrict__ nodes, const float* __restrict__ w1,\n float* __restrict__ pre_i, float* __restrict__ pre_j,\n int rows, int D, int P, int H) {\n int row = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n const float* n = nodes + row * D;\n const float* wi = w1 + h * (2 * D + P);\n float ai = 0.0f, aj = 0.0f;\n #pragma unroll 4\n for (int k = 0; k < D; ++k) {\n float x = n[k]; ai = fmaf(x, wi[k], ai); aj = fmaf(x, wi[D + k], aj);\n }\n pre_i[row * H + h] = ai;\n pre_j[row * H + h] = aj;\n}\n\n__global__ void hidden_pair_kernel(const float* __restrict__ pair_feats, const float* __restrict__ w1,\n const float* __restrict__ b1, const float* __restrict__ pre_i,\n const float* __restrict__ pre_j, float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n int row_i = b * N + i;\n int row_j = b * N + j;\n const float* wi = w1 + h * (2 * D + P) + 2 * D;\n float acc = b1[h] + pre_i[row_i * H + h] + pre_j[row_j * H + h];\n const float* pf = pair_feats + pair * P;\n #pragma unroll\n for (int k = 0; k < 16; ++k) { if (k < P) acc = fmaf(pf[k], wi[k], acc); }\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n__inline__ __device__ float warp_max(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));\n return v;\n}\n\n__global__ void second_pair_kernel(const float* __restrict__ hidden, const float* __restrict__ w2,\n const float* __restrict__ b2, float* __restrict__ pair_out,\n int total_pairs, int D, int H) {\n int pair = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 8 + warp;\n if (d >= D) return;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float sum = 0.0f;\n for (int h = lane; h < H; h += 32) sum = fmaf(hp[h], wd[h], sum);\n sum = warp_sum(sum);\n if (lane == 0) pair_out[pair * D + d] = sum + b2[d];\n}\n\n__global__ void reduce_pool_kernel(const float* __restrict__ pair_out, const float* __restrict__ edge_mask,\n float* __restrict__ pooled, int B, int N, int D) {\n int row = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 4 + warp;\n if (d >= D) return;\n float v = -FLT_MAX;\n if (lane < N && edge_mask[row * N + lane] >= 0.5f) {\n int pair = row * N + lane;\n v = pair_out[pair * D + d];\n }\n v = warp_max(v);\n if (lane == 0) pooled[row * D + d] = v;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes, const float* __restrict__ pooled,\n const float* __restrict__ gamma, const float* __restrict__ beta,\n float* __restrict__ out, int rows, int D) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) { float x = pooled[row * D + d]; sum += x; sumsq = fmaf(x, x, sumsq); }\n __shared__ float smem[256];\n smem[tid] = sum; smem[tid + blockDim.x] = sumsq;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) { smem[tid] += smem[tid + s]; smem[tid + blockDim.x] += smem[tid + blockDim.x + s]; }\n __syncthreads();\n }\n float mean = smem[0] / (float)D;\n float var = smem[blockDim.x] / (float)D - mean * mean;\n float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d]; out[row * D + d] = nodes[row * D + d] + (x - mean) * inv * gamma[d] + beta[d];\n }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0);\n auto opts = nodes.options();\n auto pre_i = torch::empty({B, N, H}, opts);\n auto pre_j = torch::empty({B, N, H}, opts);\n auto hidden = torch::empty({B, N, N, H}, opts);\n auto pair_out = torch::empty({B, N, N, D}, opts);\n auto pooled = torch::empty({B, N, D}, opts);\n auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n int total_pairs = B * N * N;\n pre_node_kernel<<<B*N, 256, 0, stream>>>(nodes.data_ptr<float>(), w1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), B*N, D, P, H);\n hidden_pair_kernel<<<total_pairs, 256, 0, stream>>>(pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n second_pair_kernel<<<dim3((D + 7) / 8, total_pairs), 256, 0, stream>>>(hidden.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pair_out.data_ptr<float>(), total_pairs, D, H);\n reduce_pool_kernel<<<dim3((D + 3) / 4, B * N), 128, 0, stream>>>(pair_out.data_ptr<float>(), edge_mask.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_v4p2', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__(); self.dim = dim; self.pair_dim = pair_dim\n self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim)); self.out_norm = nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← profile_kernel (ok)
okprofile_kernel profile_kernel PASSED: profiling complete. === Kernel Profile Summary === --- Kernel Breakdown (by GPU time) --- #1: aten::empty 54183.0μs (100%) calls=1 #2: aten::empty 61.0μs (0%) calls=1 #3: aten::empty_like 24.0μs (0%) calls=1 #4: aten::empty_strided 13.0μs (0%) calls=1 #5: aten::empty 11.0μs (0%) calls=1 ... +2 more kernels --- Timing --- GPU time: 89.98 μs [↓321.3μs ok] --- Memory Bandwidth --- DRAM BW: 267.2/3350 GB/s (8.0%) [↑7.1% ok] read=267.2 write=0.0 GB/s Hit rates: L2=447.0% --- Compute Throughput --- Dominant pipe: FP32 util=28.1% [↑20.7% ok] Pipe util: FMA=28.1%, Tensor=1.2% --- Roofline Analysis --- Ridge point (FP32): 20.00 FLOPs/byte Classification: COMPUTE-BOUND --- Occupancy --- Achieved: 241.2% [↑98.4% ok] Eligible warps/cycle: 2.89 Launch: regs/thread=132, smem/blk=6144B, block=1024, grid=32448 --- Memory Access Quality --- Global ld coalescing: 58.36 sectors/req (58.4x wasted BW) --- Warp Stall Reasons (% of issue cycles) --- long_scoreboard 10746.6% #################### mio_throttle 1237.4% #################### short_scoreboard 1066.6% #################### --- Optimization Hints --- -> 10747% stalls: global memory latency (waiting for DRAM/L2). + sectors/req=58.4 -> uncoalesced global loads, restructure access pattern or use __ldg Try shared-memory tiling, prefetching, or reducing working set. -> Global load coalescing=58.4x (ideal=1.0) -> 58x wasted DRAM BW. Make per-warp accesses contiguous. -> Compute-bound but NOT using tensor cores. If applicable, use FP16/BF16 with torch.matmul or WMMA intrinsics. --- Delta vs Previous Iteration --- GPU time: 411.30→89.98μs (↓321.31) ok DRAM BW%: 0.90→7.98% (↑7.07) ok Compute%: 7.38→28.06% (↑20.68) ok Occupancy: 142.75→241.15% (↑98.40) ok Eligible warps/cyc: 0.55→2.89 (↑2.34) ok Ld sectors/req: 32.92→58.36 (↑25.45) REGRESSED L2 hit%: 288.64→446.98% (↑158.34) ok
turn 10 · 1 tool call(s) · 24.0s turn · 24.0s LLM · 7,548 chars (click to expand)
turn 1024.0s turn · 24.0s LLM · 0.0s tools
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void pre_node_kernel(const float* __restrict__ nodes, const float* __restrict__ w1,\n float* __restrict__ pre_i, float* __restrict__ pre_j,\n int rows, int D, int P, int H) {\n int row = blockIdx.x, h = threadIdx.x;\n if (h >= H) return;\n const float* n = nodes + row * D;\n const float* wi = w1 + h * (2 * D + P);\n float ai = 0.0f, aj = 0.0f;\n #pragma unroll 4\n for (int k = 0; k < D; ++k) { float x = n[k]; ai = fmaf(x, wi[k], ai); aj = fmaf(x, wi[D+k], aj); }\n pre_i[row * H + h] = ai; pre_j[row * H + h] = aj;\n}\n\n__global__ void hidden_pair_kernel(const float* __restrict__ pair_feats, const float* __restrict__ w1,\n const float* __restrict__ b1, const float* __restrict__ pre_i,\n const float* __restrict__ pre_j, float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x, h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N; int tmp = pair / N; int i = tmp % N; int b = tmp / N;\n float acc = b1[h] + pre_i[(b*N+i)*H + h] + pre_j[(b*N+j)*H + h];\n const float* wi = w1 + h * (2 * D + P) + 2 * D;\n const float* pf = pair_feats + pair * P;\n #pragma unroll\n for (int k = 0; k < 16; ++k) { if (k < P) acc = fmaf(pf[k], wi[k], acc); }\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n\n__global__ void dotmax_kernel(const float* __restrict__ hidden, const float* __restrict__ edge_mask,\n const float* __restrict__ w2, const float* __restrict__ b2,\n float* __restrict__ pooled, int B, int N, int D, int H) {\n int row = blockIdx.y;\n int d = blockIdx.x;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n __shared__ float vals[32];\n float val = -FLT_MAX;\n if (warp < N) {\n int j = warp;\n if (edge_mask[row * N + j] >= 0.5f) {\n int pair = row * N + j;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float sum = 0.0f;\n for (int h = lane; h < H; h += 32) sum = fmaf(hp[h], wd[h], sum);\n sum = warp_sum(sum);\n if (lane == 0) val = sum + b2[d];\n }\n }\n if (lane == 0) vals[warp] = val;\n __syncthreads();\n if (threadIdx.x < 32) {\n float m = (threadIdx.x < N) ? vals[threadIdx.x] : -FLT_MAX;\n #pragma unroll\n for (int off = 16; off > 0; off >>= 1) m = fmaxf(m, __shfl_down_sync(0xffffffff, m, off));\n if (threadIdx.x == 0) pooled[row * D + d] = m;\n }\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes, const float* __restrict__ pooled,\n const float* __restrict__ gamma, const float* __restrict__ beta,\n float* __restrict__ out, int rows, int D) {\n int row = blockIdx.x, tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) { float x = pooled[row*D+d]; sum += x; sumsq = fmaf(x,x,sumsq); }\n __shared__ float smem[256]; smem[tid]=sum; smem[tid+blockDim.x]=sumsq; __syncthreads();\n for (int s=blockDim.x>>1; s>0; s>>=1) { if (tid<s) { smem[tid]+=smem[tid+s]; smem[tid+blockDim.x]+=smem[tid+blockDim.x+s]; } __syncthreads(); }\n float mean=smem[0]/(float)D; float var=smem[blockDim.x]/(float)D - mean*mean; float inv=rsqrtf(var+1.0e-5f);\n for (int d=tid; d<D; d+=blockDim.x) { float x=pooled[row*D+d]; out[row*D+d]=nodes[row*D+d]+(x-mean)*inv*gamma[d]+beta[d]; }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B=nodes.size(0), N=nodes.size(1), D=nodes.size(2), P=pair_feats.size(3), H=w1.size(0);\n auto opts=nodes.options();\n auto pre_i=torch::empty({B,N,H},opts); auto pre_j=torch::empty({B,N,H},opts); auto hidden=torch::empty({B,N,N,H},opts); auto pooled=torch::empty({B,N,D},opts); auto out=torch::empty_like(nodes);\n cudaStream_t stream=at::cuda::getCurrentCUDAStream();\n pre_node_kernel<<<B*N,256,0,stream>>>(nodes.data_ptr<float>(),w1.data_ptr<float>(),pre_i.data_ptr<float>(),pre_j.data_ptr<float>(),B*N,D,P,H);\n hidden_pair_kernel<<<B*N*N,256,0,stream>>>(pair_feats.data_ptr<float>(),w1.data_ptr<float>(),b1.data_ptr<float>(),pre_i.data_ptr<float>(),pre_j.data_ptr<float>(),hidden.data_ptr<float>(),B,N,D,P,H);\n dotmax_kernel<<<dim3(D,B*N),768,0,stream>>>(hidden.data_ptr<float>(),edge_mask.data_ptr<float>(),w2.data_ptr<float>(),b2.data_ptr<float>(),pooled.data_ptr<float>(),B,N,D,H);\n layernorm_kernel<<<B*N,128,0,stream>>>(nodes.data_ptr<float>(),pooled.data_ptr<float>(),gamma.data_ptr<float>(),beta.data_ptr<float>(),out.data_ptr<float>(),B*N,D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_v5', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__(); self.dim=dim; self.pair_dim=pair_dim\n self.fuse=nn.Sequential(nn.Linear(2*dim+pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim)); self.out_norm=nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes,pair_feats,edge_mask,self.fuse[0].weight,self.fuse[0].bias,self.fuse[2].weight,self.fuse[2].bias,self.out_norm.weight,self.out_norm.bias)\n" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=4.17e-06 mean_abs_err=4.75e-07 max_rel_err=1.69e-02
turn 11 · 1 tool call(s) · 12.2s turn · 12.2s LLM · 9,456 chars (click to expand)
turn 1112.2s turn · 12.2s LLM · 0.0s tools
call → profile_kernel
callprofile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void pre_node_kernel(const float* __restrict__ nodes, const float* __restrict__ w1,\n float* __restrict__ pre_i, float* __restrict__ pre_j,\n int rows, int D, int P, int H) {\n int row = blockIdx.x, h = threadIdx.x;\n if (h >= H) return;\n const float* n = nodes + row * D;\n const float* wi = w1 + h * (2 * D + P);\n float ai = 0.0f, aj = 0.0f;\n #pragma unroll 4\n for (int k = 0; k < D; ++k) { float x = n[k]; ai = fmaf(x, wi[k], ai); aj = fmaf(x, wi[D+k], aj); }\n pre_i[row * H + h] = ai; pre_j[row * H + h] = aj;\n}\n\n__global__ void hidden_pair_kernel(const float* __restrict__ pair_feats, const float* __restrict__ w1,\n const float* __restrict__ b1, const float* __restrict__ pre_i,\n const float* __restrict__ pre_j, float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x, h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N; int tmp = pair / N; int i = tmp % N; int b = tmp / N;\n float acc = b1[h] + pre_i[(b*N+i)*H + h] + pre_j[(b*N+j)*H + h];\n const float* wi = w1 + h * (2 * D + P) + 2 * D;\n const float* pf = pair_feats + pair * P;\n #pragma unroll\n for (int k = 0; k < 16; ++k) { if (k < P) acc = fmaf(pf[k], wi[k], acc); }\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n\n__global__ void dotmax_kernel(const float* __restrict__ hidden, const float* __restrict__ edge_mask,\n const float* __restrict__ w2, const float* __restrict__ b2,\n float* __restrict__ pooled, int B, int N, int D, int H) {\n int row = blockIdx.y;\n int d = blockIdx.x;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n __shared__ float vals[32];\n float val = -FLT_MAX;\n if (warp < N) {\n int j = warp;\n if (edge_mask[row * N + j] >= 0.5f) {\n int pair = row * N + j;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float sum = 0.0f;\n for (int h = lane; h < H; h += 32) sum = fmaf(hp[h], wd[h], sum);\n sum = warp_sum(sum);\n if (lane == 0) val = sum + b2[d];\n }\n }\n if (lane == 0) vals[warp] = val;\n __syncthreads();\n if (threadIdx.x < 32) {\n float m = (threadIdx.x < N) ? vals[threadIdx.x] : -FLT_MAX;\n #pragma unroll\n for (int off = 16; off > 0; off >>= 1) m = fmaxf(m, __shfl_down_sync(0xffffffff, m, off));\n if (threadIdx.x == 0) pooled[row * D + d] = m;\n }\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes, const float* __restrict__ pooled,\n const float* __restrict__ gamma, const float* __restrict__ beta,\n float* __restrict__ out, int rows, int D) {\n int row = blockIdx.x, tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) { float x = pooled[row*D+d]; sum += x; sumsq = fmaf(x,x,sumsq); }\n __shared__ float smem[256]; smem[tid]=sum; smem[tid+blockDim.x]=sumsq; __syncthreads();\n for (int s=blockDim.x>>1; s>0; s>>=1) { if (tid<s) { smem[tid]+=smem[tid+s]; smem[tid+blockDim.x]+=smem[tid+blockDim.x+s]; } __syncthreads(); }\n float mean=smem[0]/(float)D; float var=smem[blockDim.x]/(float)D - mean*mean; float inv=rsqrtf(var+1.0e-5f);\n for (int d=tid; d<D; d+=blockDim.x) { float x=pooled[row*D+d]; out[row*D+d]=nodes[row*D+d]+(x-mean)*inv*gamma[d]+beta[d]; }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B=nodes.size(0), N=nodes.size(1), D=nodes.size(2), P=pair_feats.size(3), H=w1.size(0);\n auto opts=nodes.options();\n auto pre_i=torch::empty({B,N,H},opts); auto pre_j=torch::empty({B,N,H},opts); auto hidden=torch::empty({B,N,N,H},opts); auto pooled=torch::empty({B,N,D},opts); auto out=torch::empty_like(nodes);\n cudaStream_t stream=at::cuda::getCurrentCUDAStream();\n pre_node_kernel<<<B*N,256,0,stream>>>(nodes.data_ptr<float>(),w1.data_ptr<float>(),pre_i.data_ptr<float>(),pre_j.data_ptr<float>(),B*N,D,P,H);\n hidden_pair_kernel<<<B*N*N,256,0,stream>>>(pair_feats.data_ptr<float>(),w1.data_ptr<float>(),b1.data_ptr<float>(),pre_i.data_ptr<float>(),pre_j.data_ptr<float>(),hidden.data_ptr<float>(),B,N,D,P,H);\n dotmax_kernel<<<dim3(D,B*N),768,0,stream>>>(hidden.data_ptr<float>(),edge_mask.data_ptr<float>(),w2.data_ptr<float>(),b2.data_ptr<float>(),pooled.data_ptr<float>(),B,N,D,H);\n layernorm_kernel<<<B*N,128,0,stream>>>(nodes.data_ptr<float>(),pooled.data_ptr<float>(),gamma.data_ptr<float>(),beta.data_ptr<float>(),out.data_ptr<float>(),B*N,D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_v5p', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__(); self.dim=dim; self.pair_dim=pair_dim\n self.fuse=nn.Sequential(nn.Linear(2*dim+pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim)); self.out_norm=nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes,pair_feats,edge_mask,self.fuse[0].weight,self.fuse[0].bias,self.fuse[2].weight,self.fuse[2].bias,self.out_norm.weight,self.out_norm.bias)\n" }
result ← profile_kernel (ok)
okprofile_kernel profile_kernel PASSED: profiling complete. === Kernel Profile Summary === --- Kernel Breakdown (by GPU time) --- #1: aten::empty 2167.0μs (97%) calls=1 #2: aten::empty 29.0μs (1%) calls=1 #3: aten::empty_like 18.0μs (1%) calls=1 #4: aten::empty 8.0μs (0%) calls=1 #5: aten::empty_strided 8.0μs (0%) calls=1 ... +1 more kernels --- Timing --- GPU time: 115.14 μs [↑25.2μs REGRESSED] --- Memory Bandwidth --- DRAM BW: 71.8/3350 GB/s (2.1%) [↓5.8% REGRESSED] read=71.8 write=0.0 GB/s Hit rates: L2=385.1% --- Compute Throughput --- Dominant pipe: FP32 util=19.8% [↓8.2% REGRESSED] Pipe util: FMA=19.8%, Tensor=0.8% --- Roofline Analysis --- Ridge point (FP32): 20.00 FLOPs/byte Classification: COMPUTE-BOUND --- Occupancy --- Achieved: 149.2% [↓92.0% REGRESSED] Eligible warps/cycle: 1.70 Launch: regs/thread=117, smem/blk=5248B, block=1408, grid=11712 --- Memory Access Quality --- Global ld coalescing: 44.67 sectors/req (44.7x wasted BW) --- Warp Stall Reasons (% of issue cycles) --- long_scoreboard 5930.8% #################### mio_throttle 862.9% #################### short_scoreboard 594.0% #################### --- Optimization Hints --- -> 5931% stalls: global memory latency (waiting for DRAM/L2). + sectors/req=44.7 -> uncoalesced global loads, restructure access pattern or use __ldg Try shared-memory tiling, prefetching, or reducing working set. -> Global load coalescing=44.7x (ideal=1.0) -> 45x wasted DRAM BW. Make per-warp accesses contiguous. -> Compute-bound but NOT using tensor cores. If applicable, use FP16/BF16 with torch.matmul or WMMA intrinsics. --- Delta vs Previous Iteration --- GPU time: 89.98→115.14μs (↑25.15) REGRESSED DRAM BW%: 7.98→2.14% (↓5.83) REGRESSED Compute%: 28.06→19.85% (↓8.22) REGRESSED Occupancy: 241.15→149.16% (↓92.00) REGRESSED Eligible warps/cyc: 2.89→1.70 (↓1.19) REGRESSED Ld sectors/req: 58.36→44.67 (↓13.70) ok L2 hit%: 446.98→385.12% (↓61.86) REGRESSED
turn 12 · 1 tool call(s) · 20.4s turn · 20.4s LLM · 8,910 chars (click to expand)
turn 1220.4s turn · 20.4s LLM · 0.0s tools
reasoning
**Preparing final submission** I need to finalize the submission and choose v4 for its speed, aiming for 90us. It seems necessary to include a static check and submit the full code. I might optimize the final version with a unique name. Should I prioritize the static check first? There are still 38 tools remaining, which is okay. I'll ensure that using the v4 code doesn't lead to any unexpected profile compile issues while performing the static check.
call → static_check
callstatic_check { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void pre_node_kernel(const float* __restrict__ nodes, const float* __restrict__ w1,\n float* __restrict__ pre_i, float* __restrict__ pre_j,\n int rows, int D, int P, int H) {\n int row = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n const float* n = nodes + row * D;\n const float* wi = w1 + h * (2 * D + P);\n float ai = 0.0f, aj = 0.0f;\n #pragma unroll 4\n for (int k = 0; k < D; ++k) {\n float x = n[k]; ai = fmaf(x, wi[k], ai); aj = fmaf(x, wi[D + k], aj);\n }\n pre_i[row * H + h] = ai;\n pre_j[row * H + h] = aj;\n}\n\n__global__ void hidden_pair_kernel(const float* __restrict__ pair_feats, const float* __restrict__ w1,\n const float* __restrict__ b1, const float* __restrict__ pre_i,\n const float* __restrict__ pre_j, float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n int row_i = b * N + i;\n int row_j = b * N + j;\n const float* wi = w1 + h * (2 * D + P) + 2 * D;\n float acc = b1[h] + pre_i[row_i * H + h] + pre_j[row_j * H + h];\n const float* pf = pair_feats + pair * P;\n #pragma unroll\n for (int k = 0; k < 16; ++k) { if (k < P) acc = fmaf(pf[k], wi[k], acc); }\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n__inline__ __device__ float warp_max(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));\n return v;\n}\n\n__global__ void second_pair_kernel(const float* __restrict__ hidden, const float* __restrict__ w2,\n const float* __restrict__ b2, float* __restrict__ pair_out,\n int total_pairs, int D, int H) {\n int pair = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 8 + warp;\n if (d >= D) return;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float sum = 0.0f;\n for (int h = lane; h < H; h += 32) sum = fmaf(hp[h], wd[h], sum);\n sum = warp_sum(sum);\n if (lane == 0) pair_out[pair * D + d] = sum + b2[d];\n}\n\n__global__ void reduce_pool_kernel(const float* __restrict__ pair_out, const float* __restrict__ edge_mask,\n float* __restrict__ pooled, int B, int N, int D) {\n int row = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 4 + warp;\n if (d >= D) return;\n float v = -FLT_MAX;\n if (lane < N && edge_mask[row * N + lane] >= 0.5f) {\n int pair = row * N + lane;\n v = pair_out[pair * D + d];\n }\n v = warp_max(v);\n if (lane == 0) pooled[row * D + d] = v;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes, const float* __restrict__ pooled,\n const float* __restrict__ gamma, const float* __restrict__ beta,\n float* __restrict__ out, int rows, int D) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) { float x = pooled[row * D + d]; sum += x; sumsq = fmaf(x, x, sumsq); }\n __shared__ float smem[256];\n smem[tid] = sum; smem[tid + blockDim.x] = sumsq;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) { smem[tid] += smem[tid + s]; smem[tid + blockDim.x] += smem[tid + blockDim.x + s]; }\n __syncthreads();\n }\n float mean = smem[0] / (float)D;\n float var = smem[blockDim.x] / (float)D - mean * mean;\n float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d]; out[row * D + d] = nodes[row * D + d] + (x - mean) * inv * gamma[d] + beta[d];\n }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0);\n auto opts = nodes.options();\n auto pre_i = torch::empty({B, N, H}, opts);\n auto pre_j = torch::empty({B, N, H}, opts);\n auto hidden = torch::empty({B, N, N, H}, opts);\n auto pair_out = torch::empty({B, N, N, D}, opts);\n auto pooled = torch::empty({B, N, D}, opts);\n auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n int total_pairs = B * N * N;\n pre_node_kernel<<<B*N, 256, 0, stream>>>(nodes.data_ptr<float>(), w1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), B*N, D, P, H);\n hidden_pair_kernel<<<total_pairs, 256, 0, stream>>>(pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n second_pair_kernel<<<dim3((D + 7) / 8, total_pairs), 256, 0, stream>>>(hidden.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pair_out.data_ptr<float>(), total_pairs, D, H);\n reduce_pool_kernel<<<dim3((D + 3) / 4, B * N), 128, 0, stream>>>(pair_out.data_ptr<float>(), edge_mask.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_final', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__(); self.dim = dim; self.pair_dim = pair_dim\n self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim)); self.out_norm = nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← static_check (ok)
okstatic_check static_check PASSED: no violations or warnings detected.
turn 13 · FINAL · 1 tool call(s) · 14.8s turn · 14.8s LLM · 8,664 chars (click to expand)
turn 1314.8s turn · 14.8s LLM · 0.0s tools · FINAL
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'\n_cuda_src = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <float.h>\n\n__global__ void pre_node_kernel(const float* __restrict__ nodes, const float* __restrict__ w1,\n float* __restrict__ pre_i, float* __restrict__ pre_j,\n int rows, int D, int P, int H) {\n int row = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n const float* n = nodes + row * D;\n const float* wi = w1 + h * (2 * D + P);\n float ai = 0.0f, aj = 0.0f;\n #pragma unroll 4\n for (int k = 0; k < D; ++k) {\n float x = n[k]; ai = fmaf(x, wi[k], ai); aj = fmaf(x, wi[D + k], aj);\n }\n pre_i[row * H + h] = ai;\n pre_j[row * H + h] = aj;\n}\n\n__global__ void hidden_pair_kernel(const float* __restrict__ pair_feats, const float* __restrict__ w1,\n const float* __restrict__ b1, const float* __restrict__ pre_i,\n const float* __restrict__ pre_j, float* __restrict__ hidden,\n int B, int N, int D, int P, int H) {\n int pair = blockIdx.x;\n int h = threadIdx.x;\n if (h >= H) return;\n int j = pair % N;\n int tmp = pair / N;\n int i = tmp % N;\n int b = tmp / N;\n int row_i = b * N + i;\n int row_j = b * N + j;\n const float* wi = w1 + h * (2 * D + P) + 2 * D;\n float acc = b1[h] + pre_i[row_i * H + h] + pre_j[row_j * H + h];\n const float* pf = pair_feats + pair * P;\n #pragma unroll\n for (int k = 0; k < 16; ++k) { if (k < P) acc = fmaf(pf[k], wi[k], acc); }\n float sig = 1.0f / (1.0f + expf(-acc));\n hidden[pair * H + h] = acc * sig;\n}\n\n__inline__ __device__ float warp_sum(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);\n return v;\n}\n__inline__ __device__ float warp_max(float v) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));\n return v;\n}\n\n__global__ void second_pair_kernel(const float* __restrict__ hidden, const float* __restrict__ w2,\n const float* __restrict__ b2, float* __restrict__ pair_out,\n int total_pairs, int D, int H) {\n int pair = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 8 + warp;\n if (d >= D) return;\n const float* hp = hidden + pair * H;\n const float* wd = w2 + d * H;\n float sum = 0.0f;\n for (int h = lane; h < H; h += 32) sum = fmaf(hp[h], wd[h], sum);\n sum = warp_sum(sum);\n if (lane == 0) pair_out[pair * D + d] = sum + b2[d];\n}\n\n__global__ void reduce_pool_kernel(const float* __restrict__ pair_out, const float* __restrict__ edge_mask,\n float* __restrict__ pooled, int B, int N, int D) {\n int row = blockIdx.y;\n int warp = threadIdx.x >> 5;\n int lane = threadIdx.x & 31;\n int d = blockIdx.x * 4 + warp;\n if (d >= D) return;\n float v = -FLT_MAX;\n if (lane < N && edge_mask[row * N + lane] >= 0.5f) {\n int pair = row * N + lane;\n v = pair_out[pair * D + d];\n }\n v = warp_max(v);\n if (lane == 0) pooled[row * D + d] = v;\n}\n\n__global__ void layernorm_kernel(const float* __restrict__ nodes, const float* __restrict__ pooled,\n const float* __restrict__ gamma, const float* __restrict__ beta,\n float* __restrict__ out, int rows, int D) {\n int row = blockIdx.x;\n int tid = threadIdx.x;\n float sum = 0.0f, sumsq = 0.0f;\n for (int d = tid; d < D; d += blockDim.x) { float x = pooled[row * D + d]; sum += x; sumsq = fmaf(x, x, sumsq); }\n __shared__ float smem[256];\n smem[tid] = sum; smem[tid + blockDim.x] = sumsq;\n __syncthreads();\n for (int s = blockDim.x >> 1; s > 0; s >>= 1) {\n if (tid < s) { smem[tid] += smem[tid + s]; smem[tid + blockDim.x] += smem[tid + blockDim.x + s]; }\n __syncthreads();\n }\n float mean = smem[0] / (float)D;\n float var = smem[blockDim.x] / (float)D - mean * mean;\n float inv = rsqrtf(var + 1.0e-5f);\n for (int d = tid; d < D; d += blockDim.x) {\n float x = pooled[row * D + d]; out[row * D + d] = nodes[row * D + d] + (x - mean) * inv * gamma[d] + beta[d];\n }\n}\n\ntorch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,\n torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,\n torch::Tensor gamma, torch::Tensor beta) {\n int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0);\n auto opts = nodes.options();\n auto pre_i = torch::empty({B, N, H}, opts);\n auto pre_j = torch::empty({B, N, H}, opts);\n auto hidden = torch::empty({B, N, N, H}, opts);\n auto pair_out = torch::empty({B, N, N, D}, opts);\n auto pooled = torch::empty({B, N, D}, opts);\n auto out = torch::empty_like(nodes);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n int total_pairs = B * N * N;\n pre_node_kernel<<<B*N, 256, 0, stream>>>(nodes.data_ptr<float>(), w1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), B*N, D, P, H);\n hidden_pair_kernel<<<total_pairs, 256, 0, stream>>>(pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);\n second_pair_kernel<<<dim3((D + 7) / 8, total_pairs), 256, 0, stream>>>(hidden.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pair_out.data_ptr<float>(), total_pairs, D, H);\n reduce_pool_kernel<<<dim3((D + 3) / 4, B * N), 128, 0, stream>>>(pair_out.data_ptr<float>(), edge_mask.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D);\n layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);\n return out;\n}\n'''\n_ext = load_inline(name='gf_vla_fused_ext_final', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, pair_dim: int, hidden: int):\n super().__init__(); self.dim = dim; self.pair_dim = pair_dim\n self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim)); self.out_norm = nn.LayerNorm(dim)\n def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:\n return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 0.08 μs Runtime stats: mean=0.08μs median=?μs std=0.00μs Numerical precision: max_abs_err=4.17e-06 mean_abs_err=4.75e-07 max_rel_err=1.69e-02 Memory: 36.38 MB peak (ref: 38.84 MB, ratio: 0.9366x) Kernel launches: 7 (ref: 50, fusion ratio: 7.1429) SOL score: 0.2776
final submitted kernel (145 lines, 7,245 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

_cpp_src = 'torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask, torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2, torch::Tensor gamma, torch::Tensor beta);'
_cuda_src = r'''
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <float.h>

__global__ void pre_node_kernel(const float* __restrict__ nodes, const float* __restrict__ w1,
                                float* __restrict__ pre_i, float* __restrict__ pre_j,
                                int rows, int D, int P, int H) {
    int row = blockIdx.x;
    int h = threadIdx.x;
    if (h >= H) return;
    const float* n = nodes + row * D;
    const float* wi = w1 + h * (2 * D + P);
    float ai = 0.0f, aj = 0.0f;
    #pragma unroll 4
    for (int k = 0; k < D; ++k) {
        float x = n[k]; ai = fmaf(x, wi[k], ai); aj = fmaf(x, wi[D + k], aj);
    }
    pre_i[row * H + h] = ai;
    pre_j[row * H + h] = aj;
}

__global__ void hidden_pair_kernel(const float* __restrict__ pair_feats, const float* __restrict__ w1,
                                   const float* __restrict__ b1, const float* __restrict__ pre_i,
                                   const float* __restrict__ pre_j, float* __restrict__ hidden,
                                   int B, int N, int D, int P, int H) {
    int pair = blockIdx.x;
    int h = threadIdx.x;
    if (h >= H) return;
    int j = pair % N;
    int tmp = pair / N;
    int i = tmp % N;
    int b = tmp / N;
    int row_i = b * N + i;
    int row_j = b * N + j;
    const float* wi = w1 + h * (2 * D + P) + 2 * D;
    float acc = b1[h] + pre_i[row_i * H + h] + pre_j[row_j * H + h];
    const float* pf = pair_feats + pair * P;
    #pragma unroll
    for (int k = 0; k < 16; ++k) { if (k < P) acc = fmaf(pf[k], wi[k], acc); }
    float sig = 1.0f / (1.0f + expf(-acc));
    hidden[pair * H + h] = acc * sig;
}

__inline__ __device__ float warp_sum(float v) {
    #pragma unroll
    for (int offset = 16; offset > 0; offset >>= 1) v += __shfl_down_sync(0xffffffff, v, offset);
    return v;
}
__inline__ __device__ float warp_max(float v) {
    #pragma unroll
    for (int offset = 16; offset > 0; offset >>= 1) v = fmaxf(v, __shfl_down_sync(0xffffffff, v, offset));
    return v;
}

__global__ void second_pair_kernel(const float* __restrict__ hidden, const float* __restrict__ w2,
                                   const float* __restrict__ b2, float* __restrict__ pair_out,
                                   int total_pairs, int D, int H) {
    int pair = blockIdx.y;
    int warp = threadIdx.x >> 5;
    int lane = threadIdx.x & 31;
    int d = blockIdx.x * 8 + warp;
    if (d >= D) return;
    const float* hp = hidden + pair * H;
    const float* wd = w2 + d * H;
    float sum = 0.0f;
    for (int h = lane; h < H; h += 32) sum = fmaf(hp[h], wd[h], sum);
    sum = warp_sum(sum);
    if (lane == 0) pair_out[pair * D + d] = sum + b2[d];
}

__global__ void reduce_pool_kernel(const float* __restrict__ pair_out, const float* __restrict__ edge_mask,
                                   float* __restrict__ pooled, int B, int N, int D) {
    int row = blockIdx.y;
    int warp = threadIdx.x >> 5;
    int lane = threadIdx.x & 31;
    int d = blockIdx.x * 4 + warp;
    if (d >= D) return;
    float v = -FLT_MAX;
    if (lane < N && edge_mask[row * N + lane] >= 0.5f) {
        int pair = row * N + lane;
        v = pair_out[pair * D + d];
    }
    v = warp_max(v);
    if (lane == 0) pooled[row * D + d] = v;
}

__global__ void layernorm_kernel(const float* __restrict__ nodes, const float* __restrict__ pooled,
                                 const float* __restrict__ gamma, const float* __restrict__ beta,
                                 float* __restrict__ out, int rows, int D) {
    int row = blockIdx.x;
    int tid = threadIdx.x;
    float sum = 0.0f, sumsq = 0.0f;
    for (int d = tid; d < D; d += blockDim.x) { float x = pooled[row * D + d]; sum += x; sumsq = fmaf(x, x, sumsq); }
    __shared__ float smem[256];
    smem[tid] = sum; smem[tid + blockDim.x] = sumsq;
    __syncthreads();
    for (int s = blockDim.x >> 1; s > 0; s >>= 1) {
        if (tid < s) { smem[tid] += smem[tid + s]; smem[tid + blockDim.x] += smem[tid + blockDim.x + s]; }
        __syncthreads();
    }
    float mean = smem[0] / (float)D;
    float var = smem[blockDim.x] / (float)D - mean * mean;
    float inv = rsqrtf(var + 1.0e-5f);
    for (int d = tid; d < D; d += blockDim.x) {
        float x = pooled[row * D + d]; out[row * D + d] = nodes[row * D + d] + (x - mean) * inv * gamma[d] + beta[d];
    }
}

torch::Tensor fused_forward(torch::Tensor nodes, torch::Tensor pair_feats, torch::Tensor edge_mask,
                            torch::Tensor w1, torch::Tensor b1, torch::Tensor w2, torch::Tensor b2,
                            torch::Tensor gamma, torch::Tensor beta) {
    int B = nodes.size(0), N = nodes.size(1), D = nodes.size(2), P = pair_feats.size(3), H = w1.size(0);
    auto opts = nodes.options();
    auto pre_i = torch::empty({B, N, H}, opts);
    auto pre_j = torch::empty({B, N, H}, opts);
    auto hidden = torch::empty({B, N, N, H}, opts);
    auto pair_out = torch::empty({B, N, N, D}, opts);
    auto pooled = torch::empty({B, N, D}, opts);
    auto out = torch::empty_like(nodes);
    cudaStream_t stream = at::cuda::getCurrentCUDAStream();
    int total_pairs = B * N * N;
    pre_node_kernel<<<B*N, 256, 0, stream>>>(nodes.data_ptr<float>(), w1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), B*N, D, P, H);
    hidden_pair_kernel<<<total_pairs, 256, 0, stream>>>(pair_feats.data_ptr<float>(), w1.data_ptr<float>(), b1.data_ptr<float>(), pre_i.data_ptr<float>(), pre_j.data_ptr<float>(), hidden.data_ptr<float>(), B, N, D, P, H);
    second_pair_kernel<<<dim3((D + 7) / 8, total_pairs), 256, 0, stream>>>(hidden.data_ptr<float>(), w2.data_ptr<float>(), b2.data_ptr<float>(), pair_out.data_ptr<float>(), total_pairs, D, H);
    reduce_pool_kernel<<<dim3((D + 3) / 4, B * N), 128, 0, stream>>>(pair_out.data_ptr<float>(), edge_mask.data_ptr<float>(), pooled.data_ptr<float>(), B, N, D);
    layernorm_kernel<<<B * N, 128, 0, stream>>>(nodes.data_ptr<float>(), pooled.data_ptr<float>(), gamma.data_ptr<float>(), beta.data_ptr<float>(), out.data_ptr<float>(), B * N, D);
    return out;
}
'''
_ext = load_inline(name='gf_vla_fused_ext_final', cpp_sources=_cpp_src, cuda_sources=_cuda_src, functions=['fused_forward'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)
class ModelNew(nn.Module):
    def __init__(self, dim: int, pair_dim: int, hidden: int):
        super().__init__(); self.dim = dim; self.pair_dim = pair_dim
        self.fuse = nn.Sequential(nn.Linear(2 * dim + pair_dim, hidden), nn.SiLU(), nn.Linear(hidden, dim)); self.out_norm = nn.LayerNorm(dim)
    def forward(self, nodes: torch.Tensor, pair_feats: torch.Tensor, edge_mask: torch.Tensor) -> torch.Tensor:
        return _ext.fused_forward(nodes, pair_feats, edge_mask, self.fuse[0].weight, self.fuse[0].bias, self.fuse[2].weight, self.fuse[2].bias, self.out_norm.weight, self.out_norm.bias)