FW-GLM-5-1 · popcorn · pop_l123_default_gpt
correct 26_ImportanceSampling.py
model
FW-GLM-5-1
turns / max
11 / 12
tool calls
11
tokens (total)
240504
wall clock
4632.9s
truncated
no
backend
cuda fp32
variant
popcorn
runtime
2.48 μs
ref runtime
0.14 μs
speedup
0.06x
started
2026-05-11T11:27:33Z
timingkernelbench.timing
kernel runtime
2.48 μs
ref runtime
0.14 μs
speedup
0.06x
kernel mean / median / std
2.48 / — / 0.00 μs
ref mean / median / std
0.14 / — / 5.33e-04 μs
numerical precisioneval_kernel_against_ref
max abs error
7.99e-06
mean abs error
8.72e-07
max rel error
1.96e-05
mean rel error
1.17e-06
gpu memoryextended_metrics.measure_memory
kernel peak
0.27 MB
ref peak
2.51 MB
kernel / ref
0.11x
kernel launches / fusiontorch.profiler
kernel launches
215
ref launches
88
fusion ratio (ref / kernel)
0.41x
total cuda time
4648 μs
energyNVML (pynvml)
kernel mJ / run
483.72
ref mJ / run
0.00
ratio (ref / kernel)
—
avg power
195.52 W
ref avg power
0.00 W
SOL (speed-of-light)nsight_hardware_counters
SOL score (0–1)
0.243
dram util %
1.2%
compute util %
24.3%
bottleneck
compute-bound
dominant pipe
FP32
arithmetic intensity
—
ridge point
20.00
roofline / occupancynsight_hardware_counters
dram bandwidth
41.31 GB/s
dram util %
1.2%
fp32 tflops
—
fp32 util %
—
fp16 tflops
—
occupancy %
38.6%
bottleneck
compute-bound
dominant pipe %
24.3%
arithmetic intensity
—
ridge point
20.00
L1 hit %
—
L2 hit %
465.1%
ld sectors / req
43.00
st sectors / req
—
regs / thread
125
smem / block
39296 B
block size
784
peak bw
3350.00 GB/s
peak fp32 tflops
67.00
peak fp16 tflops
1979.00
warp stalls (top 5)nsight
short_scoreboard
1453.1%
long_scoreboard
968.0%
mio_throttle
2.6e-04%
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn


class Model(nn.Module):
    """
    Self-normalized importance sampling estimate.
    Given samples from a proposal distribution q, computes importance
    weights w_i = p(x_i)/q(x_i), normalizes them, and returns both
    the weighted estimate of E_p[f(x)] and the effective sample size.

    Target p is a mixture of Gaussians; proposal q is a single Gaussian.
    """

    def __init__(self, dim, num_components=3):
        super().__init__()
        self.dim = dim
        self.num_components = num_components
        # Target mixture components
        self.register_buffer("mix_weights", torch.ones(num_components) / num_components)
        mus = torch.randn(num_components, dim) * 2.0
        self.register_buffer("mix_mus", mus)
        self.register_buffer("mix_stds", torch.ones(num_components, dim))
        # Proposal
        self.register_buffer("q_mu", torch.zeros(dim))
        self.register_buffer("q_std", torch.ones(dim) * 3.0)

    def _log_p(self, x):
        """Log density of target mixture."""
        diff = x.unsqueeze(1) - self.mix_mus.unsqueeze(0)  # (B, K, D)
        log_comp = -0.5 * (diff / self.mix_stds.unsqueeze(0)) ** 2 - self.mix_stds.log().unsqueeze(0)
        log_comp = log_comp.sum(-1)  # (B, K)
        return torch.logsumexp(log_comp + self.mix_weights.log().unsqueeze(0), dim=-1)

    def _log_q(self, x):
        """Log density of proposal."""
        return (-0.5 * ((x - self.q_mu) / self.q_std) ** 2 - self.q_std.log()).sum(-1)

    def forward(self, samples: torch.Tensor) -> tuple:
        """
        Args:
            samples: (N, dim) – samples drawn from q
        Returns:
            (weighted_mean, ess):
                weighted_mean: (dim,) – importance-weighted mean estimate of E_p[x]
                ess: scalar – effective sample size
        """
        log_w = self._log_p(samples) - self._log_q(samples)
        log_w = log_w - torch.logsumexp(log_w, dim=0)
        w = torch.exp(log_w)

        weighted_mean = (w.unsqueeze(-1) * samples).sum(dim=0)
        ess = 1.0 / (w ** 2).sum()
        return weighted_mean, ess


dim = 16
num_samples = 4096


def get_inputs():
    q_std = 3.0
    n = popcorn_pri.jitter_int(num_samples)
    return [torch.randn(n, dim) * q_std]


def get_init_inputs():
    return [dim]
turn 0107.7s turn · 5.5s LLM · 102.2s tools · tokens in=1,831 · out=512 · total=2,343
reasoning
Let me analyze this task. I need to implement a CUDA kernel that computes self-normalized importance sampling. Let me understand the computation: 1. `_log_p(x)` - Log density of target mixture: - `diff = x.unsqueeze(1) - self.mix_mus.unsqueeze(0)` shape: (N, K, D) - `log_comp = -0.5 * (diff / self.mix_stds.unsqueeze(0)) ** 2 - self.mix_stds.log().unsqueeze(0)` - `log_comp = log_comp.sum(-1)` shape: (N, K) - Result: `torch.logsumexp(log_comp + self.mix_weights.log().unsqueeze(0), dim=-1)` shape: (N,) 2. `_log_q(x)` - Log density of proposal: - `(-0.5 * ((x - self.q_mu) / self.q_std) ** 2 - self.q_std.log()).sum(-1)` shape: (N,) 3. `forward()`: - `log_w = self._log_p(samples) - self._log_q(samples)` shape: (N,) - `log_w = log_w - torch.logsumexp(log_w, dim=0)` - normalize - `w = torch.exp(log_w)` shape: (N,) - `weighted_mean = (w.unsqueeze(-1) * samples).sum(dim=0)` shape: (D,) - `ess = 1.0 / (w ** 2).sum()` - scalar Key parameters: - `dim = 16` - `num_samples = 4096` - `num_components = 3` Let me think about how to parallelize this: 1. Computing `log_p` for each sample: - For each sample i, we need to compute the log probability across all K=3 components - The per-component log probability involves summing over dim=16 2. Computing `log_q` for each sample is simpler - just a single Gaussian. 3. After computing log_w, we need: - logsumexp over all samples (reduction) - exponentiation - weighted mean (reduction over samples) - ESS calculation (reduction over samples) Let me get the GPU specs first to understand the hardware.
assistantI'll start by getting the GPU specs to understand the hardware constraints, then implement the CUDA kernel.
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) · 280.1s turn · 39.8s LLM · tokens in=2,099 · out=4,398 · total=6,497 · 18,282 chars (click to expand)
turn 1280.1s turn · 39.8s LLM · 240.4s tools · tokens in=2,099 · out=4,398 · total=6,497
reasoning
Now let me implement the CUDA kernel. The computation involves: 1. Computing log_p(x) for each sample - mixture of Gaussians 2. Computing log_q(x) for each sample - single Gaussian 3. Computing log weights = log_p - log_q 4. Normalizing weights via logsumexp 5. Computing weighted mean and ESS Let me write a kernel that does this efficiently. The key operations: - Log density of mixture: need to compute logsumexp across components - Log density of single Gaussian: simple - Logsumexp across samples for normalization - Reduction for weighted mean and ESS I'll use a single kernel for each major operation to minimize kernel launch overhead.
assistantNow I'll implement the CUDA kernel for this importance sampling computation:
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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Helper for warp-level reduction\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n float max_log_comp = -1e30f;\n float sum_exp = 0.0f;\n \n // Compute log-sum-exp across mixture components\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n float log_weight = logf(mix_weights[k]);\n \n float log_comp = log_weight;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (k == 0 || log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n sum_exp += expf(log_comp - max_log_comp); // Will renormalize later\n }\n \n // Actually need proper logsumexp\n // Recompute with correct max\n sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n float log_weight = logf(mix_weights[k]);\n \n float log_comp = log_weight;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Kernel 1: Compute log weights (log_p - log_q) for all samples\n__global__ void compute_log_weights_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n int N, int dim, int num_components) {\n \n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n log_w[idx] = log_p - log_q;\n }\n}\n\n// Kernel 2: Compute logsumexp reduction\n// Uses two-stage reduction: first block-level, then global\n__global__ void logsumexp_kernel(\n const float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize with thread's value or very negative number\n float my_val = (idx < N) ? log_w[idx] : -1e30f;\n \n // Warp-level max reduction\n float warp_max = warp_reduce_max(my_val);\n \n // Lane 0 of each warp writes to shared memory\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n // First warp reduces the warp maxes\n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Get block max from shared memory (broadcast from thread 0)\n block_max = s_max[0];\n \n // Compute exp(log_w - block_max) for this thread\n float my_exp = (idx < N) ? expf(my_val - block_max) : 0.0f;\n \n // Warp-level sum reduction\n float warp_sum = warp_reduce_sum(my_exp);\n \n // Lane 0 of each warp writes to shared memory\n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n // First warp reduces the warp sums\n float block_sum;\n if (warp_id == 0) {\n block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\n// Kernel 3: Normalize weights and compute weighted mean and ESS\n__global__ void normalize_and_reduce_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ weighted_mean_partial,\n float* __restrict__ ess_partial,\n int N, int dim) {\n \n __shared__ float s_mean[BLOCK_SIZE][32]; // partial sums for mean (up to dim=32)\n __shared__ float s_ess[BLOCK_SIZE];\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory\n for (int d = tid; d < dim && d < 32; d += blockDim.x) {\n s_mean[tid][d] = 0.0f;\n }\n s_ess[tid] = 0.0f;\n __syncthreads();\n \n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Accumulate weighted mean and ESS\n for (int d = 0; d < dim && d < 32; d++) {\n atomicAdd(&s_mean[0][d], w * sample[d]);\n }\n atomicAdd(&s_ess[0], w * w);\n }\n __syncthreads();\n \n // Write partial results\n if (tid == 0) {\n for (int d = 0; d < dim && d < 32; d++) {\n weighted_mean_partial[blockIdx.x * dim + d] = s_mean[0][d];\n }\n ess_partial[blockIdx.x] = s_ess[0];\n }\n}\n\n// Final reduction kernel for weighted mean and ESS\n__global__ void final_reduce_kernel(\n const float* __restrict__ weighted_mean_partial,\n const float* __restrict__ ess_partial,\n float* __restrict__ weighted_mean_out,\n float* __restrict__ ess_out,\n int num_blocks, int dim) {\n \n __shared__ float s_mean[32];\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n \n if (tid < dim && tid < 32) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += weighted_mean_partial[b * dim + tid];\n }\n s_mean[tid] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partial[b];\n }\n s_ess = sum;\n }\n __syncthreads();\n \n if (tid < dim && tid < 32) {\n weighted_mean_out[tid] = s_mean[tid];\n }\n if (tid == 0) {\n ess_out[0] = 1.0f / s_ess;\n }\n}\n\n// Alternative single-kernel approach for better performance\n__global__ void importance_sampling_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n extern __shared__ float shared_mem[];\n float* s_max = shared_mem; // BLOCK_SIZE / WARP_SIZE elements\n float* s_sum = s_max + (BLOCK_SIZE / WARP_SIZE); // BLOCK_SIZE / WARP_SIZE elements\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level logsumexp\n // Warp-level max reduction\n float warp_max = warp_reduce_max(my_log_w);\n \n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Broadcast block_max (read from shared or global depending on timing)\n __shared__ float s_block_max;\n if (tid == 0) {\n s_block_max = block_maxes[blockIdx.x];\n }\n __syncthreads();\n block_max = s_block_max;\n \n // Compute exp(log_w - block_max)\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n \n // Warp-level sum reduction\n float warp_sum = warp_reduce_sum(my_exp);\n \n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n // Allocate intermediate buffers\n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch combined kernel\n size_t shared_mem_size = 2 * (BLOCK_SIZE / WARP_SIZE) * sizeof(float);\n \n importance_sampling_kernel<<<num_blocks, BLOCK_SIZE, shared_mem_size>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // Second pass: compute global logsumexp\n // We need to launch a small kernel or do it on CPU for the block results\n // For simplicity, use a small kernel\n auto block_maxes_2 = torch::empty({1}, options);\n auto block_sums_2 = torch::empty({1}, options);\n \n int num_blocks_2 = (num_blocks + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n // For now, do the final logsumexp reduction on CPU (small data)\n // This is not ideal but works for correctness\n torch::Tensor block_maxes_cpu = block_maxes.cpu();\n torch::Tensor block_sums_cpu = block_sums.cpu();\n \n float global_max = block_maxes_cpu[0].item<float>();\n for (int i = 1; i < num_blocks; i++) {\n float val = block_maxes_cpu[i].item<float>();\n if (val > global_max) global_max = val;\n }\n \n float sum_exp = 0.0f;\n for (int i = 0; i < num_blocks; i++) {\n float max_i = block_maxes_cpu[i].item<float>();\n float sum_i = block_sums_cpu[i].item<float>();\n // Renormalize: exp(max_i) * sum_i -> exp(global_max) * exp(max_i - global_max) * sum_i\n sum_exp += expf(max_i - global_max) * sum_i;\n }\n \n float global_logsumexp = global_max + logf(sum_exp);\n \n // Third pass: normalize and compute weighted mean and ESS\n auto weighted_mean_partial = torch::zeros({num_blocks, dim}, options);\n auto ess_partial = torch::zeros({num_blocks}, options);\n \n normalize_and_reduce_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp,\n weighted_mean_partial.data_ptr<float>(),\n ess_partial.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean_out = torch::empty({dim}, options);\n auto ess_out = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, dim>>>(\n weighted_mean_partial.data_ptr<float>(),\n ess_partial.data_ptr<float>(),\n weighted_mean_out.data_ptr<float>(),\n ess_out.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean_out, ess_out);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n # Ensure contiguous and on same device\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 2 · 1 tool call(s) · 166.2s turn · 33.9s LLM · tokens in=6,365 · out=4,253 · total=10,618 · 17,629 chars (click to expand)
turn 2166.2s turn · 33.9s LLM · 132.3s tools · tokens in=6,365 · out=4,253 · total=10,618
reasoning
Good, it compiled. Now let me run correctness test.
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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Helper for warp-level reduction\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n float max_log_comp = -1e30f;\n float sum_exp = 0.0f;\n \n // Compute log-sum-exp across mixture components\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n float log_weight = logf(mix_weights[k]);\n \n float log_comp = log_weight;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (k == 0 || log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n sum_exp += expf(log_comp - max_log_comp); // Will renormalize later\n }\n \n // Actually need proper logsumexp\n // Recompute with correct max\n sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n float log_weight = logf(mix_weights[k]);\n \n float log_comp = log_weight;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Kernel 1: Compute log weights (log_p - log_q) for all samples\n__global__ void compute_log_weights_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n int N, int dim, int num_components) {\n \n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n log_w[idx] = log_p - log_q;\n }\n}\n\n// Kernel 2: Compute logsumexp reduction\n// Uses two-stage reduction: first block-level, then global\n__global__ void logsumexp_kernel(\n const float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize with thread's value or very negative number\n float my_val = (idx < N) ? log_w[idx] : -1e30f;\n \n // Warp-level max reduction\n float warp_max = warp_reduce_max(my_val);\n \n // Lane 0 of each warp writes to shared memory\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n // First warp reduces the warp maxes\n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Get block max from shared memory (broadcast from thread 0)\n block_max = s_max[0];\n \n // Compute exp(log_w - block_max) for this thread\n float my_exp = (idx < N) ? expf(my_val - block_max) : 0.0f;\n \n // Warp-level sum reduction\n float warp_sum = warp_reduce_sum(my_exp);\n \n // Lane 0 of each warp writes to shared memory\n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n // First warp reduces the warp sums\n float block_sum;\n if (warp_id == 0) {\n block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\n// Kernel 3: Normalize weights and compute weighted mean and ESS\n__global__ void normalize_and_reduce_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ weighted_mean_partial,\n float* __restrict__ ess_partial,\n int N, int dim) {\n \n __shared__ float s_mean[BLOCK_SIZE][32]; // partial sums for mean (up to dim=32)\n __shared__ float s_ess[BLOCK_SIZE];\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory\n for (int d = tid; d < dim && d < 32; d += blockDim.x) {\n s_mean[tid][d] = 0.0f;\n }\n s_ess[tid] = 0.0f;\n __syncthreads();\n \n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Accumulate weighted mean and ESS\n for (int d = 0; d < dim && d < 32; d++) {\n atomicAdd(&s_mean[0][d], w * sample[d]);\n }\n atomicAdd(&s_ess[0], w * w);\n }\n __syncthreads();\n \n // Write partial results\n if (tid == 0) {\n for (int d = 0; d < dim && d < 32; d++) {\n weighted_mean_partial[blockIdx.x * dim + d] = s_mean[0][d];\n }\n ess_partial[blockIdx.x] = s_ess[0];\n }\n}\n\n// Final reduction kernel for weighted mean and ESS\n__global__ void final_reduce_kernel(\n const float* __restrict__ weighted_mean_partial,\n const float* __restrict__ ess_partial,\n float* __restrict__ weighted_mean_out,\n float* __restrict__ ess_out,\n int num_blocks, int dim) {\n \n __shared__ float s_mean[32];\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n \n if (tid < dim && tid < 32) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += weighted_mean_partial[b * dim + tid];\n }\n s_mean[tid] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partial[b];\n }\n s_ess = sum;\n }\n __syncthreads();\n \n if (tid < dim && tid < 32) {\n weighted_mean_out[tid] = s_mean[tid];\n }\n if (tid == 0) {\n ess_out[0] = 1.0f / s_ess;\n }\n}\n\n// Alternative single-kernel approach for better performance\n__global__ void importance_sampling_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n extern __shared__ float shared_mem[];\n float* s_max = shared_mem; // BLOCK_SIZE / WARP_SIZE elements\n float* s_sum = s_max + (BLOCK_SIZE / WARP_SIZE); // BLOCK_SIZE / WARP_SIZE elements\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level logsumexp\n // Warp-level max reduction\n float warp_max = warp_reduce_max(my_log_w);\n \n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Broadcast block_max (read from shared or global depending on timing)\n __shared__ float s_block_max;\n if (tid == 0) {\n s_block_max = block_maxes[blockIdx.x];\n }\n __syncthreads();\n block_max = s_block_max;\n \n // Compute exp(log_w - block_max)\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n \n // Warp-level sum reduction\n float warp_sum = warp_reduce_sum(my_exp);\n \n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n // Allocate intermediate buffers\n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch combined kernel\n size_t shared_mem_size = 2 * (BLOCK_SIZE / WARP_SIZE) * sizeof(float);\n \n importance_sampling_kernel<<<num_blocks, BLOCK_SIZE, shared_mem_size>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // Second pass: compute global logsumexp\n // We need to launch a small kernel or do it on CPU for the block results\n // For simplicity, use a small kernel\n auto block_maxes_2 = torch::empty({1}, options);\n auto block_sums_2 = torch::empty({1}, options);\n \n int num_blocks_2 = (num_blocks + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n // For now, do the final logsumexp reduction on CPU (small data)\n // This is not ideal but works for correctness\n torch::Tensor block_maxes_cpu = block_maxes.cpu();\n torch::Tensor block_sums_cpu = block_sums.cpu();\n \n float global_max = block_maxes_cpu[0].item<float>();\n for (int i = 1; i < num_blocks; i++) {\n float val = block_maxes_cpu[i].item<float>();\n if (val > global_max) global_max = val;\n }\n \n float sum_exp = 0.0f;\n for (int i = 0; i < num_blocks; i++) {\n float max_i = block_maxes_cpu[i].item<float>();\n float sum_i = block_sums_cpu[i].item<float>();\n // Renormalize: exp(max_i) * sum_i -> exp(global_max) * exp(max_i - global_max) * sum_i\n sum_exp += expf(max_i - global_max) * sum_i;\n }\n \n float global_logsumexp = global_max + logf(sum_exp);\n \n // Third pass: normalize and compute weighted mean and ESS\n auto weighted_mean_partial = torch::zeros({num_blocks, dim}, options);\n auto ess_partial = torch::zeros({num_blocks}, options);\n \n normalize_and_reduce_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp,\n weighted_mean_partial.data_ptr<float>(),\n ess_partial.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean_out = torch::empty({dim}, options);\n auto ess_out = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, dim>>>(\n weighted_mean_partial.data_ptr<float>(),\n ess_partial.data_ptr<float>(),\n weighted_mean_out.data_ptr<float>(),\n ess_out.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean_out, ess_out);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n # Ensure contiguous and on same device\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← run_correctness (ok)
okrun_correctness run_correctness PASSED: (5 / 5) trials all matched the reference. Numerical precision: max_abs_err=7.99e-06 mean_abs_err=8.77e-07 max_rel_err=1.96e-05
turn 3 · 1 tool call(s) · 265.2s turn · 31.7s LLM · tokens in=10,663 · out=3,632 · total=14,295 · 15,323 chars (click to expand)
turn 3265.2s turn · 31.7s LLM · 233.5s tools · tokens in=10,663 · out=3,632 · total=14,295
reasoning
The correctness check passed. Now let me optimize the kernel for better performance. There are a few issues I should address: 1. The CPU fallback for logsumexp reduction is inefficient - I should do this on GPU 2. The normalize_and_reduce_kernel uses atomic operations which can be slow 3. The final_reduce_kernel is launched with just one block Let me create an optimized version that: 1. Does the logsumexp reduction entirely on GPU 2. Uses more efficient reduction techniques 3. Uses shared memory better for the weighted mean and ESS computation
assistantThe kernel passes correctness! Let me optimize it for better performance. I'll create a more efficient version that does all reductions on GPU:
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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Warp-level reductions\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Block-level reductions using shared memory\n__device__ void block_reduce_max(float* s_data, float val) {\n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n \n // Warp-level reduction\n val = warp_reduce_max(val);\n \n // Write warp result to shared memory\n if (lane_id == 0) {\n s_data[warp_id] = val;\n }\n __syncthreads();\n \n // First warp does final reduction\n if (warp_id == 0) {\n val = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_data[lane_id] : -1e30f;\n val = warp_reduce_max(val);\n if (lane_id == 0) {\n s_data[0] = val;\n }\n }\n __syncthreads();\n}\n\n__device__ void block_reduce_sum(float* s_data, float val) {\n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n \n // Warp-level reduction\n val = warp_reduce_sum(val);\n \n // Write warp result to shared memory\n if (lane_id == 0) {\n s_data[warp_id] = val;\n }\n __syncthreads();\n \n // First warp does final reduction\n if (warp_id == 0) {\n val = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_data[lane_id] : 0.0f;\n val = warp_reduce_sum(val);\n if (lane_id == 0) {\n s_data[0] = val;\n }\n }\n __syncthreads();\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n // First pass: find max log_comp\n float max_log_comp = -1e30f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n }\n \n // Second pass: compute sum of exp(log_comp - max_log_comp)\n float sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Main kernel: computes log weights and block-level reductions\n__global__ void importance_sampling_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n __shared__ float s_data[BLOCK_SIZE / WARP_SIZE + 1]; // +1 to avoid bank conflicts\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level max reduction for logsumexp\n block_reduce_max(s_data, my_log_w);\n float block_max = s_data[0];\n \n // Stage 3: Compute exp(log_w - block_max) and sum\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n block_reduce_sum(s_data, my_exp);\n \n // Store block-level results\n if (tid == 0) {\n block_maxes[blockIdx.x] = block_max;\n block_sums[blockIdx.x] = s_data[0];\n }\n}\n\n// Kernel to finalize logsumexp from block results\n__global__ void logsumexp_finalize_kernel(\n const float* __restrict__ block_maxes,\n const float* __restrict__ block_sums,\n float* __restrict__ global_logsumexp,\n int num_blocks) {\n \n __shared__ float s_data[BLOCK_SIZE / WARP_SIZE + 1];\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Find global max\n float my_max = (idx < num_blocks) ? block_maxes[idx] : -1e30f;\n block_reduce_max(s_data, my_max);\n float global_max = s_data[0];\n \n // Compute sum of exp(max_i - global_max) * sum_i\n float my_val = (idx < num_blocks) ? expf(block_maxes[idx] - global_max) * block_sums[idx] : 0.0f;\n block_reduce_sum(s_data, my_val);\n \n if (tid == 0) {\n global_logsumexp[0] = global_max + logf(s_data[0]);\n }\n}\n\n// Kernel to compute weighted mean and ESS\n__global__ void weighted_mean_ess_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ mean_partials,\n float* __restrict__ ess_partials,\n int N, int dim) {\n \n // Use dynamically sized shared memory\n extern __shared__ float s_mem[];\n float* s_mean = s_mem; // dim elements\n float* s_ess = s_mean + dim;\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory\n for (int d = tid; d < dim; d += blockDim.x) {\n s_mean[d] = 0.0f;\n }\n if (tid == 0) s_ess[0] = 0.0f;\n __syncthreads();\n \n // Compute weight and accumulate\n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Thread-local accumulations\n for (int d = tid % dim; d < dim; d += blockDim.x) {\n atomicAdd(&s_mean[d], w * sample[d]);\n }\n atomicAdd(s_ess, w * w);\n }\n __syncthreads();\n \n // Write partial results\n for (int d = tid; d < dim; d += blockDim.x) {\n mean_partials[blockIdx.x * dim + d] = s_mean[d];\n }\n if (tid == 0) {\n ess_partials[blockIdx.x] = s_ess[0];\n }\n}\n\n// Final reduction kernel\n__global__ void final_reduce_kernel(\n const float* __restrict__ mean_partials,\n const float* __restrict__ ess_partials,\n float* __restrict__ weighted_mean,\n float* __restrict__ ess,\n int num_blocks, int dim) {\n \n extern __shared__ float s_mem[];\n float* s_mean = s_mem;\n float* s_ess = s_mean + dim;\n \n int tid = threadIdx.x;\n \n // Sum across blocks\n for (int d = tid; d < dim; d += blockDim.x) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += mean_partials[b * dim + d];\n }\n s_mean[d] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partials[b];\n }\n s_ess[0] = sum;\n }\n __syncthreads();\n \n // Write final results\n for (int d = tid; d < dim; d += blockDim.x) {\n weighted_mean[d] = s_mean[d];\n }\n if (tid == 0) {\n ess[0] = 1.0f / s_ess[0];\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch main kernel\n importance_sampling_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // Finalize logsumexp\n auto global_logsumexp = torch::empty({1}, options);\n logsumexp_finalize_kernel<<<1, BLOCK_SIZE>>>(\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n global_logsumexp.data_ptr<float>(),\n num_blocks\n );\n \n // Compute weighted mean and ESS\n auto mean_partials = torch::zeros({num_blocks, dim}, options);\n auto ess_partials = torch::zeros({num_blocks}, options);\n \n size_t shared_mem_size = (dim + 1) * sizeof(float);\n weighted_mean_ess_kernel<<<num_blocks, BLOCK_SIZE, shared_mem_size>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp.item<float>(),\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean = torch::empty({dim}, options);\n auto ess = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, dim, shared_mem_size>>>(\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n weighted_mean.data_ptr<float>(),\n ess.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean, ess);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext_v2',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 4 · 1 tool call(s) · 306.2s turn · 28.5s LLM · tokens in=14,194 · out=3,499 · total=17,693 · 14,889 chars (click to expand)
turn 4306.2s turn · 28.5s LLM · 277.7s tools · tokens in=14,194 · out=3,499 · total=17,693
reasoning
Good, let me 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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Warp-level reductions\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Block-level reductions using shared memory\n__device__ void block_reduce_max(float* s_data, float val) {\n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n \n // Warp-level reduction\n val = warp_reduce_max(val);\n \n // Write warp result to shared memory\n if (lane_id == 0) {\n s_data[warp_id] = val;\n }\n __syncthreads();\n \n // First warp does final reduction\n if (warp_id == 0) {\n val = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_data[lane_id] : -1e30f;\n val = warp_reduce_max(val);\n if (lane_id == 0) {\n s_data[0] = val;\n }\n }\n __syncthreads();\n}\n\n__device__ void block_reduce_sum(float* s_data, float val) {\n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n \n // Warp-level reduction\n val = warp_reduce_sum(val);\n \n // Write warp result to shared memory\n if (lane_id == 0) {\n s_data[warp_id] = val;\n }\n __syncthreads();\n \n // First warp does final reduction\n if (warp_id == 0) {\n val = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_data[lane_id] : 0.0f;\n val = warp_reduce_sum(val);\n if (lane_id == 0) {\n s_data[0] = val;\n }\n }\n __syncthreads();\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n // First pass: find max log_comp\n float max_log_comp = -1e30f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n }\n \n // Second pass: compute sum of exp(log_comp - max_log_comp)\n float sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Main kernel: computes log weights and block-level reductions\n__global__ void importance_sampling_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n __shared__ float s_data[BLOCK_SIZE / WARP_SIZE + 1]; // +1 to avoid bank conflicts\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level max reduction for logsumexp\n block_reduce_max(s_data, my_log_w);\n float block_max = s_data[0];\n \n // Stage 3: Compute exp(log_w - block_max) and sum\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n block_reduce_sum(s_data, my_exp);\n \n // Store block-level results\n if (tid == 0) {\n block_maxes[blockIdx.x] = block_max;\n block_sums[blockIdx.x] = s_data[0];\n }\n}\n\n// Kernel to finalize logsumexp from block results\n__global__ void logsumexp_finalize_kernel(\n const float* __restrict__ block_maxes,\n const float* __restrict__ block_sums,\n float* __restrict__ global_logsumexp,\n int num_blocks) {\n \n __shared__ float s_data[BLOCK_SIZE / WARP_SIZE + 1];\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Find global max\n float my_max = (idx < num_blocks) ? block_maxes[idx] : -1e30f;\n block_reduce_max(s_data, my_max);\n float global_max = s_data[0];\n \n // Compute sum of exp(max_i - global_max) * sum_i\n float my_val = (idx < num_blocks) ? expf(block_maxes[idx] - global_max) * block_sums[idx] : 0.0f;\n block_reduce_sum(s_data, my_val);\n \n if (tid == 0) {\n global_logsumexp[0] = global_max + logf(s_data[0]);\n }\n}\n\n// Kernel to compute weighted mean and ESS\n__global__ void weighted_mean_ess_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ mean_partials,\n float* __restrict__ ess_partials,\n int N, int dim) {\n \n // Use dynamically sized shared memory\n extern __shared__ float s_mem[];\n float* s_mean = s_mem; // dim elements\n float* s_ess = s_mean + dim;\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory\n for (int d = tid; d < dim; d += blockDim.x) {\n s_mean[d] = 0.0f;\n }\n if (tid == 0) s_ess[0] = 0.0f;\n __syncthreads();\n \n // Compute weight and accumulate\n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Thread-local accumulations\n for (int d = tid % dim; d < dim; d += blockDim.x) {\n atomicAdd(&s_mean[d], w * sample[d]);\n }\n atomicAdd(s_ess, w * w);\n }\n __syncthreads();\n \n // Write partial results\n for (int d = tid; d < dim; d += blockDim.x) {\n mean_partials[blockIdx.x * dim + d] = s_mean[d];\n }\n if (tid == 0) {\n ess_partials[blockIdx.x] = s_ess[0];\n }\n}\n\n// Final reduction kernel\n__global__ void final_reduce_kernel(\n const float* __restrict__ mean_partials,\n const float* __restrict__ ess_partials,\n float* __restrict__ weighted_mean,\n float* __restrict__ ess,\n int num_blocks, int dim) {\n \n extern __shared__ float s_mem[];\n float* s_mean = s_mem;\n float* s_ess = s_mean + dim;\n \n int tid = threadIdx.x;\n \n // Sum across blocks\n for (int d = tid; d < dim; d += blockDim.x) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += mean_partials[b * dim + d];\n }\n s_mean[d] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partials[b];\n }\n s_ess[0] = sum;\n }\n __syncthreads();\n \n // Write final results\n for (int d = tid; d < dim; d += blockDim.x) {\n weighted_mean[d] = s_mean[d];\n }\n if (tid == 0) {\n ess[0] = 1.0f / s_ess[0];\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch main kernel\n importance_sampling_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // Finalize logsumexp\n auto global_logsumexp = torch::empty({1}, options);\n logsumexp_finalize_kernel<<<1, BLOCK_SIZE>>>(\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n global_logsumexp.data_ptr<float>(),\n num_blocks\n );\n \n // Compute weighted mean and ESS\n auto mean_partials = torch::zeros({num_blocks, dim}, options);\n auto ess_partials = torch::zeros({num_blocks}, options);\n \n size_t shared_mem_size = (dim + 1) * sizeof(float);\n weighted_mean_ess_kernel<<<num_blocks, BLOCK_SIZE, shared_mem_size>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp.item<float>(),\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean = torch::empty({dim}, options);\n auto ess = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, dim, shared_mem_size>>>(\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n weighted_mean.data_ptr<float>(),\n ess.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean, ess);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext_v2',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← run_correctness (fail)
failrun_correctness run_correctness FAILED: (0 / 5) trials did not all match. correctness_issue: Output mismatch max_difference: ['4.393768', '3.570274', '4.362292', '6.711818', '2.806369'] avg_difference: ['1.982900', '1.370631', '1.785097', '1.689939', '1.177099']
turn 5 · 1 tool call(s) · 446.5s turn · 35.5s LLM · tokens in=17,796 · out=3,935 · total=21,731 · 16,366 chars (click to expand)
turn 5446.5s turn · 35.5s LLM · 411.1s tools · tokens in=17,796 · out=3,935 · total=21,731
reasoning
The correctness test failed. I suspect the issue is in the logsumexp calculation. The problem is that when I do the block-level reduction, I need to be more careful about how I'm computing the partial sums. Let me think about this more carefully. For logsumexp: 1. Each block computes its local max and sum of exp(x - local_max) 2. When combining blocks, I need to: - Find global max - Rescale each block's sum: sum_i * exp(max_i - global_max) But there's a subtlety - when I use atomicAdd in shared memory, there could be race conditions. Also, the mean accumulation logic might be wrong. Let me debug by going back to a simpler approach that I know works, and optimize from there. Actually, looking at my weighted_mean_ess_kernel, there's a bug in the mean accumulation: ```cpp for (int d = tid % dim; d < dim; d += blockDim.x) { atomicAdd(&s_mean[d], w * sample[d]); } ``` This doesn't make sense. `tid % dim` can be up to 255 % 16 = 15, which is within range, but `d += blockDim.x` jumps by 256, so for dim=16, this loop only executes once at most (if tid % dim < 16). This should actually work, but let me reconsider. Actually wait, the bigger issue is that I'm using atomicAdd in shared memory, which is inefficient and might have precision issues. Let me go back to the working version and fix the CPU-side logsumexp to be GPU-side properly.
assistantThe correctness failed. Let me debug by going back to a simpler approach that I know works:
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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Warp-level reductions\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n // First pass: find max log_comp\n float max_log_comp = -1e30f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n }\n \n // Second pass: compute sum of exp(log_comp - max_log_comp)\n float sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Kernel: Compute log weights (log_p - log_q) for all samples\n__global__ void compute_log_weights_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level max reduction for logsumexp\n float warp_max = warp_reduce_max(my_log_w);\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Read block_max from shared memory (broadcast by warp 0)\n block_max = s_max[0];\n \n // Stage 3: Compute exp(log_w - block_max) and sum\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n float warp_sum = warp_reduce_sum(my_exp);\n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\n// Kernel to finalize global logsumexp\n__global__ void logsumexp_global_kernel(\n const float* __restrict__ block_maxes,\n const float* __restrict__ block_sums,\n float* __restrict__ global_logsumexp,\n int num_blocks) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Find global max across blocks\n float my_max = (idx < num_blocks) ? block_maxes[idx] : -1e30f;\n float warp_max = warp_reduce_max(my_max);\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float global_max;\n if (warp_id == 0) {\n global_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n global_max = warp_reduce_max(global_max);\n if (lane_id == 0) {\n s_max[0] = global_max;\n }\n }\n __syncthreads();\n global_max = s_max[0];\n \n // Compute sum of exp(max_i - global_max) * sum_i\n float my_val = (idx < num_blocks) ? expf(block_maxes[idx] - global_max) * block_sums[idx] : 0.0f;\n float warp_val = warp_reduce_sum(my_val);\n if (lane_id == 0) {\n s_sum[warp_id] = warp_val;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float global_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n global_sum = warp_reduce_sum(global_sum);\n if (lane_id == 0) {\n global_logsumexp[0] = global_max + logf(global_sum);\n }\n }\n}\n\n// Kernel to compute weighted mean partial sums and ESS partial sums\n__global__ void weighted_mean_ess_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ mean_partials,\n float* __restrict__ ess_partials,\n int N, int dim) {\n \n __shared__ float s_mean[64]; // Support dim up to 64\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory\n for (int d = tid; d < dim && d < 64; d += blockDim.x) {\n s_mean[d] = 0.0f;\n }\n if (tid == 0) s_ess = 0.0f;\n __syncthreads();\n \n // Compute weight and accumulate\n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Accumulate weighted mean\n for (int d = 0; d < dim && d < 64; d++) {\n atomicAdd(&s_mean[d], w * sample[d]);\n }\n // Accumulate ESS\n atomicAdd(&s_ess, w * w);\n }\n __syncthreads();\n \n // Write partial results\n for (int d = tid; d < dim && d < 64; d += blockDim.x) {\n mean_partials[blockIdx.x * dim + d] = s_mean[d];\n }\n if (tid == 0) {\n ess_partials[blockIdx.x] = s_ess;\n }\n}\n\n// Final reduction kernel\n__global__ void final_reduce_kernel(\n const float* __restrict__ mean_partials,\n const float* __restrict__ ess_partials,\n float* __restrict__ weighted_mean,\n float* __restrict__ ess,\n int num_blocks, int dim) {\n \n __shared__ float s_mean[64];\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n \n // Sum across blocks\n for (int d = tid; d < dim && d < 64; d += blockDim.x) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += mean_partials[b * dim + d];\n }\n s_mean[d] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partials[b];\n }\n s_ess = sum;\n }\n __syncthreads();\n \n // Write final results\n for (int d = tid; d < dim && d < 64; d += blockDim.x) {\n weighted_mean[d] = s_mean[d];\n }\n if (tid == 0) {\n ess[0] = 1.0f / s_ess;\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n TORCH_CHECK(dim <= 64, \"dim must be <= 64\");\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch kernel to compute log weights and block reductions\n compute_log_weights_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // Finalize global logsumexp\n auto global_logsumexp = torch::empty({1}, options);\n logsumexp_global_kernel<<<1, BLOCK_SIZE>>>(\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n global_logsumexp.data_ptr<float>(),\n num_blocks\n );\n \n // Compute weighted mean and ESS\n auto mean_partials = torch::zeros({num_blocks, dim}, options);\n auto ess_partials = torch::zeros({num_blocks}, options);\n \n weighted_mean_ess_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp.item<float>(),\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean = torch::empty({dim}, options);\n auto ess = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, 64>>>(\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n weighted_mean.data_ptr<float>(),\n ess.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean, ess);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext_v3',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 6 · 1 tool call(s) · 1803.6s turn · 29.7s LLM · tokens in=21,403 · out=3,584 · total=24,987 · 15,583 chars (click to expand)
turn 61803.6s turn · 29.7s LLM · 1773.9s tools · tokens in=21,403 · out=3,584 · total=24,987
reasoning
Now let me run the correctness test.
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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Warp-level reductions\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n // First pass: find max log_comp\n float max_log_comp = -1e30f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n }\n \n // Second pass: compute sum of exp(log_comp - max_log_comp)\n float sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Kernel: Compute log weights (log_p - log_q) for all samples\n__global__ void compute_log_weights_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level max reduction for logsumexp\n float warp_max = warp_reduce_max(my_log_w);\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Read block_max from shared memory (broadcast by warp 0)\n block_max = s_max[0];\n \n // Stage 3: Compute exp(log_w - block_max) and sum\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n float warp_sum = warp_reduce_sum(my_exp);\n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\n// Kernel to finalize global logsumexp\n__global__ void logsumexp_global_kernel(\n const float* __restrict__ block_maxes,\n const float* __restrict__ block_sums,\n float* __restrict__ global_logsumexp,\n int num_blocks) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Find global max across blocks\n float my_max = (idx < num_blocks) ? block_maxes[idx] : -1e30f;\n float warp_max = warp_reduce_max(my_max);\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float global_max;\n if (warp_id == 0) {\n global_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n global_max = warp_reduce_max(global_max);\n if (lane_id == 0) {\n s_max[0] = global_max;\n }\n }\n __syncthreads();\n global_max = s_max[0];\n \n // Compute sum of exp(max_i - global_max) * sum_i\n float my_val = (idx < num_blocks) ? expf(block_maxes[idx] - global_max) * block_sums[idx] : 0.0f;\n float warp_val = warp_reduce_sum(my_val);\n if (lane_id == 0) {\n s_sum[warp_id] = warp_val;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float global_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n global_sum = warp_reduce_sum(global_sum);\n if (lane_id == 0) {\n global_logsumexp[0] = global_max + logf(global_sum);\n }\n }\n}\n\n// Kernel to compute weighted mean partial sums and ESS partial sums\n__global__ void weighted_mean_ess_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ mean_partials,\n float* __restrict__ ess_partials,\n int N, int dim) {\n \n __shared__ float s_mean[64]; // Support dim up to 64\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory\n for (int d = tid; d < dim && d < 64; d += blockDim.x) {\n s_mean[d] = 0.0f;\n }\n if (tid == 0) s_ess = 0.0f;\n __syncthreads();\n \n // Compute weight and accumulate\n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Accumulate weighted mean\n for (int d = 0; d < dim && d < 64; d++) {\n atomicAdd(&s_mean[d], w * sample[d]);\n }\n // Accumulate ESS\n atomicAdd(&s_ess, w * w);\n }\n __syncthreads();\n \n // Write partial results\n for (int d = tid; d < dim && d < 64; d += blockDim.x) {\n mean_partials[blockIdx.x * dim + d] = s_mean[d];\n }\n if (tid == 0) {\n ess_partials[blockIdx.x] = s_ess;\n }\n}\n\n// Final reduction kernel\n__global__ void final_reduce_kernel(\n const float* __restrict__ mean_partials,\n const float* __restrict__ ess_partials,\n float* __restrict__ weighted_mean,\n float* __restrict__ ess,\n int num_blocks, int dim) {\n \n __shared__ float s_mean[64];\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n \n // Sum across blocks\n for (int d = tid; d < dim && d < 64; d += blockDim.x) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += mean_partials[b * dim + d];\n }\n s_mean[d] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partials[b];\n }\n s_ess = sum;\n }\n __syncthreads();\n \n // Write final results\n for (int d = tid; d < dim && d < 64; d += blockDim.x) {\n weighted_mean[d] = s_mean[d];\n }\n if (tid == 0) {\n ess[0] = 1.0f / s_ess;\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n TORCH_CHECK(dim <= 64, \"dim must be <= 64\");\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch kernel to compute log weights and block reductions\n compute_log_weights_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // Finalize global logsumexp\n auto global_logsumexp = torch::empty({1}, options);\n logsumexp_global_kernel<<<1, BLOCK_SIZE>>>(\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n global_logsumexp.data_ptr<float>(),\n num_blocks\n );\n \n // Compute weighted mean and ESS\n auto mean_partials = torch::zeros({num_blocks, dim}, options);\n auto ess_partials = torch::zeros({num_blocks}, options);\n \n weighted_mean_ess_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp.item<float>(),\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean = torch::empty({dim}, options);\n auto ess = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, 64>>>(\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n weighted_mean.data_ptr<float>(),\n ess.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean, ess);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext_v3',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← run_correctness (fail)
failrun_correctness run_correctness FAILED: (0 / 5) trials did not all match. correctness_issue: Output mismatch max_difference: ['4.393766', '1814721617361733719420829696.000000', '3.572236', '23222591816728576.000000', '4.362287', '7435976383701434324868931780608.000000', '6.717838', '367217917101604864.000000', '2.622046', '312109200247843979264.000000'] avg_difference: ['2.140126', '1814721617361733719420829696.000000', '1.416228', '23222591816728576.000000', '1.812993', '7435976383701434324868931780608.000000', '1.729157', '367217917101604864.000000', '1.151774', '312109200247843979264.000000']
turn 7 · 1 tool call(s) · 423.2s turn · 38.7s LLM · tokens in=25,263 · out=4,199 · total=29,462 · 17,419 chars (click to expand)
turn 7423.2s turn · 38.7s LLM · 384.5s tools · tokens in=25,263 · out=4,199 · total=29,462
reasoning
The ESS values are huge, which suggests there's a numerical issue. The problem seems to be with how the atomicAdd is working on shared memory - there might be a race condition. Let me fix this more carefully by avoiding atomic operations on shared memory and using proper thread-level accumulations. Actually, looking at the code more carefully, I see that the atomicAdd to s_ess is problematic because multiple threads are writing to the same location, and float atomic operations might not be available or might cause issues. Let me use a different approach where each thread accumulates its own values, then we do a proper reduction.
assistantThere's a numerical issue with atomic operations on shared memory. Let me fix this by using proper warp-level reductions without atomic operations:
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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Warp-level reductions\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n // First pass: find max log_comp\n float max_log_comp = -1e30f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n }\n \n // Second pass: compute sum of exp(log_comp - max_log_comp)\n float sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Kernel: Compute log weights (log_p - log_q) for all samples\n__global__ void compute_log_weights_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level max reduction for logsumexp\n float warp_max = warp_reduce_max(my_log_w);\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Read block_max from shared memory (broadcast by warp 0)\n block_max = s_max[0];\n \n // Stage 3: Compute exp(log_w - block_max) and sum\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n float warp_sum = warp_reduce_sum(my_exp);\n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\n// Kernel to finalize global logsumexp\n__global__ void logsumexp_global_kernel(\n const float* __restrict__ block_maxes,\n const float* __restrict__ block_sums,\n float* __restrict__ global_logsumexp,\n int num_blocks) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Find global max across blocks\n float my_max = (idx < num_blocks) ? block_maxes[idx] : -1e30f;\n float warp_max = warp_reduce_max(my_max);\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float global_max;\n if (warp_id == 0) {\n global_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n global_max = warp_reduce_max(global_max);\n if (lane_id == 0) {\n s_max[0] = global_max;\n }\n }\n __syncthreads();\n global_max = s_max[0];\n \n // Compute sum of exp(max_i - global_max) * sum_i\n float my_val = (idx < num_blocks) ? expf(block_maxes[idx] - global_max) * block_sums[idx] : 0.0f;\n float warp_val = warp_reduce_sum(my_val);\n if (lane_id == 0) {\n s_sum[warp_id] = warp_val;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float global_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n global_sum = warp_reduce_sum(global_sum);\n if (lane_id == 0) {\n global_logsumexp[0] = global_max + logf(global_sum);\n }\n }\n}\n\n// Kernel to compute weighted mean partial sums and ESS partial sums\n// Each thread block computes partial sums for a chunk of samples\n__global__ void weighted_mean_ess_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ mean_partials,\n float* __restrict__ ess_partials,\n int N, int dim) {\n \n // Use extern shared memory for dynamic sizing\n extern __shared__ float shared_mem[];\n float* s_mean = shared_mem; // dim * (BLOCK_SIZE/WARP_SIZE) elements for warp-level partials\n float* s_ess = s_mean + dim * (BLOCK_SIZE / WARP_SIZE); // (BLOCK_SIZE/WARP_SIZE) elements\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory - each warp has its own slot\n int warp_slot_base = warp_id * dim;\n for (int d = lane_id; d < dim; d += WARP_SIZE) {\n s_mean[warp_slot_base + d] = 0.0f;\n }\n if (lane_id == 0) {\n s_ess[warp_id] = 0.0f;\n }\n __syncthreads();\n \n // Each thread computes its own contribution\n float my_ess = 0.0f;\n float my_mean[32]; // Thread-local accumulators (max dim=32 for now)\n for (int d = 0; d < dim && d < 32; d++) {\n my_mean[d] = 0.0f;\n }\n \n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Accumulate weighted mean\n for (int d = 0; d < dim && d < 32; d++) {\n my_mean[d] = w * sample[d];\n }\n // Accumulate ESS\n my_ess = w * w;\n }\n \n // Warp-level reduction for mean (each lane reduces one dimension at a time)\n for (int d = 0; d < dim && d < 32; d++) {\n float val = my_mean[d];\n val = warp_reduce_sum(val);\n if (lane_id == 0) {\n s_mean[warp_slot_base + d] = val;\n }\n }\n \n // Warp-level reduction for ESS\n my_ess = warp_reduce_sum(my_ess);\n if (lane_id == 0) {\n s_ess[warp_id] = my_ess;\n }\n __syncthreads();\n \n // Now reduce across warps - first warp does the final reduction\n if (warp_id == 0) {\n float mean_sum[32];\n for (int d = 0; d < dim && d < 32; d++) {\n mean_sum[d] = 0.0f;\n for (int w = 0; w < (BLOCK_SIZE / WARP_SIZE); w++) {\n mean_sum[d] += s_mean[w * dim + d];\n }\n if (lane_id == d) {\n mean_partials[blockIdx.x * dim + d] = mean_sum[d];\n }\n }\n \n float ess_sum = 0.0f;\n if (lane_id == 0) {\n for (int w = 0; w < (BLOCK_SIZE / WARP_SIZE); w++) {\n ess_sum += s_ess[w];\n }\n ess_partials[blockIdx.x] = ess_sum;\n }\n }\n}\n\n// Final reduction kernel\n__global__ void final_reduce_kernel(\n const float* __restrict__ mean_partials,\n const float* __restrict__ ess_partials,\n float* __restrict__ weighted_mean,\n float* __restrict__ ess,\n int num_blocks, int dim) {\n \n __shared__ float s_mean[32];\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n \n // Each thread handles one dimension\n if (tid < dim && tid < 32) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += mean_partials[b * dim + tid];\n }\n s_mean[tid] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partials[b];\n }\n s_ess = sum;\n }\n __syncthreads();\n \n // Write final results\n if (tid < dim && tid < 32) {\n weighted_mean[tid] = s_mean[tid];\n }\n if (tid == 0) {\n ess[0] = 1.0f / s_ess;\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n TORCH_CHECK(dim <= 32, \"dim must be <= 32\");\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch kernel to compute log weights and block reductions\n compute_log_weights_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // Finalize global logsumexp\n auto global_logsumexp = torch::empty({1}, options);\n logsumexp_global_kernel<<<1, BLOCK_SIZE>>>(\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n global_logsumexp.data_ptr<float>(),\n num_blocks\n );\n \n // Compute weighted mean and ESS\n auto mean_partials = torch::zeros({num_blocks, dim}, options);\n auto ess_partials = torch::zeros({num_blocks}, options);\n \n // Shared memory: dim * num_warps + num_warps\n size_t shared_mem_size = (dim * (BLOCK_SIZE / WARP_SIZE) + (BLOCK_SIZE / WARP_SIZE)) * sizeof(float);\n \n weighted_mean_ess_kernel<<<num_blocks, BLOCK_SIZE, shared_mem_size>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp.item<float>(),\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean = torch::empty({dim}, options);\n auto ess = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, 32>>>(\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n weighted_mean.data_ptr<float>(),\n ess.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean, ess);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext_v4',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← compile_kernel (ok)
okcompile_kernel compile_kernel PASSED: kernel compiled without errors.
turn 8 · 1 tool call(s) · 395.7s turn · 33.1s LLM · tokens in=29,350 · out=4,057 · total=33,407 · 17,340 chars (click to expand)
turn 8395.7s turn · 33.1s LLM · 362.6s tools · tokens in=29,350 · out=4,057 · total=33,407
reasoning
Let me test this version for 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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Warp-level reductions\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n // First pass: find max log_comp\n float max_log_comp = -1e30f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n }\n \n // Second pass: compute sum of exp(log_comp - max_log_comp)\n float sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n \n float log_comp = logf(mix_weights[k]);\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Kernel: Compute log weights (log_p - log_q) for all samples\n__global__ void compute_log_weights_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level max reduction for logsumexp\n float warp_max = warp_reduce_max(my_log_w);\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Read block_max from shared memory (broadcast by warp 0)\n block_max = s_max[0];\n \n // Stage 3: Compute exp(log_w - block_max) and sum\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n float warp_sum = warp_reduce_sum(my_exp);\n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\n// Kernel to finalize global logsumexp\n__global__ void logsumexp_global_kernel(\n const float* __restrict__ block_maxes,\n const float* __restrict__ block_sums,\n float* __restrict__ global_logsumexp,\n int num_blocks) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Find global max across blocks\n float my_max = (idx < num_blocks) ? block_maxes[idx] : -1e30f;\n float warp_max = warp_reduce_max(my_max);\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float global_max;\n if (warp_id == 0) {\n global_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n global_max = warp_reduce_max(global_max);\n if (lane_id == 0) {\n s_max[0] = global_max;\n }\n }\n __syncthreads();\n global_max = s_max[0];\n \n // Compute sum of exp(max_i - global_max) * sum_i\n float my_val = (idx < num_blocks) ? expf(block_maxes[idx] - global_max) * block_sums[idx] : 0.0f;\n float warp_val = warp_reduce_sum(my_val);\n if (lane_id == 0) {\n s_sum[warp_id] = warp_val;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float global_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n global_sum = warp_reduce_sum(global_sum);\n if (lane_id == 0) {\n global_logsumexp[0] = global_max + logf(global_sum);\n }\n }\n}\n\n// Kernel to compute weighted mean partial sums and ESS partial sums\n// Each thread block computes partial sums for a chunk of samples\n__global__ void weighted_mean_ess_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ mean_partials,\n float* __restrict__ ess_partials,\n int N, int dim) {\n \n // Use extern shared memory for dynamic sizing\n extern __shared__ float shared_mem[];\n float* s_mean = shared_mem; // dim * (BLOCK_SIZE/WARP_SIZE) elements for warp-level partials\n float* s_ess = s_mean + dim * (BLOCK_SIZE / WARP_SIZE); // (BLOCK_SIZE/WARP_SIZE) elements\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory - each warp has its own slot\n int warp_slot_base = warp_id * dim;\n for (int d = lane_id; d < dim; d += WARP_SIZE) {\n s_mean[warp_slot_base + d] = 0.0f;\n }\n if (lane_id == 0) {\n s_ess[warp_id] = 0.0f;\n }\n __syncthreads();\n \n // Each thread computes its own contribution\n float my_ess = 0.0f;\n float my_mean[32]; // Thread-local accumulators (max dim=32 for now)\n for (int d = 0; d < dim && d < 32; d++) {\n my_mean[d] = 0.0f;\n }\n \n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Accumulate weighted mean\n for (int d = 0; d < dim && d < 32; d++) {\n my_mean[d] = w * sample[d];\n }\n // Accumulate ESS\n my_ess = w * w;\n }\n \n // Warp-level reduction for mean (each lane reduces one dimension at a time)\n for (int d = 0; d < dim && d < 32; d++) {\n float val = my_mean[d];\n val = warp_reduce_sum(val);\n if (lane_id == 0) {\n s_mean[warp_slot_base + d] = val;\n }\n }\n \n // Warp-level reduction for ESS\n my_ess = warp_reduce_sum(my_ess);\n if (lane_id == 0) {\n s_ess[warp_id] = my_ess;\n }\n __syncthreads();\n \n // Now reduce across warps - first warp does the final reduction\n if (warp_id == 0) {\n float mean_sum[32];\n for (int d = 0; d < dim && d < 32; d++) {\n mean_sum[d] = 0.0f;\n for (int w = 0; w < (BLOCK_SIZE / WARP_SIZE); w++) {\n mean_sum[d] += s_mean[w * dim + d];\n }\n if (lane_id == d) {\n mean_partials[blockIdx.x * dim + d] = mean_sum[d];\n }\n }\n \n float ess_sum = 0.0f;\n if (lane_id == 0) {\n for (int w = 0; w < (BLOCK_SIZE / WARP_SIZE); w++) {\n ess_sum += s_ess[w];\n }\n ess_partials[blockIdx.x] = ess_sum;\n }\n }\n}\n\n// Final reduction kernel\n__global__ void final_reduce_kernel(\n const float* __restrict__ mean_partials,\n const float* __restrict__ ess_partials,\n float* __restrict__ weighted_mean,\n float* __restrict__ ess,\n int num_blocks, int dim) {\n \n __shared__ float s_mean[32];\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n \n // Each thread handles one dimension\n if (tid < dim && tid < 32) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += mean_partials[b * dim + tid];\n }\n s_mean[tid] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partials[b];\n }\n s_ess = sum;\n }\n __syncthreads();\n \n // Write final results\n if (tid < dim && tid < 32) {\n weighted_mean[tid] = s_mean[tid];\n }\n if (tid == 0) {\n ess[0] = 1.0f / s_ess;\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n TORCH_CHECK(dim <= 32, \"dim must be <= 32\");\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch kernel to compute log weights and block reductions\n compute_log_weights_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // Finalize global logsumexp\n auto global_logsumexp = torch::empty({1}, options);\n logsumexp_global_kernel<<<1, BLOCK_SIZE>>>(\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n global_logsumexp.data_ptr<float>(),\n num_blocks\n );\n \n // Compute weighted mean and ESS\n auto mean_partials = torch::zeros({num_blocks, dim}, options);\n auto ess_partials = torch::zeros({num_blocks}, options);\n \n // Shared memory: dim * num_warps + num_warps\n size_t shared_mem_size = (dim * (BLOCK_SIZE / WARP_SIZE) + (BLOCK_SIZE / WARP_SIZE)) * sizeof(float);\n \n weighted_mean_ess_kernel<<<num_blocks, BLOCK_SIZE, shared_mem_size>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp.item<float>(),\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean = torch::empty({dim}, options);\n auto ess = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, 32>>>(\n mean_partials.data_ptr<float>(),\n ess_partials.data_ptr<float>(),\n weighted_mean.data_ptr<float>(),\n ess.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean, ess);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext_v4',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← run_correctness (fail)
failrun_correctness run_correctness FAILED: (0 / 5) trials did not all match. correctness_issue: Output mismatch max_difference: ['4.393766', '1814721617361733719420829696.000000', '3.572236', '23222591816728576.000000', '4.362287', '7435976383701434324868931780608.000000', '6.717838', '367217917101604864.000000', '2.622046', '312109200247843979264.000000'] avg_difference: ['2.140126', '1814721617361733719420829696.000000', '1.416228', '23222591816728576.000000', '1.812993', '7435976383701434324868931780608.000000', '1.729157', '367217917101604864.000000', '1.151774', '312109200247843979264.000000']
turn 9 · 1 tool call(s) · 38.6s turn · 38.6s LLM · tokens in=33,715 · out=4,376 · total=38,091 · 18,245 chars (click to expand)
turn 938.6s turn · 38.6s LLM · 0.0s tools · tokens in=33,715 · out=4,376 · total=38,091
reasoning
The correctness is failing with very large errors in ESS values, suggesting numerical issues. The first version of the kernel that passed correctness used CPU for the final logsumexp reduction and had simpler logic. Let me go back to that working version and submit it, since it passed correctness tests. Actually, looking at the errors more carefully - the weighted_mean values seem reasonable but the ESS values are astronomically large. This suggests an issue with the ESS computation - likely the sum of w^2 is very small due to numerical precision issues. Let me go back to my first working kernel that passed correctness.
assistantLet me go back to the first working kernel that passed correctness tests:
call → static_check
callstatic_check { "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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Helper for warp-level reduction\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n float max_log_comp = -1e30f;\n float sum_exp = 0.0f;\n \n // Compute log-sum-exp across mixture components\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n float log_weight = logf(mix_weights[k]);\n \n float log_comp = log_weight;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (k == 0 || log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n sum_exp += expf(log_comp - max_log_comp); // Will renormalize later\n }\n \n // Actually need proper logsumexp\n // Recompute with correct max\n sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n float log_weight = logf(mix_weights[k]);\n \n float log_comp = log_weight;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Kernel 1: Compute log weights (log_p - log_q) for all samples\n__global__ void compute_log_weights_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n int N, int dim, int num_components) {\n \n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n log_w[idx] = log_p - log_q;\n }\n}\n\n// Kernel 2: Compute logsumexp reduction\n// Uses two-stage reduction: first block-level, then global\n__global__ void logsumexp_kernel(\n const float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N) {\n \n __shared__ float s_max[BLOCK_SIZE / WARP_SIZE];\n __shared__ float s_sum[BLOCK_SIZE / WARP_SIZE];\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize with thread's value or very negative number\n float my_val = (idx < N) ? log_w[idx] : -1e30f;\n \n // Warp-level max reduction\n float warp_max = warp_reduce_max(my_val);\n \n // Lane 0 of each warp writes to shared memory\n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n // First warp reduces the warp maxes\n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Get block max from shared memory (broadcast from thread 0)\n block_max = s_max[0];\n \n // Compute exp(log_w - block_max) for this thread\n float my_exp = (idx < N) ? expf(my_val - block_max) : 0.0f;\n \n // Warp-level sum reduction\n float warp_sum = warp_reduce_sum(my_exp);\n \n // Lane 0 of each warp writes to shared memory\n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n // First warp reduces the warp sums\n float block_sum;\n if (warp_id == 0) {\n block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\n// Kernel 3: Normalize weights and compute weighted mean and ESS\n__global__ void normalize_and_reduce_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ weighted_mean_partial,\n float* __restrict__ ess_partial,\n int N, int dim) {\n \n __shared__ float s_mean[BLOCK_SIZE][32]; // partial sums for mean (up to dim=32)\n __shared__ float s_ess[BLOCK_SIZE];\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory\n for (int d = tid; d < dim && d < 32; d += blockDim.x) {\n s_mean[tid][d] = 0.0f;\n }\n s_ess[tid] = 0.0f;\n __syncthreads();\n \n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Accumulate weighted mean and ESS\n for (int d = 0; d < dim && d < 32; d++) {\n atomicAdd(&s_mean[0][d], w * sample[d]);\n }\n atomicAdd(&s_ess[0], w * w);\n }\n __syncthreads();\n \n // Write partial results\n if (tid == 0) {\n for (int d = 0; d < dim && d < 32; d++) {\n weighted_mean_partial[blockIdx.x * dim + d] = s_mean[0][d];\n }\n ess_partial[blockIdx.x] = s_ess[0];\n }\n}\n\n// Final reduction kernel for weighted mean and ESS\n__global__ void final_reduce_kernel(\n const float* __restrict__ weighted_mean_partial,\n const float* __restrict__ ess_partial,\n float* __restrict__ weighted_mean_out,\n float* __restrict__ ess_out,\n int num_blocks, int dim) {\n \n __shared__ float s_mean[32];\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n \n if (tid < dim && tid < 32) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += weighted_mean_partial[b * dim + tid];\n }\n s_mean[tid] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partial[b];\n }\n s_ess = sum;\n }\n __syncthreads();\n \n if (tid < dim && tid < 32) {\n weighted_mean_out[tid] = s_mean[tid];\n }\n if (tid == 0) {\n ess_out[0] = 1.0f / s_ess;\n }\n}\n\n// Alternative single-kernel approach for better performance\n__global__ void importance_sampling_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n extern __shared__ float shared_mem[];\n float* s_max = shared_mem; // BLOCK_SIZE / WARP_SIZE elements\n float* s_sum = s_max + (BLOCK_SIZE / WARP_SIZE); // BLOCK_SIZE / WARP_SIZE elements\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level logsumexp\n // Warp-level max reduction\n float warp_max = warp_reduce_max(my_log_w);\n \n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Broadcast block_max (read from shared or global depending on timing)\n __shared__ float s_block_max;\n if (tid == 0) {\n s_block_max = block_maxes[blockIdx.x];\n }\n __syncthreads();\n block_max = s_block_max;\n \n // Compute exp(log_w - block_max)\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n \n // Warp-level sum reduction\n float warp_sum = warp_reduce_sum(my_exp);\n \n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n // Allocate intermediate buffers\n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch combined kernel\n size_t shared_mem_size = 2 * (BLOCK_SIZE / WARP_SIZE) * sizeof(float);\n \n importance_sampling_kernel<<<num_blocks, BLOCK_SIZE, shared_mem_size>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // Second pass: compute global logsumexp\n // We need to launch a small kernel or do it on CPU for the block results\n // For simplicity, use a small kernel\n auto block_maxes_2 = torch::empty({1}, options);\n auto block_sums_2 = torch::empty({1}, options);\n \n int num_blocks_2 = (num_blocks + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n // For now, do the final logsumexp reduction on CPU (small data)\n // This is not ideal but works for correctness\n torch::Tensor block_maxes_cpu = block_maxes.cpu();\n torch::Tensor block_sums_cpu = block_sums.cpu();\n \n float global_max = block_maxes_cpu[0].item<float>();\n for (int i = 1; i < num_blocks; i++) {\n float val = block_maxes_cpu[i].item<float>();\n if (val > global_max) global_max = val;\n }\n \n float sum_exp = 0.0f;\n for (int i = 0; i < num_blocks; i++) {\n float max_i = block_maxes_cpu[i].item<float>();\n float sum_i = block_sums_cpu[i].item<float>();\n // Renormalize: exp(max_i) * sum_i -> exp(global_max) * exp(max_i - global_max) * sum_i\n sum_exp += expf(max_i - global_max) * sum_i;\n }\n \n float global_logsumexp = global_max + logf(sum_exp);\n \n // Third pass: normalize and compute weighted mean and ESS\n auto weighted_mean_partial = torch::zeros({num_blocks, dim}, options);\n auto ess_partial = torch::zeros({num_blocks}, options);\n \n normalize_and_reduce_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp,\n weighted_mean_partial.data_ptr<float>(),\n ess_partial.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean_out = torch::empty({dim}, options);\n auto ess_out = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, dim>>>(\n weighted_mean_partial.data_ptr<float>(),\n ess_partial.data_ptr<float>(),\n weighted_mean_out.data_ptr<float>(),\n ess_out.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean_out, ess_out);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n # Ensure contiguous and on same device\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← static_check (ok)
okstatic_check static_check PASSED: no violations or warnings detected.
turn 10 · FINAL · 1 tool call(s) · 399.9s turn · 28.7s LLM · tokens in=38,015 · out=3,365 · total=41,380 · 14,601 chars (click to expand)
turn 10399.9s turn · 28.7s LLM · 371.2s tools · tokens in=38,015 · out=3,365 · total=41,380 · FINAL
reasoning
I have a correct kernel that passed all 5 correctness tests. The static check also passed. Let me submit it now.
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#include <cmath>\n\nconstexpr int BLOCK_SIZE = 256;\nconstexpr int WARP_SIZE = 32;\n\n// Helper for warp-level reduction\n__inline__ __device__ float warp_reduce_max(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val = max(val, __shfl_down_sync(0xffffffff, val, offset));\n }\n return val;\n}\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {\n val += __shfl_down_sync(0xffffffff, val, offset);\n }\n return val;\n}\n\n// Device function to compute log_p for a single sample\n__device__ float compute_log_p_single(\n const float* __restrict__ sample,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n int dim, int num_components) {\n \n float max_log_comp = -1e30f;\n float sum_exp = 0.0f;\n \n // Compute log-sum-exp across mixture components\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n float log_weight = logf(mix_weights[k]);\n \n float log_comp = log_weight;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n if (k == 0 || log_comp > max_log_comp) {\n max_log_comp = log_comp;\n }\n sum_exp += expf(log_comp - max_log_comp); // Will renormalize later\n }\n \n // Actually need proper logsumexp\n // Recompute with correct max\n sum_exp = 0.0f;\n for (int k = 0; k < num_components; k++) {\n const float* mu_k = mix_mus + k * dim;\n const float* std_k = mix_stds + k * dim;\n float log_weight = logf(mix_weights[k]);\n \n float log_comp = log_weight;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - mu_k[d];\n float std = std_k[d];\n log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n \n sum_exp += expf(log_comp - max_log_comp);\n }\n \n return max_log_comp + logf(sum_exp);\n}\n\n// Device function to compute log_q for a single sample\n__device__ float compute_log_q_single(\n const float* __restrict__ sample,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n int dim) {\n \n float log_q = 0.0f;\n for (int d = 0; d < dim; d++) {\n float diff = sample[d] - q_mu[d];\n float std = q_std[d];\n log_q += -0.5f * (diff * diff) / (std * std) - logf(std);\n }\n return log_q;\n}\n\n// Kernel 3: Normalize weights and compute weighted mean and ESS\n__global__ void normalize_and_reduce_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ log_w,\n float global_logsumexp,\n float* __restrict__ weighted_mean_partial,\n float* __restrict__ ess_partial,\n int N, int dim) {\n \n __shared__ float s_mean[BLOCK_SIZE][32]; // partial sums for mean (up to dim=32)\n __shared__ float s_ess[BLOCK_SIZE];\n \n int tid = threadIdx.x;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Initialize shared memory\n for (int d = tid; d < dim && d < 32; d += blockDim.x) {\n s_mean[tid][d] = 0.0f;\n }\n s_ess[tid] = 0.0f;\n __syncthreads();\n \n if (idx < N) {\n float w = expf(log_w[idx] - global_logsumexp);\n const float* sample = samples + idx * dim;\n \n // Accumulate weighted mean and ESS\n for (int d = 0; d < dim && d < 32; d++) {\n atomicAdd(&s_mean[0][d], w * sample[d]);\n }\n atomicAdd(&s_ess[0], w * w);\n }\n __syncthreads();\n \n // Write partial results\n if (tid == 0) {\n for (int d = 0; d < dim && d < 32; d++) {\n weighted_mean_partial[blockIdx.x * dim + d] = s_mean[0][d];\n }\n ess_partial[blockIdx.x] = s_ess[0];\n }\n}\n\n// Final reduction kernel for weighted mean and ESS\n__global__ void final_reduce_kernel(\n const float* __restrict__ weighted_mean_partial,\n const float* __restrict__ ess_partial,\n float* __restrict__ weighted_mean_out,\n float* __restrict__ ess_out,\n int num_blocks, int dim) {\n \n __shared__ float s_mean[32];\n __shared__ float s_ess;\n \n int tid = threadIdx.x;\n \n if (tid < dim && tid < 32) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += weighted_mean_partial[b * dim + tid];\n }\n s_mean[tid] = sum;\n }\n \n if (tid == 0) {\n float sum = 0.0f;\n for (int b = 0; b < num_blocks; b++) {\n sum += ess_partial[b];\n }\n s_ess = sum;\n }\n __syncthreads();\n \n if (tid < dim && tid < 32) {\n weighted_mean_out[tid] = s_mean[tid];\n }\n if (tid == 0) {\n ess_out[0] = 1.0f / s_ess;\n }\n}\n\n// Alternative single-kernel approach for better performance\n__global__ void importance_sampling_kernel(\n const float* __restrict__ samples,\n const float* __restrict__ mix_mus,\n const float* __restrict__ mix_stds,\n const float* __restrict__ mix_weights,\n const float* __restrict__ q_mu,\n const float* __restrict__ q_std,\n float* __restrict__ log_w,\n float* __restrict__ block_maxes,\n float* __restrict__ block_sums,\n int N, int dim, int num_components) {\n \n extern __shared__ float shared_mem[];\n float* s_max = shared_mem; // BLOCK_SIZE / WARP_SIZE elements\n float* s_sum = s_max + (BLOCK_SIZE / WARP_SIZE); // BLOCK_SIZE / WARP_SIZE elements\n \n int tid = threadIdx.x;\n int warp_id = tid / WARP_SIZE;\n int lane_id = tid % WARP_SIZE;\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n // Stage 1: Compute log weights\n float my_log_w = -1e30f;\n if (idx < N) {\n const float* sample = samples + idx * dim;\n float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);\n float log_q = compute_log_q_single(sample, q_mu, q_std, dim);\n my_log_w = log_p - log_q;\n log_w[idx] = my_log_w;\n }\n \n // Stage 2: Block-level logsumexp\n // Warp-level max reduction\n float warp_max = warp_reduce_max(my_log_w);\n \n if (lane_id == 0) {\n s_max[warp_id] = warp_max;\n }\n __syncthreads();\n \n float block_max;\n if (warp_id == 0) {\n block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;\n block_max = warp_reduce_max(block_max);\n if (lane_id == 0) {\n block_maxes[blockIdx.x] = block_max;\n }\n }\n __syncthreads();\n \n // Broadcast block_max (read from shared or global depending on timing)\n __shared__ float s_block_max;\n if (tid == 0) {\n s_block_max = block_maxes[blockIdx.x];\n }\n __syncthreads();\n block_max = s_block_max;\n \n // Compute exp(log_w - block_max)\n float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;\n \n // Warp-level sum reduction\n float warp_sum = warp_reduce_sum(my_exp);\n \n if (lane_id == 0) {\n s_sum[warp_id] = warp_sum;\n }\n __syncthreads();\n \n if (warp_id == 0) {\n float block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;\n block_sum = warp_reduce_sum(block_sum);\n if (lane_id == 0) {\n block_sums[blockIdx.x] = block_sum;\n }\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std) {\n \n int N = samples.size(0);\n int dim = samples.size(1);\n int num_components = mix_mus.size(0);\n \n int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;\n \n // Allocate intermediate buffers\n auto options = samples.options();\n auto log_w = torch::empty({N}, options);\n auto block_maxes = torch::empty({num_blocks}, options);\n auto block_sums = torch::empty({num_blocks}, options);\n \n // Launch combined kernel\n size_t shared_mem_size = 2 * (BLOCK_SIZE / WARP_SIZE) * sizeof(float);\n \n importance_sampling_kernel<<<num_blocks, BLOCK_SIZE, shared_mem_size>>>(\n samples.data_ptr<float>(),\n mix_mus.data_ptr<float>(),\n mix_stds.data_ptr<float>(),\n mix_weights.data_ptr<float>(),\n q_mu.data_ptr<float>(),\n q_std.data_ptr<float>(),\n log_w.data_ptr<float>(),\n block_maxes.data_ptr<float>(),\n block_sums.data_ptr<float>(),\n N, dim, num_components\n );\n \n // For now, do the final logsumexp reduction on CPU (small data)\n torch::Tensor block_maxes_cpu = block_maxes.cpu();\n torch::Tensor block_sums_cpu = block_sums.cpu();\n \n float global_max = block_maxes_cpu[0].item<float>();\n for (int i = 1; i < num_blocks; i++) {\n float val = block_maxes_cpu[i].item<float>();\n if (val > global_max) global_max = val;\n }\n \n float sum_exp = 0.0f;\n for (int i = 0; i < num_blocks; i++) {\n float max_i = block_maxes_cpu[i].item<float>();\n float sum_i = block_sums_cpu[i].item<float>();\n sum_exp += expf(max_i - global_max) * sum_i;\n }\n \n float global_logsumexp = global_max + logf(sum_exp);\n \n // Third pass: normalize and compute weighted mean and ESS\n auto weighted_mean_partial = torch::zeros({num_blocks, dim}, options);\n auto ess_partial = torch::zeros({num_blocks}, options);\n \n normalize_and_reduce_kernel<<<num_blocks, BLOCK_SIZE>>>(\n samples.data_ptr<float>(),\n log_w.data_ptr<float>(),\n global_logsumexp,\n weighted_mean_partial.data_ptr<float>(),\n ess_partial.data_ptr<float>(),\n N, dim\n );\n \n // Final reduction\n auto weighted_mean_out = torch::empty({dim}, options);\n auto ess_out = torch::empty({1}, options);\n \n final_reduce_kernel<<<1, dim>>>(\n weighted_mean_partial.data_ptr<float>(),\n ess_partial.data_ptr<float>(),\n weighted_mean_out.data_ptr<float>(),\n ess_out.data_ptr<float>(),\n num_blocks, dim\n );\n \n return std::make_tuple(weighted_mean_out, ess_out);\n}\n'''\n\ncpp_source = r'''\nstd::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(\n torch::Tensor samples,\n torch::Tensor mix_mus,\n torch::Tensor mix_stds,\n torch::Tensor mix_weights,\n torch::Tensor q_mu,\n torch::Tensor q_std);\n'''\n\nmodule = load_inline(\n name='importance_sampling_ext',\n cuda_sources=cuda_source,\n cpp_sources=cpp_source,\n functions=['importance_sampling_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n \"\"\"\n Self-normalized importance sampling estimate with CUDA acceleration.\n \"\"\"\n \n def __init__(self, dim, num_components=3):\n super().__init__()\n self.dim = dim\n self.num_components = num_components\n # Target mixture components\n self.register_buffer(\"mix_weights\", torch.ones(num_components) / num_components)\n mus = torch.randn(num_components, dim) * 2.0\n self.register_buffer(\"mix_mus\", mus)\n self.register_buffer(\"mix_stds\", torch.ones(num_components, dim))\n # Proposal\n self.register_buffer(\"q_mu\", torch.zeros(dim))\n self.register_buffer(\"q_std\", torch.ones(dim) * 3.0)\n \n def forward(self, samples: torch.Tensor) -> tuple:\n \"\"\"\n Args:\n samples: (N, dim) \u2013 samples drawn from q\n Returns:\n (weighted_mean, ess):\n weighted_mean: (dim,) \u2013 importance-weighted mean estimate of E_p[x]\n ess: scalar \u2013 effective sample size\n \"\"\"\n # Ensure contiguous and on same device\n samples = samples.contiguous()\n mix_mus = self.mix_mus.contiguous()\n mix_stds = self.mix_stds.contiguous()\n mix_weights = self.mix_weights.contiguous()\n q_mu = self.q_mu.contiguous()\n q_std = self.q_std.contiguous()\n \n weighted_mean, ess = module.importance_sampling_cuda(\n samples, mix_mus, mix_stds, mix_weights, q_mu, q_std\n )\n \n return weighted_mean, ess.squeeze()" }
result ← submit_kernel (ok)
oksubmit_kernel submit_kernel PASSED: (5 / 5) correctness trials all passed. Kernel runtime: 2.48 μs Runtime stats: mean=2.48μs median=?μs std=0.00μs Numerical precision: max_abs_err=7.99e-06 mean_abs_err=8.72e-07 max_rel_err=1.96e-05 Memory: 0.27 MB peak (ref: 2.51 MB, ratio: 0.1093x) Kernel launches: 215 (ref: 88, fusion ratio: 0.4093) Energy: 483.72 mJ/run (ref: 0.0 mJ, ratio: -1x) SOL score: 0.2426
final submitted kernel (398 lines, 12,446 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>
#include <cmath>

constexpr int BLOCK_SIZE = 256;
constexpr int WARP_SIZE = 32;

// Helper for warp-level reduction
__inline__ __device__ float warp_reduce_max(float val) {
    for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {
        val = max(val, __shfl_down_sync(0xffffffff, val, offset));
    }
    return val;
}

__inline__ __device__ float warp_reduce_sum(float val) {
    for (int offset = WARP_SIZE / 2; offset > 0; offset /= 2) {
        val += __shfl_down_sync(0xffffffff, val, offset);
    }
    return val;
}

// Device function to compute log_p for a single sample
__device__ float compute_log_p_single(
    const float* __restrict__ sample,
    const float* __restrict__ mix_mus,
    const float* __restrict__ mix_stds,
    const float* __restrict__ mix_weights,
    int dim, int num_components) {
    
    float max_log_comp = -1e30f;
    float sum_exp = 0.0f;
    
    // Compute log-sum-exp across mixture components
    for (int k = 0; k < num_components; k++) {
        const float* mu_k = mix_mus + k * dim;
        const float* std_k = mix_stds + k * dim;
        float log_weight = logf(mix_weights[k]);
        
        float log_comp = log_weight;
        for (int d = 0; d < dim; d++) {
            float diff = sample[d] - mu_k[d];
            float std = std_k[d];
            log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);
        }
        
        if (k == 0 || log_comp > max_log_comp) {
            max_log_comp = log_comp;
        }
        sum_exp += expf(log_comp - max_log_comp);  // Will renormalize later
    }
    
    // Actually need proper logsumexp
    // Recompute with correct max
    sum_exp = 0.0f;
    for (int k = 0; k < num_components; k++) {
        const float* mu_k = mix_mus + k * dim;
        const float* std_k = mix_stds + k * dim;
        float log_weight = logf(mix_weights[k]);
        
        float log_comp = log_weight;
        for (int d = 0; d < dim; d++) {
            float diff = sample[d] - mu_k[d];
            float std = std_k[d];
            log_comp += -0.5f * (diff * diff) / (std * std) - logf(std);
        }
        
        sum_exp += expf(log_comp - max_log_comp);
    }
    
    return max_log_comp + logf(sum_exp);
}

// Device function to compute log_q for a single sample
__device__ float compute_log_q_single(
    const float* __restrict__ sample,
    const float* __restrict__ q_mu,
    const float* __restrict__ q_std,
    int dim) {
    
    float log_q = 0.0f;
    for (int d = 0; d < dim; d++) {
        float diff = sample[d] - q_mu[d];
        float std = q_std[d];
        log_q += -0.5f * (diff * diff) / (std * std) - logf(std);
    }
    return log_q;
}

// Kernel 3: Normalize weights and compute weighted mean and ESS
__global__ void normalize_and_reduce_kernel(
    const float* __restrict__ samples,
    const float* __restrict__ log_w,
    float global_logsumexp,
    float* __restrict__ weighted_mean_partial,
    float* __restrict__ ess_partial,
    int N, int dim) {
    
    __shared__ float s_mean[BLOCK_SIZE][32];  // partial sums for mean (up to dim=32)
    __shared__ float s_ess[BLOCK_SIZE];
    
    int tid = threadIdx.x;
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    
    // Initialize shared memory
    for (int d = tid; d < dim && d < 32; d += blockDim.x) {
        s_mean[tid][d] = 0.0f;
    }
    s_ess[tid] = 0.0f;
    __syncthreads();
    
    if (idx < N) {
        float w = expf(log_w[idx] - global_logsumexp);
        const float* sample = samples + idx * dim;
        
        // Accumulate weighted mean and ESS
        for (int d = 0; d < dim && d < 32; d++) {
            atomicAdd(&s_mean[0][d], w * sample[d]);
        }
        atomicAdd(&s_ess[0], w * w);
    }
    __syncthreads();
    
    // Write partial results
    if (tid == 0) {
        for (int d = 0; d < dim && d < 32; d++) {
            weighted_mean_partial[blockIdx.x * dim + d] = s_mean[0][d];
        }
        ess_partial[blockIdx.x] = s_ess[0];
    }
}

// Final reduction kernel for weighted mean and ESS
__global__ void final_reduce_kernel(
    const float* __restrict__ weighted_mean_partial,
    const float* __restrict__ ess_partial,
    float* __restrict__ weighted_mean_out,
    float* __restrict__ ess_out,
    int num_blocks, int dim) {
    
    __shared__ float s_mean[32];
    __shared__ float s_ess;
    
    int tid = threadIdx.x;
    
    if (tid < dim && tid < 32) {
        float sum = 0.0f;
        for (int b = 0; b < num_blocks; b++) {
            sum += weighted_mean_partial[b * dim + tid];
        }
        s_mean[tid] = sum;
    }
    
    if (tid == 0) {
        float sum = 0.0f;
        for (int b = 0; b < num_blocks; b++) {
            sum += ess_partial[b];
        }
        s_ess = sum;
    }
    __syncthreads();
    
    if (tid < dim && tid < 32) {
        weighted_mean_out[tid] = s_mean[tid];
    }
    if (tid == 0) {
        ess_out[0] = 1.0f / s_ess;
    }
}

// Alternative single-kernel approach for better performance
__global__ void importance_sampling_kernel(
    const float* __restrict__ samples,
    const float* __restrict__ mix_mus,
    const float* __restrict__ mix_stds,
    const float* __restrict__ mix_weights,
    const float* __restrict__ q_mu,
    const float* __restrict__ q_std,
    float* __restrict__ log_w,
    float* __restrict__ block_maxes,
    float* __restrict__ block_sums,
    int N, int dim, int num_components) {
    
    extern __shared__ float shared_mem[];
    float* s_max = shared_mem;  // BLOCK_SIZE / WARP_SIZE elements
    float* s_sum = s_max + (BLOCK_SIZE / WARP_SIZE);  // BLOCK_SIZE / WARP_SIZE elements
    
    int tid = threadIdx.x;
    int warp_id = tid / WARP_SIZE;
    int lane_id = tid % WARP_SIZE;
    int idx = blockIdx.x * blockDim.x + threadIdx.x;
    
    // Stage 1: Compute log weights
    float my_log_w = -1e30f;
    if (idx < N) {
        const float* sample = samples + idx * dim;
        float log_p = compute_log_p_single(sample, mix_mus, mix_stds, mix_weights, dim, num_components);
        float log_q = compute_log_q_single(sample, q_mu, q_std, dim);
        my_log_w = log_p - log_q;
        log_w[idx] = my_log_w;
    }
    
    // Stage 2: Block-level logsumexp
    // Warp-level max reduction
    float warp_max = warp_reduce_max(my_log_w);
    
    if (lane_id == 0) {
        s_max[warp_id] = warp_max;
    }
    __syncthreads();
    
    float block_max;
    if (warp_id == 0) {
        block_max = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_max[lane_id] : -1e30f;
        block_max = warp_reduce_max(block_max);
        if (lane_id == 0) {
            block_maxes[blockIdx.x] = block_max;
        }
    }
    __syncthreads();
    
    // Broadcast block_max (read from shared or global depending on timing)
    __shared__ float s_block_max;
    if (tid == 0) {
        s_block_max = block_maxes[blockIdx.x];
    }
    __syncthreads();
    block_max = s_block_max;
    
    // Compute exp(log_w - block_max)
    float my_exp = (idx < N) ? expf(my_log_w - block_max) : 0.0f;
    
    // Warp-level sum reduction
    float warp_sum = warp_reduce_sum(my_exp);
    
    if (lane_id == 0) {
        s_sum[warp_id] = warp_sum;
    }
    __syncthreads();
    
    if (warp_id == 0) {
        float block_sum = (lane_id < (BLOCK_SIZE / WARP_SIZE)) ? s_sum[lane_id] : 0.0f;
        block_sum = warp_reduce_sum(block_sum);
        if (lane_id == 0) {
            block_sums[blockIdx.x] = block_sum;
        }
    }
}

std::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(
    torch::Tensor samples,
    torch::Tensor mix_mus,
    torch::Tensor mix_stds,
    torch::Tensor mix_weights,
    torch::Tensor q_mu,
    torch::Tensor q_std) {
    
    int N = samples.size(0);
    int dim = samples.size(1);
    int num_components = mix_mus.size(0);
    
    int num_blocks = (N + BLOCK_SIZE - 1) / BLOCK_SIZE;
    
    // Allocate intermediate buffers
    auto options = samples.options();
    auto log_w = torch::empty({N}, options);
    auto block_maxes = torch::empty({num_blocks}, options);
    auto block_sums = torch::empty({num_blocks}, options);
    
    // Launch combined kernel
    size_t shared_mem_size = 2 * (BLOCK_SIZE / WARP_SIZE) * sizeof(float);
    
    importance_sampling_kernel<<<num_blocks, BLOCK_SIZE, shared_mem_size>>>(
        samples.data_ptr<float>(),
        mix_mus.data_ptr<float>(),
        mix_stds.data_ptr<float>(),
        mix_weights.data_ptr<float>(),
        q_mu.data_ptr<float>(),
        q_std.data_ptr<float>(),
        log_w.data_ptr<float>(),
        block_maxes.data_ptr<float>(),
        block_sums.data_ptr<float>(),
        N, dim, num_components
    );
    
    // For now, do the final logsumexp reduction on CPU (small data)
    torch::Tensor block_maxes_cpu = block_maxes.cpu();
    torch::Tensor block_sums_cpu = block_sums.cpu();
    
    float global_max = block_maxes_cpu[0].item<float>();
    for (int i = 1; i < num_blocks; i++) {
        float val = block_maxes_cpu[i].item<float>();
        if (val > global_max) global_max = val;
    }
    
    float sum_exp = 0.0f;
    for (int i = 0; i < num_blocks; i++) {
        float max_i = block_maxes_cpu[i].item<float>();
        float sum_i = block_sums_cpu[i].item<float>();
        sum_exp += expf(max_i - global_max) * sum_i;
    }
    
    float global_logsumexp = global_max + logf(sum_exp);
    
    // Third pass: normalize and compute weighted mean and ESS
    auto weighted_mean_partial = torch::zeros({num_blocks, dim}, options);
    auto ess_partial = torch::zeros({num_blocks}, options);
    
    normalize_and_reduce_kernel<<<num_blocks, BLOCK_SIZE>>>(
        samples.data_ptr<float>(),
        log_w.data_ptr<float>(),
        global_logsumexp,
        weighted_mean_partial.data_ptr<float>(),
        ess_partial.data_ptr<float>(),
        N, dim
    );
    
    // Final reduction
    auto weighted_mean_out = torch::empty({dim}, options);
    auto ess_out = torch::empty({1}, options);
    
    final_reduce_kernel<<<1, dim>>>(
        weighted_mean_partial.data_ptr<float>(),
        ess_partial.data_ptr<float>(),
        weighted_mean_out.data_ptr<float>(),
        ess_out.data_ptr<float>(),
        num_blocks, dim
    );
    
    return std::make_tuple(weighted_mean_out, ess_out);
}
'''

cpp_source = r'''
std::tuple<torch::Tensor, torch::Tensor> importance_sampling_cuda(
    torch::Tensor samples,
    torch::Tensor mix_mus,
    torch::Tensor mix_stds,
    torch::Tensor mix_weights,
    torch::Tensor q_mu,
    torch::Tensor q_std);
'''

module = load_inline(
    name='importance_sampling_ext',
    cuda_sources=cuda_source,
    cpp_sources=cpp_source,
    functions=['importance_sampling_cuda'],
    extra_cuda_cflags=['-O3'],
    verbose=False
)

class ModelNew(nn.Module):
    """
    Self-normalized importance sampling estimate with CUDA acceleration.
    """
    
    def __init__(self, dim, num_components=3):
        super().__init__()
        self.dim = dim
        self.num_components = num_components
        # Target mixture components
        self.register_buffer("mix_weights", torch.ones(num_components) / num_components)
        mus = torch.randn(num_components, dim) * 2.0
        self.register_buffer("mix_mus", mus)
        self.register_buffer("mix_stds", torch.ones(num_components, dim))
        # Proposal
        self.register_buffer("q_mu", torch.zeros(dim))
        self.register_buffer("q_std", torch.ones(dim) * 3.0)
    
    def forward(self, samples: torch.Tensor) -> tuple:
        """
        Args:
            samples: (N, dim) – samples drawn from q
        Returns:
            (weighted_mean, ess):
                weighted_mean: (dim,) – importance-weighted mean estimate of E_p[x]
                ess: scalar – effective sample size
        """
        # Ensure contiguous and on same device
        samples = samples.contiguous()
        mix_mus = self.mix_mus.contiguous()
        mix_stds = self.mix_stds.contiguous()
        mix_weights = self.mix_weights.contiguous()
        q_mu = self.q_mu.contiguous()
        q_std = self.q_std.contiguous()
        
        weighted_mean, ess = module.importance_sampling_cuda(
            samples, mix_mus, mix_stds, mix_weights, q_mu, q_std
        )
        
        return weighted_mean, ess.squeeze()