Ascend C 算子:Sigmoid 函数原理深入解析与工程化构建及验证

前言

**声明:**本文所有内容均围绕Ascend C算子开发能力认证(中级)相关知识点进行考试心得分享,为保障考试的公平性,会对完整的流程、函数、逻辑、基础算法与代码进行说明,具体的合并组合方式需要理解后自行填充。

相关知识点是不会落下的,所以肯定会对您通过考试有些帮助,祝您考试顺利。

主页地址https://www.hiascend.com/edu/certification/detail/34bf904cb410497cb9c582be6c047ff7

通过证明,后面的文章我会细致的对所有用到的知识点进行说明。

目录

前言

一、考前准备与出题者目考察目的分析

1、领取考试券

2、考试环境搭建要求

3、考试题目说明

核心特性:为什么这个函数如此重要?

[核心用途:Sigmoid 到底解决什么问题?](#核心用途:Sigmoid 到底解决什么问题?)

4、考试说明

5、提交要求

二、具体代码分析与代码编写

[1、AclNNInvocation 项目说明](#1、AclNNInvocation 项目说明)

[2、SigmoidCustom 项目说明](#2、SigmoidCustom 项目说明)

3、理解代码:

查阅SigmoidCustom\op_host\sigmoid_custom_tiling.h文件

查阅SigmoidCustom\op_host\sigmoid_custom.cpp文件

查阅SigmoidCustom\op_kernel\sigmoid_custom.cpp文件

必要跳坑说明:

三、校验代码效果

1、服务器启动

2、编码修改

3、编译操作

4、校验操作

5、提交拿证

总结


一、考前准备与出题者目考察目的分析

从此开始进行逐一的分析总结,希望能对大家有所贡献。

1、领取考试券

https://www.hiascend.com/

进入后我们先进入到【用户个人中心】。

插条消息,社区内的徽章很多,可以时时的展示自己的价值,多来参与活动吧。

点击成长值超链接:

去领取代金券:

去领取:

点击领取:

领取成功提示:

点击【个人中心-我的券码】,并点击复制的图标按钮。

现在我们已经有了免费的券码了。

返回到中级页面,即可进行考试:

https://www.hiascend.com/edu/certification/exam/34bf904cb410497cb9c582be6c047ff7

能提交5次,我这里能看到我提交了2次通过的。

2、考试环境搭建要求

这里给的是环境的一个说明,我这里使用的是华为云-ModelArts-Notebook的部署方式处理的。

环境上要有昇腾NPU,且CANN版本为8.0.0.beta1。请开发者自行准备。

典型场景举例(若指导文档中CANN版本号与"8.0.0.beta1"不一致,请自行调整):

开发者套件(Atlas200I DK A2,或香橙派)部署方式

华为云-ModelArts-Notebook 部署方式

3、考试题目说明

这个不分是对具体的算子工程进行了算法说明,Ascend C算子Sigmoid,要求编写其对应位置的代码,最后完成算子调用的测试。

下图中可以看到【点击下载】对应的的项目,并且是tar.gz的,我们也就知道肯定不是是windows环境跑的了,鼠标右键复制一下下载链接备用,我这里已经给大家复制出来了,不过我看到的具体连接地址是【.zip】也就是说windows也能处理看看。

https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/AscendC/SigmoidCustom.zip

我们先来理解一下这个算法:

sigmoid(x) = 1/(1 + exp(-x))

我们先来看这个函数,Sigmoid 函数(也叫逻辑斯蒂函数,Logistic Function)是深度学习、机器学习中最基础也最核心的激活函数之一。

所以本次中级的考试认证使用Sigmoid 函数是非常恰当的。

完整的数学表达式:

其中 x 是输入(可以是任意实数),e 是自然常数(≈2.71828),输出值严格落在 \((0, 1)\) 区间内。

核心特性:为什么这个函数如此重要?

先从数学特性理解它的【设计巧思】:

值域压缩: 无论输入 x 是还是,输出都会被 "挤压" 到(0,1) 之间:

还有光滑可导、单调递增、中心对称都可以用这个函数来表达。

核心用途:Sigmoid 到底解决什么问题?

Sigmoid 的核心价值是将任意实数映射为概率 / 置信度,或实现【二分类决策】,主要应用在以下场景:

1、 二分类任务的输出层(最核心用途)机器学习中,二分类问题(比如:判断邮件是否为垃圾邮件、肿瘤是否为恶性、用户是否点击广告)需要输出 属于正类的概率,而概率的取值范围必须是[0,1]------Sigmoid 恰好能满足这一需求。

案例分析:

假设模型通过特征计算得到一个原始得分 x(比如 x=3),经过 Sigmoid 转换后:

这里公式不好拼,可以自己复制,自行拿去:

sigma(3)=1/(1+e^{-3}) \approx 1/(1+0.0498) \approx 0.9502

这表示该样本属于正类的概率为95.02%,通常设定阈值(如 0.5):

输出 > 0.5 → 判定为正类;

输出 < 0.5 → 判定为负类;

输出 = 0.5 → 需结合业务规则决策。

这就是具体的用法,至此我们应该能理解到出题的这位老师的良苦用心了。

4、考试说明

这里的4.1和4.2是对基础结构以及编译操作给了提示。

然后是4.3和4.4对过程有效性与最终运行效果的说明。

5、提交要求

最后一个要求是根据实际选择的服务器来修改对应的value值。

根据自己选的服务器来进行具体的修改,我这里用的是【Ascend910b】的,可以看到我已经对应的修改了。

二、具体代码分析与代码编写

为了减少服务器的使用时长,我们先进行本地的具体代码查阅与编辑,最后上传到服务器上再跑一下,看看是否能通过。

我们随便找个开发工具打开看看。

这基本就了解了,然后我们具体看看。

1、AclNNInvocation 项目说明

官方说明:AclNNInvocation是一个基于华为昇腾神经网络接口的算子测试和调用项目。该项目主要用于调用和验证自定义算子的功能正确性和计算精度。

确认是要校验我们代码是否正确的项目了,下面是对应的层级结构。

复制代码
AclNNInvocation/
├── inc/                    # 头文件目录
│   ├── common.h           # 通用工具函数声明
│   ├── op_runner.h        # 算子运行器类定义
│   └── operator_desc.h    # 算子描述结构体定义
├── src/                    # 源文件目录
│   ├── main.cpp           # 主程序入口
│   ├── op_runner.cpp      # 算子运行器实现
│   ├── operator_desc.cpp  # 算子描述实现
│   └── common.cpp         # 通用工具函数实现
├── scripts/                # 脚本目录
│   ├── acl.json           # ACL 配置文件(用于 dump 或 profiling)
│   ├── gen_data.py        # 生成测试数据和真值数据
│   └── verify_result.py   # 验证计算结果精度
├── input/                  # 输入数据目录
├── output/                 # 输出数据目录
└── run.sh                  # 主运行脚本

我查看了main.cpp 的代码,下面的对应的函数说明。

InitResource(): 初始化 ACL 环境,设置设备

CreateOpDesc(): 创建算子描述,定义输入输出张量的形状、数据类型和格式

SetInputData(): 从文件加载输入数据

RunOp(): 创建算子运行器并执行算子

ProcessOutputData(): 将计算结果保存到文件

2、SigmoidCustom 项目说明

官方说明:SigmoidCustom是一个基于华为昇腾AI 处理器的自定义算子开发项目。该项目实现了自定义的 Sigmoid 激活函数算子,包含完整的算子开发框架,支持在昇腾设备上高效执行,并可集成到 TensorFlow 等深度学习框架中使用。

既然说是自定义的,那么就代表这是我们要进行编译的项目,项目结构是:

复制代码
SigmoidCustom/
├── op_kernel/              # 算子内核实现(设备端代码)
│   ├── sigmoid_custom.cpp  # Sigmoid 算子的核心计算实现(AscendC)
│   └── CMakeLists.txt      # 内核编译配置
├── op_host/                # 算子主机端代码
│   ├── sigmoid_custom.cpp  # 算子注册、形状推理、数据类型推理、Tiling 函数
│   ├── sigmoid_custom_tiling.h  # Tiling 数据结构定义
│   └── CMakeLists.txt      # 主机端编译配置
├── framework/              # 框架集成代码
│   └── tf_plugin/          # TensorFlow 插件
│       ├── tensorflow_sigmoid_custom_plugin.cc  # TensorFlow 算子注册
│       └── CMakeLists.txt
├── cmake/                  # CMake 构建脚本和工具
│   ├── config.cmake        # 构建配置
│   ├── func.cmake          # 构建函数
│   ├── intf.cmake          # 接口定义
│   ├── makeself.cmake      # 打包配置
│   └── util/               # 构建工具脚本(Python)
├── scripts/                # 安装和升级脚本
│   ├── install.sh          # 算子安装脚本
│   ├── upgrade.sh          # 算子升级脚本
│   └── help.info           # 帮助信息
├── CMakeLists.txt          # 主构建文件
├── CMakePresets.json       # CMake 预设配置
└── build.sh                # 构建脚本

我们要对op_kernel下的sigmoid_custom.cpp与op_host下的sigmoid_custom.cpp和sigmoid_custom_tiling.h进行编码。

这里我们还需要修改CMakePresets.json文件中的配置,这里直接改修行了,后面我就不再重复。

配置文件改完后,对应的代码中也需要匹配。

3、理解代码:

查阅SigmoidCustom\op_host\sigmoid_custom_tiling.h文件

这里我先给个流程:

默认的代码情况,给出的是让考生自行定义tiling结构体成员变量。

我们需要定义 Tiling 数据结构 的两个成员变量,用于在昇腾设备上进行数据分块(Tiling)计算。

cpp 复制代码
// 数据总长度(元素总数)
TILING_DATA_FIELD_DEF(uint32_t, totalLength);
// 分块数量(将数据分成多少块处理)
TILING_DATA_FIELD_DEF(uint32_t, tileNum);

totalLength: 输入张量的总元素数(例如:[8, 2048] = 16384)

tileNum: 数据分块数量,通常等于 BLOCK_DIM(8 个 AI Core)

作用: 优化大规模数据的并行计算,将数据分成多个块由不同的 AI Core 并行处理。

查阅SigmoidCustom\op_host\sigmoid_custom.cpp文件

太长了,我就弄成GIF的了。

那么对应的代码理论上您应该已经可以搞出来了。

1、计算输入张量的总元素数量(Total Length)

// GetInputShape(0): 获取第 0 个输入的形状信息。

// GetOriginShape(): 获取原始形状(不考虑动态形状)。

// GetShapeSize(): 计算形状的总元素数量(例如 [8, 2048] = 16384)。

我们这里定义一个context。

cpp 复制代码
uint32_t totalLength = context->GetInputShape(0)->GetOriginShape().GetShapeSize();

2、设置块维度到上下文,告诉框架使用多少个 AI Core 进行并行计算

根据const uint32_t BLOCK_DIM = 8;指定的AI Core 进行具体计算。

cpp 复制代码
context->SetBlockDim(BLOCK_DIM);

3、设置 Tiling 数据中的总长度字段

这个值会被传递到设备端内核代码,用于计算每个分块的大小和位置。

cpp 复制代码
tiling.set_totalLength(totalLength);

4、设置 Tiling 数据中的分块数量字段

这个值会被传递到设备端内核代码,用于确定循环次数(loopCount)。

cpp 复制代码
tiling.set_tileNum(TILE_NUM);

5、将 Tiling 数据保存到缓冲区中

GetRawTilingData()->GetData(): 获取原始 Tiling 数据的缓冲区指针。

GetRawTilingData()->GetCapacity(): 获取缓冲区的容量大小。

SaveToBuffer(): 将 tiling 结构体的数据序列化到缓冲区,供设备端内核读取。

cpp 复制代码
tiling.SaveToBuffer(context->GetRawTilingData()->GetData(), 
context->GetRawTilingData()->GetCapacity());

6、设置实际使用的 Tiling 数据大小

GetDataSize(): 获取序列化后的 Tiling 数据实际大小。

SetDataSize(): 告诉框架实际使用了多少字节的 Tiling 数据。

这个大小会被传递给设备端,用于正确读取 Tiling 数据。

cpp 复制代码
context->GetRawTilingData()->SetDataSize(tiling.GetDataSize());

7、获取工作空间(Workspace)大小数组的指针

GetWorkspaceSizes(1): 申请 1 个工作空间大小配置项。

Workspace 是算子执行时需要的临时内存空间,用于存储中间计算结果。

cpp 复制代码
size_t *currentWorkspace = context->GetWorkspaceSizes(1);

8、设置工作空间大小

设置工作空间大小为 0,表示 Sigmoid 算子不需要额外的临时内存空间。

Sigmoid 是逐元素计算,可以直接将结果写入输出,不需要中间缓冲区。

cpp 复制代码
currentWorkspace[0] = 0;

9、返回成功状态,表示 Tiling 计算完成

GRAPH_SUCCESS 表示图编译成功,可以继续后续的编译和执行流程。

cpp 复制代码
return ge::GRAPH_SUCCESS;

查阅SigmoidCustom\op_kernel\sigmoid_custom.cpp文件

就这个文件需要补充的多,但是逻辑上我们是清楚的,就是具体搞算法的过程呗。

具体的写之前我们再回顾一下整个关键主键:

应用层: AclNNInvocation 项目,用于测试和调用自定义算子。

框架层: TensorFlow 插件和 GE 图引擎,负责算子注册和图形化执行。

算子层: 算子定义、形状推理、Tiling 计算等主机端逻辑。

运行时层: ACL 运行时和调度器,负责任务调度和资源管理。

设备层: 内核代码和 AI Core,执行实际的计算任务。

注:块维度不能为零!分块数量不能为零!

函数理解:

cpp 复制代码
sigmoid_custom.cpp
├─ 1. 头文件和常量定义
├─ 2. KernelSigmoid 类
│  ├─ Init() 函数:准备工作
│  ├─ Process() 函数:执行计算
│  ├─ CopyIn() 函数:复制输入数据
│  ├─ Compute() 函数:执行 Sigmoid 计算
│  └─ CopyOut() 函数:复制输出数据
└─ 3. 内核入口函数

整体逻辑:

第一步:理解整体结构

Init() → Process() → CopyIn/Compute/CopyOut

第二步:理解数据分块

totalLength → blockLength → tileLength

第三步:理解内存操作

全局内存 ↔ 本地缓冲区

第四步:理解计算过程

Sigmoid 的数学公式和代码实现

第五步:理解优化机制

双缓冲、并行化、流水线

cpp 复制代码
//最终的处理 
op.Init(x, y, tiling_data.totalLength, tiling_data.tileNum);
op.Process();

必要跳坑说明:

我们在处理最后的除法时要使用的是【AscendC::Div】函数,这点非常的重要,不要想着直接使用反转函数就行,那是完全不行的,是个大坑,要直接跳过去,我尝试了下面是错误的效果。

逻辑和坑都说明白了,自己需要重补一下代码哦。

三、校验代码效果

这里需要先启动服务器,然后再进行基础环境搭建,编译完成后最后去校验即可。

1、服务器启动

我使用的是华为云的ModelArts的Notebook来操作的,这里要注意只有贵阳一有哦。

选完启动即可,启动时间长一点。

创建个【Terminal】运行各类命令。

在根目录进行操作即可。

通过下面的命令直接下载到服务器上即可。

wget https://obs-9be7.obs.cn-east-2.myhuaweicloud.com/AscendC/SigmoidCustom.zip

下载完毕后使用下面命令解压即可。

unzip SigmoidCustom.zip

我们已经修改了对应的代码,把已经修改过的代码进行替换掉服务器上的文件即可。

我们环境是ascend910b的,所以处理一下,再次重申哦。

改完效果:

2、编码修改

SigmoidCustom\op_host\sigmoid_custom_tiling.h

SigmoidCustom\op_host\sigmoid_custom.cpp

SigmoidCustom\op_kernel\sigmoid_custom.cpp

代码都需要自己补充,我的逻辑给的很清晰了。

完成后我们就要去编译工作了。

3、编译操作

编译之前一定要运行一下,给予对应的运行权限。

给权限的目录是:

SigmoidCustom/SigmoidCustom/build_out

给权限的命令:

chmod +x -R *

4、校验操作

在SigmoidCustom/AclNNInvocation文件夹下校验,校验命令。

bash run.sh

我们把文件夹压缩一下提交即可。

zip -r SigmoidCustom.zip SigmoidCustom

5、提交拿证

提交通过会给提示,我们可以看到。

第二天拿证:

总结

本文分享了AscendC算子开发能力认证(中级)考试的经验心得。考试围绕Sigmoid算子开发展开,详细介绍了考前准备、考试环境搭建、题目分析和代码编写过程。

重点解析了Sigmoid函数的数学特性、核心用途以及具体实现方法,包括Tiling数据结构定义、主机端和设备端代码编写要点。文章还提供了编译运行和验证的具体步骤,并提醒注意使用AscendC::Div函数等关键细节。

最后说明了提交方式和证书获取流程,为考生顺利通过认证提供了实用指导,希望能为大家提供到帮助。

相关推荐
OTWOL2 小时前
C语言操作符终极揭秘:表达式求值秘籍
c语言·开发语言·c++
无巧不成书02182 小时前
Java 21 LTS 高级特性零基础通关:静态导入、项目目录规范、泛型全实战
java·开发语言·标准目录结构·泛型原理·类型安全实现
code monkey.2 小时前
【寻找Linux的奥秘】Linux 基础 IO 全解析:从 C 库到内核,吃透文件操作的底层逻辑
linux·c语言·基础io
Ancelin安心2 小时前
西工大noj(C/C++)100题参考题解及注意事项(2024)
c语言·c++·ide·windows·vscode·算法
独特的螺狮粉2 小时前
开源鸿蒙跨平台Flutter开发:家庭传统节日记录应用
flutter·华为·开源·harmonyos
张np2 小时前
java框架和http调用接口的区别
java·开发语言·http
Fate_I_C2 小时前
uniappx 鸿蒙运行包制作失败
华为·uni-app·uniapp·harmonyos
李日灐2 小时前
【优选算法3】二分查找经典算法面试题
开发语言·c++·后端·算法·面试·二分查找·双指针
zzwq.2 小时前
PyMySQL 详解:从入门到实战,Python 操作 MySQL 一站式指南
开发语言·python