1. AI芯片软硬件协同设计的核心逻辑
1.1 为什么软硬件必须一起设计
很多刚接触AI芯片的朋友会有一个误区,觉得芯片设计就是硬件工程师的事,软件是后面才需要考虑的。这个想法在传统CPU时代或许还说得过去,但在AI芯片领域,软硬件脱节基本等于项目失败。
我参与过几个AI加速芯片的早期架构讨论,最深的体会是:AI芯片的性能天花板,往往不是由峰值算力决定的,而是由数据搬运效率和软件调度能力共同决定的。一颗标称256 TOPS的芯片,如果软件调度不当,实际利用率可能连30%都不到。这不是危言耸听,而是行业里反复验证过的事实。
为什么会出现这种情况?因为AI计算和传统通用计算有本质区别。传统CPU处理的是逻辑分支密集、数据依赖复杂的任务,硬件设计围绕指令级并行和缓存层次做优化就行。但AI计算,尤其是深度学习推理和训练,核心是大规模的矩阵乘加运算,数据流模式相对规整,却对内存带宽和片上缓存极度敏感。
这就引出一个关键问题:算力、带宽、缓存三者之间的平衡,必须在架构设计阶段就和软件栈一起考虑。硬件团队如果只盯着MAC阵列的规模,软件团队如果只关心算子覆盖率,两边各干各的,最后拼在一起就会发现——数据喂不进去,算力空转。
1.2 软硬件协同的三个层次
我把AI芯片的软硬件协同分为三个层次,从浅到深分别是:
第一层:接口协同。这是最基础的,硬件定义好寄存器接口、DMA描述符格式、中断机制,软件按照约定去读写。很多初创团队停在这一层,觉得能跑通模型就行了。但这一层只解决了“能用”的问题,离“好用”还差得远。
第二层:调度协同。硬件提供多核、多引擎的并行能力,软件需要知道什么时候该用哪个引擎、数据怎么分块、任务怎么流水线化。这一层要求软件团队深入理解硬件的微架构细节,比如每个计算单元的吞吐率、延迟、缓存行大小。
第三层:架构协同。这是最高层次,软件团队在芯片定义阶段就介入,根据主流模型的计算特征反推硬件应该支持哪些指令、缓存怎么设计、片上网络怎么拓扑。谷歌的TPU就是典型例子,软件团队和硬件团队从第一天就在一起工作。
实操心得:如果你所在的团队规模不大,至少要做到第二层。具体做法是,让负责编译器或运行时调度的工程师,每周和硬件架构师开一次同步会,把最近跑的热门模型的计算图拿过来,一起看哪些算子在硬件上效率低,是硬件改还是软件绕。
1.3 一个真实的踩坑案例
我之前接触过一个项目,硬件团队设计了一款面向边缘推理的AI加速器,MAC阵列规模不小,理论算力很漂亮。但软件团队拿到芯片后才发现,片上缓存只有256KB,而且不支持细粒度的数据复用。结果跑ResNet-50的时候,每一层的特征图都要反复从DRAM搬运,实际帧率只有理论值的四分之一。
后来复盘,问题出在架构定义阶段:硬件团队参考的是几年前的模型结构,那时候特征图还比较小,256KB勉强够用。但新的模型,中间层特征图动辄几MB,缓存根本装不下。如果软件团队早一点介入,把主流模型的内存访问模式分析清楚,硬件团队就会知道该把缓存做大,或者设计更灵活的缓存分块机制。
这个案例说明一个道理:AI芯片的硬件参数不是拍脑袋定的,必须由软件侧的真实负载来驱动。
2. 硬件设计的关键模块与选型考量
2.1 计算阵列:MAC规模不是越大越好
AI芯片的计算核心通常是MAC(乘加单元)阵列。很多初入行的团队会本能地追求更大的阵列,觉得TOPS数字越高越有竞争力。但实际设计中,MAC阵列的规模受限于几个因素:
第一,数据供给能力。每个MAC每个周期需要两个操作数,如果阵列是256x256,那就是65536个MAC,每周期需要131072个操作数。假设频率是1GHz,数据位宽是8bit,那每秒需要搬运的数据量是131072字节,也就是约131GB/s。这还只是输入,还没算输出和权重。如果片上缓存和DRAM的带宽跟不上,阵列再大也是空转。
第二,功耗和面积。MAC阵列的功耗和面积基本是线性增长的。在边缘设备上,功耗预算是硬约束,阵列规模必须妥协。
第三,利用率。大阵列在处理小矩阵时利用率会急剧下降。比如一个256x256的阵列,处理64x64的矩阵乘,利用率只有6.25%。所以现在很多芯片采用可重构的设计,把大阵列拆成多个小阵列,根据任务动态组合。
下面这张表是我在实际项目中总结的MAC阵列规模与适用场景的对应关系,供参考:
| 阵列规模 | 典型算力(INT8) | 适用场景 | 主要约束 |
|---|---|---|---|
| 32x32 | 0.5-2 TOPS | 超低功耗边缘设备 | 功耗<1W,模型需量化 |
| 64x64 | 2-8 TOPS | 边缘推理盒子 | 散热和成本 |
| 128x128 | 8-32 TOPS | 车载、工业视觉 | 带宽需求高 |
| 256x256 | 32-128 TOPS | 数据中心推理 | 功耗和面积 |
| 512x512以上 | 128 TOPS以上 | 训练或超大规模推理 | 需要HBM等高端存储 |
注意:这张表是基于常见实践的经验值,具体项目还要看工艺节点、频率目标、存储方案。不要直接照搬,但可以用它来快速判断自己的需求落在哪个区间。
2.2 存储层次:带宽比容量更致命
AI芯片的存储设计,我个人的经验是:带宽问题比容量问题更常见,也更难解决。容量不够可以压缩、可以分块,但带宽不够就是硬伤,只能降频或者减少并行度。
典型的AI芯片存储层次包括:寄存器文件、片上缓存(SRAM)、片外DRAM(LPDDR、DDR、HBM)。每一层的带宽和延迟差异巨大:
- 寄存器文件:带宽极高,延迟1个周期,但容量极小
- 片上SRAM:带宽高,延迟几个周期,容量几十KB到几MB
- LPDDR5:带宽约50-100GB/s,延迟几百个周期
- HBM2e:带宽约400-800GB/s,延迟类似
设计时的核心原则是:让数据尽可能停留在离计算单元近的地方。具体手段包括:
- 权重常驻:对于推理场景,权重是固定的,可以提前加载到片上SRAM,避免每次从DRAM读取。这要求SRAM容量至少能装下模型的最大层权重。
- 特征图分块:把大的特征图切成小块,每块在片上缓存中完成计算后再写回。分块大小要匹配SRAM容量和计算阵列的尺寸。
- 双缓冲:在计算当前块的同时,预取下一块数据,隐藏DRAM延迟。
这些手段听起来简单,但实际调优时非常考验软件团队对模型结构的理解。比如Transformer类模型,注意力矩阵的大小随序列长度平方增长,分块策略就和CNN完全不同。
2.3 数据流架构:权重 stationary 还是输出 stationary
数据流架构决定了数据在计算阵列中的流动方式,直接影响带宽需求和能效。主流的数据流有三种:
权重固定(Weight Stationary):权重加载到PE后保持不动,输入特征图流动,输出部分和累积。这种架构适合权重复用率高的场景,比如卷积层。缺点是输出部分和需要频繁写回。
输出固定(Output Stationary):每个PE负责一个输出元素,输入和权重都流动。这种架构适合全连接层,但输入和权重的带宽需求都很大。
行固定(Row Stationary):折中方案,一行PE共享输入,权重在行内流动。这是Eyeriss提出的经典架构,能较好地平衡三类数据的复用。
实际芯片中,很少有纯用一种数据流的,通常是混合的。比如卷积层用权重固定,全连接层用输出固定。软件编译器需要根据算子类型选择合适的数据流配置。
实操心得:在架构定义阶段,建议用几个代表性模型(如ResNet、BERT、YOLO)做数据流仿真,统计不同数据流下的DRAM访问次数。这个数据比理论算力更能反映实际性能。
3. 软件栈的分层设计与实现要点
3.1 编译器:从计算图到硬件指令
AI芯片的软件栈中,编译器是最核心也最复杂的部分。它的任务是把深度学习框架导出的计算图,转换成硬件能执行的指令序列。这个过程大致分为几个阶段:
图优化:包括算子融合、常量折叠、死代码消除等。算子融合对AI芯片特别重要,因为很多小算子单独执行时,数据搬运的开销远大于计算本身。比如Conv+BN+ReLU,如果不融合,就要三次读写特征图;融合后,一次读写就够了。
算子选择:硬件可能对某些算子有专用加速单元,比如卷积、矩阵乘、激活函数。编译器需要判断哪些算子用专用单元,哪些用通用计算单元,哪些需要拆解成多个小算子。
内存分配:这是最考验编译器能力的地方。需要决定哪些张量放在片上SRAM,哪些放DRAM,什么时候预取,什么时候写回。好的内存分配策略能把DRAM访问次数降低一个数量级。
指令调度:把算子映射到具体的计算单元,安排执行顺序,插入同步和DMA指令。目标是最大化硬件利用率,减少空闲等待。
下面是一个简化的编译器流程示意,用文字描述:
计算图 -> 图优化 -> 算子选择 -> 内存分配 -> 指令调度 -> 硬件指令每个阶段都有大量的工程细节。比如图优化阶段,算子融合的规则需要根据硬件特性来定。如果硬件不支持某种融合模式,编译器就不能强行融合。
3.2 运行时:任务调度与资源管理
运行时是软件栈中直接和硬件驱动打交道的部分。它的核心职责包括:
- 任务队列管理:接收上层提交的推理或训练任务,按优先级排队。
- 内存管理:管理DRAM和SRAM的分配释放,处理内存碎片。
- 多核调度:如果芯片有多个计算核心,运行时需要把任务分配到不同核心,并处理核心间的同步。
- 性能监控:采集硬件计数器的数据,用于性能分析和调优。
运行时的设计难点在于低延迟和高吞吐的平衡。对于边缘设备,单次推理的延迟很重要;对于数据中心,吞吐量更重要。运行时需要根据场景配置不同的调度策略。
我见过一些团队,运行时写得比较粗糙,任务来了就顺序执行,没有流水线化。结果硬件明明支持多引擎并行,实际却串行执行,性能损失一半以上。后来改成异步任务队列,把DMA、计算、后处理重叠起来,吞吐量直接翻倍。
3.3 算子库:手写汇编还是自动生成
算子库是软件栈中最贴近硬件的部分,直接决定了单个算子的执行效率。实现方式有两种:
手写汇编/内联函数:针对每个算子,由经验丰富的工程师手写优化代码。优点是性能极致,能充分利用硬件的特殊指令和寄存器。缺点是开发周期长,移植性差,硬件改版就要重写。
自动代码生成:用TVM、Halide等工具,根据算子描述和硬件参数自动生成代码。优点是开发效率高,容易适配不同硬件配置。缺点是生成的代码质量参差不齐,复杂算子可能不如手写。
实际项目中,通常是混合策略:核心算子(如卷积、矩阵乘)手写优化,长尾算子用自动生成。这样既能保证关键路径的性能,又能覆盖足够的算子种类。
注意:手写算子虽然性能好,但维护成本很高。如果硬件团队还在快速迭代架构,建议先以自动生成为主,等架构稳定后再逐步替换关键算子。
4. 软硬件联合调优的实操方法
4.1 性能建模:在流片前预测瓶颈
AI芯片流片一次的成本动辄几百万甚至上千万,如果流片后才发现性能不达标,损失巨大。所以流片前的性能建模至关重要。
性能建模的方法有几种:
解析模型:用数学公式估算算力、带宽、延迟。比如用Roofline模型判断一个算子是计算受限还是带宽受限。这种方法快速但粗糙,适合早期架构探索。
周期精确仿真:用SystemC或Verilog仿真器,逐周期模拟硬件行为。精度高,但速度慢,跑一个完整模型可能要几小时甚至几天。
FPGA原型:把硬件设计综合到FPGA上,跑真实模型。速度比仿真快得多,但FPGA的频率和功耗与ASIC差异较大,需要做折算。
我的建议是:早期用解析模型快速筛选架构方案,中期用FPGA原型验证关键算子,后期用周期精确仿真做最终确认。三个阶段结合,既能控制时间,又能保证精度。
4.2 瓶颈定位:从端到端到算子级
当实际性能不达预期时,需要系统地定位瓶颈。我常用的方法是逐层下钻:
- 端到端分析:先看整个模型的推理时间,和理论值差多少。
- 逐层分析:用profiling工具统计每一层的耗时,找出最慢的几层。
- 算子内分析:对最慢的算子,看是计算单元利用率低,还是DMA等待时间长,还是缓存命中率低。
- 指令级分析:如果是手写算子,看汇编代码有没有流水线停顿、寄存器冲突。
这个过程中,硬件计数器的支持很关键。芯片设计时就要预留足够的性能计数器,比如MAC利用率、DMA带宽、缓存命中率、指令发射率等。没有这些数据,调优就是盲人摸象。
4.3 常见性能问题速查表
下面这张表是我在实际项目中遇到的高频问题及排查方向,供参考:
| 现象 | 可能原因 | 排查手段 | 解决方向 |
|---|---|---|---|
| MAC利用率低 | 数据供给不足 | 看DMA带宽和缓存命中率 | 优化分块,增加预取 |
| 推理延迟高 | 算子未融合 | 看计算图节点数 | 启用算子融合 |
| 多核负载不均 | 任务划分不合理 | 看各核利用率 | 调整任务分配策略 |
| 功耗超标 | 频率过高或电压过高 | 看功耗分布 | 降频或优化数据流 |
| 精度下降 | 量化误差累积 | 逐层对比浮点结果 | 调整量化策略 |
| 内存溢出 | 缓存分配不当 | 看内存占用曲线 | 优化内存复用 |
实操心得:这张表不是万能的,但能覆盖80%的常见问题。遇到新问题时,建议先按这个框架排查一遍,再深入细节。
5. 从项目实践看软硬件设计的取舍
5.1 通用性与专用性的平衡
AI芯片设计中最纠结的问题之一,就是通用性和专用性的取舍。太通用,性能上不去;太专用,模型一变就废了。
我的经验是:在指令集层面保持一定的通用性,在微架构层面针对主流算子做专用优化。比如,指令集可以支持通用的向量运算和矩阵运算,这样新算子可以通过组合现有指令实现。同时,针对卷积、矩阵乘、注意力等高频算子,设计专用的数据通路和缓存策略。
这样做的理由是:AI模型迭代太快,如果硬件只支持当前流行的算子,下一代模型出来就可能不适用。但完全通用的设计又无法在能效上竞争。折中方案是在可编程性和专用加速之间找平衡点。
5.2 工艺节点的选择
工艺节点直接影响芯片的功耗、面积和成本。对于AI芯片,选择工艺时需要考虑:
- 算力需求:高算力通常需要先进工艺,因为功耗和面积约束更紧。
- 成本预算:先进工艺的流片成本高,但单位算力成本可能更低。
- 上市时间:先进工艺的PDK成熟度和IP可用性可能影响进度。
我见过一些团队,为了追求指标,盲目选择最先进的工艺,结果因为IP不成熟、良率低,项目延期严重。也有团队过于保守,用了老工艺,结果功耗降不下来,产品没有竞争力。
我的建议是:选择比当前主流稍晚一代的工艺。比如主流是7nm时,选12nm或16nm。这样既能享受工艺红利,又能规避最先进工艺的风险。
5.3 软硬件团队的协作模式
最后聊聊团队协作。AI芯片项目失败的原因,技术问题占一半,协作问题占另一半。软硬件团队如果各干各的,最后集成时必然出问题。
有效的协作模式包括:
- 联合架构评审:硬件架构定义时,软件团队必须参与,从软件角度评估可行性和效率。
- 共享仿真环境:软件团队能在硬件仿真器上跑模型,硬件团队能看到真实负载的性能数据。
- 定期性能对齐:每周同步性能数据,及时发现偏差。
- 联合调试:流片回来后,软硬件工程师一起调试,而不是互相甩锅。
这些做法听起来简单,但执行起来需要组织架构和考核机制的支持。如果硬件团队只考核PPA,软件团队只考核算子覆盖率,那协作就是空话。
6. 写在最后的一些个人体会
做AI芯片软硬件设计这些年,最大的感受是:这个领域没有银弹,只有权衡。每一个设计决策,都是在性能、功耗、面积、成本、灵活性之间做取舍。没有绝对正确的答案,只有适合当前场景的方案。
另外,AI芯片和传统芯片最大的不同,是软件生态的重要性被放大了。一颗芯片硬件再好,如果没有好用的软件栈,开发者不愿意用,最终也是失败。所以,如果你正在做AI芯片,一定要把软件团队放在和硬件团队同等重要的位置,甚至更重要。
最后分享一个小技巧:在项目早期,用Excel做一个简单的性能模型,把算力、带宽、缓存、功耗的关键参数列出来,然后手动调整参数,看性能怎么变。这个模型不需要很精确,但能帮你快速理解各个参数之间的制约关系。很多架构决策,在这个阶段就能看出方向。