call → compile_kernel
callcompile_kernel
{
"kernel_code": "import torch\nimport torch.nn as nn\nfrom torch.utils.cpp_extension import load_inline\n\n_cpp_src = r\"\"\"\n#include <torch/extension.h>\ntorch::Tensor logsoftmax_cuda(torch::Tensor x, int64_t dim);\n\"\"\"\n\n_cuda_src = r\"\"\"\n#include <torch/extension.h>\n#include <ATen/cuda/CUDAContext.h>\n#include <cuda.h>\n#include <cuda_runtime.h>\n#include <cfloat>\n#include <cmath>\n\nstatic __device__ __forceinline__ void combine_pair(float &m, float &s, float m2, float s2) {\n if (m2 > m) {\n s = s2 + s * __expf(m - m2);\n m = m2;\n } else {\n s = s + s2 * __expf(m2 - m);\n }\n}\n\nstatic __device__ __forceinline__ void warp_reduce_pair(float &m, float &s) {\n unsigned mask = 0xffffffffu;\n #pragma unroll\n for (int offset = 16; offset > 0; offset >>= 1) {\n float m2 = __shfl_down_sync(mask, m, offset);\n float s2 = __shfl_down_sync(mask, s, offset);\n combine_pair(m, s, m2, s2);\n }\n}\n\ntemplate<int BLOCK>\n__global__ __launch_bounds__(BLOCK, 2)\nvoid logsoftmax_row_kernel(const float* __restrict__ x, float* __restrict__ y, int rows, int cols) {\n int row = blockIdx.x;\n if (row >= rows) return;\n const float* rowx = x + (long long)row * cols;\n float* rowy = y + (long long)row * cols;\n int tid = threadIdx.x;\n\n float m = -CUDART_INF_F;\n float s = 0.0f;\n\n if ((cols & 3) == 0) {\n int n4 = cols >> 2;\n const float4* x4 = reinterpret_cast<const float4*>(rowx);\n for (int i = tid; i < n4; i += BLOCK) {\n float4 v = x4[i];\n combine_pair(m, s, v.x, 1.0f);\n combine_pair(m, s, v.y, 1.0f);\n combine_pair(m, s, v.z, 1.0f);\n combine_pair(m, s, v.w, 1.0f);\n }\n } else {\n for (int i = tid; i < cols; i += BLOCK) {\n combine_pair(m, s, rowx[i], 1.0f);\n }\n }\n\n warp_reduce_pair(m, s);\n\n __shared__ float smem_m[32];\n __shared__ float smem_s[32];\n int lane = tid & 31;\n int warp = tid >> 5;\n if (lane == 0) {\n smem_m[warp] = m;\n smem_s[warp] = s;\n }\n __syncthreads();\n\n if (warp == 0) {\n int num_warps = (BLOCK + 31) >> 5;\n m = (lane < num_warps) ? smem_m[lane] : -CUDART_INF_F;\n s = (lane < num_warps) ? smem_s[lane] : 0.0f;\n warp_reduce_pair(m, s);\n if (lane == 0) {\n smem_m[0] = m;\n smem_s[0] = s;\n }\n }\n __syncthreads();\n\n float offset = smem_m[0] + logf(smem_s[0]);\n\n if ((cols & 3) == 0) {\n int n4 = cols >> 2;\n const float4* x4 = reinterpret_cast<const float4*>(rowx);\n float4* y4 = reinterpret_cast<float4*>(rowy);\n for (int i = tid; i < n4; i += BLOCK) {\n float4 v = x4[i];\n v.x -= offset;\n v.y -= offset;\n v.z -= offset;\n v.w -= offset;\n y4[i] = v;\n }\n } else {\n for (int i = tid; i < cols; i += BLOCK) {\n rowy[i] = rowx[i] - offset;\n }\n }\n}\n\ntemplate<int BLOCK>\n__global__ __launch_bounds__(BLOCK, 2)\nvoid logsoftmax_col_kernel(const float* __restrict__ x, float* __restrict__ y, int rows, int cols) {\n int col = blockIdx.x;\n if (col >= cols) return;\n int tid = threadIdx.x;\n float m = -CUDART_INF_F;\n for (int r = tid; r < rows; r += BLOCK) {\n float v = x[(long long)r * cols + col];\n m = fmaxf(m, v);\n }\n unsigned mask = 0xffffffffu;\n #pragma unroll\n for (int off=16; off>0; off>>=1) m = fmaxf(m, __shfl_down_sync(mask, m, off));\n __shared__ float sm[32];\n int lane = tid & 31, warp = tid >> 5;\n if (lane == 0) sm[warp] = m;\n __syncthreads();\n if (warp == 0) {\n int nw = (BLOCK+31)>>5;\n m = (lane < nw) ? sm[lane] : -CUDART_INF_F;\n #pragma unroll\n for (int off=16; off>0; off>>=1) m = fmaxf(m, __shfl_down_sync(mask, m, off));\n if (lane == 0) sm[0] = m;\n }\n __syncthreads();\n m = sm[0];\n float sum = 0.0f;\n for (int r = tid; r < rows; r += BLOCK) sum += __expf(x[(long long)r * cols + col] - m);\n #pragma unroll\n for (int off=16; off>0; off>>=1) sum += __shfl_down_sync(mask, sum, off);\n __shared__ float ss[32];\n if (lane == 0) ss[warp] = sum;\n __syncthreads();\n if (warp == 0) {\n int nw = (BLOCK+31)>>5;\n sum = (lane < nw) ? ss[lane] : 0.0f;\n #pragma unroll\n for (int off=16; off>0; off>>=1) sum += __shfl_down_sync(mask, sum, off);\n if (lane == 0) ss[0] = sum;\n }\n __syncthreads();\n float offv = m + logf(ss[0]);\n for (int r = tid; r < rows; r += BLOCK) y[(long long)r * cols + col] = x[(long long)r * cols + col] - offv;\n}\n\ntorch::Tensor logsoftmax_cuda(torch::Tensor x, int64_t dim) {\n TORCH_CHECK(x.is_cuda(), \"x must be CUDA\");\n TORCH_CHECK(x.scalar_type() == at::kFloat, \"only float32 supported\");\n TORCH_CHECK(x.dim() == 2, \"only 2D tensors supported\");\n auto xc = x.contiguous();\n auto y = torch::empty_like(xc);\n int rows = (int)xc.size(0);\n int cols = (int)xc.size(1);\n cudaStream_t stream = at::cuda::getCurrentCUDAStream();\n if (dim < 0) dim += 2;\n if (dim == 1) {\n constexpr int BLOCK = 512;\n logsoftmax_row_kernel<BLOCK><<<rows, BLOCK, 0, stream>>>(xc.data_ptr<float>(), y.data_ptr<float>(), rows, cols);\n } else if (dim == 0) {\n constexpr int BLOCK = 256;\n logsoftmax_col_kernel<BLOCK><<<cols, BLOCK, 0, stream>>>(xc.data_ptr<float>(), y.data_ptr<float>(), rows, cols);\n } else {\n TORCH_CHECK(false, \"dim out of range\");\n }\n return y;\n}\n\"\"\"\n\n_ext = load_inline(name=\"logsoftmax_ext_v1\", cpp_sources=_cpp_src, cuda_sources=_cuda_src,\n functions=[\"logsoftmax_cuda\"], extra_cuda_cflags=[\"-O3\", \"--use_fast_math\"], verbose=False)\n\nclass ModelNew(nn.Module):\n def __init__(self, dim: int = 1):\n super(ModelNew, self).__init__()\n self.dim = dim\n def forward(self, x: torch.Tensor) -> torch.Tensor:\n return _ext.logsoftmax_cuda(x, self.dim)\n"
}