correct
17_Conv2d_InstanceNorm_Divide.py
started
2026-05-02T21:14:54Z
timingkernelbench.timing
kernel mean / median / std
4.05 / — / 0.11 μs
ref mean / median / std
4.95 / — / 0.02 μs
numerical precisioneval_kernel_against_ref
gpu memoryextended_metrics.measure_memory
kernel launches / fusiontorch.profiler
fusion ratio (ref / kernel)
3.43x
energyNVML (pynvml)
ratio (ref / kernel)
1.50x
SOL (speed-of-light)nsight_hardware_counters
roofline / occupancynsight_hardware_counters
dram bandwidth
8671.84 GB/s
warp stalls (top 5)nsight
reference PyTorch source (the prompt the agent sees)
import torch
import torch.nn as nn
class Model(nn.Module):
"""
Simple model that performs a convolution, applies Instance Normalization, and divides by a constant.
"""
def __init__(self, in_channels, out_channels, kernel_size, divide_by):
super(Model, self).__init__()
self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)
self.instance_norm = nn.InstanceNorm2d(out_channels)
self.divide_by = divide_by
def forward(self, x):
x = self.conv(x)
x = self.instance_norm(x)
x = x / self.divide_by
return x
batch_size = 128
in_channels = 64
out_channels = 128
height = width = 128
kernel_size = 3
divide_by = 2.0
def get_inputs():
return [torch.rand(batch_size, in_channels, height, width)]
def get_init_inputs():
return [in_channels, out_channels, kernel_size, divide_by]turn 010.8s turn · 10.8s LLM · 0.0s tools
reasoning
**Evaluating model creation**
I need to create ModelNew with the same arguments and ensure the convolution weights are properly initialized. It’s likely that I need to instantiate both Model and ModelNew with the same seed to match reference weights, which means the convolution module parameters should also be the same. I’ll define the convolution layer in ModelNew so I can load the weights. The input shape will be 128x64x128x128, and I need to compute the operations efficiently. I should think about using a custom CUDA kernel for optimization while ensuring to fuse instance normalization and division effectively.
**Considering optimization techniques**
I need to achieve faster performance by replacing instance normalization and division with a fused kernel while keeping the convolution operation in cuDNN. The reference model combines convolution, instance normalization, and division separately. By using torch.conv2d and implementing a custom fused instance norm/div in an extension, I might gain speed. I must also ensure the extension can effectively call at::conv2d or use F.conv2d. Additionally, I’ll try to measure correctness without revealing reference parameters, but I may need to consider fixed shapes and efficiently store convolution outputs to normalize properly.
**Planning computational strategy**
I need to perform a two-pass approach: first, I'll compute the convolution and store the output y, then accumulate the sum and sum of squares per N and C before normalizing. I realize that a custom convolution might be slower than cuDNN unless I can optimize it effectively, perhaps by using implicit GEMM with tiling. Alternatively, I could opt for cuDNN convolution through torch, while implementing a custom normalization step afterward.
call → get_gpu_specs
callget_gpu_specs
{}
result ← get_gpu_specs (ok)
okget_gpu_specs
GPU specs for NVIDIA H100 80GB HBM3:
total memory (runtime): 79.1 GB
spec entry: H100
GPU Architecture: Hopper
GPU Memory: 80GB
Memory Bandwidth: 3.35 TB/s
FP64 TFLOPS: 34
FP64 Tensor Core TFLOPS: 67
FP32 TFLOPS: 67
TF32 Tensor Core TFLOPS: 989 with sparsity
BFLOAT16 Tensore Core TFLOPS: 1979 with sparsity
FP16 Tensor Core TFLOPS: 1979 with sparsity
FP8 Tensor Core TFLOPS: 3958 with sparsity
INT8 Tensor Core TOPS: 3958 with sparsity
Register File Size: 64K 32-bit registers per SM
Maximum number of registers per thread: 255
Maximum number of thread blocks per SM: 32
Shared memory capacity per SM: 228 KB
Maximum shared memory per thread block: 227 KB
turn 114.9s turn · 14.9s LLM · 0.0s tools
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\n\ncpp_source = r'''\n#include <torch/extension.h>\n\ntorch::Tensor inst_norm_div(torch::Tensor x, double divide_by);\n'''\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = 16; offset > 0; offset >>= 1)\n val += __shfl_down_sync(0xffffffff, val, offset);\n return val;\n}\n\n__inline__ __device__ float block_reduce_sum(float val) {\n static __shared__ float shared[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n val = warp_reduce_sum(val);\n if (lane == 0) shared[wid] = val;\n __syncthreads();\n val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warp_reduce_sum(val);\n return val;\n}\n\n__global__ __launch_bounds__(256, 2)\nvoid inst_norm_div_kernel(const float* __restrict__ x, float* __restrict__ y,\n int rows, int S, float inv_div) {\n int row = blockIdx.x;\n if (row >= rows) return;\n const float* base = x + (long long)row * S;\n float* out = y + (long long)row * S;\n float sum = 0.0f;\n float sumsq = 0.0f;\n int S4 = S >> 2;\n const float4* base4 = reinterpret_cast<const float4*>(base);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n sum += v.x + v.y + v.z + v.w;\n sumsq += v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w;\n }\n sum = block_reduce_sum(sum);\n sumsq = block_reduce_sum(sumsq);\n __shared__ float sh_mean, sh_scale;\n if (threadIdx.x == 0) {\n float mean = sum / (float)S;\n float var = sumsq / (float)S - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_scale = rsqrtf(var + 1.0e-5f) * inv_div;\n }\n __syncthreads();\n float mean = sh_mean;\n float scale = sh_scale;\n float4* out4 = reinterpret_cast<float4*>(out);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n v.x = (v.x - mean) * scale;\n v.y = (v.y - mean) * scale;\n v.z = (v.z - mean) * scale;\n v.w = (v.w - mean) * scale;\n out4[i] = v;\n }\n}\n\ntorch::Tensor inst_norm_div(torch::Tensor x, double divide_by) {\n const c10::cuda::CUDAGuard device_guard(x.device());\n auto y = torch::empty_like(x);\n int64_t N = x.size(0), C = x.size(1), H = x.size(2), W = x.size(3);\n int rows = (int)(N * C);\n int S = (int)(H * W);\n float inv_div = 1.0f / (float)divide_by;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n inst_norm_div_kernel<<<rows, 256, 0, stream>>>(x.data_ptr<float>(), y.data_ptr<float>(), rows, S, inv_div);\n return y;\n}\n'''\n\n_ext = load_inline(name='inst_norm_div_ext_v1', cpp_sources=cpp_source, cuda_sources=cuda_source,\n functions=['inst_norm_div'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divide_by):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.instance_norm = nn.InstanceNorm2d(out_channels)\n self.divide_by = float(divide_by)\n def forward(self, x):\n y = self.conv(x)\n return _ext.inst_norm_div(y, self.divide_by)\n"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 27.2s turn · 7.2s LLM · 0.0s tools
call → run_correctness
callrun_correctness
{
"kernel_code": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.cpp_extension import load_inline\n\ncpp_source = r'''\n#include <torch/extension.h>\n\ntorch::Tensor inst_norm_div(torch::Tensor x, double divide_by);\n'''\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = 16; offset > 0; offset >>= 1)\n val += __shfl_down_sync(0xffffffff, val, offset);\n return val;\n}\n\n__inline__ __device__ float block_reduce_sum(float val) {\n static __shared__ float shared[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n val = warp_reduce_sum(val);\n if (lane == 0) shared[wid] = val;\n __syncthreads();\n val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warp_reduce_sum(val);\n return val;\n}\n\n__global__ __launch_bounds__(256, 2)\nvoid inst_norm_div_kernel(const float* __restrict__ x, float* __restrict__ y,\n int rows, int S, float inv_div) {\n int row = blockIdx.x;\n if (row >= rows) return;\n const float* base = x + (long long)row * S;\n float* out = y + (long long)row * S;\n float sum = 0.0f;\n float sumsq = 0.0f;\n int S4 = S >> 2;\n const float4* base4 = reinterpret_cast<const float4*>(base);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n sum += v.x + v.y + v.z + v.w;\n sumsq += v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w;\n }\n sum = block_reduce_sum(sum);\n sumsq = block_reduce_sum(sumsq);\n __shared__ float sh_mean, sh_scale;\n if (threadIdx.x == 0) {\n float mean = sum / (float)S;\n float var = sumsq / (float)S - mean * mean;\n if (var < 0.0f) var = 0.0f;\n sh_mean = mean;\n sh_scale = rsqrtf(var + 1.0e-5f) * inv_div;\n }\n __syncthreads();\n float mean = sh_mean;\n float scale = sh_scale;\n float4* out4 = reinterpret_cast<float4*>(out);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n v.x = (v.x - mean) * scale;\n v.y = (v.y - mean) * scale;\n v.z = (v.z - mean) * scale;\n v.w = (v.w - mean) * scale;\n out4[i] = v;\n }\n}\n\ntorch::Tensor inst_norm_div(torch::Tensor x, double divide_by) {\n const c10::cuda::CUDAGuard device_guard(x.device());\n auto y = torch::empty_like(x);\n int64_t N = x.size(0), C = x.size(1), H = x.size(2), W = x.size(3);\n int rows = (int)(N * C);\n int S = (int)(H * W);\n float inv_div = 1.0f / (float)divide_by;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n inst_norm_div_kernel<<<rows, 256, 0, stream>>>(x.data_ptr<float>(), y.data_ptr<float>(), rows, S, inv_div);\n return y;\n}\n'''\n\n_ext = load_inline(name='inst_norm_div_ext_v1', cpp_sources=cpp_source, cuda_sources=cuda_source,\n functions=['inst_norm_div'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divide_by):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.instance_norm = nn.InstanceNorm2d(out_channels)\n self.divide_by = float(divide_by)\n def forward(self, x):\n y = self.conv(x)\n return _ext.inst_norm_div(y, self.divide_by)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=7.15e-06 mean_abs_err=1.13e-07 max_rel_err=7.01e+05
turn 3 · 1 tool call(s) · 12.2s turn · 12.2s LLM · 9,417 chars (click to expand)
turn 312.2s turn · 12.2s LLM · 0.0s tools
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\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by);\n'''\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <ATen/ATen.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = 16; offset > 0; offset >>= 1)\n val += __shfl_down_sync(0xffffffff, val, offset);\n return val;\n}\n\n__inline__ __device__ float block_reduce_sum(float val) {\n static __shared__ float shared[32];\n int lane = threadIdx.x & 31;\n int wid = threadIdx.x >> 5;\n val = warp_reduce_sum(val);\n if (lane == 0) shared[wid] = val;\n __syncthreads();\n val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warp_reduce_sum(val);\n return val;\n}\n\n__global__ __launch_bounds__(256, 2)\nvoid inst_norm_div_kernel(const float* __restrict__ x, float* __restrict__ y,\n int rows, int S, float inv_div) {\n int row = blockIdx.x;\n const float* base = x + (long long)row * S;\n float* out = y + (long long)row * S;\n float sum = 0.0f, sumsq = 0.0f;\n int S4 = S >> 2;\n const float4* base4 = reinterpret_cast<const float4*>(base);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n sum += v.x + v.y + v.z + v.w;\n sumsq += v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w;\n }\n sum = block_reduce_sum(sum);\n sumsq = block_reduce_sum(sumsq);\n __shared__ float sh_mean, sh_scale;\n if (threadIdx.x == 0) {\n float mean = sum / (float)S;\n float var = sumsq / (float)S - mean * mean;\n var = fmaxf(var, 0.0f);\n sh_mean = mean;\n sh_scale = rsqrtf(var + 1.0e-5f) * inv_div;\n }\n __syncthreads();\n float mean = sh_mean, scale = sh_scale;\n float4* out4 = reinterpret_cast<float4*>(out);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n v.x = (v.x - mean) * scale;\n v.y = (v.y - mean) * scale;\n v.z = (v.z - mean) * scale;\n v.w = (v.w - mean) * scale;\n out4[i] = v;\n }\n}\n\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by) {\n const c10::cuda::CUDAGuard device_guard(x.device());\n auto yconv = at::conv2d(x, weight, bias, {1,1}, {0,0}, {1,1}, 1);\n auto y = torch::empty_like(yconv);\n int rows = (int)(yconv.size(0) * yconv.size(1));\n int S = (int)(yconv.size(2) * yconv.size(3));\n float inv_div = 1.0f / (float)divide_by;\n inst_norm_div_kernel<<<rows, 256, 0, at::cuda::getCurrentCUDAStream()>>>(yconv.data_ptr<float>(), y.data_ptr<float>(), rows, S, inv_div);\n return y;\n}\n'''\n\n_ext = load_inline(name='conv_inst_norm_div_ext_v2', cpp_sources=cpp_source, cuda_sources=cuda_source,\n functions=['conv_inst_norm_div'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divide_by):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.instance_norm = nn.InstanceNorm2d(out_channels)\n self.divide_by = float(divide_by)\n def forward(self, x):\n return _ext.conv_inst_norm_div(x, self.conv.weight, self.conv.bias, self.divide_by)\n"
}
result ← compile_kernel (fail)
failcompile_kernel
compile_kernel FAILED: RuntimeError.
RuntimeError: Error building extension 'conv_inst_norm_div_ext_v2': [1/3] /opt/conda/bin/x86_64-conda-linux-gnu-c++ -MMD -MF main.o.d -DTORCH_EXTENSION_NAME=conv_inst_norm_div_ext_v2 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/include/python3.10 -fPIC -std=c++17 -O3 -c /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_17_cache/k_182bed06effb/conv_inst_norm_div_ext_v2/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=conv_inst_norm_div_ext_v2 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/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' -O3 -std=c++17 -c /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_17_cache/k_182bed06effb/conv_inst_norm_div_ext_v2/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=conv_inst_norm_div_ext_v2 -DTORCH_API_INCLUDE_EXTENSION_H -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include -isystem /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/torch/csrc/api/include -isystem /usr/local/cuda/include -isystem /home/prabhune/.local/share/uv/python/cpython-3.10-linux-x86_64-gnu/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' -O3 -std=c++17 -c /scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_17_cache/k_182bed06effb/conv_inst_norm_div_ext_v2/cuda.cu -o cuda.cuda.o
nvcc warning : incompatible redefinition for option 'compiler-bindir', the last value of this option was used
/scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_17_cache/k_182bed06effb/conv_inst_norm_div_ext_v2/cuda.cu(69): error: more than one instance of overloaded function "at::conv2d" matches the argument list:
function "at::conv2d(const at::Tensor &, const at::Tensor &, const std::optional<at::Tensor> &, at::IntArrayRef, at::IntArrayRef, at::IntArrayRef, int64_t)" (declared at line 28 of /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/ATen/ops/conv2d.h)
function "at::conv2d(const at::Tensor &, const at::Tensor &, const std::optional<at::Tensor> &, at::IntArrayRef, c10::string_view, at::IntArrayRef, int64_t)" (declared at line 50 of /scratch/tejas/PopcornBench/.venv/lib/python3.10/site-packages/torch/include/ATen/ops/conv2d.h)
argument types are: (at::Tensor, at::Tensor, at::Tensor, {...}, {...}, {...}, int)
auto yconv = at::conv2d(x, weight, bias, {1,1}, {0,0}, {1,1}, 1);
^
/scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_17_cache/k_182bed06effb/conv_inst_norm_div_ext_v2/cuda.cu(74): error: type name is not allowed
inst_norm_div_kernel<<<rows, 256, 0, at::cuda::getCurrentCUDAStream()>>>(yconv.data_ptr<float>(), y.data_ptr<float>(), rows, S, inv_div);
^
/scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_17_cache/k_182bed06effb/conv_inst_norm_div_ext_v2/cuda.cu(74): error: expected an expression
inst_norm_div_kernel<<<rows, 256, 0, at::cuda::getCurrentCUDAStream()>>>(yconv.data_ptr<float>(), y.data_ptr<float>(), rows, S, inv_div);
^
3 errors detected in the compilation of "/scratch/tejas/PopcornBench/runs/l12_default/original/gpt-5.5-priority/level_2_problem_17_cache/k_182bed06effb/conv_inst_norm_div_ext_v2/cuda.cu".
ninja: build stopped: subcommand failed.
turn 413.3s turn · 13.3s LLM · 0.0s tools
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\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by);\n'''\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <ATen/ATen.h>\n#include <ATen/ops/conv2d.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <optional>\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = 16; offset > 0; offset >>= 1) val += __shfl_down_sync(0xffffffff, val, offset);\n return val;\n}\n__inline__ __device__ float block_reduce_sum(float val) {\n static __shared__ float shared[32];\n int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;\n val = warp_reduce_sum(val);\n if (lane == 0) shared[wid] = val;\n __syncthreads();\n val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warp_reduce_sum(val);\n return val;\n}\n__global__ __launch_bounds__(256, 2)\nvoid inst_norm_div_kernel(const float* __restrict__ x, float* __restrict__ y, int rows, int S, float inv_div) {\n int row = blockIdx.x;\n const float* base = x + (long long)row * S;\n float* out = y + (long long)row * S;\n float sum = 0.0f, sumsq = 0.0f;\n int S4 = S >> 2;\n const float4* base4 = reinterpret_cast<const float4*>(base);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n sum += v.x + v.y + v.z + v.w;\n sumsq += v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w;\n }\n sum = block_reduce_sum(sum);\n sumsq = block_reduce_sum(sumsq);\n __shared__ float sh_mean, sh_scale;\n if (threadIdx.x == 0) {\n float mean = sum / (float)S;\n float var = fmaxf(sumsq / (float)S - mean * mean, 0.0f);\n sh_mean = mean;\n sh_scale = rsqrtf(var + 1.0e-5f) * inv_div;\n }\n __syncthreads();\n float mean = sh_mean, scale = sh_scale;\n float4* out4 = reinterpret_cast<float4*>(out);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n v.x = (v.x - mean) * scale; v.y = (v.y - mean) * scale;\n v.z = (v.z - mean) * scale; v.w = (v.w - mean) * scale;\n out4[i] = v;\n }\n}\n\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by) {\n const c10::cuda::CUDAGuard device_guard(x.device());\n std::optional<at::Tensor> b = bias;\n std::vector<int64_t> stride = {1,1}, padding = {0,0}, dilation = {1,1};\n auto yconv = at::conv2d(x, weight, b, stride, padding, dilation, 1);\n auto y = torch::empty_like(yconv);\n int rows = (int)(yconv.size(0) * yconv.size(1));\n int S = (int)(yconv.size(2) * yconv.size(3));\n float inv_div = 1.0f / (float)divide_by;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const float* xp = yconv.data_ptr<float>();\n float* yp = y.data_ptr<float>();\n inst_norm_div_kernel<<<rows, 256, 0, stream>>>(xp, yp, rows, S, inv_div);\n return y;\n}\n'''\n\n_ext = load_inline(name='conv_inst_norm_div_ext_v3', cpp_sources=cpp_source, cuda_sources=cuda_source,\n functions=['conv_inst_norm_div'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divide_by):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.instance_norm = nn.InstanceNorm2d(out_channels)\n self.divide_by = float(divide_by)\n def forward(self, x):\n return _ext.conv_inst_norm_div(x, self.conv.weight, self.conv.bias, self.divide_by)\n"
}
result ← compile_kernel (ok)
okcompile_kernel
compile_kernel PASSED: kernel compiled without errors.
turn 58.1s turn · 8.1s LLM · 0.0s tools
call → run_correctness
callrun_correctness
{
"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\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by);\n'''\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <ATen/ATen.h>\n#include <ATen/ops/conv2d.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <optional>\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n for (int offset = 16; offset > 0; offset >>= 1) val += __shfl_down_sync(0xffffffff, val, offset);\n return val;\n}\n__inline__ __device__ float block_reduce_sum(float val) {\n static __shared__ float shared[32];\n int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;\n val = warp_reduce_sum(val);\n if (lane == 0) shared[wid] = val;\n __syncthreads();\n val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warp_reduce_sum(val);\n return val;\n}\n__global__ __launch_bounds__(256, 2)\nvoid inst_norm_div_kernel(const float* __restrict__ x, float* __restrict__ y, int rows, int S, float inv_div) {\n int row = blockIdx.x;\n const float* base = x + (long long)row * S;\n float* out = y + (long long)row * S;\n float sum = 0.0f, sumsq = 0.0f;\n int S4 = S >> 2;\n const float4* base4 = reinterpret_cast<const float4*>(base);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n sum += v.x + v.y + v.z + v.w;\n sumsq += v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w;\n }\n sum = block_reduce_sum(sum);\n sumsq = block_reduce_sum(sumsq);\n __shared__ float sh_mean, sh_scale;\n if (threadIdx.x == 0) {\n float mean = sum / (float)S;\n float var = fmaxf(sumsq / (float)S - mean * mean, 0.0f);\n sh_mean = mean;\n sh_scale = rsqrtf(var + 1.0e-5f) * inv_div;\n }\n __syncthreads();\n float mean = sh_mean, scale = sh_scale;\n float4* out4 = reinterpret_cast<float4*>(out);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n v.x = (v.x - mean) * scale; v.y = (v.y - mean) * scale;\n v.z = (v.z - mean) * scale; v.w = (v.w - mean) * scale;\n out4[i] = v;\n }\n}\n\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by) {\n const c10::cuda::CUDAGuard device_guard(x.device());\n std::optional<at::Tensor> b = bias;\n std::vector<int64_t> stride = {1,1}, padding = {0,0}, dilation = {1,1};\n auto yconv = at::conv2d(x, weight, b, stride, padding, dilation, 1);\n auto y = torch::empty_like(yconv);\n int rows = (int)(yconv.size(0) * yconv.size(1));\n int S = (int)(yconv.size(2) * yconv.size(3));\n float inv_div = 1.0f / (float)divide_by;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n const float* xp = yconv.data_ptr<float>();\n float* yp = y.data_ptr<float>();\n inst_norm_div_kernel<<<rows, 256, 0, stream>>>(xp, yp, rows, S, inv_div);\n return y;\n}\n'''\n\n_ext = load_inline(name='conv_inst_norm_div_ext_v3', cpp_sources=cpp_source, cuda_sources=cuda_source,\n functions=['conv_inst_norm_div'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divide_by):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.instance_norm = nn.InstanceNorm2d(out_channels)\n self.divide_by = float(divide_by)\n def forward(self, x):\n return _ext.conv_inst_norm_div(x, self.conv.weight, self.conv.bias, self.divide_by)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=7.15e-06 mean_abs_err=1.13e-07 max_rel_err=7.01e+05
turn 613.2s turn · 13.2s LLM · 0.0s tools
reasoning
**Considering performance optimizations**
I'm thinking about the timing and whether I should only submit the final result. Maybe there's a way to compare variants without worrying about correctness related to timing.
I wonder if C++'s `at::conv2d` operates the same as `nn.Conv2d`. It might help to avoid separate allocations for `yconv` and the output. If I use the convolution output in-place after computing stats, it could lower memory usage. Okay, I’ll consider using `yconv` as the output to avoid additional memory allocation altogether.
**Exploring in-place optimization**
I'm examining if I can avoid extra allocations, specifically returning `yconv` without needing additional space. By modifying the convolution output directly, it seems I can effectively maintain performance. This approach keeps input and output separate, but in-place modifications might save some allocation time, which could be beneficial.
I’m considering fixing the wrapper call to modify the kernel to work correctly. If I keep everything in a single vector read before the write, I can eliminate race conditions. I think this could speed up the process overall, so implementing it should be worthwhile!
call → run_correctness
callrun_correctness
{
"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\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by);\n'''\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <ATen/ATen.h>\n#include <ATen/ops/conv2d.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <optional>\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) val += __shfl_down_sync(0xffffffff, val, offset);\n return val;\n}\n__inline__ __device__ float block_reduce_sum(float val) {\n static __shared__ float shared[32];\n int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;\n val = warp_reduce_sum(val);\n if (lane == 0) shared[wid] = val;\n __syncthreads();\n val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warp_reduce_sum(val);\n return val;\n}\n__global__ __launch_bounds__(256, 2)\nvoid inst_norm_div_inplace_kernel(float* __restrict__ x, int rows, int S, float inv_div) {\n int row = blockIdx.x;\n float* base = x + (long long)row * S;\n float sum = 0.0f, sumsq = 0.0f;\n int S4 = S >> 2;\n float4* base4 = reinterpret_cast<float4*>(base);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n sum += v.x + v.y + v.z + v.w;\n sumsq += v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w;\n }\n sum = block_reduce_sum(sum);\n sumsq = block_reduce_sum(sumsq);\n __shared__ float sh_mean, sh_scale;\n if (threadIdx.x == 0) {\n float mean = sum / (float)S;\n float var = fmaxf(sumsq / (float)S - mean * mean, 0.0f);\n sh_mean = mean;\n sh_scale = rsqrtf(var + 1.0e-5f) * inv_div;\n }\n __syncthreads();\n float mean = sh_mean, scale = sh_scale;\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n v.x = (v.x - mean) * scale; v.y = (v.y - mean) * scale;\n v.z = (v.z - mean) * scale; v.w = (v.w - mean) * scale;\n base4[i] = v;\n }\n}\n\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by) {\n const c10::cuda::CUDAGuard device_guard(x.device());\n std::optional<at::Tensor> b = bias;\n std::vector<int64_t> stride = {1,1}, padding = {0,0}, dilation = {1,1};\n auto y = at::conv2d(x, weight, b, stride, padding, dilation, 1);\n int rows = (int)(y.size(0) * y.size(1));\n int S = (int)(y.size(2) * y.size(3));\n float inv_div = 1.0f / (float)divide_by;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n inst_norm_div_inplace_kernel<<<rows, 256, 0, stream>>>(y.data_ptr<float>(), rows, S, inv_div);\n return y;\n}\n'''\n\n_ext = load_inline(name='conv_inst_norm_div_ext_v4_inplace', cpp_sources=cpp_source, cuda_sources=cuda_source,\n functions=['conv_inst_norm_div'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divide_by):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.instance_norm = nn.InstanceNorm2d(out_channels)\n self.divide_by = float(divide_by)\n def forward(self, x):\n return _ext.conv_inst_norm_div(x, self.conv.weight, self.conv.bias, self.divide_by)\n"
}
result ← run_correctness (ok)
okrun_correctness
run_correctness PASSED: (5 / 5) trials all matched the reference.
Numerical precision: max_abs_err=7.15e-06 mean_abs_err=1.13e-07 max_rel_err=7.01e+05
turn 746.1s turn · 46.1s LLM · 0.0s tools
call → static_check
callstatic_check
{
"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\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by);\n'''\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <ATen/ATen.h>\n#include <ATen/ops/conv2d.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <optional>\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) val += __shfl_down_sync(0xffffffff, val, offset);\n return val;\n}\n__inline__ __device__ float block_reduce_sum(float val) {\n static __shared__ float shared[32];\n int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;\n val = warp_reduce_sum(val);\n if (lane == 0) shared[wid] = val;\n __syncthreads();\n val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warp_reduce_sum(val);\n return val;\n}\n__global__ __launch_bounds__(256, 2)\nvoid inst_norm_div_inplace_kernel(float* __restrict__ x, int rows, int S, float inv_div) {\n int row = blockIdx.x;\n float* base = x + (long long)row * S;\n float sum = 0.0f, sumsq = 0.0f;\n int S4 = S >> 2;\n float4* base4 = reinterpret_cast<float4*>(base);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n sum += v.x + v.y + v.z + v.w;\n sumsq += v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w;\n }\n sum = block_reduce_sum(sum);\n sumsq = block_reduce_sum(sumsq);\n __shared__ float sh_mean, sh_scale;\n if (threadIdx.x == 0) {\n float mean = sum / (float)S;\n float var = fmaxf(sumsq / (float)S - mean * mean, 0.0f);\n sh_mean = mean;\n sh_scale = rsqrtf(var + 1.0e-5f) * inv_div;\n }\n __syncthreads();\n float mean = sh_mean, scale = sh_scale;\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n v.x = (v.x - mean) * scale; v.y = (v.y - mean) * scale;\n v.z = (v.z - mean) * scale; v.w = (v.w - mean) * scale;\n base4[i] = v;\n }\n}\n\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by) {\n const c10::cuda::CUDAGuard device_guard(x.device());\n std::optional<at::Tensor> b = bias;\n std::vector<int64_t> stride = {1,1}, padding = {0,0}, dilation = {1,1};\n auto y = at::conv2d(x, weight, b, stride, padding, dilation, 1);\n int rows = (int)(y.size(0) * y.size(1));\n int S = (int)(y.size(2) * y.size(3));\n float inv_div = 1.0f / (float)divide_by;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n inst_norm_div_inplace_kernel<<<rows, 256, 0, stream>>>(y.data_ptr<float>(), rows, S, inv_div);\n return y;\n}\n'''\n\n_ext = load_inline(name='conv_inst_norm_div_ext_v4_inplace', cpp_sources=cpp_source, cuda_sources=cuda_source,\n functions=['conv_inst_norm_div'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divide_by):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.instance_norm = nn.InstanceNorm2d(out_channels)\n self.divide_by = float(divide_by)\n def forward(self, x):\n return _ext.conv_inst_norm_div(x, self.conv.weight, self.conv.bias, self.divide_by)\n"
}
result ← static_check (ok)
okstatic_check
static_check PASSED: no violations or warnings detected.
turn 824.9s turn · 24.9s LLM · 0.0s tools · FINAL
reasoning
**Optimizing conv2d process**
I’m thinking about how the host wrapper for conv2d could help reduce Python overhead and output allocation. That should improve memory usage since in-place operations can be more efficient. That's a good direction to take! I need to submit this soon. I’ll use the same kernel code but should ensure the name is unique, maybe for the final submission. Let’s get everything lined up for that!
call → submit_kernel
callsubmit_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\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by);\n'''\n\ncuda_source = r'''\n#include <torch/extension.h>\n#include <ATen/ATen.h>\n#include <ATen/ops/conv2d.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <c10/cuda/CUDAGuard.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <optional>\n\n__inline__ __device__ float warp_reduce_sum(float val) {\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) val += __shfl_down_sync(0xffffffff, val, offset);\n return val;\n}\n__inline__ __device__ float block_reduce_sum(float val) {\n static __shared__ float shared[32];\n int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;\n val = warp_reduce_sum(val);\n if (lane == 0) shared[wid] = val;\n __syncthreads();\n val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;\n if (wid == 0) val = warp_reduce_sum(val);\n return val;\n}\n__global__ __launch_bounds__(256, 2)\nvoid inst_norm_div_inplace_kernel(float* __restrict__ x, int rows, int S, float inv_div) {\n int row = blockIdx.x;\n float* base = x + (long long)row * S;\n float sum = 0.0f, sumsq = 0.0f;\n int S4 = S >> 2;\n float4* base4 = reinterpret_cast<float4*>(base);\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n sum += v.x + v.y + v.z + v.w;\n sumsq += v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w;\n }\n sum = block_reduce_sum(sum);\n sumsq = block_reduce_sum(sumsq);\n __shared__ float sh_mean, sh_scale;\n if (threadIdx.x == 0) {\n float mean = sum / (float)S;\n float var = fmaxf(sumsq / (float)S - mean * mean, 0.0f);\n sh_mean = mean;\n sh_scale = rsqrtf(var + 1.0e-5f) * inv_div;\n }\n __syncthreads();\n float mean = sh_mean, scale = sh_scale;\n for (int i = threadIdx.x; i < S4; i += blockDim.x) {\n float4 v = base4[i];\n v.x = (v.x - mean) * scale; v.y = (v.y - mean) * scale;\n v.z = (v.z - mean) * scale; v.w = (v.w - mean) * scale;\n base4[i] = v;\n }\n}\n\ntorch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by) {\n const c10::cuda::CUDAGuard device_guard(x.device());\n std::optional<at::Tensor> b = bias;\n std::vector<int64_t> stride = {1,1}, padding = {0,0}, dilation = {1,1};\n auto y = at::conv2d(x, weight, b, stride, padding, dilation, 1);\n int rows = (int)(y.size(0) * y.size(1));\n int S = (int)(y.size(2) * y.size(3));\n float inv_div = 1.0f / (float)divide_by;\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n inst_norm_div_inplace_kernel<<<rows, 256, 0, stream>>>(y.data_ptr<float>(), rows, S, inv_div);\n return y;\n}\n'''\n\n_ext = load_inline(name='conv_inst_norm_div_ext_final', cpp_sources=cpp_source, cuda_sources=cuda_source,\n functions=['conv_inst_norm_div'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, in_channels, out_channels, kernel_size, divide_by):\n super(ModelNew, self).__init__()\n self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)\n self.instance_norm = nn.InstanceNorm2d(out_channels)\n self.divide_by = float(divide_by)\n def forward(self, x):\n return _ext.conv_inst_norm_div(x, self.conv.weight, self.conv.bias, self.divide_by)\n"
}
result ← submit_kernel (ok)
oksubmit_kernel
submit_kernel PASSED: (5 / 5) correctness trials all passed.
Kernel runtime: 4.05 μs
Runtime stats: mean=4.05μs median=?μs std=0.11μs
Numerical precision: max_abs_err=7.15e-06 mean_abs_err=1.13e-07 max_rel_err=7.01e+05
Memory: 2050.1 MB peak (ref: 2530.19 MB, ratio: 0.8103x)
Kernel launches: 7 (ref: 24, fusion ratio: 3.4286)
Energy: 645.44 mJ/run (ref: 968.1 mJ, ratio: 1.4999x)
SOL score: 1.0
final submitted kernel (92 lines, 3,503 chars) — full source, untruncated
import torch
import torch.nn as nn
from torch.utils.cpp_extension import load_inline
cpp_source = r'''
#include <torch/extension.h>
torch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by);
'''
cuda_source = r'''
#include <torch/extension.h>
#include <ATen/ATen.h>
#include <ATen/ops/conv2d.h>
#include <ATen/cuda/CUDAContext.h>
#include <c10/cuda/CUDAGuard.h>
#include <cuda.h>
#include <cuda_runtime.h>
#include <optional>
__inline__ __device__ float warp_reduce_sum(float val) {
#pragma unroll
for (int offset = 16; offset > 0; offset >>= 1) val += __shfl_down_sync(0xffffffff, val, offset);
return val;
}
__inline__ __device__ float block_reduce_sum(float val) {
static __shared__ float shared[32];
int lane = threadIdx.x & 31, wid = threadIdx.x >> 5;
val = warp_reduce_sum(val);
if (lane == 0) shared[wid] = val;
__syncthreads();
val = (threadIdx.x < (blockDim.x >> 5)) ? shared[lane] : 0.0f;
if (wid == 0) val = warp_reduce_sum(val);
return val;
}
__global__ __launch_bounds__(256, 2)
void inst_norm_div_inplace_kernel(float* __restrict__ x, int rows, int S, float inv_div) {
int row = blockIdx.x;
float* base = x + (long long)row * S;
float sum = 0.0f, sumsq = 0.0f;
int S4 = S >> 2;
float4* base4 = reinterpret_cast<float4*>(base);
for (int i = threadIdx.x; i < S4; i += blockDim.x) {
float4 v = base4[i];
sum += v.x + v.y + v.z + v.w;
sumsq += v.x*v.x + v.y*v.y + v.z*v.z + v.w*v.w;
}
sum = block_reduce_sum(sum);
sumsq = block_reduce_sum(sumsq);
__shared__ float sh_mean, sh_scale;
if (threadIdx.x == 0) {
float mean = sum / (float)S;
float var = fmaxf(sumsq / (float)S - mean * mean, 0.0f);
sh_mean = mean;
sh_scale = rsqrtf(var + 1.0e-5f) * inv_div;
}
__syncthreads();
float mean = sh_mean, scale = sh_scale;
for (int i = threadIdx.x; i < S4; i += blockDim.x) {
float4 v = base4[i];
v.x = (v.x - mean) * scale; v.y = (v.y - mean) * scale;
v.z = (v.z - mean) * scale; v.w = (v.w - mean) * scale;
base4[i] = v;
}
}
torch::Tensor conv_inst_norm_div(torch::Tensor x, torch::Tensor weight, torch::Tensor bias, double divide_by) {
const c10::cuda::CUDAGuard device_guard(x.device());
std::optional<at::Tensor> b = bias;
std::vector<int64_t> stride = {1,1}, padding = {0,0}, dilation = {1,1};
auto y = at::conv2d(x, weight, b, stride, padding, dilation, 1);
int rows = (int)(y.size(0) * y.size(1));
int S = (int)(y.size(2) * y.size(3));
float inv_div = 1.0f / (float)divide_by;
cudaStream_t stream = at::cuda::getCurrentCUDAStream();
inst_norm_div_inplace_kernel<<<rows, 256, 0, stream>>>(y.data_ptr<float>(), rows, S, inv_div);
return y;
}
'''
_ext = load_inline(name='conv_inst_norm_div_ext_final', cpp_sources=cpp_source, cuda_sources=cuda_source,
functions=['conv_inst_norm_div'], extra_cuda_cflags=['-O3'], extra_cflags=['-O3'], verbose=False)
class ModelNew(nn.Module):
def __init__(self, in_channels, out_channels, kernel_size, divide_by):
super(ModelNew, self).__init__()
self.conv = nn.Conv2d(in_channels, out_channels, kernel_size)
self.instance_norm = nn.InstanceNorm2d(out_channels)
self.divide_by = float(divide_by)
def forward(self, x):
return _ext.conv_inst_norm_div(x, self.conv.weight, self.conv.bias, self.divide_by)