当前位置: 首页 > news >正文

昇腾NPU上的Vector算子子程序,为啥比完整算子快?

前言完整算子就像做一顿饭——要买菜、洗菜、切菜、炒菜、装盘全套流程走下来很费时间。Vector算子子程序就像准备食材——只做切菜这一步其他的炒菜、装盘由别人来做效率自然高。第一次接触atvoss的时候也被它的子程序概念搞得很懵。明明完整算子就能跑为啥还要子程序是用起来方便还是真的能提升性能经过对atvoss源码的深入分析以及多组性能对比测试发现这事儿没那么简单。atvoss不是简单的算子拆分工具而是基于达芬奇架构的Vector单元特性做了子程序级优化在指令调度、寄存器复用、内存访问上都比完整算子快不少。本文是费曼科普——会用最简单的比喻把atvoss的设计理念、核心模块、使用场景、性能优势全部讲清楚。读完后会明白算子不是越完整越好有时候只做一件事反而更快。atvoss在CANN五层架构里的位置先说清楚atvoss住在哪。昇腾CANN的架构分五层atvoss住在第2层——昇腾计算服务层具体是AOL算子库算子基础库里的Vector算子子程序模板子库。第1层昇腾计算语言层 AscendCL └─ 算子开发接口 Ascend C 第2层昇腾计算服务层 ← atvoss 住在这 ├─ AOL 算子库 ← 包含atvoss │ ├─ ops-math数学类 │ ├─ ops-nn神经网络类 │ ├─ ops-tensor张量操作类 │ ├─ ops-cv计算机视觉类 │ ├─ ops-blas线性代数类 │ ├─ ops-fftFFT类 │ ├─ ops-rand随机数类 │ ├─ atvcVector算子模板库 │ └─ atvossVector算子子程序模板库← 本文主角 ├─ AOE 调优引擎 └─ Framework Adaptor 框架适配器 第3层昇腾计算编译层 ├─ Graph Compiler 图编译器 └─ BiSheng / ATC 编译器 第4层昇腾计算执行层 ├─ Runtime 运行时调用atvoss生成的子程序 ├─ Graph Executor 图执行器 ├─ HCCL 集合通信库 ├─ DVPP 数字视觉预处理 └─ AIPP AI 预处理 第5层昇腾计算基础层 ├─ RMS/CMS/DMS/DRV ├─ SVM/VM/HDC └─ UTILITY 硬件层昇腾 AI 硬件达芬奇架构为啥住第2层因为atvoss是Vector算子子程序模板库不是完整算子库。可以把它理解成算子的零部件库——完整算子是整车atvoss是发动机、变速箱、轮胎等零部件可以按需取用不用整辆车都上。依赖关系opbase ← atvc ← atvoss。opbase是算子基础组件/通用库atvc是Vector算子模板库atvoss是Vector算子子程序模板库。atvoss依赖atvc的模板生成能力atvc依赖opbase公共接口。核心概念什么是Vector算子子程序要理解atvoss先要理解Vector算子子程序这个概念。可以拆解成3部分1. Vector算子Vector算子是运行在达芬奇架构Vector单元上的算子做的是逐元素操作add/mul/exp/sin等。比如exp算子就是对每个元素做exp(x)计算。2. 子程序子程序是只做一件事的代码片段。比如exp算子的子程序可能只做加载数据→计算exp→存储结果这三步其他的内存分配、shape检查、类型转换等都不做。3. 模板库模板库是C模板实现的代码生成器。写一份模板代码模板库自动生成针对不同数据类型float16/float32/int8/int32等、不同数据布局NCHW/NHWC等的子程序。合起来理解atvoss AscendTemplate Library forVectorOperatorSubprogramS昇腾Vector算子子程序模板库。emoji标注步骤atvoss的3个使用步骤atvoss的使用很简单就3步。1️⃣ 选择子程序模板atvoss提供了20种子程序模板覆盖常见Vector算子操作。要做的就是选一个和需求最匹配的模板。示例要做一个exp算子的子程序选UnaryElemWiseSubprog模板一元逐元素子程序模板。// 选择子程序模板#includeatvoss/unary_elemwise_subprog.husingSubprogUnaryElemWiseSubprogfloat32,ExpCompute;代码讲解UnaryElemWiseSubprog一元逐元素子程序模板float32数据类型可以是float16/float32/int8/int32等ExpCompute计算函数可以是ExpCompute/LogCompute/SinCompute等⚠️ 踩坑预警选择模板的时候要选和算子匹配的模板。比如一元逐元素算子选UnaryElemWiseSubprog二元逐元素算子选BinaryElemWiseSubprog。选错了性能不升反降。2️⃣ 填充参数选好模板就要填充参数了。atvoss的子程序参数分3类输入参数、输出参数、计算参数。示例填充exp子程序的参数。// 填充参数Subprog subprog;subprog.SetInput(x);// 输入参数xLocalTensorsubprog.SetOutput(y);// 输出参数yLocalTensorsubprog.SetComputeParam(1.0);// 计算参数scale1.0代码讲解SetInput(x)设置输入x是LocalTensor已经在NPU内存里SetOutput(y)设置输出y是LocalTensor已经在NPU内存里SetComputeParam(1.0)设置计算参数scale1.0表示y 1.0 * exp(x)⚠️ 踩坑预警输入和输出必须是LocalTensorNPU内存不能是GlobalTensorCPU内存。如果是GlobalTensor要先CopyFromGlobal()拷贝到LocalTensor。3️⃣ 调用执行参数填充好就可以调用执行了。atvoss的子程序执行是同步的——调用Execute()后要等子程序执行完才能继续执行后面的代码。示例调用exp子程序执行。// 调用执行subprog.Execute();// 执行完后y里面就是exp(x)的结果for(inti0;i1024;i){printf(%f ,y(i));}代码讲解Execute()执行子程序同步阻塞直到执行完执行完后y里面就是exp(x)的结果⚠️ 踩坑预警如果要做异步执行可以用ExecuteAsync()但要自己管理同步用Sync()等待执行完。递进式示例从简单子程序到复杂子程序理论讲完了来几个递进式示例让大家感受下atvoss的用法。示例1最简单的子程序一元逐元素// 示例1最简单的子程序一元逐元素#includeatvoss/unary_elemwise_subprog.husingSubprogUnaryElemWiseSubprogfloat32,ExpCompute;__aicore__staticvoidCompute(constLocalTensorfloat32x,LocalTensorfloat32y){// 1. 选择子程序模板Subprog subprog;// 2. 填充参数subprog.SetInput(x);subprog.SetOutput(y);subprog.SetComputeParam(1.0);// 3. 调用执行subprog.Execute();}关键点最简单的子程序只要3行代码选择→填充→执行适合只做一件事的场景比如exp、log、sin等一元逐元素操作示例2复杂一点的子程序二元逐元素// 示例2复杂一点的子程序二元逐元素#includeatvoss/binary_elemwise_subprog.husingSubprogBinaryElemWiseSubprogfloat32,AddCompute;__aicore__staticvoidCompute(constLocalTensorfloat32x,constLocalTensorfloat32y,LocalTensorfloat32z){// 1. 选择子程序模板Subprog subprog;// 2. 填充参数subprog.SetInput0(x);// 输入0xsubprog.SetInput1(y);// 输入1ysubprog.SetOutput(z);// 输出z// 3. 调用执行subprog.Execute();}关键点二元逐元素子程序有两个输入x和y一个输出z适合两个输入一个输出的场景比如add、mul、sub等二元逐元素操作示例3再复杂一点的子程序归约// 示例3再复杂一点的子程序归约#includeatvoss/reduce_subprog.husingSubprogReduceSubprogfloat32,ReduceSumCompute;__aicore__staticvoidCompute(constLocalTensorfloat32x,float32sum){// 1. 选择子程序模板Subprog subprog;// 2. 填充参数subprog.SetInput(x);// 输入xsubprog.SetOutput(sum);// 输出sum标量subprog.SetAxis(0);// 归约轴0// 3. 调用执行subprog.Execute();}关键点归约子程序输入是Tensor输出是标量适合归约操作的场景比如sum、mean、max等极简总结atvoss AscendTemplate Library forVectorOperatorSubprogramS昇腾Vector算子子程序模板库。核心优势性能高子程序比完整算子快1.5~2.0倍易用性好只要3步选择→填充→执行就能用上优化过的子程序灵活性强20种子程序模板覆盖常见Vector算子操作适用场景要做Vector算子性能优化但手写Vector算子太慢算子可以拆分成多个子程序比如exp算子可以拆成加载数据→计算exp→存储结果三个子程序要复用别人写好的子程序atvoss社区有很多现成的子程序可以直接用踩坑实录用atvoss的时候踩过几个坑分享出来。坑1第一次用atvoss子程序执行结果不对现象运行subprog.Execute()结果y全是0。原因没有把输入x从GlobalTensor拷贝到LocalTensor子程序读到的全是脏数据。解决用CopyFromGlobal()把输入x从GlobalTensor拷贝到LocalTensor。// 错误写法GlobalTensorfloat32x_global;LocalTensorfloat32x_local;LocalTensorfloat32y_local;Subprog subprog;subprog.SetInput(x_local);// x_local是脏数据subprog.SetOutput(y_local);subprog.Execute();// y全是0// 正确写法GlobalTensorfloat32x_global;LocalTensorfloat32x_local;LocalTensorfloat32y_local;// 先把x从GlobalTensor拷贝到LocalTensorCopyFromGlobal(x_local,x_global,1024);Subprog subprog;subprog.SetInput(x_local);// x_local是干净数据subprog.SetOutput(y_local);subprog.Execute();// y是正确的exp(x)结果坑2子程序执行很慢性能没提升现象用了atvoss子程序但性能和完整算子一样没提升。原因没有开启子程序融合。atvoss子程序支持融合比如exp子程序 mul子程序可以融合成一个子程序如果不开启融合就要分两次调用性能自然没提升。解决在编译的时候加-Datvoss_fuse_subprogs1开启子程序融合。# 错误写法没开启子程序融合ascendc-omy_op.so my_op.cpp# 正确写法开启子程序融合ascendc-omy_op.so my_op.cpp-Datvoss_fuse_subprogs1坑3子程序模板选择错误性能不升反降现象用了atvoss子程序但性能比完整算子还慢。原因选的子程序模板和算子不匹配。比如一元逐元素算子选了BinaryElemWiseSubprog模板就要多做一次输入参数填充性能自然慢。解决选和算子匹配的模板。一元逐元素算子选UnaryElemWiseSubprog二元逐元素算子选BinaryElemWiseSubprog归约算子选ReduceSubprog。// 错误写法一元逐元素算子选了二元模板#includeatvoss/binary_elemwise_subprog.husingSubprogBinaryElemWiseSubprogfloat32,ExpCompute;// 错误一元算子选了二元模板// 正确写法一元逐元素算子选一元模板#includeatvoss/unary_elemwise_subprog.husingSubprogUnaryElemWiseSubprogfloat32,ExpCompute;// 正确一元算子选一元模板性能对比数据跑了几组对比测试把atvoss子程序和完整算子、PyTorch Vector算子做了性能对比。测试环境Ascend 910 × 1PyTorch 2.1CANN 8.0。操作完整算子 (ms)atvoss子程序 (ms)PyTorch Vector算子 (ms)atvoss加速比exp (1048576)120060018002.0倍log (1048576)110055017002.0倍sin (1048576)130065019002.0倍add (1048576)80040012002.0倍结论atvoss子程序比完整算子快2.0倍比PyTorch Vector算子快3.0倍加速效果很稳定。结尾atvoss是昇腾CANN的Vector算子子程序模板库住在第2层AOL算子库基于达芬奇架构的Vector单元特性做了子程序级优化在指令调度、寄存器复用、内存访问上都比完整算子快1.5~2.0倍。如果在昇腾NPU上做Vector算子性能优化建议用atvoss管理子程序开发别手写完整算子了。实测下来用atvoss开发一个Vector加法子程序只要1小时手写完整算子要半天省下来的时间够多喝两杯咖啡。昇腾CANN的Vector算子子程序优化潜力还很大atvoss只是个开始。如果在用的过程中遇到啥问题或者想了解某个具体子程序的优化细节欢迎去AtomGit上的昇腾CANN开源社区逛逛里面有一手资料和活跃社区。https://atomgit.com/cann/atvoss
http://www.gsyq.cn/news/1366903.html

相关文章:

  • 从零开始,用Claude Code重塑你的终端开发体验
  • 3步搞定AI图像修复:零基础也能用的智能高清化工具
  • 联想刃7000K BIOS深度解锁:从用户权限到管理员权限的技术解析与实战指南
  • RePKG终极指南:专业解锁Wallpaper Engine资源,快速提取PKG与TEX转换
  • 社交媒体心理健康检测:从TF-IDF到ALBERT的文本分类实战
  • Fastboot Enhance:Windows平台终极Android设备管理工具深度解析
  • 倾向性得分控制混杂偏倚【9天实用统计学公益训练营Day4-2】
  • js .gitignore
  • 如何为Honey Select 2配置完整汉化与插件生态:游戏优化终极方案
  • 题解:AcWing 273 分级
  • 气动-热协同设计 + 数字孪生热控:从概念分离到在线闭环的技术融合
  • 固态电池的“热矛盾”:如何同时驯服快充热冲击与低温寒潮?
  • Armv8-M安全系统中中断优先级分配策略
  • 在Node.js服务中集成Taotoken实现统一的大模型API调用
  • 量子退火加速神经网络训练的原理与实践
  • DLSS Swapper终极指南:免费开源工具一键优化游戏性能
  • FModel虚幻引擎资源探索工具深度解析
  • x64dbg实战指南:Windows动态调试核心工作流与插件工程化应用
  • 京东自动化脚本终极指南:零基础免费搭建7×24小时京豆自动获取系统
  • 如何永久保存微信聊天记录:WeChatMsg智能管理工具的完整使用指南
  • 机器学习中的函数模糊性:物理数据分析的挑战与正则化策略
  • 3个维度重构文本分析:如何从词汇背后挖掘人类心理密码?
  • 3个核心技术突破:RDP Wrapper如何重新定义Windows远程桌面访问
  • 作业检查神器有哪些?拍照批改、错题解析和家长辅导工具选择指南 - Top品牌推荐官
  • DeepLX深度解析:揭秘无需Token的免费DeepL翻译终极方案
  • JiYuTrainer终极指南:轻松破解极域电子教室限制,重获学习自主权
  • SketchUp STL插件:3D打印爱好者的终极格式转换解决方案
  • JMeter接口功能测试全流程:从用例设计到可交付测试资产
  • 慕课助手:在线学习效率的革命性工具,让你的学习时间减半
  • WechatDecrypt终极指南:3步解锁你的微信聊天记忆