Skip to content

Commit 31121a4

Browse files
refactor(quant)!: simplify quantization examples and fix calibration dataset load (#5337)
Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
1 parent 600d069 commit 31121a4

8 files changed

Lines changed: 365 additions & 360 deletions

File tree

‎examples/quantization/README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
This directory contains example scripts for quantizing Megatron Bridge models using NVIDIA ModelOpt.
44

5-
> **Note**: These are minimal, hard-coded reference examples. For more comprehensive, production-quality post-training quantization (PTQ), export, and Quantization Aware Distillation (QAD) scripts, see the NVIDIA Model Optimizer repository: [examples/megatron_bridge/](https://github.com/NVIDIA/Model-Optimizer/tree/main/examples/megatron_bridge).
5+
> **Note**: These are minimal, reference examples. For more comprehensive, production-quality post-training quantization (PTQ), export, and Quantization Aware Distillation (QAD) scripts, see the NVIDIA Model Optimizer repository: [examples/megatron_bridge/](https://github.com/NVIDIA/Model-Optimizer/tree/main/examples/megatron_bridge).
66
77
## Overview
88

‎examples/quantization/export.py‎

Lines changed: 39 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
1919
Prerequisites:
2020
First, you must run the quantization process to create a quantized checkpoint:
21-
torchrun --nproc_per_node 2 examples/quantization/quantize.py --megatron-save-path ./quantized_megatron_checkpoint --tp 2
21+
torchrun --nproc_per_node 2 examples/quantization/quantize.py \
22+
--hf-model-id meta-llama/Llama-3.2-1B --megatron-save-path ./quantized_megatron_checkpoint --tp 2
2223
2324
The process is as follows:
2425
1. An AutoBridge is initialized from a pretrained Hugging Face model
@@ -27,33 +28,37 @@
2728
3. The model is exported to HuggingFace format using ModelOpt export utilities.
2829
2930
Usage:
30-
torchrun --nproc_per_node 2 examples/quantization/export.py --megatron-load-path ./quantized_megatron_checkpoint --export-dir ./hf_export --tp 2
31+
torchrun --nproc_per_node 2 examples/quantization/export.py --hf-model-id meta-llama/Llama-3.2-1B \
32+
--megatron-load-path ./quantized_megatron_checkpoint --export-dir ./hf_export --tp 2
3133
"""
3234

3335
import argparse
34-
import os
35-
import sys
3636
import warnings
3737

3838
import modelopt.torch.export as mtex
39+
import modelopt.torch.utils.distributed as dist
3940
import torch
4041
from megatron.core.utils import unwrap_model
41-
from rich.console import Console
42+
from quantize_utils import (
43+
add_common_model_args,
44+
build_bridge_and_provider,
45+
console,
46+
load_quantized_megatron_model,
47+
print_parallelism_summary,
48+
require_checkpoint,
49+
require_torchrun,
50+
)
4251

43-
from megatron.bridge import AutoBridge
4452
from megatron.bridge.models.decorators import torchrun_main
4553
from megatron.bridge.models.hf_pretrained.utils import is_safe_repo
4654

4755

4856
warnings.filterwarnings("ignore")
4957

50-
HF_MODEL_ID = "meta-llama/Llama-3.2-1B"
51-
console = Console()
52-
5358

5459
@torchrun_main
5560
def main(
56-
hf_model_id: str = HF_MODEL_ID,
61+
hf_model_id: str,
5762
tp: int = 1,
5863
pp: int = 1,
5964
ep: int = 1,
@@ -65,88 +70,50 @@ def main(
6570
trust_remote_code: bool | None = None,
6671
) -> None:
6772
"""Export a quantized Megatron-LM checkpoint to HuggingFace format on multiple GPUs."""
68-
if os.environ.get("WORLD_SIZE") is None:
69-
console.print("This script must be launched with torchrun. Please run:")
70-
console.print(f"torchrun --nproc_per_node <gpus> {sys.argv[0]}")
71-
sys.exit(1)
72-
73-
# Check if the checkpoint path exists
74-
if not os.path.exists(megatron_load_path):
75-
console.print(f"[red]Error: Quantized checkpoint path {megatron_load_path} does not exist![/red]")
76-
console.print("[yellow]Please run the quantization process first:[/yellow]")
77-
console.print(
78-
f"[yellow]torchrun --nproc_per_node {tp} examples/quantization/quantize.py --megatron-save-path {megatron_load_path} --tp {tp}[/yellow]"
79-
)
80-
sys.exit(1)
81-
82-
# Initialize bridge from HF model to get tokenizer and model structure
83-
bridge = AutoBridge.from_hf_pretrained(
84-
hf_model_id,
85-
trust_remote_code=is_safe_repo(
86-
trust_remote_code=trust_remote_code,
87-
hf_path=hf_model_id,
73+
require_torchrun()
74+
require_checkpoint(
75+
megatron_load_path,
76+
quantize_command=(
77+
f"torchrun --nproc_per_node {tp} examples/quantization/quantize.py "
78+
f"--hf-model-id {hf_model_id} --megatron-save-path {megatron_load_path} --tp {tp}"
8879
),
8980
)
9081

91-
# Get model provider and configure for multi-GPU execution
92-
model_provider = bridge.to_megatron_provider(load_weights=False)
93-
model_provider.tensor_model_parallel_size = tp
94-
model_provider.pipeline_model_parallel_size = pp
95-
model_provider.expert_model_parallel_size = ep
96-
model_provider.expert_tensor_parallel_size = etp
97-
9882
# Convert dtype string to torch dtype
9983
dtype_map = {
10084
"bfloat16": torch.bfloat16,
10185
"float16": torch.float16,
10286
"float32": torch.float32,
10387
}
10488
torch_dtype = dtype_map.get(dtype, torch.bfloat16)
105-
model_provider.pipeline_dtype = torch_dtype
10689

107-
# Once all overrides are set, finalize the model provider to ensure the post initialization logic is run
108-
model_provider.finalize()
109-
model_provider.initialize_model_parallel(seed=0)
110-
111-
# Load the quantized model
112-
megatron_model = bridge.load_megatron_model(
113-
megatron_load_path,
114-
mp_overrides={
115-
"tensor_model_parallel_size": tp,
116-
"pipeline_model_parallel_size": pp,
117-
"expert_model_parallel_size": ep,
118-
"expert_tensor_parallel_size": etp,
119-
},
120-
wrap_with_ddp=False,
90+
# Initialize bridge from HF model to get tokenizer and model structure
91+
bridge, model_provider = build_bridge_and_provider(
92+
hf_model_id,
93+
tp=tp,
94+
pp=pp,
95+
ep=ep,
96+
etp=etp,
97+
load_weights=False,
98+
pipeline_dtype=torch_dtype,
99+
trust_remote_code=trust_remote_code,
121100
)
101+
megatron_model = load_quantized_megatron_model(bridge, megatron_load_path, tp=tp, pp=pp, ep=ep, etp=etp)
122102

123103
# Now we can check for rank
124-
is_rank_0 = torch.distributed.get_rank() == 0
104+
is_rank_0 = dist.is_master()
125105

106+
print_parallelism_summary(model_provider)
126107
if is_rank_0:
127-
console.print(f"[green]Tensor parallel size: {model_provider.tensor_model_parallel_size}[/green]")
128-
console.print(f"[green]Pipeline parallel size: {model_provider.pipeline_model_parallel_size}[/green]")
129-
console.print(f"[green]Expert parallel size: {model_provider.expert_model_parallel_size}[/green]")
130-
console.print(f"[green]Expert tensor parallel size: {model_provider.expert_tensor_parallel_size}[/green]")
131108
console.print(f"[green]Loaded quantized model from: {megatron_load_path}[/green]")
132109

133110
# Get the unwrapped model for export
134111
unwrapped_model = unwrap_model(megatron_model)[0]
135112

136-
# Decide whether we are exporting only the extra_modules (e.g. EAGLE, Medusa).
137-
# Only the last pp stage may have extra_modules, hence broadcast from the last rank.
113+
# Only the last pp stage may have extra_modules (e.g. EAGLE, Medusa), hence broadcast from the last rank.
138114
has_extra_modules = hasattr(unwrapped_model, "eagle_module") or hasattr(unwrapped_model, "medusa_heads")
139-
140-
# Broadcast from the last rank in case this is pipeline parallel
141-
if torch.distributed.is_initialized():
142-
extra_modules_list = [has_extra_modules]
143-
torch.distributed.broadcast_object_list(
144-
extra_modules_list,
145-
src=torch.distributed.get_world_size() - 1,
146-
)
147-
export_extra_modules_flag = extra_modules_list[0] if export_extra_modules else False
148-
else:
149-
export_extra_modules_flag = has_extra_modules if export_extra_modules else False
115+
has_extra_modules = dist.broadcast(has_extra_modules, src=dist.size() - 1)
116+
export_extra_modules_flag = has_extra_modules if export_extra_modules else False
150117

151118
if is_rank_0:
152119
console.print("[green]Exporting to HuggingFace format...[/green]")
@@ -173,14 +140,8 @@ def main(
173140
parser = argparse.ArgumentParser(
174141
description="Export a quantized Megatron-LM checkpoint to HuggingFace format on multiple GPUs"
175142
)
176-
parser.add_argument(
177-
"--hf-model-id", type=str, default=HF_MODEL_ID, help="HuggingFace model ID for tokenizer and model structure"
178-
)
143+
add_common_model_args(parser)
179144

180-
parser.add_argument("--tp", type=int, default=1, help="Tensor parallelism size")
181-
parser.add_argument("--pp", type=int, default=1, help="Pipeline parallelism size")
182-
parser.add_argument("--ep", type=int, default=1, help="Expert parallelism size")
183-
parser.add_argument("--etp", type=int, default=1, help="Expert tensor parallelism size")
184145
parser.add_argument(
185146
"--megatron-load-path",
186147
type=str,
@@ -205,11 +166,6 @@ def main(
205166
choices=["bfloat16", "float16", "float32"],
206167
help="Data type for export",
207168
)
208-
parser.add_argument(
209-
"--trust-remote-code",
210-
action="store_true",
211-
help="if trust_remote_code",
212-
)
213169

214170
args = parser.parse_args()
215171
main(
@@ -225,5 +181,4 @@ def main(
225181
args.trust_remote_code,
226182
)
227183

228-
if torch.distributed.is_initialized():
229-
torch.distributed.destroy_process_group()
184+
dist.cleanup()

‎examples/quantization/pretrain_quantized_llama3_8b.py‎

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
from pathlib import Path
6969
from typing import Tuple
7070

71-
import torch
71+
import modelopt.torch.utils.distributed as dist
7272
from omegaconf import OmegaConf
7373

7474
from megatron.bridge.recipes.llama import llama3_8b_pretrain_config as pretrain_config
@@ -210,9 +210,7 @@ def main() -> None:
210210
pretrain(config=cfg, forward_step_func=forward_step)
211211

212212
# Cleanup process group
213-
if torch.distributed.is_initialized():
214-
torch.distributed.barrier()
215-
torch.distributed.destroy_process_group()
213+
dist.cleanup()
216214

217215

218216
if __name__ == "__main__":

0 commit comments

Comments
 (0)