call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.cpp_extension import load_inline\nimport math\n\ndef _linear_beta_schedule(num_timesteps: int, beta_start: float, beta_end: float) -> torch.Tensor:\n return torch.linspace(beta_start, beta_end, num_timesteps)\n\n# CUDA kernel code - optimized with multi-threading per batch\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cmath>\n\n// Fast SiLU using __expf for lower latency\n__device__ __forceinline__ float silu(float x) {\n return x / (1.0f + __expf(-x));\n}\n\n// Parallel matrix-vector multiply: each thread computes part of the output\n// W is (M, K) in row-major, x_in is (K,), out is (M,)\ntemplate <int M, int K>\n__device__ void matvec_mul(\n const float* __restrict__ W,\n const float* __restrict__ bias,\n const float* __restrict__ x_in,\n float* __restrict__ out,\n int tid, int block_size\n) {\n // Each thread handles a subset of output rows\n for (int i = tid; i < M; i += block_size) {\n float sum = bias[i];\n for (int j = 0; j < K; j++) {\n sum += W[i * K + j] * x_in[j];\n }\n out[i] = sum;\n }\n}\n\n__global__ void fused_diffusion_kernel(\n const float* __restrict__ x,\n const int64_t* __restrict__ t_start,\n const float* __restrict__ w1, // (dim*4, dim+1)\n const float* __restrict__ b1, // (dim*4,)\n const float* __restrict__ w2, // (dim*4, dim*4)\n const float* __restrict__ b2, // (dim*4,)\n const float* __restrict__ w3, // (dim, dim*4)\n const float* __restrict__ b3, // (dim,)\n const float* __restrict__ sqrt_recip_alphas,\n const float* __restrict__ coef_eps,\n float* __restrict__ out,\n int batch_size, int dim, int num_fused_steps, int total_timesteps\n) {\n const int dim4 = dim * 4;\n const int dim_plus1 = dim + 1;\n \n // Each thread block handles one batch element\n const int batch_idx = blockIdx.x;\n if (batch_idx >= batch_size) return;\n \n const int tid = threadIdx.x;\n const int block_size = blockDim.x;\n \n const int t_start_val = (int)t_start[batch_idx];\n \n // Use shared memory for intermediate activations\n __shared__ float x_cur[256]; // dim elements (max 256)\n __shared__ float hidden1[1024]; // dim*4 elements (max 1024)\n __shared__ float hidden2[1024]; // dim*4 elements\n __shared__ float eps[256]; // dim elements\n \n // Load initial x into shared memory\n for (int i = tid; i < dim; i += block_size) {\n x_cur[i] = x[batch_idx * dim + i];\n }\n __syncthreads();\n \n // Process each fused step\n for (int k = 0; k < num_fused_steps; k++) {\n int t_idx = t_start_val - k;\n \n // Compute t_norm = t_idx / total_timesteps\n float t_norm = (float)t_idx / (float)total_timesteps;\n \n // ===== Layer 1: Linear(dim+1, dim*4) =====\n // Input: [x_cur (dim), t_norm (1)]\n // Each thread computes part of hidden1\n \n for (int i = tid; i < dim4; i += block_size) {\n float sum = b1[i];\n for (int j = 0; j < dim; j++) {\n sum += w1[i * dim_plus1 + j] * x_cur[j];\n }\n // t_norm contribution\n sum += w1[i * dim_plus1 + dim] * t_norm;\n hidden1[i] = sum;\n }\n __syncthreads();\n \n // SiLU activation for hidden1\n for (int i = tid; i < dim4; i += block_size) {\n hidden1[i] = silu(hidden1[i]);\n }\n __syncthreads();\n \n // ===== Layer 2: Linear(dim*4, dim*4) =====\n for (int i = tid; i < dim4; i += block_size) {\n float sum = b2[i];\n for (int j = 0; j < dim4; j++) {\n sum += w2[i * dim4 + j] * hidden1[j];\n }\n hidden2[i] = sum;\n }\n __syncthreads();\n \n // SiLU activation for hidden2\n for (int i = tid; i < dim4; i += block_size) {\n hidden2[i] = silu(hidden2[i]);\n }\n __syncthreads();\n \n // ===== Layer 3: Linear(dim*4, dim) =====\n for (int i = tid; i < dim; i += block_size) {\n float sum = b3[i];\n for (int j = 0; j < dim4; j++) {\n sum += w3[i * dim4 + j] * hidden2[j];\n }\n eps[i] = sum;\n }\n __syncthreads();\n \n // ===== Apply denoising step =====\n float c1 = sqrt_recip_alphas[t_idx];\n float c2 = coef_eps[t_idx];\n \n for (int i = tid; i < dim; i += block_size) {\n x_cur[i] = c1 * (x_cur[i] - c2 * eps[i]);\n }\n __syncthreads();\n }\n \n // Write output\n for (int i = tid; i < dim; i += block_size) {\n out[batch_idx * dim + i] = x_cur[i];\n }\n}\n\ntorch::Tensor fused_diffusion_forward(\n torch::Tensor x,\n torch::Tensor t_start,\n torch::Tensor w1,\n torch::Tensor b1,\n torch::Tensor w2,\n torch::Tensor b2,\n torch::Tensor w3,\n torch::Tensor b3,\n torch::Tensor sqrt_recip_alphas,\n torch::Tensor coef_eps,\n int num_fused_steps,\n int total_timesteps\n) {\n const int batch_size = x.size(0);\n const int dim = x.size(1);\n \n auto out = torch::empty_like(x);\n \n const int blocks = batch_size;\n const int threads = 256; // More threads for better parallelism\n \n fused_diffusion_kernel<<<blocks, threads>>>(\n x.data_ptr<float>(),\n t_start.data_ptr<int64_t>(),\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 sqrt_recip_alphas.data_ptr<float>(),\n coef_eps.data_ptr<float>(),\n out.data_ptr<float>(),\n batch_size, dim, num_fused_steps, total_timesteps\n );\n \n return out;\n}\n\"\"\"\n\ncpp_source = r\"\"\"\ntorch::Tensor fused_diffusion_forward(\n torch::Tensor x,\n torch::Tensor t_start,\n torch::Tensor w1,\n torch::Tensor b1,\n torch::Tensor w2,\n torch::Tensor b2,\n torch::Tensor w3,\n torch::Tensor b3,\n torch::Tensor sqrt_recip_alphas,\n torch::Tensor coef_eps,\n int num_fused_steps,\n int total_timesteps\n);\n\"\"\"\n\n# Load the extension\nfused_extension = load_inline(\n name='fused_diffusion_ext',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['fused_diffusion_forward'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=False\n)\n\n\nclass Model(nn.Module):\n \"\"\"Reference implementation for weight initialization\"\"\"\n def __init__(self, dim: int, num_fused_steps: int, total_timesteps: int = 1000):\n super().__init__()\n assert num_fused_steps >= 1\n assert total_timesteps >= num_fused_steps + 1\n self.dim = dim\n self.num_fused_steps = num_fused_steps\n self.total_timesteps = total_timesteps\n\n self.eps_net = nn.Sequential(\n nn.Linear(dim + 1, dim * 4),\n nn.SiLU(),\n nn.Linear(dim * 4, dim * 4),\n nn.SiLU(),\n nn.Linear(dim * 4, dim),\n )\n\n betas = _linear_beta_schedule(total_timesteps, 1e-4, 0.02)\n alphas = 1.0 - betas\n alphas_cumprod = torch.cumprod(alphas, dim=0)\n self.register_buffer(\"betas\", betas)\n self.register_buffer(\"alphas\", alphas)\n self.register_buffer(\"alphas_cumprod\", alphas_cumprod)\n self.register_buffer(\"sqrt_recip_alphas\", torch.sqrt(1.0 / alphas))\n self.register_buffer(\n \"coef_eps\",\n betas / torch.sqrt(1.0 - alphas_cumprod),\n )\n\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int, num_fused_steps: int, total_timesteps: int = 1000):\n super().__init__()\n assert num_fused_steps >= 1\n assert total_timesteps >= num_fused_steps + 1\n self.dim = dim\n self.num_fused_steps = num_fused_steps\n self.total_timesteps = total_timesteps\n\n # Initialize the same weights as the reference\n self.eps_net = nn.Sequential(\n nn.Linear(dim + 1, dim * 4),\n nn.SiLU(),\n nn.Linear(dim * 4, dim * 4),\n nn.SiLU(),\n nn.Linear(dim * 4, dim),\n )\n\n betas = _linear_beta_schedule(total_timesteps, 1e-4, 0.02)\n alphas = 1.0 - betas\n alphas_cumprod = torch.cumprod(alphas, dim=0)\n self.register_buffer(\"betas\", betas)\n self.register_buffer(\"alphas\", alphas)\n self.register_buffer(\"alphas_cumprod\", alphas_cumprod)\n self.register_buffer(\"sqrt_recip_alphas\", torch.sqrt(1.0 / alphas))\n self.register_buffer(\n \"coef_eps\",\n betas / torch.sqrt(1.0 - alphas_cumprod),\n )\n\n def forward(self, x: torch.Tensor, t_start: torch.Tensor) -> torch.Tensor:\n B, d = x.shape\n assert d == self.dim\n assert t_start.shape == (B,)\n t_start = t_start.long()\n \n # Get weights from the MLP (correct indices!)\n # eps_net[0]: Linear(dim + 1, dim * 4)\n # eps_net[1]: SiLU()\n # eps_net[2]: Linear(dim * 4, dim * 4)\n # eps_net[3]: SiLU()\n # eps_net[4]: Linear(dim * 4, dim)\n w1 = self.eps_net[0].weight # (dim*4, dim+1)\n b1 = self.eps_net[0].bias # (dim*4,)\n w2 = self.eps_net[2].weight # (dim*4, dim*4)\n b2 = self.eps_net[2].bias # (dim*4,)\n w3 = self.eps_net[4].weight # (dim, dim*4)\n b3 = self.eps_net[4].bias # (dim,)\n \n # Ensure contiguous memory\n x = x.contiguous()\n t_start = t_start.contiguous()\n w1 = w1.contiguous()\n b1 = b1.contiguous()\n w2 = w2.contiguous()\n b2 = b2.contiguous()\n w3 = w3.contiguous()\n b3 = b3.contiguous()\n sqrt_recip_alphas = self.sqrt_recip_alphas.contiguous()\n coef_eps = self.coef_eps.contiguous()\n \n return fused_extension.fused_diffusion_forward(\n x, t_start, w1, b1, w2, b2, w3, b3,\n sqrt_recip_alphas, coef_eps,\n self.num_fused_steps, self.total_timesteps\n )\n\n\nbatch_size = 8\ndim = 64\nnum_fused_steps = 16\ntotal_timesteps = 1000\n\n\ndef get_inputs():\n x = torch.randn(batch_size, dim)\n low = num_fused_steps\n high = total_timesteps\n t_start = torch.randint(low, high, (batch_size,), dtype=torch.long)\n return [x, t_start]\n\n\ndef get_init_inputs():\n return [dim, num_fused_steps, total_timesteps]"
}