turn 01180.9s turn · 30.2s LLM · 1150.7s tools · tokens in=1,411 · out=2,944 · total=4,786 · FINAL
reasoning
The task is to replace the forward computation of this SE(3)-invariant linear layer with a custom CUDA kernel for speed.
I need to replace the forward computation of this SE(3)-invariant linear layer with a custom CUDA kernel to boost speed. The goal is to create a complete Python file defining `ModelNew` that mirrors `Model` but uses a custom CUDA kernel via `torch.utils.cpp_extension.
assistant```python
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
cuda_source = r'''
#include <torch/extension.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <math.h>
__global__ void se3_linear_kernel(
const float* __restrict__ scalar_feat,
const float* __restrict__ vector_feat,
const float* __restrict__ scalar_weight,
const float* __restrict__ scalar_bias,
const float* __restrict__ vector_weight,
const float* __restrict__ gate_weight,
const float* __restrict__ gate_bias,
float* __restrict__ scalar_out,
float* __restrict__ vector_out,
int B, int N, int scalar_in, int scalar_out_dim, int vector_in, int vector_out_dim
) {
int idx = blockIdx.x * blockDim.x + threadIdx.x;
int total = B * N;
if (idx >= total) return;
int b = idx / N;
int n = idx % N;
extern __shared__ float smem[];
float* vec_norm = smem;
float* combined = smem + vector_in;
float* s_out_local = combined + scalar_in + vector_in;
float* gate_local = s_out_local + scalar_out_dim;
// Compute vec_norm
for (int i = 0; i < vector_in; i++) {
float sum = 0.0f;
for (int d = 0; d < 3; d++) {
float v = vector_feat[((b * N + n) * vector_in + i) * 3 + d];
sum += v * v;
}
vec_norm[i] = sqrtf(sum);
}
// combined
for (int i = 0; i < scalar_in; i++) {
combined[i] = scalar_feat[(b * N + n) * scalar_in + i];
}
for (int i = 0; i < vector_in; i++) {
combined[scalar_in + i] = vec_norm[i];
}
// scalar linear
for (int o = 0; o < scalar_out_dim; o++) {
float sum = scalar_bias[o];
for (int i = 0; i < scalar_in + vector_in; i++) {
sum += combined[i] * scalar_weight[o * (scalar_in + vector_in) + i];
}
s_out_local[o] = sum;
scalar_out[(b * N + n) * scalar_out_dim + o] = sum;
}
// gate
for (int o = 0; o < vector_out_dim; o++) {
float sum = gate_bias[o];
for (int i = 0; i < scalar_in + vector_in; i++) {
sum += combined[i] * gate_weight[o * (scalar_in + vector_in) + i];
}
gate_local[o] = 1.0f / (1.0f + expf(-sum));
}
// vector transform + gate
for (int o = 0; o < vector_out_dim; o++) {
float g = gate_local[o];
for (int d = 0; d < 3; d++) {
float sum = 0.0f;
for (int i = 0; i < vector_in; i++) {
sum += vector_weight[o * vector_in + i] * vector_feat[((b * N + n) * vector_in + i) * 3 + d];
}
vector_out[((b * N + n) * vector_out_dim + o) * 3 + d] = g * sum;
}
}
}
torch::Tensor se3_forward_cuda(
torch::Tensor scalar_feat,
torch::Tensor vector_feat,
torch::Tensor scalar_weight,
torch::Tensor scalar_bias,
torch::Tensor vector_weight,
torch::Tensor gate_weight,
torch::Tensor gate_bias
) {
int B = scalar_feat.size(0);
int N = scalar_feat.size(1);
int scalar_in = scalar_feat.size(2);
int vector_in = vector_feat.size(2);
int scalar_out_dim = scalar_weight.size(0);
int vector_out_dim = vector_weight.size(0);
auto options = torch::TensorOptions().dtype(torch::kFloat32).device(scalar_feat.device());
auto scalar_out = torch::empty({B, N, scalar_out_dim}, options);
auto vector_out = torch::empty({B, N, vector_out_dim, 3}, options);
int total = B * N;
int threads = 256;
int blocks = (total + threads - 1) / threads;
int smem_size = (vector_in + scalar_in + vector_in + scalar_out_dim + vector_out_dim) * sizeof(float);
se3_linear_kernel<<<blocks, threads, smem_size>>>(
scalar_feat.data_ptr<float>(),
vector_feat.data_ptr<float>(),
scalar_weight.data_ptr<float>(),
scalar_bias.data_ptr<float>(),
vector_weight.data_ptr<float>(),
gate_weight.data_ptr<float>(),
gate_bias.data_ptr<float>(),
scalar_out.data_ptr<float>(),
vector_out.data_ptr<float>(),
B, N, scalar_in, scalar_out_dim, vector_in, vector_out_dim
);
return std::make_tuple(scalar_out, vector_out); // wait, need to return tuple properly but adjust
}
'''
# Fix return - actually use a wrapper that returns tuple
cpp_source = r'''
#include <torch/extension.h>
std::tuple<torch::Tensor, torch::Tensor> se3_forward_cuda(
torch::Tensor scalar_feat,
torch::Tensor vector_feat,
torch::Tensor scalar_weight,
torch::Tensor scalar_bias,
torch::Tensor vector_weight,
torch::Tensor gate_weight,
torch::Tensor gate_bias
);
'''
# Note: the return in cuda is placeholder, we will fix in python wrapper
mod = load_inline(
name='se3_linear',
cpp_sources=cpp_source,
cuda_sources=cuda_source,
functions=['se3_forward_cuda'],
verbose=False
)
class ModelNew(nn.Module):
def __init__(self, scalar_in, scalar_out, vector_in, vector_out):
super().__init__()
self.scalar_linear = nn.Linear(scalar_in + vector_in, scalar_out)
self.vector_weight = nn.Parameter(torch.randn(vector_out, vector_in))
nn.init.xavier_uniform_(self.vector_weight)
self.vector_gate = nn.Linear(scalar_in + vector_in, vector_out)
self.mod = mod
def forward(self, scalar_feat: torch.Tensor, vector_feat: torch.Tensor):
s_out, v_out = self.mod.se3_forward_cuda(
scalar_feat,
vector_feat,
self.scalar_linear.weight,
self.scalar_linear.bias,
self.vector_weight,
self.vector_gate.weight,
self.vector_gate.bias
)
return s_out, v_out
```
The above has a compilation issue in the CUDA return (tuple not handled in C++), but since final, adjusted conceptually. Actually for correctness we need proper.
To make it work, the CUDA func needs to return tuple properly.
Since must submit, here is the code with fix implied. But I put a complete one.
Corrected full code: I realize the tool call.
call → submit_kernel
callsubmit_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__global__ void se3_linear_kernel(\n const float* __restrict__ scalar_feat,\n const float* __restrict__ vector_feat,\n const float* __restrict__ scalar_weight,\n const float* __restrict__ scalar_bias,\n const float* __restrict__ vector_weight,\n const float* __restrict__ gate_weight,\n const float* __restrict__ gate_bias,\n float* __restrict__ scalar_out,\n float* __restrict__ vector_out,\n int B, int N, int scalar_in, int scalar_out_dim, int vector_in, int vector_out_dim\n) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * N;\n if (idx >= total) return;\n\n extern __shared__ float smem[];\n float* vec_norm = smem;\n float* combined = vec_norm + vector_in;\n float* gate_local = combined + scalar_in + vector_in;\n\n // vec_norm\n #pragma unroll 4\n for (int i = 0; i < vector_in; ++i) {\n float sum = 0.0f;\n for (int d = 0; d < 3; ++d) {\n float v = vector_feat[((idx * vector_in) + i) * 3 + d];\n sum += v * v;\n }\n vec_norm[i] = sqrtf(sum);\n }\n\n // combined\n for (int i = 0; i < scalar_in; ++i) {\n combined[i] = scalar_feat[idx * scalar_in + i];\n }\n for (int i = 0; i < vector_in; ++i) {\n combined[scalar_in + i] = vec_norm[i];\n }\n\n // scalar linear\n for (int o = 0; o < scalar_out_dim; ++o) {\n float sum = scalar_bias[o];\n for (int i = 0; i < scalar_in + vector_in; ++i) {\n sum += combined[i] * scalar_weight[o * (scalar_in + vector_in) + i];\n }\n scalar_out[idx * scalar_out_dim + o] = sum;\n }\n\n // gate\n for (int o = 0; o < vector_out_dim; ++o) {\n float sum = gate_bias[o];\n for (int i = 0; i < scalar_in + vector_in; ++i) {\n sum += combined[i] * gate_weight[o * (scalar_in + vector_in) + i];\n }\n gate_local[o] = 1.0f / (1.0f + expf(-sum));\n }\n\n // vector transform + gate\n for (int o = 0; o < vector_out_dim; ++o) {\n float g = gate_local[o];\n for (int d = 0; d < 3; ++d) {\n float sum = 0.0f;\n for (int i = 0; i < vector_in; ++i) {\n sum += vector_weight[o * vector_in + i] * vector_feat[(idx * vector_in + i) * 3 + d];\n }\n vector_out[(idx * vector_out_dim + o) * 3 + d] = g * sum;\n }\n }\n}\n\nstd::tuple<torch::Tensor, torch::Tensor> se3_forward_cuda(\n torch::Tensor scalar_feat,\n torch::Tensor vector_feat,\n torch::Tensor scalar_weight,\n torch::Tensor scalar_bias,\n torch::Tensor vector_weight,\n torch::Tensor gate_weight,\n torch::Tensor gate_bias\n) {\n int B = scalar_feat.size(0);\n int N = scalar_feat.size(1);\n int sc_in = scalar_feat.size(2);\n int v_in = vector_feat.size(2);\n int sc_out = scalar_weight.size(0);\n int v_out = vector_weight.size(0);\n\n auto options = torch::TensorOptions().dtype(torch::kFloat32).device(scalar_feat.device());\n auto s_out = torch::empty({B, N, sc_out}, options);\n auto v_out = torch::empty({B, N, v_out, 3}, options);\n\n int total = B * N;\n dim3 blocks((total + 255) / 256);\n dim3 threads(256);\n size_t smem = (v_in + sc_in + v_in + v_out) * sizeof(float);\n\n se3_linear_kernel<<<blocks, threads, smem>>>(\n scalar_feat.data_ptr<float>(),\n vector_feat.data_ptr<float>(),\n scalar_weight.data_ptr<float>(),\n scalar_bias.data_ptr<float>(),\n vector_weight.data_ptr<float>(),\n gate_weight.data_ptr<float>(),\n gate_bias.data_ptr<float>(),\n s_out.data_ptr<float>(),\n v_out.data_ptr<float>(),\n B, N, sc_in, sc_out, v_in, v_out\n );\n\n return std::make_tuple(s_out, v_out);\n}\n'''\n\ncpp_source = '''\n#include <torch/extension.h>\nstd::tuple<torch::Tensor, torch::Tensor> se3_forward_cuda(\n torch::Tensor scalar_feat, torch::Tensor vector_feat,\n torch::Tensor scalar_weight, torch::Tensor scalar_bias,\n torch::Tensor vector_weight, torch::Tensor gate_weight, torch::Tensor gate_bias);\n'''\n\nmod = load_inline(\n name='se3_mod',\n cpp_sources=[cpp_source],\n cuda_sources=[cuda_source],\n functions=['se3_forward_cuda'],\n verbose=False\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, scalar_in, scalar_out, vector_in, vector_out):\n super().__init__()\n self.scalar_linear = nn.Linear(scalar_in + vector_in, scalar_out)\n self.vector_weight = nn.Parameter(torch.randn(vector_out, vector_in))\n nn.init.xavier_uniform_(self.vector_weight)\n self.vector_gate = nn.Linear(scalar_in + vector_in, vector_out)\n\n def forward(self, scalar_feat, vector_feat):\n return mod.se3_forward_cuda(\n scalar_feat.contiguous(),\n vector_feat.contiguous(),\n self.scalar_linear.weight,\n self.scalar_linear.bias,\n self.vector_weight,\n self.vector_gate.weight,\n self.vector_gate.bias\n )\n"
}
result ← submit_kernel (fail)
failsubmit_kernel
submit_kernel FAILED: kernel did not compile.
Error building extension 'se3_mod': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=se3_mod -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -fPIC -std=c++17 -c /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/grok-4.3/level_1_problem_22_cache/k_4d3261da5923/se3_mod/main.cpp -o main.o
[2/3] /usr/local/cuda/bin/nvcc -MD -MF cuda.cuda.o.d -ccbin /opt/conda/bin/x86_64-conda-linux-gnu-cc -DTORCH_EXTENSION_NAME=se3_mod -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -D__CUDA_NO_HALF_OPERATORS__ -D__CUDA_NO_HALF_CONVERSIONS__ -D__CUDA_NO_BFLOAT16_CONVERSIONS__ -D__CUDA_NO_HALF2_OPERATORS__ --expt-relaxed-constexpr -gencode=arch=compute_90,code=compute_90 -gencode=arch=compute_90,code=sm_90 --compiler-options '-fPIC' -std=c++17 -c /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/grok-4.3/level_1_problem_22_cache/k_4d3261da5923/se3_mod/cuda.cu -o cuda.cuda.o
FAILED: [code=2] cuda.cuda.o
/usr/local/cuda/bin/nvcc -MD -MF cuda.cuda.o.d -ccbin /opt/conda/bin/x86_64-conda-linux-gnu-cc -DTORCH_EXTENSION_NAME=se3_mod -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/abaner/KernelBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /opt/conda/include/python3.10 -D__CUDA_NO_HALF_OPERATORS__ -D__CUDA_NO_HALF_CONVERSIONS__ -D__CUDA_NO_BFLOAT16_CONVERSIONS__ -D__CUDA_NO_HALF2_OPERATORS__ --expt-relaxed-constexpr -gencode=arch=compute_90,code=compute_90 -gencode=arch=compute_90,code=sm_90 --compiler-options '-fPIC' -std=c++17 -c /scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/grok-4.3/level_1_problem_22_cache/k_4d3261da5923/se3_mod/cuda.cu -o cuda.cuda.o
nvcc warning : incompatible redefinition for option 'compiler-bindir', the last value of this option was used
/scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/grok-4.3/level_1_problem_22_cache/k_4d3261da5923/se3_mod/cuda.cu(98): error: "v_out" has already been declared in the current scope
auto v_out = torch::empty({B, N, v_out, 3}, options);
^
/scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/grok-4.3/level_1_problem_22_cache/k_4d3261da5923/se3_mod/cuda.cu(98): error: a variable declared with an auto type specifier cannot appear in its own initializer
auto v_out = torch::empty({B, N, v_out, 3}, options);
^
/scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/grok-4.3/level_1_problem_22_cache/k_4d3261da5923/se3_mod/cuda.cu(103): error: no suitable conversion function from "at::Tensor" to "size_t" (aka "unsigned long") exists
size_t smem = (v_in + sc_in + v_in + v_out) * sizeof(float);
^
/scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/grok-4.3/level_1_problem_22_cache/k_4d3261da5923/se3_mod/cuda.cu(115): error: no suitable conversion function from "at::Tensor" to "int" exists
B, N, sc_in, sc_out, v_in, v_out
^
4 errors detected in the compilation of "/scratch/abaner/KernelBench/runs/pop_l123_st_gpt/popcorn/grok-4.3/level_1_problem_22_cache/k_4d3261da5923/se3_mod/cuda.cu".
ninja: build stopped: subcommand failed.