Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
e1fbf4e
Lazy import rotary pos emb in strategy
connermanuel Apr 20, 2026
fc31057
Fix dummy dataset packing bins race on non-zero ranks
qywu Apr 20, 2026
029b1ac
Delete unused direct_train CLI entry point
qywu Apr 21, 2026
7f77597
Raise NotImplementedError instead of falling back to HuggingFace
qywu Apr 22, 2026
8d64504
MoE backend improvements: configurable activation, fused GEMM, determ…
qywu Apr 22, 2026
6586ab7
Fix: set default grad checkpointing correctly
connermanuel Apr 23, 2026
9d2a2e5
Add grad chkpt tests and defaults
connermanuel Apr 24, 2026
1601518
Add sglang_shared_outer LoRA export format
qywu Apr 28, 2026
22cc132
Allow qkv_proj in LoRA attention target_modules whitelist
kiddyboots216 Apr 28, 2026
ba1754c
Forward lr_min and lr_decay_ratio to linear LR schedule
kiddyboots216 Apr 29, 2026
978ff4e
Fix failing tests and add GPU CI workflow
qywu Apr 29, 2026
78526c0
ci: add conventional commit check on PR title
qywu Apr 29, 2026
21e54b4
Add softmax auxiliary (Z-)loss on LM-head logits
kiddyboots216 Apr 29, 2026
417048a
Add DeepSeek V4 distributed Muon paths
kiddyboots216 Apr 30, 2026
4ec734a
fix(lora): merge in fp32 and cast the sum once
qywu Apr 30, 2026
f0649ac
fix: Muon/MoE backward perf regression on Qwen3.5-style MoE
kiddyboots216 Apr 30, 2026
462b684
Add Cautious Weight Decay (CWD)
kiddyboots216 Apr 30, 2026
e1e4f90
fix: resolve dp_sp alias in loss_group/loss_mesh
connermanuel Apr 30, 2026
83b37f0
chore(lora): remove unused stacked LoRA helpers, drop lora_utils.py
qywu May 1, 2026
54a4442
Fix nccl_broadcast TCPStore master deadlock
kiddyboots216 May 1, 2026
b5d0248
feat: add OLMo-2 support
kiddyboots216 May 5, 2026
5a10044
Move vendored xorl.ops.quack ops to xorl_quack:: torch.library namespace
qywu May 5, 2026
3b644a5
Add DistSignSGD optimizer support
kiddyboots216 May 5, 2026
b5722da
fix: preserve FA3 varlen metadata after sync padding
kiddyboots216 May 6, 2026
04175e2
feat(models): add GLM-4 MoE (GLM-4.5/4.6/4.7) training support
zzz0906 May 7, 2026
3515add
feat: Allow loss funcs to accept reducers
connermanuel May 7, 2026
eee2a2d
feat(kimi): add Kimi 2.5 support
kiddyboots216 May 9, 2026
5d9ce37
fix(tests): align Qwen3.5-MoE layer_types fixture with num_hidden_layers
qywu May 12, 2026
69c8424
refactor: tighten broad except blocks; preserve causes
qywu May 14, 2026
03658d6
refactor: use sys.stderr.write for CLI startup errors instead of print
qywu May 14, 2026
2b43ffb
Aman/gpt oss ep support
AmanSinghal927 May 14, 2026
740d7a7
feat: add P2P (Mooncake) transport backend
kiddyboots216 May 14, 2026
f995932
feat(checkpoint): grouped HF weight load + DCP convert script
kiddyboots216 May 14, 2026
22b24f3
feat: multi-LoRA
kiddyboots216 May 15, 2026
31fc4e8
perf(runner): use torch.inference_mode() for ModelRunner.forward eval…
qywu May 19, 2026
9bb1138
fix(server): align R3 routing replay with SP microbatches
kiddyboots216 May 19, 2026
c5ab17e
perf(weight-sync): improve P2P sync
kiddyboots216 May 20, 2026
e8fcbf0
feat: Add on-policy distillation MVP
kiddyboots216 May 20, 2026
48c33d4
fix(server): R3 routing replay picks Qwen3.6 nested top-k + model_top…
kiddyboots216 May 21, 2026
690cfa5
feat(skill): add XORL throughput tuner
kiddyboots216 May 21, 2026
dd55535
fix(deepep): default to synchronous combine, env-gate unsafe async
kiddyboots216 May 22, 2026
b4150e5
fix(qwen3.5): mrope_interleaved must not pairwise-rotate q/k features
kiddyboots216 May 22, 2026
60269e1
refactor: convert load-bearing asserts in arguments.py / data_loader.…
qywu May 27, 2026
1549d96
Tune Muon Gram-NS chunk memory
kiddyboots216 May 27, 2026
b9a79e1
fix(fsdp2): canonicalize FSDP-wrapped ReduceOp in BF16 a2a reduce-sca…
kiddyboots216 May 28, 2026
48efa24
chore(deps): bump flash-attn-cute to flash-attn-4 @ 59f01d6
qywu May 28, 2026
c638722
feat(weight-sync): nccl_simple two-phase backend + sidecar routing fo…
zzz0906 Jun 16, 2026
bb55abb
fix(server): unblock multi-LoRA e2e on main (forward-path fixes + Qwe…
kiddyboots216 Jun 16, 2026
a29857c
fix: un-vendor FLA — use upstream flash-linear-attention for GatedDel…
kiddyboots216 Jun 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .codespellrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[codespell]
skip = *.lock,*.json,submodules/*,.venv/*,.git,docs/node_modules/*
ignore-words-list = dout,te,subtile,parm,mot,numer
ignore-words-list = dout,te,subtile,parm,mot,numer,notin
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,13 @@ trace/
docs/node_modules/
docs/dist/
docs/.astro/

# Generated tokenized datasets and packing caches (per-benchmark)
experiments/local_benchmark/dataset_cache/
experiments/local_benchmark/datasets/

# Kimi topology sweep scratch (tracked on branch `kimi-sweep-archive` instead)
experiments/local_benchmark/sweeps/

# Multi-adapter LoRA E2E artifacts can contain full per-rank logs and copied checkpoints.
experiments/multi_adapter_lora/results/
5 changes: 3 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

1. **Branch** off `main` with a descriptive name: `feature/my-feature`, `fix/bug-description`
2. **Commit** early and often on your branch — commit messages don't matter much here
3. **Open a PR** against `main` when ready for review
3. **Open a PR** against `main` when ready for review. The PR title must follow [Conventional Commits](https://www.conventionalcommits.org/) (see below), since it becomes the squash-merge commit message and drives automated release versioning.
4. **Squash merge** — all PRs are merged as a single squash commit; write a clean PR title and description since that becomes the commit message

## PR Guidelines

- Keep PRs focused — one feature or fix per PR
- Add tests for new behavior; existing tests must pass
- Update relevant docs if behavior changes
- PR title should be imperative and descriptive: `Add chunked cross-entropy loss` not `chunked ce`
- PR title must follow Conventional Commits: `type: description` or `type(scope): description`. Allowed types: `feat`, `fix`, `perf`, `revert` (trigger releases); `chore`, `docs`, `test`, `refactor`, `ci`, `build` (no release). Append `!` for breaking changes (`feat!: ...` → major bump). An optional `[TICKET-123]` ticket prefix is allowed before the type. Examples: `feat: add chunked cross-entropy loss`, `fix(moe): correct expert routing`, `feat!: drop Python 3.9 support`.
- A CI check enforces this on every PR and comments the detected version bump.

## Commit Message (Squash Merge)

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ XoRL is a distributed training framework designed for large language models with

| Repo                        | Description |
|---|---|
| **[xorl](https://github.com/togethercomputer/xorl-internal)** | Distributed training framework — local SFT/pretraining and server-mode RL training |
| **[xorl](https://github.com/togethercomputer/xorl)** | Distributed training framework — local SFT/pretraining and server-mode RL training |
| **[xorl-client](https://github.com/togethercomputer/xorl-client)** | Lightweight Python SDK for driving the xorl training server (forward/backward, optimizer steps, checkpointing, sampling) |
| **[xorl-sglang](https://github.com/togethercomputer/xorl-sglang)** | Fork of [SGLang](https://github.com/sgl-project/sglang) with weight-sync APIs, MoE routing export, and numerical alignment for online RL |

Expand All @@ -48,8 +48,8 @@ XoRL is a distributed training framework designed for large language models with
## 🚀 Installation

```bash
git clone --recurse-submodules git@github.com:togethercomputer/xorl-internal.git
cd xorl-internal
git clone --recurse-submodules git@github.com:togethercomputer/xorl.git
cd xorl
```

> Already cloned without `--recurse-submodules`? Run `git submodule update --init --recursive`
Expand Down Expand Up @@ -102,7 +102,7 @@ pip install -e .

> **Note:** The default `pyproject.toml` uses PyTorch 2.10.0. sglang requires PyTorch 2.9.1, so the two cannot coexist in the same environment unless you use `pyproject.sglang.toml`.

See the [installation guide](https://togethercomputer.github.io/xorl-internal/getting-started/installation/) for full setup including optional dependencies (DeepEP, Flash Attention).
See the [installation guide](https://togethercomputer.github.io/xorl/getting-started/installation/) for full setup including optional dependencies (DeepEP, Flash Attention).

## ⚡ Quick Start

Expand Down
4 changes: 2 additions & 2 deletions docs/src/content/docs/config-reference/local.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ torchrun --nproc_per_node=8 -m xorl.cli.train config.yaml \
| `ep_dispatch` | `alltoall` | Expert-parallel dispatch: `alltoall` or `deepep` (NVLink-optimized). |
| `deepep_buffer_size_gb` | `2.0` | DeepEP NVLink buffer size per GPU in GB. Only active when `ep_dispatch: deepep`. |
| `deepep_num_sms` | `20` | SMs assigned to DeepEP communication kernels. Must be even. Lower values leave more SMs for overlapped compute. |
| `deepep_async_combine` | `false` | Overlap DeepEP combine with the next layer's compute (experimental). |
| `deepep_async_combine` | `false` | Overlap DeepEP combine with the next layer's compute (experimental, unsafe). Forced to `false` in code unless `XORL_DEEPEP_UNSAFE_ASYNC_COMBINE=1` is exported; without that env var, deferring the comm-stream sync races the transformer block's read of the combined tensor on the default stream. |
| `merge_qkv` | `true` | Keep Q/K/V projections fused as `qkv_proj`. Set `false` for tensor parallelism or per-projection LoRA. |
| `basic_modules` | `[]` | Additional module names (beyond `_no_split_modules`) to shard as separate FSDP units. |
| `foundation` | `{}` | Extra foundation model config (dict). |
Expand Down Expand Up @@ -167,7 +167,7 @@ Each entry in `datasets` (or `test_datasets`) is a dict:
| `activation_gpu_limit` | `0.0` | GB of activations to keep on GPU when offloading. `0.0` = offload all. |
| `enable_compile` | `false` | `torch.compile` for model forward pass. |
| `init_device` | `cuda` | Device for weight initialization: `cpu` (rank 0 only), `cuda`, `meta` (required for FSDP2), `npu`. |
| `load_weights_mode` | `broadcast` | `broadcast`: rank 0 reads weights, broadcasts to other ranks (reduces disk I/O). `all_ranks`: every rank reads from disk. |
| `load_weights_mode` | `grouped` | `grouped`: one reader per node for dense/shared weights plus one reader per EP-FSDP group for expert weights, with rank-0 fallback when grouped fanout groups are unavailable. `all_ranks`: every rank reads from disk. `skip`: skip HuggingFace weight loading and materialize model weights from `load_checkpoint_path` (DCP). |
| `enable_full_determinism` | `false` | Full determinism mode. Requires `allow_cuda_launch_blocking: true`. Degrades performance. |
| `allow_cuda_launch_blocking` | `false` | Allow `CUDA_LAUNCH_BLOCKING=1`. Off by default to prevent accidental performance degradation. |
| `empty_cache_steps` | `500` | Call `torch.cuda.empty_cache()` every N steps. |
Expand Down
5 changes: 3 additions & 2 deletions docs/src/content/docs/config-reference/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ python -m xorl.server.launcher --mode auto --config config.yaml \
| `ep_dispatch` | `alltoall` | Expert-parallel dispatch: `alltoall` or `deepep` (NVLink-optimized). |
| `deepep_buffer_size_gb` | `2.0` | DeepEP NVLink buffer size per GPU in GB. Only active when `ep_dispatch: deepep`. |
| `deepep_num_sms` | `20` | SMs assigned to DeepEP communication kernels. Must be even. |
| `deepep_async_combine` | `false` | Overlap DeepEP combine with the next layer's compute (experimental). |
| `deepep_async_combine` | `false` | Overlap DeepEP combine with the next layer's compute (experimental, unsafe). Forced to `false` in code unless `XORL_DEEPEP_UNSAFE_ASYNC_COMBINE=1` is exported; without that env var, deferring the comm-stream sync races the transformer block's read of the combined tensor on the default stream. |
| `merge_qkv` | `true` | Keep Q/K/V projections fused. Set `false` for tensor parallelism. |
| `basic_modules` | `[]` | Additional module names to shard as separate FSDP units. |
| `foundation` | `{}` | Foundation model extra config (dict). |
Expand Down Expand Up @@ -86,7 +86,7 @@ These flags align the training model's numerics with the inference engine (SGLan
| `enable_reentrant` | `false` | Use reentrant gradient checkpointing. |
| `enable_forward_prefetch` | `false` | FSDP forward prefetch. |
| `init_device` | `meta` | Model initialization device: `cpu`, `meta`, `cuda`. |
| `load_weights_mode` | `auto` | Weight loading: `auto`, `safetensors`, `dcp`. |
| `load_weights_mode` | `grouped` | Weight loading mode: `grouped` (default, with rank-0 fallback), `all_ranks`, or `skip`. |
| `ce_mode` | `compiled` | Cross-entropy implementation: `compiled` (recommended, `torch.compile`) or `eager` (may OOM at 32K+ seq len). |

---
Expand Down Expand Up @@ -170,6 +170,7 @@ ZMQ communication between the launcher, workers, and API server.
| `qlora_exclude_modules` | `null` | Modules to exclude from quantization (e.g., `[lm_head]`). |
| `merge_lora_interval` | `0` | Merge LoRA into base weights every N steps. `0` = never. |
| `reset_optimizer_on_merge` | `false` | ReLoRA optimizer reset after merge. |
| `adapter_state_load_mode` | `all_ranks` | How to restore multi-adapter checkpoints: `all_ranks` loads on every rank; `rank0_broadcast` loads on rank 0 and broadcasts weights, metadata, and optimizer state. |

---

Expand Down
4 changes: 2 additions & 2 deletions docs/src/content/docs/getting-started/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ title: "Installation"
## Clone the repo

```bash
git clone --recurse-submodules https://github.com/togethercomputer/xorl-internal
cd xorl-internal
git clone --recurse-submodules https://github.com/togethercomputer/xorl
cd xorl
```

> Already cloned without `--recurse-submodules`? Run `git submodule update --init --recursive`
Expand Down
6 changes: 3 additions & 3 deletions docs/src/content/docs/getting-started/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ future = requests.post(f"{base_url}/api/v1/optim_step", json={

### Example: SFT on No Robots

[`examples/server/no_robot_sft/`](https://github.com/togethercomputer/xorl-internal/tree/main/examples/server/no_robot_sft) — Supervised fine-tuning on the [No Robots](https://huggingface.co/datasets/HuggingFaceH4/no_robots) dataset using `xorl_client`.
[`examples/server/no_robot_sft/`](https://github.com/togethercomputer/xorl/tree/main/examples/server/no_robot_sft) — Supervised fine-tuning on the [No Robots](https://huggingface.co/datasets/HuggingFaceH4/no_robots) dataset using `xorl_client`.

```bash
# 1. Start the training server
Expand All @@ -131,7 +131,7 @@ The script uses `xorl_client.TrainingClient` to drive a LoRA SFT loop with onlin

### Example: Password Memorization (end-to-end weight sync)

[`examples/server/password_memorization/`](https://github.com/togethercomputer/xorl-internal/tree/main/examples/server/password_memorization) — End-to-end test for the training → weight sync → inference pipeline. Trains a model to memorize 3 secret codes via SFT, syncs weights to a running xorl-sglang instance, and queries inference to verify recall.
[`examples/server/password_memorization/`](https://github.com/togethercomputer/xorl/tree/main/examples/server/password_memorization) — End-to-end test for the training → weight sync → inference pipeline. Trains a model to memorize 3 secret codes via SFT, syncs weights to a running xorl-sglang instance, and queries inference to verify recall.

```bash
# 1. Start the training server
Expand All @@ -149,7 +149,7 @@ python examples/server/password_memorization/run_password_test.py \
--model Qwen/Qwen3-8B --steps 16 --lr 1e-5
```

Supports all training modes (full, LoRA, QLoRA nvfp4/block_fp8/nf4), LR schedules (constant, cosine, warmup+cosine), and FP8 weight sync re-quantization. See the [example README](https://github.com/togethercomputer/xorl-internal/tree/main/examples/server/password_memorization/README.md) for the full test matrix across Qwen3-8B, Qwen3-30B, and Qwen3-235B.
Supports all training modes (full, LoRA, QLoRA nvfp4/block_fp8/nf4), LR schedules (constant, cosine, warmup+cosine), and FP8 weight sync re-quantization. See the [example README](https://github.com/togethercomputer/xorl/tree/main/examples/server/password_memorization/README.md) for the full test matrix across Qwen3-8B, Qwen3-30B, and Qwen3-235B.

## LoRA Fine-tuning

Expand Down
24 changes: 18 additions & 6 deletions docs/src/content/docs/moe/deepep.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ model:
| `ep_dispatch` | `alltoall` | Set to `deepep` to enable |
| `deepep_buffer_size_gb` | `2.0` | Per-GPU NVLink buffer pool in GB. Larger = fewer chunked transfers. Rule of thumb: `2 × token_budget × hidden_dim × sizeof(bf16)` |
| `deepep_num_sms` | `20` | SMs dedicated to communication kernels. Must be even. |
| `deepep_async_combine` | `false` | Overlap combine with next layer's compute (experimental) |
| `deepep_async_combine` | `false` | Overlap combine with next layer's compute (experimental, **currently disabled** — see [Async Combine](#async-combine-experimental)) |

---

Expand Down Expand Up @@ -223,17 +223,29 @@ If you see OOM during initialization, reduce `deepep_buffer_size_gb`. If profili

## Async Combine (Experimental)

`deepep_async_combine: true` overlaps the combine communication (outputs flowing back from expert ranks) with the next layer's compute:
:::caution[Currently disabled]
The async combine path is **forced off in code**. The combined
tensor is consumed by the rest of the transformer block (residual add, norm,
attention) on the default stream **before** the next `token_pre_dispatch()`
runs, so deferring `event.current_stream_wait()` races those consumers.
Setting `deepep_async_combine: true` alone is a no-op (logs a one-time warning).
To actually run async, also export `XORL_DEEPEP_UNSAFE_ASYNC_COMBINE=1` — only
do this if you have separately ensured the downstream consumer waits on the
combine event.
:::

`deepep_async_combine: true` requests overlap of the combine communication
(outputs flowing back from expert ranks) with the next layer's compute:

```
Step N: dispatch → compute → [combine starts]
Step N+1: [combine finishes] + next layer compute (overlapped)
```

**Benefit:** Hides combine latency behind useful compute, especially when combine > dispatch (typical for large output projections).
**Benefit (when working):** Hides combine latency behind useful compute, especially when combine > dispatch (typical for large output projections).

**Limitations:**
- Experimental — correctness verified on Qwen3 but not all architectures
- Gated off behind `XORL_DEEPEP_UNSAFE_ASYNC_COMBINE=1`
- Requires careful ordering of CUDA streams
- Not compatible with pipeline parallelism (PP > 1)

Expand All @@ -247,7 +259,7 @@ On Qwen3-235B-A22B with EP=64 (8 nodes, 64 H100 NVLink GPUs):
|---|---|---|
| AllToAll (NCCL) | ~5s per forward_backward | Baseline |
| DeepEP (num_sms=20) | ~1s per forward_backward | ~5× faster |
| DeepEP + async_combine | ~0.6s per forward_backward | ~8× faster |
| DeepEP + async_combine | ~0.6s per forward_backward | ~8× faster (currently gated off, see [Async Combine](#async-combine-experimental)) |

Gains are most pronounced at high EP sizes (≥ 32) where AllToAll's O(EP) staging bottleneck dominates.

Expand All @@ -259,7 +271,7 @@ Gains are most pronounced at high EP sizes (≥ 32) where AllToAll's O(EP) stagi
| EP ≤ 8, multi-node InfiniBand | AllToAll — IB already uses RDMA |
| EP ≥ 16, NVLink cluster | DeepEP |
| EP ≥ 32, NVLink cluster | DeepEP strongly recommended |
| EP ≥ 64, NVLink cluster | DeepEP + async_combine |
| EP ≥ 64, NVLink cluster | DeepEP (async_combine currently gated off) |

---

Expand Down
21 changes: 11 additions & 10 deletions docs/src/content/docs/parallelism/data_parallelism.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ train:
enable_full_shard: true
enable_mixed_precision: true
init_device: meta # required for FSDP2
load_weights_mode: broadcast # rank0 loads, broadcasts to all ranks
load_weights_mode: grouped # grouped fanout, with rank-0 fallback
```

`init_device: meta` is **required** for FSDP2. Parameters are initially created on the meta device (zero-cost), then materialized by FSDP2 after `fully_shard` is applied.
Expand Down Expand Up @@ -267,7 +267,7 @@ train:
enable_full_shard: true
enable_mixed_precision: true
init_device: meta
load_weights_mode: broadcast
load_weights_mode: grouped
```

The constraint that must hold: `data_parallel_shard_size × data_parallel_replicate_size == data_parallel_size` (where `data_parallel_size = world_size / (TP × PP × CP)`). xorl validates this in `TrainingArguments.__post_init__`.
Expand Down Expand Up @@ -478,7 +478,7 @@ train:
enable_gradient_checkpointing: true
enable_full_shard: true
init_device: meta
load_weights_mode: broadcast
load_weights_mode: grouped
```

**Memory profile (Qwen3-8B, ~8B params):**
Expand All @@ -505,7 +505,7 @@ train:
enable_gradient_checkpointing: true
enable_full_shard: true
init_device: meta
load_weights_mode: broadcast
load_weights_mode: grouped
```

Here `world_size = dp_shard × ulysses = 2 × 4 = 8`. Each 2-GPU FSDP shard group uses 4-way Ulysses to handle long sequences that would not fit on 2 GPUs individually.
Expand All @@ -522,7 +522,7 @@ train:
enable_gradient_checkpointing: true
enable_full_shard: true
init_device: meta
load_weights_mode: broadcast
load_weights_mode: grouped
```

Cross-node IB traffic is limited to the all-reduce of *averaged gradients* (not full shard all-gathers), which is typically 4–8x less than pure FSDP2 would require across nodes.
Expand Down Expand Up @@ -578,7 +578,7 @@ train:
enable_full_shard: true
reshard_after_forward: false # PP: keep params gathered between fwd micro-batches
init_device: meta
load_weights_mode: broadcast
load_weights_mode: grouped
```

`world_size = PP × dp_shard = 2 × 4 = 8`. Each PP stage has 4 GPUs running FSDP2 over non-expert params and EP=4 over expert params.
Expand Down Expand Up @@ -643,15 +643,16 @@ When EP is enabled, xorl replaces FSDP2's automatic prefetching with explicit pe
|-------|-------------|-----------------|
| `meta` | Parameters on meta device; materialized lazily by FSDP2 | FSDP2 only (required) |
| `cuda` | Parameters initialized directly on GPU | DDP, or FSDP2 debugging |
| `cpu` | Parameters on CPU (rank 0 only for broadcast) | DDP only; not supported with EP |
| `cpu` | Parameters on CPU (rank 0 only for rank-0 fallback) | DDP only; not supported with EP |
| `npu` | Ascend NPU device | DDP, FSDP2 |

### `load_weights_mode`

| Value | Description | When to use |
|-------|-------------|-------------|
| `broadcast` (default) | Rank 0 reads checkpoint from disk, broadcasts shards to all ranks | Default; avoids N-way disk I/O bottleneck |
| `grouped` (default) | Dense/shared tensors are read once per node and expert tensors once per EP-FSDP group, then replicated/scattered within those groups | Default; best for large MoE/EP loads and falls back to rank-0 loading when grouped fanout groups are unavailable |
| `all_ranks` | Every rank reads the checkpoint independently | Fast parallel storage (e.g., Lustre, object storage), or when EP requires each rank to load its own expert shard |
| `skip` | Skip HuggingFace checkpoint loading and load model weights later from `load_checkpoint_path` | Model-only DCP checkpoints created by `scripts/convert_checkpoint.py --save-format dcp` |

---

Expand All @@ -665,9 +666,9 @@ Meta-device initialization creates parameter tensors with zero CPU/GPU memory co
init_device: meta
```

### Use `load_weights_mode: broadcast` by default
### Use `load_weights_mode: grouped` by default

`broadcast` mode has rank 0 load the checkpoint from disk and distribute shards. This is the safest option when the storage system cannot handle parallel reads from all ranks simultaneously. Switch to `all_ranks` only on parallel filesystems with guaranteed per-rank I/O performance, or when loading EP shards that differ per rank.
`grouped` mode uses grouped fanout for large MoE checkpoints so dense/shared weights are read once per node and expert weights are read once per EP-FSDP group. When grouped fanout groups are unavailable, it falls back to rank-0 loading. Switch to `all_ranks` only on parallel filesystems with guaranteed per-rank I/O performance.

### Set `reshard_after_forward: false` for pipeline parallelism

Expand Down
Loading
Loading