恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
NPU与TPU架构解析:从脉动阵列到模型迁移实战
首页
资讯中心
/
NPU与TPU架构解析:从脉动阵列到模型迁移实战
NPU与TPU架构解析:从脉动阵列到模型迁移实战
发布时间:2026/10/15 20:31:44
1. 为什么CPU和GPU不够用1.1 从通用计算到专用加速NPU/TPU出现的底层逻辑做深度学习系统的人大概都逃不开一个尴尬场景模型结构还没调明白手里的计算资源却先扛不住了。CPU跑一次训练迭代要几分钟GPU倒是快不少但显存动不动就爆功耗和成本也跟着往上蹿。等到真正部署到生产环境面对一路飙升的推理延迟问题就变得非常具体到底怎么让模型跑得更快、更省、更稳NPU和TPU这类专用AI加速硬件就是冲着这个矛盾来的。NPU的全称是神经网络处理器TPU则是张量处理单元。它们的核心思路其实特别朴素既然深度学习里最有价值、最消耗时间的操作就是矩阵乘法和卷积那为什么不干脆造一块专门做这些事情的芯片这种把特定计算模式固化到硬件里的思路在计算机体系结构里叫ASIC也就是专用集成电路。专用意味着放弃通用性换回来的是同功耗下好几倍的计算密度和能效比。我见过不少同学第一次拿到NPU开发板或者云上的加速实例时第一反应是兴奋第二反应是茫然。兴奋是因为跑起模型来确实快茫然是因为整套流程和平时用GPU完全不是一回事。这也正是我想写这一章的原因NPU/TPU不是简单的“换了块更快显卡”它的编程模型、计算范式、性能瓶颈都有一套独立的逻辑。理解这套逻辑才能真正把这代硬件用明白。1.2 深度学习计算的三大特征决定了硬件方向为什么CPU和GPU在AI负载上显得不顺手归根到底是因为深度学习的计算特征太特殊跟通用程序的负载模型差别太大。我简单梳理一下你会发现专用加速器的每一个设计选择几乎都能在这三个特征里找到根源。第一个特征是计算极度规律。无论是卷积还是Transformer里的自注意力本质上都是由密集矩阵乘法和元素级操作组成的。这类运算的数据访问模式是可以预先准确预测的不需要分支预测、乱序执行那一套复杂的通用处理器机制只需设计一个极简的计算阵列反复执行乘加操作就行。第二个特征是数据量极大但单次操作简单。一个ResNet50模型推理大概需要几亿次乘加运算。单次乘加本身并不复杂麻烦的是给计算单元喂数据。所以硬件设计的重心从来不是“怎么算”而是“怎么高效地把数据搬到计算单元里”。这里就引出了存储层级、片上缓存、数据流调度这些概念NPU/TPU设计中的各种花哨技巧八成以上都在解决数据搬运问题。第三个特征是精度容忍度高。神经网络参数和中间激活值不需要像数据库系统那样精确到每一个比特。从早期的FP32到现在的FP16、BF16再到现在越来越常见的INT8甚至更低精度精度每降一档计算速度和能效往往能翻一倍以上。专用加速器直接在硬件层面支持低精度计算这也是GPU通用计算短期内追不上的关键差距。看完这三个特征就能理解AI加速本质上是一个“在特定精度下、以尽可能低的数据搬移成本、完成大规模规律计算”的问题。NPU和TPU的一切设计都是围绕这个目标在展开。2. NPU与TPU的架构内核2.1 脉动阵列让数据自己动起来讲到NPU/TPU的架构第一个绕不开的概念就是脉动阵列。我第一次理解这个概念时觉得它特别像儿时玩过的一种流水线游戏一排人站在传送带旁边每个人只处理经过自己面前的那一件东西然后传给下一个人。脉动阵列的原理与之高度类似。传统的CPU或者GPU计算矩阵乘法时每个计算单元需要自己从内存里把操作数取进来而脉动阵列则不同成百上千个计算单元排成一个二维阵列数据像脉搏一样在单元之间规律地流动每个单元只需要从相邻单元接收数据做一次乘加再把结果传给下一个单元。这样一来数据从内存里被读取的次数大大减少绝大部分数据复用发生在阵列内部的寄存器层面功耗和延迟都会显著下降。很多人在看这块芯片的规格参数时会盯着每秒多少万亿次运算的峰值算力看但真正决定实际性能的往往是这个脉动阵列结构能不能和你的矩阵尺寸匹配上。举个例子某个加速器的脉动阵列是128乘128的你输入一个256乘256的矩阵乘法硬件可能会把它切成四块分时处理如果你的矩阵尺寸是127乘127这种不规整的数字大量计算单元就会空转实际吞吐可能只有峰值的一半。这也是为什么很多推理框架会要求输入数据的长宽是8、16甚至32的整数倍——不是矫情是在适配底层的脉动阵列。2.2 存储优先设计算得快不如搬得快你看NPU和TPU的芯片照片一定会发现一个规律计算单元只占芯片面积的一小部分剩下大片区域全部是SRAM缓存和片上互联。这个设计取向很有意思。对通用处理器来说缓存只是辅助但对专用AI加速器来说片上存储就是整个性能模型的核心。我做一个不太严谨但很好理解的计算。假设某个加速器峰值算力是200TOPS也就是每秒钟要执行200万亿次操作数据精度按INT8算。这意味着每秒钟至少要有200TB的数据从存储流向计算单元。哪怕是目前最先进的HBM高带宽内存带宽也就在几个TB每秒量级远跟不上这个需求。唯一的解法就是把尽量多的数据放到离计算单元最近的SRAM里让数据在片上反复复用减少对片外内存的依赖。这就解释了为什么NPU的编译器那么在乎“数据布局”。同样一个张量是按NCHW还是NHWC排列在GPU上可能只是几分之一的性能差异但在NPU上可能就是倍数的差距。因为布局直接决定了数据能不能连续地从SRAM流进脉动阵列。做部署优化时我建议你先去查一下硬件的手册看看它原生支持哪种布局然后让模型往那个布局上靠这比后期硬调算子高效得多。2.3 精度战争FP16、BF16和INT8的选择背后专用加速器的另一个杀手锏是在硬件层面把低精度计算的能力做到了极致。这里很多人有个误区觉得低精度就是把小数点后的位数砍掉是个简单的取舍问题。真实情况远比这复杂因为不同的低精度格式有不同的数值分布特性选错了格式跑起来精度掉得莫名其妙还找不到原因。FP16是IEEE标准的半精度浮点用1位符号、5位指数、10位尾数表示。它的优点是动态范围不错缺点是数值精度低训练时容易出现梯度下溢。BF16则完全不同它用8位指数和7位尾数动态范围和FP32几乎一致但精度更差。它的好处是可以稳定地用在训练场景里因为梯度的数量级不太容易跑飞这是我实际踩过坑后感受很深的点。INT8则是另一个维度的事情。整数计算速度最快但需要做量化也就是把浮点范围内的数值映射到-128到127之间。这里面有对称量化和非对称量化之分还有per-tensor和per-channel两种粒度的区别。做PTQ训练后量化时如果校准数据集选得不好某个通道的数值范围估计偏差过大整个模型的精度就会掉得很厉害。我更推荐的做法是在训练时就引入量化感知训练虽然工作量增大但部署后的稳定性完全不一样。选什么精度格式不只是一个技术参数它背后还牵扯到训练和推理的一致性。训练时用高精度保证收敛部署时换成低精度保证性能这个转换过程中需要加入细致的评测和校正不然模型效果就悬了。3. 实操把一个模型真正迁移到NPU3.1 获取加速硬件的三条路径对比开始聊迁移流程之前先解决一个现实问题去哪里找NPU用。我见过不少同学理论看了很多但一直没动手就是因为手上没有硬件。实际上现在获取这些专用加速资源的门槛已经低了很多我整理一下大概有三条路径。第一条是云端的加速实例。现在主流云服务商都推出了搭载自研或第三方AI加速芯片的实例按小时计费适合做评测和短期项目。好处是免运维、弹性好坏处是数据出域和长期成本问题要仔细考量。第二条是边缘开发板现在不少国产开发板板载了NPU性能足够跑一些视觉和语音模型价格也不贵非常适合学习和原型验证。第三条是自己攒服务器适合对数据敏感或者需要长期稳定运行的中大型团队但硬件选型和驱动适配的坑会比较多。我自己经历过的一个坑是在软件模拟器上把一个模型优化得很好跑到了满意的指标一上真机因为驱动版本和模拟器有差异算子行为、内存分配策略全变了性能直接回退到优化前。所以我的建议是不管哪条路径拿到真机后第一件事就是跑一个最小模型把编译工具链和Runtime的版本对齐再谈优化。3.2 模型到硬件的编译流程把PyTorch或者TensorFlow写出来的模型变成能在NPU上执行的文件中间经历的过程我习惯把它拆成四步理解这个过程对排查问题很有帮助。第一步是前端解析和目标转换。通过ONNX或者各家的模型转换工具把通用框架的模型图导出再转换到硬件厂商自定义的中间表示层。这个阶段最常见的问题是算子不被支持比如某个框架里的特殊操作找不到对应的映射转换直接报错。第二步是图优化这一步有点像代码编译器的优化 pass融合算子、常量折叠、删减冗余节点都在这里完成。一个好的图优化能把算子数量减少一半以上效果立竿见影。第三步是算子映射和布局转换。通用框架里的一个Conv2D算子在硬件上可能会被拆成多个子操作或者被改写成一个融合了Bias和激活函数的复合算子。同时还要对每个张量做数据布局变换保证在硬件上能高效执行。第四步是后端代码生成和内存分配这一步会把计算图映射到具体的计算单元上并为每个中间张量分配片上存储地址。如果存储不够编译器就会插入额外的数据搬移操作性能就会打折扣。四步走完生成一个可以被Runtime加载并执行的可执行文件。多说一句这个过程虽然复杂但大多数厂商都提供了高度自动化的工具链你不需要手动干预每一步。你需要做的是理解每一步的目标这样在报错时才能快速判断问题出在哪个阶段。3.3 一个典型迁移项目的时间线纸上谈兵终觉浅我拿一个具体的OCR方向模型迁移项目来还原真实过程我们内部习惯叫它模拟项目X。这个项目需要把一版在GPU上训练好的文本检测模型部署到NPU加速卡上目标是保证推理精度不降的前提下把单张图片的推理延迟从50毫秒压到20毫秒以内。项目第一周做的主要是摸清底数。我把模型结构和全部算子清单打印出来逐个对照目标平台的算子支持列表发现动态形状相关的几个算子平台上不支持这直接决定了后面要改模型结构的方向。第二周做模型改造和转换把不支持的算子用支持算子重新组合然后用厂商的转换工具导出并编译跑通了端到端流程。这周结束时的性能大概是90毫秒比GPU还慢团队一度很焦虑。第三周进入真正的性能调优阶段我把重点放在三个方向上算子融合消除多余的数据搬移、调整输入图的分辨率和padding让尺寸对齐脉动阵列、替换更积极的量化配置降低计算精度。一周下来延迟降到35毫秒但离20毫秒的目标仍然有距离。第四周做了更彻底的内存复用规划配合模型结构精简最终稳定在18毫秒左右精度相比FP32版本损失控制在1%以内。这个时间线想表达的是NPU迁移不是一次转换就完事的它是一个从兼容性修复、到流程跑通、再到性能调优的持续过程。前期的算子清点越仔细后期返工越少。3.4 算子兼容性检查与改写技巧算子兼容性是迁移过程中最消耗精力的环节没有之一。我见过很多团队前面都很顺利最后被一个看似不起眼的算子卡了一周。这里分享一些实用的处理顺序和改写思路能帮你少走弯路。第一优先级是查官方算子列表确认支持情况。同样叫Gather的算子在不同硬件上的支持细节可能完全不同有的只支持固定维度有的只支持特定数据类型。哪怕官方文档说支持也建议用小形状的测试用例先验证一遍。第二个常用技巧是用多个简单算子组合来替代一个复杂算子。比如某些硬件对LayerNorm的原生支持很弱但拆成Mean、Sub、Square、Rsqrt、Mul等基础算子后反而能正确执行性能甚至更好。第三个思路是调整模型结构规避不支持的操作比如把动态大小的Resize操作改成固定尺寸的插值把循环内部的不规则切片逻辑挪到循环外。一个非常重要的经验是任何算子的改写都要在CPU参考实现上先做数值对齐验证确认改写前后的输出误差在可接受范围内之后再谈NPU上的性能。不然你会陷入“不知道为什么性能对了但精度错了”的两难排查中。4. 性能调优把硬件喂饱而不是算到冒烟4.1 先判断瓶颈在哪算力还是搬运拿到一块NPU上手第一件事不是急着改代码而是搞清楚你的模型到底被什么限制住了。这是性能调优最重要的一步很多人在这一步就做错了。如果你的模型是那种计算密集型的每一层都有大量矩阵乘法那么它可能真的是算力限制优化方向是降低计算精度、提升阵列利用率。但如果你的模型里有大量element-wise操作、数据变形、动态形状那么你的瓶颈大概率在数据搬运上。这种情况下再堆算力也没用因为计算单元大部分时间都在等待数据从内存里送过来。怎么判断最直接的办法是用性能分析工具跑一下看关键指标设备利用率和内存带宽利用率。设备利用率高说明计算单元确实在干活带宽利用率高说明数据通道是饱和的。如果设备利用率只有百分之二三十但带宽已经跑满了那你的优化重点就应该是减少数据搬移量、增加片上数据复用而不是去调计算参数。我自己常用的一个土办法是把模型最后一层结构改小再加一层很重的卷积对比前后推理时间的变化。如果耗时不增加说明原模型根本不是算力瓶颈如果耗时线性增加说明算力确实是堵点。这个方法虽然粗糙但在前期快速判断方向上特别管用。4.2 算子融合把碎片化的计算拼起来算子融合是提升NPU性能最立竿见影的技术之一。它的原理很直白把多个相邻的算子合并成一个算子减少中间结果的写出和读入。在GPU上这种优化更多是减少kernel的启动次数在NPU上它的意义更大因为每一次跨越片上SRAM边界的数据搬运成本都极其高昂。举一个最常见的融合场景。卷积后面接BN再接ReLU很多主流编译工具已经能自动融合成一个算子。但更多情况下融合需要你手动去调整图结构。比如一个残差结构里卷积的输出要和旁路的输入做加法再经过激活函数。默认情况下编译器可能会为加法生成一个单独的算子你可以在图优化阶段手动把加法合并到卷积算子里的输出阶段这样少了一次片上存储的读改写周期。还有一个容易被忽视的融合点是在量化场景下。浮点模型中量化操作是独立的算子部署时如果每个算子都插入严格的量化反量化操作中间会产生大量冗余转换。正确做法是在图优化时把连续的量化反量化操作消除掉只在网络边界保留必要的转换节点。这一步做得好INT8模型往往能获得20%以上的额外加速。4.3 张量形状与内存对齐的隐藏门道这一节是最容易写进经验贴、也最容易被人忽略的部分。NPU和GPU最不一样的地方就是对张量形状的敏感度远超想象。我举一个具体例子。某个加速器处理卷积时底层阵列是64乘64的强制要求输入宽高是32的整数倍。如果你的输入是正常的512乘512那没问题但如果你的输入是513乘513这种刚好差一点的尺寸硬件会做补齐把张量pad到544乘544再算这时候多出来的大量灰色计算会让你的延迟直接涨15%以上。所以在设计模型输入时从源头就把尺寸定在对齐友好的数值上比后期在部署时再调要划算得多。如果是动态尺寸比如检测模型输入图大小随框变化可以做一个保比例的resize和padding把变化范围收敛到几个固定候选尺寸。这等于用少量精度损失换取性能稳定性实际项目中收益非常明显。内存对齐还有一层意思是张量在内存中的排列顺序。前面第二章提到过NCHW和NHWC布局的差异这里再补充一点有些加速器原生支持的是NHWC布局因为它的通道维连续排列对卷积的硬件数据流更友好。但训练框架默认是NCHW所以转换时可能需要插入布局转换算子。如果这个转换算子实现得不好会成为新的瓶颈需要特别关注。4.4 量化配置从入门到精通的三个台阶量化这个话题值得单开一节因为它在NPU优化中的位置太关键了。很多模型迁移到NPU上性能不错但是精度崩了八成都是量化配置的问题。我把它分成三个台阶方便你对号入座。第一个台阶是PTQ训练后量化。这是最省事的方案用一小部分校准数据统计每层激活值的动态范围然后计算出缩放因子和零点。它的优点是快、不需要改训练流程缺点是如果某个层有离群值或者校准数据覆盖不够全面精度就很容易翻车。我建议校准集至少要覆盖实际业务中可能出现的最极端情况宁可多选不能少选。第二个台阶是QAT量化感知训练。在训练过程中插入伪量化节点让模型提前适应低精度带来的噪声。这个方案的精度通常更稳但也意味着你需要在训练环境中加入量化相关的库并且花时间重新跑一遍训练。如果你的模型是要长期部署、对精度要求高的场景我强烈建议走QAT。第三个台阶是混合精度或者说分级量化。不同层的敏感度不一样不是所有层都必须用INT8某些敏感层可以保持FP16其他层降到INT8。量化分析工具会逐层输出敏感度排名我拿到这个排名后的习惯是优先保证前几个残差块的精度后段网络的量化风险相对低。这样操作下来往往能用很小的精度代价换回接近全INT8的性能。5. 常见问题与排查实录5.1 算子不支持、编译失败类问题的排查这是迁移初期最高频的报错大部分是转换工具在算子映射阶段抛出来的。我看到报错后第一反应不是急着搜哪个算子不支持因为报错信息里一般已经写清楚了。我真正会做的是回看一眼整个模型结构判断这个算子是否必要以及整个模型里还有没有同类问题一次性改完。有些时候算子不支持不是真的不支持而是输入数据类型的组合不支持。比如某个加速器对INT8的Conv支持很好但如果你传入的数据是FP32的编译工具不会自动帮你转精度而是直接报“operator not supported”。这种情况只需要把前一个算子的输出类型改为INT8就能过。所以我经常建议报错后先确认的数据类型、形状、布局三个信息再往算子实现层面去查能省不少时间。如果确认算子真的没有原生支持那就回到3.4节讲的改写方案。这里再强调一点改写完的算子组合一定要在CPU上做数值对齐验证。这是防止“性能上去了精度悄悄垮了”的唯一可靠手段。5.2 性能不升反降的深层原因辛辛苦苦把模型迁移到NPU上跑完发现比原来的GPU还慢这是最打击人、也最容易让人措手不及的情况。根据我的经验原因通常出在三个方面。第一个原因是模型太小计算量不足以摊薄硬件调度的开销。NPU和GPU类似每次调用算子都有启动开销如果模型里充满了小算子你的时间大部分花在等待硬件就绪上。优化方向就是算子融合把几十个小算子合并成几个大算子效果会非常明显。第二个原因是数据搬运路径过长中间张量太大根本无法放进片上SRAM导致频繁的片外内存读写。这种情况下的优化方向是切分计算让每一块数据尽量在片上处理完再写回。第三个原因则是输入数据布局转换过于频繁每个算子在执行前都要做一次NCHW和NHWC的互转转换开销比计算本身还高。判断是哪种原因还是得靠性能分析工具。我建议至少跑三层profile第一层看整体时间分布算子和数据搬移各占多少第二层定位到耗时的具体算子看它的设备利用率第三层看这个算子内部的工作流水确认是不是有空泡等待的情况。分析到这一步性能瓶颈在哪就一目了然了。5.3 精度偏差从浮点堡垒到整数废墟迁移到NPU后精度掉了这个问题涉及的面比较广。我有一张常用排查清单按照从浅到深的顺序列出来排查效率会高很多。第一项是确认数值类型是否发生了意外的截断。比如在转换过程中某些中间张量被悄无声息地转成了低精度而这个位置原本应该保持高精度。第二项是检查量化参数本身校准集是否覆盖了业务数据的真实分布各通道的数值范围估计是否准确。可以通过对比每层输出的统计特征来定位具体偏差层。第三项是检查算子改写的正确性特别是手写的替代算子组合有没有细微的边界条件差异。第四项是检查融合是否诱导了数值顺序变化比如浮点加法顺序改变会导致舍入误差累积在BN和残差结构中尤其要注意。我见过一个典型案例模型其他层都好好的就最后几层精度异常查了整整两天最后发现是残差相加的上下游算子被融合后加法顺序发生了变化导致累积误差偏大。把融合策略稍微调整一下只对那一路跳过融合精度马上回来了。这一类问题没有快捷方式只能靠逐层排查。5.4 稳定性和多卡并行问题模型能跑、精度也对不代表可以安心上线。部署一段时间后可能会遇到一些比较隐蔽的稳定性问题。比如长时间运行后内存碎片导致分配失败比如多张加速卡之间的负载不均衡。内存碎片问题常见于频繁创建和销毁推理会话的场景。我的建议是用常驻的推理引擎加线程池不要每次请求都初始化一遍上下文同时显式预分配好内存池。负载不均衡问题常见于多卡并联部署时因为输入形状动态变化较大各卡分配到的任务量差异明显。解决思路是动态负载均衡把输入按照形状预分类尽量均匀分发到多张卡上。硬件本身的散热和降频问题也要留意。有些加速卡的峰值性能只能在特定功耗范围内维持长时间高负载运转后会出现性能热降频推理延迟会在某个时间点突然变差。监控设备日志中的功耗和频率信息能够及时预警这类问题。做生产环境部署稳定性比极限性能更难解决值得投入精力。6. 最后再分享一个心得实际接触NPU和TPU的这大半年我感触最深的一点是这类硬件的性能天花板取决于你是否愿意调整自己的习惯而不是硬件本身有多强。它不像GPU那样兼容性极好、随便写写也能跑得不错它要求你把数据布局、算子融合、精度选择、内存规划这些软件层面的东西全部照顾到位它们决定了硬件能发挥出几成实力。如果你刚开始接触这类硬件我的建议是不要一上来就挑战大模型先拿一个结构简单但网络类型丰富的模型走一遍全流程从转换到部署再到性能分析把这个闭环跑透。等你理解了编译器在背后替你做了什么、哪些事情它做不了要你手动补上再上大模型就是水到渠成的事情了。这一章的内容到这里就算完整了。后面如果大家有兴趣我可以再整理一下针对特定模型结构的逐层优化笔记包括怎么把常见的Transformer结构在NPU上拆解、怎么评估每层到底该用多少比特位宽这类更细的内容。我踩过的坑、花掉的时间希望你能用它少踩一遍。