correct
9_BayesianLinearRegression.py
started
2026-05-05T02:07:01Z
timingkernelbench.timing
kernel mean / median / std
0.14 / — / 4.79e-04 μs
ref mean / median / std
0.33 / — / 0.02 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
70.50x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
warp stalls (top 5)nsight
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
class Model(nn.Module):
"""
Bayesian linear regression with a conjugate Gaussian prior.
Given features X and targets y, computes the posterior distribution
over weights: p(w | X, y) = N(mu_post, Sigma_post) in closed form
via the matrix inversion lemma / Cholesky decomposition.
"""
def __init__(self, input_dim, prior_precision=1.0, noise_precision=1.0):
super().__init__()
self.input_dim = input_dim
self.prior_precision = prior_precision
self.noise_precision = noise_precision
def forward(
self, X: torch.Tensor, y: torch.Tensor, X_test: torch.Tensor
) -> tuple:
"""
Args:
X: (B, N, D) – training features
y: (B, N, 1) – training targets
X_test: (B, M, D) – test features
Returns:
(pred_mean, pred_var):
pred_mean: (B, M, 1)
pred_var: (B, M)
"""
D = X.shape[-1]
eye = torch.eye(D, device=X.device, dtype=X.dtype).unsqueeze(0)
# Posterior precision: Lambda_post = alpha * I + beta * X^T X
Lambda_post = self.prior_precision * eye + self.noise_precision * (X.transpose(-1, -2) @ X)
L = torch.linalg.cholesky(Lambda_post)
# Posterior mean: mu_post = Lambda_post^{-1} * beta * X^T y
rhs = self.noise_precision * (X.transpose(-1, -2) @ y)
mu_post = torch.cholesky_solve(rhs, L)
# Predictive distribution
pred_mean = X_test @ mu_post
Sigma_post = torch.cholesky_inverse(L)
pred_var = (X_test @ Sigma_post * X_test).sum(-1) + 1.0 / self.noise_precision
return pred_mean, pred_var
input_dim = 16
num_train = 256
num_test = 64
batch_size = 16
def get_inputs():
p = popcorn_pri
X = torch.randn(p.jitter_int(batch_size), p.jitter_int(num_train), input_dim)
y = torch.randn(p.jitter_int(batch_size), p.jitter_int(num_train), 1)
X_test = torch.randn(p.jitter_int(batch_size), p.jitter_int(num_test), input_dim)
return [X, y, X_test]
def get_init_inputs():
return [input_dim]
turn 0 · FINAL · 1 tool call(s) · 31.9s turn · 31.9s LLM · 7,310 chars (click to expand)
turn 031.9s turn · 31.9s 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 = r\"\"\"\n#include <torch/extension.h>\n#include <vector>\n\nstd::vector<torch::Tensor> blr_forward_cuda(torch::Tensor X, torch::Tensor y, torch::Tensor X_test, double prior_precision, double noise_precision);\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#include <vector>\n#include <cmath>\n\n__global__ void blr_kernel(const float* __restrict__ X,\n const float* __restrict__ y,\n const float* __restrict__ Xt,\n float* __restrict__ out_mean,\n float* __restrict__ out_var,\n int B, int N, int D, int M,\n float alpha, float beta) {\n // Optimized for the benchmark dimensions (D=16), but works for D<=16.\n int b = blockIdx.x;\n int tid = threadIdx.x;\n __shared__ float A[16*16];\n __shared__ float rhs[16];\n __shared__ float L[16*16];\n __shared__ float invA[16*16];\n __shared__ float mu[16];\n __shared__ float tmp[16*16];\n\n const float* Xb = X + ((long long)b) * N * D;\n const float* yb = y + ((long long)b) * N;\n const float* Xtb = Xt + ((long long)b) * M * D;\n\n if (tid < 256) {\n int i = tid >> 4;\n int j = tid & 15;\n if (i < D && j < D) {\n float s = 0.0f;\n #pragma unroll 4\n for (int n = 0; n < N; ++n) {\n s = fmaf(Xb[n*D + i], Xb[n*D + j], s);\n }\n A[i*16 + j] = beta * s + ((i == j) ? alpha : 0.0f);\n }\n }\n if (tid < 16) {\n int i = tid;\n if (i < D) {\n float s = 0.0f;\n #pragma unroll 4\n for (int n = 0; n < N; ++n) {\n s = fmaf(Xb[n*D + i], yb[n], s);\n }\n rhs[i] = beta * s;\n }\n }\n __syncthreads();\n\n if (tid == 0) {\n // Cholesky decomposition A = L L^T, lower triangular.\n for (int i = 0; i < D; ++i) {\n for (int j = 0; j <= i; ++j) {\n float sum = A[i*16 + j];\n for (int k = 0; k < j; ++k) sum -= L[i*16 + k] * L[j*16 + k];\n if (i == j) {\n L[i*16 + j] = sqrtf(fmaxf(sum, 1.0e-20f));\n } else {\n L[i*16 + j] = sum / L[j*16 + j];\n }\n }\n for (int j = i + 1; j < D; ++j) L[i*16 + j] = 0.0f;\n }\n\n // Solve A * mu = rhs using the Cholesky factors.\n float z[16];\n for (int i = 0; i < D; ++i) {\n float s = rhs[i];\n for (int k = 0; k < i; ++k) s -= L[i*16 + k] * z[k];\n z[i] = s / L[i*16 + i];\n }\n for (int i = D - 1; i >= 0; --i) {\n float s = z[i];\n for (int k = i + 1; k < D; ++k) s -= L[k*16 + i] * mu[k];\n mu[i] = s / L[i*16 + i];\n }\n\n // Compute inv(L) into tmp (lower triangular) by triangular inverse.\n for (int i = 0; i < D*16; ++i) tmp[i] = 0.0f;\n for (int col = 0; col < D; ++col) {\n for (int i = 0; i < D; ++i) {\n float s = (i == col) ? 1.0f : 0.0f;\n for (int k = col; k < i; ++k) s -= L[i*16 + k] * tmp[k*16 + col];\n if (i >= col) tmp[i*16 + col] = s / L[i*16 + i];\n }\n }\n // inv(A) = inv(L)^T * inv(L). Store full symmetric matrix.\n for (int i = 0; i < D; ++i) {\n for (int j = 0; j < D; ++j) {\n float s = 0.0f;\n int start = (i > j) ? i : j;\n for (int k = start; k < D; ++k) s += tmp[k*16 + i] * tmp[k*16 + j];\n invA[i*16 + j] = s;\n }\n }\n }\n __syncthreads();\n\n // Predictive mean and variance. One thread per test point, striding for general M.\n for (int m = tid; m < M; m += blockDim.x) {\n const float* x = Xtb + m * D;\n float mean = 0.0f;\n for (int i = 0; i < D; ++i) mean = fmaf(x[i], mu[i], mean);\n out_mean[((long long)b) * M + m] = mean;\n\n float var = 0.0f;\n for (int i = 0; i < D; ++i) {\n float row = 0.0f;\n for (int j = 0; j < D; ++j) row = fmaf(invA[i*16 + j], x[j], row);\n var = fmaf(x[i], row, var);\n }\n out_var[((long long)b) * M + m] = var + 1.0f / beta;\n }\n}\n\nstd::vector<torch::Tensor> blr_forward_cuda(torch::Tensor X, torch::Tensor y, torch::Tensor X_test, double prior_precision, double noise_precision) {\n const int B = (int)X.size(0);\n const int N = (int)X.size(1);\n const int D = (int)X.size(2);\n const int M = (int)X_test.size(1);\n auto mean = torch::empty({B, M, 1}, X.options());\n auto var = torch::empty({B, M}, X.options());\n const int threads = 256;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n blr_kernel<<<B, threads, 0, stream>>>(\n X.data_ptr<float>(), y.data_ptr<float>(), X_test.data_ptr<float>(),\n mean.data_ptr<float>(), var.data_ptr<float>(), B, N, D, M,\n (float)prior_precision, (float)noise_precision);\n return {mean, var};\n}\n\"\"\"\n\n_ext = load_inline(\n name=\"blr_closed_form_ext_v1\",\n cpp_sources=_cpp_src,\n cuda_sources=_cuda_src,\n functions=[\"blr_forward_cuda\"],\n extra_cflags=[\"-O3\"],\n extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"],\n with_cuda=True,\n verbose=False,\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, input_dim, prior_precision=1.0, noise_precision=1.0):\n super().__init__()\n self.input_dim = input_dim\n self.prior_precision = prior_precision\n self.noise_precision = noise_precision\n\n def forward(self, X: torch.Tensor, y: torch.Tensor, X_test: torch.Tensor) -> tuple:\n return tuple(_ext.blr_forward_cuda(X, y, X_test, float(self.prior_precision), float(self.noise_precision)))\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=5.96e-07 mean_abs_err=4.01e-08 max_rel_err=1.32e-03
Memory: 32.34 MB peak (ref: 32.51 MB, ratio: 0.9947x)
Kernel launches: 2 (ref: 141, fusion ratio: 70.5)
Energy: 241.46 mJ/run (ref: 0.0 mJ, ratio: -1x)
SOL score: 0.0008
final submitted kernel (169 lines, 5,908 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>
#include <vector>
std::vector<torch::Tensor> blr_forward_cuda(torch::Tensor X, torch::Tensor y, torch::Tensor X_test, double prior_precision, double noise_precision);
"""
_cuda_src = r"""
#include <torch/extension.h>
#include <ATen/cuda/CUDAContext.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <vector>
#include <cmath>
__global__ void blr_kernel(const float* __restrict__ X,
const float* __restrict__ y,
const float* __restrict__ Xt,
float* __restrict__ out_mean,
float* __restrict__ out_var,
int B, int N, int D, int M,
float alpha, float beta) {
// Optimized for the benchmark dimensions (D=16), but works for D<=16.
int b = blockIdx.x;
int tid = threadIdx.x;
__shared__ float A[16*16];
__shared__ float rhs[16];
__shared__ float L[16*16];
__shared__ float invA[16*16];
__shared__ float mu[16];
__shared__ float tmp[16*16];
const float* Xb = X + ((long long)b) * N * D;
const float* yb = y + ((long long)b) * N;
const float* Xtb = Xt + ((long long)b) * M * D;
if (tid < 256) {
int i = tid >> 4;
int j = tid & 15;
if (i < D && j < D) {
float s = 0.0f;
#pragma unroll 4
for (int n = 0; n < N; ++n) {
s = fmaf(Xb[n*D + i], Xb[n*D + j], s);
}
A[i*16 + j] = beta * s + ((i == j) ? alpha : 0.0f);
}
}
if (tid < 16) {
int i = tid;
if (i < D) {
float s = 0.0f;
#pragma unroll 4
for (int n = 0; n < N; ++n) {
s = fmaf(Xb[n*D + i], yb[n], s);
}
rhs[i] = beta * s;
}
}
__syncthreads();
if (tid == 0) {
// Cholesky decomposition A = L L^T, lower triangular.
for (int i = 0; i < D; ++i) {
for (int j = 0; j <= i; ++j) {
float sum = A[i*16 + j];
for (int k = 0; k < j; ++k) sum -= L[i*16 + k] * L[j*16 + k];
if (i == j) {
L[i*16 + j] = sqrtf(fmaxf(sum, 1.0e-20f));
} else {
L[i*16 + j] = sum / L[j*16 + j];
}
}
for (int j = i + 1; j < D; ++j) L[i*16 + j] = 0.0f;
}
// Solve A * mu = rhs using the Cholesky factors.
float z[16];
for (int i = 0; i < D; ++i) {
float s = rhs[i];
for (int k = 0; k < i; ++k) s -= L[i*16 + k] * z[k];
z[i] = s / L[i*16 + i];
}
for (int i = D - 1; i >= 0; --i) {
float s = z[i];
for (int k = i + 1; k < D; ++k) s -= L[k*16 + i] * mu[k];
mu[i] = s / L[i*16 + i];
}
// Compute inv(L) into tmp (lower triangular) by triangular inverse.
for (int i = 0; i < D*16; ++i) tmp[i] = 0.0f;
for (int col = 0; col < D; ++col) {
for (int i = 0; i < D; ++i) {
float s = (i == col) ? 1.0f : 0.0f;
for (int k = col; k < i; ++k) s -= L[i*16 + k] * tmp[k*16 + col];
if (i >= col) tmp[i*16 + col] = s / L[i*16 + i];
}
}
// inv(A) = inv(L)^T * inv(L). Store full symmetric matrix.
for (int i = 0; i < D; ++i) {
for (int j = 0; j < D; ++j) {
float s = 0.0f;
int start = (i > j) ? i : j;
for (int k = start; k < D; ++k) s += tmp[k*16 + i] * tmp[k*16 + j];
invA[i*16 + j] = s;
}
}
}
__syncthreads();
// Predictive mean and variance. One thread per test point, striding for general M.
for (int m = tid; m < M; m += blockDim.x) {
const float* x = Xtb + m * D;
float mean = 0.0f;
for (int i = 0; i < D; ++i) mean = fmaf(x[i], mu[i], mean);
out_mean[((long long)b) * M + m] = mean;
float var = 0.0f;
for (int i = 0; i < D; ++i) {
float row = 0.0f;
for (int j = 0; j < D; ++j) row = fmaf(invA[i*16 + j], x[j], row);
var = fmaf(x[i], row, var);
}
out_var[((long long)b) * M + m] = var + 1.0f / beta;
}
}
std::vector<torch::Tensor> blr_forward_cuda(torch::Tensor X, torch::Tensor y, torch::Tensor X_test, double prior_precision, double noise_precision) {
const int B = (int)X.size(0);
const int N = (int)X.size(1);
const int D = (int)X.size(2);
const int M = (int)X_test.size(1);
auto mean = torch::empty({B, M, 1}, X.options());
auto var = torch::empty({B, M}, X.options());
const int threads = 256;
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
blr_kernel<<<B, threads, 0, stream>>>(
X.data_ptr<float>(), y.data_ptr<float>(), X_test.data_ptr<float>(),
mean.data_ptr<float>(), var.data_ptr<float>(), B, N, D, M,
(float)prior_precision, (float)noise_precision);
return {mean, var};
}
"""
_ext = load_inline(
name="blr_closed_form_ext_v1",
cpp_sources=_cpp_src,
cuda_sources=_cuda_src,
functions=["blr_forward_cuda"],
extra_cflags=["-O3"],
extra_cuda_cflags=["-O3", "--use_fast_math"],
with_cuda=True,
verbose=False,
)
class ModelNew(nn.Module):
def __init__(self, input_dim, prior_precision=1.0, noise_precision=1.0):
super().__init__()
self.input_dim = input_dim
self.prior_precision = prior_precision
self.noise_precision = noise_precision
def forward(self, X: torch.Tensor, y: torch.Tensor, X_test: torch.Tensor) -> tuple:
return tuple(_ext.blr_forward_cuda(X, y, X_test, float(self.prior_precision), float(self.noise_precision)))