forked from ccf-ai-infra/GPUCodeForces
263 lines
9.6 KiB
Python
263 lines
9.6 KiB
Python
|
|
import torch
|
|||
|
|
import torch.nn as nn
|
|||
|
|
from torch.utils.cpp_extension import load_inline
|
|||
|
|
|
|||
|
|
# 定义维度常量
|
|||
|
|
N, C, H, W = 32, 64, 56, 56
|
|||
|
|
EPS = 1e-6
|
|||
|
|
|
|||
|
|
assert (H * W) % 4 == 0, "Instance size (H * W) must be a multiple of 4"
|
|||
|
|
|
|||
|
|
|
|||
|
|
class ModelNew(nn.Module):
|
|||
|
|
"""
|
|||
|
|
EvoNorm-S0/B0 的 CUDA 优化实现
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
def __init__(self, evonorm_gamma, evonorm_beta, evonorm_v=None, use_b0=False):
|
|||
|
|
super().__init__()
|
|||
|
|
self.gamma = nn.Parameter(evonorm_gamma.clone().view(1, C, 1, 1))
|
|||
|
|
self.beta = nn.Parameter(evonorm_beta.clone().view(1, C, 1, 1))
|
|||
|
|
self.eps = EPS
|
|||
|
|
self.nonlinear = (evonorm_v is not None)
|
|||
|
|
self.use_b0 = use_b0
|
|||
|
|
|
|||
|
|
if self.nonlinear:
|
|||
|
|
self.v = nn.Parameter(evonorm_v.clone().view(1, C, 1, 1))
|
|||
|
|
else:
|
|||
|
|
self.register_parameter('v', None)
|
|||
|
|
|
|||
|
|
if self.use_b0:
|
|||
|
|
self.register_buffer('running_var', torch.ones(1, C, 1, 1))
|
|||
|
|
self.momentum = 0.1
|
|||
|
|
|
|||
|
|
self._compile_cuda_kernel()
|
|||
|
|
|
|||
|
|
def _compile_cuda_kernel(self):
|
|||
|
|
cpp_source = """
|
|||
|
|
#include <torch/extension.h>
|
|||
|
|
|
|||
|
|
torch::Tensor evonorm_forward_cuda(
|
|||
|
|
torch::Tensor input,
|
|||
|
|
torch::Tensor mean,
|
|||
|
|
torch::Tensor var,
|
|||
|
|
torch::Tensor gamma,
|
|||
|
|
torch::Tensor beta,
|
|||
|
|
torch::Tensor v,
|
|||
|
|
float eps,
|
|||
|
|
bool nonlinear,
|
|||
|
|
int N, int C, int H, int W);
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
cuda_source = """
|
|||
|
|
#include <cuda_runtime.h>
|
|||
|
|
#include <device_launch_parameters.h>
|
|||
|
|
#include <cmath>
|
|||
|
|
|
|||
|
|
// 优化: 使用快速数学函数
|
|||
|
|
#define FAST_DIV(a, b) __fdividef(a, b)
|
|||
|
|
#define FAST_EXP(x) __expf(x)
|
|||
|
|
|
|||
|
|
// 优化 1: Sigmoid 快速计算(使用查找表或优化公式)
|
|||
|
|
__device__ __forceinline__ float fast_sigmoid(float x) {
|
|||
|
|
// 使用快速除法和指数
|
|||
|
|
return FAST_DIV(1.0f, 1.0f + FAST_EXP(-x));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 优化 2: 向量化 sigmoid 计算
|
|||
|
|
__device__ __forceinline__ float4 sigmoid_vec(float4 x, float v_val) {
|
|||
|
|
float4 result;
|
|||
|
|
result.x = fast_sigmoid(x.x * v_val);
|
|||
|
|
result.y = fast_sigmoid(x.y * v_val);
|
|||
|
|
result.z = fast_sigmoid(x.z * v_val);
|
|||
|
|
result.w = fast_sigmoid(x.w * v_val);
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
__global__ void evonorm_apply_kernel(
|
|||
|
|
const float* __restrict__ x,
|
|||
|
|
const float* __restrict__ mean,
|
|||
|
|
const float* __restrict__ var,
|
|||
|
|
const float* __restrict__ gamma,
|
|||
|
|
const float* __restrict__ beta,
|
|||
|
|
const float* __restrict__ v,
|
|||
|
|
float* __restrict__ y,
|
|||
|
|
float eps,
|
|||
|
|
bool nonlinear,
|
|||
|
|
int N, int C, int H, int W
|
|||
|
|
) {
|
|||
|
|
const int nc_idx = blockIdx.x;
|
|||
|
|
if (nc_idx >= N * C) return;
|
|||
|
|
|
|||
|
|
const int n_idx = nc_idx / C;
|
|||
|
|
const int c_idx = nc_idx % C;
|
|||
|
|
|
|||
|
|
// 优化 3: 使用 __ldg() 读取只读全局内存
|
|||
|
|
const float m = __ldg(&mean[nc_idx]);
|
|||
|
|
const float variance = __ldg(&var[nc_idx]);
|
|||
|
|
|
|||
|
|
// 优化 4: 预计算常量
|
|||
|
|
const float inv_std = rsqrtf(variance + eps); // rsqrtf 比 1.0f/sqrtf 快
|
|||
|
|
|
|||
|
|
const float g = __ldg(&gamma[c_idx]);
|
|||
|
|
const float b = __ldg(&beta[c_idx]);
|
|||
|
|
const float v_val = nonlinear ? __ldg(&v[c_idx]) : 0.0f;
|
|||
|
|
|
|||
|
|
const int instance_size = H * W;
|
|||
|
|
const int instance_offset = n_idx * C * instance_size + c_idx * instance_size;
|
|||
|
|
const float* x_ptr = x + instance_offset;
|
|||
|
|
float* y_ptr = y + instance_offset;
|
|||
|
|
|
|||
|
|
const int instance_size_div4 = instance_size / 4;
|
|||
|
|
const float4* x4_ptr = reinterpret_cast<const float4*>(x_ptr);
|
|||
|
|
float4* y4_ptr = reinterpret_cast<float4*>(y_ptr);
|
|||
|
|
|
|||
|
|
const int BLOCK_SIZE = 256;
|
|||
|
|
|
|||
|
|
// 优化 5: 循环展开(处理 2 个 float4 每次迭代)
|
|||
|
|
const int items_per_thread = (instance_size_div4 + BLOCK_SIZE - 1) / BLOCK_SIZE;
|
|||
|
|
const int base_idx = threadIdx.x;
|
|||
|
|
|
|||
|
|
#pragma unroll 2
|
|||
|
|
for (int i = 0; i < items_per_thread; ++i) {
|
|||
|
|
int idx = base_idx + i * BLOCK_SIZE;
|
|||
|
|
if (idx < instance_size_div4) {
|
|||
|
|
// 优化 6: 使用 __ldg() 读取输入(如果对齐)
|
|||
|
|
float4 x_val = x4_ptr[idx];
|
|||
|
|
float4 y_val;
|
|||
|
|
|
|||
|
|
// 归一化: (x - m) / std
|
|||
|
|
// 注意: 不使用 volatile,因为统计量已在 Python 端计算
|
|||
|
|
float x_norm_x = (x_val.x - m) * inv_std;
|
|||
|
|
float x_norm_y = (x_val.y - m) * inv_std;
|
|||
|
|
float x_norm_z = (x_val.z - m) * inv_std;
|
|||
|
|
float x_norm_w = (x_val.w - m) * inv_std;
|
|||
|
|
|
|||
|
|
// 仿射变换: x_norm * g + b (使用 FMA)
|
|||
|
|
float y_affine_x = fmaf(x_norm_x, g, b);
|
|||
|
|
float y_affine_y = fmaf(x_norm_y, g, b);
|
|||
|
|
float y_affine_z = fmaf(x_norm_z, g, b);
|
|||
|
|
float y_affine_w = fmaf(x_norm_w, g, b);
|
|||
|
|
|
|||
|
|
// 非线性门控
|
|||
|
|
if (nonlinear) {
|
|||
|
|
// 优化 7: 向量化 sigmoid 计算
|
|||
|
|
float sigmoid_x = fast_sigmoid(x_val.x * v_val);
|
|||
|
|
float sigmoid_y = fast_sigmoid(x_val.y * v_val);
|
|||
|
|
float sigmoid_z = fast_sigmoid(x_val.z * v_val);
|
|||
|
|
float sigmoid_w = fast_sigmoid(x_val.w * v_val);
|
|||
|
|
|
|||
|
|
y_val.x = y_affine_x * sigmoid_x;
|
|||
|
|
y_val.y = y_affine_y * sigmoid_y;
|
|||
|
|
y_val.z = y_affine_z * sigmoid_z;
|
|||
|
|
y_val.w = y_affine_w * sigmoid_w;
|
|||
|
|
} else {
|
|||
|
|
y_val.x = y_affine_x;
|
|||
|
|
y_val.y = y_affine_y;
|
|||
|
|
y_val.z = y_affine_z;
|
|||
|
|
y_val.w = y_affine_w;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
y4_ptr[idx] = y_val;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ============================================================
|
|||
|
|
// C++ Wrapper
|
|||
|
|
// ============================================================
|
|||
|
|
torch::Tensor evonorm_forward_cuda(
|
|||
|
|
torch::Tensor input,
|
|||
|
|
torch::Tensor mean,
|
|||
|
|
torch::Tensor var,
|
|||
|
|
torch::Tensor gamma,
|
|||
|
|
torch::Tensor beta,
|
|||
|
|
torch::Tensor v,
|
|||
|
|
float eps,
|
|||
|
|
bool nonlinear,
|
|||
|
|
int N, int C, int H, int W
|
|||
|
|
) {
|
|||
|
|
input = input.contiguous();
|
|||
|
|
auto output = torch::empty_like(input);
|
|||
|
|
|
|||
|
|
const int BLOCK_SIZE = 256;
|
|||
|
|
dim3 blocks(N * C);
|
|||
|
|
dim3 threads(BLOCK_SIZE);
|
|||
|
|
|
|||
|
|
// 优化 8: 使用 CUDA stream(可选)
|
|||
|
|
evonorm_apply_kernel<<<blocks, threads>>>(
|
|||
|
|
input.data_ptr<float>(),
|
|||
|
|
mean.data_ptr<float>(),
|
|||
|
|
var.data_ptr<float>(),
|
|||
|
|
gamma.data_ptr<float>(),
|
|||
|
|
beta.data_ptr<float>(),
|
|||
|
|
nonlinear ? v.data_ptr<float>() : nullptr,
|
|||
|
|
output.data_ptr<float>(),
|
|||
|
|
eps,
|
|||
|
|
nonlinear,
|
|||
|
|
N, C, H, W
|
|||
|
|
);
|
|||
|
|
|
|||
|
|
return output;
|
|||
|
|
}
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
# 优化 9: 使用更激进的编译选项
|
|||
|
|
self.evonorm_op = load_inline(
|
|||
|
|
name="evonorm_cuda_optimized_v4",
|
|||
|
|
cpp_sources=cpp_source,
|
|||
|
|
cuda_sources=cuda_source,
|
|||
|
|
functions=["evonorm_forward_cuda"],
|
|||
|
|
extra_cuda_cflags=[
|
|||
|
|
"-O3",
|
|||
|
|
"--use_fast_math", # 启用快速数学(可能略微降低精度但提升性能)
|
|||
|
|
"-lineinfo" # 便于性能分析
|
|||
|
|
],
|
|||
|
|
verbose=False
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
def forward(self, x: torch.Tensor) -> torch.Tensor:
|
|||
|
|
if x.dtype != torch.float32 or not x.is_cuda:
|
|||
|
|
x = x.to("cuda", dtype=torch.float32)
|
|||
|
|
|
|||
|
|
N, C, H, W = x.size()
|
|||
|
|
|
|||
|
|
if self.use_b0:
|
|||
|
|
# EvoNorm-B0
|
|||
|
|
if self.training:
|
|||
|
|
mean = x.mean(dim=[2, 3], keepdim=True)
|
|||
|
|
var = x.var(dim=[2, 3], keepdim=True, unbiased=False)
|
|||
|
|
|
|||
|
|
with torch.no_grad():
|
|||
|
|
batch_var = var.mean(dim=0, keepdim=True)
|
|||
|
|
self.running_var = (1 - self.momentum) * self.running_var + self.momentum * batch_var
|
|||
|
|
else:
|
|||
|
|
mean = x.mean(dim=[2, 3], keepdim=True)
|
|||
|
|
var = self.running_var.expand(N, C, 1, 1)
|
|||
|
|
else:
|
|||
|
|
# EvoNorm-S0
|
|||
|
|
# 优化 10: 融合计算 E[x^2] 和 E[x] 可以考虑自定义 CUDA kernel
|
|||
|
|
x_sq_mean = torch.mean(x * x, dim=[2, 3], keepdim=True)
|
|||
|
|
x_mean = torch.mean(x, dim=[2, 3], keepdim=True)
|
|||
|
|
var = x_sq_mean - x_mean * x_mean
|
|||
|
|
mean = torch.zeros_like(x_mean)
|
|||
|
|
|
|||
|
|
gamma_view = self.gamma.data.view(C).contiguous()
|
|||
|
|
beta_view = self.beta.data.view(C).contiguous()
|
|||
|
|
|
|||
|
|
if self.nonlinear:
|
|||
|
|
v_view = self.v.data.view(C).contiguous()
|
|||
|
|
else:
|
|||
|
|
v_view = torch.zeros(C, device=x.device, dtype=torch.float32)
|
|||
|
|
|
|||
|
|
return self.evonorm_op.evonorm_forward_cuda(
|
|||
|
|
x.contiguous(),
|
|||
|
|
mean.contiguous().view(N, C),
|
|||
|
|
var.contiguous().view(N, C),
|
|||
|
|
gamma_view,
|
|||
|
|
beta_view,
|
|||
|
|
v_view,
|
|||
|
|
self.eps,
|
|||
|
|
self.nonlinear,
|
|||
|
|
N, C, H, W
|
|||
|
|
)
|