分布式并行训练
当模型规模超出单卡容量时,动态图(PyNative)训练采用 多维混合并行,把模型与数据按不同维度切分到多张卡上协同训练。可按需组合多种切分方法:按数据切分(数据并行 / FSDP)、按算子内权重切分(张量并行 TP)、按序列切分(上下文并行 CP)、按模型层切分(流水线并行 PP)、按 MoE 专家切分(专家并行 EP)。所有并行配置都写在配置文件的 parallelism 字段。
这些并行能力由 HyperParallel 提供,是动态图训练的必需依赖(要求 MindSpore >= 2.10)。安装方式见 安装指南 · 安装 HyperParallel。
本页的使用顺序如下:
选维度:在「并行能力」中,根据模型规模与显存情况选择需要开启的并行维度;
配参数:参考「并行配置方法」,设置并行度与批大小两类参数;
校验启动:参考各维度的场景示例完成 YAML 配置,确认满足「并行配置约束」后启动训练。
并行能力
下表列出动态图支持的并行维度,可先根据模型规模与显存情况选择需要开启的维度:
维度 |
配置字段 |
切分对象 |
典型场景 |
|---|---|---|---|
数据并行 / FSDP |
|
样本维 + 参数/梯度/优化器状态分片 |
几乎所有训练的基础;显存紧张时增大分片度 |
HSDP(副本+分片) |
|
节点内分片、跨节点复制 |
多节点训练,需用节点内带宽做分片、节点间做复制 |
张量并行 TP |
|
算子内权重(注意力/FFN 线性层) |
单层权重无法在单卡容纳的大模型 |
上下文并行 CP |
|
序列维(含注意力计算) |
长序列(长上下文/长文档),激活显存超出单卡容量时 |
流水线并行 PP |
|
模型按层切到多个 stage |
层数较多、单卡无法容纳整个模型;常与 TP/DP 组合 |
专家并行 EP |
|
MoE 专家分布到不同卡 |
MoE 模型(DeepSeek-V3 等) |
序列并行 SP |
(随 TP 自动开启) |
TP 未切分部分(LayerNorm/Dropout/残差)的序列维 |
开启 TP 即自动生效,无需也无法单独配置 |
并行配置方法
分布式并行配置分为并行度与批大小两类参数,分别写在配置文件的不同字段中。
① 并行度(写在 parallelism 字段)
按「并行能力」表选出要开启的维度,设置对应的并行度;未开启的维度保持默认 1。
配置项 |
说明 |
|---|---|
|
数据并行分片度。默认 |
|
张量并行度 |
|
上下文并行度 |
|
流水线并行度 |
|
专家并行度(仅 MoE 模型需要) |
② 批大小(写在 training 字段)
配置项 |
说明 |
|---|---|
|
一个训练步(一次优化器更新)累计消费的样本总数 |
|
每张卡一次前向处理的样本数 |
配好后,框架会自动推导数据并行维度、梯度累积步数等数值,并校验总卡数与批大小是否匹配——这些推导与约束规则统一见文末「并行配置约束」。
全局配置示例与字段汇总
下面是一份覆盖主要 parallelism 字段的“总览型”配置,便于对照字段含义;实际使用时,按下文各维度的场景示例裁剪即可。
parallelism:
# —— 数据并行 / FSDP / HSDP ——
data_parallel_shard: -1 # 用户唯一需要配的 DP 字段;-1=剩余卡全部做分片(纯 FSDP)
reshard_after_forward_policy: "default" # 前向后是否重新分片参数:always / never / default
cpu_offload: False # 将分片后的参数/梯度卸载到 CPU
disable_gradient_division: True # 关闭 FSDP 自动梯度均分(按 sum 聚合)
# —— 张量并行 TP ——
tensor_parallel: 1
# —— 上下文并行 CP ——
context_parallel: 1
context_parallel_method: "colossal" # colossal / ulysses / hybrid
context_parallel_async: False
ulysses_degree_in_cp: null # ulysses / hybrid 时按规则取值
context_parallel_mask_type: "causal"
# —— 流水线并行 PP ——
pipeline_parallel: 1
pipeline_parallel_interleave_num: 1 # 每个 stage 的交织模型块数
pipeline_parallel_layers_per_stage: null # pp>1 时必填:auto(均分)或各 stage 层区间列表,见 4.4
pipeline_parallel_overlap_p2p: False
pipeline_parallel_overlap_b_f: False
# —— 专家并行 EP(MoE)——
expert_parallel: 1 # 须整除 dp_shard*cp*tp(专家分片网格 efsdp 由此计算得出)
moe_token_dispatcher_type: "alltoall" # alltoall / alltoall_deredundancy
npu_nums_per_device: 8
# —— 序列并行 SP ——
# SP 随 TP 自动开启,当前不支持单独关闭,无需在此配置(见第六节)
一、数据并行与 FSDP / HSDP
1.1 概述
动态图默认采用 FSDP(全分片数据并行) 方案:在分片组内对参数、梯度、优化器状态做切分,前向/反向时按需 all-gather 权重、reduce-scatter 梯度。框架进一步把数据并行拆成两层:
dp_shard(分片度):组内对参数/梯度/优化器状态做切分——节省显存,组内有 all-gather/reduce-scatter 通信。dp_replicate(副本度):组间整份复制权重、只在反向同步梯度——经典数据并行,通信少但不节省显存。
两者都大于 1 时即 HSDP(混合分片数据并行):节点内分片、跨节点复制,兼顾节省显存与降低跨节点通信。只要 dp_shard > 1 或 cp > 1,FSDP 就会启用。
1.2 适用场景与选型
基线:单机多卡训练直接用纯 FSDP(
data_parallel_shard: -1,副本度为 1),把全部数据并行卡用于分片,显存利用率最高。显存不足:优先增大分片度(即让更多卡加入同一分片组)。显存极度紧张时再叠加
cpu_offload、reshard_after_forward_policy: always。多节点希望降低跨节点通信:使用 HSDP——把分片度设为「节点内卡数」,让框架推导出「副本度 = 节点数」,分片通信通过节点内高带宽完成,副本只做梯度 all-reduce。配置上只需把
data_parallel_shard设成一个小于数据并行维度的正数。
1.3 字段表
字段 |
类型 |
默认值 |
说明 |
|---|---|---|---|
|
int |
|
分片度(dp_shard)。 |
|
str |
|
前向后是否重新分片参数: |
|
bool |
|
将分片后的参数/梯度卸载到 CPU 内存,进一步节省显存,代价是 H2D/D2H 拷贝。 |
|
bool |
|
关闭 FSDP 自动梯度均分:以 sum 而非 mean 聚合梯度(对所有 HSDP 子模块设 reduce op = "sum")。 |
常见问题:
disable_gradient_division=True是默认值,意味着 FSDP 梯度按 sum 聚合而非取平均。由此带来的数量级差异,框架会在反向传播的 loss 缩放(系数1/(world_size//pp))与梯度范数计算中自动修正,无需用户手动设置任何缩放系数。reshard_after_forward_policy: default在 PP 下解析为never:因为 PP 每个 microbatch 都会重复前向,若每次都 reshard 会带来反复 all-gather,故默认保留聚合权重。
1.4 场景配置
场景 A:单机 8 卡纯 FSDP(推荐基线)
8 卡全部做分片,副本度为 1。满足 dp_replicate(1) * dp_shard(8) * cp(1) * tp(1) * pp(1) == 8。
parallelism:
data_parallel_shard: -1 # 此时框架自动推导为 8
reshard_after_forward_policy: "default"
cpu_offload: False
disable_gradient_division: True
tensor_parallel: 1
context_parallel: 1
pipeline_parallel: 1
expert_parallel: 1
场景 B:双机 16 卡 HSDP(节点内分片 + 跨节点复制)
每节点 8 卡,希望节点内分片、节点间复制。把分片度设为 8,框架推导出 data_parallel = 16、dp_replicate = 16 // 8 = 2、dp_shard = 8。满足 2 * 8 * 1 * 1 * 1 == 16。
parallelism:
data_parallel_shard: 8 # 节点内 8 卡分片;副本度 2 由框架推导
reshard_after_forward_policy: "default"
cpu_offload: False
disable_gradient_division: True
tensor_parallel: 1
context_parallel: 1
pipeline_parallel: 1
二、张量并行(TP)
2.1 概述
tensor_parallel 指定 TP 规模,对注意力与 FFN 中的线性层权重在 算子内 做列/行切分(apply_non_moe_tp 用 ColwiseParallel / RowwiseParallel),组内通过 all-gather / all-reduce 同步激活。
2.2 适用场景与选型
单层权重无法在单卡容纳、或单卡注意力/FFN 激活过大时启用。
TP 通信发生在 每一层的前反向,对带宽极敏感,通常只在单节点内 开(TP 组规模一般 ≤ 节点内卡数,如 2/4/8)。
与 FSDP 正交:
world_size = dp_total * tp * pp * cp,开了 TP 后剩余卡数自动用于数据并行。
2.3 字段表
字段 |
类型 |
默认值 |
说明 |
|---|---|---|---|
|
int |
|
张量并行规模, |
2.4 场景配置:单机 8 卡 DP + TP 微调
tp=2,剩余 data_parallel = 8 // 2 = 4 全部用于分片(data_parallel_shard: -1 推导出 dp_shard = 4)。满足 1 * 4 * 1 * 2 * 1 == 8。
parallelism:
data_parallel_shard: -1 # 此时框架自动推导为 4
tensor_parallel: 2
context_parallel: 1
pipeline_parallel: 1
expert_parallel: 1
reshard_after_forward_policy: "default"
disable_gradient_division: True
三、上下文并行(CP)
3.1 概述
context_parallel 在 序列维 对输入进行切分,使每张卡只处理一段序列,显著降低长序列下的激活显存与注意力计算量;FlashAttention 在 CP 组内交换 KV 完成全序列注意力。动态图支持三种实现方法 context_parallel_method:
方法 |
原理 |
约束( |
|---|---|---|
|
默认;按序列分块、组内交换 KV |
无额外约束; |
|
在注意力 head 维做 all-to-all 切分 |
要求 |
|
colossal + ulysses 混合 |
必须设 |
3.2 适用场景与选型
主要用于 长序列/长上下文(
seq_length很大、激活显存超出单卡容量)。CP 组规模越大,单卡序列越短、激活显存越省,但组内 KV 交换通信也越多。colossal:通用首选,序列切分直接,无 head 整除限制。ulysses:在 head 维切分,更适合 head 数较多的模型;启用 async 时要保证 head 数能被 ulysses 度整除。hybrid:把 CP 拆成「序列分块 × head 切分」两层,适合既需切分长序列、又需 head 维并行的超长序列场景。
CP 与 FSDP 的耦合:启用 CP 时,FSDP 也会作用于 CP 组:分片网格名为 fsdp,规模为 dp_shard * cp,即便 dp_shard == 1(见 parallel_dims.py 的 fsdp_enabled / fsdp 属性)。也就是说开 CP 会自动让参数在 CP 组内分片,无需单独配置。
此外,CP 在前向开始前会把一个 batch 的输入(input_ids、position_ids、掩码等)沿序列维切分并分发到 CP 组各卡,使每张卡只拿到自己负责的那段序列——这一步称为 CP 输入准备。它目前仅支持 context_parallel_mask_type: causal,传入其它值会直接抛 NotImplementedError,也不接受用户自定义的 attention_mask:CP 依赖模型侧的压缩注意力掩码,必须按下文 3.3 开启掩码压缩。
3.3 注意力掩码压缩(CP 必需)
context_parallel > 1 时必须开启注意力掩码压缩,否则 context_parallel.py 的 apply_context_parallel_model_io 会直接抛错:
Context parallel (context_parallel > 1) requires a compressed attention mask.
Please enable use_attn_mask_compression for non-eod data, or
create_compressed_eod_mask for eod data.
必须压缩的原因(显存开销):未压缩时,注意力掩码是一张 seq_length × seq_length 的稠密布尔矩阵。CP 主要服务于长序列场景,seq_length 很大时这张稠密 mask 本身就会占用大量显存(与 CP「节省激活显存」的目标相悖),且各 CP rank 还需各自持有并切分它。压缩掩码只保留生成因果/EOD 掩码所需的紧凑信息(如各子序列长度),由模型在注意力算子内即时重建,避免物化稠密矩阵。因此 CP 强制要求压缩,并建议关闭数据集侧的稠密掩码构建。
按数据集类型分两种配法。这里的「EOD 数据集」指:为提高吞吐,预训练常把多篇较短的文档拼接(packing)进同一条定长序列,文档之间用一个 EOD(End-Of-Document,文档结束)特殊 token 分隔;同时配 reset_position_ids / reset_attention_mask,使注意力不跨越文档边界(每篇文档内部各自做因果注意力)。这类数据集的掩码不再是单一的整段下三角,而是「分段块对角」结构,需用 create_compressed_eod_mask 记录各子序列长度(actual_seq_len)来紧凑表达。非拼接、一条序列即一篇文档的常规数据则属「非 EOD 数据集」,采用通用因果掩码压缩即可。
非 EOD 数据集:在 YAML 的
model字段开启use_attn_mask_compression(通用因果掩码压缩):model: # ... use_attn_mask_compression: true # 非 eod 数据集:模型侧开启因果掩码压缩
EOD 数据集:在 YAML 的数据集
dataloader.config字段开启create_compressed_eod_mask,并把create_attention_mask设为false(避免再额外构建稠密掩码、节省显存):train_dataset: dataloader: config: # ... create_compressed_eod_mask: true # eod 数据集:生成压缩 EOD 掩码(同步开启模型侧 eod 掩码压缩) create_attention_mask: false # 关闭稠密 attention_mask 构建,节省显存
create_compressed_eod_mask: true会被框架同步到模型侧的use_eod_attn_mask_compression,满足 CP 的压缩要求;create_attention_mask: false则确保数据管线不再物化那张seq_length × seq_length稠密掩码。
3.4 字段表
字段 |
类型 |
默认值 |
说明 |
|---|---|---|---|
|
int |
|
上下文并行规模。 |
|
str |
|
CP 实现方法: |
|
bool |
|
启用异步 CP 通信钩子(Hyper-Parallel);与 |
|
int |
|
Ulysses 维度。 |
|
str |
|
CP 输入准备(按序列维切分输入,见 3.2)所用的掩码类型,仅支持 |
3.5 场景配置
以下
parallelism示例均需配合 3.3 的掩码压缩配置(在model或数据集dataloader.config字段)一起使用,此处从略。
场景 A:单机 8 卡 colossal CP(长序列)
cp=2,剩余 data_parallel = 8 // 2 = 4 做分片。FSDP 分片组规模 = dp_shard(4) * cp(2) = 8。满足 1 * 4 * 2 * 1 * 1 == 8。
parallelism:
data_parallel_shard: -1 # 此时框架自动推导为 4
tensor_parallel: 1
context_parallel: 2
context_parallel_method: "colossal"
context_parallel_mask_type: "causal"
pipeline_parallel: 1
场景 B:ulysses CP(head 维切分)
cp=4,ulysses 要求 ulysses_degree_in_cp == context_parallel。满足 1 * 2 * 4 * 1 * 1 == 8(data_parallel = 8//4 = 2)。
parallelism:
data_parallel_shard: -1 # 此时框架自动推导为 2
context_parallel: 4
context_parallel_method: "ulysses"
ulysses_degree_in_cp: 4 # 必须等于 context_parallel
context_parallel_async: False # 若设 True,需保证 num_attention_heads % 4 == 0
tensor_parallel: 1
pipeline_parallel: 1
场景 C:hybrid CP(序列分块 × head 切分)
cp=4,hybrid 要求 1 < ulysses_degree_in_cp < cp 且整除 cp,故取 2。满足 1 * 2 * 4 * 1 * 1 == 8。
parallelism:
data_parallel_shard: -1 # 此时框架自动推导为 2
context_parallel: 4
context_parallel_method: "hybrid"
ulysses_degree_in_cp: 2 # 1 < 2 < 4 且 4 % 2 == 0
context_parallel_mask_type: "causal"
tensor_parallel: 1
pipeline_parallel: 1
四、流水线并行(PP)
4.1 概述
pipeline_parallel 把模型 按层切分到多个 stage,配合 microbatch 流水执行。动态图内部固定使用交织式 1F1B 调度器(ScheduleInterleaved1F1B),通过 interleave 把每个 stage 切成多个虚拟模型块以减小流水线气泡。
4.2 适用场景与选型
模型层数较多、单卡无法容纳整个模型时启用;常与 TP(节点内)、DP(节点间)组合成 3D 并行。
增大
pipeline_parallel_interleave_num可进一步减小气泡,但会增加 stage 间 P2P 通信次数;可叠加pipeline_parallel_overlap_p2p把通信与计算重叠。
微批数与调度策略(自动推导 / 预留):
pipeline_parallel_microbatch_size由框架自动推导,不是用户可配项。trainer.py 会用梯度累积步数覆盖它:num_accumulation_steps = global_batch_size // (data_parallel * local_batch_size)(其中data_parallel = dp_replicate * dp_shard为数据并行维度),随后pipeline_parallel_microbatch_size = num_accumulation_steps。所以需通过global_batch_size/local_batch_size间接控制微批数(见 配置文件说明),手填该字段无效。pipeline_parallel_schedule(ParallelismConfig中默认"1f1b")当前未参与分支:动态图固定使用上述交织式 1F1B 调度,该字符串不被读取,属预留项。真正影响流水行为的是pipeline_parallel_interleave_num与pipeline_parallel_overlap_p2p/pipeline_parallel_overlap_b_f。pipeline_parallel_enable_dxdw_split(默认False)当前为预留项:ParallelismConfig中定义了该字段(用于 PP 中 dx/dw 通信拆分),但动态图代码中暂未读取使用,改动它不会改变行为,属预留/占位项,无需填写。
4.3 字段表
字段 |
类型 |
默认值 |
说明 |
|---|---|---|---|
|
int |
|
流水线 stage 数。 |
|
int |
|
每个 stage 的交织模型块数(虚拟 stage 数 = |
|
list/str |
|
各 stage 的层分配。 |
|
bool |
|
启用 stage 间 P2P 通信与计算重叠。 |
|
bool |
|
启用反向(b)与前向(f)计算重叠。 |
|
int |
|
由框架自动推导,运行时被 |
|
str |
|
预留项,动态图固定用交织 1F1B,当前不参与分支。 |
|
bool |
|
预留项,PP 中 dx/dw 通信拆分开关,当前动态图未读取使用,不影响行为。 |
4.4 场景配置
pp > 1 时必须通过 pipeline_parallel_layers_per_stage 指定各 stage 的层放置,按层数能否均分选择以下两种方式之一。
场景一:层数可均匀放置时配置 auto
当 num_hidden_layers 能被虚拟 stage 总数(pp * interleave_num)整除时,配置 auto 即可,框架按虚拟 stage 顺序把层连续均分(每个虚拟 stage 分得 num_hidden_layers / (pp * interleave_num) 层)。例如 8 层模型、pp=2、interleave_num=2:4 个虚拟 stage 各放 2 层。
parallelism:
data_parallel_shard: -1
tensor_parallel: 4
pipeline_parallel: 2
pipeline_parallel_interleave_num: 2 # 虚拟 stage 总数 = 2 * 2 = 4
pipeline_parallel_layers_per_stage: auto
pipeline_parallel_overlap_p2p: True
若层数不能整除而仍配置 auto,启动时会报错并提示改用显式配置。
场景二:层数不能均分时显式指定各 stage 的层区间
列表每一项对应一个物理 stage(第 i 项给 pp_rank = i);项内用逗号分隔出 interleave_num 段层区间,第 k 段是该卡的第 k 个交织模型块,对应虚拟 stage 编号 k * pp + i。区间写法为 "start-end"(闭区间)或单层 "n",所有区间按虚拟 stage 顺序必须恰好覆盖 0 ~ num_hidden_layers-1 且层号递增。
以 10 层模型(层号 0–9)、pp=2、interleave_num=2 为例,10 % 4 != 0 无法均分,可显式配置:
parallelism:
data_parallel_shard: -1
tensor_parallel: 4
pipeline_parallel: 2
pipeline_parallel_interleave_num: 2
pipeline_parallel_layers_per_stage:
- "0-1, 4-8" # 物理 stage 0:虚拟 stage 0 放层 0-1,虚拟 stage 2 放层 4-8
- "2-3, 9" # 物理 stage 1:虚拟 stage 1 放层 2-3,虚拟 stage 3 放层 9
pipeline_parallel_overlap_p2p: True
层的执行顺序依次为虚拟 stage 0、1、2、3,即层 0-1、2-3、4-8、9。各 stage 层数可以不等(如本例为 2/2/5/1),可用于平衡首尾 stage 上 embedding / lm_head 的额外显存与计算。
五、专家并行(EP)
5.1 概述
针对 MoE 模型(DeepSeek-V3 等),expert_parallel 把专家分布到不同卡,token 经 all-to-all 路由到所在卡的专家计算(apply_moe_ep_tp)。EP 不是独立的卡维度——它不出现在 dp_replicate * dp_shard * cp * tp * pp == world_size 的乘积里,而是 复用在 dp_shard * cp * tp 这片卡上:parallel_dims.py 的 build_mesh 为专家单独构造一张稀疏网格 ["pp", "dp_replicate", "efsdp", "ep"],专家的 FSDP 分片网格 efsdp 由下式计算得到:
efsdp = dp_shard * cp * tp // expert_parallel
网格 |
维度 |
适用对象 |
|---|---|---|
dense(稠密) |
|
非专家参数(注意力 / 共享 FFN 等) |
sparse(稀疏, |
|
MoE 专家参数 |
因此 expert_parallel 必须整除 dp_shard * cp * tp(否则 efsdp 不是正整数,框架构建网格时报错)。ep 越大,efsdp 越小、单卡专家越少、显存越省,但 all-to-all 通信越多。专家是否随 TP 切分不需单独配置,由上面的 efsdp 公式从 tensor_parallel / expert_parallel 的相对大小自动得到。
5.2 适用场景与选型
仅 MoE 模型需要。专家数较多、单卡无法容纳全部专家时启用 EP;
expert_parallel越大,单卡专家越少、显存占用越低,all-to-all 通信越多。专家是否随 TP 切分由
ep与tp的相对大小自动决定:当ep <= tp时efsdp = dp_shard*cp*tp//ep仍含tp的因子,相当于专家权重在 EP 之外还保留部分 TP 切分;当ep增大到将tp因子用尽(ep接近cp*tp乃至更大)时,专家主要由 EP 分布、TP 切分弱化。约束始终是ep整除dp_shard*cp*tp。alltoallvsalltoall_deredundancy:alltoall是默认全连接 all-to-all 分发;alltoall_deredundancy(DeredundancyExpertParallel)用「节点间外层 all-gather/reduce-scatter + 节点内 all-to-all」的去冗余方案降低跨节点通信,仅在多机大 EP 时收益明显,并要求expert_parallel >= npu_nums_per_device(否则ParallelismConfig.__post_init__直接报错)。
5.3 字段表
字段 |
类型 |
默认值 |
说明 |
|---|---|---|---|
|
int |
|
专家并行规模;须整除 |
|
str |
|
token 分发方式: |
|
int |
|
每节点 NPU 数, |
5.4 场景配置
场景 A:单机 8 卡 MoE,EP ≤ TP(专家保留部分 TP 切分)
tp=4、ep=2(ep <= tp)。剩余 data_parallel = 8//(4*1*1) = 2,故 dp_shard = 2。满足总规模 1 * 2 * 1 * 4 * 1 == 8;ep(2) 整除 dp_shard*cp*tp = 2*1*4 = 8,专家分片网格 efsdp = 8//2 = 4。
parallelism:
data_parallel_shard: -1 # 此时框架自动推导为 2
tensor_parallel: 4
expert_parallel: 2 # 须整除 dp_shard*cp*tp(=8)
moe_token_dispatcher_type: "alltoall"
context_parallel: 1
pipeline_parallel: 1
场景 B:多机 16 卡 MoE,EP > TP + 去冗余分发
tp=2、ep=8(ep > tp);用去冗余分发,要求 ep(8) >= npu_nums_per_device(8)。剩余 data_parallel = 16//(2*1*1) = 8,故 dp_shard = 8。满足总规模 1 * 8 * 1 * 2 * 1 == 16;ep(8) 整除 dp_shard*cp*tp = 8*1*2 = 16,专家分片网格 efsdp = 16//8 = 2(专家主要由 EP 分布,TP 切分被 EP 占用一部分)。
parallelism:
data_parallel_shard: -1 # 此时框架自动推导为 8
tensor_parallel: 2
expert_parallel: 8 # 须整除 dp_shard*cp*tp(=16);并 >= npu_nums_per_device
moe_token_dispatcher_type: "alltoall_deredundancy"
npu_nums_per_device: 8 # 要求 expert_parallel >= 此值
context_parallel: 1
pipeline_parallel: 1
六、序列并行(SP)
序列并行(SP)在 TP 的基础上,对 TP 未切分的部分(LayerNorm、Dropout、残差)按 序列维 进一步切分,降低这些算子的激活显存。
SP 随 TP 自动开启,当前不支持单独关闭:动态图 SPMD 路径中,只要开启 TP(tensor_parallel > 1)就会自动施加 SP:源码 base_models/gpt/parallelize.py 调用 apply_non_moe_tp 时形参 enable_sp 恒为 True,不读取 sequence_parallel 配置字段,因此当前无法通过配置关闭 SP。
注意:
sequence_parallel字段仍会被 transformer_block.py 的TransformerBlock.__init__读取,但仅用于检测 CP 与 SP 的冲突并输出告警(cp > 1且sequence_parallel=True时提示「SP 与 CP 冲突,SP 被忽略」),它不是 SP 的功能开关。
因此无需为 SP 单独配置:按本页第二节配好 TP(tensor_parallel > 1),SP 即自动生效。
并行配置约束
设备网格的总规模必须满足以下整除关系,否则启动时框架会直接报错:
总规模:
dp_replicate * dp_shard * cp * tp * pp == world_size(world_size即msrun的总卡数)。其中dp_replicate(副本度)与dp_shard(分片度)由框架自动推导,用户只配data_parallel_shard。数据并行维度:
data_parallel = world_size // (tp * pp * cp),必须 ≥ 1,且能被推导出的dp_shard整除。批大小:
data_parallel * local_batch_size <= global_batch_size,否则报错。框架据此推导梯度累积步数num_accumulation_steps = global_batch_size // (data_parallel * local_batch_size);开大并行度会减小data_parallel,在批大小不变时累积步数随之变大。TP / SP:
tensor_parallel > 1才有意义;SP 随 TP 自动开启(无独立开关,当前不支持关闭,见第六节)。CP 方法:
ulysses要求ulysses_degree_in_cp == context_parallel;hybrid要求1 < ulysses_degree_in_cp < context_parallel且整除;ulysses + async还要求num_attention_heads % ulysses_degree == 0;CP 启用时 FSDP 分片组规模为dp_shard * cp。CP 掩码压缩(必需):
context_parallel > 1时必须开启压缩掩码——非 EOD 数据在model字段设use_attn_mask_compression: true,EOD 数据在数据集dataloader.config字段设create_compressed_eod_mask: true且create_attention_mask: false,否则报错「requires a compressed attention mask」(见 3.3)。EP:
expert_parallel必须整除dp_shard * cp * tp(专家分片网格efsdp = dp_shard*cp*tp//ep须为正整数);EP 不计入dp_replicate*dp_shard*cp*tp*pp==world_size的乘积;moe_token_dispatcher_type = alltoall_deredundancy时要求expert_parallel >= npu_nums_per_device。
启动
配好 parallelism 与批大小、确认满足上面的并行配置约束后,用 msrun 拉起多卡训练:
msrun --worker_num=8 --local_worker_num=8 --master_port=8118 --join=True \
run_mindformer.py --config your_config.yaml --mode 1
--mode 1 表示 PYNATIVE(动态图);--worker_num 即总卡数 world_size,必须与配置推导出的 dp_replicate * dp_shard * cp * tp * pp 相等,否则启动即报错。