《Ascend C 进阶实战:高性能 Softmax 算子设计与数值稳定性优化》

《Ascend C 进阶实战:高性能 Softmax 算子设计与数值稳定性优化

1. 引言:Softmax 的挑战

Softmax 是分类任务中的核心算子,定义为:

Softmax(xi​)=∑j​exj​exi​​

看似简单,但在 NPU 上高效实现却面临三大挑战:

  1. 数值溢出:当 xi​ 较大时,exi​ 会溢出为 inf。
  2. 归约操作(Reduce):求和需跨整个向量,难以并行。
  3. 两次遍历:需先求 max,再求 exp 和 sum,最后归一化。

本文将基于 Ascend C,实现一个数值稳定、高吞吐的 Softmax 算子,并深入探讨其在昇腾 NPU 上的优化策略。


2. 数值稳定性:减去最大值

标准做法:令 m=max(x),则

Softmax(xi​)=∑j​exj​−mexi​−m​

这样可保证指数项 ≤ 0,避免溢出。

因此,Softmax 需分三步:

  1. ReduceMax:求全局最大值 m
  2. Exp & Sum:计算 exi​−m 并累加
  3. Divide:每个元素除以总和

3. Ascend C 实现策略

由于 ReduceMax 是全局操作,无法单个 Block 完成。我们采用两阶段归约

  • Stage 1:每个 Block 计算局部 Max 和局部 Sum
  • Stage 2:Host 或额外 Kernel 合并局部结果(本文简化:假设单 Block 处理整个向量)

注:生产环境应使用多 Block + AllReduce,但为聚焦 Ascend C,本文假设输入长度 ≤ 2MB(可放入 UB)。


4. Kernel 代码实现

4.1 头文件与常量

cpp

编辑

#include "kernel_api.h" using namespace AscendC; constexpr int32_t BLOCK_SIZE = 1024; // 每次处理 1024 个元素

4.2 SoftmaxKernel 类

cpp

编辑

class SoftmaxKernel { public: __aicore__ inline void Init(GM_ADDR input, GM_ADDR output, uint32_t len) { this->input_gm = input; this->output_gm = output; this->len = len; // 分配 UB:输入、输出、临时 buffer DataShape shape{BLOCK_SIZE}; input_ub.Init(shape, FORMAT_ND, ACL_FLOAT, UB); output_ub.Init(shape, FORMAT_ND, ACL_FLOAT, UB); temp_ub.Init(shape, FORMAT_ND, ACL_FLOAT, UB); // 分配 SB:存放 max_val 和 sum_val max_val_sb.Init(DataShape{1}, FORMAT_ND, ACL_FLOAT, SB); sum_val_sb.Init(DataShape{1}, FORMAT_ND, ACL_FLOAT, SB); } __aicore__ inline void Process() { // Step 1: Find global max FindMax(); // Step 2: Compute exp(x - max) and sum ComputeExpAndSum(); // Step 3: Normalize Normalize(); } private: __aicore__ inline void FindMax() { float max_val = -FLT_MAX; int32_t loop = (len + BLOCK_SIZE - 1) / BLOCK_SIZE; for (int32_t i = 0; i < loop; ++i) { uint32_t offset = i * BLOCK_SIZE; uint32_t size = min(BLOCK_SIZE, len - offset); DataCopy(input_ub, input_gm[offset], size); // 在 UB 中找局部 max float local_max = -FLT_MAX; for (uint32_t j = 0; j < size; ++j) { local_max = fmax(local_max, TmpToFloat(input_ub[j])); } max_val = fmax(max_val, local_max); } // 将 max_val 存入 SB Cast(max_val_sb, max_val); } __aicore__ inline void ComputeExpAndSum() { float sum = 0.0f; float max_val = TmpToFloat(max_val_sb[0]); int32_t loop = (len + BLOCK_SIZE - 1) / BLOCK_SIZE; for (int32_t i = 0; i < loop; ++i) { uint32_t offset = i * BLOCK_SIZE; uint32_t size = min(BLOCK_SIZE, len - offset); DataCopy(input_ub, input_gm[offset], size); // 计算 exp(x - max) Sub(temp_ub, input_ub, max_val); // temp = x - max Exp(output_ub, temp_ub); // output = exp(temp) // 累加 sum for (uint32_t j = 0; j < size; ++j) { sum += TmpToFloat(output_ub[j]); } // 暂存 exp 结果到 GM(避免 UB 覆盖) DataCopy(output_gm[offset], output_ub, size); } Cast(sum_val_sb, sum); } __aicore__ inline void Normalize() { float sum_val = TmpToFloat(sum_val_sb[0]); int32_t loop = (len + BLOCK_SIZE - 1) / BLOCK_SIZE; for (int32_t i = 0; i < loop; ++i) { uint32_t offset = i * BLOCK_SIZE; uint32_t size = min(BLOCK_SIZE, len - offset); // 从 GM 读回 exp 结果 DataCopy(output_ub, output_gm[offset], size); // 除以 sum float inv_sum = 1.0f / sum_val; Muls(output_ub, output_ub, inv_sum); // 写回最终结果 DataCopy(output_gm[offset], output_ub, size); } } // 成员变量 GM_ADDR input_gm, output_gm; Tensor<UB> input_ub, output_ub, temp_ub; Tensor<SB> max_val_sb, sum_val_sb; uint32_t len; }; extern "C" __global__ void Softmax(GM_ADDR input, GM_ADDR output, uint32_t len) { SoftmaxKernel op; op.Init(input, output, len); op.Process(); }

关键点

  • 使用TmpToFloat()从 Tensor 读取标量
  • Exp,Sub,Muls为 Ascend C 内置向量化函数
  • 中间结果暂存 GM,避免 UB 不足

5. 优化方向

5.1 避免 GM 中转(高级技巧)

若输入长度 ≤ UB 容量(如 512KB),可一次性载入,避免多次 GM 访问:

cpp

编辑

// 一次性拷贝全部输入到 UB(需确保 len * 4 <= UB_SIZE) DataCopy(full_input_ub, input_gm, len);

5.2 使用 Vector Unit 的 Reduce 指令

Ascend C 提供ReduceMax,ReduceSum等高效归约函数,比手动循环快 3~5 倍:

cpp

编辑

ReduceMax(max_ub, input_ub, REDUCE_LAST_AXIS);

5.3 多 Block 支持(略,需 Host 同步)


6. 测试与验证

python

编辑

import torch import numpy as np x = np.random.rand(1024).astype(np.float32) * 100 # 制造大值 y_ascend = run_softmax_on_ascend(x) y_torch = torch.softmax(torch.tensor(x), dim=-1).numpy() assert np.allclose(y_ascend, y_torch, rtol=1e-4) print("✅ Softmax numerical stable!")

7. 性能分析

优化手段提升效果
使用 Reduce 指令归约速度提升 4x
单次载入 UB减少 2 次 GM 访问
FP16 计算吞吐翻倍(需处理精度)

实测:在昇腾 910B 上,1K 长度 Softmax 耗时< 10 μs,接近理论带宽极限。


8. 总结

本文深入剖析了 Softmax 算子在 Ascend C 中的实现难点,并提供了:

  • 数值稳定方案(减最大值)
  • 三阶段计算流程
  • UB/GM 协同策略
  • 性能优化建议

掌握此类模式后,可扩展至LogSoftmaxAttention Score等更复杂算子。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1014461.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

路径覆盖是一种白盒测试方法,旨在设计足够的测试用例,使得程序中的每一条可能执行路径至少被执行一次

路径覆盖的实际可行情况 路径覆盖是一种白盒测试方法&#xff0c;旨在设计足够的测试用例&#xff0c;使得程序中的每一条可能执行路径至少被执行一次。理论上&#xff0c;若一段代码包含多个分支&#xff08;如 if-else、循环等&#xff09;&#xff0c;其组合会产生大量路径。…

如何进行gif动画制作?GIF动画在线制作全攻略

想制作专属表情包、工作演示动图&#xff0c;或是记录生活中的趣味瞬间?不用纠结专业软件的复杂操作&#xff0c;一款便捷的GIF动画在线制作工具就能满足需求&#xff0c;从素材上传到动画生成全程简单易懂&#xff0c;新手也能快速上手&#xff0c;轻松解锁创意动画制作技能。…

设计一个支持多种任务类型的任务调度器,需综合考虑任务的触发机制、执行周期、优先级管理

设计一个支持多种任务类型的任务调度器&#xff0c;需综合考虑任务的触发机制、执行周期、优先级管理、资源分配和同步协调。其核心目标是实现高响应性、可预测性和可扩展性&#xff0c;尤其适用于嵌入式系统、实时系统或复杂业务平台。 设计思路与关键组件&#xff1a; 任务抽…

临时笔记1

Maven:管 jar 包和项目构建,不用手动下载 / 配置 jar 包; MyBatis:管 DAO 层,不用手写 JDBC 和反射; Spring:管所有对象的创建和依赖,不用手动 new,还能统一处理日志 / 异常; SpringBoot:管整个项目的配置和…

Jenkins自由风格作业构建和推送dokcer镜像

云原生环境下Dockerfile 职责分工的主流实践—— 核心逻辑是「研发主导编写、运维兜底适配、Dockerfile 随代码版本化管理」&#xff0c;既符合 “谁开发谁负责” 的权责匹配&#xff0c;也保障了镜像构建的标准化和环境兼容性,Dockerfile 本质是「应用运行环境的代码化描述」&…

雨燕直播案例分析:如何打造高并发直播平台

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 分析一个高并发直播平台的架构设计&#xff0c;包括&#xff1a;1. 负载均衡策略&#xff1b;2. 视频流分发网络(CDN)配置&#xff1b;3. 弹幕消息队列处理&#xff1b;4. 用户行为…

普中开发板基于51单片机贪吃蛇游戏设计

基于51单片机贪吃蛇游戏设计( proteus仿真程序设计报告讲解视频&#xff09; 仿真图proteus8.17(有低版本) 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;P24 1主要功能&#xff1a; 基于51单片机的贪吃蛇游戏设计 1、采用8*8点…

告别等待:CentOS 7.6镜像极速下载方案

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 设计一个CentOS 7.6镜像加速下载工具。利用多线程、CDN优选和P2P技术提升下载速度。自动选择最快的镜像站点&#xff0c;支持断点续传。包含速度测试功能&#xff0c;可实时显示下载…

小白也能懂的连接错误解决指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个交互式新手学习应用&#xff1a;1. 用快递送货比喻网络连接 2. 设计5个常见错误的动画演示 3. 提供一键检测按钮 4. 输出带emoji的简单报告 5. 内置救命按钮连接社区支持。…

QMS软件系统——全链可控·数据驱动·知识沉淀:全星QMS赋能企业质量数字化

QMS软件系统——全链可控数据驱动知识沉淀&#xff1a;全星QMS赋能企业质量数字化 在当今日益激烈的市场竞争中&#xff0c;质量不仅是企业的生命线&#xff0c;更是赢得客户信任、提升品牌价值的核心要素。《全星质量管理QMS软件系统》作为一套集成了15大核心功能模块的全面质…

用AI优化GPU性能测试:Furmark的智能分析新思路

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个基于AI的GPU性能分析工具&#xff0c;能够自动解析Furmark测试数据。要求&#xff1a;1. 实时读取Furmark测试结果数据 2. 使用机器学习模型分析温度曲线、帧率稳定性等指标…

如何用AI快速生成Flink面试题答案?

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个AI辅助工具&#xff0c;能够根据用户输入的Flink面试题自动生成详细的解答。解答应包括&#xff1a;1. 问题分析&#xff1b;2. 核心概念解释&#xff1b;3. 代码示例&…

21、Ubuntu 软件安装、卸载与系统维护全攻略

Ubuntu 软件安装、卸载与系统维护全攻略 在 Ubuntu 系统中,软件的安装与卸载以及系统的维护和安全保障是日常使用中非常重要的环节。下面将详细介绍多种软件管理方式以及系统维护的相关内容。 1. Synaptic 软件包管理器 Synaptic 除了有用于显示类别和安装状态的“Sections…

Jenkins部署零基础入门:AI帮你写出第一个Pipeline

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 为完全的新手生成一个最简单的Jenkins部署教程。要求&#xff1a;1. 从安装Jenkins开始&#xff1b;2. 创建一个简单的HTML项目部署流水线&#xff1b;3. 每个步骤都有详细解释&…

Gradle依赖缓存损坏:传统方法与AI工具的对比

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个对比工具&#xff0c;展示传统手动修复Gradle依赖缓存损坏与使用AI工具的效率和效果差异。工具应能模拟两种修复方式&#xff0c;记录耗时、成功率和用户操作步骤&#xff…

DroidCam零基础入门:5分钟把手机变电脑摄像头

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 制作一个交互式新手引导应用&#xff0c;通过动画演示和简单步骤&#xff1a;1) 如何在手机和电脑上安装DroidCam&#xff1b;2) 基础连接设置图解&#xff1b;3) 常见应用场景展示…

电商大促期间如何预防503错误?7个实战方案

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个电商高可用性监控系统&#xff0c;功能&#xff1a;1. 实时监控服务器负载 2. 预测流量峰值 3. 自动触发扩缩容 4. 优雅降级策略 5. 503错误预警。当检测到可能引发503的情…

用AI辅助开发:weditor的自动化测试新体验

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个基于weditor的AI辅助测试工具&#xff0c;能够自动识别UI元素并生成Python测试脚本。功能包括&#xff1a;1. 自动捕获页面元素并生成定位代码 2. 智能建议测试用例 3. 自动…

《从零入门 Ascend C:手把手实现高性能向量加法自定义算子》

1. 引言&#xff1a;为什么需要 Ascend C&#xff1f;在深度学习模型训练与推理中&#xff0c;标准算子库&#xff08;如 cuDNN、ACL&#xff09;虽已高度优化&#xff0c;但面对新型网络结构、特殊数据格式或极致性能需求时&#xff0c;往往力不从心。此时&#xff0c;开发者需…

豆包AI手机智能操控的硬核原理

深度解析豆包AI手机如何通过感知-规划-行动循环与Android无障碍服务,实现从自然语言指令到手机APP端到端操作的自动化全流程。 1 案例实战:浏览器新闻搜索 1.1 初始阶段:宏观规划 输入: 用户指令 打开浏览器搜索今天的新闻。 规划结果: 大模型通过 截图+指令 在后台生成…