correct
24_VoxelGridPooling.py
started
2026-05-11T12:13:30Z
timingkernelbench.timing
kernel mean / median / std
0.06 / — / 9.28e-04 μs
ref mean / median / std
10.40 / — / 1.12 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
344.92x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
2862.44 GB/s
warp stalls (top 5)nsight
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
class Model(nn.Module):
"""
Voxel-grid pooling for 3-D molecular point clouds. Discretizes
continuous 3-D coordinates into a regular grid and pools per-atom
features into each voxel. Used in 3-D-CNN approaches for molecular
property prediction and ligand docking (e.g., PointVoxel-CNN,
3D-Infomax).
"""
def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):
super().__init__()
self.feat_dim = feat_dim
self.grid_size = grid_size
self.voxel_size = voxel_size
self.linear = nn.Linear(feat_dim, feat_dim)
def forward(
self, coords: torch.Tensor, features: torch.Tensor
) -> torch.Tensor:
"""
Args:
coords: (B, N, 3) – atom coordinates
features: (B, N, feat_dim) – per-atom features
Returns:
voxel_grid: (B, feat_dim, G, G, G) – pooled voxel features
"""
B, N, _ = coords.shape
G = self.grid_size
features = self.linear(features)
# Center coordinates and discretize
center = coords.mean(dim=1, keepdim=True)
shifted = (coords - center) / self.voxel_size + G / 2.0
indices = shifted.long().clamp(0, G - 1) # (B, N, 3)
voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)
ix = indices[:, :, 0]
iy = indices[:, :, 1]
iz = indices[:, :, 2]
batch_idx = torch.arange(B, device=coords.device).unsqueeze(1).expand(-1, N)
for d in range(self.feat_dim):
feat_d = features[:, :, d]
voxel_grid[:, d].index_put_(
(batch_idx.reshape(-1), ix.reshape(-1), iy.reshape(-1), iz.reshape(-1)),
feat_d.reshape(-1),
accumulate=True,
)
return voxel_grid
feat_dim = 32
grid_size = 32
voxel_size = 1.0
num_atoms = 256
batch_size = 4
def get_inputs():
p = popcorn_pri
bs = p.jitter_int(batch_size)
na = p.jitter_int(num_atoms)
coords = torch.randn(bs, na, 3) * 5.0
features = torch.randn(bs, na, feat_dim)
return [coords, features]
def get_init_inputs():
return [feat_dim, grid_size, voxel_size]
turn 0599.3s turn · 3.7s LLM · 595.5s tools · tokens in=1,812 · out=266 · total=2,078
reasoning
Let me understand this task:
1. I need to replace a PyTorch model that does voxel-grid pooling for 3-D molecular point clouds
2. The model discretizes continuous 3-D coordinates into a regular grid and pools per-atom features into each voxel
3. The forward pass:
- Applies a linear layer to features
- Centers coordinates and discretizes them
- Uses index_put_ to accumulate features into a voxel grid
Let me analyze the computation:
- B = batch_size = 4
- N = num_atoms = 256
- feat_dim = 32
- G = grid_size = 32
The operations are:
1. Linear transformation: features (B, N, feat_dim) -> (B, N, feat_dim)
2. Center coordinates: coords.mean(dim=1)
3. Shift and discretize: (coords - center) / voxel_size + G / 2.0
4. Clamp to [0, G-1]
5. For each feature dimension, accumulate into voxel grid using index_put_
The current implementation has a loop over feat_dim (32 iterations), which is inefficient. I should parallelize this with a CUDA kernel.
Let me first check the GPU specs to understand the hardware:
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 1415.0s turn · 12.8s LLM · 402.2s tools · tokens in=2,060 · out=1,263 · total=3,323
reasoning
Now let me write an initial kernel for this voxel pooling operation. The key operations are:
1. Linear transformation of features (B, N, feat_dim) -> (B, N, feat_dim)
2. Center coordinates, shift, discretize to grid indices
3. Scatter-add features to voxel grid
Let me write a kernel that handles this efficiently.
assistantLet me write the initial kernel for this voxel pooling operation:
call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n const int batch_idx = blockIdx.x;\n const int atom_idx = blockIdx.y * blockDim.x + threadIdx.x;\n \n if (batch_idx >= B || atom_idx >= N) return;\n \n // Load center for this batch\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Process each feature dimension\n for (int d = 0; d < feat_dim; d++) {\n const scalar_t feat_val = features[batch_idx * N * feat_dim + atom_idx * feat_dim + d];\n \n // Voxel grid index: (B, feat_dim, G, G, G) - index is [b, d, ix, iy, iz]\n const int voxel_idx = batch_idx * feat_dim * G * G * G + d * G * G * G + ix * G * G + iy * G + iz;\n \n // Atomic add\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n }\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers on CPU (small data, could also do on GPU)\n auto centers = coords.mean(/*dim=*/1); // (B, 3)\n \n const int threads = 256;\n const int blocks_y = (N + threads - 1) / threads;\n \n dim3 grid(B, blocks_y);\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<grid, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 2426.5s turn · 10.3s LLM · 416.2s tools · tokens in=3,261 · out=1,201 · total=4,462
reasoning
The kernel compiled successfully. Now let me run correctness check to see if it produces the same results as the reference implementation.
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n const int batch_idx = blockIdx.x;\n const int atom_idx = blockIdx.y * blockDim.x + threadIdx.x;\n \n if (batch_idx >= B || atom_idx >= N) return;\n \n // Load center for this batch\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Process each feature dimension\n for (int d = 0; d < feat_dim; d++) {\n const scalar_t feat_val = features[batch_idx * N * feat_dim + atom_idx * feat_dim + d];\n \n // Voxel grid index: (B, feat_dim, G, G, G) - index is [b, d, ix, iy, iz]\n const int voxel_idx = batch_idx * feat_dim * G * G * G + d * G * G * G + ix * G * G + iy * G + iz;\n \n // Atomic add\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n }\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers on CPU (small data, could also do on GPU)\n auto centers = coords.mean(/*dim=*/1); // (B, 3)\n \n const int threads = 256;\n const int blocks_y = (N + threads - 1) / threads;\n \n dim3 grid(B, blocks_y);\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<grid, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=1.19e-07 mean_abs_err=1.71e-14 max_rel_err=1.48e-07
turn 311.8s turn · 11.8s LLM · 0.0s tools · tokens in=4,495 · out=1,217 · total=5,712
reasoning
The kernel passes correctness. Now let me check if there are any reward-hacking patterns before submitting:
assistantThe correctness test passed! Let me run a static check to ensure there are no reward-hacking patterns:
call → static_check
callstatic_check
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n const int batch_idx = blockIdx.x;\n const int atom_idx = blockIdx.y * blockDim.x + threadIdx.x;\n \n if (batch_idx >= B || atom_idx >= N) return;\n \n // Load center for this batch\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Process each feature dimension\n for (int d = 0; d < feat_dim; d++) {\n const scalar_t feat_val = features[batch_idx * N * feat_dim + atom_idx * feat_dim + d];\n \n // Voxel grid index: (B, feat_dim, G, G, G) - index is [b, d, ix, iy, iz]\n const int voxel_idx = batch_idx * feat_dim * G * G * G + d * G * G * G + ix * G * G + iy * G + iz;\n \n // Atomic add\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n }\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers on CPU (small data, could also do on GPU)\n auto centers = coords.mean(/*dim=*/1); // (B, 3)\n \n const int threads = 256;\n const int blocks_y = (N + threads - 1) / threads;\n \n dim3 grid(B, blocks_y);\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<grid, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← static_check (ok)
okstatic_check
static_check PASSED: no violations or warnings detected.
turn 4 · 1 tool call(s) · 493.3s turn · 15.6s LLM · tokens in=5,706 · out=1,505 · total=7,211 · 7,102 chars (click to expand)
turn 4493.3s turn · 15.6s LLM · 477.8s tools · tokens in=5,706 · out=1,505 · total=7,211
reasoning
The static check passed. Let me now optimize the kernel further. There are a few potential improvements:
1. Process multiple feature dimensions per thread to reduce atomic contention
2. Use shared memory for local aggregation
3. Better memory access patterns
Let me think about this more carefully. The current issue is that multiple atoms might land in the same voxel, causing atomic contention. With 256 atoms per batch and 32x32x32 = 32768 voxels, most atoms should end up in different voxels unless they're clustered.
Actually, let me try an optimized version that:
1. Uses coalesced memory access better
2. Uses vectorized loads if possible
3. Reduces atomic contention
Let me also consider using a different approach: instead of one thread per atom, we could use one thread block per voxel and have threads in the block atomically aggregate within shared memory. But that might be more complex.
Actually, let me try a simpler optimization first: process all atoms and all feature dimensions more efficiently using better memory access patterns.
Let me also check if there's contention by using atomicAdd with float vs double. On H100, atomicAdd for float should be quite fast.
Let me try an optimized version:
assistantLet me optimize the kernel to improve performance. I'll try to reduce atomic contention and improve memory access patterns:
call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel with optimizations\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// Optimized kernel: each thread handles one atom across all feature dimensions\n// Uses vectorized loads and better memory access patterns\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n const int batch_idx = blockIdx.x;\n const int atom_idx = blockIdx.y * blockDim.x + threadIdx.x;\n \n if (batch_idx >= B || atom_idx >= N) return;\n \n // Load center for this batch (coalesced)\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates (coalesced within batch)\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Base index for this atom's features\n const int feat_base = batch_idx * N * feat_dim + atom_idx * feat_dim;\n \n // Base index for this voxel in the output grid\n const int voxel_base = batch_idx * feat_dim * G * G * G + ix * G * G + iy * G + iz;\n const int feat_dim_stride = G * G * G;\n \n // Process each feature dimension\n #pragma unroll 4\n for (int d = 0; d < feat_dim; d++) {\n const scalar_t feat_val = features[feat_base + d];\n const int voxel_idx = voxel_base + d * feat_dim_stride;\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n }\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers\n auto centers = coords.mean(/*dim=*/1); // (B, 3)\n \n const int threads = 256;\n const int blocks_y = (N + threads - 1) / threads;\n \n dim3 grid(B, blocks_y);\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<grid, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda_v2',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 5703.5s turn · 11.3s LLM · 692.1s tools · tokens in=6,972 · out=1,241 · total=8,213
reasoning
Let me check correctness for this optimized version.
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel with optimizations\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// Optimized kernel: each thread handles one atom across all feature dimensions\n// Uses vectorized loads and better memory access patterns\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n const int batch_idx = blockIdx.x;\n const int atom_idx = blockIdx.y * blockDim.x + threadIdx.x;\n \n if (batch_idx >= B || atom_idx >= N) return;\n \n // Load center for this batch (coalesced)\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates (coalesced within batch)\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Base index for this atom's features\n const int feat_base = batch_idx * N * feat_dim + atom_idx * feat_dim;\n \n // Base index for this voxel in the output grid\n const int voxel_base = batch_idx * feat_dim * G * G * G + ix * G * G + iy * G + iz;\n const int feat_dim_stride = G * G * G;\n \n // Process each feature dimension\n #pragma unroll 4\n for (int d = 0; d < feat_dim; d++) {\n const scalar_t feat_val = features[feat_base + d];\n const int voxel_idx = voxel_base + d * feat_dim_stride;\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n }\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers\n auto centers = coords.mean(/*dim=*/1); // (B, 3)\n \n const int threads = 256;\n const int blocks_y = (N + threads - 1) / threads;\n \n dim3 grid(B, blocks_y);\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<grid, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda_v2',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=2.38e-07 mean_abs_err=4.05e-14 max_rel_err=3.78e-07
turn 6 · 1 tool call(s) · 284.9s turn · 11.3s LLM · tokens in=8,261 · out=1,297 · total=9,558 · 6,104 chars (click to expand)
turn 6284.9s turn · 11.3s LLM · 273.6s tools · tokens in=8,261 · out=1,297 · total=9,558
reasoning
Good, still correct. Let me try a more optimized version that processes multiple atoms per thread block to improve data locality, and maybe use shared memory for reduction. But first let me submit this version to see how it performs.
assistantLet me try a more optimized version with better thread utilization and potentially using shared memory for reductions:
call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel with more aggressive optimizations\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// Optimized kernel with better thread utilization\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n // Use 1D grid for better flexibility\n const int total_atoms = B * N;\n const int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n if (idx >= total_atoms) return;\n \n // Decode batch and atom index\n const int batch_idx = idx / N;\n const int atom_idx = idx % N;\n \n // Load center for this batch\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Base index for this atom's features\n const int feat_base = batch_idx * N * feat_dim + atom_idx * feat_dim;\n \n // Base index for this voxel in the output grid\n const int voxel_base = batch_idx * feat_dim * G * G * G + ix * G * G + iy * G + iz;\n const int feat_dim_stride = G * G * G;\n \n // Process each feature dimension\n for (int d = 0; d < feat_dim; d++) {\n const scalar_t feat_val = features[feat_base + d];\n const int voxel_idx = voxel_base + d * feat_dim_stride;\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n }\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers\n auto centers = coords.mean(/*dim=*/1); // (B, 3)\n \n const int total_atoms = B * N;\n const int threads = 256;\n const int blocks = (total_atoms + threads - 1) / threads;\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<blocks, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda_v3',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 7610.7s turn · 11.7s LLM · 599.0s tools · tokens in=9,526 · out=1,272 · total=10,798
reasoning
Let me test correctness and if it passes, let me try a different approach - perhaps using float4 for vectorized loads since feat_dim is 32, which is divisible by 4.
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel with more aggressive optimizations\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// Optimized kernel with better thread utilization\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n // Use 1D grid for better flexibility\n const int total_atoms = B * N;\n const int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n if (idx >= total_atoms) return;\n \n // Decode batch and atom index\n const int batch_idx = idx / N;\n const int atom_idx = idx % N;\n \n // Load center for this batch\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Base index for this atom's features\n const int feat_base = batch_idx * N * feat_dim + atom_idx * feat_dim;\n \n // Base index for this voxel in the output grid\n const int voxel_base = batch_idx * feat_dim * G * G * G + ix * G * G + iy * G + iz;\n const int feat_dim_stride = G * G * G;\n \n // Process each feature dimension\n for (int d = 0; d < feat_dim; d++) {\n const scalar_t feat_val = features[feat_base + d];\n const int voxel_idx = voxel_base + d * feat_dim_stride;\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n }\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers\n auto centers = coords.mean(/*dim=*/1); // (B, 3)\n \n const int total_atoms = B * N;\n const int threads = 256;\n const int blocks = (total_atoms + threads - 1) / threads;\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<blocks, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda_v3',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=2.38e-07 mean_abs_err=3.77e-14 max_rel_err=3.78e-07
turn 8 · 1 tool call(s) · 365.7s turn · 20.7s LLM · tokens in=10,817 · out=2,233 · total=13,050 · 9,776 chars (click to expand)
turn 8365.7s turn · 20.7s LLM · 345.0s tools · tokens in=10,817 · out=2,233 · total=13,050
reasoning
There was a typo in my kernel - I wrote `feat_dim_stride` but declared it as `feat_dim_stride`. Let me check - actually I declared it as `feat_dim_stride` but used `feat_dim_stride`. Wait, I see the error now - I declared `feat_dim_stride` but used `feat_dim_stride` in the for loop. Let me check the code more carefully...
Actually looking at the code I submitted:
```
const int feat_dim_stride = G * G * G;
for (int d = 0; d < feat_dim; d++) {
const scalar_t feat_val = features[feat_base + d];
const int voxel_idx = voxel_base + d * feat_dim_stride;
```
It should be the same variable. But the kernel compiled and passed correctness, so maybe there was a typo in what I thought I saw. Let me re-check the actual code I sent...
Looking at the original, I see:
```
const int feat_dim_stride = G * G * G;
for (int d = 0; d < feat_dim; d++) {
const scalar_t feat_val = features[feat_base + d];
const int voxel_idx = voxel_base + d * feat_dim_stride; // This should be correct
```
Wait, I'm looking at what I have and it says `feat_dim_stride` not `feat_dim_stride`. There's something off. Let me just re-examine and submit a corrected version if needed.
Actually, looking more carefully at the kernel I sent, I see `feat_dim_stride` appears twice but there's no declaration matching that variable name. The declaration is `feat_dim_stride` but the usage is `feat_dim_stride`. Hmm, but the kernel compiled and passed correctness, so the code I sent must be correct. Let me look at the code I actually sent in the compile_kernel call:
```cpp
const int feat_dim_stride = G * G * G;
// Process each feature dimension
for (int d = 0; d < feat_dim; d++) {
const scalar_t feat_val = features[feat_base + d];
const int voxel_idx = voxel_base + d * feat_dim_stride;
```
Wait, I see `feat_dim_stride` in declaration but `feat_dim_stride` in usage! That should be a compile error. But the kernel compiled successfully... Let me check again very carefully.
Oh wait, I see now. I actually have different code in the two places. Let me look at the exact text I submitted:
Line 1: `const int feat_dim_stride = G * G * G;`
Line 2: `const int voxel_idx = voxel_base + d * feat_dim_stride;`
Actually both use `feat_dim_stride` (with `dim` not `dim`). But then in my last submission I see there's inconsistency. Let me check the v3 submission...
Actually, I realize I may have made a copy-paste error. The kernel that compiled successfully must have consistent variable names. Let me just re-write a clean version and test it again.
Actually, the correctness test passed, so the kernel must be fine. But let me double check with a cleaner version just to be sure, and potentially make more optimizations.
Let me try a different approach - using a thread-per-feature-dimension approach where each thread handles one (atom, feature_dim) pair, potentially giving better parallelism for small batch sizes.
assistantLet me try a more optimized version with better parallelism:
call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel with better parallelism\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// Optimized kernel: each thread handles one (atom, feature_dim) pair\n// This gives B * N * feat_dim total threads for maximum parallelism\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n const int total_work = B * N * feat_dim;\n const int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n if (idx >= total_work) return;\n \n // Decode indices\n const int d = idx % feat_dim;\n const int remainder = idx / feat_dim;\n const int batch_idx = remainder / N;\n const int atom_idx = remainder % N;\n \n // Load center for this batch\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Load feature value\n const scalar_t feat_val = features[batch_idx * N * feat_dim + atom_idx * feat_dim + d];\n \n // Compute voxel index: (B, feat_dim, G, G, G) - index is [b, d, ix, iy, iz]\n const int voxel_idx = batch_idx * feat_dim * G * G * G + d * G * G * G + ix * G * G + iy * G + iz;\n \n // Atomic add\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n}\n\n// Compute centers kernel\ntemplate <typename scalar_t>\n__global__ void compute_centers_kernel(\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ centers, // (B, 3)\n int B, int N\n) {\n const int batch_idx = blockIdx.x * blockDim.y + threadIdx.y;\n const int dim = threadIdx.x; // 0, 1, or 2\n \n if (batch_idx >= B) return;\n \n scalar_t sum = 0;\n for (int i = 0; i < N; i++) {\n sum += coords[batch_idx * N * 3 + i * 3 + dim];\n }\n centers[batch_idx * 3 + dim] = sum / static_cast<scalar_t>(N);\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers on GPU\n auto centers = torch::empty({B, 3}, coords.options());\n dim3 center_threads(3, 128); // 3 dims per batch, 128 batches per block\n dim3 center_blocks((B + 127) / 128);\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"compute_centers_kernel\", ([&] {\n compute_centers_kernel<scalar_t><<<center_blocks, center_threads>>>(\n coords.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N\n );\n }));\n \n const int total_work = B * N * feat_dim;\n const int threads = 256;\n const int blocks = (total_work + threads - 1) / threads;\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<blocks, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda_v4',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 9 · 1 tool call(s) · 427.9s turn · 14.2s LLM · tokens in=12,389 · out=1,549 · total=13,938 · 6,957 chars (click to expand)
turn 9427.9s turn · 14.2s LLM · 413.8s tools · tokens in=12,389 · out=1,549 · total=13,938
reasoning
The user is suggesting I submit the kernel now. Let me check if the last compiled version is correct by running the correctness test first, then submit if it passes.
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel with better parallelism\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// Optimized kernel: each thread handles one (atom, feature_dim) pair\n// This gives B * N * feat_dim total threads for maximum parallelism\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n const int total_work = B * N * feat_dim;\n const int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n if (idx >= total_work) return;\n \n // Decode indices\n const int d = idx % feat_dim;\n const int remainder = idx / feat_dim;\n const int batch_idx = remainder / N;\n const int atom_idx = remainder % N;\n \n // Load center for this batch\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Load feature value\n const scalar_t feat_val = features[batch_idx * N * feat_dim + atom_idx * feat_dim + d];\n \n // Compute voxel index: (B, feat_dim, G, G, G) - index is [b, d, ix, iy, iz]\n const int voxel_idx = batch_idx * feat_dim * G * G * G + d * G * G * G + ix * G * G + iy * G + iz;\n \n // Atomic add\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n}\n\n// Compute centers kernel\ntemplate <typename scalar_t>\n__global__ void compute_centers_kernel(\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ centers, // (B, 3)\n int B, int N\n) {\n const int batch_idx = blockIdx.x * blockDim.y + threadIdx.y;\n const int dim = threadIdx.x; // 0, 1, or 2\n \n if (batch_idx >= B) return;\n \n scalar_t sum = 0;\n for (int i = 0; i < N; i++) {\n sum += coords[batch_idx * N * 3 + i * 3 + dim];\n }\n centers[batch_idx * 3 + dim] = sum / static_cast<scalar_t>(N);\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers on GPU\n auto centers = torch::empty({B, 3}, coords.options());\n dim3 center_threads(3, 128); // 3 dims per batch, 128 batches per block\n dim3 center_blocks((B + 127) / 128);\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"compute_centers_kernel\", ([&] {\n compute_centers_kernel<scalar_t><<<center_blocks, center_threads>>>(\n coords.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N\n );\n }));\n \n const int total_work = B * N * feat_dim;\n const int threads = 256;\n const int blocks = (total_work + threads - 1) / threads;\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<blocks, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda_v4',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=1.19e-07 mean_abs_err=2.95e-14 max_rel_err=1.97e-07
turn 10 · 1 tool call(s) · 14.4s turn · 14.4s LLM · tokens in=13,994 · out=1,604 · total=15,598 · 7,089 chars (click to expand)
turn 1014.4s turn · 14.4s LLM · 0.0s tools · tokens in=13,994 · out=1,604 · total=15,598
reasoning
The kernel passes correctness. Since I have limited turns left and the kernel is working, I should submit it. The kernel:
1. Computes centers on GPU instead of CPU
2. Uses maximum parallelism with one thread per (atom, feature_dim) pair
3. Uses atomic adds for the voxel grid accumulation
This should be faster than the PyTorch reference which uses a Python loop and index_put_. Let me submit this kernel.
call → static_check
callstatic_check
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Define the CUDA kernel with better parallelism\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// Optimized kernel: each thread handles one (atom, feature_dim) pair\n// This gives B * N * feat_dim total threads for maximum parallelism\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n const int total_work = B * N * feat_dim;\n const int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n if (idx >= total_work) return;\n \n // Decode indices\n const int d = idx % feat_dim;\n const int remainder = idx / feat_dim;\n const int batch_idx = remainder / N;\n const int atom_idx = remainder % N;\n \n // Load center for this batch\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Load feature value\n const scalar_t feat_val = features[batch_idx * N * feat_dim + atom_idx * feat_dim + d];\n \n // Compute voxel index: (B, feat_dim, G, G, G) - index is [b, d, ix, iy, iz]\n const int voxel_idx = batch_idx * feat_dim * G * G * G + d * G * G * G + ix * G * G + iy * G + iz;\n \n // Atomic add\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n}\n\n// Compute centers kernel\ntemplate <typename scalar_t>\n__global__ void compute_centers_kernel(\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ centers, // (B, 3)\n int B, int N\n) {\n const int batch_idx = blockIdx.x * blockDim.y + threadIdx.y;\n const int dim = threadIdx.x; // 0, 1, or 2\n \n if (batch_idx >= B) return;\n \n scalar_t sum = 0;\n for (int i = 0; i < N; i++) {\n sum += coords[batch_idx * N * 3 + i * 3 + dim];\n }\n centers[batch_idx * 3 + dim] = sum / static_cast<scalar_t>(N);\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers on GPU\n auto centers = torch::empty({B, 3}, coords.options());\n dim3 center_threads(3, 128); // 3 dims per batch, 128 batches per block\n dim3 center_blocks((B + 127) / 128);\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"compute_centers_kernel\", ([&] {\n compute_centers_kernel<scalar_t><<<center_blocks, center_threads>>>(\n coords.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N\n );\n }));\n \n const int total_work = B * N * feat_dim;\n const int threads = 256;\n const int blocks = (total_work + threads - 1) / threads;\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<blocks, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda_v4',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← static_check (ok)
okstatic_check
static_check PASSED: no violations or warnings detected.
turn 11 · FINAL · 1 tool call(s) · 1107.1s turn · 12.8s LLM · tokens in=15,612 · out=1,533 · total=17,145 · 7,181 chars (click to expand)
turn 111107.1s turn · 12.8s LLM · 1094.3s tools · tokens in=15,612 · out=1,533 · total=17,145 · FINAL
reasoning
The kernel has passed all correctness tests and the static check. I should 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\n# Define the CUDA kernel with better parallelism\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// Optimized kernel: each thread handles one (atom, feature_dim) pair\n// This gives B * N * feat_dim total threads for maximum parallelism\ntemplate <typename scalar_t>\n__global__ void voxel_pool_kernel(\n const scalar_t* __restrict__ features, // (B, N, feat_dim)\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)\n const scalar_t* __restrict__ centers, // (B, 3)\n int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G\n) {\n const int total_work = B * N * feat_dim;\n const int idx = blockIdx.x * blockDim.x + threadIdx.x;\n \n if (idx >= total_work) return;\n \n // Decode indices\n const int d = idx % feat_dim;\n const int remainder = idx / feat_dim;\n const int batch_idx = remainder / N;\n const int atom_idx = remainder % N;\n \n // Load center for this batch\n const scalar_t cx = centers[batch_idx * 3 + 0];\n const scalar_t cy = centers[batch_idx * 3 + 1];\n const scalar_t cz = centers[batch_idx * 3 + 2];\n \n // Load coordinates\n const int coord_base = batch_idx * N * 3 + atom_idx * 3;\n const scalar_t x = coords[coord_base + 0];\n const scalar_t y = coords[coord_base + 1];\n const scalar_t z = coords[coord_base + 2];\n \n // Compute grid indices\n const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));\n const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));\n const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));\n \n // Load feature value\n const scalar_t feat_val = features[batch_idx * N * feat_dim + atom_idx * feat_dim + d];\n \n // Compute voxel index: (B, feat_dim, G, G, G) - index is [b, d, ix, iy, iz]\n const int voxel_idx = batch_idx * feat_dim * G * G * G + d * G * G * G + ix * G * G + iy * G + iz;\n \n // Atomic add\n atomicAdd(&voxel_grid[voxel_idx], feat_val);\n}\n\n// Compute centers kernel\ntemplate <typename scalar_t>\n__global__ void compute_centers_kernel(\n const scalar_t* __restrict__ coords, // (B, N, 3)\n scalar_t* __restrict__ centers, // (B, 3)\n int B, int N\n) {\n const int batch_idx = blockIdx.x * blockDim.y + threadIdx.y;\n const int dim = threadIdx.x; // 0, 1, or 2\n \n if (batch_idx >= B) return;\n \n scalar_t sum = 0;\n for (int i = 0; i < N; i++) {\n sum += coords[batch_idx * N * 3 + i * 3 + dim];\n }\n centers[batch_idx * 3 + dim] = sum / static_cast<scalar_t>(N);\n}\n\ntorch::Tensor voxel_pool_cuda(\n torch::Tensor features, // (B, N, feat_dim) - already transformed\n torch::Tensor coords, // (B, N, 3)\n torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros\n int G, float voxel_size\n) {\n const int B = coords.size(0);\n const int N = coords.size(1);\n const int feat_dim = features.size(2);\n const float half_G = static_cast<float>(G) / 2.0f;\n \n // Compute centers on GPU\n auto centers = torch::empty({B, 3}, coords.options());\n dim3 center_threads(3, 128); // 3 dims per batch, 128 batches per block\n dim3 center_blocks((B + 127) / 128);\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"compute_centers_kernel\", ([&] {\n compute_centers_kernel<scalar_t><<<center_blocks, center_threads>>>(\n coords.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N\n );\n }));\n \n const int total_work = B * N * feat_dim;\n const int threads = 256;\n const int blocks = (total_work + threads - 1) / threads;\n \n AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), \"voxel_pool_kernel\", ([&] {\n voxel_pool_kernel<scalar_t><<<blocks, threads>>>(\n features.data_ptr<scalar_t>(),\n coords.data_ptr<scalar_t>(),\n voxel_grid.data_ptr<scalar_t>(),\n centers.data_ptr<scalar_t>(),\n B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)\n );\n }));\n \n return voxel_grid;\n}\n'''\n\ncpp_source = r'''\ntorch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);\n'''\n\nvoxel_extension = load_inline(\n name='voxel_pool_cuda_v4',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['voxel_pool_cuda'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):\n super().__init__()\n self.feat_dim = feat_dim\n self.grid_size = grid_size\n self.voxel_size = voxel_size\n self.linear = nn.Linear(feat_dim, feat_dim)\n\n def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:\n B, N, _ = coords.shape\n G = self.grid_size\n\n features = self.linear(features)\n\n # Initialize voxel grid\n voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)\n\n # Call CUDA kernel\n voxel_grid = voxel_extension.voxel_pool_cuda(\n features.contiguous(),\n coords.contiguous(),\n voxel_grid,\n G,\n self.voxel_size\n )\n\n return voxel_grid"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 0.06 μs
Runtime stats: mean=0.06μs median=?μs std=0.00μs
Numerical precision: max_abs_err=1.19e-07 mean_abs_err=2.95e-14 max_rel_err=1.97e-07
Memory: 49.27 MB peak (ref: 49.85 MB, ratio: 0.9884x)
Kernel launches: 13 (ref: 4484, fusion ratio: 344.9231)
SOL score: 0.8545
Flagged for excessive speedup — this submission may have been rejected by automated review.
final submitted kernel (159 lines, 5,521 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
# Define the CUDA kernel with better parallelism
cuda_source = r'''
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
// Optimized kernel: each thread handles one (atom, feature_dim) pair
// This gives B * N * feat_dim total threads for maximum parallelism
template <typename scalar_t>
__global__ void voxel_pool_kernel(
const scalar_t* __restrict__ features, // (B, N, feat_dim)
const scalar_t* __restrict__ coords, // (B, N, 3)
scalar_t* __restrict__ voxel_grid, // (B, feat_dim, G, G, G)
const scalar_t* __restrict__ centers, // (B, 3)
int B, int N, int feat_dim, int G, scalar_t voxel_size, scalar_t half_G
) {
const int total_work = B * N * feat_dim;
const int idx = blockIdx.x * blockDim.x + threadIdx.x;
if (idx >= total_work) return;
// Decode indices
const int d = idx % feat_dim;
const int remainder = idx / feat_dim;
const int batch_idx = remainder / N;
const int atom_idx = remainder % N;
// Load center for this batch
const scalar_t cx = centers[batch_idx * 3 + 0];
const scalar_t cy = centers[batch_idx * 3 + 1];
const scalar_t cz = centers[batch_idx * 3 + 2];
// Load coordinates
const int coord_base = batch_idx * N * 3 + atom_idx * 3;
const scalar_t x = coords[coord_base + 0];
const scalar_t y = coords[coord_base + 1];
const scalar_t z = coords[coord_base + 2];
// Compute grid indices
const int ix = max(0, min(G - 1, static_cast<int>((x - cx) / voxel_size + half_G)));
const int iy = max(0, min(G - 1, static_cast<int>((y - cy) / voxel_size + half_G)));
const int iz = max(0, min(G - 1, static_cast<int>((z - cz) / voxel_size + half_G)));
// Load feature value
const scalar_t feat_val = features[batch_idx * N * feat_dim + atom_idx * feat_dim + d];
// Compute voxel index: (B, feat_dim, G, G, G) - index is [b, d, ix, iy, iz]
const int voxel_idx = batch_idx * feat_dim * G * G * G + d * G * G * G + ix * G * G + iy * G + iz;
// Atomic add
atomicAdd(&voxel_grid[voxel_idx], feat_val);
}
// Compute centers kernel
template <typename scalar_t>
__global__ void compute_centers_kernel(
const scalar_t* __restrict__ coords, // (B, N, 3)
scalar_t* __restrict__ centers, // (B, 3)
int B, int N
) {
const int batch_idx = blockIdx.x * blockDim.y + threadIdx.y;
const int dim = threadIdx.x; // 0, 1, or 2
if (batch_idx >= B) return;
scalar_t sum = 0;
for (int i = 0; i < N; i++) {
sum += coords[batch_idx * N * 3 + i * 3 + dim];
}
centers[batch_idx * 3 + dim] = sum / static_cast<scalar_t>(N);
}
torch::Tensor voxel_pool_cuda(
torch::Tensor features, // (B, N, feat_dim) - already transformed
torch::Tensor coords, // (B, N, 3)
torch::Tensor voxel_grid, // (B, feat_dim, G, G, G) - pre-initialized zeros
int G, float voxel_size
) {
const int B = coords.size(0);
const int N = coords.size(1);
const int feat_dim = features.size(2);
const float half_G = static_cast<float>(G) / 2.0f;
// Compute centers on GPU
auto centers = torch::empty({B, 3}, coords.options());
dim3 center_threads(3, 128); // 3 dims per batch, 128 batches per block
dim3 center_blocks((B + 127) / 128);
AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), "compute_centers_kernel", ([&] {
compute_centers_kernel<scalar_t><<<center_blocks, center_threads>>>(
coords.data_ptr<scalar_t>(),
centers.data_ptr<scalar_t>(),
B, N
);
}));
const int total_work = B * N * feat_dim;
const int threads = 256;
const int blocks = (total_work + threads - 1) / threads;
AT_DISPATCH_FLOATING_TYPES(features.scalar_type(), "voxel_pool_kernel", ([&] {
voxel_pool_kernel<scalar_t><<<blocks, threads>>>(
features.data_ptr<scalar_t>(),
coords.data_ptr<scalar_t>(),
voxel_grid.data_ptr<scalar_t>(),
centers.data_ptr<scalar_t>(),
B, N, feat_dim, G, static_cast<scalar_t>(voxel_size), static_cast<scalar_t>(half_G)
);
}));
return voxel_grid;
}
'''
cpp_source = r'''
torch::Tensor voxel_pool_cuda(torch::Tensor features, torch::Tensor coords, torch::Tensor voxel_grid, int G, float voxel_size);
'''
voxel_extension = load_inline(
name='voxel_pool_cuda_v4',
cpp_sources=cpp_source,
cuda_sources=cuda_source,
functions=['voxel_pool_cuda'],
extra_cuda_cflags=['-O3', '-use_fast_math'],
verbose=True
)
class ModelNew(nn.Module):
def __init__(self, feat_dim, grid_size=32, voxel_size=1.0):
super().__init__()
self.feat_dim = feat_dim
self.grid_size = grid_size
self.voxel_size = voxel_size
self.linear = nn.Linear(feat_dim, feat_dim)
def forward(self, coords: torch.Tensor, features: torch.Tensor) -> torch.Tensor:
B, N, _ = coords.shape
G = self.grid_size
features = self.linear(features)
# Initialize voxel grid
voxel_grid = coords.new_zeros(B, self.feat_dim, G, G, G)
# Call CUDA kernel
voxel_grid = voxel_extension.voxel_pool_cuda(
features.contiguous(),
coords.contiguous(),
voxel_grid,
G,
self.voxel_size
)
return voxel_grid