CANN AscendTransformerBoost ActivationOperation C++ Demo 实战:从环境搭建到 GELU / SwiGLU 算子调用

发布时间:2026/9/19 3:09:21
CANN AscendTransformerBoost ActivationOperation C++ Demo 实战:从环境搭建到 GELU / SwiGLU 算子调用 CANN AscendTransformerBoost ActivationOperation C Demo 实战从环境搭建到 GELU / SwiGLU 算子调用【免费下载链接】ascend-transformer-boost本项目是CANN提供的是一款高效、可靠的Transformer加速库基于华为Ascend AI处理器提供Transformer定制化场景的高性能融合算子。项目地址: https://gitcode.com/cann/ascend-transformer-boost本文围绕ascend-transformer-boost仓库中 example/op_demo/activation/README_en.md 对应的 ActivationOperation C 调用示例展开完整讲解如何配置 CANN 与 NNAL加速库运行环境、编译并执行 activation_demo.cpp并逐段剖析该 demo 中 GELUFasterGelu与 SwiGLU 正向两类激活算子的调用流程从设备初始化、Context/Stream 创建到输入 Tensor 准备、Setup/Execute执行、Workspace 管理及资源释放。读者读完本文后能够独立编写、编译并运行基于atb::infer::ActivationParam的激活算子推理示例并理解其背后的参数校验、Shape 推导与 Runner 分发机制。一、示例概览示例能做什么该示例位于 example/op_demo/activation/是一个纯 C 的加速库算子调用样例演示了ActivationOperation的两种典型用法演示函数激活类型参数设置输出 ShapeRunGeluDemoACTIVATION_FASTER_GELU_FORWARD无额外参数[16, 1024, 4096]与输入一致RunSwigluDemoACTIVATION_SWIGLU_FORWARDdim -1最后一维切分[16, 1024, 2048]最后一维减半两种算子共享同一个PrepareInTensor输入构造逻辑生成形状为[BATCH_SIZE, SEQ_LEN, HIDDEN_SIZE] [16, 1024, 4096]、数值范围在[-100, 100)的随机 float 数据并通过aclrtMemcpy以ACL_MEMCPY_HOST_TO_DEVICE方式拷贝到 Device 侧。其中 SwiGLU 的正向计算本质上是把输入张量在指定维度dim -1即最后一维一分为二得到a、b两个切片再计算sigmoid(a) * a * b因此输出最后一维为输入的一半——这也解释了为何 Swiglu 示例的输出 Shape 是[16, 1024, 2048]。该公式可以在 tests/apitest/opstest/python/operations/activation/test_activation.py 的TestSwigluForwardOperation.golden_calc中看到精确的对照实现x in_tensors[0] a, b x.chunk(2, dimself.SPLIT_DIM) # SPLIT_DIM -1 y torch.sigmoid(a) * a * b二、运行环境准备source 两个安装路径示例的运行依赖 CANN 工具链与 NNAL加速库两个软件包的环境变量使用前必须依次执行 source# 1. source CANN 安装路径下的 set_env.sh默认安装路径 source /usr/local/Ascend/ascend-toolkit/set_env.sh # 2. source NNAL加速库安装路径下的 set_env.sh source /usr/local/Ascend/nnal/atb/set_env.sh关于第二步README 特别给出了一个替代场景如果使用加速库源码自行编译则应改为 source 源码编译输出目录下的环境脚本# 从加速库源码编译后使用源码输出路径下的 set_env.sh source ./ascend-transformer-boost/output/atb/set_env.sh这一点对开发者非常实用仓库根目录 CMakeLists.txt 构建完成后产物会输出到output/atb目录其中包含了加速库的头文件、动态库以及set_env.sh环境脚本。也就是说开发者既可以选择安装官方发布的 NNAL 包也可以先本地编译再直接 source 源码产物两种方式都能让示例链接到atb头文件与库。三、编译与运行 Demo环境准备就绪后在示例目录下执行bash build.shREADME 中特别提示了 C ABI 的注意事项示例的编译必须与加速库发布包使用的cxx_abi保持一致否则链接期或运行期会出现符号不匹配问题。使用 cxx_abi0默认时需要设置D_GLIBCXX_USE_CXX11_ABI0g -D_GLIBCXX_USE_CXX11_ABI0 -I ...使用 cxx_abi1 时改为g -D_GLIBCXX_USE_CXX11_ABI1 -I ...说明_GLIBCXX_USE_CXX11_ABI是 GCC 新旧标准库 ABI 的切换宏。加速库预编译产物在特定 ABI 下生成调用方编译宏必须与之匹配这是所有基于该仓库的 C 示例包括 example/atb_aclnn、example/multiStream 等都要遵守的通用约束。-I ...部分需替换为实际的加速库头文件包含路径一般由set_env.sh导出的ASCEND_HOME_PATH等环境变量决定。程序运行成功后会在终端依次打印两行成功标志Gelu Activation demo success! Swiglu_forward Activation demo success!四、代码剖析激活算子的完整调用链路activation_demo.cpp 的主函数完整展示了加速库算子的标准使用范式共分为四步环境初始化 → 创建算子并准备参数包 → Setup/Execute → 释放资源。4.1 入口初始化 ACL、创建 Context 与 Streamint main(int argc, char **argv) { CHECK_STATUS(aclInit(nullptr)); int32_t deviceId 0; CHECK_STATUS(aclrtSetDevice(deviceId)); atb::Context *context nullptr; CHECK_STATUS(atb::CreateContext(context)); void *stream nullptr; CHECK_STATUS(aclrtCreateStream(stream)); context-SetExecuteStream(stream); RunGeluDemo(context, stream); RunSwigluDemo(context, stream); // 资源释放 CHECK_STATUS(aclrtDestroyStream(stream)); CHECK_STATUS(atb::DestroyContext(context)); // context全局资源后释放 CHECK_STATUS(aclFinalize()); return 0; }关键点aclInit(nullptr)初始化 ACL 运行时aclrtSetDevice(deviceId)指定使用 0 号卡atb::CreateContext(context)创建加速库上下文aclrtCreateStream创建 Stream并通过context-SetExecuteStream(stream)将执行流绑定到上下文释放顺序是先 Stream、再 Context、最后aclFinalize注释中明确说明 Context 属于全局资源必须后释放。这个后创建先释放、先创建后释放的原则与示例中 Operation 对象的释放时机见 4.4一起构成了完整的资源生命周期管理。4.2 创建激活算子GELU 与 SwiGLU 的参数设置atb::Status GeluOperation(atb::Operation **opPtr) { atb::infer::ActivationParam opParam; opParam.activationType atb::infer::ActivationType::ACTIVATION_FASTER_GELU_FORWARD; CHECK_STATUS(atb::CreateOperation(opParam, opPtr)); return atb::ErrorType::NO_ERROR; } atb::Status SwigluOperation(atb::Operation **opPtr) { atb::infer::ActivationParam opParam; opParam.activationType atb::infer::ActivationType::ACTIVATION_SWIGLU_FORWARD; opParam.dim -1; CHECK_STATUS(atb::CreateOperation(opParam, opPtr)); return atb::ErrorType::NO_ERROR; }两个算子的区别仅在于activationType与dim参数。atb::infer::ActivationParam定义在 include/atb/infer_op_params.h完整字段如下字段类型默认值含义activationTypeActivationTypeACTIVATION_UNDEFINED激活函数类型必填scalefloat1.0fSWISH 激活函数的缩放参数dimint32_t-1SWIGLU 激活函数的切分维度geluModeGeLUModeTANH_MODEGeLU 计算模式TANH_MODE0用 tanh 近似NONE_MODE1用原公式rsv[8]uint8_t{0}预留参数ActivationType枚举定义在同一文件infer_op_params.h支持的类型包括ACTIVATION_UNDEFINED 0 未定义 ACTIVATION_RELU 1 ReLU ACTIVATION_GELU 2 GELU ACTIVATION_FAST_GELU 3 快速 GELU近似计算速度快且保持较高精度 ACTIVATION_SWISH 4 Swish ACTIVATION_LOG 5 Log ACTIVATION_SWIGLU_FORWARD 6 SwiGLU 正向 ACTIVATION_SWIGLU_BACKWARD 7 SwiGLU 反向求梯度仅 Atlas 800I A2 推理产品支持 ACTIVATION_SIGMOID 8 Sigmoid ACTIVATION_FASTER_GELU_FORWARD 9 简化后的 FasterGelu计算速度更快 ACTIVATION_MAX 10 枚举最大值非激活类型README 对几个核心类型的语义有明确说明ACTIVATION_FAST_GELU对 Tensor 内每个元素做 GELU 近似计算速度更快且精度较高ACTIVATION_FASTER_GELU_FORWARD是进一步简化后的 FastGeluACTIVATION_SWIGLU_FORWARD在 Atlas 推理系列产品中只支持 32 位对齐的数据即最后一维须为 32 的倍数。4.3 输入 Tensor 准备与 VariantPack 组装PrepareInTensor展示了Host 生成数据 → 申请 Device 内存 → 拷贝的标准流程std::vectorfloat inTensorData(BATCH_SIZE * SEQ_LEN * HIDDEN_SIZE); std::random_device rd; std::mt19937 gen(rd()); std::uniform_real_distributionfloat dis(-100.0f, 100.0f); for (float val : inTensorData) { val dis(gen); } atb::Tensor inTensor; CreateTensor(ACL_FLOAT, aclFormat::ACL_FORMAT_ND, {BATCH_SIZE, SEQ_LEN, HIDDEN_SIZE}, inTensor); CHECK_STATUS(aclrtMemcpy(inTensor.deviceData, inTensor.dataSize, inTensorData.data(), sizeof(float) * inTensorData.size(), ACL_MEMCPY_HOST_TO_DEVICE));这里用到的CreateTensor辅助函数定义在 example/op_demo/demo_util.h它完成三件事填充atb::Tensor.descdtype/format/shape、调用atb::Utils::GetTensorSize计算数据字节数、用aclrtMalloc(..., ACL_MEM_MALLOC_HUGE_FIRST)申请 Device 内存。该头文件还提供了CastOp调用 Elewise 的ELEWISE_CAST做类型转换、TransdataOpND 与 FRACTAL_NZ 格式互转、CreateTensorFromVector等可复用的工具函数以及统一错误打印的CHECK_STATUS宏——宏会根据错误码范围100000~999999 为 ACL 错误码区分打印 ACL 还是 ATB 的查错文档指引。Tensor 准备完成后通过atb::VariantPack把输入输出 Tensor 打包交给算子atb::VariantPack geluVariantPack; CHECK_STATUS(PrepareInTensor(geluVariantPack.inTensors)); // 放入输入 tensor atb::Tensor tensorOut; CreateTensor(ACL_FLOAT, aclFormat::ACL_FORMAT_ND, {BATCH_SIZE, SEQ_LEN, HIDDEN_SIZE}, tensorOut); geluVariantPack.outTensors.push_back(tensorOut); // 放入输出 tensor注意 Swiglu 的输出 Shape 不同由于dim -1切分输出最后一维是HIDDEN_SIZE / 2 2048CreateTensor(ACL_FLOAT, aclFormat::ACL_FORMAT_ND, {BATCH_SIZE, SEQ_LEN, HIDDEN_SIZE / 2}, tensorOut);4.4 Setup 与 Execute两阶段执行模型与 Workspace加速库算子的执行采用经典的准备 执行两阶段模型这也是Operation接口的核心语义uint64_t geluWorkspaceSize 0; CHECK_STATUS(geluOp-Setup(geluVariantPack, geluWorkspaceSize, context)); // 阶段一准备 uint8_t *geluWorkspacePtr nullptr; if (geluWorkspaceSize 0) { CHECK_STATUS(aclrtMalloc((void **)(geluWorkspacePtr), geluWorkspaceSize, ACL_MEM_MALLOC_HUGE_FIRST)); } geluOp-Execute(geluVariantPack, geluWorkspacePtr, geluWorkspaceSize, context); // 阶段二执行 CHECK_STATUS(aclrtSynchronizeStream(stream)); // 流同步等待 device 侧任务计算完成Setup负责基于实际传入的 Tensor 描述做校验、Shape 推导、Tiling 等准备工作并通过输出参数返回算子所需的Workspace 大小调用方根据该大小申请 Workspace 内存后调用Execute真正下发计算任务Execute是异步的必须用aclrtSynchronizeStream(stream)做流同步否则后续立刻释放内存会破坏还在 Device 侧排队执行的任务。执行完成后示例按输入/输出 Tensor → Workspace → Operation 对象的顺序依次释放for (atb::Tensor inTensor : geluVariantPack.inTensors) { CHECK_STATUS(aclrtFree(inTensor.deviceData)); } for (atb::Tensor outTensor : geluVariantPack.outTensors) { CHECK_STATUS(aclrtFree(outTensor.deviceData)); } if (geluWorkspaceSize 0) { CHECK_STATUS(aclrtFree(geluWorkspacePtr)); } CHECK_STATUS(atb::DestroyOperation(geluOp)); // operation对象概念先释放五、源码级原理从 CreateOperation 到 RunnerDemo 中看似简单的atb::CreateOperation与Setup/Execute背后是 src/ops/ops_infer/activation/ 目录下一套完整的算子实现。理解这些源码能帮助开发者更好地掌握参数约束与平台差异。5.1 CreateOperation 的参数校验atb::CreateOperation(const infer::ActivationParam , Operation **)的模板特化实现在 activation_operation.cpp主要校验逻辑activationType必须落在(ACTIVATION_UNDEFINED, ACTIVATION_MAX)开区间内否则返回ERROR_INVALID_PARAMdim参数只允许为 -1对 SWIGLU 类算子会报 only support splitting dim -1对其他激活类型则报 does not support splitting dim——这解释了为何 demo 中 Swiglu 必须显式设置dim -1平台差异在ASCEND_950平台上仅支持 GELU、SWISH、SIGMOID、SWIGLU_FORWARD 四种类型且分别走GeluAclnnRunner、ActivationAclnnRunner、SwigluForwardAclnnRunner三条 aclnn 加载路径其他平台则统一创建ActivationOperation对象。5.2 Shape 推导SwiGLU 输出为何减半ActivationOperation::InferShapeImplactivation_operation.cpp体现了三种类型的 Shape 规则SWIGLU_FORWARD输出 Shape 与输入相同但splitDimdim为负时先加dimNum归一化上的尺寸除以 2SWIGLU_BACKWARD输出 Shape 直接取第二个输入x的 Shape即恢复为切分前尺寸用于梯度回传其他激活类型RELU/GELU/FASTER_GELU 等输出与输入 Shape 完全一致。同时SetupCheckImpl与CheckSwigluForwardInTensor还包含额外的约束校验Swiglu 反向算子要求两个输入维数一致且inTensor0y_grad在切分维上尺寸须为inTensor1x的一半Swiglu 正向算子在 310PAtlas 推理系列上要求输入最后一维hidden size为 32 的倍数源码中HIDDEN_SIZE_DIM_BASE 32与 README 中只支持 32 位对齐数据的说明相互印证dim的取值范围为[-dimNums, dimNums - 1]负值表示从最高维开始计数。5.3 Runner 分发与 Kernel 图构建ActivationOperation::CreateRunneractivation_operation.cpp按平台与类型分发 RunnerASCEND_950平台走各类 aclnn Runner其他平台走ActivationOpsRunner。而 activation_ops_runner.cpp 展示了ActivationOpsRunner如何把算子描述成一张单节点 Kernel 图节点数为 1opDesc由RunnerUtil::GetActivationNodeOpDesc(param_)生成并根据类型决定输入数量——普通激活 1 个输入SWIGLU_BACKWARD则按(y_grad, x)顺序挂接 2 个输入。从 Kernel 实现侧看仓库在 src/kernels/kernels/activation/ 下按算子类型分目录维护了对应的 Ascend 算子实现tiling 与 kernel 代码例如 demo 使用的 FasterGelu 对应 faster_gelu_forward/ 目录其中tiling/负责切分策略计算、kernel/负责 Device 侧向量计算。这与 demo 中Setup阶段返回 Workspace 大小、Execute阶段执行 Kernel 的流程一一对应。六、结果验证结合 Python 用例对照精度README 末尾的Remarks部分明确指出示例中生成的数据随机数不代表实际业务场景若需要了解真实的数据生成与精度校验方式请参考根目录下的 Python 用例tests/apitest/opstest/python/operations/activation/该目录下的 test_activation.py 基于operation_test.OperationTest框架为每种激活类型提供了golden_calc 参考实现可作为 C demo 输出正确性的对照标准测试类activationType输入构造golden 公式TestActivationOperation4SWISHtorch.rand(2, 3, 5)bfloat16x / (1 exp(-x * scale))TestSwigluForwardOperation6SWIGLU_FORWARD(8192, 1, 3904)float16a, b x.chunk(2, -1); sigmoid(a) * a * bTestSwigluBackwardOperation7SWIGLU_BACKWARDy_grad(8192, 1, 1952) x(8192, 1, 3904)float32分别计算b * y_grad * swiglu_grad(a)与y_grad * swiglu(a)后按 -1 维拼接TestFasterGeluForwardNd*9FASTER_GELU_FORWARD多种 Shape、fp16/fp32/bf16、数据范围 [-5, 5]get_golden_data(float_in_tensors)这些用例同时给出了多种可运行的输入 Shape 组合如[1, 1024]、[8, 5504]、[8192, 5504]、[1123, 4032]等并且用例会在特定 SoC如 Ascend910B / Ascend310B上做条件判断开发者可以把 C demo 的输出与 golden 结果对比验证算子精度。此外仓库 tests/high_level_test/ActivationOperation/ 下还有基于 CSV 的高层测试用例集可作为更多参数组合的参考。七、小结Demo 背后的通用范式通过对 activation_demo.cpp 的完整剖析可以提炼出加速库 C 调用的通用四步范式它同样适用于仓库 example/op_demo 下的其他算子示例如 rms_norm、rope、linear 等环境与资源source CANN/NNAL 的set_env.shaclInit→aclrtSetDevice→atb::CreateContext→aclrtCreateStream→SetExecuteStream算子与数据填充对应的atb::infer::*Param结构体 →atb::CreateOperation创建算子 → 构造输入输出 Tensor 并装入atb::VariantPack两阶段执行Setup获取 Workspace 大小 → 申请 Workspace →Execute下发任务 →aclrtSynchronizeStream同步资源释放先释放 Tensor 内存与 Workspace再DestroyOperation最后按Stream → Context → aclFinalize的顺序收尾。理解这套范式后读者可以在此基础上进一步探索 src/ops/ops_infer/activation/ 的算子实现细节参数校验、Shape 推导、Runner 分发或通过 tests/apitest/opstest/python/operations/activation/test_activation.py 的 golden 实现来校验自研调用的正确性。【免费下载链接】ascend-transformer-boost本项目是CANN提供的是一款高效、可靠的Transformer加速库基于华为Ascend AI处理器提供Transformer定制化场景的高性能融合算子。项目地址: https://gitcode.com/cann/ascend-transformer-boost创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询