Skip to content

Update FSDP, AC, Compile ordering - #923

Merged
mikasenghaas merged 7 commits into
mainfrom
sami/update_fsdp_orderring
Sep 16, 2025
Merged

mikasenghaas merged 7 commits into
mainfrom
sami/update_fsdp_orderring

Conversation

@samsja

@samsja samsja commented Sep 16, 2025 •

Copy link
Copy Markdown
Member

couple of thing that I noticed are different between us and torchtitan:

┏━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┓
┃    Step ┃         MFU          ┃      Throughput      ┃      Step Time       ┃
┡━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━┩
│       1 │        39.50%        │        63.74K        │        2.05s         │
│       2 │        39.39%        │        63.56K        │        2.05s         │
│       3 │        39.32%        │        63.45K        │        2.05s         │
│         │                      │                      │                      │
│ Overall │    39.40% ± 0.09%    │   63.58K ± 147.78    │    2.05s ± 0.00s     │
│         │   [39.32%, 39.50%]   │   [63.45K, 63.74K]   │    [2.05s, 2.05s]    │
└─────────┴──────────────────────┴──────────────────────┴──────────────────────┘

branch sami/update_fsdp_orderring

┏━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┓
┃    Step ┃         MFU          ┃      Throughput      ┃      Step Time       ┃
┡━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━┩
│       1 │        27.29%        │        44.03K        │        2.97s         │
│       2 │        27.32%        │        44.08K        │        2.96s         │
│       3 │        27.32%        │        44.08K        │        2.97s         │
│         │                      │                      │                      │
│ Overall │    27.31% ± 0.02%    │    44.07K ± 27.75    │    2.96s ± 0.00s     │
│         │   [27.29%, 27.32%]   │   [44.03K, 44.08K]   │    [2.96s, 2.97s]    │
└─────────┴──────────────────────┴──────────────────────┴──────────────────────┘

reproduce with

srun bash -c '
    source /data/.env
    cd /data/prime-rl
    
    uv run torchrun \
    --nnodes=1 \
    --nproc_per_node=8 \
    --node-rank $SLURM_PROCID \
    src/prime_rl/trainer/sft/train.py \
    --model.name Qwen/Qwen3-8B\
    --model.attn sdpa \
    --model.ac \
    --model.compile \
    --data.type fake \
    --data.seq-len 2048 \
    --data.batch-size 64 \
    --data.micro-batch-size 8 \
    --data.pack-function stack \
    --log.level debug \
    --bench 2>&1 | tee /data/prime-rl/outputs/logs/latest_rank${SLURM_PROCID}.log /data/prime-rl/outputs/logs/torchrun_${SLURM_JOB_ID}_rank${SLURM_PROCID}.log'
    

@mikasenghaas
mikasenghaas force-pushed the sami/update_fsdp_orderring branch from bd290d4 to 7d38a16 Compare September 16, 2025 08:46
@mikasenghaas mikasenghaas changed the title Sami/update fsdp orderring Update FSDP, AC, Compile ordering Sep 16, 2025
@mikasenghaas
mikasenghaas marked this pull request as ready for review September 16, 2025 12:43

@mikasenghaas mikasenghaas left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

banger

Comment thread src/prime_rl/trainer/model.py Resolved
@samsja
samsja force-pushed the sami/update_fsdp_orderring branch from 79b52a9 to a4628dc Compare September 16, 2025 17:41
@mikasenghaas
mikasenghaas merged commit 01b67d0 into main Sep 16, 2025
@mikasenghaas
mikasenghaas deleted the sami/update_fsdp_orderring branch August 5, 2026 04:27
garrett361 added a commit that referenced this pull request Oct 7, 2026
… and activation checkpointing (#3925)

With `moe_router_dtype="float32"` (the RL default) and activation
checkpointing on, every MoE block ran eager under `torch.compile`. Two
things combine to cause it:

- The fp32 router is its own FSDP2 unit, and FSDP2 hooks are
dynamo-disabled, so the router always breaks the graph.
- Under `compile(AC(block))` the checkpoint compiles as a higher-order
op, which forbids breaks, so Dynamo ran the whole block eagerly.

This PR compiles inside the checkpoint instead: for any checkpointed
block that holds a nested FSDP unit (today, the fp32 router), an eager
checkpoint now wraps the compiled block (`AC(compile(block))`), so the
nested unit's break only splits the block into compiled graphs. To see
those units, compile now runs after FSDP. Compiling in place keeps the
same module object, so the order changes nothing at runtime.

The reorder is safe. The old `AC -> Compile -> FSDP` comment was ported
from TorchTitan in #923, when `apply_compile` still wrapped each block
with `torch.compile(block)`. #957 switched to in-place `.compile()` two
days later without revisiting it. With in-place compile, both orders
trace the same frames: graph breaks, loss and step time match on both
workloads, and `fullgraph=True` (with a bf16 router) still compiles with
zero graph breaks.

| Workload (8x H200, EP 8, full AC) | before (s/step) | after (s/step) |
MFU |
|---|---|---|---|
| GLM-4.5-Air, 16 layers, real data | 6.21, 6.17 | 5.22, 5.21 | 35% to
42% |
| Qwen3-30B-A3B, fake data | 5.96, 5.96 | 4.51, 4.51 | 32% to 42% |

Two runs per arm, each the median `time/step` over steps 5 to 20, no
offloading. Peak memory is unchanged, and loss and grad norm track the
baseline within run-to-run noise.

![Qwen3-30B-A3B MoE layer forward, before and
after](https://raw.githubusercontent.com/PrimeIntellect-ai/prime-rl/09e64ed1afc27e97fda6080556171522e29c9a0e/pr-figures/fp32-router-compile/qwen_layer_forward.png)

**Figure:** one MoE layer's forward on Qwen3-30B-A3B, before and after
this PR. The orange eager elementwise kernels collapse into a few pink
compiled Triton kernels, so the layer's forward drops from 16.4 to 11.3
ms.

<details><summary>Same view on GLM-4.5-Air</summary>

![GLM-4.5-Air MoE layer forward, before and
after](https://raw.githubusercontent.com/PrimeIntellect-ai/prime-rl/09e64ed1afc27e97fda6080556171522e29c9a0e/pr-figures/fp32-router-compile/glm_layer_forward.png)

</details>

## Alternative considered

Keeping recompute inside the compiler: drop the block-level checkpoint
and instead checkpoint two compiled regions that exclude the router, the
attention module and the post-router MoE work. It beat the baseline but
was slower than this PR (Qwen3-30B 5.50 vs 4.51 s/step, GLM-4.5-Air 5.85
vs 5.22 s/step) and used more memory, because the norms and the router's
fp32 activations stay outside any checkpoint.

## North star: fullgraph fp32 router support

Fullgraph compile with an fp32 router stays unsupported, and
`model.compile.fullgraph=true` still raises for it. The blocker is the
router's FSDP unit itself: FSDP2 applies one mixed-precision policy per
unit, so the fp32 router cannot share the block's bf16 unit, and its
dynamo-disabled hooks are the graph break above. PyTorch
[#196626](pytorch/pytorch#196626) adds
per-parameter mixed precision, which lets the router stay in the block's
unit. That removes the break, enables fullgraph, and makes this PR's
compile-inside-AC path unnecessary, so it should be reverted then.
#196626 is on PyTorch `main` but not yet in a release.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants