1. 从一张拓扑图说起:为什么单卡跑不动大模型
第一次接触昇腾AI集群的人,十有八九会问同一个问题:我手里这张NPU单卡算力已经够猛了,为什么还要折腾什么集群、什么并行?答案其实特别朴素——显存不够,时间不够,规模不够。
拿现在主流的千亿参数模型来说,光是权重本身,FP16精度下就要吃掉接近2TB的显存。单张昇腾NPU的HBM容量再大,也塞不下这个体量。更要命的是,训练过程中还有优化器状态、梯度、激活值这些额外开销,实际占用往往是模型权重的3到5倍。所以从第一天起,大模型训练就注定是一个分布式问题,单卡只能跑推理,训练必须上集群。
但集群不是把一堆卡插上电、连上网线就完事了。真正难的地方在于:怎么让成百上千张NPU协同工作,还能保持接近线性的加速比。这就引出了今天要聊的核心——多维混合并行。
昇腾AI集群服务器架构里,多维混合并行不是一个可选的高级技巧,而是支撑大模型训练的基础设施级能力。它把数据并行、张量并行、流水线并行、专家并行等多种策略组合在一起,针对不同的模型结构、不同的集群规模、不同的通信带宽,动态选择最优的切分方式。说白了,就是让每一张NPU都尽量别闲着,同时让卡与卡之间的通信别成为瓶颈。
这篇文章适合谁看?如果你正在做昇腾平台上的大模型训练,或者准备从单卡实验迁移到集群环境,又或者你只是好奇“多维混合并行”这几个字背后到底藏着什么工程细节,那接下来的内容应该能给你一些可以直接抄作业的东西。我会从架构设计思路讲起,然后拆解核心并行策略的实现要点,再给出一套可复现的实操流程,最后把踩过的坑和排查技巧整理成速查表。
2. 多维混合并行的整体设计思路
2.1 为什么单一并行策略走不通
先说说为什么不能只用一种并行方式。数据并行(Data Parallelism)是最直观的:每张卡拿一份完整的模型副本,喂不同的数据,算完梯度再AllReduce同步。听起来很美,但它有个硬伤——每张卡都得存一份完整的模型。模型一大,单卡显存直接爆掉。所以数据并行只适合中小模型,或者显存足够大的场景。
张量并行(Tensor Parallelism)解决的是单层内部太大的问题。比如一个巨大的矩阵乘法,把它按行或按列切开,分到多张卡上算,算完再拼起来。这样单卡只需要存一部分权重。但张量并行的通信非常频繁,每层前向和反向都要做AllReduce或AllGather,对卡间带宽要求极高。如果跨机做张量并行,通信开销能把计算收益吃干净。
流水线并行(Pipeline Parallelism)换了个思路:按层切分,前几层放一组卡,后几层放另一组卡,数据像流水线一样依次流过。这样通信量小很多,但会引入“气泡”——流水线填充和排空阶段,部分卡是空闲的。流水线级数越多,气泡占比越大,需要靠微批次(micro-batch)来填满。
专家并行(Expert Parallelism)是MoE(混合专家)模型专属的。不同的专家网络放在不同的卡上,每个token根据路由结果只激活部分专家。这样参数量可以做得极大,但计算量不会等比例增长。不过路由不均衡会导致某些卡忙死、某些卡闲死,需要额外的负载均衡策略。
你看,每种并行都有它的适用场景和明显短板。真实的大模型训练,往往是几千亿参数、上百层、MoE结构,还要求高吞吐。这时候单一策略根本不够用,必须把它们组合起来——这就是多维混合并行的由来。
2.2 昇腾集群的硬件底座:NPU与HCCL
聊并行策略之前,得先认清昇腾集群的硬件底子。昇腾NPU的架构和通用GPU不太一样,它采用了达芬奇核心,包含Cube矩阵计算单元、Vector向量计算单元和Scalar标量计算单元。Cube单元专门负责矩阵乘加,这是深度学习里最密集的计算;Vector单元处理激活函数、归一化这些逐元素操作;Scalar单元做流程控制。这种分工让NPU在矩阵运算上效率很高,但也意味着算子开发时需要针对不同单元做适配。
集群内部,NPU之间通过HCCL(Huawei Collective Communication Library)通信。HCCL提供了一套集合通信原语,包括AllReduce、AllGather、ReduceScatter、Broadcast、All2All等。这些原语是多维混合并行的通信基础。HCCL会根据集群的物理拓扑——比如同一台服务器内通过HCCS互联、跨服务器通过RoCE或IB网络——自动选择最优的通信路径和算法。
这里有个关键点:HCCL的通信带宽和延迟直接决定了并行策略的上限。同一台服务器内的NPU互联带宽通常远高于跨服务器网络。所以张量并行这种通信密集型策略,一般优先放在同一台服务器内;流水线并行和专家并行的通信量相对小一些,可以跨服务器部署。这个“通信分级”的思路,是多维混合并行设计的核心原则之一。
2.3 混合并行的组合逻辑:按通信密度分层
多维混合并行的设计哲学可以用一句话概括:按通信密度分层,把高通信密度的并行放在高带宽域内,低通信密度的并行放在低带宽域间。
具体来说,一个典型的昇腾集群混合并行配置是这样的:
- 张量并行(TP):放在同一台服务器内的NPU之间,利用HCCS高带宽互联。TP的通信量最大,每层都要同步,所以必须放在最快的链路上。
- 流水线并行(PP):跨服务器部署,通信量相对小,主要是层与层之间的激活值传递。PP的通信可以重叠计算,对带宽要求没那么苛刻。
- 数据并行(DP):放在最外层,跨更多的服务器。DP的通信是梯度AllReduce,频率低(每个迭代一次),但数据量大。昇腾集群通常用分层AllReduce来优化,先在服务器内做ReduceScatter,再跨服务器做AllReduce,最后服务器内AllGather。
- 专家并行(EP):根据MoE模型的路由策略,把不同专家分布到不同NPU上。EP的通信是All2All,通信模式比较随机,需要配合负载均衡。
这种分层组合的好处是,每一层并行都跑在最适合它的通信域里,整体通信开销最小化。但挑战也很明显:不同并行维度之间的交互非常复杂,切分策略、通信组划分、内存布局、计算图优化,任何一个环节出问题都会导致性能断崖式下跌。
2.4 昇腾软件栈的支撑:CANN与MindSpore
硬件之上,昇腾的软件栈为多维混合并行提供了完整的支撑。CANN(Compute Architecture for Neural Networks)是底层的异构计算架构,负责算子编译、图优化、内存管理、通信调度。HCCL就是CANN的一部分。上层的MindSpore框架则提供了并行策略的编程接口,开发者可以通过简单的配置或自动并行算法,把模型切分到集群上。
MindSpore的自动并行能力值得一提。它会根据模型的计算图和集群的拓扑信息,自动搜索最优的切分策略。比如它会分析每个算子的通信量和计算量,然后决定哪些算子做张量并行、哪些做数据并行。当然,自动并行不是万能的,复杂模型还是需要手动调优。但至少它提供了一个不错的起点,让新手不用一上来就面对一堆通信组配置。
3. 核心并行策略的细节拆解与实操要点
3.1 数据并行:看似简单,坑在梯度同步
数据并行是最好理解的:每张卡一份完整模型,喂不同数据,反向传播后同步梯度。昇腾平台上,数据并行的实现主要依赖HCCL的AllReduce。
但这里有个容易被忽略的细节:梯度同步的时机和方式。最朴素的做法是等所有卡的梯度都算完,然后一次性AllReduce。但这样通信和计算是串行的,通信时间完全暴露。优化做法是梯度分桶(gradient bucketing):把梯度按大小分成多个桶,一个桶算完就立刻开始AllReduce,让通信和后续桶的计算重叠起来。
昇腾的HCCL支持这种分桶通信,MindSpore里可以通过配置bucket_size参数来控制。桶太小,通信次数多,启动开销大;桶太大,重叠效果差。经验值是在16MB到64MB之间,具体要看模型梯度的分布和网络带宽。我实测下来,在昇腾910集群上,32MB的桶大小对大多数Transformer类模型都比较均衡。
另一个坑是梯度累积与数据并行的交互。如果你用了梯度累积来模拟更大的batch size,那要注意AllReduce的频率。梯度累积的每一步都做AllReduce是浪费的,应该等累积完再同步。MindSpore里可以通过accumulation_step配合通信调度来实现。
注意:数据并行的加速比不是线性的。当卡数增加到一定程度,AllReduce的通信时间会超过计算时间,加速比反而下降。这时候就需要引入其他并行维度来分担压力。
3.2 张量并行:切分矩阵的学问
张量并行的核心是把大的权重矩阵切开。以Transformer里的注意力层为例,Q、K、V的投影矩阵可以按列切分,输出投影可以按行切分。这样每张卡只存一部分权重,计算也只需要算一部分。
但切分方式直接影响通信量。按列切分的话,每张卡算出一部分输出,需要AllGather拼起来;按行切分的话,每张卡需要完整的输入,算完做AllReduce求和。两种方式的通信量差不多,但AllReduce通常比AllGather更高效,因为可以做ReduceScatter+AllGather的融合。
昇腾平台上做张量并行,有几个实操要点:
第一,通信组要尽量小。张量并行的通信组通常限制在单机8卡以内,因为跨机的AllReduce延迟太高。如果模型太大,单机8卡放不下,那就得配合流水线并行,把不同层放到不同机器上。
第二,算子融合很关键。张量并行会产生很多小算子,比如切分后的矩阵乘、拼接、求和。如果不做融合,算子启动开销会吃掉大量时间。CANN提供了图优化能力,可以自动融合一些常见模式,但复杂的切分模式还是需要手动调优。
第三,注意内存对齐。NPU的HBM访问有对齐要求,切分后的矩阵维度如果不是对齐的倍数,性能会明显下降。比如昇腾910的Cube单元对矩阵维度有16的倍数要求,切分时尽量保证每张卡上的维度是16的倍数。
3.3 流水线并行:气泡怎么填
流水线并行的核心思想是“层切分+微批次”。把模型按层分成多个阶段(stage),每个stage放在不同的NPU组上。数据切成多个微批次,依次流过各个stage。这样同一时刻,不同stage可以处理不同的微批次,提高利用率。
但流水线有个天然缺陷:填充和排空阶段,部分stage是空闲的,这就是“气泡”。气泡占比的公式是:
气泡占比 = (PP - 1) / (micro_batch_num + PP - 1)
其中PP是流水线级数,micro_batch_num是微批次数量。要降低气泡占比,就得增加微批次数量。但微批次太多,又会增加内存占用和调度开销。
昇腾平台上,流水线并行的实现通常配合1F1B(One Forward One Backward)调度。这种调度方式让每个stage在前向一个微批次后,立刻反向一个微批次,最大化重叠。MindSpore的流水线并行支持1F1B和更复杂的交错调度。
实操中,微批次数量一般设为流水线级数的4到8倍。比如PP=4,微批次可以设16到32。这样气泡占比能降到10%以下。但要注意,微批次数量受限于全局batch size,不能无限增加。
另一个坑是stage之间的负载均衡。如果某个stage的层数特别多或计算特别重,它就会成为瓶颈,其他stage等它。所以切分时要尽量让每个stage的计算量接近。Transformer类模型通常按层数平均分,但要注意embedding层和输出层的计算量差异。
3.4 专家并行:路由与负载均衡
专家并行是MoE模型的专属并行方式。MoE层里有很多个专家网络,每个token通过门控网络选择top-k个专家进行计算。专家并行就是把不同专家放到不同NPU上,token根据路由结果发送到对应的NPU。
这里最大的挑战是负载不均衡。如果路由策略不好,某些专家被大量token选中,对应的NPU就忙不过来;其他专家没人选,NPU就闲着。昇腾平台上,通常用**容量因子(capacity factor)和辅助损失(auxiliary loss)**来缓解这个问题。容量因子限制了每个专家最多处理多少token,超出的token会被丢弃或走残差连接。辅助损失则鼓励门控网络均匀分配token。
专家并行的通信是All2All,每个NPU把token发送到目标专家所在的NPU,算完再收回来。All2All的通信模式比较随机,对网络拓扑敏感。昇腾的HCCL对All2All做了优化,支持分组通信和流水线传输。但实操中还是要注意,专家并行的通信组不要跨太多机器,否则延迟会很高。
3.5 多维混合:组合的艺术
把上面几种并行组合起来,就是多维混合并行。比如一个典型的配置是:TP=8(单机内),PP=4(跨4台机器),DP=2(再复制2份),总共8×4×2=64张NPU。MoE模型还可以加上EP=4,把专家分布到4个NPU组上。
组合的关键是通信组的划分。每个并行维度都有自己的通信组,组内的NPU需要频繁通信。TP组是单机内的8张卡,PP组是跨机的同stage卡,DP组是跨机的同位置卡。这些通信组不能冲突,否则会出现死锁或性能问题。
MindSpore里可以通过strategy配置来定义每个维度的切分方式。比如:
from mindspore import context import mindspore.nn as nn from mindspore.parallel import set_algo_parameters # 设置并行模式 context.set_auto_parallel_context( parallel_mode="semi_auto_parallel", device_num=64, global_rank=0, gradients_mean=True, enable_parallel_optimizer=True ) # 定义切分策略 strategy = { "input": (8, 1, 1), # TP=8 "weight": (8, 1), # TP=8 "output": (1, 4, 2) # PP=4, DP=2 }这段代码只是示意,实际配置要复杂得多。但核心思路是:每个算子的输入输出张量都标注切分维度,框架根据这些标注自动生成通信算子。
4. 实操过程:从单卡到集群的完整迁移
4.1 环境准备与集群初始化
假设你手里有一个昇腾集群,比如8台服务器,每台8张NPU,总共64卡。第一步是环境准备。
首先确认CANN和MindSpore的版本匹配。昇腾的软件栈版本兼容性比较严格,CANN 7.0对应MindSpore 2.0,CANN 8.0对应MindSpore 2.2。版本不匹配会出现各种奇怪的错误,比如算子找不到、通信超时。
然后配置HCCL的环境变量。关键的有:
export HCCL_WHITELIST_DISABLE=1 export HCCL_INTRA_ROCE_ENABLE=1 export HCCL_EXEC_TIMEOUT=600 export HCCL_CONNECT_TIMEOUT=120HCCL_EXEC_TIMEOUT是通信超时时间,默认是300秒。大模型训练时,某些集合通信可能耗时较长,建议调到600秒以上。HCCL_CONNECT_TIMEOUT是建链超时,集群规模大时也要适当增加。
集群初始化时,每个NPU进程需要知道自己的rank和总卡数。通常用rank_table文件来配置,里面记录了每张卡的IP、端口、device_id。这个文件可以用昇腾提供的工具自动生成,也可以手动写。手动写的话,注意IP和device_id的对应关系不能错,否则通信组会建错。
4.2 模型切分策略的配置
环境准备好后,开始配置模型切分。以MindSpore为例,有两种方式:自动并行和半自动并行。
自动并行最简单,设置parallel_mode="auto_parallel",框架会自动搜索策略。但自动并行对复杂模型效果一般,而且搜索过程可能很慢。半自动并行需要手动指定每个算子的切分策略,灵活但工作量大。
我的建议是:先用自动并行跑一遍,看看框架给出的策略是什么,然后在此基础上手动调整。MindSpore提供了strategy的导出功能,可以把自动搜索的策略保存下来,然后手动修改。
对于Transformer类模型,切分策略有一些经验规律:
- Embedding层:按词表维度切分,做张量并行。
- 注意力层:Q、K、V投影按列切分,输出投影按行切分。
- FFN层:第一个线性层按列切分,第二个按行切分。
- LayerNorm:通常不切分,或者按特征维度切分。
- 输出层:按词表维度切分,配合张量并行。
这些规律不是绝对的,但可以作为起点。实际调优时,要根据通信量和计算量的平衡来调整。
4.3 通信组划分与HCCL配置
通信组划分是多维混合并行的核心。以TP=8、PP=4、DP=2为例,64张卡要分成多个通信组。
TP组:每8张卡一个组,共8个组。组内做AllReduce。 PP组:每个stage有16张卡(8×2),共4个stage。stage之间传递激活值。 DP组:每个位置有2张卡(跨2个DP副本),共32个组。组内做梯度AllReduce。
通信组的划分要保证:同一TP组内的卡在同一台服务器内;同一PP组的卡可以跨服务器;同一DP组的卡跨服务器。
HCCL会根据通信组的配置自动选择通信算法。对于TP组的AllReduce,HCCL会用Ring或Tree算法;对于DP组的AllReduce,会用分层算法。如果发现通信性能不达标,可以手动指定算法:
export HCCL_ALGO="Ring" export HCCL_REDUCE_ALGO="HD"HD是分层归约,适合跨机场景。Ring适合单机内。
4.4 训练启动与性能监控
配置完成后,启动训练。昇腾集群通常用mpirun或rank_table方式启动。启动命令类似:
mpirun -n 64 --hostfile hostfile \ python train.py \ --config config.yaml \ --rank_table rank_table.json训练启动后,要密切监控性能。关键指标包括:
- NPU利用率:用
npu-smi查看,理想情况是接近100%。如果某张卡利用率低,说明负载不均衡。 - HCCL通信带宽:用
hccn_tool查看,确认通信没有成为瓶颈。 - 显存占用:用
npu-smi查看,确保没有OOM。 - 迭代时间:记录每个迭代的耗时,观察是否稳定。
如果发现性能不达标,先看NPU利用率。如果所有卡利用率都低,可能是通信瓶颈;如果部分卡利用率低,可能是负载不均衡。
4.5 调优实战:一个千亿模型的切分案例
假设我们要训练一个千亿参数的MoE模型,128张NPU,每台8卡,共16台服务器。模型有64层,每层有一个MoE层,8个专家。
切分策略如下:
- TP=8:单机内做张量并行,切分注意力层和FFN层。
- PP=8:跨8台服务器做流水线并行,每台服务器放8层。
- DP=2:再复制2份,跨2组服务器。
- EP=4:每个MoE层的8个专家分布到4张卡上,每张卡2个专家。
总卡数:8×8×2=128,EP=4是在TP组内进一步切分,不增加总卡数。
微批次数量设为32,气泡占比约为(8-1)/(32+8-1)=17.9%。可以接受。
训练启动后,发现NPU利用率只有70%。排查发现,MoE层的All2All通信耗时较长。优化方案:把EP的通信组限制在单机内,即每台服务器内的8张卡做EP,专家不跨机。这样All2All的延迟大幅降低,利用率提升到85%。
进一步优化:调整容量因子,从1.0降到0.8,减少token丢弃,同时用辅助损失鼓励均衡路由。利用率提升到90%以上。
5. 常见问题与排查技巧实录
5.1 通信超时与建链失败
现象:训练启动时卡住,日志显示HCCL建链超时。
排查思路:
- 检查
rank_table文件,确认IP和device_id对应正确。 - 检查网络连通性,用
ping和hccn_tool测试。 - 检查防火墙设置,确保HCCL使用的端口开放。
- 增加
HCCL_CONNECT_TIMEOUT环境变量。
避坑技巧:集群规模大时,建链时间会很长。建议先用小规模(比如8卡)验证配置,再扩展到全集群。
5.2 显存溢出(OOM)
现象:训练过程中报OOM错误。
排查思路:
- 检查切分策略,确认每张卡的显存占用是否均衡。
- 减小微批次大小或梯度累积步数。
- 开启重计算(recompute),用计算换显存。
- 检查是否有内存泄漏,比如未释放的中间张量。
避坑技巧:昇腾NPU的显存管理比较严格,建议预留10%到20%的显存余量。MindSpore提供了mindspore.nn.AdamWeightDecay等优化器,可以开启enable_parallel_optimizer来切分优化器状态,进一步降低显存。
5.3 负载不均衡
现象:部分NPU利用率高,部分低。
排查思路:
- 检查流水线并行的stage切分,确认每层计算量均衡。
- 检查MoE的路由策略,确认专家负载均衡。
- 检查数据并行的数据分发,确认每个卡拿到的数据量一致。
避坑技巧:流水线并行切分时,可以用计算量估算工具来辅助。MindSpore提供了mindspore.parallel.auto_parallel的profile功能,可以分析每个stage的计算量。
5.4 通信性能不达标
现象:HCCL通信带宽远低于理论值。
排查思路:
- 检查通信组划分,确认高通信密度的并行放在高带宽域内。
- 检查HCCL算法选择,尝试不同的算法。
- 检查网络拓扑,确认没有跨交换机瓶颈。
- 检查是否有其他进程占用网络带宽。
避坑技巧:昇腾集群的HCCS带宽通常很高,但RoCE网络可能成为瓶颈。如果跨机通信量大,考虑用IB网络替代RoCE。
5.5 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 训练启动卡住 | HCCL建链超时 | 检查rank_table和网络 | 增加超时时间,检查防火墙 |
| OOM | 显存不足 | 查看npu-smi | 减小微批次,开启重计算 |
| 利用率低 | 负载不均衡 | 查看各卡利用率 | 调整切分策略,均衡负载 |
| 通信慢 | 通信组划分不合理 | 查看HCCL带宽 | 调整通信组,优化算法 |
| 梯度爆炸 | 学习率过大 | 查看梯度范数 | 调整学习率,加梯度裁剪 |
| 精度下降 | 并行策略影响 | 对比单卡结果 | 检查切分是否正确,调整通信 |
6. 一些个人体会与后续扩展方向
多维混合并行在昇腾AI集群上的落地,说到底是一个“平衡”的活儿。计算和通信要平衡,显存和算力要平衡,并行度和气泡要平衡。没有一套放之四海而皆准的配置,每个模型、每个集群都需要针对性地调优。
我个人的经验是,先从简单的并行策略开始,比如纯数据并行或纯张量并行,跑通了再逐步叠加其他维度。每加一个维度,都要重新评估通信开销和负载均衡。不要一上来就搞最复杂的配置,那样出了问题很难定位。
另外,昇腾的软件栈更新比较快,CANN和MindSpore的版本迭代会带来性能提升和新特性。建议定期关注官方文档和社区,看看有没有新的并行策略或优化工具。比如最近MindSpore在自动并行方面有不少改进,对MoE模型的支持也更好了。
后续如果要进一步扩展,可以考虑几个方向:一是结合昇腾的图编译能力,做更激进的算子融合和内存复用;二是探索异构并行,把部分计算放到CPU或其他加速器上;三是优化MoE的路由算法,进一步降低All2All的通信开销。这些方向都有不少工程细节可以挖,等有机会再展开聊。