Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
b671ca7
support fine-grained activation offloading
lhb8125 Oct 24, 2025
e8fd17f
update years in copyright
lhb8125 Oct 24, 2025
85548e6
update copyright
lhb8125 Oct 27, 2025
5dd6841
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Oct 27, 2025
f5bf8c4
fix ft and import error
Oct 28, 2025
0321e20
address comments
lhb8125 Oct 28, 2025
9068805
format
lhb8125 Oct 28, 2025
61af7fd
update golden values on eos
lhb8125 Oct 28, 2025
b67a0ed
minor fix
lhb8125 Oct 28, 2025
a11d351
format
lhb8125 Oct 28, 2025
b84b5ff
renaming golden values
lhb8125 Oct 29, 2025
2f76430
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Oct 29, 2025
c320e5b
fix bug: accuracy issu because of recomputing and offloading same modul
lhb8125 Nov 4, 2025
896c02f
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Nov 4, 2025
ccb2f8a
Merge branch 'hongbinl/activation_offloading_github_main' of https://…
lhb8125 Nov 4, 2025
aa4c86c
format
lhb8125 Nov 4, 2025
92ce540
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Nov 5, 2025
5787848
update golden values
lhb8125 Nov 5, 2025
7eaec4d
update golden values
lhb8125 Nov 5, 2025
3c68f79
update model_config and golden values
lhb8125 Nov 6, 2025
ee53677
format
lhb8125 Nov 6, 2025
1c1d9c8
remove old golden values
lhb8125 Nov 6, 2025
30f8dec
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Nov 10, 2025
b2a261f
update golden values
lhb8125 Nov 6, 2025
50dc90b
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Nov 18, 2025
0a9b694
support new TE version
lhb8125 Nov 18, 2025
950b26f
move set_ideal_affinity_for_current_gpu to pipeline/util
lhb8125 Nov 18, 2025
495032a
format
lhb8125 Nov 18, 2025
2123564
format
lhb8125 Dec 1, 2025
bd69216
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Dec 1, 2025
8d05dfc
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Dec 9, 2025
9d23103
update golden value
lhb8125 Dec 9, 2025
7b6ebb3
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Dec 9, 2025
743ac56
code refactor
lhb8125 Jan 6, 2026
6829963
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 6, 2026
4b96d05
Merge branch 'hongbinl/activation_offloading_github_main' of https://…
lhb8125 Jan 6, 2026
7d8929b
format
lhb8125 Jan 6, 2026
480cbfa
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 6, 2026
83058e4
bug fix when cuda graph is disabled and fix for dumping offloading info
Jan 7, 2026
9605a67
refactor and update ut
lhb8125 Jan 8, 2026
b7a25ac
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 8, 2026
cb612c7
format
lhb8125 Jan 8, 2026
64ae361
remove unrelated changes
lhb8125 Jan 8, 2026
a8dfa65
fix ut
lhb8125 Jan 8, 2026
2c63e1d
fix ut
lhb8125 Jan 8, 2026
f52069e
fix ut
lhb8125 Jan 8, 2026
0643e55
update ut
lhb8125 Jan 9, 2026
d57ccb0
format
lhb8125 Jan 9, 2026
eadb8a3
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 9, 2026
ff4a2cd
update golden values
lhb8125 Jan 9, 2026
6dc9e2f
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 9, 2026
9555702
fix ut
lhb8125 Jan 9, 2026
9895754
Merge branch 'hongbinl/activation_offloading_github_main' of https://…
lhb8125 Jan 9, 2026
fd2d3fd
add version check
lhb8125 Jan 12, 2026
f8c09fa
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 12, 2026
84d13e9
minor refactor for fine_grained_activation_offload.py
lhb8125 Jan 12, 2026
49f3643
Merge branch 'hongbinl/activation_offloading_github_main' of https://…
lhb8125 Jan 12, 2026
1d1e0ca
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 12, 2026
483d87a
format
lhb8125 Jan 12, 2026
a498067
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 12, 2026
2f42e91
fix doc
lhb8125 Jan 14, 2026
469cef0
code refactor
lhb8125 Jan 14, 2026
c1fdba4
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 14, 2026
b93d212
remove group_start() calls
lhb8125 Jan 14, 2026
16d4114
format
lhb8125 Jan 14, 2026
1964268
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 14, 2026
6263630
add comments
lhb8125 Jan 14, 2026
9423c6b
fix min_offload_size and update golden values
lhb8125 Jan 14, 2026
cc28dd7
rename group_commit
lhb8125 Jan 15, 2026
b7153fa
Merge branch 'main' into hongbinl/activation_offloading_github_main
lhb8125 Jan 15, 2026
871bdaf
fix test_mamba_moe_model.py
lhb8125 Jan 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 31 additions & 0 deletions docs/user-guide/features/fine_grained_activation_offloading.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Fine-grained Activation Offloading (collaborated with rednote)

Memory capacity is more and more important with the rising of extreme sparse MoE models like DeepSeek-V3 and Qwen3-235B. Fine-grained recomputing reduces the memory footprint at the cost of extra recomputation, while offloading could utilize the host-device bandwidth to achieve nearly zero-overhead. Fine-grained Activation Offloading targets at offloading the activation at the granularity of specific modules, so that we can calibrate the amount of offloading activation to maximize the training throughput.

Currently, the supported offloading modules are `"attn_norm", "core_attn", "attn_proj", "mlp_norm", "expert_fc1", "moe_act"`, which could work with fine-grained recomputation to release almost all activations of a transformer layer.

**Features**
* Support PP=1/PP/Interleaved PP
* Compatible with fine-grained recomputation
* Support FP8
* Support MTP
* Support mixed dense & moe layer
* Support A2A Overlap
* Support CUDA Graph
* (Temporary) cuda graph scope cannot contains the offloading modules

**Usage**
Comment thread
lhb8125 marked this conversation as resolved.
```bash
# Enable fine-grained activation offloading
--fine-grained-activation-offloading

# Specify which modules are going to offload its input
# Choices: "attn_norm", "core_attn", "attn_proj", "mlp_norm", "expert_fc1", "moe_act".
--offload-modules expert_fc1
```
**Compatible with Fine-grained Recomputation**
- For modules with minor perf overhead like layernorm or moe_act, use recomputing to reduce memory footprint;
- For other modules, use offloading to reduce memory footprint;
- Make sure the offloading/reloading could be overlapped with computing;

![Fine-grained Activation Offloading and Fine-grained Recomputation](../../images/fine_grained_activation_offloading/offloading_and_recomputing.png)
18 changes: 17 additions & 1 deletion megatron/core/extensions/transformer_engine.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2024, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.

import dataclasses
import enum
Expand Down Expand Up @@ -520,6 +520,7 @@ def __init__(
extra_kwargs["delay_wgrad_compute"] = self.config.delay_wgrad_compute
else:
raise RuntimeError("Only TE with version >=2.3.0 supports delay_wgrad_compute now.")

if (
self.config.tp_comm_overlap
and tp_comm_buffer_name
Expand Down Expand Up @@ -2487,3 +2488,18 @@ def set_save_original_input(module):
"set_save_original_input is only needed on transformer-engine modules that save "
"quantized tensors by default. It needs transformer-engine>=2.6.0dev0."
)


try:
# pylint: disable=unused-import
from transformer_engine.pytorch import cpu_offload_v1 as cpu_offload
except ImportError:
try:
from transformer_engine.pytorch import cpu_offload
except ImportError:
cpu_offload = None
try:
# pylint: disable=unused-import
from transformer_engine.pytorch.float8_tensor import Float8Tensor
except ImportError:
Float8Tensor = None
19 changes: 15 additions & 4 deletions megatron/core/models/gpt/fine_grained_callables.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
import torch

from megatron.core import tensor_parallel
from megatron.core.pipeline_parallel.fine_grained_activation_offload import (
FineGrainedActivationOffloadingInterface as off_interface,
)
from megatron.core.pipeline_parallel.utils import ScheduleNode, make_viewless
from megatron.core.transformer.module import float16_to_fp32
from megatron.core.transformer.moe.moe_layer import MoELayer
Expand Down Expand Up @@ -374,11 +377,13 @@ def submodule_post_attn_forward(node: ScheduleNode, hidden_states: torch.Tensor)
"""
if layer.recompute_pre_mlp_layernorm:
layer.pre_mlp_norm_checkpoint = tensor_parallel.CheckpointWithoutOutput()
pre_mlp_layernorm_output = layer.pre_mlp_norm_checkpoint.checkpoint(
layer.pre_mlp_layernorm, hidden_states
)
with off_interface(layer.offload_mlp_norm, hidden_states, "mlp_norm") as hidden_states:
pre_mlp_layernorm_output = layer.pre_mlp_norm_checkpoint.checkpoint(
layer.pre_mlp_layernorm, hidden_states
)
else:
pre_mlp_layernorm_output = layer.pre_mlp_layernorm(hidden_states)
with off_interface(layer.offload_mlp_norm, hidden_states, "mlp_norm") as hidden_states:
pre_mlp_layernorm_output = layer.pre_mlp_layernorm(hidden_states)

probs, routing_map = layer.mlp.route(pre_mlp_layernorm_output)
local_tokens, probs = layer.mlp.preprocess(pre_mlp_layernorm_output, probs, routing_map)
Expand Down Expand Up @@ -460,6 +465,12 @@ def submodule_combine_forward(
hidden_states = layer.mlp_bda(layer.training, layer.config.bias_dropout_fusion)(
mlp_output_with_bias, residual, layer.hidden_dropout
)
# Delay the offload of the mlp norm until after the mlp_bda has been computed
# because the residual is needed in the mlp_bda.
if layer.offload_mlp_norm:
hidden_states = off_interface.group_commit(
hidden_states, name="mlp_norm", forced_released_tensors=[residual]
)
output = make_viewless_tensor(
inp=hidden_states, requires_grad=hidden_states.requires_grad, keep_graph=True
)
Expand Down
27 changes: 27 additions & 0 deletions megatron/core/models/gpt/gpt_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
)
from megatron.core.models.common.language_module.language_module import LanguageModule
from megatron.core.packed_seq_params import PackedSeqParams
from megatron.core.pipeline_parallel.fine_grained_activation_offload import (
FineGrainedActivationOffloadingInterface as off_interface,
)
from megatron.core.process_groups_config import ProcessGroupCollection
from megatron.core.quantization.utils import get_quant_config_or_none
from megatron.core.tensor_parallel import gather_from_sequence_parallel_region
Expand Down Expand Up @@ -120,6 +123,7 @@ def __init__(
self.parallel_output = parallel_output
self.share_embeddings_and_output_weights = share_embeddings_and_output_weights
self.vp_stage = vp_stage
self.disable_param_offloading = True

if hasattr(self.config, 'position_embedding_type'):
self.position_embedding_type = self.config.position_embedding_type
Expand Down Expand Up @@ -420,6 +424,24 @@ def _preprocess(

return preproc_output

def preprocess_for_fine_grained_offloading(self):
"""Preprocess for fine-grained activation offloading."""
off_interface.init_chunk_handler(
vp_size=self.config.virtual_pipeline_model_parallel_size,
vp_stage=self.vp_stage,
min_offloaded_tensor_size=self.config.min_offloaded_tensor_size,
)
if self.disable_param_offloading:
for param in self.decoder.parameters():
off_interface.mark_not_offloadable(param)
if self.mtp_process:
for param in self.mtp.parameters():
off_interface.mark_not_offloadable(param)
if self.post_process:
for param in self.output_layer.parameters():
off_interface.mark_not_offloadable(param)
self.disable_param_offloading = False

def forward(
self,
input_ids: Tensor,
Expand All @@ -445,6 +467,8 @@ def forward(
runtime_gather_output (bool): Gather output at runtime. Default None means
`parallel_output` arg in the constructor will be used.
"""
if self.config.fine_grained_activation_offloading:
self.preprocess_for_fine_grained_offloading()

inference_context = deprecate_inference_params(inference_context, inference_params)

Expand Down Expand Up @@ -719,6 +743,9 @@ def build_schedule_plan(
TransformerModelChunkSchedulePlan: The model chunk schedule plan.
"""

if self.config.fine_grained_activation_offloading:
self.preprocess_for_fine_grained_offloading()

from ..common.model_chunk_schedule_plan import TransformerModelChunkSchedulePlan

return TransformerModelChunkSchedulePlan(
Expand Down
Loading
Loading