nemo-mbridge-perf-cpu-offloading
NVIDIA/skills
Configurer et valider le délestage CPU pour l'entraînement de Megatron Bridge, y compris le délestage des activations et celui de l'état de l'optimiseur à l'aide de HybridDeviceOptimizer.
...Développer toutDéchargement du processeur
Références
- Documentation stable : @docs/training/cpu-offloading.md
- Métadonnées structurées : @skills/nemo-mbridge-perf-cpu-offloading/card.yaml
De quoi s'agit-il ?
Deux mécanismes indépendants permettant de transférer des données de la mémoire du GPU vers celle du CPU :
| Mécanisme | Espace de noms de configuration | Ce qui est déchargé | Restriction PP |
|---|---|---|---|
| Déchargement d’activation | model.cpu_offloading* |
Activations (et, éventuellement, poids) par couche de transformateur | PP doit être égal à 1 |
| Déchargement de l’optimiseur | optimizer.optimizer_cpu_offload |
États de l'optimiseur Adam (momentum + variance) via HybridDeviceOptimizer |
Aucun |
Décision rapide
| Situation | Recommandation |
|---|---|
| Modèle MoE volumineux (plus de 30 milliards), nécessite un PP > 1 | Déchargement de l’optimiseur — le déchargement de l’activation est bloqué par PP=1 |
| Modèle petit/moyen, PP = 1 convient, la mémoire d’activation domine | Délestage des activations |
| On souhaite un compromis réglable entre mémoire et vitesse | Déchargement de l’optimiseur avec un paramètre fractionnaire optimizer_offload_fraction |
| Le débit est la priorité absolue | Ne pas activer — le déchargement ajoute toujours une surcharge |
| Des graphes CUDA sont nécessaires | Déchargement de l’optimiseur uniquement — le déchargement d’activation est incompatible |
| La pression sur la mémoire est modérée | Déchargement de l’optimiseur à un taux de 25 à 50 % pour une efficacité optimale |
Activation
Déchargement de l’optimiseur vers le CPU (recommandé pour les grands modèles)
cfg.optimizer.optimizer_cpu_offload = True
cfg.optimizer.optimizer_offload_fraction = 1.0
cfg.optimizer.overlap_cpu_optimizer_d2h_h2d = True
Remplacements via l'interface en ligne de commande :
optimizer.optimizer_cpu_offload=True \
optimizer.optimizer_offload_fraction=0,5 \
optimizer.overlap_cpu_optimizer_d2h_h2d=True
Déchargement des activations vers le CPU (modèles petits/moyens uniquement)
cfg.model.cpu_offloading = True
cfg.model.cpu_offloading_num_layers = 16
cfg.model.cpu_offloading_activations = True
cfg.model.cpu_offloading_weights = False
cfg.model.pipeline_model_parallel_size = 1
cfg.model.recompute_granularity = None
cfg.model.cuda_graph_impl = "none"
Référence des paramètres de configuration
Déchargement de l’optimiseur
| Paramètre | Valeur par défaut | Description |
|---|---|---|
optimizer_cpu_offload |
Faux |
Commutateur principal |
optimizer_offload_fraction |
0,0 |
Fraction des états de l'optimiseur sur le CPU (0,0–1,0) |
overlap_cpu_optimizer_d2h_h2d |
Faux |
Superposition des transferts GPU↔CPU avec le calcul |
use_torch_optimizer_for_cpu_offload |
Faux |
Utiliser torch.optim à la place de l'optimiseur fusionné pour la partie CPU |
Déchargement des activations
| Paramètre | Valeur par défaut | Description |
|---|---|---|
cpu_offloading |
Faux |
Commutateur principal |
cpu_offloading_num_layers |
0 |
Nombre de couches du transformateur à décharger (de 0 à num_layers-1) |
cpu_offloading_activations |
Vrai |
Décharger les activations |
cpu_offloading_weights |
Faux |
Poids de déchargement |
cpu_offloading_double_buffering |
Faux |
Double tampon entre les couches lors du rechargement |
Compatibilité et contraintes
Déchargement des activations
pipeline_model_parallel_sizedoit être égal à 1recompute_granularitydoit êtreNone- Ne peut pas être combiné avec
fine_grained_activation_offloading - Ne peut pas être combiné avec les graphes CUDA
cpu_offloading_num_layersdoit être comprisentre 0 et num_layers-1
Délestage de l’optimiseur
- Nécessite
use_distributed_optimizer = True(valeur par défaut dans la plupart des recettes) - Aucune restriction concernant le PP, le recalcul ou les graphes CUDA
optimizer_offload_fractiondoit être comprisentre 0,0 et 1,0
Cas pratique : grands modèles MoE
Le déchargement des activations est bloqué pour Qwen3-30B-A3B et les grands modèles MoE similaires. La contrainte PP=1 implique que chaque GPU contient les 48 couches ; les poids du modèle et les états de l’optimiseur à eux seuls (~70 Go) dépassent la capacité de 80 Go du H100.
Commande minimale d'exécution
uv run python scripts/training/run_recipe.py \
--recipe qwen3_30b_a3b_pretrain_config \
optimizer.optimizer_cpu_offload=True \
optimizer.optimizer_offload_fraction=0.5 \
train.train_iters=20 \
train.global_batch_size=8 \
train.micro_batch_size=1
Vérification
Tests unitaires
uv run python -m pytest \
tests/unit_tests/models/test_gpt_full_te_layer_autocast_spec.py -k "cpu_offload" \
tests/unit_tests/peft/test_utils.py -k "cpu_offload" -q
Critères de réussite
- La validation de la configuration réussit pour le mode de déchargement sélectionné
- L'entraînement s'achève sans erreur OOM ni NCCL
- La perte correspond à celle de la référence sans déchargement (écart maximal < 0,001)
- L'utilisation de la mémoire diminue proportionnellement à la fraction de déchargement
Ancrages de code
Contraintes de déchargement de l’activation MCore
if self.cpu_offloading and (
self.cpu_offloading_num_layers < 0 or self.cpu_offloading_num_layers >=self.num_layers
):
raise ValueError(...)
si self.cpu_offloading et self.pipeline_model_parallel_size > 1 :
lève une exception ValueError(
« Le parallélisme de pipeline n’est actuellement pas pris en charge avec le déchargement CPU »
)
if self.cpu_offloading and self.recompute_granularity is not None:
raise ValueError(
"Le déchargement CPU ne fonctionne pas lorsque le recalcul des activations est activé"
)
Incompatibilité du graphe CUDA de MCore
si self.cpu_offloading :
lève ValueError("Graphes CUDA non pris en charge avec le déchargement CPU.")
Exclusion mutuelle entre le déchargement fin de MCore et le déchargement du CPU
if self.fine_grained_activation_offloading:
assert (
not self.cpu_offloading
), « fine_grained_activation_offloading ne peut pas être activé avec cpu_offloading. »
Instanciation de HybridDeviceOptimizer par MCore
if config.optimizer_cpu_offload:
# ... configuration des classes d'optimisation CPU/GPU ...
optimizer = HybridDeviceOptimizer(
param_groups,
offload_fraction=config.optimizer_offload_fraction,
cpu_optimizer_cls=cpu_optimizer_cls,
gpu_optimizer_cls=gpu_optimizer_cls,
overlap_cpu_optimizer_d2h_h2d=config.overlap_cpu_optimizer_d2h_h2d,
pin_cpu_grads=config.pin_cpu_grads,
pin_cpu_params=config.pin_cpu_params,
)
Protection du graphe CUDA de Bridge
assert not config.cpu_offloading and config.recompute_granularity is None, « Cudagraphs non pris en charge »
Pont d'externalisation des activations dans PEFT
si self.config.cpu_offloading et self.config.cpu_offloading_activations :
x.activation_offloading = True
x, _ = self.linear_in(x)
x = self.activation(x)
si self.config.cpu_offloading et self.config.cpu_offloading_activations :
x.activation_offloading = True
x, _ = self.linear_out(x)
Diagnostic des défaillances
| Symptôme | Cause probable | Comment vérifier | Solution |
|---|---|---|---|
Le parallélisme des pipelines avec déchargement du processeur n'est actuellement pas pris en charge |
Déchargement d'activation + PP > 1 | Vérifiez la valeur de pipeline_model_parallel_size |
Définissez PP=1 ou utilisez le déchargement de l'optimiseur |
Le déchargement CPU ne fonctionne pas lorsque le recalcul d’activation est activé |
Déchargement des activations + recalcul | Vérifier la valeur de « recompute_granularity » |
Définissez ` recompute_granularity` sur `null` |
Le déchargement d'activation à granularité fine ne peut pas être activé avec le déchargement CPU |
Les deux modes de déchargement sont activés | Vérifier les deux indicateurs | Utilisez l’un ou l’autre |
Les graphes CUDA ne sont pas pris en charge avec le déchargement vers le processeur |
Graphiques CUDA + déchargement d'activation | Vérifier cuda_graph_impl |
Définissez cuda_graph_impl="none" |
| Erreur OOM avec déchargement des activations | Modèle trop volumineux pour PP=1 | Vérifier la mémoire allouée par rapport à 80 Go | Utiliser le déchargement de l'optimiseur avec PP > 1 |
| Ralentissement extrême (>4x) | Déchargement de l’optimiseur à 100 %, goulot d’étranglement CPU Adam | Comparer le temps d’itération pour différentes fractions | Réduire la fraction ou activer overlap_cpu_optimizer_d2h_h2d |
| Erreur OOM lors d’un déchargement partiel de l’optimiseur | Déchargement insuffisant pour cette configuration | Vérifier la mémoire pour différentes fractions | Augmentez la fraction ou ajoutez du PP |
Limitations connues
- Le délestage de l’activation nécessite PP=1, ce qui le rend impraticable pour les grands modèles (plus de 30 milliards de MoE) nécessitant un parallélisme en pipeline.
- La perte de débit liée au déchargement de l’optimiseur est linéaire (~1,9x à 25 %, ~4,2x à 100 % pour Qwen3-30B-A3B).
- Le chevauchement D2H/H2D n'apporte qu'un gain de vitesse d'environ 7 %, car le calcul Adam sur le CPU constitue le goulot d'étranglement principal.
Le « fine_grained_activation_offloading »est une approche distincte au niveau des modules qui fonctionne avec un PP > 1, mais ne peut pas être combinée avecle « cpu_offloading »au niveau des couches .
---
name: nemo-mbridge-perf-cpu-offloading
description: Configure and validate CPU offloading for Megatron Bridge training, including activation offloading and optimizer state offloading with HybridDeviceOptimizer.
license: Apache-2.0
---
# CPU Offloading
## References
- Stable docs: @docs/training/cpu-offloading.md
- Structured metadata: @skills/nemo-mbridge-perf-cpu-offloading/card.yaml
## What It Is
Two independent mechanisms to move data from GPU to CPU memory:
| Mechanism | Config namespace | What gets offloaded | PP restriction |
|---|---|---|---|
| Activation offloading | `model.cpu_offloading*` | Activations (and optionally weights) per transformer layer | PP must be 1 |
| Optimizer offloading | `optimizer.optimizer_cpu_offload` | Adam optimizer states (momentum + variance) via `HybridDeviceOptimizer` | None |
## Quick Decision
| Situation | Recommendation |
|---|---|
| Large MoE model (30B+), needs PP > 1 | Optimizer offloading — activation offloading is blocked by PP=1 |
| Small/medium model, PP=1 fits, activation memory dominates | Activation offloading |
| Want tunable memory-speed tradeoff | Optimizer offloading with fractional `optimizer_offload_fraction` |
| Throughput is top priority | Don't enable — offloading always adds overhead |
| CUDA graphs are needed | Only optimizer offloading — activation offloading is incompatible |
| Memory pressure is moderate | Optimizer offload at 25–50% fraction for best efficiency |
## Enablement
### Optimizer CPU offloading (recommended for large models)
```python
cfg.optimizer.optimizer_cpu_offload = True
cfg.optimizer.optimizer_offload_fraction = 1.0
cfg.optimizer.overlap_cpu_optimizer_d2h_h2d = True
```
CLI overrides:
```bash
optimizer.optimizer_cpu_offload=True \
optimizer.optimizer_offload_fraction=0.5 \
optimizer.overlap_cpu_optimizer_d2h_h2d=True
```
### Activation CPU offloading (small/medium models only)
```python
cfg.model.cpu_offloading = True
cfg.model.cpu_offloading_num_layers = 16
cfg.model.cpu_offloading_activations = True
cfg.model.cpu_offloading_weights = False
cfg.model.pipeline_model_parallel_size = 1
cfg.model.recompute_granularity = None
cfg.model.cuda_graph_impl = "none"
```
## Config Parameter Reference
### Optimizer offloading
| Parameter | Default | Description |
|-----------|---------|-------------|
| `optimizer_cpu_offload` | `False` | Master switch |
| `optimizer_offload_fraction` | `0.0` | Fraction of optimizer states on CPU (0.0–1.0) |
| `overlap_cpu_optimizer_d2h_h2d` | `False` | Overlap GPU↔CPU transfers with compute |
| `use_torch_optimizer_for_cpu_offload` | `False` | Use `torch.optim` instead of fused optimizer for CPU portion |
### Activation offloading
| Parameter | Default | Description |
|-----------|---------|-------------|
| `cpu_offloading` | `False` | Master switch |
| `cpu_offloading_num_layers` | `0` | Number of transformer layers to offload (0 to num_layers-1) |
| `cpu_offloading_activations` | `True` | Offload activations |
| `cpu_offloading_weights` | `False` | Offload weights |
| `cpu_offloading_double_buffering` | `False` | Double-buffer across layers while reloading |
## Compatibility And Constraints
### Activation offloading
- `pipeline_model_parallel_size` must be 1
- `recompute_granularity` must be `None`
- Cannot combine with `fine_grained_activation_offloading`
- Cannot combine with CUDA graphs
- `cpu_offloading_num_layers` must be in `[0, num_layers-1)`
### Optimizer offloading
- Requires `use_distributed_optimizer = True` (default in most recipes)
- No PP, recompute, or CUDA graph restrictions
- `optimizer_offload_fraction` must be in `[0.0, 1.0]`
### Practical: large MoE models
Activation offloading is blocked for Qwen3-30B-A3B and similar large MoE
models. The PP=1 constraint means each GPU holds all 48 layers; model
weights + optimizer states alone (~70 GB) exceed H100 80 GB capacity.
## Minimal Runnable Command
```bash
uv run python scripts/training/run_recipe.py \
--recipe qwen3_30b_a3b_pretrain_config \
optimizer.optimizer_cpu_offload=True \
optimizer.optimizer_offload_fraction=0.5 \
train.train_iters=20 \
train.global_batch_size=8 \
train.micro_batch_size=1
```
## Verification
### Unit tests
```bash
uv run python -m pytest \
tests/unit_tests/models/test_gpt_full_te_layer_autocast_spec.py -k "cpu_offload" \
tests/unit_tests/peft/test_utils.py -k "cpu_offload" -q
```
### Success criteria
- Config validation passes for the selected offloading mode
- Training completes without OOM or NCCL errors
- Loss matches the non-offloaded baseline (max delta < 0.001)
- Memory usage drops proportionally to offload fraction
## Code Anchors
### MCore activation offload constraints
```1296:1310:3rdparty/Megatron-LM/megatron/core/transformer/transformer_config.py
if self.cpu_offloading and (
self.cpu_offloading_num_layers < 0 or self.cpu_offloading_num_layers >= self.num_layers
):
raise ValueError(...)
if self.cpu_offloading and self.pipeline_model_parallel_size > 1:
raise ValueError(
"Currently there is no support for Pipeline parallelism with CPU offloading"
)
if self.cpu_offloading and self.recompute_granularity is not None:
raise ValueError(
"CPU offloading does not work when activation recomputation is enabled"
)
```
### MCore CUDA graph incompatibility
```1943:1944:3rdparty/Megatron-LM/megatron/core/transformer/transformer_config.py
if self.cpu_offloading:
raise ValueError("CUDA graphs not supported with CPU offloading.")
```
### MCore fine-grained offloading mutual exclusion
```1427:1430:3rdparty/Megatron-LM/megatron/core/transformer/transformer_config.py
if self.fine_grained_activation_offloading:
assert (
not self.cpu_offloading
), "fine_grained_activation_offloading cannot be enabled with cpu_offloading."
```
### MCore HybridDeviceOptimizer instantiation
```480:518:3rdparty/Megatron-LM/megatron/core/optimizer/__init__.py
if config.optimizer_cpu_offload:
# ... setup cpu/gpu optimizer classes ...
optimizer = HybridDeviceOptimizer(
param_groups,
offload_fraction=config.optimizer_offload_fraction,
cpu_optimizer_cls=cpu_optimizer_cls,
gpu_optimizer_cls=gpu_optimizer_cls,
overlap_cpu_optimizer_d2h_h2d=config.overlap_cpu_optimizer_d2h_h2d,
pin_cpu_grads=config.pin_cpu_grads,
pin_cpu_params=config.pin_cpu_params,
)
```
### Bridge CUDA graph guard
```232:234:src/megatron/bridge/models/gpt_full_te_layer_autocast_spec.py
assert not config.cpu_offloading and config.recompute_granularity is None, "Cudagraphs not supported"
```
### Bridge activation offloading in PEFT
```621:631:src/megatron/bridge/peft/utils.py
if self.config.cpu_offloading and self.config.cpu_offloading_activations:
x.activation_offloading = True
x, _ = self.linear_in(x)
x = self.activation(x)
if self.config.cpu_offloading and self.config.cpu_offloading_activations:
x.activation_offloading = True
x, _ = self.linear_out(x)
```
## Failure Diagnosis
| Symptom | Likely Cause | How To Confirm | Fix |
|---|---|---|---|
| `Currently there is no support for Pipeline parallelism with CPU offloading` | Activation offload + PP > 1 | Check `pipeline_model_parallel_size` | Set PP=1 or use optimizer offloading |
| `CPU offloading does not work when activation recomputation is enabled` | Activation offload + recompute | Check `recompute_granularity` | Set `recompute_granularity=null` |
| `fine_grained_activation_offloading cannot be enabled with cpu_offloading` | Both offloading modes enabled | Check both flags | Use one or the other |
| `CUDA graphs not supported with CPU offloading` | CUDA graphs + activation offload | Check `cuda_graph_impl` | Set `cuda_graph_impl="none"` |
| OOM with activation offloading | Model too large for PP=1 | Check allocated memory vs 80 GB | Use optimizer offloading with PP > 1 |
| Extreme slowdown (>4x) | 100% optimizer offload, CPU Adam bottleneck | Compare iter time at different fractions | Reduce fraction or enable `overlap_cpu_optimizer_d2h_h2d` |
| OOM at partial optimizer offload | Insufficient offload for this config | Check memory at different fractions | Increase fraction or add PP |
## Known Limitations
- Activation offloading requires PP=1, making it impractical for large models
(30B+ MoE) that need pipeline parallelism.
- Optimizer offloading throughput penalty scales linearly (~1.9x at 25%,
~4.2x at 100% for Qwen3-30B-A3B).
- D2H/H2D overlap provides only ~7% speedup because CPU Adam compute is
the dominant bottleneck.
- `fine_grained_activation_offloading` is a separate module-level approach
that works with PP > 1 but cannot be combined with layer-level
`cpu_offloading`.
Tous les fichiers
6 fichiersInstaller nemo-mbridge-perf-cpu-offloading
Téléchargez et décompressez les fichiers de compétences dans votre répertoire .claude/skills/.
Télécharger le ZIPClonez le dépôt et copiez les fichiers de compétence dans votre projet.
git clone https://github.com/NVIDIA/skills/tree/main/skills/nemo-mbridge-perf-cpu-offloading # Copy SKILL.md to your .claude/skills/ directory
Copier





Maison
