gpt-5.5-priority · popcorn · l123_single_gpt
correct 43_ContactMapPrediction.py
model
gpt-5.5-priority
turns / max
1 / 1
tool calls
1
tokens (total)
0
wall clock
—
truncated
no
backend
cuda fp32
variant
popcorn
runtime
0.14 μs
ref runtime
0.11 μs
speedup
0.80x
started
2026-05-05T00:14:42Z
timingkernelbench.timing
kernel runtime
0.14 μs
ref runtime
0.11 μs
speedup
0.80x
kernel mean / median / std
0.14 / — / 5.05e-04 μs
ref mean / median / std
0.11 / — / 0.03 μs
numerical precisioneval_kernel_against_ref
max abs error
1.19e-07
mean abs error
1.22e-08
max rel error
2.37e-07
mean rel error
2.37e-08
gpu memoryextended_metrics.measure_memory
kernel peak
37.09 MB
ref peak
49.03 MB
kernel / ref
0.76x
kernel launches / fusiontorch.profiler
kernel launches
1
ref launches
41
fusion ratio (ref / kernel)
41.00x
total cuda time
25 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.009
dram util %
0.9%
compute util %
0.0%
bottleneck
unknown
dominant pipe
None
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
31.74 GB/s
dram util %
0.9%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
65.7%
bottleneck
unknown
dominant pipe %
—
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
37.3%
ld sectors / req
22.10
st sectors / req
—
regs / thread
34
smem / block
3712 B
block size
128
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
short_scoreboard
2452.5%
long_scoreboard
1220.5%
mio_throttle
1074.6%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
import torch.nn.functional as F


class Model(nn.Module):
    """
    Contact map prediction head.  Takes residue-pair embeddings and
    predicts a symmetric binary contact probability matrix (residue i
    within 8 Å of residue j).  Uses a small MLP on the symmetrised pair
    representation followed by a sigmoid.  Common final stage in protein
    structure prediction pipelines.
    """

    def __init__(self, pair_dim, hidden_dim):
        super().__init__()
        self.layer_norm = nn.LayerNorm(pair_dim)
        self.mlp = nn.Sequential(
            nn.Linear(pair_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, 1),
        )

    def forward(self, pair_repr: torch.Tensor) -> torch.Tensor:
        """
        Args:
            pair_repr: (B, N, N, pair_dim)
        Returns:
            contact_probs: (B, N, N) – symmetric contact probability
        """
        x = self.layer_norm(pair_repr)
        # Symmetrise
        x = (x + x.permute(0, 2, 1, 3)) / 2.0
        logits = self.mlp(x).squeeze(-1)  # (B, N, N)
        return torch.sigmoid(logits)


pair_dim = 64
hidden_dim = 32
seq_len = 64
batch_size = 4


def get_inputs():
    return [torch.randn(popcorn_pri.jitter_int(batch_size), popcorn_pri.jitter_int(seq_len), popcorn_pri.jitter_int(seq_len), pair_dim)]


def get_init_inputs():
    return [pair_dim, hidden_dim]
turn 0 · FINAL · 1 tool call(s) · 42.4s turn · 42.4s LLM · 9,391 chars (click to expand)
turn 042.4s turn · 42.4s LLM · 0.0s tools · FINAL
reasoning
**Planning Python Model Implementation** I need to produce a complete Python file to implement a faster model. It will have fixed dimensions, like `pair_dim` of 64 and `hidden` of 32, possibly with weights from NN modules. The `ModelNew` constructor will initialize and load the state dict. I must ensure the `evaluator` creates `ModelNew(pair_dim, hidden_dim)` and that attributes are consistent. For efficiency, I could optimize and fuse operations while averaging normalized vectors through a custom setup, using CUDA. **Designing Kernel for Output** I'm working on a host wrapper that accepts tensors and returns outputs. I need to ensure it handles FP32 types only, importing `torch.Tensor` for this. For the kernel design, I'll aim for one block per output element, likely using 128 threads. I plan to compute layer normalization statistics for two vectors and manage hidden layer reductions with shared arrays. Each thread will compute values for normalization, while maintaining the correct bias adjustments. The structure allows for ReLU activations and final outputs using sigmoid functions, ensuring a clean, efficient flow.
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\n\ntorch::Tensor contact_forward_cuda(torch::Tensor pair_repr,\n torch::Tensor ln_w, torch::Tensor ln_b,\n torch::Tensor w1, torch::Tensor b1,\n torch::Tensor w2, torch::Tensor b2,\n torch::Tensor w3, torch::Tensor b3);\n\ntorch::Tensor contact_forward(torch::Tensor pair_repr,\n torch::Tensor ln_w, torch::Tensor ln_b,\n torch::Tensor w1, torch::Tensor b1,\n torch::Tensor w2, torch::Tensor b2,\n torch::Tensor w3, torch::Tensor b3) {\n return contact_forward_cuda(pair_repr, ln_w, ln_b, w1, b1, w2, b2, w3, b3);\n}\n\"\"\"\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\n#define C_DIM 64\n#define H_DIM 32\n\n__global__ void contact_kernel(const float* __restrict__ x,\n const float* __restrict__ ln_w,\n const float* __restrict__ ln_b,\n const float* __restrict__ w1,\n const float* __restrict__ b1,\n const float* __restrict__ w2,\n const float* __restrict__ b2,\n const float* __restrict__ w3,\n const float* __restrict__ b3,\n float* __restrict__ out,\n int B, int N) {\n const int i = (int)blockIdx.x;\n const int j = (int)blockIdx.y;\n const int b = (int)blockIdx.z;\n if (i > j) return;\n\n const int tid = (int)threadIdx.x;\n __shared__ float sA[128];\n __shared__ float sA2[128];\n __shared__ float sB[128];\n __shared__ float sB2[128];\n __shared__ float xs[C_DIM];\n __shared__ float h1[H_DIM];\n __shared__ float h2[H_DIM];\n __shared__ float stats[4];\n\n const long baseA = (((long)b * N + i) * N + j) * C_DIM;\n const long baseB = (((long)b * N + j) * N + i) * C_DIM;\n\n float va = 0.0f, vb = 0.0f;\n if (tid < C_DIM) {\n va = __ldg(x + baseA + tid);\n vb = __ldg(x + baseB + tid);\n }\n sA[tid] = va;\n sA2[tid] = va * va;\n sB[tid] = vb;\n sB2[tid] = vb * vb;\n __syncthreads();\n\n // Reduce 128 lanes. Lanes >=64 contain zeros, which keeps the code simple.\n for (int stride = 64; stride > 0; stride >>= 1) {\n if (tid < stride) {\n sA[tid] += sA[tid + stride];\n sA2[tid] += sA2[tid + stride];\n sB[tid] += sB[tid + stride];\n sB2[tid] += sB2[tid + stride];\n }\n __syncthreads();\n }\n\n if (tid == 0) {\n const float meanA = sA[0] * (1.0f / (float)C_DIM);\n const float meanB = sB[0] * (1.0f / (float)C_DIM);\n float varA = sA2[0] * (1.0f / (float)C_DIM) - meanA * meanA;\n float varB = sB2[0] * (1.0f / (float)C_DIM) - meanB * meanB;\n varA = varA > 0.0f ? varA : 0.0f;\n varB = varB > 0.0f ? varB : 0.0f;\n stats[0] = meanA;\n stats[1] = rsqrtf(varA + 1.0e-5f);\n stats[2] = meanB;\n stats[3] = rsqrtf(varB + 1.0e-5f);\n }\n __syncthreads();\n\n if (tid < C_DIM) {\n const float a = __ldg(x + baseA + tid);\n const float c = __ldg(x + baseB + tid);\n const float norm_sum = (a - stats[0]) * stats[1] + (c - stats[2]) * stats[3];\n xs[tid] = 0.5f * norm_sum * __ldg(ln_w + tid) + __ldg(ln_b + tid);\n }\n __syncthreads();\n\n if (tid < H_DIM) {\n float acc = __ldg(b1 + tid);\n const float* ww = w1 + tid * C_DIM;\n #pragma unroll\n for (int k = 0; k < C_DIM; ++k) {\n acc = fmaf(__ldg(ww + k), xs[k], acc);\n }\n h1[tid] = acc > 0.0f ? acc : 0.0f;\n }\n __syncthreads();\n\n if (tid < H_DIM) {\n float acc = __ldg(b2 + tid);\n const float* ww = w2 + tid * H_DIM;\n #pragma unroll\n for (int k = 0; k < H_DIM; ++k) {\n acc = fmaf(__ldg(ww + k), h1[k], acc);\n }\n h2[tid] = acc > 0.0f ? acc : 0.0f;\n }\n __syncthreads();\n\n if (tid == 0) {\n float acc = __ldg(b3);\n #pragma unroll\n for (int k = 0; k < H_DIM; ++k) {\n acc = fmaf(__ldg(w3 + k), h2[k], acc);\n }\n const float y = 1.0f / (1.0f + expf(-acc));\n const long o1 = ((long)b * N + i) * N + j;\n const long o2 = ((long)b * N + j) * N + i;\n out[o1] = y;\n out[o2] = y;\n }\n}\n\ntorch::Tensor contact_forward_cuda(torch::Tensor pair_repr,\n torch::Tensor ln_w, torch::Tensor ln_b,\n torch::Tensor w1, torch::Tensor b1,\n torch::Tensor w2, torch::Tensor b2,\n torch::Tensor w3, torch::Tensor b3) {\n const int B = (int)pair_repr.size(0);\n const int N = (int)pair_repr.size(1);\n auto out = torch::empty({B, N, N}, pair_repr.options());\n dim3 grid(N, N, B);\n dim3 block(128);\n contact_kernel<<<grid, block, 0, at::cuda::getCurrentCUDAStream()>>>(\n pair_repr.data_ptr<float>(),\n ln_w.data_ptr<float>(), ln_b.data_ptr<float>(),\n w1.data_ptr<float>(), b1.data_ptr<float>(),\n w2.data_ptr<float>(), b2.data_ptr<float>(),\n w3.data_ptr<float>(), b3.data_ptr<float>(),\n out.data_ptr<float>(), B, N);\n C10_CUDA_KERNEL_LAUNCH_CHECK();\n return out;\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"contact_head_fused_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"contact_forward\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n verbose=False,\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, pair_dim, hidden_dim):\n super().__init__()\n self.layer_norm = nn.LayerNorm(pair_dim)\n self.mlp = nn.Sequential(\n nn.Linear(pair_dim, hidden_dim),\n nn.ReLU(),\n nn.Linear(hidden_dim, hidden_dim),\n nn.ReLU(),\n nn.Linear(hidden_dim, 1),\n )\n\n def forward(self, pair_repr: torch.Tensor) -> torch.Tensor:\n # The benchmark shape is fixed at pair_dim=64, hidden_dim=32 and fp32 CUDA.\n if not pair_repr.is_contiguous():\n pair_repr = pair_repr.contiguous()\n return _ext.contact_forward(\n pair_repr,\n self.layer_norm.weight,\n self.layer_norm.bias,\n self.mlp[0].weight,\n self.mlp[0].bias,\n self.mlp[2].weight,\n self.mlp[2].bias,\n self.mlp[4].weight,\n self.mlp[4].bias,\n )\n" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 0.14 μs Runtime stats: mean=0.14μs median=?μs std=0.00μs Numerical precision: max_abs_err=1.19e-07 mean_abs_err=1.22e-08 max_rel_err=2.37e-07 Memory: 37.09 MB peak (ref: 49.03 MB, ratio: 0.7565x) Kernel launches: 1 (ref: 41, fusion ratio: 41.0) SOL score: 0.0095
final submitted kernel (202 lines, 6,820 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline


_cpp_src = r"""
#include <torch/extension.h>

torch::Tensor contact_forward_cuda(torch::Tensor pair_repr,
                                   torch::Tensor ln_w, torch::Tensor ln_b,
                                   torch::Tensor w1, torch::Tensor b1,
                                   torch::Tensor w2, torch::Tensor b2,
                                   torch::Tensor w3, torch::Tensor b3);

torch::Tensor contact_forward(torch::Tensor pair_repr,
                              torch::Tensor ln_w, torch::Tensor ln_b,
                              torch::Tensor w1, torch::Tensor b1,
                              torch::Tensor w2, torch::Tensor b2,
                              torch::Tensor w3, torch::Tensor b3) {
    return contact_forward_cuda(pair_repr, ln_w, ln_b, w1, b1, w2, b2, w3, b3);
}
"""

_cuda_src = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>

#define C_DIM 64
#define H_DIM 32

__global__ void contact_kernel(const float* __restrict__ x,
                               const float* __restrict__ ln_w,
                               const float* __restrict__ ln_b,
                               const float* __restrict__ w1,
                               const float* __restrict__ b1,
                               const float* __restrict__ w2,
                               const float* __restrict__ b2,
                               const float* __restrict__ w3,
                               const float* __restrict__ b3,
                               float* __restrict__ out,
                               int B, int N) {
    const int i = (int)blockIdx.x;
    const int j = (int)blockIdx.y;
    const int b = (int)blockIdx.z;
    if (i > j) return;

    const int tid = (int)threadIdx.x;
    __shared__ float sA[128];
    __shared__ float sA2[128];
    __shared__ float sB[128];
    __shared__ float sB2[128];
    __shared__ float xs[C_DIM];
    __shared__ float h1[H_DIM];
    __shared__ float h2[H_DIM];
    __shared__ float stats[4];

    const long baseA = (((long)b * N + i) * N + j) * C_DIM;
    const long baseB = (((long)b * N + j) * N + i) * C_DIM;

    float va = 0.0f, vb = 0.0f;
    if (tid < C_DIM) {
        va = __ldg(x + baseA + tid);
        vb = __ldg(x + baseB + tid);
    }
    sA[tid] = va;
    sA2[tid] = va * va;
    sB[tid] = vb;
    sB2[tid] = vb * vb;
    __syncthreads();

    // Reduce 128 lanes.  Lanes >=64 contain zeros, which keeps the code simple.
    for (int stride = 64; stride > 0; stride >>= 1) {
        if (tid < stride) {
            sA[tid] += sA[tid + stride];
            sA2[tid] += sA2[tid + stride];
            sB[tid] += sB[tid + stride];
            sB2[tid] += sB2[tid + stride];
        }
        __syncthreads();
    }

    if (tid == 0) {
        const float meanA = sA[0] * (1.0f / (float)C_DIM);
        const float meanB = sB[0] * (1.0f / (float)C_DIM);
        float varA = sA2[0] * (1.0f / (float)C_DIM) - meanA * meanA;
        float varB = sB2[0] * (1.0f / (float)C_DIM) - meanB * meanB;
        varA = varA > 0.0f ? varA : 0.0f;
        varB = varB > 0.0f ? varB : 0.0f;
        stats[0] = meanA;
        stats[1] = rsqrtf(varA + 1.0e-5f);
        stats[2] = meanB;
        stats[3] = rsqrtf(varB + 1.0e-5f);
    }
    __syncthreads();

    if (tid < C_DIM) {
        const float a = __ldg(x + baseA + tid);
        const float c = __ldg(x + baseB + tid);
        const float norm_sum = (a - stats[0]) * stats[1] + (c - stats[2]) * stats[3];
        xs[tid] = 0.5f * norm_sum * __ldg(ln_w + tid) + __ldg(ln_b + tid);
    }
    __syncthreads();

    if (tid < H_DIM) {
        float acc = __ldg(b1 + tid);
        const float* ww = w1 + tid * C_DIM;
        #pragma unroll
        for (int k = 0; k < C_DIM; ++k) {
            acc = fmaf(__ldg(ww + k), xs[k], acc);
        }
        h1[tid] = acc > 0.0f ? acc : 0.0f;
    }
    __syncthreads();

    if (tid < H_DIM) {
        float acc = __ldg(b2 + tid);
        const float* ww = w2 + tid * H_DIM;
        #pragma unroll
        for (int k = 0; k < H_DIM; ++k) {
            acc = fmaf(__ldg(ww + k), h1[k], acc);
        }
        h2[tid] = acc > 0.0f ? acc : 0.0f;
    }
    __syncthreads();

    if (tid == 0) {
        float acc = __ldg(b3);
        #pragma unroll
        for (int k = 0; k < H_DIM; ++k) {
            acc = fmaf(__ldg(w3 + k), h2[k], acc);
        }
        const float y = 1.0f / (1.0f + expf(-acc));
        const long o1 = ((long)b * N + i) * N + j;
        const long o2 = ((long)b * N + j) * N + i;
        out[o1] = y;
        out[o2] = y;
    }
}

torch::Tensor contact_forward_cuda(torch::Tensor pair_repr,
                                   torch::Tensor ln_w, torch::Tensor ln_b,
                                   torch::Tensor w1, torch::Tensor b1,
                                   torch::Tensor w2, torch::Tensor b2,
                                   torch::Tensor w3, torch::Tensor b3) {
    const int B = (int)pair_repr.size(0);
    const int N = (int)pair_repr.size(1);
    auto out = torch::empty({B, N, N}, pair_repr.options());
    dim3 grid(N, N, B);
    dim3 block(128);
    contact_kernel<<<grid, block, 0, at::cuda::getCurrentCUDAStream()>>>(
        pair_repr.data_ptr<float>(),
        ln_w.data_ptr<float>(), ln_b.data_ptr<float>(),
        w1.data_ptr<float>(), b1.data_ptr<float>(),
        w2.data_ptr<float>(), b2.data_ptr<float>(),
        w3.data_ptr<float>(), b3.data_ptr<float>(),
        out.data_ptr<float>(), B, N);
    C10_CUDA_KERNEL_LAUNCH_CHECK();
    return out;
}
"""

_ext = load_inline(
    name="contact_head_fused_ext_v1",
    cpp_sources=_cpp_src,
    cuda_sources=_cuda_src,
    functions=["contact_forward"],
    extra_cflags=["-O3"],
    extra_cuda_cflags=["-O3", "--use_fast_math"],
    verbose=False,
)


class ModelNew(nn.Module):
    def __init__(self, pair_dim, hidden_dim):
        super().__init__()
        self.layer_norm = nn.LayerNorm(pair_dim)
        self.mlp = nn.Sequential(
            nn.Linear(pair_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.ReLU(),
            nn.Linear(hidden_dim, 1),
        )

    def forward(self, pair_repr: torch.Tensor) -> torch.Tensor:
        # The benchmark shape is fixed at pair_dim=64, hidden_dim=32 and fp32 CUDA.
        if not pair_repr.is_contiguous():
            pair_repr = pair_repr.contiguous()
        return _ext.contact_forward(
            pair_repr,
            self.layer_norm.weight,
            self.layer_norm.bias,
            self.mlp[0].weight,
            self.mlp[0].bias,
            self.mlp[2].weight,
            self.mlp[2].bias,
            self.mlp[4].weight,
            self.mlp[4].bias,
        )