写这个系列之前,我一直在想该怎么把"AI 芯片的软硬件设计"讲得既专业又不像教科书。市面上聊AI芯片的文章,讲硬件架构的多,讲软件栈的少;讲算法映射的多,讲工程取舍的少。而这几年我接触或复盘过的AI芯片项目,几乎都会在同一个地方卡壳:硬件做出来了,软件却跑不通,或者跑出了个让人尴尬的性能数字。于是我想用一个系列来系统整理一下这块的经验,第一篇先讲清楚软硬件协同设计的整体框架和核心矛盾,后续再逐层展开编译器、算子库、数据流、存储架构这些细节。
这个系列适合三类人:打算做AI芯片/存算一体/NPU的芯片架构师和验证工程师,正在给嵌入式平台做AI部署的软件工程师,以及想在AI芯片赛道入行但还没找到切入点的学生。看完你至少能回答这三个问题:一颗AI芯片的硬件结构究竟由什么决定?软件栈为什么比芯片本身更决定生死?软硬件协同设计在真实项目中到底是怎么推进的?
1. 先拨开一个迷思:AI芯片的核心难点不在电路,在"软硬件怎么一起设计"
1.1 从流片到能用,中间隔着一整个软件栈
很多刚接触AI芯片的朋友,第一反应是盯住算力规格:多少TOPS、多少GHz、几个核。这些数字确实吸引人,但真实项目里,一颗芯片从流片回来到能稳定跑起一个像样的模型,往往要再折腾大半年。大半年里最耗时的不是修RTL的BUG,而是把算法框架、编译器、算子库、运行时、驱动一层一层对接起来。
拿ST的STM32N6举例,很多人把它当成"带NPU的MCU",觉得嵌入式跑AI嘛,调个库就好。真上手就会发现,ST除了给一颗NPU,还配套提供专用的中间表示和编译工具链,模型要从PyTorch或者ONNX格式导入,经过量化、算子映射、内存规划之后,才能生成NPU可执行的指令。芯片只是负责算,怎么把模型换算力,怎么切分到不同核心,怎么分配缓冲区,全是软件栈的事。这个认知如果不到位,后面所有工作都会跑偏。
1.2 软硬件协同设计到底协同什么
我把"协同"拆成三层,这三层贯穿项目始终:
- 功能划分:哪些功能做成硬件单元,哪些留给软件。硬件化收益高但灵活性差,软件化灵活但性能和功耗拖后腿。
- 性能兑现:芯片的峰值算力只是"理论极限",软件栈负责把它变成真实吞吐和延迟。这里经常出现硬件号称10 TOPS,实际跑模型只能到2 TOPS的尴尬。
- 成本控制:协同设计不仅指性能和功能,还指项目的迭代效率。硬件早冻结、软件跟不上,或者算法频繁变导致硬件白做,都是成本灾难。
这三层,几乎每一层都涉及架构师、算法工程师、编译器工程师、驱动工程师之间的反复拉扯。一个典型的教训是:架构师喜欢为某个特定模型做极致优化,算法工程师却希望架构能适配三个月后就要换的新模型。所以协同设计的第一件事不是画框图,而是对齐"到底为哪些模型服务"。
1.3 一个典型AI芯片软硬件全栈长什么样
从上到下大致是:算法框架(PyTorch/TensorFlow等)— 模型转换层(ONNX/量化/图优化)— 编译器(图优化、算子融合、指令生成)— 算子库/内核 — 运行时与驱动 — 硬件(计算单元、存储、互连、控制)。
每一层之间都有一对"接口约束"。比如算法层希望数据类型越宽越好,硬件层希望数据位宽越窄越好,于是编译器中间表示就成了博弈的战场。再比如运行时要知道有多少片上SRAM、多少内存带宽,才能决定模型怎么分块执行。可以说没有哪个环节能独立决定性能,也没有哪个环节能脱离其他环节独自优化。
我个人的体会是:刚入行的人往往把"AI芯片"想象成一块电路板,一做项目才发现它更像一套从模型到指令的流水线操作系统。硬件架构决定了流水线的物理边界,软件栈决定了流水线能跑多满。
2. 算力从哪来:算法结构如何决定芯片该长什么样
2.1 卷积时代和Transformer时代的需求差异
AI芯片设计的起点是算法结构。不同算法的算力需求、数据复用特征、访存模式差别极大,这会直接改变硬件设计的方向。
以卷积神经网络为例,卷积的局部性极好:一个卷积核的权重可以在整张特征图上反复复用,激活数据也有很强的空间局部性。所以针对CNN设计的芯片会倾向于配置大量乘加单元阵列,配合多级片上缓存,尽量把数据"喂"进计算阵列反复用。
Transformer时代情况变了。核心是矩阵乘(GEMM)加注意力机制,注意力分数的计算 QK^T 需要把整条序列的特征两两交互,是典型的高算力高访存操作。同时还有大量非矩阵类算子,比如Softmax、LayerNorm、RMSNorm,这些算子计算密度不高但数据依赖强,对硬件控制流和片上存储的随机访问能力提出了新要求。
这就解释了为什么新一代NPU不再像早期那样只堆"卷积加速器",而是开始加入更强的通用向量单元、更大的片上存储、更灵活的互连结构。你设计的芯片如果不看清这一点,很可能算法一迭代就过时。
2.2 计算、搬运、存储:AI芯片的三大先天矛盾
我记得有句话特别贴切:AI芯片的设计,本质上是在算力、访存带宽、存储容量三个维度里找平衡点。
衡量一个计算任务能不能发挥硬件峰值,常用"算术强度"这个概念:
算术强度 = 单位字节数据搬移对应的计算量(FLOPs/B)
Roofline模型会给出一个现实结论:实际性能 = min(峰值算力, 内存带宽 × 算术强度)。一个矩阵乘,理论上FLOPs很多,但如果数据搬移量设计不合理,实际性能会被带宽卡死。
举一个具体例子。一个 4096×4096×4096 的矩阵乘,计算量约 137 GFLOPs,如果用FP16精度的朴素算法直接做,需要搬运约 200 MB 的数据,算术强度大约只有 680 FLOPs/B。如果片上带宽只有 200 GB/s,那么性能上限就被死死摁在 136 TOPS 左右。但如果你把矩阵分块成 128×128 的小块,让数据在片上反复复用,算术强度能提高一个数量级,性能天花板随之大幅抬升。可以看到,硬件设计里那些看起来复杂的存储分块和调度逻辑,本质都在干一件事:提高算术强度。
2.3 精度选择是工程决策,不是技术选型
FP32、FP16、BF16、INT8、INT4,每个选择背后都牵动硬件面积、功耗、性能和精度四根弦。我见过只强调"高精度"而把芯片面积做爆的,也见过为了性能盲目量化最后模型精度崩了的。
实际经验是:训练阶段基本用FP32,推理阶段首选FP16/BF16与INT8混合方案。BF16的指数位和FP32一致,训练时更稳定;INT8的吞吐在同等面积下能做FP16的两倍甚至更多,是边缘推理芯片的主流选择。INT4则通常是极致性能场景下的妥协,需要配合更精细的量化训练和误差校正,不是谁都能驾驭。
这不是简单的"挑一个格式"。硬件上,混合精度意味着同一个计算阵列要支持多套数据通路、对齐逻辑和累加方案;软件上,编译器要能自动做精度转换和数据重排。协同设计的早期,最该明确的环节之一就是"精度方案定了没",因为一旦定了,后面所有环节都围着它转。
3. 硬件架构的三大主战场:计算阵列、片上存储与互连
3.1 脉动阵列 vs SIMD:两条路线的取舍逻辑
AI芯片的核心处理单元大致分两大流派:
| 维度 | 脉动阵列(Systolic Array) | SIMD/SIMT(类GPU) |
|---|---|---|
| 代表 | Google TPU | nVIDIA GPU |
| 控制开销 | 极低,数据像脉动一样流经各处理单元 | 高,每个指令需广播、每个线程需调度 |
| 峰值能效 | 高,逻辑基本全在乘加运算上 | 相对低,控制与调度电路占比高 |
| 灵活性 | 弱,稀疏性、不规则形状算子难处理 | 强,适应性好 |
| 典型弱点 | 依赖编译器保证数据不"空泡" | 访存瓶颈和缓存一致性复杂 |
实际商用NPU很少走极端路线。RK3588的NPU、Jetson系列里的深度学习加速器,大多是"向量单元 + MAC阵列"的混合体。向量单元处理归一化、激活函数、Attention里的杂活,MAC阵列专门跑矩阵乘和卷积。这个组合我倾向用一句话概括:用灵活性兜底,用专用性冲峰值。
3.2 存储墙怎么破:从HBM到片上SRAM的"数据不动计算动"
AI芯片领域有个老生常谈但不得不谈的问题:存储墙。外部DRAM带宽的增长速度远跟不上算力增长速度,于是芯片设计者们把大量SRAM搬到了片上,尽量让数据在片上流动,减少进出片外的次数。这就是所谓的"数据不动计算动"。
具体到数据流策略,常见的几种:
- 权重固定(Weight Stationary):权重驻留在处理单元里,输入数据流过去,适合模型权重大于激活的场景。
- 输入固定(Input Stationary):输入留在片上,权重流动,适合大量不同卷积核共享输入的场合。
- 输出固定(Output Stationary):输出部分和累加器留在片上,减少中间结果的写回。
选择哪种数据流,其实是由模型本身的复用结构决定的。比如卷积操作里权重复用价值高,就常见权重固定;而全连接层或注意力机制里激活复用也可能成为主导。芯片架构师要做的,是让硬件数据流与主流模型的复用模式匹配,而不只是拼峰值算力。
3.3 NoC与总线:多核时代的"数据交通规划"
核一多,互连就成了瓶颈。传统的AXI等总线适合低吞吐的控制流和配置流,但AI载荷是典型的高吞吐持续数据流,多个核同时读写,极易发生拥塞。
所以现代AI芯片普遍引入NoC(片上网络)或者更复杂的交叉开关结构。NoC把数据包化,按路由规则在网格里传输,好处是可扩展性好,多核时不需要重写总线协议;代价是额外的路由节点延迟和面积开销。我见过一个项目,为了解决两个计算集群之间的通信拥塞,最后把互连从"共享总线"改为"2D Mesh NoC",峰值性能提升将近两倍,而面积只增了不到一成。
NoC的维度、链路带宽、缓存深度都值得精细调优。比如视频流类任务需要极低的延迟抖动,那NoC的仲裁策略就不能用简单的轮询,得做优先级调度。这块不做,软件栈优化得再好也白搭。
4. 软件栈决定芯片生死:编译器、算子库与运行时如何兑现性能
4.1 编译器:从PyTorch到下发给芯片的指令
AI编译器的核心目标,是把高层模型描述翻译成芯片能高效执行的底层指令。流程大致如下:
- 前端解析:读取PyTorch/ONNX模型,转换成中间表示(IR)。
- 图优化:算子融合、常量折叠、死节点消除。
- 布局转换:处理NCHW/NHWC等数据布局,匹配硬件存储排布。
- 算子分解:大算子拆成芯片支持的小算子组合,比如把一个大GEMM切成多个小块。
- 内存规划:每个张量分配在哪一级存储、何时分配、何时释放。
- 指令调度:按硬件流水线特性排布指令顺序。
- 代码生成:生成芯片可执行的二进制。
这里最简单的优化例子是算子融合。Conv + BN + ReLU三个算子如果不融合,中间结果要写回DRAM再读出来,来回多搬好几轮数据。融合成单个算子后,中间张量就留在片上寄存器里,性能提升往往非常可观。编译器的抽象层次越高,越能在这种"看似不起眼"的地方赚回大把性能。
真正的难点在于编译器几乎不存在通用的最优解。同一个模型在不同芯片上,最优图切分和数据布局完全不同。所以编译器架构通常要设计成"硬件描述抽象 + 自动调优"的组合:硬件相关规则下沉到后端,平台无关优化留到前端。
4.2 算子库:性能的最后一道防线
你可能觉得编译器已经做了大部分优化,但实际上,对很多成熟芯片来说,手工调优的算子库仍然是性能基石。比如一些知名移动端推理库,大量卷积和矩阵乘内核都是逐行逐指令手写的。
算子库的核心工作分两块:分块参数调优和指令级优化。分块参数决定数据搬移的粒度,指令级优化决定利用向量指令、减少流水线气泡。很多芯片刚流片回来时性能不达标,原因往往不是硬件本身不行,而是算子库还没跟上:一个3×3卷积硬是写成了通用矩阵乘在跑,性能自然大打折扣。
4.3 运行时和调度:多核AI芯片的"交通警察"
当芯片有多个计算核时,运行时负责把计算任务切分到不同核上,并管理数据依赖和数据搬移。
这里容易踩的坑是:任务切分不当导致负载不均。比如两个核,一个要跑非常重的GEMM,一个跑轻量算子,如果排程算法不感知算力差异,就会出现一个核累死一个核闲死。更复杂的是数据依赖,下一个算子的输入依赖上一个算子的输出,必须在正确的时间点做同步。运行时的调度粒度、同步机制、中断延迟,都会直接影响端到端性能。
5. 软硬件协同设计怎么做:从工作负载画像到性能模型校准
5.1 第一步:工作负载画像,把算法翻译成硬件需求
任何AI芯片设计,都应该从"工作负载画像"开始。所谓画像,就是把目标应用里的模型统计一遍,形成一个表格:
| 模型 | 主要算子 | 计算量 | 权重规模 | 激活规模 | 内存带宽需求 |
|---|---|---|---|---|---|
| ResNet-50 | 卷积 | 约8 GFLOPs | 约25 MB | 小,但中间特征图多 | 中等 |
| BERT-base | GEMM+Attention | 约22 GFLOPs | 约110 MB | 序列相关,显存占用大 | 高 |
| Llama-7B | 大GEMM+Attention | 每token约15 GFLOPs | 约14 GB(FP16) | 每token约几十KB | 极高 |
有了画像,才能做"反推":目标帧率/吞吐量是多少?反推出来需要多少MACs/s?多少内存带宽?多少片上存储?这些数字构成设计规格,而不是拍脑袋定TOPS。
5.2 设计空间探索:面积、功耗、性能的三角博弈
工作负载定了,硬件参数还面临大量选择:计算阵列多大、片上SRAM多大、主频多高、外部接口多少带宽。这是一场典型的面积-功耗-性能三角博弈,通常会建一个性能模型来做设计空间探索。
性能模型能在RTL之前给出粗估,让团队快速筛选参数。我在实际项目中见过一个很典型的案例:架构团队在探索时发现,把片上SRAM从4 MB加到6 MB,面积增加大约15%,但部分模型的性能提升接近40%,原因是很多算子的中间结果不再需要搬出片外。这种结论只有靠模型量化才能得到,靠拍脑袋很难发现。设计空间探索产出的通常是一个"Pareto前沿":一组不互相支配的配置,最后结合成本和功耗目标做最终选择。
5.3 性能模型、RTL仿真与实测的三次校准
协同设计最大的坑,是性能模型和最终芯片实测对不上。所以必须做三次校准:
- 模型校准:拿目标模型在性能模型上跑,看Roofline估算和实际预估差距在哪。
- RTL校准:RTL级仿真数据回填性能模型,修正模型中的假设误差,比如实际访存延迟、仲裁排队延迟这些。
- 硅后校准:流片回来后用benchmark实测数据回填,反过来修正模型和软件栈的调优方向。
很多团队的研发节奏是"流片回来才开始调软件",结果硅后调试周期被拖到半年。我强烈建议在RTL阶段就把软件栈的雏形搭出来,哪怕只能跑一个子集模型,也要尽早做端到端打通。芯片后端和芯片测试的资源最好也提前介入,因为关键路径问题和DFT覆盖率问题都会反过来限制软件能发挥的性能空间。
6. 从量产芯片回看协同设计:RK3588、Jetson Orin带来的启示
6.1 RK3588的NPU:终端场景的"够用即最优"
RK3588的NPU是一颗典型为端侧场景设计的加速器,不是追求极致算力的大杀器,而是用适量的算力加上强大的软件适配能力,去满足大量工业视觉、边缘计算、智能终端的需求。它的算力规格在同类里并不夸张,但开发者体验相对友好。
这种设计思路值得学的一点是"按场景定义规格":工业视觉任务大多是中低分辨率视频流和中小型检测模型,不需要超大上下文窗口的Transformer能力。设计团队把资源花在每路视频稳定处理、硬件编解码协同、多模型流水线切换的能力上,比一味堆TOPS更有价值。做硬件最怕的就是"什么都想做,什么都做不深"。
6.2 Jetson Orin为什么"好用":生态比硬件值钱
Jetson Orin Nano这类产品的算力在绝对数字上并不是最强的,但它在AI开发者里的口碑一直不错,核心原因就是软件生态成熟。它可以直接跑PyTorch,有相对完整的TensorRT管线,社区里"踩坑答案"多,从CUDA到JetPack SDK的路径清晰。对于项目开发来说,这种"到了就能用"的体验,价值不亚于把芯片性能再提20%。
对比之下,很多自研AI芯片最大的短板不是硬件,而是工具链断裂:模型转换报错、算子缺失、文档过时,导致客户花三周都跑不通一个demo。做AI芯片项目,一定要把软件工具链和开发者体验纳入核心指标,否则芯片做得再强也没人愿意用。
6.3 给想入行AI芯片的工程师的实践路径
如果你正想进入这个领域,我的建议是:先别急着写RTL,先把算法模型的部署跑通。至少用PyTorch训练或转化一个小模型,然后做一次量化、编译、上板全流程。你可以从STM32N6或树莓派加NPU套件入手,体会"模型到硬件"的完整链路。然后再深入编译器的算子融合与循环优化,最后才是研究计算阵列与数据流。这个顺序帮你在脑子里建立"算法-软件-硬件"的闭环,思维一下子就通了。
最后再说一点我个人的经验:AI芯片的软硬件设计,与其说是技术问题,不如说是个系统工程问题。所有环节都必须从模型出发,又回到模型上去验证。这个系列第一篇把框架搭起来了,下一篇我打算专门拆编译器里的算子融合和内存规划,那才是最考验细节、也是最容易拉开性能差距的地方。