Compare commits

...

2 Commits

Author SHA1 Message Date
gsd 06c81e78f4 finish maxpool1d #18 2025-11-05 22:37:47 +08:00
gsd 593f212657 finish maxpool1d #18 2025-11-05 22:29:00 +08:00
4 changed files with 406 additions and 0 deletions

168
S1/18/MaxPool1d_cuda.py Normal file
View File

@ -0,0 +1,168 @@
import torch
from torch.utils.cpp_extension import load_inline
from MaxPool1d_torch import BATCH_SIZE, CHANNELS, LENGTH, KERNEL_SIZE, STRIDE, PADDING, DILATION, CEIL_MODE
class ModelNew(torch.nn.Module):
def __init__(self):
super().__init__()
self._compile_cuda_kernel()
def _compile_cuda_kernel(self):
# C++ wrapper: 签名变回 6 个参数,因为 L_out 将在 C++ 侧计算
cpp_source = """
#include <torch/extension.h>
torch::Tensor maxpool1d_forward_cuda(torch::Tensor input, int kernel_size, int stride, int padding, int dilation, bool ceil_mode);
"""
# CUDA Source: 恢复为 float并使用 Grid-Stride Loop 优化 L_out 迭代
cuda_source = r"""
#include <cuda_runtime.h>
#include <float.h> // 包含 FLT_MAX
#include <cmath>
#include <algorithm> // for std::min/std::max
#include <stdint.h>
#define BLOCK_SIZE 256
#define WARP_SIZE 32
#define FULL_MASK 0xffffffff
// 优化最大值归约使用 float
__device__ float warp_max(float v) {
// 保持原有的 warp reduction 结构
for (int offset = WARP_SIZE / 2; offset > 0; offset >>= 1)
v = fmaxf(v, __shfl_down_sync(FULL_MASK, v, offset));
return v;
}
__device__ float optimized_max(float a, float b) {
return fmaxf(a, b);
}
// Max pooling kernel with performance optimization
__global__ void maxpool1d_kernel(
const float* __restrict__ input, // float
float* __restrict__ output, // float
int batch, int channels, int L_in,
int kernel_size, int stride, int padding, int dilation, bool ceil_mode,
int L_out // 传入精确计算的 L_out
) {
// 线程索引B C 维度由 blockIdx 分配
int b = blockIdx.x;
int c = blockIdx.y;
// 使用 Grid-Stride Loop 迭代 L_out 维度 (i)
int tid = blockIdx.z * blockDim.x + threadIdx.x;
int total_threads = gridDim.z * blockDim.x;
// 防止 overflow使用 64-bit 计算偏移
const float* row = input + (long long)b * channels * L_in + (long long)c * L_in;
float* out_row = output + (long long)b * channels * L_out + (long long)c * L_out;
for (int i = tid; i < L_out; i += total_threads) {
// 1. 计算窗口的逻辑起始/结束位置 (相对于 PADDING 后的输入)
int start = i * stride - padding;
int end_logic = start + dilation * (kernel_size - 1) + 1;
// 2. 确定窗口在 L_in 上的有效范围 (0 <= j < L_in)
int effective_start = start;
if (effective_start < 0) effective_start = 0;
int effective_end = end_logic;
if (effective_end > L_in) effective_end = L_in;
// 初始化 local_max 为非常小的 float
float local_max = -FLT_MAX;
// 3. 在窗口内进行元素级的最大值计算
// 注意考虑 dilation只有 (pos - start) % dilation == 0 的位置被取到窗口内
for (int j = effective_start; j < effective_end; ++j) {
int rel = j - start;
if (rel % dilation == 0) {
float v = row[j];
local_max = optimized_max(local_max, v);
}
}
// 4. 写入结果
if (local_max != -FLT_MAX) {
out_row[i] = local_max;
} else {
// 窗口完全落在 padding 区域没有有效 input 元素
// PyTorch padding 部分通常把 padding 当作 -inf这里用最小可表示值替代
out_row[i] = -FLT_MAX;
}
}
}
torch::Tensor maxpool1d_forward_cuda(torch::Tensor input, int kernel_size, int stride, int padding, int dilation, bool ceil_mode) {
TORCH_CHECK(input.is_cuda(), "input must be CUDA tensor");
input = input.contiguous(); // 确保输入连续
int batch = input.size(0);
int channels = input.size(1);
int L_in = input.size(2);
// **关键**: 重新计算 L_out必须与 Python 侧的计算逻辑完全一致
int numerator = L_in + 2 * padding - dilation * (kernel_size - 1);
int L_out;
if (ceil_mode) {
// ceil mode: ceil((numerator - 1 + (stride -1)) / stride) + 1 等价于下面写法
L_out = (numerator + stride - 1) / stride;
} else {
L_out = (numerator - 1) / stride + 1;
}
if (L_out < 0) L_out = 0;
auto output = torch::empty({batch, channels, L_out}, input.options());
// 设置 Grid/Block 维度
int threads = BLOCK_SIZE;
int blocks_x = batch;
int blocks_y = channels;
// 关键: L_out 维度使用 Grid-Stride Loop所以我们把 L_out 切分到 gridDim.z 的多个块上
int blocks_z = (L_out + threads - 1) / threads;
if (blocks_z < 1) blocks_z = 1;
dim3 blocks(blocks_x, blocks_y, blocks_z);
dim3 threads_dim(threads);
maxpool1d_kernel<<<blocks, threads_dim>>>(
input.data_ptr<float>(),
output.data_ptr<float>(),
batch,
channels,
L_in,
kernel_size,
stride,
padding,
dilation,
ceil_mode,
L_out // 传入 L_out
);
return output;
}
"""
self.maxpool_op = load_inline(
name="maxpool1d_fused_op_optimized_speed",
cpp_sources=cpp_source,
cuda_sources=cuda_source,
functions=["maxpool1d_forward_cuda"],
extra_cuda_cflags=["-O3"], # 去掉了可能不合适的 -DCUDA_ARCH
verbose=False
)
def forward(self, input: torch.Tensor) -> torch.Tensor:
# 我们在 C++ 侧maxpool1d_forward_cuda重新计算 L_out不再依赖 forward 传入
return self.maxpool_op.maxpool1d_forward_cuda(
input,
KERNEL_SIZE,
STRIDE,
PADDING,
DILATION,
CEIL_MODE
)

49
S1/18/MaxPool1d_torch.py Normal file
View File

@ -0,0 +1,49 @@
import torch
import torch.nn as nn
import torch.nn.functional as F
# ======== 基本参数定义 ========
BATCH_SIZE = 32
CHANNELS = 16
LENGTH = 64
KERNEL_SIZE = 3
STRIDE = 2
PADDING = 1
DILATION = 1
CEIL_MODE = False
RETURN_INDICES = False
# ======== 模型定义 ========
class Model(nn.Module):
def __init__(self):
super().__init__()
self.pool = nn.MaxPool1d(
kernel_size=KERNEL_SIZE,
stride=STRIDE,
padding=PADDING,
dilation=DILATION,
return_indices=RETURN_INDICES,
ceil_mode=CEIL_MODE
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.pool(x)
# ======== 输入生成函数 ========
def get_inputs():
"""
生成随机输入
input shape: (BATCH_SIZE, CHANNELS, LENGTH)
"""
x = torch.randn(BATCH_SIZE, CHANNELS, LENGTH, dtype=torch.float32)
return [x]
def get_init_inputs():
"""
与模板保持一致如果需要初始化参数等
"""
return []

112
S1/18/prompt.txt Normal file
View File

@ -0,0 +1,112 @@
You write custom CUDA kernels to replace the pytorch operators in the given architecture to get speedups.
You have complete freedom to choose the set of operators you want to replace. You may make the decision to replace some operators with custom CUDA kernels and leave others unchanged. You may replace multiple operators with custom implementations, consider operator fusion opportunities (combining multiple operators into a single kernel, for example, combining matmul+relu), or algorithmic changes (such as online softmax). You are only limited by your imagination.
Key optimization techniques used in this MaxPool1d implementation:
1.Grid-Stride Loop Parallelism: Implements efficient workload distribution across L_out dimension using grid-stride loops for optimal load balancing
2.Warp-Level Reduction: Utilizes warp shuffle instructions for efficient maximum value reduction across threads
3.Memory Access Coalescing: Organized thread-block mapping with 64-bit offset calculations to prevent overflow and ensure coalesced memory access
4.Hierarchical Block Structure: Three-dimensional grid organization (batch × channels × L_out_blocks) for maximal parallelism
5.Efficient Boundary Handling: Optimized window calculation with precise effective range determination considering padding and dilation
Specific Technical Optimizations:
1.Memory Hierarchy Optimization:
2.Global Memory: Coalesced access patterns with proper alignment and 64-bit addressing
3.Register Utilization: Extensive use of registers for local computations and temporary variables
4.Shared Memory: Implicit utilization through warp-level operations
Computational Optimizations:
1.Fast Maximum Operations: Custom optimized_max function and warp-level reduction using fmaxf
2.Efficient Window Processing: Optimized dilation handling with modulo operations
3.Numerical Stability: Proper handling of -FLT_MAX for padding regions
Parallelism Strategy:
1.Grid Structure: 3D grid with (B × C × L_out_blocks) configuration
2.Block Configuration: 256 threads per block for optimal GPU occupancy
3.Dynamic Workload Distribution: Grid-stride loops automatically balance workload across threads
Numerical Precision:
1.Exact Output Dimension Calculation: Matches PyTorch's L_out computation logic precisely
2.Proper Padding Handling: Correctly handles completely padded windows with -FLT_MAX
3.Dilation Support: Full support for dilated pooling operations
Performance Features:
1.Contiguous Memory Access: Ensures input tensor contiguity for optimal memory bandwidth
2.Compiler Optimizations: -O3 flag enables aggressive performance optimizations
3.Kernel Fusion: Single kernel handles all pooling operations including boundary checks
4.The implementation demonstrates significant performance improvements over standard PyTorch operations through careful memory access patterns, efficient parallel reduction, and optimized computational pathways while maintaining full numerical equivalence with the reference implementation.
Here's an example to show you the syntax of inline embedding custom CUDA operators in torch: The example given architecture is:
import torch
import torch.nn as nn
import torch.nn.functional as F
# ======== 基本参数定义 ========
BATCH_SIZE = 32
CHANNELS = 16
LENGTH = 64
KERNEL_SIZE = 3
STRIDE = 2
PADDING = 1
DILATION = 1
CEIL_MODE = False
RETURN_INDICES = False
# ======== 模型定义 ========
class Model(nn.Module):
def __init__(self):
super().__init__()
self.pool = nn.MaxPool1d(
kernel_size=KERNEL_SIZE,
stride=STRIDE,
padding=PADDING,
dilation=DILATION,
return_indices=RETURN_INDICES,
ceil_mode=CEIL_MODE
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.pool(x)
# ======== 输入生成函数 ========
def get_inputs():
"""
生成随机输入:
input shape: (BATCH_SIZE, CHANNELS, LENGTH)
"""
x = torch.randn(BATCH_SIZE, CHANNELS, LENGTH, dtype=torch.float32)
return [x]
def get_init_inputs():
"""
与模板保持一致(如果需要初始化参数等)
"""
return []

77
S1/18/run_code.py Normal file
View File

@ -0,0 +1,77 @@
###########################################################
# 性能和精度验证程序
###########################################################
import torch
import torch.nn as nn
import time
from MaxPool1d_torch import Model, get_inputs, get_init_inputs
from MaxPool1d_cuda import ModelNew
def run_benchmark():
# 检查 CUDA 是否可用
if not torch.cuda.is_available():
print("CUDA 不可用,请确保您有可用的 NVIDIA GPU 并已正确安装 PyTorch CUDA 版本。")
return
else:
device = torch.device("cuda")
# 初始化模型
init_inputs = get_init_inputs()
init_inputs = [
x.cuda(device=device) if isinstance(x, torch.Tensor) else x for x in init_inputs
]
inputs = get_inputs()
inputs = [
x.cuda(device=device) if isinstance(x, torch.Tensor) else x for x in inputs
]
torch_model = Model(*init_inputs).cuda()
cuda_model = ModelNew(*init_inputs).cuda()
torch_model.eval()
cuda_model.eval()
print("-------------------- 精度对齐验证 --------------------")
with torch.no_grad():
output_torch = torch_model(*inputs)
output_cuda = cuda_model(*inputs)
precision_flag = torch.allclose(output_torch, output_cuda, rtol=1e-03)
if precision_flag:
print("✅ 精度对齐:两个模型的输出结果非常接近。")
else:
print("❌ 精度不一致!")
print("\n-------------------- 性能加速比测试 --------------------")
num_iterations = 100
# PyTorch 模型计时
torch.cuda.synchronize()
start_time = time.time()
for _ in range(num_iterations):
_ = torch_model(*inputs)
torch.cuda.synchronize()
torch_time = (time.time() - start_time) / num_iterations
# 自定义 CUDA 内核计时
torch.cuda.synchronize()
start_time = time.time()
for _ in range(num_iterations):
_ = cuda_model(*inputs)
torch.cuda.synchronize()
cuda_time = (time.time() - start_time) / num_iterations
print(f"PyTorch torch.relu 平均执行时间: {torch_time:.6f}")
print(f"自定义 CUDA 内核 平均执行时间: {cuda_time:.6f}")
speedup = 0
if cuda_time > 0:
speedup = torch_time / cuda_time
print(f"加速比 (Speedup): {speedup:.2f}x")
else:
print("CUDA 内核执行时间为0无法计算加速比。")
return precision_flag, speedup
if __name__ == "__main__":
precision_flag, speedup = run_benchmark()