Skip to content
This repository was archived by the owner on May 20, 2026. It is now read-only.

Commit 2eb57c2

Browse files
parthmannanHuy Vu2abhinavg4rootroot
authored
DFM Performance Improvements (#45)
* first commit * workable code * workable thd * clean up, remove all CP for sbhd, CP now is only for thd * run outside of Mbridge * Update example scripts and add new data module for multimodal datasets - Added comments to clarify file purposes in example_commands.sh, inference_wan.py, pretrain_wan.py, wan_provider.py, wan_step.py, and wan.py. - Introduced EnergonMultiModalDataModule for handling multimodal datasets in nemo_vfm. - Created SequentialMegatronSampler for efficient sequential sampling in large datasets. - Added new files for DIT attention and base data handling. This commit enhances documentation and introduces new functionalities for better data management and processing. * workable code before refactoring * refactor attention submodules + reorder files locations * update refactor * update refactor * reorganize files * reorganize files * refactoring code * add README for perf test * using vae, t5, scheduler from Diffusers * update repo, remove Wan's Github moduels * fix Ruff * fix ruff + copyright * fix Ruff + Lint * fix Ruff + Lint * fix Ruff + Lint * fix Ruff + Lint * fix Ruff + Lint * fix Ruff + Lint * fix Ruff + Lint * fix Ruff + Lint * merged main + address comments * remove example_commands.md, Google waits until mid Nov * refactor inference_configs + mockdatamodule * add dit_embeddings.py * fix lint ruff * add 'average_gradients_across_tp_domain' to torch.nn for when running sequence_parallelism * add english negative prompt * fix ruff lint * Update uv.lock for deps: diffusers==0.35.1, easydict, imageio * update dfm/src/megatron/data/dit * change english negative prompt * seem to workable seq_packing * refactor with Sajad's PR - DiT data to common dir * fix Ruff, lint * fix Ruff, lint * fix Ruff, lint * workable mock datamodule (doesn't need setting path); updated training algo + hyper-parameters aligning with Linnan; tested training with anime dataset finetung * bring wan_task encoders features to common, sharing with dit * lint, ruff * lint, ruff * lint, ruff * fix CP error (input of thd_split_inputs_cp to be cu_seqlens_q_padded instead of cu_seqlens_q) * udpate README_perf_test.md * fix lint, ruff * update uv.lock, merge main * uv.lock * uv.lock * uv.lock * update uv.lock [using ci] * Performance improvements to Wan * Perf optimizations * Tiny fix * Remove CP disable as packed sequences not supported * Fix comment * Minor fixes. Revert video_latent comparison * Fix missed check * Lint fix * H100 mock pretraining perf config * Rename config file * Lint check Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Adding GB200 perf config Signed-off-by: Parth Mannan <pmannan@nvidia.com> * GB300 perf config Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Refactor Energon data module to return wrapped dataloaders and add EnergonDataloader class for cyclic iteration. Introduce WAN pretrain mock data configuration for testing. * Enhance DiffusionTaskEncoder to handle None attributes in stacking and concatenation methods. Add WAN pretrain mock data configuration for testing purposes. * Refactor data processing in dit_data_step to simplify batch retrieval and update WAN pretrain configuration to include train_iters. * Add op fusions Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Update H100 config Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Fix lint Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Resolve conflict Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Fix for mock dataloader test Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Fix Dummyiter Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Fix test Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Make RoPE test only GPU Signed-off-by: Parth Mannan <pmannan@nvidia.com> * Rope cuda fix Signed-off-by: Parth Mannan <pmannan@nvidia.com> --------- Signed-off-by: Parth Mannan <pmannan@nvidia.com> Co-authored-by: Huy Vu2 <huvu@login-eos02.eos.clusters.nvidia.com> Co-authored-by: Abhinav Garg <abhinavg@stanford.edu> Co-authored-by: root <root@eos0025.eos.clusters.nvidia.com> Co-authored-by: root <root@eos0558.eos.clusters.nvidia.com> Co-authored-by: Pablo Garay <pagaray@nvidia.com>
1 parent 1dc22a5 commit 2eb57c2

15 files changed

Lines changed: 247 additions & 37 deletions

File tree

dfm/src/megatron/data/common/base_energon_datamodule.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ def train_dataloader(self) -> Any:
195195
train_dataset = self.datasets_provider(worker_config, split="train")
196196
energon_dataloader = get_savable_loader(train_dataset, worker_config=worker_config)
197197
self.train_dataloader_object = energon_dataloader
198-
return self.train_dataloader_object
198+
return EnergonDataloader(self.train_dataloader_object)
199199

200200
def val_dataloader(self):
201201
"""
@@ -233,7 +233,7 @@ def val_dataloader(self):
233233
val_dataset = self.datasets_provider(worker_config, split="val")
234234
energon_loader = get_savable_loader(val_dataset, worker_config=worker_config)
235235
self.val_dataloader_object = energon_loader
236-
return self.val_dataloader_object
236+
return EnergonDataloader(self.val_dataloader_object)
237237

238238
def test_dataloader(self) -> None:
239239
"""
@@ -337,3 +337,26 @@ def load_state_dict(self, state_dict: Dict[str, Any]) -> None:
337337
consumed_samples=consumed_samples,
338338
consistency_check=False,
339339
)
340+
341+
342+
class EnergonDataloader:
343+
"""A wrapper to use Megatron Energon dataloader with the Megatron-LM training loop."""
344+
345+
def __init__(self, dataloader):
346+
self._dataloader = dataloader
347+
self._iter = iter(cyclic_iter(dataloader))
348+
349+
def __next__(self):
350+
return self._iter.__next__()
351+
352+
def __iter__(self):
353+
return self._iter.__iter__()
354+
355+
def save_state(self):
356+
return self._dataloader.save_state_rank()
357+
358+
359+
def cyclic_iter(iter):
360+
while True:
361+
for x in iter:
362+
yield x

dfm/src/megatron/data/common/diffusion_task_encoder_with_sp.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,10 +88,16 @@ def pack_selected_samples(self, samples: List[DiffusionSample]) -> DiffusionSamp
8888
"""Construct a new Diffusion sample by concatenating the sequences."""
8989

9090
def stack(attr):
91-
return torch.stack([getattr(sample, attr) for sample in samples], dim=0)
91+
if hasattr(samples[0], attr) and getattr(samples[0], attr) is not None:
92+
return torch.stack([getattr(sample, attr) for sample in samples], dim=0)
93+
else:
94+
return None
9295

9396
def cat(attr):
94-
return torch.cat([getattr(sample, attr) for sample in samples], dim=0)
97+
if hasattr(samples[0], attr) and getattr(samples[0], attr) is not None:
98+
return torch.cat([getattr(sample, attr) for sample in samples], dim=0)
99+
else:
100+
return None
95101

96102
return DiffusionSample(
97103
__key__=",".join([s.__key__ for s in samples]),

dfm/src/megatron/data/wan/wan_mock_datamodule.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,12 +113,15 @@ class WanMockDataModuleConfig(DatasetProvider):
113113
W_latents: int = 60
114114
patch_spatial: int = 2
115115
patch_temporal: int = 1
116-
number_packed_samples: int = 3
116+
number_packed_samples: int = 1
117117
context_seq_len: int = 512
118118
context_embeddings_dim: int = 4096
119119

120120
def __post_init__(self):
121121
mock_ds = _MockDataset(length=1024)
122+
kwargs = {}
123+
if self.num_workers > 0:
124+
kwargs["prefetch_factor"] = 8
122125
self._train_dl = DataLoader(
123126
mock_ds,
124127
batch_size=self.micro_batch_size,
@@ -135,6 +138,8 @@ def __post_init__(self):
135138
),
136139
shuffle=False,
137140
drop_last=False,
141+
pin_memory=True,
142+
**kwargs,
138143
)
139144
self._train_dl = iter(self._train_dl)
140145
self.sequence_length = self.seq_length

dfm/src/megatron/model/wan/flow_matching/flow_pipeline.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ def training_step(
195195
packed_seq_params["self_attention"].cu_seqlens_q_padded,
196196
parallel_state.get_context_parallel_group(),
197197
)
198+
# TODO (pmannan): Disable CP for CrossAttention as KV context is small.
199+
# We don't need to split context embeddings across context parallelism
200+
# if we disable context parallelism for cross-attention
198201
context_embeddings = thd_split_inputs_cp(
199202
context_embeddings,
200203
packed_seq_params["cross_attention"].cu_seqlens_kv_padded,
@@ -261,5 +264,4 @@ def training_step(
261264
context=context_embeddings,
262265
packed_seq_params=packed_seq_params,
263266
)
264-
265267
return hidden_states

dfm/src/megatron/model/wan/rope_utils.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ def __init__(self, dim_head, max_position_len):
3232
],
3333
dim=1,
3434
)
35+
if torch.cuda.is_available():
36+
self.freqs = self.freqs.cuda()
3537

3638
def rope_params(self, max_position_len, dim_head, theta=10000):
3739
assert dim_head % 2 == 0
@@ -41,10 +43,6 @@ def rope_params(self, max_position_len, dim_head, theta=10000):
4143
return freqs
4244

4345
def forward(self, n_head, dim_head, cu_seqlens_q_padded, grid_sizes, device):
44-
self.freqs = self.freqs.to(
45-
device,
46-
)
47-
4846
n, c = n_head, dim_head // 2
4947

5048
# split freqs

dfm/src/megatron/model/wan/wan_layer_spec.py

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
# pylint: disable=C0115,C0116,C0301
1616

17+
import copy
1718
from dataclasses import dataclass
1819
from typing import Optional, Union
1920

@@ -65,10 +66,16 @@ def __init__(self, config: TransformerConfig):
6566

6667
setattr(self.modulation, "sequence_parallel", config.sequence_parallel)
6768

69+
@jit_fuser
6870
def forward(self, timestep_emb):
69-
e = (self.modulation + timestep_emb).chunk(6, dim=1)
71+
e = (self.modulation + timestep_emb).transpose(0, 1)
72+
e = e.chunk(6, dim=0)
7073
return e
7174

75+
@jit_fuser
76+
def normalize_modulate(self, norm, hidden_states, shift, scale):
77+
return self.modulate(norm(hidden_states), shift, scale)
78+
7279
@jit_fuser
7380
def modulate(self, x, shift, scale):
7481
return x * (1 + scale) + shift
@@ -96,19 +103,31 @@ def __init__(
96103
pg_collection: Optional[ProcessGroupCollection] = None,
97104
vp_stage: Optional[int] = None,
98105
):
106+
def _replace_no_cp_submodules(submodules):
107+
modified_submods = copy.deepcopy(submodules)
108+
modified_submods.cross_attention = IdentityOp
109+
return modified_submods
110+
111+
# Replace any submodules that will have CP disabled and build them manually later after TransformerLayer init.
112+
# modified_submods = _replace_no_cp_submodules(submodules)
99113
super().__init__(
100114
config=config, submodules=submodules, layer_number=layer_number, hidden_dropout=hidden_dropout
101115
)
102116

103-
# # TODO: Override Cross Attention to disable TP Comm overlap as well. ???
104-
# # Not disabling will attempt re-use of buffer size same as Q and lead to incorrect tensor shapes.
105-
# cp_override_config = copy.deepcopy(config)
106-
# cp_override_config.tp_comm_overlap = False
107-
# self.cross_attention = build_module(
108-
# submodules.cross_attention,
109-
# config=cp_override_config,
110-
# layer_number=layer_number,
111-
# )
117+
# TODO (pmannan): Override Cross Attention to disable CP.
118+
# Disable TP Comm overlap as well. Not disabling will attempt re-use of buffer size same as
119+
# Q and lead to incorrect tensor shapes.
120+
# if submodules.cross_attention != IdentityOp:
121+
# cp_override_config = copy.deepcopy(config)
122+
# cp_override_config.context_parallel_size = 1
123+
# cp_override_config.tp_comm_overlap = False
124+
# self.cross_attention = build_module(
125+
# submodules.cross_attention,
126+
# config=cp_override_config,
127+
# layer_number=layer_number,
128+
# )
129+
# else:
130+
# self.cross_attention = None
112131

113132
self.full_self_attention = build_module(
114133
submodules.full_self_attention,
@@ -148,6 +167,10 @@ def _mark_trainable_params_for_tp_grad_avg(self, modules: Optional[list] = None)
148167
if isinstance(param, nn.Parameter) and param.requires_grad:
149168
setattr(param, "average_gradients_across_tp_domain", True)
150169

170+
@jit_fuser
171+
def add_residual(self, x: torch.Tensor, residual: torch.Tensor) -> torch.Tensor:
172+
return x + residual
173+
151174
def forward(
152175
self,
153176
hidden_states,
@@ -169,19 +192,13 @@ def forward(
169192
rope_emb = rotary_pos_emb
170193

171194
shift_full, scale_full, gate_full, shift_mlp, scale_mlp, gate_mlp = self.adaLN(timestep_emb)
172-
# transpose to bring it to [1, b, ...] format
173-
shift_full = shift_full.transpose(0, 1)
174-
scale_full = scale_full.transpose(0, 1)
175-
gate_full = gate_full.transpose(0, 1)
176-
shift_mlp = shift_mlp.transpose(0, 1)
177-
scale_mlp = scale_mlp.transpose(0, 1)
178-
gate_mlp = gate_mlp.transpose(0, 1)
179195

180196
# ******************************************** full self attention *******************************************
181197

182198
# adaLN with scale + shift + gate
183-
pre_full_attn_layernorm_output_ada = self.adaLN.modulate(
184-
self.norm1(hidden_states),
199+
pre_full_attn_layernorm_output_ada = self.adaLN.normalize_modulate(
200+
self.norm1,
201+
hidden_states,
185202
shift=shift_full,
186203
scale=scale_full,
187204
)
@@ -201,6 +218,12 @@ def forward(
201218

202219
# ******************************************** cross attention ******************************************************
203220

221+
# TODO (pmannan): Disable CP for CrossAttention as KV context is small.
222+
# But needs better support for packed sequences and padding to ensure correct calculations
223+
# packed_seq_params['cross_attention'].cu_seqlens_q = torch.tensor(
224+
# [0, hidden_states.shape[0]],
225+
# device=packed_seq_params['cross_attention'].cu_seqlens_kv.device,
226+
# dtype=torch.int32)
204227
attention_output, bias = self.cross_attention(
205228
self.norm3(hidden_states),
206229
attention_mask=context_mask,
@@ -210,12 +233,13 @@ def forward(
210233
if bias is not None:
211234
attention_output = attention_output + bias
212235

213-
hidden_states = hidden_states + attention_output
236+
hidden_states = self.add_residual(hidden_states, attention_output)
214237

215238
# ******************************************** mlp ******************************************************
216239

217-
pre_mlp_layernorm_output_ada = self.adaLN.modulate(
218-
self.norm2(hidden_states),
240+
pre_mlp_layernorm_output_ada = self.adaLN.normalize_modulate(
241+
self.norm2,
242+
hidden_states,
219243
shift=shift_mlp,
220244
scale=scale_mlp,
221245
)

dfm/src/megatron/model/wan/wan_provider.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class WanModelProvider(TransformerConfig, ModelProviderMixin[VisionModule]):
5151
bf16: bool = False
5252
params_dtype: torch.dtype = torch.float32
5353
qkv_format: str = "sbhd" # "thd". NOTE: if we use context parallelism, we need to use "thd"
54+
apply_rope_fusion: bool = True
55+
bias_activation_fusion: bool = True
5456
# these attributes are unused for images/videos, we just set because bridge training requires for LLMs
5557
seq_length: int = 1024
5658
share_embeddings_and_output_weights: bool = False

dfm/src/megatron/model/wan/wan_step.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,8 @@
3232

3333

3434
def wan_data_step(qkv_format, dataloader_iter):
35-
batch = next(iter(dataloader_iter.iterable))
36-
35+
batch = next(dataloader_iter)
3736
batch = {k: v.to(device="cuda", non_blocking=True) if torch.is_tensor(v) else v for k, v in batch.items()}
38-
3937
# Construct packed sequence parameters
4038
if ("seq_len_q" in batch) and ("seq_len_kv" in batch):
4139
zero = torch.zeros(1, dtype=torch.int32, device="cuda")

dfm/src/megatron/recipes/wan/wan.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ def pretrain_config(
170170
context_embeddings_dim=4096,
171171
micro_batch_size=micro_batch_size,
172172
global_batch_size=global_batch_size,
173-
num_workers=10,
173+
num_workers=16,
174174
packing_buffer_size=None,
175175
)
176176
else:
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# WAN Pretrain Mock Data Test Configuration
2+
# Converted from L2_Function_Tests_GPU_Wan_Mock_Data.sh
3+
4+
model:
5+
tensor_model_parallel_size: 1
6+
pipeline_model_parallel_size: 1
7+
context_parallel_size: 1
8+
crossattn_emb_size: 1536
9+
hidden_size: 1536
10+
ffn_hidden_size: 8960
11+
num_attention_heads: 12
12+
num_layers: 3
13+
qkv_format: thd
14+
seq_length: 2048
15+
16+
train:
17+
eval_iters: 0
18+
train_iters: 10
19+
global_batch_size: 2
20+
micro_batch_size: 1
21+
22+
optimizer:
23+
lr: 5.0e-6
24+
min_lr: 5.0e-6
25+
26+
scheduler:
27+
lr_decay_style: constant
28+
lr_warmup_iters: 0
29+
30+
checkpoint:
31+
save: ${oc.env:CHECKPOINT_DIR,null}
32+
load: ${oc.env:CHECKPOINT_DIR,null}
33+
load_optim: false
34+
save_interval: 200
35+
36+
dataset:
37+
path: ${oc.env:DATASET_PATH,null}
38+
seq_length: 2048
39+
global_batch_size: 2
40+
micro_batch_size: 1
41+
packing_buffer_size: 50
42+
43+
logger:
44+
log_interval: 1

0 commit comments

Comments
 (0)