资讯动态

DynaCore形状自适应架构:突破大模型两相推理瓶颈

发布时间:2026/10/20 8:19:43 来源:尧图企业网站定制
1. 从两相推理的瓶颈说起大模型推理这件事做过部署的人都知道真正卡脖子的往往不是算力总量而是显存带宽和计算单元之间的配合节奏。尤其是现在主流的自回归生成模式整个推理过程被硬生生切成了两个性格完全不同的阶段一个是预填充阶段输入一整段提示词模型要并行处理所有 token计算密度高、矩阵乘法占主导属于典型的计算密集型任务另一个是解码阶段每次只蹦出一个 token却要把整个 KV Cache 从头读到尾计算量小得可怜但访存量大得惊人属于典型的访存密集型任务。这两个阶段的硬件需求几乎是相反的。预填充喜欢大算力、高并行度解码则对显存带宽和缓存命中率极度敏感。传统做法是用同一套硬件配置硬扛两个阶段结果就是预填充时算力没吃满解码时带宽又成了瓶颈整体吞吐量被拖在一个尴尬的中间值上。DynaCore 这篇工作瞄准的就是这个痛点它提出的形状自适应架构核心思路是让硬件在两种推理阶段之间动态调整自己的计算形态而不是让软件去迁就固定的硬件。这个方向之所以值得关注是因为它触及了一个根本矛盾静态硬件与动态负载之间的错配。你不可能为每个阶段都配一套专用芯片那样成本和控制复杂度都不可接受但如果你只用一套通用架构就必然在某些阶段浪费资源。DynaCore 的解法是在架构层面引入可重构性让同一个物理单元在不同阶段呈现出不同的逻辑形状。这听起来有点像 FPGA 的思路但它的粒度更粗、切换开销更小更贴近 ASIC 的能效表现。我读这篇论文的时候最直观的感受是它把“两相推理”这个已经被讨论烂了的问题从调度层面拉回到了架构层面。之前大家卷的是 continuous batching、PagedAttention、chunked prefill 这些软件策略本质上是在既有硬件上做时间维度的调度优化。DynaCore 则问了一个更底层的问题如果硬件本身能变形软件调度是不是可以简单很多这个视角的转换才是这篇论文真正有意思的地方。2. DynaCore 的核心设计拆解2.1 形状自适应到底自适的是什么先把这个概念说清楚。DynaCore 里的“形状”不是指芯片的物理外形而是指计算单元的组织形态和互连拓扑。具体来说它包含三个可调的维度一是脉动阵列的几何尺寸比如 128x128 还是 64x256二是片上缓存的分配比例多少给权重、多少给 KV Cache三是数据流的调度模式是权重 stationary 还是输出 stationary。这三个维度在预填充和解码阶段的最优取值完全不同。预填充阶段输入序列长矩阵乘法的 M 维度很大适合用高瘦型的阵列让权重一次性加载后反复复用解码阶段M 维度退化成 1或者 batch 内的小数值阵列如果还是高瘦型大部分计算单元会闲置这时候需要把阵列压扁腾出面积给缓存同时切换到输出 stationary 模式减少 KV Cache 的重复读取。论文里给出的数据是在 7B 模型上预填充阶段的计算利用率能到 85% 以上但解码阶段如果沿用同一配置利用率会掉到 20% 以下。这个落差就是 DynaCore 要填的坑。它的做法是在两个阶段之间插入一个重构窗口把阵列重新划分、缓存重新分配、数据流重新配置整个过程控制在微秒级对上层推理引擎几乎透明。注意重构窗口的开销是这类架构的命门。如果切换太频繁重构本身的开销会吃掉收益。DynaCore 的策略是按 batch 粒度切换而不是按 token 粒度这样摊薄下来每次重构只占整体延迟的不到 2%。2.2 可重构阵列的硬件实现路径DynaCore 的阵列由若干个可重构计算块组成每个块内部有独立的乘法累加单元和小型寄存器文件块与块之间通过一条可配置的互连网络连接。这条互连网络是关键它支持两种拓扑一种是全连接网格适合预填充阶段的大矩阵并行另一种是链式流水适合解码阶段的向量-矩阵乘。切换拓扑的机制论文里叫“软交换”实际上是一组多路选择器和配置寄存器的组合。配置信息在推理开始前由编译器生成运行时由控制器按阶段加载。这里有个设计取舍如果配置粒度太细灵活性高但配置存储和加载开销大如果粒度太粗切换不灵活但开销小。DynaCore 选择的是中等粒度把阵列分成 8 个可独立配置的区域每个区域可以单独选择拓扑模式。这个选择背后的逻辑是预填充和解码的边界并不是一刀切的。在实际推理中一个 batch 里可能同时存在正在预填充的请求和正在解码的请求这时候需要的是部分重构而不是全局切换。8 个区域的划分让 DynaCore 可以做到“东边预填充、西边解码”这是它比全局重构方案更实用的地方。2.3 缓存分配的动态平衡KV Cache 的管理是解码阶段的核心矛盾。DynaCore 把片上缓存分成三个池权重池、激活池、KV 池。预填充阶段权重池占大头因为要频繁读取权重矩阵解码阶段KV 池需要扩容因为序列越长KV Cache 越大而且每次解码都要全量读取。论文里给出的分配策略是基于序列长度预测的。在请求进入时调度器会估算这个请求的预期输出长度然后提前把 KV 池的容量预留出来。如果实际输出超过预期再触发一次缓存重分配。这个预测的准确率直接影响性能论文里用的是基于历史统计的轻量级预测器准确率在 80% 左右剩下的 20% 靠动态调整兜底。我个人的经验是这种预测兜底的策略在真实负载下比纯动态分配更稳。纯动态分配虽然灵活但每次调整都有开销而且容易在长尾请求上反复抖动。DynaCore 的做法相当于用一点预测误差换取了整体稳定性这个 trade-off 在工程上是合理的。3. 两相推理的加速效果与实测数据3.1 预填充阶段的加速来源预填充阶段的加速主要来自阵列形状的匹配。传统固定阵列在处理变长输入时如果序列长度不是阵列尺寸的整数倍会有大量的填充浪费。DynaCore 的可重构阵列可以根据实际序列长度调整几何尺寸比如输入长度是 192它可以把阵列配成 64x3 的模式而不是硬塞进 128x128 的固定网格里。论文里给的实测数据是在 2048 长度的输入上预填充吞吐量比固定阵列基线提升了 1.7 倍。这个提升幅度不算夸张但考虑到预填充本身已经是计算密集型、利用率较高能再挤出 70% 的吞吐已经不容易了。提升主要来自两个方面一是减少了填充浪费二是权重加载的次数随着阵列形状优化而降低。还有一个容易被忽略的点是权重预取。DynaCore 在预填充阶段会把下一层要用到的权重提前加载到权重池里利用的是预填充阶段计算量大、有足够时间掩盖加载延迟的特点。这个预取策略在解码阶段就不适用了因为解码阶段计算量太小预取反而会增加带宽压力。所以预取逻辑也是随阶段切换的这也是形状自适应的一部分。3.2 解码阶段的带宽优化解码阶段的加速逻辑完全不同。这个阶段的瓶颈是 KV Cache 的读取带宽DynaCore 的优化手段主要有三个一是KV Cache 压缩把不重要的历史 token 的 KV 对做低秩近似减少读取量二是缓存亲和性调度把同一序列的 KV 尽量放在同一个缓存区域减少跨区域访问三是链式流水拓扑让多个解码步骤之间的数据依赖通过流水线传递而不是每次都回写再读取。论文里给出的解码吞吐提升是 2.3 倍比预填充的 1.7 倍更显著。这符合预期因为解码阶段的优化空间本来就更大。2.3 倍这个数字是在 batch size 为 32 的条件下测的batch 越大KV Cache 的复用率越高提升幅度会更大。论文里提到在 batch size 为 128 时解码吞吐提升能到 3.1 倍。不过这里有个坑KV Cache 压缩是有精度损失的。论文里用的是 rank-8 的低秩近似在大多数任务上精度损失在 0.5% 以内但在一些需要长距离依赖的任务上比如代码生成和数学推理损失会稍微大一点。论文的建议是对精度敏感的任务关闭压缩只靠缓存亲和性和流水拓扑来优化。这个建议很务实没有为了追求吞吐数字而牺牲可用性。3.3 端到端延迟与吞吐的权衡把两个阶段的提升合起来看端到端的效果取决于两个阶段的耗时占比。对于一个典型的对话场景输入 512 token、输出 256 token预填充耗时约占 30%解码耗时约占 70%。按这个比例加权DynaCore 的端到端吞吐提升大约是 1.7×0.3 2.3×0.7 2.12 倍。但端到端延迟的情况更复杂。预填充阶段的重构窗口会增加一点延迟解码阶段的流水线启动也有填充开销。论文里测的 TTFT首 token 时间比基线高了约 8%但 TPOT每 token 输出时间降低了 55%。这意味着对于长输出任务DynaCore 的优势会随时间放大对于短输出任务TTFT 的增加可能让用户感知到轻微变慢。这个 trade-off 在实际部署中需要根据业务场景来调。如果是聊天机器人用户对 TTFT 敏感可能需要把重构窗口调小牺牲一点吞吐换延迟如果是批量文档生成TPOT 更重要可以接受稍高的 TTFT。DynaCore 把这些参数都做成了可配置的这一点比那些硬编码策略的方案要友好得多。4. 实操复现的关键步骤与配置要点4.1 环境搭建与依赖准备如果你想复现 DynaCore 的实验首先得明确一点这不是一个纯软件方案它需要硬件层面的支持。论文里用的是基于 FPGA 的原型验证平台具体型号就不说了反正不是消费级显卡能跑的东西。但它的设计思路和调度策略是可以在软件层面做部分模拟的这对于理解它的工作机制很有帮助。软件模拟的环境搭建大致需要这些东西一个支持自定义算子调度的推理框架比如修改过的 ONNX Runtime 或者 TVM一个可配置的缓存管理器以及一个能模拟阵列形状切换的调度器。论文里开源了调度器的核心逻辑但硬件模拟部分只给了接口定义需要自己补实现。提示如果你只是想验证形状自适应对推理性能的影响可以先用软件模拟的方式把阵列形状抽象成不同的 tile 配置在 GPU 上通过改变 block size 和 shared memory 分配来近似。虽然不如真实硬件精确但趋势是对的。4.2 重构窗口的参数调优重构窗口的大小是 DynaCore 里最需要调参的地方。窗口太小配置加载不完整会导致计算错误窗口太大切换开销增加抵消收益。论文里给的默认值是 128 个时钟周期但这个值跟阵列规模和配置复杂度有关需要根据实际情况调整。调优的方法是做敏感性分析固定其他参数只变重构窗口大小测端到端吞吐和延迟。你会看到一个先升后降的曲线峰值就是最优值。论文里提到在 8 区域配置下最优窗口在 96 到 160 周期之间具体取决于区域间的配置差异有多大。如果两个阶段的配置差异小窗口可以短一些差异大就需要更长的加载时间。还有一个技巧是预加载配置。在预填充阶段快结束时提前把解码阶段的配置加载到影子寄存器里等切换时直接生效这样重构窗口可以缩短一半。这个技巧论文里没有重点提但我在类似的可重构架构上用过效果很明显。4.3 缓存池的分配比例计算缓存池的分配比例不是拍脑袋定的需要根据模型结构和序列长度分布来算。假设模型有 L 层每层权重占 W 字节KV Cache 每 token 占 K 字节预期序列长度为 Sbatch size 为 B那么权重池最小容量 L × WKV 池最小容量 L × K × S × B激活池容量取决于最大中间激活值通常是权重池的 10% 到 20%预填充阶段权重池需要全量加载KV 池只需要容纳当前 batch 的输入解码阶段权重池可以缩减到只保留当前层的权重KV 池需要全量扩容。DynaCore 的控制器会根据这些公式动态计算每个池的目标容量然后通过缓存重映射来实现。实际调参时我建议把 KV 池的容量留 20% 的余量因为序列长度预测不可能完全准确。余量太小会导致频繁的缓存重分配余量太大又浪费片上空间。20% 是我在多个模型上试出来的经验值你可以根据预测器的准确率微调。5. 常见问题与排查技巧实录5.1 重构失败导致的计算错误这是最常见的问题表现是推理结果出现乱码或者数值异常。根本原因通常是配置加载不完整或者互连拓扑切换时有时序违例。排查的第一步是检查重构窗口是否足够长可以先把窗口调到默认值的两倍如果问题消失说明是窗口太短。如果窗口调大后问题依旧就要检查配置寄存器的写入顺序。DynaCore 的配置加载是有顺序依赖的必须先配互连拓扑再配阵列形状最后配缓存分配。顺序错了会导致中间状态不一致计算单元可能读到错误的配置。论文里给了配置加载的状态机图照着实现基本不会错。还有一个隐蔽的坑是跨区域配置冲突。8 个区域如果相邻区域的拓扑模式不兼容互连网络可能无法正确路由。比如区域 0 配成全连接网格区域 1 配成链式流水两者之间的数据通路需要额外的桥接逻辑。论文里提到这个问题在早期版本中存在后来通过限制相邻区域的配置组合解决了。如果你自己实现建议也加类似的约束。5.2 解码阶段吞吐不升反降有时候你会发现解码阶段的吞吐比基线还低这通常是因为 KV Cache 压缩的精度损失导致了额外的重算。DynaCore 的压缩策略是自适应的如果压缩后的 KV 对在后续步骤中被频繁访问它会触发解压缩和重算这个开销可能超过压缩节省的带宽。排查方法是看压缩率和解压缩率的比值。如果解压缩率超过 30%说明压缩策略太激进了需要降低压缩等级或者关闭压缩。论文里给的 rank-8 是个保守值但在某些任务上还是太激进。我的建议是从 rank-16 开始试逐步降低找到吞吐和精度的平衡点。另一个可能的原因是缓存亲和性调度失效。如果序列的 KV 被分散到多个缓存区域跨区域访问的延迟会抵消流水线带来的收益。检查方法是看缓存命中率如果低于 70%说明亲和性调度没起作用。可能是序列 ID 的哈希函数分布不均匀换一个哈希函数通常能解决。5.3 预填充阶段的填充浪费反而增加这听起来反直觉但确实会发生。原因是可重构阵列在调整形状时如果新形状和旧形状的边界不对齐会产生额外的填充。比如从 128x128 切到 64x256中间有一个过渡状态部分计算单元需要等待重新配置这段时间的利用率是零。解决办法是形状切换的粒度对齐。尽量让新旧形状的公约数大一些比如 128x128 和 64x256 的公约数是 64切换时以 64 为单位逐步调整而不是一次性全切。论文里把这个叫“渐进式重构”实测能减少 40% 的切换开销。还有一个技巧是形状预判。根据输入序列的长度分布提前把阵列配成最接近的形状减少运行时的切换次数。比如你的负载里 80% 的输入长度在 256 到 512 之间那就把默认形状设成能覆盖这个区间的配置只在遇到极端长度时才切换。这个策略在真实业务里比动态切换更实用因为真实负载的分布通常比较集中。5.4 常见问题速查表问题现象可能原因排查方法解决措施推理结果乱码配置加载不完整检查重构窗口长度增大窗口至默认值两倍数值异常拓扑切换时序违例检查配置写入顺序按拓扑→形状→缓存的顺序加载解码吞吐下降KV 压缩过于激进统计解压缩率降低压缩等级或关闭压缩缓存命中率低亲和性调度失效检查序列 ID 哈希分布更换哈希函数预填充浪费增加形状切换边界不对齐检查新旧形状公约数采用渐进式重构端到端延迟抖动缓存重分配频繁监控重分配次数增加 KV 池余量至 20%6. 这套架构思路的延展与个人体会DynaCore 最让我欣赏的一点是它没有试图用一个万能方案解决所有问题而是承认了预填充和解码的本质差异然后针对性地做架构层面的适配。这种“承认差异、分别优化”的思路比那些追求统一抽象的方案要务实得多。在实际工程中很多性能问题之所以难解就是因为我们在用同一套工具处理不同性质的任务然后抱怨工具不够好。这个思路可以延展到其他场景。比如训练和推理的混合负载前向和反向传播的计算特征也不同是不是也可以做类似的动态重构再比如多模态模型里视觉编码器和语言解码器的计算模式差异更大能不能用可重构架构来统一论文里没有展开这些但它的设计原则是通用的先识别负载的相变点再让硬件在相变点之间切换形态。我个人在实际操作中的体会是这类架构最大的挑战不在硬件设计而在编译器和调度器的配合。硬件提供了可重构的能力但什么时候重构、怎么重构、重构到什么程度这些决策需要编译器在编译期给出指导调度器在运行期做微调。DynaCore 的编译器部分论文里讲得比较简略只说了配置生成的基本流程但实际落地时这部分的工作量可能比硬件还大。最后分享一个小技巧如果你在软件层面模拟这类架构不要试图精确模拟硬件时序那样工作量太大且容易跑偏。抓住核心变量——阵列形状、缓存分配、数据流模式——用抽象的参数来控制然后测端到端指标。只要趋势对了具体数值的偏差可以接受。毕竟我们做架构研究的目的是找到设计方向而不是复现每一个门电路的延迟。

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

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

免费获取报价 →
↑