call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n# Fused probability-flow ODE integration kernel\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n// SiLU activation: x * sigmoid(x)\n__device__ __forceinline__ float silu(float x) {\n return x * (1.0f / (1.0f + expf(-x)));\n}\n\n// Fused MLP forward pass for velocity network\ntemplate <int IN_DIM, int HIDDEN_DIM, int OUT_DIM, int BLOCK_SIZE>\n__device__ void fused_mlp_forward(\n const float* __restrict__ input, // [IN_DIM]\n float* __restrict__ output, // [OUT_DIM]\n const float* __restrict__ w1, // [HIDDEN_DIM, IN_DIM]\n const float* __restrict__ b1, // [HIDDEN_DIM]\n const float* __restrict__ w2, // [HIDDEN_DIM, HIDDEN_DIM]\n const float* __restrict__ b2, // [HIDDEN_DIM]\n const float* __restrict__ w3, // [OUT_DIM, HIDDEN_DIM]\n const float* __restrict__ b3, // [OUT_DIM]\n float* __restrict__ shared_buf // shared memory buffer\n) {\n // Stage 1: Linear1 + SiLU\n float* hidden1 = shared_buf; // [HIDDEN_DIM]\n \n for (int h = threadIdx.x; h < HIDDEN_DIM; h += BLOCK_SIZE) {\n float sum = b1[h];\n for (int i = 0; i < IN_DIM; i++) {\n sum += w1[h * IN_DIM + i] * input[i];\n }\n hidden1[h] = silu(sum);\n }\n __syncthreads();\n \n // Stage 2: Linear2 + SiLU\n float* hidden2 = shared_buf + HIDDEN_DIM; // [HIDDEN_DIM]\n \n for (int h = threadIdx.x; h < HIDDEN_DIM; h += BLOCK_SIZE) {\n float sum = b2[h];\n for (int i = 0; i < HIDDEN_DIM; i++) {\n sum += w2[h * HIDDEN_DIM + i] * hidden1[i];\n }\n hidden2[h] = silu(sum);\n }\n __syncthreads();\n \n // Stage 3: Linear3 (output layer)\n for (int o = threadIdx.x; o < OUT_DIM; o += BLOCK_SIZE) {\n float sum = b3[o];\n for (int i = 0; i < HIDDEN_DIM; i++) {\n sum += w3[o * HIDDEN_DIM + i] * hidden2[i];\n }\n output[o] = sum;\n }\n __syncthreads();\n}\n\n// Main kernel: fused Euler integration\ntemplate <int DIM, int HIDDEN_DIM, int NUM_STEPS, int BLOCK_SIZE>\n__global__ void fused_euler_ode_kernel(\n const float* __restrict__ x0, // [B, DIM]\n float* __restrict__ x_out, // [B, DIM]\n const float* __restrict__ w1, // [HIDDEN_DIM, DIM+1]\n const float* __restrict__ b1, // [HIDDEN_DIM]\n const float* __restrict__ w2, // [HIDDEN_DIM, HIDDEN_DIM]\n const float* __restrict__ b2, // [HIDDEN_DIM]\n const float* __restrict__ w3, // [DIM, HIDDEN_DIM]\n const float* __restrict__ b3, // [DIM]\n const float dt // time step = 1.0 / NUM_STEPS\n) {\n const int batch_idx = blockIdx.x;\n const int tid = threadIdx.x;\n \n // Shared memory: input buffer + hidden1 + hidden2 + velocity\n extern __shared__ float shared_mem[];\n float* input_buf = shared_mem; // [DIM+1]\n float* hidden_buf = shared_mem + (DIM + 1); // [2 * HIDDEN_DIM]\n float* velocity_buf = hidden_buf + 2 * HIDDEN_DIM; // [DIM]\n \n // Load initial x into registers\n float x_reg[DIM];\n const float* x0_ptr = x0 + batch_idx * DIM;\n \n #pragma unroll\n for (int d = tid; d < DIM; d += BLOCK_SIZE) {\n x_reg[d] = x0_ptr[d];\n }\n __syncthreads();\n \n // Euler integration loop\n for (int step = 0; step < NUM_STEPS; step++) {\n // Compute time t = (k + 0.5) / num_steps\n const float t = (float(step) + 0.5f) / float(NUM_STEPS);\n \n // Prepare input: [x, t]\n for (int d = tid; d < DIM; d += BLOCK_SIZE) {\n input_buf[d] = x_reg[d];\n }\n if (tid == 0) {\n input_buf[DIM] = t;\n }\n __syncthreads();\n \n // Compute velocity through fused MLP\n fused_mlp_forward<DIM + 1, HIDDEN_DIM, DIM, BLOCK_SIZE>(\n input_buf, velocity_buf,\n w1, b1, w2, b2, w3, b3,\n hidden_buf\n );\n __syncthreads();\n \n // Euler update: x = x + dt * v\n for (int d = tid; d < DIM; d += BLOCK_SIZE) {\n x_reg[d] += dt * velocity_buf[d];\n }\n __syncthreads();\n }\n \n // Write output\n float* x_out_ptr = x_out + batch_idx * DIM;\n for (int d = tid; d < DIM; d += BLOCK_SIZE) {\n x_out_ptr[d] = x_reg[d];\n }\n}\n\n// Host function to launch kernel\nvoid launch_fused_euler_ode(\n const torch::Tensor& x0,\n torch::Tensor& x_out,\n const torch::Tensor& w1,\n const torch::Tensor& b1,\n const torch::Tensor& w2,\n const torch::Tensor& b2,\n const torch::Tensor& w3,\n const torch::Tensor& b3,\n int dim, int hidden_dim, int num_steps\n) {\n const int batch_size = x0.size(0);\n const float dt = 1.0f / float(num_steps);\n \n const int block_size = 128; // Tunable\n \n // Shared memory size: input(DIM+1) + 2*hidden + output(DIM)\n size_t shared_mem_size = (dim + 1 + 2 * hidden_dim + dim) * sizeof(float);\n \n // Launch configuration\n dim3 grid(batch_size);\n dim3 block(block_size);\n \n fused_euler_ode_kernel<64, 256, 32, 128><<<grid, block, shared_mem_size>>>(\n x0.data_ptr<float>(),\n x_out.data_ptr<float>(),\n w1.data_ptr<float>(),\n b1.data_ptr<float>(),\n w2.data_ptr<float>(),\n b2.data_ptr<float>(),\n w3.data_ptr<float>(),\n b3.data_ptr<float>(),\n dt\n );\n}\n\"\"\"\n\ncpp_source = r\"\"\"\nvoid launch_fused_euler_ode(\n const torch::Tensor& x0,\n torch::Tensor& x_out,\n const torch::Tensor& w1,\n const torch::Tensor& b1,\n const torch::Tensor& w2,\n const torch::Tensor& b2,\n const torch::Tensor& w3,\n const torch::Tensor& b3,\n int dim, int hidden_dim, int num_steps\n);\n\"\"\"\n\n# Load the CUDA extension\nfused_ode_module = load_inline(\n name='fused_ode_extension',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['launch_fused_euler_ode'],\n extra_cuda_cflags=['-O3', '--use_fast_math'],\n verbose=True\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, num_steps: int):\n super().__init__()\n assert dim >= 1 and num_steps >= 1\n self.dim = dim\n self.num_steps = num_steps\n self.hidden_dim = dim * 4\n \n # Create the velocity network (same architecture as reference)\n self.velocity = nn.Sequential(\n nn.Linear(dim + 1, self.hidden_dim),\n nn.SiLU(),\n nn.Linear(self.hidden_dim, self.hidden_dim),\n nn.SiLU(),\n nn.Linear(self.hidden_dim, dim),\n )\n\n def forward(self, x0: torch.Tensor) -> torch.Tensor:\n B, d = x0.shape\n assert d == self.dim\n \n # Ensure contiguous float32 tensors\n x0_f32 = x0.float().contiguous()\n \n # Get weight tensors from velocity network\n # Sequential: [Linear, SiLU, Linear, SiLU, Linear]\n # Indices: 0 1 2 3 4\n w1 = self.velocity[0].weight.data.float().contiguous() # [hidden, dim+1]\n b1 = self.velocity[0].bias.data.float().contiguous() # [hidden]\n w2 = self.velocity[2].weight.data.float().contiguous() # [hidden, hidden]\n b2 = self.velocity[2].bias.data.float().contiguous() # [hidden]\n w3 = self.velocity[4].weight.data.float().contiguous() # [dim, hidden]\n b3 = self.velocity[4].bias.data.float().contiguous() # [dim]\n \n # Allocate output\n x_out = torch.empty_like(x0_f32)\n \n # Launch fused kernel\n fused_ode_module.launch_fused_euler_ode(\n x0_f32, x_out,\n w1, b1, w2, b2, w3, b3,\n self.dim, self.hidden_dim, self.num_steps\n )\n \n return x_out.to(x0.dtype)"
}