资讯动态

AI芯片软硬件协同设计:从峰值算力到有效算力的优化实践

发布时间:2026/10/20 23:30:57 来源:尧图企业网站定制
1. 从能跑就行到跑得省电AI芯片软硬件协同设计的核心命题做AI芯片这行的人大概都经历过这样一个阶段模型在仿真环境里跑通了精度也达标了团队欢呼雀跃觉得大功告成。结果一上板子功耗直接爆表散热压不住频率被迫降档实际吞吐量连理论值的一半都不到。这种仿真猛如虎实测二百五的落差几乎成了每一代AI加速器项目都要交的学费。这个系列写到第五篇我想把话题收拢到一个最容易被低估、却最能决定产品成败的交叉地带——软硬件协同设计。注意这里说的协同不是一句口号而是指硬件微架构的每一个取舍都要在软件栈里有对应的映射策略反过来软件调度和编译优化的每一个决策也要能落到硬件资源的具体分配上。两者脱节芯片就是一块昂贵的硅片两者咬合同样的面积和功耗预算下有效算力可以差出好几倍。这篇文章适合谁看如果你正在参与AI加速器的架构定义、RTL设计、编译器开发或者系统级性能调优尤其是那种硬件已经流片、软件还在补窟窿或者软件需求天天变、硬件改不动的团队这里面的思路应该能帮你少走一些弯路。我会尽量把原理讲透把参数怎么算、方案怎么选、坑在哪里都摊开来说。需要提前说明的是文中涉及的具体数值和案例都是基于行业常见实践做的合理推演用来把逻辑讲清楚不代表某个特定产品的真实参数。2. 算力账本要两头算峰值算力与有效算力的鸿沟从哪来2.1 为什么纸面TOPS经常是注水肉几乎每一份AI芯片的规格书首页都会印着一个醒目的算力数字比如多少TOPS。这个数字怎么来的通常是MAC阵列规模乘以频率再乘以2一次乘加算两次操作。问题是这个数字假设了所有MAC单元在每个时钟周期都在做有效计算且数据供给从不间断。现实中这个假设几乎从不成立。有效算力上不去根子往往不在计算单元本身而在数据搬运。我习惯用一个类比MAC阵列是厨房里的灶台数据是食材。灶台再多如果配菜、传菜的速度跟不上厨师只能干等着。AI计算里这个传菜就是片上存储带宽和片间/片外访存带宽。一个典型的矩阵乘法如果数据复用率没设计好计算单元有七成时间在等数据那有效算力就只有峰值的30%左右。所以看一颗AI芯片不能只看TOPS要同时看三个数峰值算力、片上缓存带宽、外部内存带宽。这三者之间存在一个平衡点业界常用计算强度Operational Intensity每字节数据能支撑多少次运算来衡量。当某个算子的计算强度低于硬件的平衡点时它就是访存瓶颈高于平衡点时才是计算瓶颈。软硬件协同的第一件事就是让尽可能多的算子落在计算瓶颈区或者通过数据复用把访存瓶颈区的算子抬上去。2.2 用一张表把瓶颈算清楚下面这张表是我在做架构评估时常用的一个简化模型用来快速判断某类算子在目标硬件上到底卡在哪算子类型典型计算强度OP/Byte硬件平衡点瓶颈判定优化方向大矩阵乘GEMM50~200约30计算瓶颈提升MAC利用率、减少流水线气泡深度可分离卷积5~20约30访存瓶颈提高数据复用、算子融合逐元素激活1~3约30严重访存瓶颈与前后算子融合、片上完成归一化层2~8约30访存瓶颈融合进卷积、减少往返访存这张表的价值在于它把为什么我的芯片跑ResNet快、跑Transformer慢这类问题量化了。你会发现很多轻量级网络里大量存在的是深度可分离卷积和逐元素操作它们的计算强度远低于硬件平衡点所以芯片的峰值算力根本发挥不出来。解决办法不是继续堆MAC而是从软件侧做算子融合把多个低强度算子合并成一个高强度算子让数据在片上多待一会儿。2.3 数据复用协同设计里最值钱的两个字数据复用分三个层次时间复用同一份数据在不同时刻被多次使用、空间复用同一份数据被多个计算单元同时使用、层次复用数据在寄存器、片上缓存、外部内存之间合理驻留。硬件设计时片上缓存的容量、bank划分、互联拓扑决定了复用的上限软件设计时循环分块tiling、数据布局layout、调度顺序决定了能否逼近这个上限。举个具体的例子。假设你要在片上做一次64x64的矩阵乘硬件有16x16的MAC阵列和一块256KB的片上缓存。如果软件把整个矩阵一次性搬进来缓存装不下只能反复换入换出带宽全浪费在搬运上。正确的做法是做分块把大矩阵切成16x16的小块每次只加载计算当前输出块所需的数据让每个数据块在被换出前尽可能多地被复用。这个分块大小怎么定它受限于片上缓存容量、MAC阵列尺寸和寄存器文件大小是一个典型的软硬件联合优化问题。分块太小复用率低分块太大缓存溢出。我通常会用一个小脚本枚举不同分块组合算出每种组合下的理论访存量再挑访存量最小的那个作为起点。3. 存储层次怎么切片上缓存、暂存器与外部内存的分工逻辑3.1 三级存储的职责边界AI芯片的存储层次粗分是三级外部内存通常是高带宽内存、片上全局缓存Shared Memory / L2、本地暂存器Register File / Scratchpad。这三级的带宽和容量呈数量级差异设计时最忌讳的就是职责不清。外部内存容量大但带宽有限、延迟高适合存放权重和激活值的冷数据片上全局缓存带宽高、容量中等适合做数据中转和跨计算单元的共享本地暂存器带宽极高、容量极小直接喂给MAC阵列。软硬件协同的关键是让数据在这三级之间各就各位而不是频繁地跨级搬运。我见过不少设计把本该放在本地暂存器的中间结果写回片上全局缓存甚至写回外部内存结果带宽全被这些无谓的往返吃掉了。判断一个数据该放哪一级有个简单的原则如果一个数据在被消费前只被一个计算单元使用且生命周期很短就尽量留在本地暂存器如果被多个计算单元共享或者生命周期跨越多个计算阶段才考虑放到片上全局缓存。3.2 双缓冲与流水线让搬运和计算重叠起来存储层次设计里有一个几乎绕不开的技术叫双缓冲Double Buffering。原理很朴素准备两块缓冲区一块用于当前计算另一块同时预取下一批数据。这样数据搬运和计算就能重叠计算单元不用停下来等数据。但双缓冲不是免费的。它需要双倍的缓冲区容量而且对同步机制有要求。如果预取时机没控制好要么预取太早导致缓冲区被占满、后续数据进不来要么预取太晚导致计算单元还是得等。在硬件上这通常通过DMA引擎和计算单元之间的握手信号来实现在软件上则需要在编译器或运行时里插入合适的同步原语。实测中一个常见的坑是双缓冲的深度设成2但数据依赖链比较长导致预取的数据还没用完新的预取请求就来了缓冲区频繁切换反而增加了同步开销。这时候可以考虑加深缓冲深度或者改用多级流水的方式把搬运、计算、写回拆成更细的流水级。具体设几级要看算子的数据依赖图和硬件的并行度没有万能答案得实测。3.3 片上缓存的bank划分与冲突避免片上缓存通常会被划分成多个bank以支持并行访问。如果多个计算单元同时访问同一个bank就会发生bank冲突访问被串行化带宽骤降。这个问题在矩阵转置、卷积的im2col展开等操作里特别容易触发。避免bank冲突硬件侧可以通过增加bank数量、采用更复杂的互联网络来缓解软件侧则可以通过调整数据布局来规避。比如把矩阵按列优先还是行优先存储会直接影响访问模式落在哪些bank上。我在做卷积优化时经常会把权重和激活值的存储布局做一次重排让同一时刻被访问的数据尽量分散到不同bank。这个重排操作本身有开销但如果能显著降低冲突率整体收益是正的。判断是否发生bank冲突最直接的办法是在仿真环境里统计每个bank的访问次数看是否存在明显的热点。如果某个bank的访问次数远高于平均值基本可以确定有冲突。解决思路无非两条要么改布局要么改访问顺序。4. 编译器与硬件的握手指令调度如何决定实际性能4.1 从计算图到指令流中间发生了什么一个AI模型从框架里的计算图到最终在芯片上执行的指令流中间要经过图优化、算子融合、内存分配、指令选择、指令调度等一系列步骤。这个链条里指令调度是最贴近硬件、也最能体现软硬件协同水平的一环。指令调度的核心任务是在满足数据依赖的前提下把指令重新排序让硬件的并行资源尽可能被填满。比如一条访存指令的延迟很长调度器就应该在它后面插入几条不依赖它的计算指令让计算单元在等待数据的同时有事可做。这个插入的时机和数量取决于硬件的流水线深度、访存延迟和并行度。如果编译器不知道硬件的这些参数它就只能保守调度性能自然上不去。所以成熟的AI芯片团队通常会让编译器团队和硬件团队共享一份硬件抽象模型里面明确标注了各类指令的延迟、吞吐、资源占用。这份模型是软硬件协同的合同双方都按它来设计和优化。4.2 算子融合省的不只是访存还有调度开销算子融合是软件侧提升有效算力的利器。把卷积、批归一化、激活函数融合成一个算子中间结果不用写回外部内存直接在片上流转。这省下的访存带宽前面算过可能是数倍于计算本身的收益。但融合也有边界。融合后的算子其数据依赖图会变复杂对片上缓存和寄存器的压力更大。如果融合导致寄存器溢出反而会引入额外的溢出/恢复开销。所以融合策略要结合硬件资源来定寄存器多、片上缓存大的硬件可以融合得更激进资源紧张的硬件就得保守一些。我在实践中总结了一个经验法则优先融合那些计算强度低、访存量大的算子比如逐元素操作和归一化层对于计算强度本来就高的算子融合的边际收益相对小可以往后放。另外融合后的算子如果太大编译时间会显著增加调试也更困难所以建议分阶段融合每融合一步就验证一次精度和性能。4.3 指令级并行与数据级并行的取舍硬件通常同时支持指令级并行ILP和数据级并行DLP。ILP靠的是流水线和多发射让多条指令重叠执行DLP靠的是SIMD或向量化让一条指令处理多个数据。两者都能提升吞吐但资源开销和适用场景不同。编译器在做调度时需要决定是把一个循环展开成多条独立指令来挖掘ILP还是向量化成一条宽指令来挖掘DLP。这个决策取决于硬件支持哪种并行、以及数据本身的特性。如果数据之间有依赖强行展开成ILP反而会增加寄存器压力如果数据规整且连续向量化通常是更优解。一个实用的判断方法是先看硬件的向量宽度和寄存器数量再估算展开后的寄存器需求。如果展开后寄存器不够用就退回向量化如果向量化后仍有空闲的发射槽再考虑适度展开。这个权衡过程最好在编译器的调度框架里做成可配置的策略而不是写死。5. 功耗与散热被软件调度悄悄影响的隐形账本5.1 动态功耗从哪里来软件能管多少芯片的动态功耗大致正比于 电容 × 电压平方 × 频率。电压和频率是硬件设定的但翻转率单位时间内信号翻转的次数却和软件执行的行为密切相关。同样的计算任务不同的指令序列、不同的数据布局会导致不同的翻转率进而影响动态功耗。软件能做的主要是减少无效翻转和降低峰值功耗。比如避免频繁地读写同一块内存会引起位线反复充放电尽量让数据在寄存器里完成计算再比如把大算力任务在时间上打散避免所有计算单元同时满负荷运行造成功耗尖峰。这些优化在硬件设计阶段就要预留支持比如提供功耗管理单元、支持动态调频调压软件才能通过配置寄存器来生效。5.2 散热约束下的频率策略散热能力决定了芯片能持续跑在什么频率上。如果软件调度让芯片长时间处于高功耗状态温度上升硬件为了保护自己会降频性能反而下降。这就是所谓的热节流。软硬件协同在这里的体现是软件要能感知硬件的热状态并动态调整任务调度。比如在温度接近阈值时主动降低非关键任务的优先级或者把任务迁移到温度较低的計算单元上。这需要硬件提供温度传感器和相应的中断/状态寄存器软件侧则要有对应的调度策略。我见过一个案例某加速器在跑一个长时任务时前几秒性能很好之后就明显掉速。排查发现是散热设计余量不足芯片很快触发热节流。后来软件侧做了调整把任务拆成多个短片段片段之间插入短暂的轻负载间隔让芯片有机会散热。虽然总任务时间没有缩短但避免了长时间降频整体吞吐反而更稳定。这个例子说明功耗和散热不是纯硬件问题软件调度有相当大的作为空间。5.3 精度与功耗的联动还有一个容易被忽略的点数据精度直接影响功耗。用FP32做计算数据位宽大翻转的位数多功耗自然高换成FP16或INT8位宽减半甚至更少功耗显著下降。所以在精度允许的前提下尽量用低位宽数据是软硬件协同降功耗的直接手段。但精度降低会带来数值误差需要在模型训练或量化阶段就考虑进去。硬件侧要支持多种精度的计算单元和相应的舍入模式软件侧则要有量化感知训练和精度校准的流程。两者配合才能在精度和功耗之间找到最佳平衡点。6. 实测中的几个典型坑与排查思路6.1 仿真性能好、上板性能差先查时钟和复位仿真环境里时钟是理想的复位是干净的。上板之后时钟可能有抖动复位可能不彻底这些都会影响性能。如果上板后性能远低于仿真第一步应该查时钟频率是否达到预期、复位是否覆盖了所有寄存器。我遇到过因为复位信号扇出太大导致部分寄存器复位延迟进而引发流水线气泡的案例排查了很久才定位到。6.2 带宽利用率上不去看DMA配置和访问粒度如果实测带宽远低于理论带宽先看DMA的配置。访问粒度太小会导致大量的小事务效率低下访问地址不对齐会触发额外的拆分。通常建议把访问粒度设成硬件支持的最大值并确保地址对齐。另外DMA的并发通道数也要和计算单元的并行度匹配通道太少会成为瓶颈。6.3 多核协同效率低查同步和共享资源争用多核AI芯片里核间同步和共享资源如片上缓存、外部内存控制器的争用是性能杀手。如果多核加速比远低于核数就要查同步机制是否高效、共享资源是否成为瓶颈。常见的优化包括用硬件信号量代替软件轮询、给每个核划分独立的缓存区域减少争用、调整任务划分让各核负载更均衡。6.4 精度不达标从数据布局和累加顺序查起有时候硬件跑出来的结果和软件参考实现有微小差异导致精度不达标。这往往不是计算单元的问题而是累加顺序不同引起的浮点误差。浮点加法不满足结合律不同的累加顺序会得到不同的结果。解决方法是统一软硬件的累加顺序或者在硬件里采用更高精度的累加器。这个问题在低位宽计算里更明显需要特别注意。7. 一些个人体会做AI芯片的软硬件协同最深的体会是不要试图在硬件和软件之间划一条清晰的界线然后各自为政。真正高效的团队硬件工程师会去读编译器的调度日志软件工程师会去翻硬件的微架构手册双方用同一套性能模型对话。这种协作模式比任何单方面的优化都管用。另外性能优化永远是一个迭代过程。第一版设计不可能完美重要的是建立一套可观测、可复现的评估流程能准确测量每个算子的耗时和访存量能快速定位瓶颈在哪一级存储或哪一类资源能方便地尝试不同的分块、融合、调度策略。有了这套流程优化就是按图索骥而不是碰运气。最后说一个具体的技巧在做分块和融合策略时先用一个简化的分析模型算出理论上限再拿实测数据去对比。如果实测和理论差距很大说明还有优化空间如果已经很接近理论上限就别再死磕了把精力放到别的地方。知道什么时候停手也是一种经验。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑