LeetGPU习题01:Sigmoid手动实现
813 字
4 分钟
LeetGPU习题01:Sigmoid手动实现
Sigmoid 函数的实现
知识讲解
Sigmoid 函数定义为 ,它将任意实数压缩至 区间。 其导数为 ,在 处取得最大值 ,向两侧迅速衰减至 。

数学特性:
- 单调递增,光滑可导
- 饱和区: 时梯度趋近于 ,导致梯度消失
- 中心对称:,满足
深度学习应用:
- 分类输出层:将网络输出转化为正类概率 ,配合交叉熵损失实现稳定训练。
- 旧式隐藏层激活:早期全连接网络常用,但因饱和区梯度消失,已被 ReLU 系列取代。
题目描述
难度:简单 任务:编写一个GPU程序,对一个32位浮点数向量逐元素应用Sigmoid激活函数。 对于输入向量中的每一个元素,计算
并将结果存储到输出向量当中,Sigmoid函数将任意实数映射至区间内。
实现要求:
- 仅允许C/CUDA runtime库
- 最终结果存储在Y当中
示例输入/输出
请自行测试:
示例1:
输入 X = [0.0, 1.0, -1.0, 2.0]输出 Y = [0.5, 0.7311, 0.2689, 0.8808]示例2:
输入 X = [0.5, -0.5, 3.0, -3.0]输出 Y = [0.6225, 0.3775, 0.9526, 0.0474]模板代码
CUDA版
你只需要填写sigmoid_kernel。
#include <stdio.h>#include <cuda_runtime.h>#include <math.h>
// ========== 请在此处实现 sigmoid_kernel ==========__global__ void sigmoid_kernel(float* x, float* y, int N) { // TODO: 计算全局索引,确保不越界,计算 sigmoid // 提示: 使用 expf 进行指数运算
}// =================================================
int main() { // 典型测试值 float typical_vals[] = {-10.0f, -5.0f, -2.0f, -1.0f, -0.5f, 0.0f, 0.5f, 1.0f, 2.0f, 5.0f, 10.0f}; int num_typical = sizeof(typical_vals) / sizeof(float);
int repeat = 100000; // 每个典型值重复次数 int N = num_typical * repeat; size_t bytes = N * sizeof(float);
// 主机内存分配与初始化 float* hx = (float*)malloc(bytes); float* hy = (float*)malloc(bytes); for (int r = 0; r < repeat; r++) { for (int i = 0; i < num_typical; i++) { hx[r * num_typical + i] = typical_vals[i]; } }
// 设备内存分配与数据拷贝 float *dx, *dy; cudaMalloc(&dx, bytes); cudaMalloc(&dy, bytes); cudaMemcpy(dx, hx, bytes, cudaMemcpyHostToDevice);
// 配置内核启动参数 int threads_per_block = 256; int blocks_per_grid = (N + threads_per_block - 1) / threads_per_block;
// 启动内核 sigmoid_kernel<<<blocks_per_grid, threads_per_block>>>(dx, dy, N); cudaDeviceSynchronize(); // 等待内核完成
// 结果拷贝回主机 cudaMemcpy(hy, dy, bytes, cudaMemcpyDeviceToHost); printf(" x -> sigmoid(x)\n"); printf("-----------------------\n"); for (int i = 0; i < num_typical; i++) { printf("%6.2f -> %8.6f\n", hx[i], hy[i]); }
// 释放内存 free(hx); free(hy); cudaFree(dx); cudaFree(dy); cudaDeviceReset(); return 0;}Triton版
import torchimport tritonimport triton.language as tl
# ========== 请在此处实现 sigmoid_kernel ==========@triton.jitdef sigmoid_kernel(x_ptr, y_ptr, N, BLOCK_SIZE: tl.constexpr): # TODO: 获取当前程序的起始索引 pass
def solve(X): N = X.numel() Y = torch.empty_like(X)
# 配置 block 大小和 grid 大小 BLOCK_SIZE = 256 grid = (triton.cdiv(N, BLOCK_SIZE),)
sigmoid_kernel[grid](X, Y, N, BLOCK_SIZE=BLOCK_SIZE) return Y
def main(): # 典型测试值 typical_vals = torch.tensor([-10.0, -5.0, -2.0, -1.0, -0.5, 0.0, 0.5, 1.0, 2.0, 5.0, 10.0], dtype=torch.float32) num_typical = typical_vals.numel() repeat = 100000 N = num_typical * repeat
hx = typical_vals.repeat(repeat).cuda()
# 调用 solve hy = solve(hx)
# 打印结果 print(" x -> sigmoid(x)") print("-----------------------") for i in range(num_typical): print(f"{hx[i]:6.2f} -> {hy[i]:8.6f}")
if __name__ == "__main__": main()Pytorch版
import torch
# ========== 请在此处实现 sigmoid 函数 ==========def sigmoid(x): # 手动实现 sigmoid 函数 return torch.sigmoid(x)
def solve(X): return sigmoid(X)
def main(): # 典型测试值 typical_vals = torch.tensor([-10.0, -5.0, -2.0, -1.0, -0.5, 0.0, 0.5, 1.0, 2.0, 5.0, 10.0], dtype=torch.float32) num_typical = typical_vals.numel() repeat = 100000 N = num_typical * repeat
hx = typical_vals.repeat(repeat).cuda()
hy = solve(hx)
print(" x -> sigmoid(x)") print("-----------------------") for i in range(num_typical): print(f"{hx[i]:6.2f} -> {hy[i]:8.6f}")
if __name__ == "__main__": main()支持与分享
如果这篇文章对你有帮助,欢迎分享给更多人或赞助支持!
LeetGPU习题01:Sigmoid手动实现
https://dlog.com.cn/posts/leetgpu01/sigmoid/ 相关文章 智能推荐
1
Fresh现代编辑器
工具 或许你是时候该换一款更加现代的编辑器了
2
CUDA学习之路[4]——CUDA全局坐标计算
CUDA学习之路 从一维到三维,彻底理清CUDA线程索引的映射逻辑。
3
CUDA学习之路[3]——GPU并行本质 | 硬件架构 × 编程模型
CUDA学习之路 深入拆解 GPU 硬件架构本源,厘清 CUDA 全栈体系,搞懂并行计算的核心范式与 GPU 的适配边界,为高性能 CUDA 开发打下底层基础
4
CUDA学习之路[2]——你需要哪些C/C++的知识呢?
CUDA学习之路 你学Java/Python忽视的知识点,反而是在CUDA编程中最需要的。
5
CUDA学习之路[1]——速通环境配置
CUDA学习之路 如果说深度学习是星辰大海,那环境配置就是暗礁浅滩。我不允许你永远在入门!
随机文章 随机推荐