mindspore-ai / mindspore-ai/hyper-parallel
[Benchmark] Qwen3-8B-lite fully_shard 性能对比(torch_npu 原生 vs hyper torch/ms)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 53
- Forks
- 63
- Avg merge
- 23h 45m
- Merged PRs (30d)
- 63
Description
Qwen3-8B-lite fully_shard 性能优化实验全记录
Issue 类型:Benchmark + Profiler 瓶颈分析 + 源码优化验证
测试目录:dev/test/qwen3_8b_hsdp2/
环境:Ascend NPU 8 卡,CANN 9.0,seq_len=4096,batch=1,steps=20/warmup=2
最后更新:2026-06-08(含 P12 norm/lm_head 拆 wrap 负向验证)
零、执行摘要
| 维度 | 结论 |
|---|---|
| 最优配置 | hyper torch + prefetch(1/1) + PR707 → 542 ms/step(FSDP8) |
| vs 原生 | 快 3.7%(原生 563 ms);HSDP24 prefetch 后 持平(790 vs 791 ms) |
| 根因 | hyper 默认慢 不在计算(Computing 反而快 47 ms),在 通信重叠率低(4.6% vs 82.6%)+ per-param collective 碎片化(360 AG vs 38) |
| 关键开关 | prefetch 是质变(-17%);comm_fusion 单独开更慢;P0/P1 让 cf+prefetch 追平原生 |
| 残余热点 | post_backward:norm(~190 ms,不宜拆 wrap)、pre_backward prefetch:layers.7(~107 ms) |
性能演进(FSDP8 hyper torch,ms/step):
默认 658 ──prefetch──► 544 ──PR707──► 542 ⭐ 当前最优
│
└──comm_fusion 单独──► 701(更慢)
└──cf+prefetch──► 581 ──P0──► 568 ──P1──► 565 ≈ 原生 563
一、测试方法与配置
1.1 对比路径
| 标识 | 后端 | 说明 |
|---|---|---|
| 原生 | torch_npu.distributed.fsdp.fully_shard |
NPU 原生 FSDP2 |
| hyper torch | hyper_parallel + HYPER_PARALLEL_PLATFORM=torch |
本 Issue 主要优化对象 |
| hyper MS | hyper_parallel + MindSpore 后端 |
参考对比 |
1.2 统一参数
| 项 | 值 |
|---|---|
| 模型 | Qwen3-8B-lite:dim=4096,layers=8,ffn=12288,32 heads / 8 kv |
| Mesh | FSDP8 (8,) / HSDP24 (2,4) |
| 精度 | bf16 param + fp32 reduce |
| 优化器 | AdamW(lr=1e-4),weight_decay=0 |
| 对齐 | align_data_8b/:init_weights.pt + preset_batches.pt,seed=42 |
| 计时 | warmup 后整步 torch.npu.synchronize() 平均 |
1.3 Profiler 采集
torch_npu.profiler,Level0,with_stack=Falseschedule(wait=2, warmup=1, active=2, repeat=1)→ 分析 rank0 step 3–4- 数据源:
ASCEND_PROFILER_OUTPUT/step_trace_time.csv+operator_details.csv
1.4 开关说明
| 开关 | 含义 |
|---|---|
prefetch |
正反向各预取 1 层(set_modules_to_forward/backward_prefetch) |
comm_fusion |
模块级 fused AG/RS(collective 次数 360→38) |
| P0/P1 | 本地 hyper_parallel/platform/torch/fully_shard/ 源码优化 |
| PR707 | hsdp_scheduler.py:hook 顺序 unshard → prefetch(PR #707) |
二、实验全景(11 项 e2e + 11 项 profiler)
2.1 端到端实验(无 Profiler,steps=20)
| ID | 实验 | Mesh | ms/step | vs 原生 | 结果文件 |
|---|---|---|---|---|---|
| T1 | 原生 默认 | FSDP8 | 563.08 | — | baseline_8card/torch_native_8b_8card_fsdp_s4096.json |
| T2 | hyper 默认 | FSDP8 | 657.88 | +17% | pure_fsdp2_8card/hyper_torch_8b_8card_fsdp_s4096.json |
| T3 | hyper MS 默认 | FSDP8 | 698.16 | +24% | pure_fsdp2_8card/mindspore_8b_8card_fsdp_s4096.json |
| T4 | hyper +prefetch | FSDP8 | 543.59 | -3.5% | hyper_torch_prefetch/..._prefetch.json |
| T5 | hyper +prefetch PR707 | FSDP8 | 542.23 | -3.7% ⭐ | pr707_hyper_torch_prefetch/..._pr707.json |
| T6 | hyper +comm_fusion | FSDP8 | 700.80 | +24% | hyper_torch_comm_fusion/..._comm_fusion.json |
| T7 | 原生 默认 | HSDP24 | 791.28 | — | torch_native_hsdp24/..._foreach_false.json |
| T8 | hyper 默认 | HSDP24 | 1028.15 | +30% | baseline_8card/torch_align_..._hsdp24.json |
| T9 | hyper MS 默认 | HSDP24 | 1051.14 | +33% | baseline_8card/mindspore_align_..._hsdp24.json |
| T10 | hyper +prefetch | HSDP24 | 789.67 | -0.2% | hyper_torch_prefetch/..._hsdp24_prefetch.json |
| T11 | hyper +comm_fusion | HSDP24 | 1100.49 | +39% | hyper_torch_comm_fusion/..._hsdp24_comm_fusion.json |
2.2 Profiler 实验(steps=8,含 profiler 开销)
| ID | 实验 | prof e2e | Stage | Compute | Comm未重叠 | 重叠率 | AG/RS | 目录 |
|---|---|---|---|---|---|---|---|---|
| P1 | 原生 FSDP8 | 566.50 | 566.8 | 521.8 | 40.7 | 82.6% | 38/40 | profiler/torch_native_fsdp8/ |
| P2 | hyper 无 prefetch | 660.46 | 662.9 | 474.7 | 181.5 | 4.6% | 360/364 | profiler/hyper_torch_fsdp8/ |
| P3 | hyper +prefetch | 546.03 | 549.5 | 492.4 | 50.2 | 80.1% | 360/364 | profiler/hyper_torch_fsdp_prefetch/ |
| P4 | hyper +prefetch PR707 | 544.70 | 551.5 | 492.9 | 51.7 | 79.8% | 360/364 | profiler/hyper_torch_fsdp_prefetch_pr707/ |
| P5 | hyper +prefetch fwd1/bwd2 | 544.56 | 551.0 | 491.7 | 52.0 | 80.0% | 360/364 | profiler/hyper_torch_fsdp_prefetch_fwd1_bwd2/ |
| P12 | split norm/lm_head ❌ | 570.71 | 574.7 | 486.6 | 82.7 | 66.0% | 360/364 | profiler/hyper_torch_fsdp_prefetch_split_norm_lm_head/ |
| P6 | cf+prefetch 优化前 | 581.05 | 584.5 | 532.0 | 46.7 | 81.2% | 38/40 | profiler/..._comm_fusion_prefetch/ |
| P7 | cf+prefetch P0 | 568.45 | 570.6 | 519.3 | 44.3 | 81.5% | 38/40 | profiler/..._prefetch_p0/ |
| P8 | cf+prefetch P1 | 565.31 | 567.5 | 515.1 | 46.8 | 80.5% | 38/40 | profiler/..._prefetch_p1/ |
| P9 | 原生 HSDP24 | 792.41 | 798.6 | 626.1 | 165.6 | 71.0% | 38/40 | profiler/torch_native_hsdp24/ |
| P10 | hyper 无 prefetch | 1025.78 | 1028.9 | 515.6 | 505.4 | 32.3% | 360/364 | profiler/hyper_torch_hsdp24/ |
| P11 | hyper +prefetch | 793.15 | 801.0 | 570.3 | 224.2 | 62.9% | 360/364 | profiler/hyper_torch_hsdp24_prefetch/ |
三、优化过程(按阶段)
阶段 0:基线对比(T1/T2/T7/T8)
发现:hyper 默认比原生慢 17%(FSDP8)/ 30%(HSDP24),但 loss 完全对齐。
| Mesh | 原生 | hyper 默认 | 差距 |
|---|---|---|---|
| FSDP8 | 563 ms | 658 ms | +95 ms |
| HSDP24 | 791 ms | 1028 ms | +237 ms |
阶段 1:Profiler 根因定位(P1/P2/P9/P10)
假设:hyper 计算慢?→ 否定。
FSDP8 rank0 分解(step 3–4):
| 指标 | 原生 P1 | hyper 无 prefetch P2 | Δ |
|---|---|---|---|
| Stage | 566.8 ms | 662.9 ms | +96 ms |
| Computing | 521.8 ms | 474.7 ms | -47 ms |
| Comm(未重叠) | 40.7 ms | 181.5 ms | +141 ms |
| Comm(已重叠) | 193.6 ms | 8.7 ms | -185 ms |
| 重叠率 | 82.6% | 4.6% | — |
| collective | 38 AG / 40 RS | 360 AG / 364 RS | 9× 碎片化 |
Stage 差距 +96 ms ≈ Computing -47 ms + Comm(未重叠) +141 ms
HSDP24 同理:hyper Computing 515.6 ms < 原生 626.1 ms,但 Comm(未重叠) 505.4 ms >> 原生 165.6 ms。
根因闭环:逐参数 collective + 无 prefetch → 通信几乎不与计算重叠。
阶段 2:开启 prefetch(T4/T10,P3/P11)
措施:train_hyper_torch.py 增加 --prefetch,正反向各 1 层。
| Mesh | 无 prefetch | +prefetch | 变化 | 重叠率 |
|---|---|---|---|---|
| FSDP8 e2e | 658 ms | 544 ms | -17% | 4.6%→80.1% |
| HSDP24 e2e | 1028 ms | 790 ms | -23% | 32.3%→62.9% |
prefetch 是质变级优化:FSDP8 超越原生,HSDP24 追平。
阶段 3:comm_fusion 路径优化(P6→P7→P8,P0/P1 源码)
背景:comm_fusion 单独开启更慢(T6: 701 ms);但 collective 次数与原生对齐(38/40),适合大模型。
P0 措施(state.py, param_group.py):
post_backward_for_comm_fusion()流水线重排:先 issue 当前层 RS,再 drain 上一层- 每层
_reduce_scatter_handle独立存储 reduce_scatter_copy_in():torch.cat+ 单次 copyensure_flat_param_buffer()延迟初始化
P1 措施(param_group.py, param.py, state.py):
foreach_all_gather_copy_out()AG view 零拷贝release_unshard_buffers()在shard()时释放_reduce_scatter_input跨 step 复用
| 阶段 | prof e2e | vs 优化前 | 关键算子变化 |
|---|---|---|---|
| cf+prefetch 优化前 P6 | 581.05 ms | — | split_with_sizes_copy 45.6 ms |
| P0 P7 | 568.45 ms | -12.6 ms | aten::copy_ 153→115 ms |
| P1 P8 | 565.31 ms | -3.1 ms | split_with_sizes_copy →0 ms |
| 原生 P1 | 566.50 ms | 参考 | — |
| prefetch only P3 | 546.03 ms | 仍最快 | — |
阶段 4:调度微调(P4/P5,PR707 + prefetch 深度)
PR #707:hsdp_scheduler.py forward/backward pre-hook 从 prefetch→unshard 改为 unshard→prefetch。
| 指标 | P3 旧顺序 | P4 PR707 | Δ |
|---|---|---|---|
| e2e(无 profiler) | 543.59 ms | 542.23 ms | -1.36 ms |
| prof e2e | 546.03 ms | 544.70 ms | -1.33 ms |
unshard:tok_embeddings device |
38.7 ms | 35.8 ms | -2.9 ms |
prefetch:layers.7 device |
107.2 ms | 107.5 ms | 不变 |
prefetch 深度扫描 P5(fwd=1, bwd=2):
| 配置 | prof e2e | 重叠率 |
|---|---|---|
| fwd1/bwd1 P3 | 546.03 ms | 80.1% |
| fwd1/bwd2 P5 | 544.56 ms | 80.0% |
加深 prefetch 无收益(差 0.3%,噪声内)。
阶段 5:norm/lm_head 拆 wrap 验证(P12)❌ 负向结果
假设:post_backward:norm(~186 ms)因 norm 与 lm_head 绑在同一 FSDP 单元,RS 粒度过粗;拆分后可降低尾部 RS 耗时。
措施:train_hyper_torch.py 新增 --split-norm-lm-head,将
fully_shard([norm, lm_head]) # 默认
改为
fully_shard(norm); fully_shard(lm_head) # 各自独立 wrap
配置:FSDP8 + prefetch + PR707,其余与 P4 相同。
| 指标 | P4 绑定 norm+lm_head | P12 拆分 | Δ |
|---|---|---|---|
| prof e2e | 544.70 ms | 570.71 ms | +26.0 ms(慢 4.8%) |
| Stage | 551.5 | 574.7 | +23.2 |
| Comm(未重叠) | 51.7 | 82.7 | +31.0 |
| 重叠率 | 79.8% | 66.0% | -13.8 pp |
| AG/RS 次数 | 360/364 | 360/364 | 不变 |
Hook 变化(device ms,rank0,2 step):
| Hook | P4 绑定 | P12 拆分 |
|---|---|---|
post_backward:norm |
185.6 | 47.6 |
post_backward:lm_head |
(含在 norm 内) | 278.5 |
| norm + lm_head 合计 | ~186 | ~326 |
post_backward:layers.7 |
19.8 | 75.8 |
根因:
- 绑定时 norm+lm_head 一次 RS(~186 ms),可与计算较好重叠
- 拆分后变成 两次串行 RS(48 + 279 ms),合计更高且更难重叠
- wrap 单元 11→12,prefetch 链被打断,
layers.7post_backward 从 20→76 ms - lm_head 参数量远大于 norm,不应单独拆出,绑定反而更优
结论:❌ 保持默认 fully_shard([norm, lm_head]),不要拆分。
四、Profiler 深度分析
4.1 FSDP8 配置横向对比(rank0)
| 配置 | Stage | Compute | Comm未重叠 | Comm未重叠占Stage | 重叠率 |
|---|---|---|---|---|---|
| 原生 | 566.8 | 521.8 | 40.7 | 7.2% | 82.6% |
| hyper 无 prefetch | 662.9 | 474.7 | 181.5 | 27.4% | 4.6% |
| +prefetch | 549.5 | 492.4 | 50.2 | 9.1% | 80.1% |
| +prefetch PR707 | 551.5 | 492.9 | 51.7 | 9.4% | 79.8% |
| cf+prefetch P1 | 567.5 | 515.1 | 46.8 | 8.2% | 80.5% |
4.2 HSDP24 配置横向对比(rank0)
| 配置 | Stage | Compute | Comm未重叠 | 重叠率 |
|---|---|---|---|---|
| 原生 | 798.6 | 626.1 | 165.6 | 71.0% |
| hyper 无 prefetch | 1028.9 | 515.6 | 505.4 | 32.3% |
| +prefetch | 801.0 | 570.3 | 224.2 | 62.9% |
HSDP prefetch 后 Comm(未重叠) 仍高于原生(224 vs 166 ms),是 HSDP 残余差距来源。
4.3 Hook 热点(device 累计 ms,2 step,rank0)
| Hook | 无 prefetch P2 | +prefetch P3 | PR707 P4 | split P12 | cf+P1 P8 |
|---|---|---|---|---|---|
post_backward:norm |
280 | 185 | 186 | 48 | 190 |
post_backward:lm_head |
— | — | — | 279 | — |
pre_backward prefetch:layers.7 |
— | 107 | 108 | 108 | 114 |
post_backward:layers.7 |
~80 | ~20 | 20 | 76 | — |
post_backward:layers.*(其他层) |
~80 | ~60 | ~61 | ~60 | ~65 |
HSDP post_backward:layers.7 |
707 | 521 | — | — | — |
解读:
- prefetch 将 norm RS 从 280→185 ms;profiler 记为
post_backward:norm实为 norm+lm_head 绑定单元的一次 RS - 拆分 norm/lm_head(P12)反而更慢:两次 RS 合计 ~326 ms,重叠率降至 66%
layers.7backward prefetch AG 是固定尾部开销(~107 ms)- HSDP 无 prefetch 时 layers.7 post_backward 极高(707 ms),prefetch 后大幅缓解
五、结论与配置推荐
5.1 核心结论
- mesh:纯 FSDP8 比 HSDP24 快 ~1.4×,公平对比优先 FSDP8。
- prefetch 必开:默认配置不可用(慢 17–30%);开启后 FSDP8 超原生。
- comm_fusion 单独开有害;配合 P0/P1 + prefetch 可与原生持平,但不如 prefetch-only 快。
- PR707 建议合入:小幅收益(~1.3 ms),首层 unshard 阻塞减少。
- prefetch 深度 1/1 足够;norm/lm_head 保持绑定 wrap(拆分实测慢 4.8%);HSDP replicate AR 待优化。
5.2 配置推荐
| 场景 | 推荐 | 预期 ms/step |
|---|---|---|
| FSDP8 极致性能 | prefetch=True, comm_fusion=False(+PR707) |
~542 |
| 对齐原生 collective 次数 / 大模型 | prefetch=True, comm_fusion=True(P0/P1) |
~565 |
| HSDP24 追平原生 | prefetch=True |
~790 |
| ❌ 不推荐 | 默认无 prefetch / 单独 comm_fusion / split norm+lm_head | 658–1100 / 571 |
六、复现命令
source ~/env.sh
cd dev/test/qwen3_8b_hsdp2
# ── 端到端 ──
./run_baseline_8card.sh # T1/T8 等基线
./run_pure_fsdp2_8card.sh # T2/T3 hyper 默认
./run_hyper_torch_prefetch.sh # T4/T10 +prefetch
./run_hyper_torch_comm_fusion.sh # T6/T11 comm_fusion
# ── PR707 验证(本地 hyper-parallel 已 apply patch)──
python train_hyper_torch.py --nproc 8 --mesh fsdp --prefetch --prefetch-layers 1 \
--align-dir align_data_8b --steps 20 \
--output-json results/pr707_hyper_torch_prefetch/out.json
# ── Profiler ──
./run_torch_native_fsdp8_profile.sh # P1
./run_hyper_torch_fsdp8_profile.sh # P2(若脚本存在)
./run_hyper_torch_prefetch_profile.sh fsdp # P3
./run_hyper_torch_comm_fusion_prefetch_profile.sh fsdp # P6/P7/P8
./run_torch_native_hsdp24_profile.sh # P9
./run_hyper_torch_hsdp24_profile.sh # P10/P11
# ── prefetch 深度扫描 ──
python train_hyper_torch.py --nproc 8 --mesh fsdp --prefetch \
--prefetch-forward-layers 1 --prefetch-backward-layers 2 \
--npu-profiler --profiler-dir results/profiler/hyper_torch_fsdp_prefetch_fwd1_bwd2 ...
七、结果文件索引
results/
├── baseline_8card/ # T1 原生 FSDP8, T8 hyper HSDP24
├── pure_fsdp2_8card/ # T2/T3 hyper 默认 FSDP8
├── hyper_torch_prefetch/ # T4/T10 +prefetch e2e
├── pr707_hyper_torch_prefetch/ # T5 PR707 e2e
├── hyper_torch_comm_fusion/ # T6/T11 comm_fusion e2e
├── torch_native_hsdp24/ # T7 原生 HSDP24
└── profiler/
├── torch_native_fsdp8/ # P1
├── hyper_torch_fsdp8/ # P2
├── hyper_torch_fsdp_prefetch/ # P3
├── hyper_torch_fsdp_prefetch_pr707/ # P4
├── hyper_torch_fsdp_prefetch_fwd1_bwd2/ # P5
├── hyper_torch_fsdp_prefetch_split_norm_lm_head/ # P12 ❌
├── hyper_torch_fsdp_comm_fusion_prefetch/ # P6
├── hyper_torch_fsdp_comm_fusion_prefetch_p0/ # P7
├── hyper_torch_fsdp_comm_fusion_prefetch_p1/ # P8
├── torch_native_hsdp24/ # P9
├── hyper_torch_hsdp24/ # P10
└── hyper_torch_hsdp24_prefetch/ # P11
八、后续 TODO
- 基线 e2e 对比(T1–T11)
- Profiler 根因分析(P1/P2/P9/P10)
- prefetch 验证(T4/T10,P3/P11)
- comm_fusion 单独开启验证(T6/T11)
- cf+prefetch P0/P1 源码优化(P6→P8)
- PR #707 本地验证(T5/P4)
- prefetch 深度扫描 fwd1/bwd2(P5)
- 合入 PR #707 到上游 master
- hyper torch 默认开启 prefetch
- P2 norm/lm_head 拆 wrap 验证(P12) — ❌ 负向,慢 26 ms,保持绑定
- P2 RS pack 改用
_chunk_cat(降aten::copy_) - HSDP replicate 维 AR 优化(P11 Comm未重叠 224 vs P9 166 ms)
- hyper mindspore 同步 P0/P1 并 benchmark
本文档由 dev/test/qwen3_8b_hsdp2/ 全部实验数据自动汇总生成。
schema_version: 1
source: gitcode
gitcode_repo: mindspore/hyper-parallel
gitcode_issue: 192
source_url: https://gitcode.com/mindspore/hyper-parallel/issues/192
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in dev/test/qwen3_8b_hsdp2/ with train_hyper_torch.py and the listed benchmark and profiler scripts. Reproduce the prefetch and comm_fusion configurations using the aligned data, then inspect the profiler output directories and compare step time, communication overlap, and collective counts. Done means the reported performance conclusions are reproducible and any source optimization is validated against the stated baselines.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, pytorch
- Domain
- distributed-systems, performance
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 38/100