拓冰建站拓冰建站
首页 / 资讯中心 / 正文

NPU芯片架构深度解析:算力核心是数据复用与片上存储

我第一次把一颗带 NPU 的芯片开盖放到显微镜下看 die 布局的时候旁边做嵌入式的老同事凑过来扫了一眼说这不就是个会算乘加的仓库吗。话糙但我后来越琢磨越觉得他是真把 NPU 芯片架构看透了。很多人第一次接触 NPU翻架构白皮书满眼都是什么脉动阵列、数据流引擎、张量核心、近存计算、多级流水线……每个词都认识连在一起就不知道在说什么了。这篇我就想用一句话把 NPU 芯片架构说清楚然后再把这句话拆开揉碎讲明白每一个词到底意味着什么。不管你是做 AI 应用开发的、做嵌入式移植的还是单纯想搞懂手机发布会上的“NPU 算力提升 200%”到底在说什么这篇文章都能给你一个能直接拿去用的理解框架。看懂之后你再去看任何一颗 NPU 的 datasheet会发现里面的架构图都不再那么劝退了。1. 一句话版 NPU 架构数据搬运越少算得就越快这句话是我压箱底的总结NPU 的芯片架构本质上是把“算”和“搬”这两件事做了极致的分工——把尽可能多的计算单元堆成规则的阵列让数据在片上尽量少出去、多复用谁能在最靠近计算单元的地方把数据喂饱谁就能赢得算力。这句话里有三个关键词规则阵列、数据复用、喂饱数据。一个比一个重要。先说“规则阵列”。神经网络里 90% 以上的计算量集中在卷积和矩阵乘法上这两种运算有一个共同特点它们是由大量完全独立、互不依赖的乘加操作组成的。两个矩阵相乘结果矩阵里的每一个元素都可以单独计算谁先算谁后算根本不影响结果。这意味着芯片设计者不需要像设计 CPU 那样造一套复杂的乱序执行、分支预测逻辑来“挖掘指令级并行”只需要把成千上万个乘加单元MACMultiply-Accumulate像阅兵方阵一样整整齐齐排好然后让数据以固定的节奏流过这个方阵就行。再说“数据复用”。这是 NPU 架构和 CPU/GPU 最根本的分水岭。卷积运算有个天然特性同一个权重会被多个输入像素反复使用同一个输入像素也会被多个权重反复读取。如果每一次乘加都从内存里重新取一份数据和权重那芯片再快也会被内存拖死。NPU 的架构设计只有一个中心思想——尽量让数据在片上多待一会儿多被用几次再写回内存。这就像厨房里做菜高水平的厨师绝对不会切一次菜就跑一趟仓库取一次料而是把常用的料都摆在手边一趟备料撑起一整桌菜。最后说“喂饱数据”。这也是我这些年最深的体会绝大多数 NPU 实际跑不到标称算力原因根本不在计算单元而在数据根本喂不进去。计算阵列在那儿空转等待数据就像高速公路上修了一条十二车道的路但收费站只有一个窗口。所以你会发现真正决定一颗 NPU 好用不好用的往往是它的片上缓存有多大、DMA 搬运能力有多强、数据流水线能不能无间隙地一直跑。有了这句话打底下面我把 NPU 芯片架构设计的来龙去脉、内部布局、软硬件协同以及真实性能账全部展开讲一遍。我尽量不堆术语但该精确的地方也会给出具体的计算逻辑力求你看完能自己去分析任何一款 NPU 产品。2. 为什么 CPU 和 GPU 搞不定神经网络推理的效率账要理解 NPU 为什么长成这样得先搞清楚 CPU 和 GPU 到底“错”在哪里。这不是说 CPU 和 GPU 不行而是它们在设计之初要解决的是通用问题为了通用性付出了大量成本而神经网络的计算模式刚好撞上了它们的软肋。2.1 冯·诺依曼瓶颈取指令这件事本身就是浪费我们最熟悉的 CPU 是典型的冯·诺依曼架构每做一次运算都要经历取指令、译码、取数据、执行、写回这一整套流程。这套流程的优点是灵活你可以在同一个芯片上跑操作系统、跑数据库、跑游戏全靠指令来驱动。但代价是什么呢芯片的功耗和时间大部分不是花在“计算”上而是花在“跑腿”上了。从 CPU 的寄存器到内存有一条我们常说的“内存墙”。处理器内核的频率动辄好几 GHz但如果数据在内存里光是等待数据从内存传回处理器就可能需要几百个周期的延迟。在这段时间里计算单元只能干等。更扎心的是能耗账一次 32 位浮点乘法操作在计算单元里只需要大约 0.9 pJ皮焦耳的能量但从内存里搬一个数据过来却要花掉约 80~100 pJ 的能量。换句话说数据搬运的能耗比计算本身高将近两个数量级。如果一个程序大量在内存和计算单元之间搬数据那么整个系统的能耗和延迟都会被“跑腿”这件事支配。神经网络恰恰是这种模式的重灾区——卷积运算需要反复读取权重和特征图如果不做任何优化每一次乘加都要从内存取数那么能耗账单会彻底爆炸。2.2 GPU 的通用性救不了端侧算力焦虑有些人可能会问GPU 不是已经有很多计算单元了吗为什么还要专门搞 NPU没错GPU 的并行计算能力确实强它把成千上万个核心组织成 SIMT单指令多线程模式非常适合图形渲染和通用并行计算。GPU 也做了很多针对矩阵运算的优化比如 NVIDIA 的 Tensor Core。但 GPU 的设计起点是通用并行计算它需要兼容各种各样不规则的访问模式、分支逻辑和复杂的数据结构。这种通用性是有代价的每个运算单元周围都要配套调度硬件、寄存器文件和复杂的缓存层级。在服务器机房里GPU 是插在电费账单上的庞然大物功耗几百瓦起步散热靠的是整套液冷系统。但到了手机、平板、笔记本、车载设备这些场景里你能给 AI 计算分配的功耗预算可能只有几瓦甚至不到一瓦。如果指望把 GPU 那套架构原封不动搬过来光是把数据从显存搬到计算单元这条路径上的开销就吃不消了。2.3 NPU 的“减法”哲学把不需要的东西全砍掉NPU 的设计思路跟 CPU/GPU 完全不同它不是在做加法而是在做减法。既然神经网络的计算模式如此固定——满是乘加操作数据访问如此有规律——那为什么还要保留通用指令的那套复杂逻辑呢NPU 砍掉了乱序执行、分支预测、通用缓存一致性协议这些与神经网络计算无关的东西把省下来的芯片面积和功耗预算全部投入到两件事上一是多放预测计算单元MAC 阵列二是多放片上存储SRAM。架构上的主要工作就是用一个极其精简的控制器配合 DMA直接内存访问引擎把数据按照预定的节奏从内存搬到计算阵列面前再把结果搬回去。这种架构思路可以类比中央厨房和家庭厨房的区别家庭厨房什么菜都可能做什么工具都得备着五花八门的锅碗瓢盆占了一柜子中央厨房只做固定的几个菜灶台排成一排食材切好分装好按流水线传过来厨师只管机械地下锅翻炒效率自然高出几个量级。NPU 就是这个中央厨房它把“做什么菜”这件事在编译阶段就定死了运行时只负责“按节奏执行”。3. 一张 NPU 的 die 上到底摆了什么存储、计算与控制的三方布局知道了 NPU 的动机之后我们来点硬核的把 NPU 的 die 图剖开看里面到底有哪些物理模块这些模块之间是怎么配合的3.1 核心组成模块逐个拆解如果你拿任何一颗主流 NPU 的 floorplan布局图来看大概率会看到这几类模块MAC 阵列乘加阵列占据芯片面积最大的部分是一排排整齐的乘加单元。每个单元在单个时钟周期内完成一次 a×bc 的操作。整个阵列整体呈规则的矩形因为这样布线最短、时序最好收敛。片上 SRAM静态随机存储器也叫 scratchpad memory便签存储器紧贴着 MAC 阵列布置。它存放的是当前这一阶段计算需要的权重和中间激活值读写速度极快能在一个周期内完成。SRAM 的容量和 MAC 数量之间的比例关系直接决定了这颗 NPU 的数据复用能力。累加器与激活函数单元MAC 阵列算出来的中间结果需要累加比如卷积的每个输出像素是 3×3×通道数 次乘加的结果累加器就负责存下这些部分和。累加完之后通常会经过激活函数层ReLU、Sigmoid 等这一层在 NPU 里一般用查找表或专用简单电路实现不像 CPU 那样用通用浮点单元去算。DMA 引擎Direct Memory Access负责片上 SRAM 和片外 DRAM内存或显存之间的数据搬运。它可以绕开 CPU 核心直接把数据按设定好的地址和长度批量搬进搬出而计算阵列在搬运的同时可以继续算上一批数据实现流水线重叠。控制器与编解码器NPU 里也有一套精简的指令集但这些指令不是给程序员写业务逻辑用的而是描述“从哪搬数据到哪、搬多少、什么时候开始算”的搬运和调度指令。这套指令由编译生成由控制单元逐条执行。我用一个表格来总结这些模块的分工模块职能类比MAC 阵列执行乘加运算生产线上的工位片上 SRAM暂存权重和中间数据工位旁的原料架累加器汇总部分积每道工序的积料盒DMA 引擎内存与片上存储之间的批量搬运自动叉车控制单元按节奏发号施令车间调度员3.2 两类主流的数据流设计权重固定还是激活固定MAC 阵列好摆但真正决定一颗 NPU 性能上限的是数据在阵列里怎么流动。这个问题在业界有一个专门的词叫“数据流”dataflow。你去看 Google TPU 的脉动阵列、Intel 的 NPU、手机上那几家 NPU 的专利本质都是在讨论不同数据流方案的取舍。先说脉动阵列Systolic Array。这是 Google TPU 的招牌也是最容易理解的设计权重预先“驻扎”在每一个 MAC 单元内部输入数据像波浪一样从阵列左侧流进来每经过一个 MAC 单元就做一次乘加然后部分和沿着另一个方向往下传递。数据每移动一步就完成一层计算整个阵列像一条流水线所有单元在同一时刻都在工作。这种方案的优点是数据复用率极高——同一个输入数据会被整列权重轮流使用几乎不需要反复取数。缺点是阵列的利用率高度依赖卷积的形状如果算子的尺寸和阵列尺寸不匹配边上就会空转浪费。另一类是**输出固定Output Stationary**的数据流这也是很多移动端 NPU 爱用的方案。它的思路是把某个输出像素的计算过程固化到一组 MAC 单元里权重和输入数据轮流流经这组单元不断累加出最终结果。在这种方案里每个 MAC 单元里都有一个“私人累加器”减少了中间结果的搬动特别适合卷积核尺寸小、通道数深的计算场景。这两种方案没有绝对的好坏只是针对不同算法形态的优化方向不同。芯片厂商在设计 NPU 时一般会用配套编译器去分析神经网络结构然后选择最合适的映射方式有时候甚至动态混用多种数据流。这也就是为什么各家 NPU 虽然表面上都是 MAC 阵列实际跑同一个模型时帧率差异可能很大的原因之一。3.3 为什么面积都花在 SRAM 上而不是计算单元上我见过不少第一次接触 NPU 的人都会有一个疑问既然要算力强为什么不堆多一点 MAC 单元反而在芯片上放那么大面积的 SRAM这背后的账其实很清楚MAC 单元的数量乘以工作频率决定了芯片每秒能做多少次乘加这是理论算力但实际吞吐量还取决于每个 MAC 单元能不能持续拿到数据。如果在某个时钟周期里 MAC 想算但数据没到这个周期就是浪费的。为了保证 MAC 阵列不饿肚子就得在它旁边堆足够的 SRAM 做缓冲同时配合 DMA 提前把下一块数据搬进来。这里有一个经验比例芯片设计者们一般会把片上 SRAM 与 MAC 阵列的面积比例保持在 1:1 到 2:1 之间。也就是说你看到一颗 NPU 里一半面积是 SRAM不用惊讶这是为了避免“大炮打蚊子”——计算单元再多数据喂不进来也是白搭。而且SRAM 的功耗单位是 pJ 级别片外 DRAM 要上百 pJ两者差了两个数量级。把数据尽量留在片上不仅是为了速度更是为了把功耗控制在端侧设备能承受的范围里。这也就是为什么 NPU 架构会反复强调“近存计算”——让存储离计算越近越好。4. 从硬件架构反推软件栈编译器才是 NPU 的隐形灵魂很多人以为 NPU 难的是硬件其实真上手开发过就知道硬件架构只是骨架真正让你想摔键盘的是软件栈。我做过一段时间的 Intel NPU 开发也用过不少端侧 NPU 的开发工具链最大的感受是一颗 NPU 能发挥几成性能一半看硬件架构另一半看编译器。4.1 你没有在“编程” NPU而是在描述计算图主流的 CPU 开发是写指令代码GPU 开发写 CUDA/OpenCL 这类并行程序而 NPU 的开发基本不是这个画风。你做的更多是用一个框架比如 PyTorch、TensorFlow、ONNX定义好神经网络结构然后通过厂商提供的工具链把模型转换、量化、编译成 NPU 能执行的二进制。这时候你会接触到一个叫“计算图”graph的概念。计算图是一个有向无环图每个节点是一种算子卷积、池化、全连接、激活函数……每条边表示张量数据在算子之间的流动。NPU 的编译器要做的事情就是把这个图拆解成一层层算子序列再决定每一层算子应该用 MAC 阵列里的哪些单元去执行、权重该放在 SRAM 的哪个位置、什么时候从片外把下一层的数据搬进来。4.2 算子融合减少搬运次数的关键手段编译器里最重要也最出效果的一步优化叫算子融合operator fusion。我刚才说数据搬运的能耗和延迟远大于计算本身那么最直接的优化思路就是把多个算子合并成一个算子让中间数据不要写回内存直接在片上完成所有计算。举个例子卷积层后面通常跟一个批归一化BatchNorm和一个 ReLU 激活函数。在未优化的执行方式里卷积的结果要写回内存批归一化要从内存读出再写回ReLU 再读一次再写一次。三次访存纯粹浪费。编译器可以在编译阶段把批归一化的参数折算进卷积层的权重和偏置里再把 ReLU 直接接在卷积的激活单元后面三者合成一步中间数据根本不落到片外内存只存在于寄存器级别的累加器里。我拿一个实际项目的数据来说明一个 ResNet-50 模型未经任何算子融合直接跑 NPU实际吞吐量只有理论算力的 40% 出头。做了算子融合、内存再分配之后同一颗芯片跑到 85% 以上的理论吞吐量。差距之大远超很多人预期。所以当你感觉自己的 NPU 跑模型“不够快”的时候先别急着赖硬件回头看看编译器的优化报告更靠谱。4.3 量化感知训练对架构的深度适配NPU 的 MAC 单元在设计时就硬编码了对特定数据格式的支持。浮点虽然精度高但浮点 MAC 的面积和功耗是定点格式的好几倍。端侧 NPU 更偏向 INT8、INT16、甚至 INT4 这样的低精度整数格式。一个 INT8 乘法器占的面积大约是 FP32 乘法器的 1/4 到 1/5功耗低得更多而深度学习模型对 INT8 量化后的精度损失通常可以接受。不过量化不是简单把模型权重从 FP32 转成 INT8 那么简单。这里面有一个大坑叫“量化敏感层”。我实操中发现大部分层的权重量化到 INT8 后精度几乎不掉但总有那么极少数几层比如检测头、Attention 里的 Softmax 附近对量化特别敏感一旦转 INT8精度下降肉眼可见。成熟一点的工具链支持混合量化也就是敏感层保持 FP16 或 INT16其余层走 INT8。能不能做混合量化、支持哪些数据格式、量化粒度有多细这些都是评估一颗 NPU 开发体验好坏的核心指标。4.4 内存规划编译器手里的隐形魔法神经网络执行时最占内存的往往不是权重而是中间激活值。一张 256×256 的输入图经过 64 个通道的卷积输出的特征图就是 256×256×64假设每个元素 1 字节INT8这一层就要 4 MB 的存储空间。如果芯片上的 SRAM 只有 2 MB那激活值就必须被切分成小块tiling分批次处理每处理一块就写回片外内存再读下一块。编译器的一个重要任务就是决定这个切分边界应该在哪里。切块太小DMA 搬运次数多效率差切块太大片上的 SRAM 装不下就得频繁换出换入。这个优化在原理上跟我们手动调整卷积循环的循环分块loop tiling非常像只是 NPU 编译器是自动完成的。我看到很多性能问题最后查来查去都出在这个环节要么是编译器没有拿到正确的输入尺寸信息导致切分策略保守要么是用户代码在数据布局上跟编译器期望的 NHWC/NCHW 格式不一致导致每层数据都在做额外的转置搬运。5. 看懂 NPU 规格参数TOPS、MAC 数量与内存带宽的换算关系每次有新款芯片发布宣传海报上最显眼的数字就是“AI 算力 XX TOPS”。这个数字到底是怎么来的是不是越大越好我在这里给大家把账算明白看完你就不会再被营销稿带节奏了。5.1 TOPS 这个数字是怎么算出来的先明确定义TOPS 是 Tera Operations Per Second 的缩写也就是每秒钟能执行多少次操作这里的操作一般按“乘加各算一次”来数。换句话说一个 MAC 单元完成一次乘加会计为 2 次操作1 次乘法 1 次加法。那么一颗 NPU 的 TOPS 就由三个参数决定MAC 单元的数量、芯片的运行频率、以及计数规则通常是每周期 2 次操作。公式就是TOPS MAC 数量 × 频率Hz× 2 ÷ 10^12举个例子。假设一颗 NPU 有 1024 个 MAC 单元运行频率是 1 GHz那它的理论算力就是 1024 × 1e9 × 2 2.048 TOPS。如果同一代架构把 MAC 数量翻到 2048其他不变就是 4.096 TOPS。看到这里你应该明白了厂商如果想提升宣传数字最简单的办法就是堆 MAC 数量、提频率或者在计数规则上做文章。有些厂商把 INT4 算一次、INT8 算一次、FP16 算一次然后每种精度各算一遍 TOPS 再相加这样数字直接翻三倍看起来很吓人但对实际浮点精度任务的指导意义有限。我建议大家看 datasheet 的时候只认两个东西一是精度的具体格式是 INT8 还是 FP16二是在这个精度下 MAC 阵列的实际尺寸。5.2 从带宽反推真实性能理论 TOPS 只是上限真实性能要看带宽把数据喂到 MAC 阵列面前的能力。让我们来做一个极端假设。一颗 10 TOPSINT8的 NPU每秒需要完成 5×10^12 次乘加10 TOPS ÷ 2。每次乘加至少需要两个操作数一个输入激活、一个权重理想情况下每操作数 1 字节那么每秒至少要读取 10×10^12 字节 10 TB/s 的数据。如果这片芯片的内存带宽只有 25 GB/s这已经算不错的端侧水准了且数据完全没有复用那么即使 MAC 阵列再快实际算力也只能跑到 25 GB/s ÷ 10 B/次运算 × 2 操作 ≈ 5 GOPS跟 10 TOPS 差了整整三个数量级。好在 NPU 有片上 SRAM 和数据复用机制实际有效带宽需求会被大幅降低。假设卷积的权重复用率为 50 倍、激活值复用率为 10 倍那么实际需要的片外带宽就降到 10 TB/s ÷ 500 ≈ 20 GB/s这时候跟 25 GB/s 的带宽就匹配得上了。这也解释了为什么 NPU 架构那么看重“数据复用”和“片上存储”没有这两样再高的 TOPS 都是空中楼阁。我平时评测一颗 NPU 能不能满足项目需求会做一个快速估算先用理论 TOPS 计算出它在目标模型上的理想推理时间再看内存带宽是否能支撑 50% 以上的理论算力。如果带宽明显不足那实际帧率大概率不理想需要在开案前就跟供应商确认清楚。5.3 为什么 PCIe 和闪存延迟也会混进 AI 算力话题里最近“闪存芯片架构”这个词频繁出现在 AI 硬件讨论里很多人觉得奇怪AI 算力跟存储有什么关系其实关系很大。芯片端的算力再强数据和模型始终得从存储系统里来。大模型权重动辄几十上百 GB根本放不进芯片的片上内存所以推理时要么把权重流式地从硬盘搬进内存要么在内存和计算单元之间反复搬运。这时候存储介质的带宽和延迟就直接成为系统瓶颈。NAND 闪存顺序读带宽可以做到很高但随机读延迟是纳秒级的数十倍甚至上百倍如果是大量小权重的随机访问存储架构不够好NPU 就得长时间饿肚子等数据。所以你会看到很多做 AI 芯片的公司也在强调存储架构的配合——这背后就是同一本账计算容易堆数据难喂。6. 给想用 NPU 的人几条实在建议文章写到这里关于 NPU 架构的核心逻辑基本都过了一遍。最后把我这些年踩坑总结出的几条实际经验分享给准备上手 NPU 项目的朋友算是“快速上路指南”。6.1 先看编译器支持矩阵再谈算力我见过太多项目选型时盯着 TOPS 数字、脑门一热定了芯片结果开发到一半发现厂商的工具链压根不支持你这套模型里用到的某个算子。特别是 Transformer 类模型里的 Self-Attention、LayerNorm 这类非常规算子很多 NPU 工具链的支持成熟度远不如对 CNN 卷积算子的支持。最靠谱的做法是在选型阶段就把你的目标模型跑一遍厂商的编译器看看能转换成功的算子比例是多少、不支持的算子在 CPU 上做回退的代价有多大。算力再高的芯片如果不支持的算子把你的模型拆得七零八落、每个算子都要 CPU 和 NPU 之间来回切片最终性能反而可能不如一个算子支持完整的低端方案。6.2 别用 GPU 优化的模型直接扔给 NPUGPU 上写算子、调优的习惯跟 NPU 完全是两个世界。GPU 性能优化靠的是并行线程块划分和共享内存手动管理NPU 优化靠的是计算图的拓扑结构和数据布局。很多人在 GPU 上跑得好好的 PyTorch 模型直接导出 ONNX 丢给 NPU 工具链结果性能一塌糊涂还找不到原因。我自己的经验是转换到 NPU 之前先对模型做结构层面的梳理。比如把输入数据的排布方式固定成 NCHW 或者 NHWC 的其中一个免得每层都要做数据转换再比如尽量用标准算子组合避免用自定义 op。这些看起来是小事但在 NPU 上它们会直接影响编译器能不能做出好的融合和调度优化。6.3 跑一次真实的基准测试比什么都有用厂商给的 SDK 里通常自带几个 benchmark 示例比如 MobileNet、ResNet 系列的推理延迟测试。这些示例跑出来的数字通常很好看但别高兴太早。它们往往针对厂商硬件做了深度优化用的量化配置、batch size、输入分辨率都是对性能最有利的那组。我建议你准备一套自己的代表模型最好能反映你的业务里最常出现的算子组合、张量形状和精度需求然后在目标 NPU 开发板上跑一次端到端的推理计时。要特别关注 CPU 和 NPU 之间的数据拷贝是否频繁、有没有隐式同步点导致流水线断流。这些坑在厂商 benchmark 里是暴露不出来的但在你的真实业务里都是致命的。6.4 什么时候真的不该用 NPU最后说句逆耳的话不是所有 AI 任务都适合 NPU。如果你要跑的是过于稀疏的模型、动态 shape 变化非常大的输入、或者逻辑分支极其复杂的模型NPU 的“极致专用化”反而会成为负担——它的高效来自编译期就把执行计划定死而动态性和不规则性恰恰是它最不擅长处理的。在端侧NPU 和 CPU/GPU 的关系应该理解成互补简单重复的重计算丢给 NPU不规则的控制流和动态逻辑留在 CPU张力大但算子标准的活可以给 GPU。我自己做过一个端侧视频分析项目最初想把整个检测模型都塞进 NPU结果帧率只有 15 FPS后来逼我开了编译器的手工调度接口把预处理和输出后处理留在 CPU 上NPU 只跑最关键的那个主干网络时间最长的卷积部分帧率反而直接翻倍到了 32 FPS。所以我一直觉得理解 NPU 芯片架构最大的价值不是让你去设计芯片而是让你知道手里这颗芯片擅长什么、不擅长什么然后把它放到最合适的位置上。理清了数据搬运这核心逻辑你就拿到了评估和用好任何一颗 NPU 的钥匙。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门