call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\ncuda_source = r'''\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cufft.h>\n#include <complex>\n#include <cuda_fp16.h>\n\n#define CUFFT_CHECK(call) \\\n do { \\\n cufftResult err = call; \\\n if (err != CUFFT_SUCCESS) { \\\n printf(\"CUFFT error %d at line %d\\n\", err, __LINE__); \\\n return; \\\n } \\\n } while(0)\n\n// Complex multiplication kernel\n__global__ void complex_multiply_kernel(const cufftComplex* x_f, const cufftComplex* k_f, \n cufftComplex* out_f, int B, int C, int fft_size) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * C * fft_size;\n \n if (idx < total) {\n int b = idx / (C * fft_size);\n int c = (idx / fft_size) % C;\n int f = idx % fft_size;\n \n int x_idx = b * C * fft_size + c * fft_size + f;\n int k_idx = c * fft_size + f;\n int out_idx = x_idx;\n \n cufftComplex x_val = x_f[x_idx];\n cufftComplex k_val = k_f[k_idx];\n \n // Complex multiplication: (a + bi)(c + di) = (ac - bd) + (ad + bc)i\n out_f[out_idx].x = x_val.x * k_val.x - x_val.y * k_val.y;\n out_f[out_idx].y = x_val.x * k_val.y + x_val.y * k_val.x;\n }\n}\n\n// Pad input to 2*L and compute RFFT\n__global__ void pad_and_prepare_kernel(const float* input, float* padded, int B, int C, int L) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * C * L;\n \n if (idx < total) {\n int b = idx / (C * L);\n int c = (idx / L) % C;\n int l = idx % L;\n \n int padded_idx = b * C * 2 * L + c * 2 * L + l;\n padded[padded_idx] = input[idx];\n padded[padded_idx + L] = 0.0f; // Zero pad\n }\n}\n\n// Extract result (first L elements from IRFFT output)\n__global__ void extract_result_kernel(const float* irfft_out, float* result, int B, int C, int L) {\n int idx = blockIdx.x * blockDim.x + threadIdx.x;\n int total = B * C * L;\n \n if (idx < total) {\n int b = idx / (C * L);\n int c = (idx / L) % C;\n int l = idx % L;\n \n int irfft_idx = b * C * 2 * L + c * 2 * L + l;\n result[idx] = irfft_out[irfft_idx];\n }\n}\n\n// Host function to run the FFT convolution\nvoid fft_conv_cuda(const float* input, const float* filter, float* output,\n int B, int C, int L, cudaStream_t stream) {\n int fft_size = 2 * L;\n int rfft_size = L + 1; // Output size of RFFT for real input of length 2L\n \n // Allocate memory\n float* d_x_padded;\n float* d_k_padded;\n cufftComplex* d_x_f;\n cufftComplex* d_k_f;\n cufftComplex* d_out_f;\n float* d_irfft_out;\n \n size_t padded_size = B * C * fft_size * sizeof(float);\n size_t filter_padded_size = C * fft_size * sizeof(float);\n size_t complex_size = B * C * rfft_size * sizeof(cufftComplex);\n size_t filter_complex_size = C * rfft_size * sizeof(cufftComplex);\n \n cudaMalloc(&d_x_padded, padded_size);\n cudaMalloc(&d_k_padded, filter_padded_size);\n cudaMalloc(&d_x_f, complex_size);\n cudaMalloc(&d_k_f, filter_complex_size);\n cudaMalloc(&d_out_f, complex_size);\n cudaMalloc(&d_irfft_out, padded_size);\n \n // Create cuFFT plans\n cufftHandle plan_rfft_x, plan_rfft_k, plan_irfft;\n \n // Plan for input RFFT (batched: B*C transforms of length fft_size)\n int n_x[1] = {fft_size};\n int istride_x = 1, ostride_x = 1;\n int idist_x = fft_size, odist_x = rfft_size;\n CUFFT_CHECK(cufftPlanMany(&plan_rfft_x, 1, n_x, \n NULL, 1, istride_x, idist_x,\n NULL, 1, ostride_x, odist_x,\n CUFFT_R2C, B * C));\n \n // Plan for filter RFFT (batched: C transforms of length fft_size)\n int idist_k = fft_size, odist_k = rfft_size;\n CUFFT_CHECK(cufftPlanMany(&plan_rfft_k, 1, n_x,\n NULL, 1, istride_x, idist_k,\n NULL, 1, ostride_x, odist_k,\n CUFFT_R2C, C));\n \n // Plan for IRFFT (batched: B*C transforms of length fft_size)\n CUFFT_CHECK(cufftPlanMany(&plan_irfft, 1, n_x,\n NULL, 1, ostride_x, odist_x,\n NULL, 1, istride_x, idist_x,\n CUFFT_C2R, B * C));\n \n // Set stream for all plans\n cufftSetStream(plan_rfft_x, stream);\n cufftSetStream(plan_rfft_k, stream);\n cufftSetStream(plan_irfft, stream);\n \n // Pad input to 2*L\n int total_input = B * C * L;\n int threads = 256;\n int blocks = (total_input + threads - 1) / threads;\n pad_and_prepare_kernel<<<blocks, threads, 0, stream>>>(input, d_x_padded, B, C, L);\n \n // Pad filter to 2*L\n int total_filter = C * L;\n blocks = (total_filter + threads - 1) / threads;\n pad_and_prepare_kernel<<<blocks, threads, 0, stream>>>(filter, d_k_padded, 1, C, L);\n \n // RFFT of input\n CUFFT_CHECK(cufftExecR2C(plan_rfft_x, (cufftReal*)d_x_padded, d_x_f));\n \n // RFFT of filter\n CUFFT_CHECK(cufftExecR2C(plan_rfft_k, (cufftReal*)d_k_padded, d_k_f));\n \n // Complex multiplication\n int total_complex = B * C * rfft_size;\n blocks = (total_complex + threads - 1) / threads;\n complex_multiply_kernel<<<blocks, threads, 0, stream>>>(d_x_f, d_k_f, d_out_f, B, C, rfft_size);\n \n // IRFFT\n CUFFT_CHECK(cufftExecC2R(plan_irfft, d_out_f, (cufftReal*)d_irfft_out));\n \n // Extract first L elements\n total_input = B * C * L;\n blocks = (total_input + threads - 1) / threads;\n extract_result_kernel<<<blocks, threads, 0, stream>>>(d_irfft_out, output, B, C, L);\n \n // Cleanup\n cufftDestroy(plan_rfft_x);\n cufftDestroy(plan_rfft_k);\n cufftDestroy(plan_irfft);\n \n cudaFree(d_x_padded);\n cudaFree(d_k_padded);\n cudaFree(d_x_f);\n cudaFree(d_k_f);\n cudaFree(d_out_f);\n cudaFree(d_irfft_out);\n}\n\ntorch::Tensor fft_conv_forward(torch::Tensor input, torch::Tensor filter) {\n int B = input.size(0);\n int C = input.size(1);\n int L = input.size(2);\n \n auto output = torch::empty({B, C, L}, input.options());\n \n cudaStream_t stream = c10::cuda::getCurrentCUDAStream();\n \n fft_conv_cuda(input.data_ptr<float>(), filter.data_ptr<float>(), \n output.data_ptr<float>(), B, C, L, stream);\n \n return output;\n}\n'''\n\ncpp_source = \"torch::Tensor fft_conv_forward(torch::Tensor input, torch::Tensor filter);\"\n\nfft_module = load_inline(\n name='fft_conv',\n cpp_sources=cpp_source,\n cuda_sources=cuda_source,\n functions=['fft_conv_forward'],\n extra_cuda_cflags=['-O3', '-use_fast_math'],\n verbose=True\n)\n\nclass ModelNew(nn.Module):\n def __init__(self, channels: int, seq_len: int):\n super(ModelNew, self).__init__()\n self.channels = channels\n self.seq_len = seq_len\n self.fft_size = 2 * seq_len\n self.filter = nn.Parameter(torch.randn(channels, seq_len))\n\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return fft_module.fft_conv_forward(x, self.filter)"
}