grok-4.3 · popcorn · pop_l123_default_gpt
incorrect 9_BayesianLinearRegression.py
model
grok-4.3
turns / max
6 / 12
tool calls
5
tokens (total)
52083
wall clock
946.7s
truncated
no
backend
cuda fp32
variant
popcorn
runtime
—
ref runtime
0.45 μs
speedup
—
started
2026-05-11T12:42:10Z
correctness issue: Output mismatch
timingkernelbench.timing
kernel runtime
—
ref runtime
0.45 μs
speedup
—
kernel mean / median / std
—
ref mean / median / std
0.45 / — / 0.03 μs
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.001
dram util %
0.1%
compute util %
0.0%
bottleneck
unknown
dominant pipe
None
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
4.28 GB/s
dram util %
0.1%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
24.7%
bottleneck
unknown
dominant pipe %
—
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
282.7%
ld sectors / req
3.39
st sectors / req
—
regs / thread
64
smem / block
7296 B
block size
512
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
short_scoreboard
819.1%
long_scoreboard
134.4%
mio_throttle
0.0%
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 · 0 tool call(s) · 11.6s turn · 11.6s LLM · tokens in=1,770 · out=1,834 · total=3,948 · 6,567 chars (click to expand)
turn 011.6s turn · 11.6s LLM · 0.0s tools · tokens in=1,770 · out=1,834 · total=3,948
reasoning
The task is to replace the forward computation of this Bayesian linear regression model with a custom CUDA kernel that's faster than PyTorch.
assistant```python import torch import torch.nn as nn from torch.utils.cpp_extension import load_inline cuda_source = r''' #include <torch/extension.h> #include <cuda.h> #include <cuda_runtime.h> #define BLOCK_SIZE 16 __global__ void bayesian_linear_kernel( const float* __restrict__ X, const float* __restrict__ y, const float* __restrict__ X_test, float* __restrict__ pred_mean, float* __restrict__ pred_var, int B, int N, int D, int M, float prior_precision, float noise_precision ) { int b = blockIdx.x; if (b >= B) return; extern __shared__ float smem[]; const float* Xb = X + b * N * D; const float* yb = y + b * N; const float* Xt = X_test + b * M * D; float* Lambda = smem; // D*D float* Lchol = smem + D*D; // D*D float* rhs = smem + 2*D*D; // D float* mu = smem + 2*D*D + D; // D float* Sigma = smem + 2*D*D + 2*D; // D*D float* temp = smem + 3*D*D + 2*D; // D*D or scratch // Compute X^T X and X^T y for (int i = threadIdx.x; i < D*D; i += blockDim.x) { int row = i / D; int col = i % D; float sum = 0.0f; for (int k = 0; k < N; k++) { sum += Xb[k*D + row] * Xb[k*D + col]; } Lambda[i] = prior_precision * (row == col ? 1.0f : 0.0f) + noise_precision * sum; } __syncthreads(); // Cholesky decomposition (naive, for D=16) for (int i = 0; i < D; i++) { for (int j = threadIdx.x; j <= i; j += blockDim.x) { float sum = 0.0f; for (int k = 0; k < j; k++) { sum += Lchol[i*D + k] * Lchol[j*D + k]; } if (i == j) { Lchol[i*D + i] = sqrtf(Lambda[i*D + i] - sum); } else { Lchol[i*D + j] = (Lambda[i*D + j] - sum) / Lchol[j*D + j]; } } __syncthreads(); } // rhs = noise * X^T y for (int i = threadIdx.x; i < D; i += blockDim.x) { float sum = 0.0f; for (int k = 0; k < N; k++) { sum += Xb[k*D + i] * yb[k]; } rhs[i] = noise_precision * sum; } __syncthreads(); // cholesky_solve: forward then back sub // Forward: L z = rhs for (int i = 0; i < D; i++) { if (threadIdx.x == 0) { float sum = 0.0f; for (int k = 0; k < i; k++) sum += Lchol[i*D + k] * mu[k]; mu[i] = (rhs[i] - sum) / Lchol[i*D + i]; } __syncthreads(); } // Back: L^T mu = z for (int i = D-1; i >= 0; i--) { if (threadIdx.x == 0) { float sum = 0.0f; for (int k = i+1; k < D; k++) sum += Lchol[k*D + i] * mu[k]; mu[i] = (mu[i] - sum) / Lchol[i*D + i]; } __syncthreads(); } // pred_mean = X_test @ mu for (int m = threadIdx.x; m < M; m += blockDim.x) { float sum = 0.0f; for (int d = 0; d < D; d++) { sum += Xt[m*D + d] * mu[d]; } pred_mean[b*M + m] = sum; } // cholesky_inverse: solve L L^T Sigma = I for (int col = 0; col < D; col++) { // forward sub for each column for (int i = 0; i < D; i++) { if (threadIdx.x == 0) { float sum = (i == col ? 1.0f : 0.0f); for (int k = 0; k < i; k++) sum -= Lchol[i*D + k] * temp[k*D + col]; temp[i*D + col] = sum / Lchol[i*D + i]; } __syncthreads(); } // back sub for (int i = D-1; i >= 0; i--) { if (threadIdx.x == 0) { float sum = temp[i*D + col]; for (int k = i+1; k < D; k++) sum -= Lchol[k*D + i] * Sigma[k*D + col]; Sigma[i*D + col] = sum / Lchol[i*D + i]; } __syncthreads(); } } // pred_var for (int m = threadIdx.x; m < M; m += blockDim.x) { float sum = 0.0f; for (int d = 0; d < D; d++) { float tmp = 0.0f; for (int e = 0; e < D; e++) { tmp += Xt[m*D + e] * Sigma[e*D + d]; } sum += tmp * Xt[m*D + d]; } pred_var[b*M + m] = sum + 1.0f / noise_precision; } } std::vector<torch::Tensor> bayesian_linear_cuda( torch::Tensor X, torch::Tensor y, torch::Tensor X_test, float prior_precision, float noise_precision ) { int B = X.size(0); int N = X.size(1); int D = X.size(2); int M = X_test.size(1); auto options = torch::TensorOptions().dtype(X.dtype()).device(X.device()); auto pred_mean = torch::zeros({B, M, 1}, options); auto pred_var = torch::zeros({B, M}, options); dim3 grid(B); dim3 block(256); int smem_size = (3*D*D + 2*D + D*D) * sizeof(float); // rough bayesian_linear_kernel<<<grid, block, smem_size>>>( X.data_ptr<float>(), y.data_ptr<float>(), X_test.data_ptr<float>(), pred_mean.data_ptr<float>(), pred_var.data_ptr<float>(), B, N, D, M, prior_precision, noise_precision ); return {pred_mean, pred_var}; } ''' cpp_source = ''' std::vector<torch::Tensor> bayesian_linear_cuda( torch::Tensor X, torch::Tensor y, torch::Tensor X_test, float prior_precision, float noise_precision ); ''' module = load_inline( name='bayesian_linear', cpp_sources=cpp_source, cuda_sources=cuda_source, functions=['bayesian_linear_cuda'], 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, y, X_test): res = module.bayesian_linear_cuda(X, y, X_test, self.prior_precision, self.noise_precision) return res[0], res[1] ```
turn 1 · 1 tool call(s) · 119.0s turn · 9.2s LLM · tokens in=4,016 · out=1,841 · total=5,983 · 7,134 chars (click to expand)
turn 1119.0s turn · 9.2s LLM · 109.8s tools · tokens in=4,016 · out=1,841 · total=5,983
reasoning
The instruction says: "You must call at least one tool this turn: use `compile_kernel` / `run_correctness` to iterate, or call `submit_kernel` with your best `ModelNew` implementation to finalize the ...
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n#define BLOCK_SIZE 16\n\n__global__ void bayesian_linear_kernel(\n const float* __restrict__ X,\n const float* __restrict__ y,\n const float* __restrict__ X_test,\n float* __restrict__ pred_mean,\n float* __restrict__ pred_var,\n int B, int N, int D, int M,\n float prior_precision, float noise_precision\n) {\n int b = blockIdx.x;\n if (b >= B) return;\n\n extern __shared__ float smem[];\n\n const float* Xb = X + b * N * D;\n const float* yb = y + b * N;\n const float* Xt = X_test + b * M * D;\n\n float* Lambda = smem; // D*D\n float* Lchol = smem + D*D; // D*D\n float* rhs = smem + 2*D*D; // D\n float* mu = smem + 2*D*D + D; // D\n float* Sigma = smem + 2*D*D + 2*D; // D*D\n float* temp = smem + 3*D*D + 2*D; // D*D or scratch\n\n // Compute X^T X and X^T y\n for (int i = threadIdx.x; i < D*D; i += blockDim.x) {\n int row = i / D;\n int col = i % D;\n float sum = 0.0f;\n for (int k = 0; k < N; k++) {\n sum += Xb[k*D + row] * Xb[k*D + col];\n }\n Lambda[i] = prior_precision * (row == col ? 1.0f : 0.0f) + noise_precision * sum;\n }\n __syncthreads();\n\n // Cholesky decomposition (naive, for D=16)\n for (int i = 0; i < D; i++) {\n for (int j = threadIdx.x; j <= i; j += blockDim.x) {\n float sum = 0.0f;\n for (int k = 0; k < j; k++) {\n sum += Lchol[i*D + k] * Lchol[j*D + k];\n }\n if (i == j) {\n Lchol[i*D + i] = sqrtf(Lambda[i*D + i] - sum);\n } else {\n Lchol[i*D + j] = (Lambda[i*D + j] - sum) / Lchol[j*D + j];\n }\n }\n __syncthreads();\n }\n\n // rhs = noise * X^T y\n for (int i = threadIdx.x; i < D; i += blockDim.x) {\n float sum = 0.0f;\n for (int k = 0; k < N; k++) {\n sum += Xb[k*D + i] * yb[k];\n }\n rhs[i] = noise_precision * sum;\n }\n __syncthreads();\n\n // cholesky_solve: forward then back sub\n // Forward: L z = rhs\n for (int i = 0; i < D; i++) {\n if (threadIdx.x == 0) {\n float sum = 0.0f;\n for (int k = 0; k < i; k++) sum += Lchol[i*D + k] * mu[k];\n mu[i] = (rhs[i] - sum) / Lchol[i*D + i];\n }\n __syncthreads();\n }\n // Back: L^T mu = z\n for (int i = D-1; i >= 0; i--) {\n if (threadIdx.x == 0) {\n float sum = 0.0f;\n for (int k = i+1; k < D; k++) sum += Lchol[k*D + i] * mu[k];\n mu[i] = (mu[i] - sum) / Lchol[i*D + i];\n }\n __syncthreads();\n }\n\n // pred_mean = X_test @ mu\n for (int m = threadIdx.x; m < M; m += blockDim.x) {\n float sum = 0.0f;\n for (int d = 0; d < D; d++) {\n sum += Xt[m*D + d] * mu[d];\n }\n pred_mean[b*M + m] = sum;\n }\n\n // cholesky_inverse: solve L L^T Sigma = I\n for (int col = 0; col < D; col++) {\n // forward sub for each column\n for (int i = 0; i < D; i++) {\n if (threadIdx.x == 0) {\n float sum = (i == col ? 1.0f : 0.0f);\n for (int k = 0; k < i; k++) sum -= Lchol[i*D + k] * temp[k*D + col];\n temp[i*D + col] = sum / Lchol[i*D + i];\n }\n __syncthreads();\n }\n // back sub\n for (int i = D-1; i >= 0; i--) {\n if (threadIdx.x == 0) {\n float sum = temp[i*D + col];\n for (int k = i+1; k < D; k++) sum -= Lchol[k*D + i] * Sigma[k*D + col];\n Sigma[i*D + col] = sum / Lchol[i*D + i];\n }\n __syncthreads();\n }\n }\n\n // pred_var\n for (int m = threadIdx.x; m < M; m += blockDim.x) {\n float sum = 0.0f;\n for (int d = 0; d < D; d++) {\n float tmp = 0.0f;\n for (int e = 0; e < D; e++) {\n tmp += Xt[m*D + e] * Sigma[e*D + d];\n }\n sum += tmp * Xt[m*D + d];\n }\n pred_var[b*M + m] = sum + 1.0f / noise_precision;\n }\n}\n\nstd::vector<torch::Tensor> bayesian_linear_cuda(\n torch::Tensor X, torch::Tensor y, torch::Tensor X_test,\n float prior_precision, float noise_precision\n) {\n int B = X.size(0);\n int N = X.size(1);\n int D = X.size(2);\n int M = X_test.size(1);\n\n auto options = torch::TensorOptions().dtype(X.dtype()).device(X.device());\n auto pred_mean = torch::zeros({B, M, 1}, options);\n auto pred_var = torch::zeros({B, M}, options);\n\n dim3 grid(B);\n dim3 block(256);\n int smem_size = (3*D*D + 2*D + D*D) * sizeof(float); // rough\n\n bayesian_linear_kernel<<<grid, block, smem_size>>>(\n X.data_ptr<float>(), y.data_ptr<float>(), X_test.data_ptr<float>(),\n pred_mean.data_ptr<float>(), pred_var.data_ptr<float>(),\n B, N, D, M, prior_precision, noise_precision\n );\n\n return {pred_mean, pred_var};\n}\n'''\n\ncpp_source = '''\nstd::vector<torch::Tensor> bayesian_linear_cuda(\n torch::Tensor X, torch::Tensor y, torch::Tensor X_test,\n float prior_precision, float noise_precision\n);\n'''\n\nmodule = load_inline(\n name='bayesian_linear',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['bayesian_linear_cuda'],\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, y, X_test):\n res = module.bayesian_linear_cuda(X, y, X_test, self.prior_precision, self.noise_precision)\n return res[0], res[1]\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 2 · 1 tool call(s) · 137.0s turn · 12.2s LLM · tokens in=6,000 · out=1,842 · total=7,856 · 7,535 chars (click to expand)
turn 2137.0s turn · 12.2s LLM · 124.8s tools · tokens in=6,000 · out=1,842 · total=7,856
reasoning
It compiled successfully. Now I should check correctness with run_correctness.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n#define BLOCK_SIZE 16\n\n__global__ void bayesian_linear_kernel(\n const float* __restrict__ X,\n const float* __restrict__ y,\n const float* __restrict__ X_test,\n float* __restrict__ pred_mean,\n float* __restrict__ pred_var,\n int B, int N, int D, int M,\n float prior_precision, float noise_precision\n) {\n int b = blockIdx.x;\n if (b >= B) return;\n\n extern __shared__ float smem[];\n\n const float* Xb = X + b * N * D;\n const float* yb = y + b * N;\n const float* Xt = X_test + b * M * D;\n\n float* Lambda = smem; // D*D\n float* Lchol = smem + D*D; // D*D\n float* rhs = smem + 2*D*D; // D\n float* mu = smem + 2*D*D + D; // D\n float* Sigma = smem + 2*D*D + 2*D; // D*D\n float* temp = smem + 3*D*D + 2*D; // D*D or scratch\n\n // Compute X^T X and X^T y\n for (int i = threadIdx.x; i < D*D; i += blockDim.x) {\n int row = i / D;\n int col = i % D;\n float sum = 0.0f;\n for (int k = 0; k < N; k++) {\n sum += Xb[k*D + row] * Xb[k*D + col];\n }\n Lambda[i] = prior_precision * (row == col ? 1.0f : 0.0f) + noise_precision * sum;\n }\n __syncthreads();\n\n // Cholesky decomposition (naive, for D=16)\n for (int i = 0; i < D; i++) {\n for (int j = threadIdx.x; j <= i; j += blockDim.x) {\n float sum = 0.0f;\n for (int k = 0; k < j; k++) {\n sum += Lchol[i*D + k] * Lchol[j*D + k];\n }\n if (i == j) {\n Lchol[i*D + i] = sqrtf(Lambda[i*D + i] - sum);\n } else {\n Lchol[i*D + j] = (Lambda[i*D + j] - sum) / Lchol[j*D + j];\n }\n }\n __syncthreads();\n }\n\n // rhs = noise * X^T y\n for (int i = threadIdx.x; i < D; i += blockDim.x) {\n float sum = 0.0f;\n for (int k = 0; k < N; k++) {\n sum += Xb[k*D + i] * yb[k];\n }\n rhs[i] = noise_precision * sum;\n }\n __syncthreads();\n\n // cholesky_solve: forward then back sub\n // Forward: L z = rhs\n for (int i = 0; i < D; i++) {\n if (threadIdx.x == 0) {\n float sum = 0.0f;\n for (int k = 0; k < i; k++) sum += Lchol[i*D + k] * mu[k];\n mu[i] = (rhs[i] - sum) / Lchol[i*D + i];\n }\n __syncthreads();\n }\n // Back: L^T mu = z\n for (int i = D-1; i >= 0; i--) {\n if (threadIdx.x == 0) {\n float sum = 0.0f;\n for (int k = i+1; k < D; k++) sum += Lchol[k*D + i] * mu[k];\n mu[i] = (mu[i] - sum) / Lchol[i*D + i];\n }\n __syncthreads();\n }\n\n // pred_mean = X_test @ mu\n for (int m = threadIdx.x; m < M; m += blockDim.x) {\n float sum = 0.0f;\n for (int d = 0; d < D; d++) {\n sum += Xt[m*D + d] * mu[d];\n }\n pred_mean[b*M + m] = sum;\n }\n\n // cholesky_inverse: solve L L^T Sigma = I\n for (int col = 0; col < D; col++) {\n // forward sub for each column\n for (int i = 0; i < D; i++) {\n if (threadIdx.x == 0) {\n float sum = (i == col ? 1.0f : 0.0f);\n for (int k = 0; k < i; k++) sum -= Lchol[i*D + k] * temp[k*D + col];\n temp[i*D + col] = sum / Lchol[i*D + i];\n }\n __syncthreads();\n }\n // back sub\n for (int i = D-1; i >= 0; i--) {\n if (threadIdx.x == 0) {\n float sum = temp[i*D + col];\n for (int k = i+1; k < D; k++) sum -= Lchol[k*D + i] * Sigma[k*D + col];\n Sigma[i*D + col] = sum / Lchol[i*D + i];\n }\n __syncthreads();\n }\n }\n\n // pred_var\n for (int m = threadIdx.x; m < M; m += blockDim.x) {\n float sum = 0.0f;\n for (int d = 0; d < D; d++) {\n float tmp = 0.0f;\n for (int e = 0; e < D; e++) {\n tmp += Xt[m*D + e] * Sigma[e*D + d];\n }\n sum += tmp * Xt[m*D + d];\n }\n pred_var[b*M + m] = sum + 1.0f / noise_precision;\n }\n}\n\nstd::vector<torch::Tensor> bayesian_linear_cuda(\n torch::Tensor X, torch::Tensor y, torch::Tensor X_test,\n float prior_precision, float noise_precision\n) {\n int B = X.size(0);\n int N = X.size(1);\n int D = X.size(2);\n int M = X_test.size(1);\n\n auto options = torch::TensorOptions().dtype(X.dtype()).device(X.device());\n auto pred_mean = torch::zeros({B, M, 1}, options);\n auto pred_var = torch::zeros({B, M}, options);\n\n dim3 grid(B);\n dim3 block(256);\n int smem_size = (3*D*D + 2*D + D*D) * sizeof(float); // rough\n\n bayesian_linear_kernel<<<grid, block, smem_size>>>(\n X.data_ptr<float>(), y.data_ptr<float>(), X_test.data_ptr<float>(),\n pred_mean.data_ptr<float>(), pred_var.data_ptr<float>(),\n B, N, D, M, prior_precision, noise_precision\n );\n\n return {pred_mean, pred_var};\n}\n'''\n\ncpp_source = '''\nstd::vector<torch::Tensor> bayesian_linear_cuda(\n torch::Tensor X, torch::Tensor y, torch::Tensor X_test,\n float prior_precision, float noise_precision\n);\n'''\n\nmodule = load_inline(\n name='bayesian_linear',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['bayesian_linear_cuda'],\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, y, X_test):\n res = module.bayesian_linear_cuda(X, y, X_test, self.prior_precision, self.noise_precision)\n return res[0], res[1]\n" }
result ← run_correctness (fail)
failrun_correctness run_correctness FAILED: (0 / 5) trials did not all match. correctness_issue: Output mismatch max_difference: ['0.052969', '0.009739', '0.054024', '0.010747', '0.065366', '0.009737', '0.067590', '0.014611', '0.040142', '0.009076'] avg_difference: ['0.008337', '0.002116', '0.010259', '0.001980', '0.009305', '0.002084', '0.009591', '0.002139', '0.008055', '0.002041']
turn 3 · 1 tool call(s) · 192.6s turn · 17.7s LLM · tokens in=8,013 · out=1,887 · total=10,196 · 7,276 chars (click to expand)
turn 3192.6s turn · 17.7s LLM · 174.9s tools · tokens in=8,013 · out=1,887 · total=10,196
reasoning
The kernel is incorrect. There are bugs in the CUDA code, especially in the Cholesky inverse part, as the temp and Sigma indexing looks wrong, and the parallelization is only using one thread for many...
call → compile_kernel
callcompile_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void bayesian_linear_kernel(\n const float* __restrict__ X,\n const float* __restrict__ y,\n const float* __restrict__ X_test,\n float* __restrict__ pred_mean,\n float* __restrict__ pred_var,\n int B, int N, int D, int M,\n float prior_precision, float noise_precision\n) {\n int b = blockIdx.x;\n if (b >= B) return;\n\n extern __shared__ float smem[];\n\n const float* Xb = X + b * N * D;\n const float* yb = y + b * N;\n const float* Xt = X_test + b * M * D;\n\n float* Lambda = smem;\n float* L = smem + D*D;\n float* rhs = smem + 2*D*D;\n float* mu_post = smem + 2*D*D + D;\n float* Sigma = smem + 2*D*D + 2*D;\n float* temp = smem + 3*D*D + 2*D;\n\n // Initialize Lambda = alpha * I\n for (int i = threadIdx.x; i < D*D; i += blockDim.x) {\n int r = i / D, c = i % D;\n Lambda[i] = (r == c) ? prior_precision : 0.0f;\n }\n __syncthreads();\n\n // Compute beta * X^T X and add to Lambda, X^T y\n for (int i = threadIdx.x; i < D; i += blockDim.x) {\n for (int j = 0; j < D; j++) {\n float sum_xx = 0.0f;\n for (int k = 0; k < N; k++) {\n sum_xx += Xb[k*D + i] * Xb[k*D + j];\n }\n Lambda[i*D + j] += noise_precision * sum_xx;\n }\n float sum_xy = 0.0f;\n for (int k = 0; k < N; k++) {\n sum_xy += Xb[k*D + i] * yb[k];\n }\n rhs[i] = noise_precision * sum_xy;\n }\n __syncthreads();\n\n // Cholesky L of Lambda, lower triangular\n for (int i = 0; i < D; ++i) {\n for (int j = threadIdx.x; j <= i; j += blockDim.x) {\n float s = 0.0f;\n for (int k = 0; k < j; ++k) {\n s += L[i*D + k] * L[j*D + k];\n }\n if (i == j) {\n L[i*D + i] = sqrtf(Lambda[i*D + i] - s);\n } else {\n L[i*D + j] = (Lambda[i*D + j] - s) / L[j*D + j];\n }\n }\n __syncthreads();\n }\n\n // Forward substitution L z = rhs -> mu_post temporarily\n for (int i = 0; i < D; ++i) {\n if (threadIdx.x == 0) {\n float s = 0.0f;\n for (int k = 0; k < i; ++k) s += L[i*D + k] * mu_post[k];\n mu_post[i] = (rhs[i] - s) / L[i*D + i];\n }\n __syncthreads();\n }\n // Backward L^T mu = z\n for (int i = D - 1; i >= 0; --i) {\n if (threadIdx.x == 0) {\n float s = 0.0f;\n for (int k = i + 1; k < D; ++k) s += L[k*D + i] * mu_post[k];\n mu_post[i] = (mu_post[i] - s) / L[i*D + i];\n }\n __syncthreads();\n }\n\n // pred_mean = X_test @ mu_post\n for (int m = threadIdx.x; m < M; m += blockDim.x) {\n float sum = 0.0f;\n for (int d = 0; d < D; ++d) {\n sum += Xt[m * D + d] * mu_post[d];\n }\n pred_mean[b * M + m] = sum;\n }\n\n // Compute Sigma = inv(Lambda) via cholesky inverse: solve L Y = I then L^T Sigma = Y\n for (int col = 0; col < D; ++col) {\n // solve L Y_col = e_col\n for (int i = 0; i < D; ++i) {\n if (threadIdx.x == 0) {\n float val = (i == col ? 1.0f : 0.0f);\n for (int k = 0; k < i; ++k) val -= L[i*D + k] * temp[k*D + col];\n temp[i*D + col] = val / L[i*D + i];\n }\n __syncthreads();\n }\n // solve L^T Sigma_col = Y_col\n for (int i = D-1; i >= 0; --i) {\n if (threadIdx.x == 0) {\n float val = temp[i*D + col];\n for (int k = i+1; k < D; ++k) val -= L[k*D + i] * Sigma[k*D + col];\n Sigma[i*D + col] = val / L[i*D + i];\n }\n __syncthreads();\n }\n }\n\n // pred_var = diag(X_test @ Sigma @ X_test^T) + 1/beta\n for (int m = threadIdx.x; m < M; m += blockDim.x) {\n float sum = 0.0f;\n for (int d = 0; d < D; ++d) {\n float tmp = 0.0f;\n for (int e = 0; e < D; ++e) {\n tmp += Xt[m*D + e] * Sigma[e * D + d];\n }\n sum += tmp * Xt[m*D + d];\n }\n pred_var[b * M + m] = sum + 1.0f / noise_precision;\n }\n}\n\nstd::vector<torch::Tensor> bayesian_linear_cuda(\n torch::Tensor X, torch::Tensor y, torch::Tensor X_test,\n float prior_precision, float noise_precision\n) {\n int B = X.size(0);\n int N = X.size(1);\n int D = X.size(2);\n int M = X_test.size(1);\n\n auto options = torch::TensorOptions().dtype(X.dtype()).device(X.device());\n auto pred_mean = torch::zeros({B, M, 1}, options);\n auto pred_var = torch::zeros({B, M}, options);\n\n dim3 grid(B);\n dim3 block(256);\n size_t smem_size = (4 * D * D + 2 * D) * sizeof(float);\n\n bayesian_linear_kernel<<<grid, block, smem_size>>>(\n X.data_ptr<float>(), y.data_ptr<float>(), X_test.data_ptr<float>(),\n pred_mean.data_ptr<float>(), pred_var.data_ptr<float>(),\n B, N, D, M, prior_precision, noise_precision\n );\n\n cudaDeviceSynchronize();\n return {pred_mean.view({B, M, 1}), pred_var};\n}\n'''\n\ncpp_source = '''\nstd::vector<torch::Tensor> bayesian_linear_cuda(\n torch::Tensor X, torch::Tensor y, torch::Tensor X_test,\n float prior_precision, float noise_precision\n);\n'''\n\nmodule = load_inline(\n name='bayesian_linear',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['bayesian_linear_cuda'],\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, y, X_test):\n res = module.bayesian_linear_cuda(X, y, X_test, self.prior_precision, self.noise_precision)\n return res[0], res[1]\n" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 4201.2s turn · 26.3s LLM · 174.9s tools · tokens in=10,213 · out=835 · total=11,054
reasoning
Compiled. Now test correctness.
call → run_correctness
callrun_correctness { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void bayesian_linear_kernel(\n const float* __restrict__ X,\n const float* __restrict__ y,\n const float* __restrict__ X_test,\n float* __restrict__ pred_mean,\n float* __restrict__ pred_var,\n int B, int N, int D, int M,\n float prior_precision, float noise_precision\n) {\n int b = blockIdx.x;\n if (b >= B) return;\n\n extern __shared__ float smem[];\n\n const float* Xb = X + b * N * D;\n const float* yb = y + b * N;\n const float* Xt = X_test + b * M * D;\n\n float* Lambda = smem;\n float* L = smem + D*D;\n float* rhs = smem + 2*D*D;\n float* mu_post = smem + 2*D*D + D;\n float* Sigma = smem + 2*D*D + 2*D;\n float* temp = smem + 3*D*D + 2*D;\n\n // Initialize Lambda = alpha * I\n for (int i = threadIdx.x; i < D*D; i += blockDim.x) {\n int r = i / D, c = i % D;\n Lambda[i] = (r == c) ? prior_precision : 0.0f;\n }\n __syncthreads();\n\n // Compute beta * X^T X and add to Lambda, X^T y\n for (int i = threadIdx.x; i < D; i += blockDim.x) {\n for (int j = 0; j < D; j++) {\n float sum_xx = 0.0f;\n for (int k = 0; k < N; k++) {\n sum_xx += Xb[k*D + i] * Xb[k*D + j];\n }\n Lambda[i*D + j] += noise_precision * sum_xx;\n }\n float sum_xy = 0.0f;\n for (int k = 0; k < N; k++) {\n sum_xy += Xb[k*D + i] * yb[k];\n }\n rhs[i] = noise_precision * sum_xy;\n }\n __syncthreads();\n\n // Cholesky L of Lambda, lower triangular\n for (int i = 0; i < D; ++i) {\n for (int j = threadIdx.x; j <= i; j += blockDim.x) {\n float s = 0.0f;\n for (int k = 0; k < j; ++k) {\n s += L[i*D + k] * L[j*D + k];\n }\n if (i == j) {\n L[i*D + i] = sqrtf(Lambda[i*D + i] - s);\n } else {\n L[i*D + j] = (Lambda[i*D + j] - s) / L[j*D + j];\n }\n }\n __syncthreads();\n }\n\n // Forward substitution L z = rhs -> mu_post temporarily\n for (int i = 0; i < D; ++i) {\n if (threadIdx.x == 0) {\n float s = 0.0f;\n for (int k = 0; k < i; ++k) s += L[i*D + k] * mu_post[k];\n mu_post[i] = (rhs[i] - s) / L[i*D + i];\n }\n __syncthreads();\n }\n // Backward L^T mu = z\n for (int i = D - " }
result ← run_correctness (fail)
failrun_correctness run_correctness FAILED: kernel did not compile. Syntax error in custom generated code or ModelNew not found
turn 5 · FINAL · 1 tool call(s) · 285.2s turn · 47.5s LLM · tokens in=11,082 · out=1,887 · total=13,046 · 7,725 chars (click to expand)
turn 5285.2s turn · 47.5s LLM · 237.6s tools · tokens in=11,082 · out=1,887 · total=13,046 · FINAL
reasoning
The kernel_code was truncated in the call because of length. The function response shows it cut off.
call → submit_kernel
callsubmit_kernel { "kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void bayesian_linear_kernel(\n const float* __restrict__ X,\n const float* __restrict__ y,\n const float* __restrict__ X_test,\n float* __restrict__ pred_mean,\n float* __restrict__ pred_var,\n int B, int N, int D, int M,\n float prior_precision, float noise_precision\n) {\n int b = blockIdx.x;\n if (b >= B) return;\n\n extern __shared__ float smem[];\n\n const float* Xb = X + b * N * D;\n const float* yb = y + b * N;\n const float* Xt = X_test + b * M * D;\n\n float* Lambda = smem;\n float* L = smem + D*D;\n float* rhs = smem + 2*D*D;\n float* mu_post = smem + 2*D*D + D;\n float* Sigma = smem + 2*D*D + 2*D;\n float* temp = smem + 3*D*D + 2*D;\n\n // Initialize Lambda = alpha * I\n for (int i = threadIdx.x; i < D*D; i += blockDim.x) {\n int r = i / D, c = i % D;\n Lambda[i] = (r == c) ? prior_precision : 0.0f;\n }\n __syncthreads();\n\n // Compute beta * X^T X and add to Lambda, X^T y\n for (int i = threadIdx.x; i < D; i += blockDim.x) {\n for (int j = 0; j < D; j++) {\n float sum_xx = 0.0f;\n for (int k = 0; k < N; k++) {\n sum_xx += Xb[k*D + i] * Xb[k*D + j];\n }\n Lambda[i*D + j] += noise_precision * sum_xx;\n }\n float sum_xy = 0.0f;\n for (int k = 0; k < N; k++) {\n sum_xy += Xb[k*D + i] * yb[k];\n }\n rhs[i] = noise_precision * sum_xy;\n }\n __syncthreads();\n\n // Cholesky L of Lambda, lower triangular\n for (int i = 0; i < D; ++i) {\n for (int j = threadIdx.x; j <= i; j += blockDim.x) {\n float s = 0.0f;\n for (int k = 0; k < j; ++k) {\n s += L[i*D + k] * L[j*D + k];\n }\n if (i == j) {\n L[i*D + i] = sqrtf(Lambda[i*D + i] - s);\n } else {\n L[i*D + j] = (Lambda[i*D + j] - s) / L[j*D + j];\n }\n }\n __syncthreads();\n }\n\n // Forward substitution L z = rhs -> mu_post temporarily\n for (int i = 0; i < D; ++i) {\n if (threadIdx.x == 0) {\n float s = 0.0f;\n for (int k = 0; k < i; ++k) s += L[i*D + k] * mu_post[k];\n mu_post[i] = (rhs[i] - s) / L[i*D + i];\n }\n __syncthreads();\n }\n // Backward L^T mu = z\n for (int i = D - 1; i >= 0; --i) {\n if (threadIdx.x == 0) {\n float s = 0.0f;\n for (int k = i + 1; k < D; ++k) s += L[k*D + i] * mu_post[k];\n mu_post[i] = (mu_post[i] - s) / L[i*D + i];\n }\n __syncthreads();\n }\n\n // pred_mean = X_test @ mu_post\n for (int m = threadIdx.x; m < M; m += blockDim.x) {\n float sum = 0.0f;\n for (int d = 0; d < D; ++d) {\n sum += Xt[m * D + d] * mu_post[d];\n }\n pred_mean[b * M + m] = sum;\n }\n\n // Compute Sigma = inv(Lambda) via cholesky inverse: solve L Y = I then L^T Sigma = Y\n for (int col = 0; col < D; ++col) {\n // solve L Y_col = e_col\n for (int i = 0; i < D; ++i) {\n if (threadIdx.x == 0) {\n float val = (i == col ? 1.0f : 0.0f);\n for (int k = 0; k < i; ++k) val -= L[i*D + k] * temp[k*D + col];\n temp[i*D + col] = val / L[i*D + i];\n }\n __syncthreads();\n }\n // solve L^T Sigma_col = Y_col\n for (int i = D-1; i >= 0; --i) {\n if (threadIdx.x == 0) {\n float val = temp[i*D + col];\n for (int k = i+1; k < D; ++k) val -= L[k*D + i] * Sigma[k*D + col];\n Sigma[i*D + col] = val / L[i*D + i];\n }\n __syncthreads();\n }\n }\n\n // pred_var = diag(X_test @ Sigma @ X_test^T) + 1/beta\n for (int m = threadIdx.x; m < M; m += blockDim.x) {\n float sum = 0.0f;\n for (int d = 0; d < D; ++d) {\n float tmp = 0.0f;\n for (int e = 0; e < D; ++e) {\n tmp += Xt[m*D + e] * Sigma[e * D + d];\n }\n sum += tmp * Xt[m*D + d];\n }\n pred_var[b * M + m] = sum + 1.0f / noise_precision;\n }\n}\n\nstd::vector<torch::Tensor> bayesian_linear_cuda(\n torch::Tensor X, torch::Tensor y, torch::Tensor X_test,\n float prior_precision, float noise_precision\n) {\n int B = X.size(0);\n int N = X.size(1);\n int D = X.size(2);\n int M = X_test.size(1);\n\n auto options = torch::TensorOptions().dtype(X.dtype()).device(X.device());\n auto pred_mean = torch::zeros({B, M, 1}, options);\n auto pred_var = torch::zeros({B, M}, options);\n\n dim3 grid(B);\n dim3 block(256);\n size_t smem_size = (4 * D * D + 2 * D) * sizeof(float);\n\n bayesian_linear_kernel<<<grid, block, smem_size>>>(\n X.data_ptr<float>(), y.data_ptr<float>(), X_test.data_ptr<float>(),\n pred_mean.data_ptr<float>(), pred_var.data_ptr<float>(),\n B, N, D, M, prior_precision, noise_precision\n );\n\n cudaDeviceSynchronize();\n return {pred_mean.view({B, M, 1}), pred_var};\n}\n'''\n\ncpp_source = '''\nstd::vector<torch::Tensor> bayesian_linear_cuda(\n torch::Tensor X, torch::Tensor y, torch::Tensor X_test,\n float prior_precision, float noise_precision\n);\n'''\n\nmodule = load_inline(\n name='bayesian_linear',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['bayesian_linear_cuda'],\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, y, X_test):\n res = module.bayesian_linear_cuda(X, y, X_test, self.prior_precision, self.noise_precision)\n return res[0], res[1]\n" }
result ← submit_kernel (fail)
failsubmit_kernel submit_kernel FAILED: correctness check did not pass ((0 / 5) trials). correctness_issue: Output mismatch max_difference: ['0.052969', '0.009739', '0.054024', '0.010747', '0.065366', '0.009737', '0.067590', '0.014611', '0.040142', '0.009076'] avg_difference: ['0.008337', '0.002116', '0.010259', '0.001980', '0.009305', '0.002084', '0.009591', '0.002139', '0.008055', '0.002041']
final submitted kernel (192 lines, 5,946 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline

cuda_source = r'''
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>

__global__ void bayesian_linear_kernel(
    const float* __restrict__ X,
    const float* __restrict__ y,
    const float* __restrict__ X_test,
    float* __restrict__ pred_mean,
    float* __restrict__ pred_var,
    int B, int N, int D, int M,
    float prior_precision, float noise_precision
) {
    int b = blockIdx.x;
    if (b >= B) return;

    extern __shared__ float smem[];

    const float* Xb = X + b * N * D;
    const float* yb = y + b * N;
    const float* Xt = X_test + b * M * D;

    float* Lambda = smem;
    float* L = smem + D*D;
    float* rhs = smem + 2*D*D;
    float* mu_post = smem + 2*D*D + D;
    float* Sigma = smem + 2*D*D + 2*D;
    float* temp = smem + 3*D*D + 2*D;

    // Initialize Lambda = alpha * I
    for (int i = threadIdx.x; i < D*D; i += blockDim.x) {
        int r = i / D, c = i % D;
        Lambda[i] = (r == c) ? prior_precision : 0.0f;
    }
    __syncthreads();

    // Compute beta * X^T X and add to Lambda, X^T y
    for (int i = threadIdx.x; i < D; i += blockDim.x) {
        for (int j = 0; j < D; j++) {
            float sum_xx = 0.0f;
            for (int k = 0; k < N; k++) {
                sum_xx += Xb[k*D + i] * Xb[k*D + j];
            }
            Lambda[i*D + j] += noise_precision * sum_xx;
        }
        float sum_xy = 0.0f;
        for (int k = 0; k < N; k++) {
            sum_xy += Xb[k*D + i] * yb[k];
        }
        rhs[i] = noise_precision * sum_xy;
    }
    __syncthreads();

    // Cholesky L of Lambda, lower triangular
    for (int i = 0; i < D; ++i) {
        for (int j = threadIdx.x; j <= i; j += blockDim.x) {
            float s = 0.0f;
            for (int k = 0; k < j; ++k) {
                s += L[i*D + k] * L[j*D + k];
            }
            if (i == j) {
                L[i*D + i] = sqrtf(Lambda[i*D + i] - s);
            } else {
                L[i*D + j] = (Lambda[i*D + j] - s) / L[j*D + j];
            }
        }
        __syncthreads();
    }

    // Forward substitution L z = rhs -> mu_post temporarily
    for (int i = 0; i < D; ++i) {
        if (threadIdx.x == 0) {
            float s = 0.0f;
            for (int k = 0; k < i; ++k) s += L[i*D + k] * mu_post[k];
            mu_post[i] = (rhs[i] - s) / L[i*D + i];
        }
        __syncthreads();
    }
    // Backward L^T mu = z
    for (int i = D - 1; i >= 0; --i) {
        if (threadIdx.x == 0) {
            float s = 0.0f;
            for (int k = i + 1; k < D; ++k) s += L[k*D + i] * mu_post[k];
            mu_post[i] = (mu_post[i] - s) / L[i*D + i];
        }
        __syncthreads();
    }

    // pred_mean = X_test @ mu_post
    for (int m = threadIdx.x; m < M; m += blockDim.x) {
        float sum = 0.0f;
        for (int d = 0; d < D; ++d) {
            sum += Xt[m * D + d] * mu_post[d];
        }
        pred_mean[b * M + m] = sum;
    }

    // Compute Sigma = inv(Lambda) via cholesky inverse: solve L Y = I then L^T Sigma = Y
    for (int col = 0; col < D; ++col) {
        // solve L Y_col = e_col
        for (int i = 0; i < D; ++i) {
            if (threadIdx.x == 0) {
                float val = (i == col ? 1.0f : 0.0f);
                for (int k = 0; k < i; ++k) val -= L[i*D + k] * temp[k*D + col];
                temp[i*D + col] = val / L[i*D + i];
            }
            __syncthreads();
        }
        // solve L^T Sigma_col = Y_col
        for (int i = D-1; i >= 0; --i) {
            if (threadIdx.x == 0) {
                float val = temp[i*D + col];
                for (int k = i+1; k < D; ++k) val -= L[k*D + i] * Sigma[k*D + col];
                Sigma[i*D + col] = val / L[i*D + i];
            }
            __syncthreads();
        }
    }

    // pred_var = diag(X_test @ Sigma @ X_test^T) + 1/beta
    for (int m = threadIdx.x; m < M; m += blockDim.x) {
        float sum = 0.0f;
        for (int d = 0; d < D; ++d) {
            float tmp = 0.0f;
            for (int e = 0; e < D; ++e) {
                tmp += Xt[m*D + e] * Sigma[e * D + d];
            }
            sum += tmp * Xt[m*D + d];
        }
        pred_var[b * M + m] = sum + 1.0f / noise_precision;
    }
}

std::vector<torch::Tensor> bayesian_linear_cuda(
    torch::Tensor X, torch::Tensor y, torch::Tensor X_test,
    float prior_precision, float noise_precision
) {
    int B = X.size(0);
    int N = X.size(1);
    int D = X.size(2);
    int M = X_test.size(1);

    auto options = torch::TensorOptions().dtype(X.dtype()).device(X.device());
    auto pred_mean = torch::zeros({B, M, 1}, options);
    auto pred_var = torch::zeros({B, M}, options);

    dim3 grid(B);
    dim3 block(256);
    size_t smem_size = (4 * D * D + 2 * D) * sizeof(float);

    bayesian_linear_kernel<<<grid, block, smem_size>>>(
        X.data_ptr<float>(), y.data_ptr<float>(), X_test.data_ptr<float>(),
        pred_mean.data_ptr<float>(), pred_var.data_ptr<float>(),
        B, N, D, M, prior_precision, noise_precision
    );

    cudaDeviceSynchronize();
    return {pred_mean.view({B, M, 1}), pred_var};
}
'''

cpp_source = '''
std::vector<torch::Tensor> bayesian_linear_cuda(
    torch::Tensor X, torch::Tensor y, torch::Tensor X_test,
    float prior_precision, float noise_precision
);
'''

module = load_inline(
    name='bayesian_linear',
    cpp_sources=cpp_source,
    cuda_sources=cuda_source,
    functions=['bayesian_linear_cuda'],
    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, y, X_test):
        res = module.bayesian_linear_cuda(X, y, X_test, self.prior_precision, self.noise_precision)
        return res[0], res[1]