从矩阵乘法到NPU/TPU:硬件加速架构原理、量化调优与选型实战指南

发布时间:2026/10/16 14:46:22
从矩阵乘法到NPU/TPU:硬件加速架构原理、量化调优与选型实战指南
我写硬件加速相关的笔记已经有段时间了这篇是第19章。说句实话这几年做AI应用部署最大的感受就是模型架构在快速迭代但真正决定一个产品能不能落地、功耗和成本能不能压下来的往往是底层那几块专用芯片——NPU、TPU这类硬件加速器。很多朋友刚开始接触时会觉得这些概念离自己很远觉得只是大厂云端的事。但实际接触下来会发现无论是手机端侧跑大模型还是云服务器上批量推理、训练微调硬件加速已经是绕不开的一环了。这一章我不打算做教科书式的架构科普而是想从“为什么芯片设计会走到专用加速这条路”开始讲再把NPU、TPU这类加速器的内部原理、软件栈、实测调优、选型取舍这些串起来。内容密度不低但你如果曾经好奇“同样的模型为什么在不同硬件上速度差几十倍”、“为什么市面上的AI芯片算力标得吓人跑起真实模型却没那么理想”那这一章应该能给你不少可以拿去用的思路。1. 为什么通用计算芯片扛不住AI负载从矩阵乘法和访存开销说起1.1 一次矩阵乘法里藏着的计算特征先别急着看得太深我们回到最初的问题为什么CPU跑神经网络模型那么费劲神经网络的前向计算说穿了就是一大堆矩阵乘法和卷积算子的堆叠。拿矩阵乘法C A × B举例一个单精度浮点的乘加运算需要读入A的一个元素和B的一个元素做一次乘法和一次加法。理想情况下计算单元应该一直满负荷运转。但真实情况是一个通用CPU核心去执行这组乘加时要先经过指令解码、乱序执行、分支预测这些流水线步骤数据又要从L1缓存、L2缓存一路搬运到寄存器。算下来真正花在乘法运算上的晶体管周期只占一小部分大部分能量和时钟周期都消耗在“准备工作”上了。业界常说“算力容易堆数据搬运难”就是这个意思。有人可能会说GPU不是已经并行很强了吗确实GPU用几千个小型计算核心把并行度拉起来了训练通用大模型主要靠的就是GPU。但GPU的短板也很明显功耗高面积大在手机、冰箱、智能摄像头、车载设备这些场景里根本塞不进去。而且GPU的核心本质上仍然是通用并行计算它在处理密集的定长小规模矩阵运算、低精度整数计算时并不是最高效的形态。1.2 能效比AI硬件真正的分水岭学术界和企业界衡量AI芯片好坏有一个绕不开的指标叫能效比单位是TOPS/W也就是每秒万亿次操作除以功耗。一个通用CPU跑到10 TOPS可能需要几百瓦而一颗专用NPU跑到50 TOPS可能只用十几瓦。这背后不是魔法而是芯片设计理念的根本差异通用芯片要把计算能力和兼容性拉满什么都可能跑所以晶体管大量花在控制逻辑、缓存、分支预测上专用加速器只干一种活就可以把这些“配套开销”全部砍到最少。我自己做端侧部署时的体会很直接同样的一个图像分类模型在CPU上跑一次推理约40毫秒功耗3瓦左右换到手机内置的NPU上推理5毫秒功耗不到0.5瓦。这个差距不是靠优化指令能追平的是硬件架构层面已经注定了的。所以只要想在一个功耗受限的设备上做实时AI应用NPU几乎就是必选项。1.3 理解TOPS、FLOPS和MACs这几个单位交流中经常会碰到算力单位先把它们掰扯清楚。TOPS是每秒万亿次整数运算FLOPS是每秒浮点运算次数MACs是一次乘加运算。因为一个MAC 一次乘法 一次加法约等于2 FLOPS有些厂商宣传时会玩数字游戏把MAC算成2次运算把浮点换成整数峰值标称值就翻倍了。选芯片时我习惯自己先做一道估算题模型一次推理需要多少MAC以某个轻量级目标检测模型为例假设总计算量是20 GMACs加速器算200 GOPS那么理论推理时间大约是20 × 2 / 200 0.2秒。这个数字很粗但能帮你在拿到实物之前就对硬件能力有个合理预期而不是被宣传参数带偏。2. 从制造到计算NPU和TPU的架构设计到底“特化”在哪里2.1 脉动阵列用二维计算单元阵列把数据“流过”卷起来聊到NPU和TPU最常被提到的一个词是脉动阵列。这个概念听起来高深其实可以类比成一条多工位装配线计算单元像工人们一字排开数据像半成品一样依次传下去每个工位把自己负责的那一步做完再传给下一位。这样就不需要每个计算单元都直接从内存里搬数据而是通过相邻单元之间的寄存器传递大幅减少数据读内存的次数。举个简化例子一个8×8的脉动阵列有64个乘加单元。传统CPU每个乘加单元各自去缓存拿数据脉动阵列则是让矩阵数据沿着阵列的行和列“流”进去每个单元之间直接传递半成品结果。这种方式一次性可以完成大量乘累加。我第一回在仿真器里看数据流时才真正明白什么叫“数据就近计算”比“计算等数据”快得多。脉动阵列对计算密集型且规律性强的算子特别有用比如卷积、矩阵乘法。缺点是灵活性差换个稀疏计算、动态分支的场景利用率就下来了。这也是为什么很多芯片会在脉动阵列之外保留独立的标量向量单元用来处理那些“不那么规律”的算子。2.2 片上存储的优先级把数据钉在离计算最近的地方普通程序跑在通用芯片上数据默认从外部内存读取加速器不同第一优先级是把数据搬进片上SRAM。SRAM的读取延迟比DRAM低一到两个数量级而且芯片内部带宽可以做得很宽。你可以把加速器看成一家“自带仓库的工厂”外部内存是远处的物流中心SRAM是工厂门口的前置仓计算单元是生产线。前置仓备货充分生产线才能不空转。我在部署量化模型时碰过这样一个情况模型很小权重只有几MB但推理速度上不去。查了一圈根源是每次推理都要从外部内存读权重读完就丢下次再来一遍。后来在支持权重常驻片上存储的加速器上跑同样模型速度提升了近3倍。这就说明“访存优化”往往比单纯堆算力更值钱。2.3 指令集与编程模型上的巨大差异NPU、TPU这类加速器的指令集完全不是我们熟悉的x86或ARM那套。它编译出来的指令往往直接描述数据流调度把哪块内存搬进哪个缓冲区、让卷积阵列处理什么、激活函数在哪级流水线执行。开发者很少直接写汇编而是通过框架把自己的模型转换成中间表示再交给芯片厂商的编译器工具链。这里引出一个重要特性不同厂商的加速器中间表示不同、算子库不同所以同一个模型要适配多个平台就得分别编译、分别做算子映射。切换底座的成本通常不在模型本身而在“算子支持矩阵”上。3. 模型要如何“喂”给加速器编译、映射与量化那些事3.1 计算图与算子融合减少搬运就能快上不少模型给到加速器后第一步往往是把神经网络表达成一张计算图节点是算子边是张量流动。编译器会做很多图优化最经典的包括算子融合把相邻几个算子合并成一个算子执行减少中间结果的落盘和读取。最常见的是把Conv后面的BatchNorm、ReLU融合进卷积计算内部。这个优化有多重要做过一次实验一个带大量Conv-BN-ReLU结构的骨干网络开启算子融合后端到端推理速度提升了大概35%精度不变。原因很简单融合前每个中间张量都要写出读入融合后这些数据留在片上寄存器或SRAM里直接参与运算了。想优化推理第一件事永远是检查编译器生成了什么样的融合图和算子调度。3.2 量化用降低位宽换取数倍吞吐NPU和TPU在推理场景最喜欢的数据格式往往不是FP32而是INT8甚至INT4。把浮点模型转成整数模型这个流程叫量化。为什么硬件喜欢低精度因为整数的乘加单元面积更小、功耗更低同样一块晶圆能放下更多算力而且INT8数据的搬运量只有FP32的四分之一存储墙压力小很多。量化不是简单把浮点砍掉小数位那么简单还需要校准拿一部分代表性数据去统计激活值的分布找出合理的缩放和零点偏移。实践里最常用的方案是后训练量化不需要重新训练但可能掉一点精度。如果精度损失严重就得用量化感知训练在训练过程里模拟低比特效果。我自己的经验是对于分类和常规检测任务INT8量化掉精度通常在0.5%以内某些分割或姿态任务稍敏感要先试一批校准数据检查每个层的输出分布。3.3 动态Shape与算子兼容性跑通背后是看不见的适配工作平时在GPU上用PyTorch动态Shape完全不是问题张量尺寸变了就动态分配内存。可到了NPU上很多加速器偏好静态Shape预先编译好指定尺寸的调度方案内存布局也提前安排好。一旦输入尺寸改变可能就要重新编译甚至标量回退速度立刻断崖式下降。所以做端侧推理时我一般会把输入分辨率固定、batch size也固定。宁可多封装几个不同Size的入口也不要让运行时动态调整。否则你会在性能测试时看到一种奇特现象第一帧很慢后续帧变快换个尺寸又变慢全是编译器重新适配的过程。关于算子兼容性还要检查硬件的算子支持矩阵。常见情况是模型主体能在加速器上跑但有个把不常用的算子需要回退到CPU执行每次回退就要做一次跨硬件数据传输性能瞬间被拖垮。处理办法通常是把模型拆分避开带特殊动态控制的子图或者手写部分算子调用库。4. 一个真实推理项目的性能踩坑与调优复盘4.1 项目背景与性能基线纸面算力和实际吞吐间的鸿沟这里记录一个用第19章知识实际落地的案例。项目是做一个端侧手势识别模块目标是在一块带NPU的嵌入式板卡上跑一个轻量级关键点检测模型帧率要求不低于30 FPS功耗不高于2瓦。模型大约是18 GMACs芯片NPU标称算力是40 TOPS。按理论算18 × 2 / 40 0.9毫秒别说30 FPS100 FPS都够。但真把模型转换跑起来第一次测试推理延迟是24毫秒离目标差了一倍多。这就是典型“纸面算力好看实际跑起来打折扣”的案例。排查第一步先看模型转换后的性能剖析报告。结果显示Conv算子的利用率只有31%大部分时间花在4个低效算子回退和一个动态Reshape节点上。这表明问题不在硬件本身而在编译映射阶段。4.2 定位瓶颈从层耗时表到数据搬运热区拿到算子的逐层耗时表后我把耗时Top10的算子列了出来。结果很有意思耗时最高的不是计算量最大的层而是几个看起来不起眼的小算子——通道重排、Split和动态Shape拼接。这些小算子在GPU上几乎不耗时但在这颗NPU上它们触发多次全局内存读写成了真正的时间黑洞。根因是数据布局不匹配。加速器喜欢NCHW和特殊通道优先排列模型自动转换时某些算子输出了不友好的中间格式下一个算子要用又得转一遍。这就像工厂的流水线上前一个工序的产出是长方体后一个工序却只认正方体每道工序都在重新包装自然快不起来。调整方式有两种一种是在模型结构层面做等价重构把这些小算子折叠进相邻卷积另一种是修改编译器图优化配置强制指定更合理的数据布局。我选择了第一种因为模型本来就是要重新训练的在结构层面直接做优化更彻底。重构后再跑推理延迟降到11毫秒。4.3 量化、内存复用和线程调度把最后几毫秒抠出来接下来是量化。把这个手势模型从FP16转到INT8做了后训练量化用200张覆盖不同光照和手型的图像做校准。转换后精度评估关键点平均误差从3.2像素变为3.5像素影响很小。推理延迟从11毫秒降到6.2毫秒几乎翻倍。之后我又做了两件事一是把多路摄像头数据的预处理改成双缓冲机制让CPU端读图、缩放和NPU端推理并行起来二是调整板卡上的核心绑定策略把NPU驱动、图像采集线程分别钉在不同CPU核心上避免资源争抢。最终稳定到4.8毫秒每帧不仅满足30 FPS还给别的任务留了余量。优化阶段推理延迟关键改动初始转换后24 ms算子兼容性差存在CPU回退结构重构后11 ms消除动态Shape折叠小算子量化后6.2 ms转为INT8校准缓冲与调度优化后4.8 ms双缓冲核心绑定这个项目让我形成了一套排查固定流程先看逐层耗时表再查算子是否回退然后调数据布局和静态Shape最后才是量化。顺序反了容易白做工——没解决回退问题之前就量化性能收益会被底层问题吞掉一大半。4.4 多模型并发与吞吐优先场景的另一种经验前面例子是单模型低延迟场景但有些场景是吞吐优先比如云端图片审核服务一次性来几百张图更关注每秒能处理多少张。这种场景下我发现把多个推理请求打包成一个batch比单张并发更高效。原因很好理解硬件内的高并行计算单元喜欢被“喂饱”batch越大流水线越满单片功耗越能被摊薄。在支持动态batch的加速器上我把batch从1提到8总吞吐提升了约3.8倍单张延迟只增加了一些。不过这里有个边界batch不是越大越好。超过一定程度后片上存储不够用权重和中间结果会被挤到外部内存吞吐反而下降。实际项目中最佳batch值要实测通常配合内存池复用做调节。另外多模型并发时还要避免不同的模型轮番切换权重那会让缓存命中率雪崩。常见的办法是按模型分组排队让同一模型尽量集中推理。5. 到底要不要上NPU/TPU选型维度和一条务实的入门路径5.1 判断一个项目是否真的需要专用加速器先给结论并不是所有AI项目都要用NPU或TPU。我的判断标准有四个至少要中两个才值得引入专用加速。第一看场景是否实时比如在手势识别、自动驾驶、机器人控制里推理延迟直接决定体验专用加速的确定性延迟比CPU硬扛可控得多。第二看功耗预算电池供电设备上NPU通常决定了产品能不能用满一个工作日。第三看部署密度云端如果要在一个物理机上同时服务很多路视频流算力密度和成本优势会很明显。第四看模型形态如果模型极其固定长期不需要变那专用加速非常划算如果模型三天两头换结构每换一次都要重新适配算子那维护成本可能会吃掉性能收益。5.2 多硬件选型对比算力、功耗、成本与灵活性结合个人项目经验把几种常见路径放在一起做对比更直观维度通用CPU通用GPU端侧NPU云端专用加速器单位能效比低中等高高算子灵活性极高高低较低受工具链制约开发便捷性极高高中等中等偏低适合场景低频小任务训练、通用推理移动端实时推理规模化托管推理主要成本低高中低中高理想组合往往不是“只用一个硬件”而是分层搭配。重模型的训练和复杂后处理留给GPU前端实时推理、低耗电任务放在端侧NPU规模化服务用云端专用加速器做批量推理。这几种硬件之间的模型转换工作可以提前做好归一化像ONNX这类中间表示就经常能省很多事。5.3 一条可复制的起步路径先用模拟器再上真机如果你第一次接触NPU/TPU我强烈建议不要直接买硬件。大部分编译器工具链都提供模拟器模式可以先在开发机上把模型转换成加速器中间表示跑离线仿真统计每层耗时和内存占用。这一步能把逻辑错误先消灭掉也方便对比不同图优化配置的效果。等模拟结果靠谱了再上开发板或云端实例实测。实测时记得记录三样东西端到端延迟、硬件利用率、峰值内存占用。之后每做一次优化就把这三项数据更新一遍。这样整个项目的过程会非常透明也能避免“调参调到后面甚至不记得最初问题在哪”的混乱状况。另外选择硬件时不要只看峰值算力还要看编译器成熟度、算子覆盖数量和社区活跃度。同一个NPU工具链迭代两年后的表现往往比新发布但工具链粗糙的型号好很多。硬件是身软件是魂这句话在专用加速领域尤其成立。谈谈我自己在这些项目里的体会这几段内容快写完了再分享一些个人经验。专用加速器不是“更快的CPU”它是另一种形态的计算机。理解并利用好它的数据流架构和量化偏好能够获得远比“把模型丢进去跑”多得多的性能收益。我常和同事说在NPU上调优本质上是“让数据和算子在正确的时间、正确的地点相遇”。这个观点放在云端、端侧都成立。最后给一个特别值得留意的小技巧拿到任何一张加速器性能规格表先找它的存储带宽和片上缓存大小再细看算子支持矩阵最后才看算力数字。因为很多宣传参数漂亮但入手后难用的硬件瓶颈几乎都藏在数据搬运和算子兼容性上而不是那枚芯片本身。下一章如果有机会我打算详细记录一个真实的多模型并发调度项目把任务级流水线和内存池管理展开来写那部分东西对系统架构设计帮助相当大。