1. 万亿大模型训推的真正瓶颈在哪
今年团队接手了一个接近万亿参数的MoE模型训练项目。一开始我们和大多数人一样,以为只要把卡的数量堆上去,训练速度自然就上来了。结果跑了一次全链路压测之后彻底改观:单卡算力利用率只有40%出头,集群规模翻倍,吞吐只涨了三成不到。复盘时三条线摆在那里——算力、存储、通信,每一堵墙都不是新问题,但到了万亿这个量级,它们会叠加成一场灾难。
1.1 算力墙:算力堆得上去,效率未必撑得住
先说算力。AI加速器的峰值算力一直在涨,但“峰值”和“实际跑到”是两回事。大模型训练的每一步基本是矩阵乘加激活函数,理论上FLOPs可以打满,实际却会被两个东西拖住:内存带宽和算子调度。
内存带宽很好理解。矩阵乘法的计算强度不够高时,芯片处理单元多数时间在等数据从HBM里搬出来,而不是在计算。大家常说的“Memory Bound”就是这种情况。某些注意力计算、归一化、残差连接以及各类elementwise算子,跑起来非常依赖带宽。万亿模型里参数量巨大,中间的激活值也巨大,每一层都要反复读写,内存带宽一旦供不上,算力再高也是白搭。
另一个是算子调度。模型不是只有大矩阵乘,还有大量的通信算子、规约算子、数据搬运算子。这些算子之间需要同步、切分、拼接,调度不好就会出现一段一段的等待。我们压测时用性能分析工具看了时间分布,算子等待占了接近20%,这个比例在千亿模型上可以忍受,到了万亿量级就完全不能忍。
1.2 存储墙:显存不够用,分布式切分处处受限
存储墙是模型规模决定的硬约束。单张加速卡的显存再大,也装不下万亿参数。这里有个容易被忽略的细节:训练时占显存的不只是参数本身。以1.8T参数的稠密模型估算,参数用BF16存储需要3.6TB,如果Adam优化器加FP32状态,参数量再乘以三到四倍,光是优化器状态就超过10TB。更不用说激活值、梯度、KV Cache这些运行时数据。
显存不够靠什么补?业界基本两种思路:一是把模型切到更多张卡上,通过张量并行把每个参数分给多张卡;二是把暂时用不到的数据卸载到内存或SSD,用的时候再搬回来。
前者的问题是切得越碎,通信越重。参数每多切一份,前向和反向都要做更多跨卡规约。后者的问题是IO路径太长,CPU内存到加速卡显存之间的带宽通常只有几十GB/s,动不动阻塞。我们在一次对比里发现,同样规模的模型,启用了较多CPU卸载策略后,训练step时间反而变长了30%。存储墙和通信墙经常一起出现,你不能只解决一个。
1.3 通信墙:卡一多,网络先成短板
通信墙是最容易被低估的。千亿模型用几十张卡就能跑,很多人对通信压力没有概念。但到了万亿模型,动辄几百上千张卡并行,几乎每一步计算后面都跟着一次跨卡通信。
典型如AllReduce通信。数据并行下,每张卡算完梯度要全局求和再广播回去,通信数据量和卡的数量成正比。假设单次梯度大小为10GB,在400张卡上跑一次AllReduce,按传统服务器的跨节点网络带宽计算,保守估计就需要数十秒,而对应step的计算时间可能只有十几秒。通信一多,整体算力利用率就被压下去了。
更麻烦的是网络拓扑的缺陷。传统集群里,机内通信带宽可达几百GB/s到TB/s,跨机通信却只有几GB/s到几十GB/s。这个数量级落差导致模型并行策略必须把跨节点通信尽量压缩。张量并行不敢跨机,只能靠流水线和数据并行去弥补,但流水线的气泡又回来了。最后陷入一个死循环:显存不够要多切,多切了通信扛不住,通信扛不住利用率就低。我们当时折腾了很久才明白,单纯把卡堆多,天花板就在这。
2. 超节点架构在硬件层面改了什么
打破三堵墙,不能靠软磨硬泡的参数调优。业界头部厂商给出的方向,是把原来分离的算力、存储和网络重新整合成一个超级计算单元,也就是我标题里说的超节点。它不是一个简单的新机柜,也不是换一种交换机,而是把多个AI加速器通过超高带宽互联变成一个逻辑整体。
2.1 用一个逻辑大卡替代一群散装加速卡
先理解超节点最核心的思路:把几十张加速卡像一张大卡一样对待。传统集群里,每张加速卡是独立资源,通过网络互相通信。超节点里则通过高速互联把所有卡的内存地址空间打通,任意一张卡可以用统一寻址的方式直接读写另一张卡的内存,参考的是GPU厂商在单机多卡里使用的统一内存技术,只是把范围从一台机器扩展到了整个超节点。
这意味着什么?对训练框架来说,节点不再是物理服务器的边界。原本必须控制在单个物理节点内的张量并行,现在可以横向扩展到超节点的全部加速卡上。1.8T模型的参数切分,可以从64路扩到128路、256路而不必担心通信路径过慢。模型开发人员不再需要把“性能”和“显存”这两件事分开考虑,至少在一个超节点内部,容量和带宽是同时放宽的。
我拿一个例子说明:某团队在部署一个约6000亿参数的MoE模型时,原先要拆成两个物理集群做数据并行,跨集群通信占据了整体训练时间的30%。换成超节点后,部署从两层跨服务器通信降为一层超节点内通信,首尾通信耗时几乎砍半,整体MFU从46%升到58%。这是我在现场看到的真实收益,比PPT数字更保守,但趋势非常明确。
2.2 内存池与缓存协同,把存储压力降下来
超节点的第二个关键是存储侧的重构。它不只是把显存容量堆上去,而是做了一层统一的内存池。HBM、可扩展内存、甚至高速存储介质被抽象成一个多级缓存体系。训练框架看来,超节点就是一个拥有超大内存空间的设备,数据在各级存储之间搬运由底层统一调度。
这里面值得展开的是一种“近卡缓存”的设计。很多大模型训练为了避免频繁读远端冷数据,会在每个计算节点放一份数据副本。节点一多,重复存储消耗严重。超节点由于内部带宽高、延迟低,可以把数据副本大幅缩减,让一份数据在需要时快速广播到任意一张卡。直接收益是存储利用率提升了,IO等待显著下降。
还有个细节是优化器状态的驻留。Adam优化器状态体积大,但访问频率高,传统架构只能把一部分放到CPU内存,每步都要异步搬移。超节点的大容量显存允许把完整优化器状态驻留在HBM里,彻底去掉这类往返搬运。对比实验中,仅这一项就省下了约8%的step时间。经验是:预算允许的情况下,尽量用HBM容量换掉CPU offload,收益远大于参数调优。
2.3 通信拓扑重构,Scale-up带宽做大
通信墙的突破口是把超节点内部互联带宽做到一个数量级以上。传统服务器内部高速互联速度目前大约在几百GB/s,超节点的目标是超过这个数量级,并且把时延压到微秒级,让上千卡之间进行全连接通信变得像单机内部一样。
拓扑上最大的变化是抛弃了多层之间的中心化交换,转而采用高基数的无阻塞全互联结构。每一张卡都能以同样的低延迟访问其他卡,不再存在“跨了一个交换层级就慢一个数量级”的现状。对框架来说这是个好消息,因为通信图无论怎么切,走的都是相似的路径,通信时间可预估,调度算法的空间就被打开。
不过要说清楚,超节点并没有消灭所有通信问题。跨超节点之间依然是常规网络,只是原先发生在几百张卡之间的跨机通信,现在变成“超节点内部通信+少量跨超节点通信”。通信复杂度从一张全连接图退化成带街区结构的图,压力小很多。在万亿模型场景,这个降维级的变化基本决定了整体方案的可行性。
3. 从原理到落地:训练与推理的调优路径
超节点的硬件优势不是开机就能自动兑现的,需要配合并行策略、推理架构和集群调度做适配。这一章讲我们实际用下来的路径和细节。
3.1 并行策略怎么配才匹配超节点
并行策略的选型直接决定硬件资源的利用率。传统集群上大家习惯用“数据并行为主、张量并行做补充、流水线并行做扩展”的组合,到超节点上这个权重需要颠倒过来。
超节点内通信带宽极高,应当尽可能把模型切分放在超节点内部,也就是优先使用大规模张量并行和专家并行。以MoE模型为例,专家参数通常占大头。传统架构里专家分散在几十个节点,每个token要跨节点去访问多个专家,通信开销巨大。超节点内可以将专家全部驻留在一个超节点内,token到专家的路径从“跨节点走网络”变成“本地内存访问”,延迟下降非常明显。
我们配置1.8T MoE模型时的并行方案是这样的:
- 超节点内做128路张量并行,所有参数平均切分;
- 专家维度按8个超节点分布,每个超节点处理自己的专家子集;
- 跨超节点只走数据并行和少量专家并行,通信量保持在可控范围。
实测内部平均梯度同步耗时从原来的每步9.2秒降到2.8秒,训练吞吐提高了近一倍。要注意的是张量并行路数太高时,算子内的规约开销也会上升,128路是一个平衡点,再往上收益递减。
3.2 推理侧的KV Cache与PD分离
大模型推理和训练不一样,瓶颈往往在解码阶段。每次生成一个token,都要读取全部KV Cache,而且并发请求越多,KV Cache占用越大。万亿模型的推理如果沿用训练时的数据并行模式,每张卡都要冗余存一份完整KV Cache,显存浪费严重。
超节点方案的推理推荐采用PD分离,也就是Prefill和Decode分开部署。Prefill阶段计算密集,适合用大规模张量并行做高吞吐输入处理;Decode阶段是访存密集、延迟敏感,可以让请求分发到KV Cache最完整的卡上,减少跨卡读取。由于超节点内部任意卡访问速度接近,KV Cache天然可以做成共享状态,缓存命中率大幅提升,首Token延迟也稳得住。
我们在一次七千亿参数模型的推理压测中,使用单超节点承载1024路并发,KV Cache命中率接近91%,单Token生成延迟中位数在加速器允许的栅栏内稳定输出。这个设计里的关键点是:不要让推理请求随机路由到任意卡,而是先用一层轻量调度器判断KV Cache分布,再决定请求落到哪张卡。这个策略放在传统网络上,调度成本可能比收益还高,但在超节点上因为内部延迟低,收益非常显著。
3.3 调度与故障恢复的工程细节
超节点的资源颗粒度变大了,调度器要处理的问题也就跟着变了。原来是以“台”为单位的资源分配,现在必须支持以“逻辑大卡”为单位的分配。框架层面做的是把超节点整体作为调度对象,应用无法感知到内部拓扑细节。
故障恢复是另一个重点。模型训练动辄几十天,硬件不可能全程不出问题。传统模式下单卡故障只需重启该卡所属worker;超节点模式下,一张卡故障可能影响整个超节点内的所有并行进程。所以必须做好两件事:一是快速故障检测,比如把故障检测时间压缩到秒级;二是训练任务无感迁移,定期打checkpoint并把状态保存到独立位置。
这里给出一个简化的训练任务配置示例,展示我们如何定义超节点资源和容错策略:
# 训练任务调度配置示例 task: name: trillion_moe_test resource: supernode: 4 # 申请4个超节点 accelerator_per_node: 32 strategy: tensor_parallel: 128 # 超节点内张量并行 pipeline_parallel: 4 # 跨超节点流水线 data_parallel: 8 # 跨超节点数据并行 fault_tolerance: checkpoint_interval: 300 node_failure_policy: auto_restart state_store: distributed_fs这个配置看起来简单,但每一个字段都经历了反复验证。尤其注意tensor_parallel设为128后,如果对应框架对集合通信算子没有做超节点拓扑感知,性能会大打折扣。所以选型时不能只看硬件参数,还要确认软件栈是否完整适配。
4. 实测复盘:一次万亿级MoE模型的调测经历
理论说得再好,不如一次完整调测来得真实。这一章记录我们团队在某AI实验室环境下,围绕1.8T参数MoE模型跑出的详细数据和踩坑经验。
4.1 从45%利用率到62%的优化过程
刚开始跑基线时,我们的模型利用率只有45%,低于同行业公开基准。分析下来有四个主要问题:通信算子等待过长、数据加载与训练步重叠不够、优化器状态反复offload、部分算子内存分配频繁。
先处理通信等待。把集合通信的timeline拉出来看,发现不少通信发生在关键路径上,原因是我们并行策略里的张量并行切分了超节点内通信和跨超节点通信,而框架默认按流水线同步等待。调整成异步通信调度后,等待时间降低了12%。这一步不需要改代码逻辑,只要在框架的通信配置里打开拓扑感知调度即可。
再看数据加载。我们在数据管道里增加了四层预取队列,把数据整理的流程完全挪到计算单元之外,并利用超节点的高带宽把多级缓存命中率提升到90%以上。数据侧问题解决后,step时间再次缩短了7%。最后把优化器状态完全驻留在HBM,去掉了CPU offload路径,整体MFU最终稳定在62%。这个结果离理论峰值还有距离,但相比传统集群已经是不小的胜利。
4.2 踩坑点:跨超节点通信仍是大头
测试中最大的教训是:超节点只把“墙”往后推了,没有完全拆掉。跨超节点之间的通信依然是整个训练链路里最大的单点瓶颈。
一开始我们天真地认为,既然单超节点可以承载128路张量并行,那整个模型塞进一个超节点就完了。实际算下来,万亿模型加优化器状态约需14TB显存,而单个超节点HBM总量还不够,必须扩展到多个超节点。跨超节点通信占到总通信量的40%,训练效率因此被拉了约10个百分点。
解决的办法主要有两个方向。一是让流水线并行切分跨超节点的边界,把高频同步通信留在超节点内部,跨超节点只传输激活值这类低频数据。二是引入显存感知的调度,尽量减少跨超节点的数据搬运。最终我们将跨超节点通信占比压缩到20%,利用率重新回升。这里想对读者说一句:规划资源时一定要给跨超节点带宽留出余量,否则就算超节点内部再快,整体性能一样会被拖死。
4.3 存储缓存策略调整
存储层面的优化也颇费周折。大模型训练的数据集动辄几十TB甚至上百TB,不可能全部放进加速器本地缓存。我们的第一版方案是依赖文件系统缓存,结果每过几个epoch就会出现明显的IO峰值,训练步长忽高忽低。
后来参考头部项目经验,改成了“全局元数据索引+超节点本地热数据缓存”的两层结构。数据集按shard切好后,每个shard标记清晰,调度器把它分配给最靠前使用的超节点,之后对该超节点而言,所需数据基本都在本地。训练流程变成大部分时间顺序读取,IO峰值基本消失。
这个过程中还发现一个反直觉的点:缓存命中率并不是越高越好。为了把命中率从85%推到95%,我们付出了大量内存容量,挤占了训练所需的激活值空间,导致计算因为缺显存而频繁重排,反而变慢。最终把命中率控制在88%附近,整体耗时最优。要明白,缓存策略要跟着训练动态调整,不是一锤子买卖。
表格里汇总了这次调测中主要问题与对应方案:
| 问题 | 根因 | 调整方案 | 收益 |
|---|---|---|---|
| 通信等待时间长 | 通信调度未感知超节点拓扑 | 开启拓扑感知异步通信 | step时间降低12% |
| 数据加载阻塞 | 数据管道切分不合理 | 四层预取队列,多级缓存 | step时间降低7% |
| 优化器状态读写延迟 | 频繁CPU offload | 状态完全驻留HBM | 内存访问耗时减少 |
| 跨超节点通信占比高 | 并行切分边界设置不当 | 流水边界重排 | 利用率回升6个百分点 |
| IO峰值明显 | 缓存策略单一 | 全局索引+本地热缓存 | IO峰值基本消除 |
5. 超节点不是万能药:选型与成本判断
超节点方案很适合万亿级大模型的训练和推理,但这不代表所有团队都应该立刻跟进。做技术选型时,最忌讳的是拿着别人的最优解当成自己的标配。
5.1 什么任务适合,什么任务不适合
适合超节点的场景有几个共同特征:模型参数量在几千亿以上,训练周期以周或月计,推理并发高且对延迟敏感,团队具备成体系的模型并行调优能力。这类任务对算力、显存、通信带宽同时有要求,也只有超节点能同时把三堵墙一起后撤。
不适合的场景同样明显。如果你的模型在百亿量级,几十张卡就能跑完,超节点内部的超大带宽根本用不满,花同样的钱买一台传统服务器集群,性价比更高。如果业务以小规模微调和频繁迭代为主,超节点这种大颗粒资源调度也会成为负担。毕竟一个超节点动辄占大量功耗和机柜资源,调度灵活性比若干独立节点差。
我们的做法是先跑一个成本模型,以每单位Token的训练成本和推理成本作为核心指标,再对比传统集群和超节点的综合开销。测算下来,跨过五千亿参数这条线后,超节点才开始有显著优势。低于这个规模,算力利用率提升带来的收益覆盖不了硬件成本。
5.2 中小集群和租用算力的替代考虑
不是所有团队都有实力自建超节点集群。对大部分中小团队,更务实的路径是租用算力平台上的超节点资源,按需申请。目前市面上一些云服务商已经提供超节点实例,计价方式通常按“逻辑大卡”或“超节点片”计费,支持弹性扩缩。
租用和自建在运维上有本质区别。自建超节点需要考虑散热、供电、机房承重,一个机柜的功率密度可能达到原来三四倍,普通数据中心根本接不住。租用则简单很多,但也意味着把调度、监控、故障替换等能力交给了平台。选平台时建议重点考察两点:一是能否提供超节点拓扑感知的监控数据,二是故障恢复能否在分钟级完成。
我们实际租用过一段时间,整体感受是门槛低了很多,但成本需要精细管理。适合的做法是:频繁迭代阶段用弹性算力跑小规模验证,确定模型结构后,再一次性申请足够规模的超节点资源,按周租用,把训练窗口压缩到最短。这样既享受超节点带宽优势,又不至于让闲置成本失控。
5.3 演进方向
超节点方向上,我看到几个明显的演进趋势。一是超节点内部的加速器数量还会继续增加,从几十卡走向上百卡,互联带宽从当前数量级继续翻倍,让单个逻辑大卡能容纳更大参数的模型。二是存储和计算会进一步融合,计算单元直接在存储附近做处理,减少数据搬运次数。三是调度系统会越来越成熟,把超节点当作标准的资源单位来管理,真正做到像集装箱一样装配。
对大多数做模型研发的团队来说,现在是用较少但更强的资源去做更集中训练的阶段。掌握超节点原理和调优方法,会逐渐成为大模型工程人员的通用技能,和当年分布式集群的普及路径类似。硬件买不买得起是一回事,思路和技术储备提前跟上,起码能保证在机会来临时不用从零开始。
写到这里,我最大的体会是:超节点不是把墙推倒了,而是把墙往外移得足够远,让大部分模型不再撞墙。它解决的是规模化的问题,而规模化背后是系统工程的问题。每一堵墙背后都有一堆配套的软件要做,硬件快一步,软件跟一步,最终效果取决于两者咬合得有多紧。做工程的乐趣也就在这里,看着效率曲线被一点一点顶上去,整个团队都会觉得这几周调测没白熬。