首页 / 资讯中心 / 文章详情

AI芯片软硬件协同设计全流程:架构、编译器与接口验证实践

AI芯片软硬件协同设计全流程:架构、编译器与接口验证实践 ★ FEATURED ARTICLE
1. 项目全景AI芯片的软硬件协同到底在做什么做过几次AI芯片从架构定义到流片回板的全流程之后我有个很深的体会所谓“AI芯片的软硬件设计”从来不是“先把硬件定下来再顺手写个软件栈”而是从第一天就要把模型算子、编译器、运行时、驱动、应用API全部串成一条链条。很多团队倒在流片后的“软件适配地狱”就是因为硬件和软件在立项时被当成两个独立项目在推进。这篇文章就是想把AI芯片软硬件设计的完整思路、关键拆解和实际踩坑经验整理出来给正在做自研AI加速器的团队、准备入行的工程师还有那些需要和硬件团队打交道的算法同学一个参考。我默认的讨论对象是面向深度学习推理/训练场景的专用AI芯片也就是常说的ASIC加速器。这个题目看起来很大但落到工程上无非三条主线第一硬件架构怎样组成一个高吞吐、低访存压力的计算系统第二软件栈怎样把PyTorch之类的模型“翻译”成硬件能高效执行的指令序列第三软硬件之间那段接口区域怎么定义、怎么验证、怎么迭代。这三条线如果有一处断裂整颗芯片的实际效能都会大打折扣。1.1 为什么一定要“软硬件同时设计”算法迭代速度远快于芯片设计周期这是这个行业最残酷的现实。你花两年做出一颗针对某个网络结构的芯片等流片回来当年那套模型早就被替换掉了。所以硬件设计不能死死绑定在某一个具体的模型结构上而是要在“通用性”和“高效性”之间找一个中间点。这个中间点就叫可编程域。硬件提供的是一组可配置的计算单元、存储层次和数据通路软件通过编译器把新的模型映射到这组资源上。换句话说芯片的寿命靠硬件生命力靠软件。我做过的模拟项目X立项时目标是跑一组视觉检测网络。团队一开始想把卷积核展开逻辑做到极致几乎把3x3卷积的每种padding、stride组合都用硬件硬算。后来算法同学说模型可能要切到Attention结构。这时候如果硬件没有可扩展的矩阵运算单元和灵活的数据路由整个芯片就废了。所以我们中途调整了架构保留下通用的乘加阵列把特定结构优化改到软件编译器层去做。这次调整让我意识到硬件架构必须预留“未来模型不确定”的意识软件栈也要在第一天就介入架构讨论而不是等寄存器列表冻结了才来适配。1.2 不同芯片方案的选择逻辑AI芯片并不只有ASIC一条路。很多团队一开始会在GPU、FPGA、ASIC之间纠结。我通常给出的选择逻辑是这样的如果目标是快速验证算法、快速迭代产品FPGA是最合理的因为它可以反复改配置但代价是性能和功耗都差不少如果做的是数据中心里的通用计算想要规模效应GPU类的统一架构更合适如果流量大、模型相对固定、功耗和成本都有硬指标才适合上ASIC。这个选择的背后是“沉没成本”的差异。ASIC每一次改版都要重新流片动辄几十周周期、上千万的投入所以必须在设计阶段就把软件栈考虑清楚。而FPGA原型验证正是为了降低这个风险在FPGA上跑真实的模型、真实的编译链、真实的runtime可以提前暴露90%的软硬件接口问题。这也是软硬件协同设计最朴素的实践方式。一个合格的项目在正式流片前软件栈就应该能在FPGA原型上完整跑通几个代表性模型而不是等芯片回来才第一次启动软件栈。2. 硬件架构拆解算力到底从哪里来很多人看AI芯片第一眼就是看TOPS、TFLOPS。但真实性能从来不只是峰值算力说了算。硬件架构的核心是在给定的功耗和面积预算下让计算单元、存储、互联三者形成一个能持续高效运转的系统。如果只有计算单元很快而数据喂不上MAC阵列大部分时间都在空转那标称的TOPS就是纸面数字。2.1 计算阵列怎么组织主流AI芯片的计算核心基本是一个大规模乘加阵列也叫MAC阵列。每个MAC单元在一个周期内完成一次乘法和一次加法两个操作通常算2次FLOPs。阵列的组织方式大致分成两类一类是脉动阵列数据在阵列里流水式传递每个处理单元只和相邻单元通信另一类是权重广播方式同一份权重同时送到所有处理单元输入数据逐个更新。脉动阵列的优势是数据复用率高、寄存器用得少但对数据流形状比较挑剔权重广播对编译器更友好调度灵活不过片上连线压力大。以模拟项目X的矩阵单元为例我们最后采用了一个256个MAC的二维阵列主频1GHz。理论上峰值算力是256×2×1G 512GFLOPS。听起来不难但真正跑矩阵乘法时得把一个大矩阵拆成若干小块逐块送入阵列。如果分块尺寸和阵列形状不匹配计算效率会直接跌到60%甚至更低。所以编译器里的“分块”参数本质上就是硬件的“形状”参数两者强绑定。2.2 为什么存储层次决定芯片的命AI芯片大多是数据搬运型负载计算本身很快瓶颈往往在数据从哪来。举个例子算一个64x64x64的输出矩阵输入特征图64x64x32卷积核3x3x32x64。这个卷积需要的总数据读取量大约是输入512KB、权重72KB、输出1MB加起来接近1.6MB。如果阵列算力是512GFLOPS理论计算时间只有零点几毫秒但如果芯片的片上缓存不够、只能从外部DDR反复读取数据访存时间会远远超过计算时间。所以硬件设计里有句话叫“做存储比做计算难”。片上SRAM虽然快但面积和功耗都不便宜。一颗中等规模的AI芯片SOC上2MB到8MB的SRAM就已经很可观了。增加缓存容量、提高缓存命中率比堆算力更划算。这里有一个关键参数片上缓存容量和外部带宽的比值直接决定你能跑多大、多深的网络。如果网络中间层输出太大片上缓存放不下只能写回DDR这个操作一旦频繁出现性能断崖式下跌。2.3 片上互联与功耗约束计算阵列、缓存、外部接口之间靠什么连起来也是一个大问题。简单场景用高速总线就行规模一大就要上NoC片上网络。我记得某次测试跑一个多核调度任务热点明明在计算单元可延时就是下不去最后定位到NoC的一个路由节点在特定流量模式下形成拥塞。这时候光提升主频没用得改数据路由策略。硬件设计里要先想清楚“数据流模式”哪些数据是广播的、哪些是点对点的、哪些是多播的片上网络的路由算法就得跟着数据流走。功耗控制也强调“静态”与“动态”两手抓。动态功耗主要来自电容充放电和电压、频率、翻转率相关静态功耗则是漏电流先进工艺下占比越来越高。实际做功耗控制的手段无非几样动态电压频率调节、时钟门控、电源门控、以及把某些算力弱的需求切到低功耗核跑。但这些省电策略对软件是有要求的什么时候进入低功耗模式、什么时候需要快速唤醒如果runtime只按固定策略跑很容易出现“省了电但把延时拖垮”的情况。所以电源管理策略本身也是一层软硬件协同的协议。3. 软件栈设计把模型“安”到硬件上硬件做出来之后真正决定用户愿不愿意用你的芯片的是软件栈好不好用。很多做硬件的团队容易低估软件的工程量实际上编译器、算子库、runtime、profiler的开发周期经常比RTL还长。一个比较完整的AI芯片软件栈至少包括模型解析、图优化、算子调度、指令生成、运行时管理、调试工具这几层。3.1 编译器怎么把算子映射到阵列上以最常见的矩阵乘法为例。编译器拿到一个输入形状为(M,K)和(K,N)的矩阵乘第一步是把它拆成符合硬件阵列尺寸的小块。比如硬件MAC阵列是8x8的每个周期能算一个8x8的输出块。编译器就需要做tiling把输出矩阵拆成多个8x8的小块并决定每个块按什么顺序送入阵列。这个顺序会影响数据复用如果先固定住一个输入分块反复从缓存里取权重那就应该让权重始终驻留片上反过来如果权重太大驻留不下就得考虑重新加载的次数。分块参数的选取背后有一个“算术强度”的概念也就是单位字节访存能支撑多少计算量。假设阵列峰值算力是512GFLOPS外部内存带宽是64GB/s那么要达到算力与带宽匹配每个操作数至少要有512/648 FLOPs/Byte的算术强度。如果某个算子的实际强度只有4它注定跑不满算力我们叫“访存受限”。编译器优化的重要目标就是通过分块、融合、布局变换把每个算子的算术强度往上抬尽可能靠近或超过硬件的拐点。3.2 算子融合与图优化在实际工程里算子融合带来的收益远大于单个算子的调度优化。最典型的例子是卷积、批归一化、ReLU三段融合。批归一化在推理时可以简化成一个仿射变换也就是给卷积结果乘一个缩放因子再加个偏置这两步可以直接并到卷积的偏置计算里ReLU激活也只是结果过一遍阈值判断。三个算子融合成一个算子中间层的输出不需要写回片上缓存更不需要写回DDR既省访存又省延时。这类图优化逻辑编译器一般用一套Pass来实现先解析框架的计算图做算子级分析然后应用融合规则。但融合规则不能写死因为不同的硬件有不同的算力与缓存比例。我见过一个团队在GPU上精简的融合Pass直接套到自研芯片上结果因为片上缓存太小融合后中间结果反而导致寄存器溢出性能不升反降。所以图优化规则必须跟着硬件的实际资源参数来配置做成一组可选项而不是一套铁律。3.3 量化与精度平衡部署AI模型量化几乎是绕不开的话题。Float32推理虽然在硬件上最省事但内存占用和带宽消耗成倍增加。当前主流做法是训练后量化到INT8。原理很简单把float张量乘一个scale因子映射到[-127,127]的整数范围反量化时再乘回来。问题是网络里不同层的数值分布差异很大有的层紧随0附近有的层分布很宽用同一个scale显然不行所以还需要逐层或逐通道计算scale和zero point。我曾经在一个检测模型上遇到过量化后精度掉了3个点的事故。逐层排查后发现某个深度卷积层的激活值分布出现长尾离群点普通的最大值校准把scale拉得很大导致大部分数值被压到很小离散误差暴增。解决办法是把那一层改成混合精度保持FP16计算或者做分位点裁剪把离群点截断掉。这样的问题只能在软硬件联调的阶段暴露所以软件栈最好在早期就提供逐层量化误差分析工具不然等板子回来后一头雾水地调参效率很低。4. 软硬件接口与验证最容易翻车的区域谈完架构和软件栈必须专门讲接口。所谓软硬件接口既指寄存器和指令集的定义也指编译器和硬件行为之间的契约。接口定义得好软硬件团队可以并行开发定义得模糊两边各做各的最后联调时一定是一团乱麻。4.1 指令集与寄存器定义的关键面向AI加速器指令集设计通常分为两层一层是高级控制指令比如启动一个内核、等待事件、同步数据搬运另一层是计算指令描述在哪些数据上做什么操作。计算指令的设计要特别注意“显式数据搬运”和“隐式数据搬运”的区别。有的芯片指令里直接包含DMA读写的源地址、目的地址和长度编译器负责精细排布有的芯片则让数据搬运由硬件自动完成软件只需要提交计算任务。前者对软件要求高但性能可预期后者软件省事但灵活性差、容易浪费带宽。寄存器定义也不只是给个地址完事。好的寄存器设计会考虑软件debug的需求可以读出当前各计算核的忙碌状态、缓存命中率、总线占用率这样性能分析工具才有数据可用。我那会儿最痛苦的事情就是寄存器列表里没有性能计数器软件工程师只能靠猜来判断关键路径在哪。后来重新定义了下个版本寄存器把各类性能事件全部暴露出来联调效率提升了一个量级。4.2 虚拟样机与FPGA原型验证软硬件设计还有一个“时间差”的问题。RTL写完后再进行RTL仿真跑一个复杂模型速度慢到难以忍受可能一个batch就要跑几天。所以完全依赖RTL仿真迭代软件栈不现实。业内更常见的做法是先建一个高性能虚拟样机也就是用C/C写的CPU模型跑完整软件栈和硬件行为速度比RTL仿真快几个数量级。软件团队把这个模型当成“模拟的芯片”在真实流片前就完成大部分功能调试。FPGA原型验证则是下一步它的好处是能挂上真实的外设接口跑真实的运行时。但FPGA原型也有坑容量有限很多时候只能放下部分运算核频率低导致跑模型时需要调整超时配置不然runtime会误判芯片“卡死”。这些差异需要在FPGA验证阶段就记录下来并在软件驱动层做参数化而不是等芯片回来后发现同一套代码跑不通。4.3 性能建模与瓶颈分析软硬件架构选型阶段不要等到代码写完了再测性能而是要从需求定义开始就建一个可调整的性能模型。经典的Roofline模型就能快速判断每个算子到底是被算力限制还是被带宽限制。假设某卷积算子算术强度为96 FLOPs/Byte而我的芯片峰值算力与外部带宽的比值为8 FLOPs/Byte那么这个算子显然落在“算力受限区”意味着它已经到达硬件可提供的最高吞吐不必再花力气省带宽。反之如果一个算子算术强度只有4说明它是访存受限优化重点是减少数据搬运、提高缓存命中率。性能模型还有一个重要应用做配置权衡。增加片上缓存、增加带宽、提升主频各自能带来多少收益用模型一算很快就能看出性价比。不用建模全凭感觉架构评审就是吵架。用模型至少每一次取舍都有数字支撑大家讨论的是数值不是情绪。5. 常见问题与排查技巧实录这部分是从多个项目里攒下来的真实问题合集。每一次排障最后基本都指向软硬件协同设计中的某个细节没对齐。我把几个高频问题整理成一张速查表方便大家直接对照。现象可能原因排查思路与解决方案编译生成的代码在硬件上跑得很慢内存分块过大或过小bank冲突严重先用profiler看片上缓存命中率再调整tile大小按2的幂逐步扫描同时检查数据布局是否对齐到缓存line大小芯片实际功耗超标并发调度激进数据翻转率高检查是否有大量写同一个地址的冗余操作开启时钟门控调整DVFS策略把非关键环节降到低频模型量化后精度明显下降某些敏感层分布被粗暴截断逐层输出激活分布对离群层采用混合精度或分位点校准对比FP32的中间结果定位偏差扩散点双核协作时偶发死锁片上网络路由方式在特定流量下循环等待抓取拥塞热点分布修改路由方向限制或增加缓冲必要时调整任务分配策略避免两个核互相等待对方数据软件栈同一份代码在FPGA原型上经常超时报错FPGA频率低导致真实延时比预期高好几个量级把超时阈值参数化按板卡频率自动缩放在芯片带回前加入“仿真慢时钟”模式避免runtime误判最容易让人抓狂的问题其实是“编译明明没错但性能就是不对”。这种情况下先不要怀疑编译器bug而是先怀疑数据布局。AI芯片对输入数据的形状、对齐要求非常敏感一个通道数不是缓存line倍数的网络可能会导致大量padding操作看起来寥寥几行代码差距实际带宽浪费了30%。排查方法是把算子逐个替换成内存拷贝操作测纯粹的数据搬运吞吐如果连拷贝都跑不满带宽那就是布局和地址对齐的问题跟计算逻辑无关。另一个常见坑是软件栈里的“乐观假设”。比如编译器假设某个中间结果一定在片上缓存里于是直接用缓存地址写进指令。但runtime在任务并行执行时缓存内容可能已经被其他核冲掉了。这类Bug最隐蔽因为在单核单任务下测不出来一旦跑多任务、多batch就偶发。解决思路是给编译器和runtime之间加一层“内存租约”机制编译器申请资源时runtime返回一个合法的地址和有效区间用完必须释放。没有这种约束后续维护就是持续的“打补丁”永远也补不完。6. 一些个人体会与建议做了几个完整的AI芯片项目后我对“软硬件协同”的理解已经不再是一句口号而是落到了几个很具体的经验上。第一软硬件接口文档一定要在一个季度内冻结第一版然后保留版本演进机制。接口一旦频繁变动两边的开发节奏都会被拖垮。但也不能认为冻结就是一切新需求可以用扩展寄存器的方式兼容保证老代码不破坏。第二整个项目最好能有一个“最小垂直切片”作为里程碑把最小的硬件模块、最小的软件路径、一个最简单的模型串起来跑通。这个切片能让你在最早期就验证工具链、启动流程、调试路径是不是通顺的而不是到了后期才发现底下基础是空的。我踩过的最大的一个坑是在一次项目里把大量精力花在优化一个高频算子的细节后来用性能模型一算才恍然大悟全系统的瓶颈根本不在那个算子而在外部带宽的分配策略上。从那时候起我每做一个新项目都会在上手第一周先写出一个PCE性能模型哪怕粗糙一些后面迭代起来也比拍脑袋准得多。性能工具不是可有可无的东西它是架构决策的坐标系。这个方向后续还可以延伸很多多芯粒互联的低延迟、片上可重构加速器、自动生成算子库的RTL、以及面向新模型结构的自适应调度。但万变不离其宗所有延伸归根结底都是在处理“更灵活地计算、更高效地搬数据、更准确地控制功耗”这三件事。如果你正打算启动一个AI芯片项目我建议先从软件栈的性能模型写起然后带着模型去定义硬件接口这样硬件的每一分面积和功耗投入都会花在看得见收益的地方。
阅读完成 · 觉得有帮助?
咨询建站