1. 从一张算力卡说起:AI芯片软硬件协同到底在解决什么问题
如果你最近两年接触过模型训练或推理部署,大概率会有一种强烈的割裂感:硬件参数表上写着几百 TFLOPS 的峰值算力,实际跑起模型来利用率却常常只有百分之二三十,甚至更低。这不是某一家的产品缺陷,而是整个 AI 芯片领域最核心的矛盾——峰值算力不等于有效算力。把这个问题拆开看,它牵扯的正是软硬件设计如何配合:芯片的矩阵计算单元、片上存储层次、片间互联带宽,这些是硬件侧的事;而算子调度、内存复用、精度量化、编译优化,这些是软件侧的事。两者任何一边掉链子,最终都会体现在那张“利用率曲线”上。
我写这篇东西的出发点,是想把 AI 芯片软硬件设计这条链路从头到尾捋一遍。它适合三类人看:一是刚进入这个方向、被各种缩写和架构名词绕晕的工程师;二是做算法或模型部署、想搞清楚底层到底发生了什么的应用侧同学;三是做系统集成、需要判断一颗芯片到底适不适合自己业务的技术决策者。我不会只讲概念,而是尽量把“为什么这么设计”“这么设计会带来什么代价”“实际调优时该盯哪些指标”讲透。
先给一个整体判断:AI 芯片的软硬件设计,本质上是在算力、带宽、功耗、灵活性这四个维度之间做取舍。硬件决定了取舍的边界,软件决定了你能逼近这个边界多远。一颗设计得再好的芯片,如果没有配套的编译器和算子库,实际表现可能连设计目标的零头都达不到;反过来,一个再聪明的调度算法,也救不了一颗带宽被卡死的芯片。所以这两件事必须放在一起谈,割裂地看任何一边都是耍流氓。
接下来的内容,我会按“硬件架构怎么选—软件栈怎么搭—协同优化怎么做—实测怎么调”这条主线展开,中间穿插一些我在实际项目里踩过的坑和总结出来的判断方法。文中涉及的具体产品、团队、项目一律用代称,重点在方法论和可复现的思路。
2. 硬件侧的核心取舍:为什么AI芯片不是“堆算力”这么简单
2.1 计算单元:矩阵乘加阵列的规模不是越大越好
AI 芯片里最显眼的部分就是那个巨大的矩阵计算阵列,通常是脉动阵列(Systolic Array)或者类似的二维乘加结构。直觉上,阵列越大,单周期能处理的乘加操作越多,峰值算力越高。但实际设计时,阵列规模受制于好几个因素。
第一个是数据复用率。矩阵乘法里,一个输入元素会被反复使用多次。阵列越大,理论上数据复用窗口越大,但前提是你的数据供给能跟上。如果片上缓存带宽不够,大阵列就会频繁“饿死”,利用率暴跌。我见过一个模拟项目,把阵列从 64x64 扩到 128x128,理论算力翻四倍,但实测某些算子只提升了不到一倍,原因就是缓存带宽没同步扩展。
第二个是利用率随形状变化。真实模型的矩阵形状千奇百怪,有很“瘦高”的,也有很“扁平”的。一个方形的大阵列在处理非方形矩阵时,边缘会有大量计算单元闲置。所以现在很多设计会采用可重构阵列,或者用多个小阵列组合来适配不同形状。选型时要问自己:我的业务里主流算子的矩阵形状分布是什么样的?如果全是方阵,大阵列划算;如果形状很杂,灵活的中等规模阵列可能更实用。
第三个是功耗密度。阵列越大,单位面积功耗越高,散热和供电设计难度陡增。这在边缘侧芯片上尤其致命。所以边缘 AI 芯片往往走小阵列加高主频,或者干脆用 DSP 加专用加速器的混合路线,而不是一味堆矩阵规模。
2.2 存储层次:带宽往往比算力更早成为瓶颈
这是我最想强调的一点。很多人在评估 AI 芯片时,第一眼看算力数字,第二眼看功耗,却把存储带宽放在很后面。但实际部署中,内存带宽经常是最先撞墙的那堵墙。
AI 计算的一个显著特征是“计算密集”和“访存密集”并存。卷积层里,权重和激活值的搬运量很大;注意力机制里,KV 缓存的读写更是带宽杀手。如果片外内存带宽不够,计算单元再强也只能干等。一个粗略的经验公式是:每瓦算力对应的带宽需求。你可以算一下目标芯片的算力带宽比,再对比你模型的实际需求。如果比值明显偏低,那这颗芯片跑大模型时大概率会卡在带宽上。
片上存储的设计同样关键。多级缓存、暂存器(Scratchpad)、寄存器堆的容量和访问延迟,直接决定了算子能不能高效流水。这里有个常见误区:以为缓存越大越好。实际上,缓存大了访问延迟可能上升,而且面积和功耗代价高。好的设计是根据主流算子的数据局部性来定制缓存层次,而不是无脑堆容量。
2.3 互联:多芯片扩展时的隐形天花板
单芯片算力总有上限,所以现在做大规模训练基本都要多芯片互联。这时候互联带宽和拓扑结构就成了新的瓶颈。片间互联如果带宽不足,多芯片并行时的通信开销会吃掉大部分收益,出现“加卡不加速度”甚至“加卡变慢”的情况。
互联设计要考虑几个维度:带宽、延迟、拓扑、可扩展性。全连接拓扑延迟低但成本高,环形或网状拓扑成本低但跳数多、延迟高。实际选型要看你的并行策略:数据并行对带宽要求高但模式简单,模型并行和张量并行对延迟和拓扑更敏感。我个人的经验是,如果业务以推理为主,单芯片或小规模互联往往就够;如果要做大模型训练,互联设计必须和并行策略一起考虑,不能分开决策。
2.4 精度支持:不是所有场景都需要 FP32
AI 芯片对精度的支持范围,直接影响它的适用场景和成本。训练通常需要 FP32 或 BF16/TF32 来保证数值稳定性,推理则可以用 FP16、INT8 甚至 INT4。硬件如果原生支持低精度计算,就能在同样面积下获得更高的吞吐和更低的功耗。
但这里有个坑:低精度不是免费午餐。量化会引入精度损失,需要软件侧做校准和补偿。如果硬件只支持粗暴的截断量化,而软件又没有好的量化感知训练方案,最终模型精度可能掉得没法用。所以看一颗芯片的精度支持时,不能只看它“支持 INT8”,还要看它的量化粒度、是否有混合精度通路、软件工具链是否成熟。
3. 软件栈的搭建逻辑:编译器、算子库和运行时各管什么
3.1 编译器:把模型图翻译成硬件能执行的指令
软件栈里最核心也最难做的部分就是编译器。它的任务是把上层框架(比如 PyTorch、TensorFlow)导出的计算图,经过一系列优化,最终生成硬件能执行的指令序列。这个过程大致分几步:图优化、算子融合、内存分配、指令调度、代码生成。
图优化包括常量折叠、死代码消除、算子替换等,目的是减少计算量。算子融合是把多个小算子合并成一个大算子,减少中间结果的读写。这一步对性能影响极大,因为 AI 计算里很多时间花在数据搬运上,融合能显著降低访存开销。内存分配要解决的是片上缓存和片外内存的分配问题,好的分配策略能大幅减少数据搬运。指令调度则要考虑硬件的流水线特性,把计算和搬运重叠起来。
编译器做得好不好,直接决定了芯片的“实际可用算力”。我见过一些芯片,理论算力很漂亮,但编译器只能支持有限的算子组合,遇到不支持的算子就回退到 CPU,性能断崖式下跌。所以评估一颗芯片时,一定要问:编译器支持哪些算子?不支持时怎么办?融合策略有多激进?
3.2 算子库:手写优化的最后一道防线
编译器再聪明,也不可能对所有算子都生成最优代码。所以成熟的 AI 芯片都会配一套手写优化的算子库,针对常见算子(卷积、矩阵乘、注意力、归一化等)做极致调优。这些算子库通常由硬件厂商的工程师针对自家芯片微架构手工编写,能充分利用硬件的特殊指令和存储层次。
算子库的覆盖度和质量,是衡量芯片软件成熟度的关键指标。覆盖度不够,模型就跑不起来;质量不高,性能就上不去。实际选型时,可以拿自己业务里的核心模型去测,看有多少算子能命中库里的优化版本,命中的那些性能如何。如果大量算子需要回退到通用实现,那这颗芯片的实际表现就要打问号。
3.3 运行时与驱动:调度、内存管理和多卡通信
运行时负责在模型执行时做动态调度,包括任务分发、内存管理、多流并行、多卡通信等。这部分往往被忽视,但它对实际性能影响很大。比如内存管理,如果运行时不能高效复用内存,模型稍微大一点就 OOM;如果多卡通信调度不好,并行效率就会很低。
驱动层则负责和硬件打交道,包括指令下发、中断处理、状态监控等。驱动不稳定,整个系统就会频繁出问题。我在实际项目里遇到过驱动导致的计算结果偶发错误,排查了很久才发现是驱动在高负载下的一个竞态条件。所以驱动和运行时的成熟度,是芯片能否上生产环境的重要前提。
3.4 框架对接:让算法工程师无感迁移
再好的软件栈,如果算法工程师用起来很别扭,推广就会受阻。所以框架对接层要做的事,是让用户尽量用原生框架的写法就能跑在目标芯片上。常见做法是提供框架插件或后端,把框架的算子映射到自家算子库,同时处理设备管理、数据搬运等细节。
这里的关键是兼容性和透明性。用户不希望为了用一颗新芯片而重写模型。所以对接层要尽量做到:支持的算子自动映射,不支持的给出明确提示,性能差异有文档说明。我见过做得好的,用户改一行代码就能切换设备;也见过做得差的,用户得手动改几十处才能跑通,这种推广起来就很吃力。
4. 软硬件协同优化:那些单看一边永远想不明白的事
4.1 算子融合的边界:硬件存储层次决定融合策略
算子融合是软硬件协同最典型的例子。从软件角度看,融合越多越好,因为能减少访存。但融合能不能做、能做到什么程度,取决于硬件的存储层次。如果两个算子融合后中间结果太大,超出片上缓存容量,那就只能写回片外内存,融合反而增加了复杂度却没省下搬运。
所以好的融合策略是硬件感知的:编译器要知道片上缓存有多大、各级存储的带宽和延迟是多少,然后据此决定融合哪些算子、中间结果放哪里。这也是为什么同一套编译器,在不同芯片上需要不同的调优参数。脱离硬件谈融合策略,就是纸上谈兵。
4.2 精度与性能的平衡:量化策略要跟着硬件走
量化是另一个协同点。软件侧希望用尽量低的精度来省带宽、提吞吐,但硬件侧对低精度的支持程度不同。有的芯片 INT8 是原生支持,有的需要软件模拟,有的只支持对称量化,有的支持非对称。这些差异直接决定了量化方案的设计。
实际操作中,我通常建议先摸清硬件的量化能力边界,再设计量化策略。比如硬件只支持对称量化,那就尽量用对称量化友好的方法;硬件支持逐通道量化,那就用逐通道来减少精度损失。反过来,如果软件强行用硬件不擅长的方式量化,性能可能不升反降。
4.3 并行策略与互联拓扑的匹配
多卡并行时,并行策略和互联拓扑必须匹配。数据并行通信量大但模式规整,适合高带宽互联;模型并行通信频繁但单次数据量小,对延迟敏感;流水并行则介于两者之间。如果互联拓扑和并行策略不匹配,通信就会成为瓶颈。
我的一般做法是:先根据模型大小和单卡容量确定需要多少卡,再根据互联拓扑选择并行策略,最后根据实测通信开销微调切分方式。这个顺序不能反,否则容易做出“理论上可行、实测很慢”的方案。
4.4 编译期与运行期的分工
编译期能做静态优化,比如算子融合、内存预分配、指令调度;运行期能做动态优化,比如根据实际输入形状调整调度、动态选择算子实现。两者分工要合理:编译期做不了的留给运行期,运行期开销大的尽量在编译期解决。
一个常见问题是编译期过度优化,导致运行期灵活性不足。比如编译期把内存分配死了,运行期遇到动态形状就崩。另一个极端是编译期什么都不做,全丢给运行期,导致每次执行都有大量调度开销。好的设计是在两者之间找平衡,把稳定的优化放编译期,把变化的留给运行期。
5. 实测调优:从利用率曲线里读出问题
5.1 先建立基线:别急着优化,先知道现状
调优的第一步永远是建立基线。拿你的目标模型在目标芯片上跑一遍,记录几个关键指标:端到端延迟、吞吐、计算单元利用率、内存带宽利用率、功耗。这些指标是后续所有优化的参照系。
我见过很多人一上来就改代码、调参数,结果改了半天不知道有没有变好。没有基线,优化就是盲人摸象。基线还要分场景:单算子、单层、整个模型、多卡,每个层级的基线都要有,这样才能定位问题出在哪一层。
5.2 定位瓶颈:算力受限还是带宽受限
拿到基线后,第一件事是判断瓶颈类型。方法很简单:看计算单元利用率和内存带宽利用率。如果计算利用率高、带宽利用率低,那是算力受限,优化方向是减少计算量或提升计算效率;如果带宽利用率高、计算利用率低,那是带宽受限,优化方向是减少访存或提升数据复用。
还有一种情况是两者都不高,那可能是调度问题、同步问题或者算子实现太差。这时候要往下钻,看具体是哪个算子、哪个阶段拖了后腿。常用的手段是逐算子 profiling,把每个算子的耗时和访存列出来,找出异常项。
5.3 常见性能陷阱与应对
实际调优中,有几个陷阱特别常见。第一个是小算子过多,每个算子都有启动开销和访存开销,累积起来很可观。应对方法是算子融合,或者用批处理把小算子合并。第二个是内存分配碎片化,导致大块内存申请失败或频繁整理。应对方法是预分配内存池,或者用编译期内存规划。第三个是同步点过多,多流并行时频繁同步会打断流水。应对方法是减少不必要的同步,或者用异步机制。
还有一个容易被忽视的陷阱是数据布局转换。不同算子可能要求不同的数据布局,转换本身要花时间和带宽。好的做法是在模型层面统一布局,或者在算子融合时顺便完成转换。
5.4 多卡扩展的效率验证
多卡场景下,除了单卡指标,还要看扩展效率。理想情况下,N 卡应该接近 N 倍性能,但实际会有通信开销和负载不均。验证方法是:固定问题规模,逐步增加卡数,看吞吐增长曲线。如果增长明显低于线性,就要分析通信占比和负载分布。
通信占比高,可能是并行策略或互联拓扑的问题;负载不均,可能是切分方式不合理。这两类问题的解法不同,要先定位再动手。我个人的经验是,多卡调优里,切分方式的微调往往能带来意想不到的收益,值得多花时间。
6. 几个容易踩的坑和我的应对经验
6.1 别迷信峰值算力,要看有效算力
这是我最想反复强调的一点。峰值算力是理论值,实际能用到多少,取决于软件栈成熟度、模型结构、批大小、精度配置等一系列因素。评估芯片时,一定要用真实模型测有效算力,而不是看宣传页上的数字。我一般会算一个“算力达成率”,即实测有效算力除以峰值算力,这个比值比峰值本身更有参考价值。
6.2 软件栈成熟度比硬件参数更难评估
硬件参数是公开的,软件栈成熟度却很难量化。我的经验是看几个信号:算子库覆盖多少常用算子、编译器支持哪些框架、文档和示例是否完整、社区是否活跃、厂商是否提供调优工具。如果这些都不行,硬件再好也难用起来。实际选型时,可以要求厂商提供针对你业务模型的 benchmark,而不是只看通用 benchmark。
6.3 精度问题往往在最后才暴露
量化带来的精度损失,经常在模型上线前的最后测试才被发现。所以我的建议是:量化方案要尽早验证,不要等到部署阶段才做。验证时要覆盖业务的典型输入分布,不能只用公开数据集。如果发现精度不达标,要能快速回退到更高精度,所以硬件和软件都要支持混合精度。
6.4 散热和功耗是长期运行的隐形杀手
实验室里跑 benchmark 和机房长期运行是两回事。散热不好会导致降频,功耗高会推高运营成本。评估时要把散热和功耗纳入考量,尤其是边缘部署场景。我见过一些方案在实验室跑分很好,一到实际环境就因为散热问题性能腰斩。
6.5 生态锁定风险要提前考虑
不同芯片的软件栈往往不兼容,一旦选定,迁移成本很高。所以选型时要考虑生态开放性:是否支持标准框架、是否有跨平台中间表示、是否有迁移工具。如果业务可能长期演进,生态锁定风险值得认真评估。
7. 一个可复现的评估流程:拿到新芯片后我会怎么做
7.1 第一步:环境搭建与基础验证
拿到芯片和开发环境后,先跑通官方示例,确认驱动、运行时、框架对接都正常。然后跑一个标准模型(比如 ResNet 或 BERT 的小版本),记录基线指标。这一步的目的是确认环境没问题,同时建立初步的性能预期。
7.2 第二步:核心算子微基准测试
针对业务里的核心算子,写微基准测试,单独测每个算子的延迟、吞吐、访存。这一步能暴露算子库的质量和编译器的优化能力。如果某个算子性能异常,就要深入看它的实现和调度。
7.3 第三步:端到端模型测试与瓶颈定位
把完整模型跑起来,用 profiling 工具采集各阶段耗时和资源利用率,定位瓶颈。然后针对瓶颈做优化,每次只改一个变量,观察指标变化。这一步要耐心,不要一次改太多,否则无法归因。
7.4 第四步:多卡与长稳测试
如果涉及多卡,做扩展效率测试。然后做长稳测试,连续跑几个小时甚至几天,观察是否有性能衰减、内存泄漏、偶发错误。长稳测试能暴露很多短期测试发现不了的问题。
7.5 第五步:形成评估报告与选型建议
最后把测试结果整理成报告,包括有效算力、瓶颈分析、优化空间、风险点。这份报告是选型决策的依据,也是后续调优的起点。我一般会把报告分成“硬指标”和“软指标”两部分,硬指标是性能数据,软指标是易用性、生态、支持力度等。
8. 写在最后:一些个人体会
做 AI 芯片软硬件设计这些年,我最大的体会是:这是一个系统工程问题,没有银弹。硬件再强,软件跟不上就是废铁;软件再巧,硬件有硬伤也白搭。真正做得好的方案,一定是软硬件团队深度协作、反复迭代出来的。
另一个体会是,评估和调优的能力比单纯的设计能力更稀缺。能设计芯片的人不少,能准确评估一颗芯片实际表现、快速定位瓶颈的人却不多。这种能力需要大量实测经验积累,没有捷径。
最后分享一个小技巧:每次遇到性能问题,先问自己“这是算力问题还是带宽问题”,这个简单的二分法能帮你快速缩小排查范围。大部分 AI 计算问题,最终都能归到这两类里。把这两类问题的典型特征和应对手段记熟,调优效率会高很多。