
1. AI 芯片软硬件协同设计的核心命题搞 AI 芯片这行当绕不开一个根本矛盾算法迭代以月为单位芯片流片以年为单位。你不可能为每一个新出的网络结构都重新设计一版硅片所以必须找到一种方法让硬件在保持足够灵活性的同时还能把矩阵乘加这类核心运算做到极致的能效比。这就是软硬件协同设计存在的意义——它不是简单的“软件适配硬件”或者“硬件支持软件”而是在架构定义阶段就把两边的人拉到同一张桌子上用同一套语言讨论问题。我接触过不少团队硬件组闷头把 MAC 阵列堆到几千个软件组拿到 RTL 之后才发现数据搬运根本喂不饱计算单元最后实际利用率不到三成。这种教训在行业里反复上演根源就在于缺乏对“数据流”的统一认知。AI 芯片的软硬件设计本质上是在设计一套数据在存储层次和计算单元之间流动的规则而脉动阵列、数值格式这些具体技术都是这套规则下的实现手段。这篇文章面向的是有一定数字电路基础、想深入了解 AI 加速器设计细节的工程师也适合做模型部署的算法同学用来理解硬件侧的约束。我会从架构选型的逻辑讲起把脉动阵列的工作原理拆开揉碎再深入 FP8 这类低精度格式的设计取舍最后落到实际的量化部署流程上。每个环节我都会解释“为什么这么选”而不只是“是什么”。2. 脉动阵列为什么它成了矩阵乘法的首选架构2.1 从冯诺依曼瓶颈说起传统处理器做矩阵乘法每算一次乘加都要从寄存器文件或缓存里取两个操作数算完再写回去。这个过程中计算单元大部分时间在等数据真正用于运算的周期可能只有百分之几。AI 芯片里矩阵乘法的操作数复用率极高——一个权重值要和很多个激活值相乘一个激活值也要和很多个权重相乘——如果能让数据在计算单元之间“流动”起来而不是每次都回存储取就能大幅降低对存储带宽的需求。脉动阵列Systolic Array的核心思想就是让数据像心跳一样有节奏地流过计算阵列。每个计算单元只负责一个乘加操作然后把结果传给下一个单元数据在阵列中一步步“脉动”前进。权重预先加载到各个 PE 中并保持不动激活值从左侧流入、从右侧流出部分和从上往下累积。这样每个 PE 在每个周期都能做一次有效的乘加不需要频繁访问外部存储。2.2 脉动阵列的数据流拆解以一个 4x4 的脉动阵列为例假设我们要计算矩阵 A4x4乘以矩阵 B4x4。在经典的权重固定Weight Stationary数据流中B 的每一列被预先加载到对应列的 PE 中A 的每一行从左侧依次流入。具体来说第 0 个周期A[0][0] 进入 PE(0,0)与预存的 B[0][0] 相乘结果暂存。第 1 个周期A[0][1] 进入 PE(0,1)同时 A[0][0] 从 PE(0,0) 向右传到 PE(0,1) 的左侧输入PE(0,0) 接收 A[1][0] 开始第二行的计算。以此类推每个 PE 在每个周期都执行一次乘加部分和沿着垂直方向向下传递最终从底部输出完整的结果。这种结构的精妙之处在于数据复用是“空间换时间”的典型体现。一个权重值被加载一次就能和整行激活值相乘一个激活值流过整列就能和整列权重相乘。实际芯片中阵列规模通常是 16x16 到 256x256 不等规模越大数据复用率越高但布线延迟和面积开销也越大。2.3 脉动阵列的局限与变体脉动阵列不是万能的。它的效率高度依赖于矩阵维度与阵列维度的匹配程度。如果矩阵是 100x100 而阵列是 128x128边缘的 PE 就会闲置利用率降到约 61%。更麻烦的是Transformer 类模型里存在大量非矩阵乘操作比如 LayerNorm、Softmax、激活函数这些在脉动阵列上跑效率很低需要额外的向量处理单元来配合。所以现代 AI 芯片很少用纯脉动阵列而是采用“脉动阵列 向量单元 标量单元”的异构架构。脉动阵列负责矩阵乘向量单元处理逐元素运算标量单元做流程控制。软件侧需要把算子合理映射到不同单元上这就引出了编译器和调度器的设计问题。实操心得设计脉动阵列时阵列维度不要盲目求大。我见过一个团队为了追求峰值算力把阵列做到 256x256结果布线拥塞导致频率只能跑到 800MHz实际算力还不如 128x128 跑 1.5GHz 的版本。建议先用面积和频率的折中模型估算再决定阵列规模。3. 数值格式的博弈从 FP32 到 FP8 的演进逻辑3.1 精度与能效的权衡AI 芯片设计里数值格式的选择直接决定了乘法器的面积、功耗和精度。FP32 乘法器面积大约是 FP16 的 4 倍功耗是 3 倍以上。而神经网络对精度的容忍度出奇地高——推理阶段用 FP16 甚至 INT8 往往精度损失不到 1%。这就给了硬件设计巨大的优化空间。早期 AI 芯片多用 INT8因为整数乘法器面积小、功耗低。但 INT8 的问题是动态范围太窄只有 256 个离散值遇到激活值分布跨度大的层就容易溢出或精度崩塌。FP16 动态范围大但尾数只有 10 位精度又不够。于是业界开始探索介于两者之间的格式比如 BF168 位指数 7 位尾数和 TF328 位指数 10 位尾数以及后来专门为深度学习设计的 FP8。3.2 FP8 的两种变体E4M3 与 E5M2FP8 有两种主流格式E4M34 位指数 3 位尾数和 E5M25 位指数 2 位尾数。E4M3 精度更高但动态范围小适合前向传播的激活值和权重E5M2 动态范围大但精度低适合梯度计算。实际训练中通常混合使用两种格式前向用 E4M3反向用 E5M2这样既保证了精度又控制了误差累积。从硬件角度看FP8 乘法器可以复用 FP16 乘法器的部分电路面积增加不多但吞吐量翻倍。NVIDIA 从 Hopper 架构开始支持 FP8国内不少 AI 芯片也跟进。关键是软件栈要能自动完成格式转换和缩放因子管理否则精度问题会让模型效果大打折扣。3.3 量化误差的传播与控制低精度格式最大的风险是误差在层间传播放大。假设每层引入 0.1% 的相对误差50 层之后累积误差可能超过 5%足以让分类结果完全跑偏。控制误差的核心手段是缩放因子Scale Factor的精细管理。每一层的激活值分布不同需要独立的缩放因子把数值映射到 FP8 的可表示范围内。实际部署中通常用校准数据集跑一遍前向传播统计每层激活值的最大值和分布然后计算最优缩放因子。这个过程叫“校准”Calibration是量化部署的关键步骤。校准不充分会导致某些层溢出校准过度又会浪费精度位。格式指数位尾数位动态范围典型用途FP32823极大训练基准FP16510大推理/训练BF1687大训练FP8 E4M343中前向推理FP8 E5M252大反向梯度INT8-7小推理注意事项FP8 的缩放因子不是静态的。某些模型在推理时激活值分布会随输入变化静态缩放因子可能在某些输入下溢出。建议对关键层采用动态缩放每批次重新计算缩放因子代价是额外的计算开销。4. 软硬件协同的实操流程4.1 从模型到硬件的映射路径一个典型的 AI 芯片部署流程是这样的模型训练完成后先用编译器把计算图拆解成硬件支持的算子集合然后做量化校准把 FP32 权重和激活值转成 FP8 或 INT8接着做算子融合和内存调度最后生成硬件可执行的指令流。这个流程里每一步都可能引入精度损失或性能瓶颈。编译器需要知道硬件的具体参数脉动阵列的维度、各级缓存的容量和带宽、支持的数据格式、指令发射的延迟。这些信息通常以硬件描述文件的形式提供给编译器。软件团队和硬件团队需要共同定义这个描述文件的格式和内容这是协同设计最具体的落地点。4.2 算子融合的收益与陷阱算子融合是提升性能的重要手段。比如把 Conv Bias ReLU 融合成一个算子中间结果不用写回内存直接留在寄存器里。在脉动阵列上这意味着卷积的输出可以直接流入向量单元做激活省去了一次全局内存往返。实测下来融合通常能带来 20% 到 40% 的性能提升。但融合不是越多越好。过度融合会导致寄存器压力过大编译器被迫插入溢出代码反而降低性能。而且融合后的算子如果太大会降低调度的灵活性遇到不同形状的输入时可能无法适配。我的经验是优先融合那些中间结果尺寸大、复用率高的算子对比如矩阵乘后面的逐元素操作。4.3 内存层次的设计考量AI 芯片的性能瓶颈往往不在计算而在内存带宽。脉动阵列再快数据供不上也是白搭。所以内存层次的设计要和计算阵列匹配寄存器文件要能支撑 PE 的吞吐共享缓存要能支撑阵列的吞吐全局内存要能支撑整个芯片的吞吐。一个实用的估算方法是假设脉动阵列是 128x128每个周期做 16384 次乘加每次乘加需要两个操作数各 1 字节 FP8那么每周期需要 32KB 的数据供给。如果频率是 1GHz带宽需求就是 32TB/s。这个数字远超当前任何外部存储的带宽所以必须靠片上缓存和寄存器复用把大部分数据留在芯片内。实际设计中权重通常常驻在 PE 的寄存器里激活值在阵列中流动复用只有少量数据需要从全局内存加载。5. 常见问题与排查技巧实录5.1 精度崩塌的排查思路模型量化后精度掉得厉害是最常见的问题。排查时按这个顺序走先看是哪一层开始出现大的误差通常是对数值范围敏感的层比如第一层卷积和最后的分类层。然后检查这些层的缩放因子是否合理是不是有溢出或下溢。如果缩放因子没问题再看是不是某些特殊操作如 Softmax、LayerNorm在低精度下不稳定这些操作往往需要保留 FP16 或 FP32。我遇到过一个案例模型在 FP8 下精度掉了 15%排查发现是残差连接处的加法在低精度下累积误差。解决办法是把残差加法保留在 FP16只对卷积和矩阵乘用 FP8精度恢复到 1% 以内性能只损失了 5%。5.2 脉动阵列利用率低的定位方法如果实测性能远低于理论峰值先算一下阵列利用率。方法是统计实际执行的乘加次数除以阵列维度乘以周期数。如果利用率低于 50%通常是矩阵维度不匹配或者数据供给不足。维度不匹配可以通过 padding 或分块解决数据供给不足则需要检查缓存命中率和带宽。还有一个容易被忽略的点是指令发射开销。如果每个小算子都要重新配置阵列配置时间可能比计算时间还长。解决办法是把多个小算子合并成一个大算子或者用流水线方式让配置和计算重叠。5.3 常见问题速查表问题现象可能原因排查方法解决方向量化后精度骤降缩放因子不当逐层对比误差重新校准或混合精度阵列利用率低维度不匹配统计实际乘加数Padding 或分块性能低于预期内存带宽不足检查缓存命中率优化数据复用编译时间过长算子融合过度查看融合后算子数调整融合策略推理结果不稳定动态范围溢出检查激活值分布动态缩放或回退精度实操心得调试 AI 芯片时一定要有逐层对比的工具链。把硬件上每一层的输出和 GPU 上的参考输出做对比能快速定位问题层。没有这个工具排查精度问题就像盲人摸象。6. 从设计到部署的几点个人体会做 AI 芯片软硬件设计这些年最大的体会是不要试图设计一个“通用”的加速器。通用意味着什么都能跑但什么都跑不快。成功的 AI 芯片都是在特定场景下做到极致比如专门优化 Transformer 的注意力机制或者专门优化卷积网络的通道复用。场景越聚焦软硬件协同的收益越大。另一个体会是数值格式的选择要跟着模型走而不是跟着硬件走。硬件支持 FP8 不代表所有模型都适合 FP8。有些模型对精度敏感强行上 FP8 只会得不偿失。量化策略应该是模型、数据、硬件三者共同决定的没有一刀切的方案。最后软硬件协同不是一次性的工作而是一个持续迭代的过程。模型在变硬件在变编译器也在变。建立一套自动化的精度和性能回归测试流程比任何单点优化都重要。我见过太多团队在流片后才发现某个算子不支持或者某个精度配置有问题这时候再改已经来不及了。把问题暴露在流片之前是软硬件协同设计最核心的价值。