call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncpp_source = r\"\"\"\n#include <torch/extension.h>\n\n// Declaration of the function defined in CUDA source\ntorch::Tensor vae_elbo_forward(\n torch::Tensor x,\n torch::Tensor encoder_weight, torch::Tensor encoder_bias,\n torch::Tensor fc_mu_weight, torch::Tensor fc_mu_bias,\n torch::Tensor fc_logvar_weight, torch::Tensor fc_logvar_bias,\n torch::Tensor decoder1_weight, torch::Tensor decoder1_bias,\n torch::Tensor decoder2_weight, torch::Tensor decoder2_bias,\n torch::Tensor eps,\n torch::Tensor elbo_out,\n torch::Tensor recon_out,\n torch::Tensor kl_out,\n torch::Tensor h_out,\n torch::Tensor mu_out,\n torch::Tensor logvar_out,\n torch::Tensor z_out,\n torch::Tensor h_dec_out,\n torch::Tensor x_recon_out\n);\n\"\"\"\n\ncuda_source = r\"\"\"\n#include <torch/extension.h>\n#include <cuda_runtime.h>\n#include <cmath>\n\n// Device functions for activations\n__device__ __forceinline__ float relu(float x) {\n return x > 0.0f ? x : 0.0f;\n}\n\n__device__ __forceinline__ float sigmoid(float x) {\n return 1.0f / (1.0f + expf(-x));\n}\n\n// Fused encoder kernel: Linear + ReLU\n__global__ void encoder_kernel(\n const float* __restrict__ input,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ output,\n int batch_size, int in_features, int out_features\n) {\n int b = blockIdx.x;\n int o = threadIdx.x;\n \n if (b >= batch_size || o >= out_features) return;\n \n float sum = bias[o];\n for (int i = 0; i < in_features; i++) {\n sum += input[b * in_features + i] * weight[o * in_features + i];\n }\n output[b * out_features + o] = relu(sum);\n}\n\n// Linear kernel (no activation)\n__global__ void linear_kernel(\n const float* __restrict__ input,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ output,\n int batch_size, int in_features, int out_features\n) {\n int b = blockIdx.x;\n int o = threadIdx.x;\n \n if (b >= batch_size || o >= out_features) return;\n \n float sum = bias[o];\n for (int i = 0; i < in_features; i++) {\n sum += input[b * in_features + i] * weight[o * in_features + i];\n }\n output[b * out_features + o] = sum;\n}\n\n// Decoder intermediate: Linear + ReLU\n__global__ void decoder_intermediate_kernel(\n const float* __restrict__ input,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ output,\n int batch_size, int in_features, int out_features\n) {\n int b = blockIdx.x;\n int o = threadIdx.x;\n \n if (b >= batch_size || o >= out_features) return;\n \n float sum = bias[o];\n for (int i = 0; i < in_features; i++) {\n sum += input[b * in_features + i] * weight[o * in_features + i];\n }\n output[b * out_features + o] = relu(sum);\n}\n\n// Decoder output: Linear + Sigmoid\n__global__ void decoder_output_kernel(\n const float* __restrict__ input,\n const float* __restrict__ weight,\n const float* __restrict__ bias,\n float* __restrict__ output,\n int batch_size, int in_features, int out_features\n) {\n int b = blockIdx.x;\n int o = threadIdx.x;\n \n if (b >= batch_size || o >= out_features) return;\n \n float sum = bias[o];\n for (int i = 0; i < in_features; i++) {\n sum += input[b * in_features + i] * weight[o * in_features + i];\n }\n output[b * out_features + o] = sigmoid(sum);\n}\n\n// Reparameterization: z = mu + std * eps\n__global__ void reparameterize_kernel(\n const float* __restrict__ mu,\n const float* __restrict__ logvar,\n const float* __restrict__ eps,\n float* __restrict__ z,\n int batch_size, int latent_dim\n) {\n int b = blockIdx.x;\n int d = threadIdx.x;\n \n if (b >= batch_size || d >= latent_dim) return;\n \n float std_val = expf(0.5f * logvar[b * latent_dim + d]);\n z[b * latent_dim + d] = mu[b * latent_dim + d] + std_val * eps[b * latent_dim + d];\n}\n\n// Compute losses: BCE and KL divergence\n__global__ void compute_losses_kernel(\n const float* __restrict__ x_recon,\n const float* __restrict__ x,\n const float* __restrict__ mu,\n const float* __restrict__ logvar,\n float* __restrict__ elbo,\n float* __restrict__ recon_loss,\n float* __restrict__ kl_div,\n int batch_size, int input_dim, int latent_dim\n) {\n int b = blockIdx.x;\n \n if (b >= batch_size) return;\n \n // Compute reconstruction loss (BCE sum)\n float recon = 0.0f;\n for (int i = 0; i < input_dim; i++) {\n int idx = b * input_dim + i;\n float x_r = x_recon[idx];\n float x_i = x[idx];\n // BCE: -[x*log(x_r) + (1-x)*log(1-x_r)]\n // Clamp for numerical stability\n float x_r_clamped = fmaxf(fminf(x_r, 1.0f - 1e-7f), 1e-7f);\n recon -= x_i * logf(x_r_clamped) + (1.0f - x_i) * logf(1.0f - x_r_clamped);\n }\n \n // Compute KL divergence\n float kl = 0.0f;\n for (int d = 0; d < latent_dim; d++) {\n int idx = b * latent_dim + d;\n float mu_val = mu[idx];\n float logvar_val = logvar[idx];\n // kl = -0.5 * (1 + logvar - mu^2 - exp(logvar))\n kl += -0.5f * (1.0f + logvar_val - mu_val * mu_val - expf(logvar_val));\n }\n \n recon_loss[b] = recon;\n kl_div[b] = kl;\n elbo[b] = -(recon + kl);\n}\n\n// Host function\ntorch::Tensor vae_elbo_forward(\n torch::Tensor x,\n torch::Tensor encoder_weight, torch::Tensor encoder_bias,\n torch::Tensor fc_mu_weight, torch::Tensor fc_mu_bias,\n torch::Tensor fc_logvar_weight, torch::Tensor fc_logvar_bias,\n torch::Tensor decoder1_weight, torch::Tensor decoder1_bias,\n torch::Tensor decoder2_weight, torch::Tensor decoder2_bias,\n torch::Tensor eps,\n torch::Tensor elbo_out,\n torch::Tensor recon_out,\n torch::Tensor kl_out,\n torch::Tensor h_out,\n torch::Tensor mu_out,\n torch::Tensor logvar_out,\n torch::Tensor z_out,\n torch::Tensor h_dec_out,\n torch::Tensor x_recon_out\n) {\n int batch_size = x.size(0);\n int input_dim = x.size(1);\n int hidden_dim = encoder_weight.size(0);\n int latent_dim = fc_mu_weight.size(0);\n \n // Encoder: Linear + ReLU\n encoder_kernel<<<batch_size, hidden_dim>>>(\n x.data_ptr<float>(),\n encoder_weight.data_ptr<float>(),\n encoder_bias.data_ptr<float>(),\n h_out.data_ptr<float>(),\n batch_size, input_dim, hidden_dim\n );\n \n // fc_mu: Linear (no activation)\n linear_kernel<<<batch_size, latent_dim>>>(\n h_out.data_ptr<float>(),\n fc_mu_weight.data_ptr<float>(),\n fc_mu_bias.data_ptr<float>(),\n mu_out.data_ptr<float>(),\n batch_size, hidden_dim, latent_dim\n );\n \n // fc_logvar: Linear (no activation)\n linear_kernel<<<batch_size, latent_dim>>>(\n h_out.data_ptr<float>(),\n fc_logvar_weight.data_ptr<float>(),\n fc_logvar_bias.data_ptr<float>(),\n logvar_out.data_ptr<float>(),\n batch_size, hidden_dim, latent_dim\n );\n \n // Reparameterization\n reparameterize_kernel<<<batch_size, latent_dim>>>(\n mu_out.data_ptr<float>(),\n logvar_out.data_ptr<float>(),\n eps.data_ptr<float>(),\n z_out.data_ptr<float>(),\n batch_size, latent_dim\n );\n \n // Decoder: Linear + ReLU\n decoder_intermediate_kernel<<<batch_size, hidden_dim>>>(\n z_out.data_ptr<float>(),\n decoder1_weight.data_ptr<float>(),\n decoder1_bias.data_ptr<float>(),\n h_dec_out.data_ptr<float>(),\n batch_size, latent_dim, hidden_dim\n );\n \n // Decoder output: Linear + Sigmoid\n decoder_output_kernel<<<batch_size, input_dim>>>(\n h_dec_out.data_ptr<float>(),\n decoder2_weight.data_ptr<float>(),\n decoder2_bias.data_ptr<float>(),\n x_recon_out.data_ptr<float>(),\n batch_size, hidden_dim, input_dim\n );\n \n // Compute losses\n compute_losses_kernel<<<batch_size, 1>>>(\n x_recon_out.data_ptr<float>(),\n x.data_ptr<float>(),\n mu_out.data_ptr<float>(),\n logvar_out.data_ptr<float>(),\n elbo_out.data_ptr<float>(),\n recon_out.data_ptr<float>(),\n kl_out.data_ptr<float>(),\n batch_size, input_dim, latent_dim\n );\n \n return elbo_out;\n}\n\"\"\"\n\n# Compile the CUDA extension\nvae_module = load_inline(\n name='vae_elbo_cuda_v4',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['vae_elbo_forward'],\n with_cuda=True,\n extra_cuda_cflags=['-O3']\n)\n\n\nclass ModelNew(nn.Module):\n def __init__(self, input_dim, hidden_dim, latent_dim):\n super().__init__()\n self.input_dim = input_dim\n self.hidden_dim = hidden_dim\n self.latent_dim = latent_dim\n \n # Initialize weights matching the original model structure\n self.encoder_weight = nn.Parameter(torch.empty(hidden_dim, input_dim))\n self.encoder_bias = nn.Parameter(torch.empty(hidden_dim))\n \n self.fc_mu_weight = nn.Parameter(torch.empty(latent_dim, hidden_dim))\n self.fc_mu_bias = nn.Parameter(torch.empty(latent_dim))\n \n self.fc_logvar_weight = nn.Parameter(torch.empty(latent_dim, hidden_dim))\n self.fc_logvar_bias = nn.Parameter(torch.empty(latent_dim))\n \n self.decoder1_weight = nn.Parameter(torch.empty(hidden_dim, latent_dim))\n self.decoder1_bias = nn.Parameter(torch.empty(hidden_dim))\n \n self.decoder2_weight = nn.Parameter(torch.empty(input_dim, hidden_dim))\n self.decoder2_bias = nn.Parameter(torch.empty(input_dim))\n \n # Initialize weights same as original model\n self._init_weights()\n \n def _init_weights(self):\n # Match PyTorch default Linear initialization\n for w in [self.encoder_weight, self.fc_mu_weight, self.fc_logvar_weight,\n self.decoder1_weight, self.decoder2_weight]:\n nn.init.kaiming_uniform_(w, a=0.0, mode='fan_in', nonlinearity='linear')\n for b in [self.encoder_bias, self.fc_mu_bias, self.fc_logvar_bias,\n self.decoder1_bias, self.decoder2_bias]:\n nn.init.zeros_(b)\n \n def forward(self, x: torch.Tensor) -> tuple:\n batch_size = x.size(0)\n \n # Generate random noise for reparameterization\n eps = torch.randn(batch_size, self.latent_dim, device=x.device, dtype=x.dtype)\n \n # Allocate output tensors\n elbo = torch.empty(batch_size, device=x.device, dtype=x.dtype)\n recon = torch.empty(batch_size, device=x.device, dtype=x.dtype)\n kl = torch.empty(batch_size, device=x.device, dtype=x.dtype)\n h = torch.empty(batch_size, self.hidden_dim, device=x.device, dtype=x.dtype)\n mu = torch.empty(batch_size, self.latent_dim, device=x.device, dtype=x.dtype)\n logvar = torch.empty(batch_size, self.latent_dim, device=x.device, dtype=x.dtype)\n z = torch.empty(batch_size, self.latent_dim, device=x.device, dtype=x.dtype)\n h_dec = torch.empty(batch_size, self.hidden_dim, device=x.device, dtype=x.dtype)\n x_recon = torch.empty(batch_size, self.input_dim, device=x.device, dtype=x.dtype)\n \n # Call CUDA kernel\n vae_module.vae_elbo_forward(\n x,\n self.encoder_weight, self.encoder_bias,\n self.fc_mu_weight, self.fc_mu_bias,\n self.fc_logvar_weight, self.fc_logvar_bias,\n self.decoder1_weight, self.decoder1_bias,\n self.decoder2_weight, self.decoder2_bias,\n eps,\n elbo, recon, kl,\n h, mu, logvar, z, h_dec, x_recon\n )\n \n return elbo, recon, kl"
}