NPU体系结构详解:从MAC阵列到带宽墙的AI芯片优化

发布时间:2026/10/13 11:51:18

NPU体系结构详解:从MAC阵列到带宽墙的AI芯片优化 1. 为什么专门把NPU从“计算机体系结构”里拎出来体系结构课上讲CPU绕不开流水线、分支预测、乱序执行、Cache层级讲GPU绕不开SIMT、线程块、warp调度。但一旦讲到NPU你会发现话题突然拐向了另一个方向二维乘加阵列、片上SRAM、DMA搬运、数据复用。这不是教材故意漏掉了什么而是NPU本来就是另一套设计哲学它把“控制”这件事尽量弱化把“数据搬来搬去”这件事推向极端。NPU不是CPU也不是GPU。CPU的特点是“什么都能算但单个线程的效率天花板明显”GPU的特点是“大量线程并行跑能覆盖图像、通用计算但没有专门为某一种算子做死电路”。NPU走的是另一条路先把最常见的算子卷积、矩阵乘、激活、归一化给固化成硬件数据通路然后围绕这些算子的访存模式来倒推内存系统和调度方式。它的直接目标不是让任意程序跑得快而是让某几类程序跑得极快、单位功耗算得极多。所以这篇文章才值得单开一篇。它不是讲“神经网络怎么训练”而是站在计算机体系结构的角度把NPU当作一个具体算例来解剖它由哪些模块组成为什么长成这个形状公式层面的性能极限在哪里以及作为一个工程师该怎么让它真正跑满。适合读这篇的人有三类。第一类是正在补体系结构课的在校生想搞清楚“NPU和CPU在体系结构上到底差在哪”第二类是刚转去做AI芯片或者AI编译器的新人需要一个不绕弯子的入门框架第三类是搞模型部署的工程师虽然不设计芯片但非常需要理解“为什么我的模型在NPU上总跑不出理论算力”。2. NPU体系结构解剖它到底由什么组成2.1 核心部件MAC阵列、向量单元、SRAM、DMA一个典型的NPU内部其实只有四大块计算阵列、向量/标量单元、片上存储、DMA搬运引擎。这个结构和CPU“取指-译码-执行-访存”的经典五级流水完全不同甚至可以说它根本没有传统意义上的通用指令流水线。计算阵列是整颗芯片的心脏。它由大量乘加单元MACMultiply-Accumulate排成二维网格构成。为什么是二维而不是一堆独立的乘法器挂在一个总线上因为神经网络里的卷积和矩阵乘本质上是“高维规约计算”把一大块数据反复搬进ALU不如让数据在阵列里按固定方向流动。二维阵列的好处是同一份数据可以同时喂给多个乘法器寄存器之间直接转发不需要每次都从内存取数。乘加单元本身不复杂一个乘法器加一个加法器就够了。但阵列规模一上去功耗和面积就非常敏感。于是各种实现细节就出来了低精度乘数器可以用更少的逻辑门INT8乘法在实际电路里比FP32乘法省好几倍面积累加器则需要保留更高位宽因为INT8乘完累加很容易溢出常见做法是累加器用INT32甚至FP32。这些细节看似琐碎却直接决定了NPU的“真实算力”而不是“纸面算力”。向量单元负责处理那些“不是矩阵乘”的活。比如ReLU激活、通道间Pooling、LayerNorm、残差相加、逐元素乘法。为什么要单独立一块因为把这些操作也用MAC阵列去跑利用率极低——MAC阵列张开一次要做几千个乘加为几个元素激活去铺开它实在太浪费。所以NPU一般会有一个宽度适中的向量处理单元按几百个元素一批去跑逐元素运算。很多NPU性能上不去问题不在MAC阵列而是向量单元不够宽或者向量单元和MAC阵列之间没有独立的Buffer通道导致激活计算和矩阵乘排队打架。片上SRAM是NPU的生命线。它通常被切成几个物理分区激活Buffer、权重Buffer、输出Buffer、共享Scratchpad。注意这里没有Cache的概念。Cache是硬件自动管理、按地址命中的NPU里的Buffer是“软件显式管理”的也就是程序员或编译器要明确告诉硬件“这块数据放哪、什么时候放进来、什么时候用完可以覆盖”。这听着很原始但恰恰是为了可控性DRAM访问的延迟和带宽都是可预测的但Cache命中不确定性会带来计算单元的随机停顿这对一个以“确定性吞吐”为目标的引擎是不可接受的。DMA引擎负责片外DRAM和片上SRAM之间的数据搬运。它支持二维甚至三维的地址描述可以直接搬一个Tile块不需要CPU逐行拷贝。DMA做完一次搬运后会触发一个中断或状态位计算单元再开始消费数据。这套机制保证了“搬运”和“计算”可以重叠上一块数据在算的时候下一块数据已经在路上。如果你见过“双缓冲”三个字指的就是这件事。2.2 “指令”是什么一个被简化到极致的控制通路很多人第一反应是问NPU跑的是什么程序答案是一种数据流描述或者说是一串“Tile指令”。NPU的控制器不像CPU那样每个周期去取一条指令、译码一次。它的做法更接近“任务级流水”编译器先分析整个模型把计算切成一个个Tile生成一张任务图运行时再按任务图向NPU的队列里下发描述符。每个描述符里面大概写着把哪块输入搬到哪个Buffer把哪块权重搬到哪个Buffer让MAC阵列做一次矩阵乘结果写到哪个地址然后对结果做一次ReLU最后发一个同步信号给下一个任务。这种指令不包含“分支跳转”。NPU里几乎没有条件判断就算有也是“算完这个Tile后是否跳到下一个更小的循环”而不是复杂的控制流。为什么可以这样因为神经网络的拓扑在推理阶段其实是静态的模型有几层、每层输入输出多大在编译期就确定了。NPU要做的只是按固定顺序把一堆数据流任务执行完。那如果模型是动态的呢比如序列长度变化、有循环网络、有基于数据的条件分支这种场景下NPU一般有两种处理方式要么把动态部分卸载回CPU/GPU要么把动态模型拆成多个静态子图在NPU上分次加载执行。这也是为什么NPU很少单独存在它总是和CPU绑在一起形成一个SoCCPU负责控制逻辑和动态分支NPU负责纯计算。3. 算力不等于性能NPU的带宽墙和访存公式3.1 一个必须写进脑子里的概念计算强度先看一个最简单的例子。假设一个NPU标称算力是100 TOPSINT8也就是每秒钟能做100万亿次整数运算。听起来很吓人。但问题是这100万亿次运算所需要的数据是从哪里来如果每一次乘加都需要从外部DRAM读两个操作数那访存量就是200TB/s。就算今天的HBM技术也做不到这种带宽成本早就把芯片本身压垮了。所以NPU设计的第一原则就是让数据在片上被反复用而不是每次都用完就丢。量化这个原则的指标叫“计算强度”Arithmetic Intensity定义是每从片外读一个字节能在片上完成多少次运算。单位是FLOP/Byte或者MAC/Byte。这个概念在体系结构里其实不新老早的Roofline模型就用它来判断一段代码是计算密集型还是访存密集型但在NPU这里它变成了芯片设计指南。如果计算强度太低NPU满速运转时就需要海量外部带宽最后瓶颈一定在内存标称算力根本发挥不出来。这叫“带宽墙”。相反如果计算强度足够高数据从片外读一次在片内被重复利用几百次那外部带宽要求就会急剧下降芯片才有机会逼近理论算力。3.2 一眼算出你的NPU能不能跑满把上面的逻辑转成公式。假设目标算力是 PMAC/s外部存储带宽是 BByte/s你的算法平均计算强度是 IMAC/Byte那么要跑满算力必须满足 P / I ≤ B也就是带宽需求 B_need P / I。反过来给你一块芯片你也能反推它能跑满多高的有效算力P_eff min(P, B × I)。举个例子。某个NPU标称INT8算力50 TOPS即50×10^12 MAC/s片外带宽50GB/s。如果算法的计算强度只有100 MAC/Byte那么带宽能支撑的算力就是50GB/s × 100 5 TOPS。这意味着标称50 TOPS的芯片在这个算法上最多跑出5 TOPS利用率只有10%。这不是芯片不行是算法访存特性不行。那怎么提高计算强度靠数据复用。拿卷积来说一个3×3卷积同一个输入特征图的某个像素会参与所有输出通道的计算。在当前输出通道这层里它被读进片上之后可以被复用很多次不同卷积核位置、不同输出通道都能共用。所以卷积天然比“两个大矩阵直接做逐元素乘加”更容易跑满带宽。矩阵乘法的计算强度也和分块尺寸强相关K维度越长每个权重元素被复用的次数越多。这也是为什么很多NPU编译器都在疯狂优化Tile尺寸靠Tile选得巧能把片外访问量降低一个数量级。这个公式还能解释另一个现象为什么现在大家都在做INT8、INT4、FP16的低精度推理。因为计算强度不变的情况下低精度直接把每字节能承载的运算次数翻倍。同样是1字节FP32只能存一个数INT8能存一个FP16能存两个INT4能存四个。哪怕MAC阵列的物理结构完全不变“有效计算强度”也提高了带宽墙自然被推远了一些。所以低精度不只是为了省存储更是为了突破带宽瓶颈。3.3 片上容量是藏在背后的限制条件不过光有带宽公式还不够。计算强度能提高前提是“把一块数据留在片上反复用”。但如果这块数据太大片上SRAM根本放不下那你就只能分块处理或者频繁把中间结果写回DRAM。所以第二个限制条件是片上SRAM容量。一个实际检查方法如果你要复用的数据块是10MB而某NPU的片上SRAM只有2MB那无论如何编译器都只能切成5块每块数据对应的复用范围也跟着缩小计算强度会被大幅削弱。因此NPU设计的核心矛盾从来不只是“算得多快”而是“在有限的片上存储里怎么把数据流动的设计做到最优”。这带来一个有趣的设计结论有些NPU宁愿把MAC阵列做得小一点也要把SRAM做大。因为算力可以通过提高频率或加阵列宽度硬堆但访存效率一旦被存储容量卡死堆更多算力也只是浪费面积。你先保住“有效利用带宽”再谈峰值算力这才是NPU架构的正确姿势。4. 让NPU跑起来Tile、DMA和编译器的协同4.1 一切计算的单位都是Tile给NPU编程不考虑整张计算图考虑的是“Tile”。一个Tile就是一块刚好能塞进片上SRAM的数据片段比如输入特征图的某个空间区域和对应的部分通道。矩阵乘法也是一个道理把一个大矩阵拆成若干小矩阵块每次计算一个块。为什么要分块因为片上SRAM有限而模型往往巨大。编译器的工作就是从外层循环开始把整个模型的计算切成合适的Tile序列让每块数据在片上的生命周期尽量长。这里的生命周期不是指时间长短而是指它被读入后在写回或丢弃之前参与了多少次运算。我常看到有人用下面这段伪代码来理解NPU的调度逻辑它虽然简化但基本抓住了精髓// 一个矩阵乘 C A × B分块到 SRAM for (int m0 0; m0 M; m0 TILE_M) for (int n0 0; n0 N; n0 TILE_N) for (int k0 0; k0 K; k0 TILE_K) { // 异步搬 A 和 B 的块到 SRAM dma_load(A_buf, A[m0][k0], TILE_M, TILE_K); dma_load(B_buf, B[k0][n0], TILE_K, TILE_N); // 等 DMA 完成后开始计算 wait_dma_done(); mac_compute(C_buf, A_buf, B_buf, TILE_M, TILE_K, TILE_N); // 把 C 块积累到片外或保留在片上继续累加 dma_store(C_buf, C[m0][n0], TILE_M, TILE_N); }这段代码里的关键点有三个一是DMA是异步的计算还没结束就能预取下一块二是计算单元和DMA可以并行工作这是NPU高利用率的来源三是对K维度的循环往往不把中间结果写回DRAM而是直接留在C Buffer里累加这能节省大量带宽。4.2 卷积在NPU上是怎么落地的卷积说起来复杂落到NPU上通常会转换成两种形态。第一种是显式Im2col把卷积展开成一个大矩阵乘优点是统一了计算内核缺点是会额外产生数据拷贝消耗带宽。第二种是“隐式Im2col”也就是不让数据真的变成矩阵而是在DMA搬运和地址计算时按卷积窗口的坐标去取数计算内核仍然是矩阵乘但避免了物理拷贝。隐式Im2col是现在主流编译器喜欢的方式。它会为每个输入像素计算好“它应该出现在哪次乘加里”然后用地址偏移去描述。这个描述看起来复杂实际上就是一组仿射变换编译器可以静态算出来。这也是为什么NPU编译器里有大量循环嵌套生成的代码其实都是在做坐标映射。卷积里另一个烦人的东西是Padding。如果输入特征图边缘要补零编译器有两种选择一种是在DMA搬运时直接把零补齐搬进来就是完整块另一种是在SRAM里临时清零。两者都有代价最怕的是每个Tile边缘都有Padding导致大量重复搬运。处理这类问题没什么魔法就是控制好Tile边界让Padding区域尽量落在同一批搬运范围内。4.3 编译器本质上在做数据流图重构从上层看神经网络模型是一个计算图节点是算子边是Tensor。但NPU不认计算图它只认“数据搬进Buffer算一下搬到下一块”。所以编译器干的活是把计算图重写成“图调度”每个算子必须被切分成多个Tile每个Tile挂上DMA任务和计算任务任务之间再按依赖关系排好顺序。这个过程中最容易被忽略的是同步机制。两个任务之间如果共享同一个Buffer就必须插入依赖和屏障否则后一个任务会把前一个任务还没用完的数据覆盖。很多NPU暴露给软件的同步原语是一组事件ID或者Barrier编译器负责为每个任务分配事件号并在正确位置WAIT。判断一个编译器成熟不成熟就看它生成的同步是不是足够稀疏同步太密会拖慢流水线太多空等会让DMA和MAC互相卡死同步太稀又是错的数据不一致。另外编译器还要决定哪些算子可以“融进”前一个算子的计算任务里。比如ReLU、偏置加法、残差相加这些逐元素操作如果独立成一个任务就必须把中间结果写回DRAM再读一遍浪费两个搬移周期。理想做法是把它们直接挂在MAC阵列的输出流水线上计算完矩阵乘直接做激活再决定存不存。这种融合优化对有效带宽的影响极大是NPU编译器里收益最明显的一项工作。5. 实战排查为什么NPU跑不满5.1 常见问题的速查表在实际项目里摸爬滚打你会发现NPU跑不出预期性能问题通常不是芯片坏了而是下面几类情况。整理成一张表遇到问题可以逐条对照。现象大概率原因排查思路算力利用率不到50%MAC阵列经常空等数据检查DMA预取深度看看有没有双缓冲计算等待搬运的周期占比整模型延迟正常但单层时快时慢片上Buffer容量不足导致Tile切分过细打印每个算子的Tile尺寸看是否有大量“不足一个Tile”的尾部块有效带宽远低于硬件标称带宽访问地址跨度过大DRAM Bank冲突调整数据布局把按照NCHW排列的特征图换成编译器期望的NHWC排列向量单元占用过高MAC阵列空闲激活、LayerNorm等逐元素算子比重大检查算子融合优先把激活融进卷积结算流程同一模型跑INT8比FP16快不了多少模型里混有大量非INT8友好算子对算子做量化回退分析找出量化敏感层并优化或混合精度延迟波动明显片外内存访问和其他子系统抢占带宽给NPU访问通道分配更高优先级或者使用独立内存通道这里要特别提一个高频问题只看“理论瓶颈”不看“实际访存模式”。很多人拿带宽公式算完觉得瓶颈不在内存结果一测还是慢。原因是公式里的计算强度是理论上的“理想复用次数”但编译器切分Tile时可能把复用切丢了。比如一个很大的卷积核如果Tile的通道方向取得太小权重就只能被读N次而不是被复用足够多次。遇到这种情况别急着改芯片配置先看编译器日志里每个Tile的“读入字节数/有效运算次数”通常一眼就能看出问题。5.2 一条我自己沿用很久的排查步骤先说观点性能问题优先怀疑访存而不是算力。因为芯片厂商给算力数字时都很诚实但“把数据送进计算单元”这件事它们通常只字不提。我的排查顺序是这样的第一步拿到一个算子先手工估算计算强度再对照芯片带宽算出理论最优延迟这是天花板。第二步用芯片厂商工具或仿真器拿到每层的实际运行时间和理论最优延迟对比。差3倍以内说明调度还不错差10倍以上不用看别处访存规划一定有问题。第三步看每一层的DMA搬运量和搬运次数。如果DMA搬了理论最少数据量的3倍以上逐元素中间结果的回写或Padding重复搬运大概率是元凶。这时候去查算子融合和Tile边界改动收益最快。第四步如果访存没问题看MAC阵列利用率。阵列利用率低往往是任务粒度过小。每个任务的启动开销远大于实际计算时间导致计算单元频繁启停。这种情况的解法是把连续多个小算子合并成一个任务或者增加串行执行的批次数。这套流程看着简单但几乎每次都能在最合理的层面发现问题。很多团队一上来就怀疑芯片设计有问题其实大部分时候是被编译器生成的搬运代码坑了。6. NPU本质是“把数据流动写死”的计算机体系结构课上讲的通用处理器核心思想是“指令流驱动数据流”程序在哪、数据在哪一切由指令控制。NPU把这个思路颠倒过来它更像“数据流驱动计算”数据按预定的路径流动计算单元在正确的时间窗口被触发。所以判断一个硬件是不是真NPU不看你标了多少TOPS而是看它是不是围绕“数据复用”来设计存储和调度。设计NPU和设计CPU有个完全不同的地方CPU追求对任意代码的通用性所以它的流水线深度、分支预测器、Cache替换策略都要处理“最坏情况”NPU追求的是对一小类计算模式的极致效率所以它愿意把大量芯片面积花在SRAM和定向数据通路上。一个通用计算芯片不会为“连续几千次乘加”专门铺一大片阵列NPU会因为这就是它的全部价值。这也决定了NPU的编程方式和CPU完全不同。程序员写CPU代码时关心指令、分支、内存地址写NPU代码时关心Tile大小、Buffer分配、DMA双缓冲、同步屏障。前者是“控制流”的思维后者是“数据流”的思维。两种思维能自由切换的人才是体系结构里最难培养的能力。至少对我个人而言做完一个NPU相关的项目后最大的体会是不要迷信峰值算力不要迷信TOPS更不要一上来就买大板子。先把“数据从片外到片内要走多久、能在片上复用几次、最终有效算力是多少”这三个问题算清楚比什么优化技巧都管用。很多所谓的性能问题根本不是优化技巧能解决的是设计阶段就走错了方向。如果你刚开始接触NPU也建议先拿一组真实模型做一遍理论带宽估算再去看任何厂商的SDK文档那样你会少走很多弯路。
延伸阅读

更多相关文章

2026/10/13 11:51:18

CS2更新后Valve界面闪退?Overflow溢出的根因与排查全攻略

先聊点实在的:这次 CS2 更新之后,我身边至少有三五个朋友跑来问同一个问题——“一进游戏,左上角那个 Valve 图标刚冒出来,画面就卡死闪退,偶尔还会跳一行 Overflow 溢出的红字报错,这到底怎么回事&#xf…

2026/10/13 11:51:18

TextBlob英文情感分析实战:从快速原型到生产环境的避坑指南

1. 为什么英文情感分析值得单独拎出来聊很多人第一次接触情感分析,都是从中文语料开始的,结果一上来就被分词、停用词、网络新词搞得焦头烂额。我当初也是这个路径,后来因为一个海外用户反馈分析的小需求,被迫转向英文文本&#x…

2026/10/13 11:51:18

定积分实战指南:可积性判断、牛顿-莱布尼茨边界与数值积分选型

1. 这不是课本里的定积分,而是你真正能用上的数学工具“数学分析 - 定积分(待修改)”这个标题乍看像教务系统里一条待处理的课程条目,但如果你正卡在某个实际问题里——比如想算清楚某段温度曲线下的总热量、评估一段变速运动的真…

2026/10/13 12:46:34

LODmesh实战:大场景渲染卡顿的网格细节层次优化方案

简介:细节层次(LOD)技术在三维渲染中广泛用于平衡性能与画面表现,它根据观察者与对象的距离动态调整模型细节级别。这份LODmesh实例代码面向图形学初学者与游戏开发入门者,通过一个短小工程完整演示了多级LOD模型的组织…

2026/10/13 12:46:34

Eclipse环境下SAP CDS视图创建全流程:从插件安装到报错处理

简介:CDS视图是SAP HANA数据库层的一种虚拟表,通过将跨表关联逻辑下沉到数据库执行,能够显著减少应用层与数据库的往返交互,提升复杂查询的响应速度。其核心原理在于过滤条件下推与数据预关联,让百万级数据量的多表查询…

2026/10/13 5:19:27

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/12 12:01:26

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/12 12:54:07

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/13 0:04:41

基于Triton部署YOLO目标检测:从训练脚本到线上服务

简介:这份资源面向希望将目标检测模型落地到生产环境的深度学习开发者与算法工程师,聚焦于用 Triton Inference Server 部署 YOLOv9 的完整实战方案,解决从训练权重到线上推理服务之间的工程化难题。压缩包共 16 个文件,约 886KB&…

2026/10/13 0:04:41

手把手教你云端部署Qwen-Image-2.1:从GPU选型到在线文生图服务

Qwen-Image-2.1 这个开源的图像生成模型,最近在内容创作和 AI 应用圈子里热度相当高。它属于通义 Qwen 系列里的视觉生成分支,让我眼前一亮的是它对中文长文本的理解能力——以前用那些老方案生成带中文文字的图,十个里九个是“乱码印刷体”&…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑