New to Claude Skills? Learn how to install them →

nvidia on GitHub

Activation Recompute

OfficialFree

Optimize GPU memory usage with activation recompute.

by nvidia2.8k stars on nvidia/skills
2 views
Updated Aug 7, 2026
Get this skill

Free · Opens the source repo

What Activation Recompute does

Activation recompute is a technique designed to manage GPU memory usage effectively during the training of large models, particularly within the Megatron Bridge framework. By discarding intermediate activations during the forward pass and recomputing them during the backward pass, this skill allows users to trade off compute power for memory savings. This is particularly useful when working with large transformer models that often exceed available GPU memory. The skill supports two granularities of recompute: selective and full. Selective recompute allows users to specify particular submodules to recompute, while full recompute applies to entire transformer layers, offering different levels of memory savings and compute costs.

The skill is particularly beneficial for developers and researchers working on large-scale machine learning models who are facing out-of-memory (OOM) issues. It provides a structured approach to manage memory pressure by allowing users to choose which parts of their model to recompute based on their specific needs. The configuration options are straightforward, enabling users to set their desired granularity and specify which modules to recompute. This flexibility helps in optimizing performance while minimizing memory usage, making it a valuable addition to any deep learning workflow.

However, users should be aware of the constraints associated with activation recompute. For instance, full-layer recompute is incompatible with certain CUDA graph settings, which may limit its applicability in specific scenarios. Additionally, while selective recompute can save memory, it may not always be sufficient, necessitating a careful evaluation of the model architecture and training requirements. Overall, this skill is a practical solution for managing GPU memory more effectively in demanding machine learning tasks.

When to use it

Use this skill when training large transformer models that exceed available GPU memory and require efficient memory management.

When not to use it

Avoid this skill if your model fits comfortably within GPU memory or if you are not using Megatron Bridge for training.

What you can build with it

Training Large Language Models

When training large language models, use activation recompute to manage GPU memory effectively and avoid OOM errors.

Experimenting with Model Configurations

During experimentation with different model architectures, selectively recompute specific modules to find the best memory-performance trade-off.

Optimizing Resource Usage

In scenarios where GPU resources are limited, apply activation recompute to maximize the efficiency of your training process.

How to install Activation Recompute

View source

1. Install with the skills CLI

npx skills add nvidia/skills/nemo-mbridge-perf-activation-recompute --agent claude-code

2. Or install it manually

Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.

Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs

Inside SKILL.md

Written by nvidia

Activation Recompute

Stable docs: @docs/training/activation-recomputation.md Card: @skills/nemo-mbridge-perf-activation-recompute/card.yaml

<!-- NVSkills CI refresh: 2026-06-15. No instruction changes. -->

What It Is

Activation recompute trades GPU compute for memory by discarding intermediate activations during the forward pass and recomputing them during backward. Megatron Bridge supports two granularities:

GranularityWhat you specifyWhat gets recomputedMemory savingsCompute cost
selectiverecompute_modules list (e.g. core_attn, mlp)specific submodules within each layermoderate (module-dependent)low to high
fullrecompute_num_layers + recompute_methodentire transformer layers (N layers)strongesthighest

Note: MCore names these "selective" (submodule-level) vs "full" (layer-level). "Full" means recomputing full layers, not the full model — you still choose how many layers via recompute_num_layers.

Quick Decision

  1. Rule out allocator fragmentation first with PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True; see @skills/nemo-mbridge-perf-memory-tuning/SKILL.md.
  2. For activation pressure, start with selective recompute: recompute_granularity="selective" and recompute_modules=["core_attn"].
  3. Add modules by cost: "layernorm" is cheap but saves little, while "mlp" saves much more memory at a clear throughput cost.
  4. Use full-layer recompute only when selective recompute does not fit, and set all required fields: recompute_granularity="full", recompute_method, and recompute_num_layers.
  5. With FP8 or TE-scoped CUDA graphs, avoid full-layer recompute unless graph scope is full_iteration; otherwise use selective recompute or disable TE graph capture.

CPU offloading (cpu_offloading=True) is an alternative that avoids recompute cost entirely, but it is incompatible with PP > 1.

Enablement

Selective recompute

cfg.model.recompute_granularity = "selective"
cfg.model.recompute_modules = ["core_attn"]  # add "layernorm", "mlp", or other valid modules as needed

Full-layer recompute

cfg.model.recompute_granularity = "full"
cfg.model.recompute_method = "uniform"
cfg.model.recompute_num_layers = 4

Available recompute_modules

ModuleWhat it recomputesCompute costMemory savings
core_attnattention softmax/dropout/QKV dot productlow (Flash Attention already recomputes internally)moderate
layernormlayer normalizationnegligible (~0%)negligible
mlpfull FFN blockhigh (~16% on Llama3 70B, hidden=28672)~3 GB
moeMoE expert dispatchvariesvaries
moe_actMoE activation functionslowsmall
shared_expertsshared expert layersmoderatemoderate
mla_up_projMulti-Latent Attention up projectionmoderatemoderate

Performance harness CLI

uv run python scripts/performance/run_script.py \
  -m llama \
  -mr llama3_8b \
  --task pretrain \
  -g h100 \
  -c bf16 \
  -ng 8 \
  --recompute_modules core_attn,layernorm \
  ...

Compatibility and Constraints

  • recompute_granularity=selective requires a non-empty recompute_modules list
  • recompute_granularity=full requires recompute_method and recompute_num_layers
  • Layer-level recompute (recompute_granularity="full" + recompute_num_layers) is incompatible with TE-scoped CUDA graphs. MCore calls this "full" granularity — the name refers to recomputing full transformer layers, not the full model. Even though you're selecting how many layers to recompute, MCore treats it differently from submodule recompute. Any TE-scoped scope (attn, mlp, moe_router, etc.) will assert. This commonly hits FP8 configs that enable TE-scoped graphs by default (e.g. LLAMA3_70B_SFT_CONFIG_H100_FP8_CS_V1 sets cuda_graph_impl="transformer_engine", cuda_graph_scope="mlp"). Options:
    • use submodule recompute (recompute_granularity="selective" + recompute_modules) — compatible with TE-scoped graphs
    • disable CUDA graphs (cuda_graph_impl="none") and use layer-level recompute
    • switch to cuda_graph_impl="local", cuda_graph_scope="full_iteration"
  • distribute_saved_activations=True cannot be combined with sequence_parallel=True
  • Combining mlp + core_attn recompute is slightly worse than mlp alone due to double recompute overhead

Measured Results

Llama3 70B SFT on 32x H100 80GB, FP8 (Current Scaling):

  • Baseline: TP=4, PP=4, VPP=5, DP=2, MBS=1, GBS=32, seq_len=4096
  • Golden GPU utilization: 709.93 TFLOP/s/GPU
  • Regression threshold: 5%
Experimentrecompute_modulesTFLOP/s/GPUvs GoldenPeak Mem (GB)Result
Baseline[core_attn]~704-0.8%58.8 (OOM rank0)OOM
Exp 1[mlp]593.6-16.4%55.6Perf regression
Exp 2[mlp, core_attn]586.8-17.3%55.6Perf regression
Exp 3[core_attn, layernorm]~702-1.1%59.6 (OOM rank0)OOM

Key takeaways:

  • layernorm recompute is nearly free compute-wise but saves negligible memory
  • mlp recompute saves ~3 GB peak but costs ~16% because the Llama3 70B FFN (hidden=28672) is expensive to recompute
  • Combining mlp + core_attn is slightly worse than mlp alone
  • For this workload, the actual OOM fix was PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True (memory fragmentation, not capacity). See @skills/nemo-mbridge-perf-memory-tuning/SKILL.md.

Code Anchors

Recompute modules enum and selective checkpoint logic

# 3rdparty/Megatron-LM/megatron/core/transformer/transformer_block.py
# _checkpointed_forward() applies selective recompute based on recompute_modules

Recompute config validation

# 3rdparty/Megatron-LM/megatron/core/transformer/transformer_config.py
# Validates recompute_granularity, recompute_method, recompute_num_layers

Llama3 recipe defaults

    # Memory saving (recompute & offloading)
    cfg.model.recompute_granularity = None
    cfg.model.recompute_modules = None
    cfg.model.fine_grained_activation_offloading = False
    cfg.model.offload_modules = None

Full recompute + CUDA graph assertion (MCore)

            if self.recompute_granularity:
                if self.recompute_granularity != "selective":
                    assert self.cuda_graph_scope == [
                        CudaGraphScope.full_iteration
                    ], "full recompute is only supported with full iteration CUDA graph."

CPU offloading PP incompatibility (MCore)

        if self.cpu_offloading and self.pipeline_model_parallel_size > 1:
            raise ValueError(
                "Currently there is no support for Pipeline parallelism with CPU offloading"
            )

Failure Diagnosis

SymptomCauseConfirmFix
>15% GPU utilization dropmlp recompute on a large FFNcheck whether recompute_modules includes mlpremove mlp, lower micro batch size, or use CPU offload if PP=1
Still OOM after adding layernormlayernorm activations are too small to move the peak materiallycompare peak memory before/afterswitch to a higher-impact module or full-layer recompute
AssertionError: full recompute is only supported with full iteration CUDA graphlayer-level recompute with TE-scoped graph capturecheck cuda_graph_impl and cuda_graph_scopeuse selective, set cuda_graph_impl=none, or use local + full_iteration
ValueError: PP + CPU offloadingcpu_offloading=True with pipeline_model_parallel_size > 1check PP configdisable CPU offloading or set PP=1
mlp+core_attn worse than mlp alonedouble recompute overheadcompare Exp 1 vs Exp 2use mlp alone

Known Limitations

  • Per-module memory savings vary significantly by model architecture and hidden dimension
  • No automatic module selection — users must choose which modules to recompute
  • layernorm recompute is almost never worth it as a standalone fix
  • CPU offloading (the zero-compute-cost alternative) is blocked when PP > 1

Verification

uv run python -m pytest \
  tests/unit_tests/training/test_config.py -k "recompute" -q

Success criteria:

  • Unit tests pass for recompute config validation
  • No assertion errors from config validation

Frequently asked questions about Activation Recompute

Similar skills