mirror of
https://github.com/NVIDIA/Model-Optimizer.git
synced 2026-10-02 03:14:52 +08:00
Fix pruned-HF export fallback + add Nemotron-3.5-Lightning launcher examples (#2196)
### What does this PR do? Type of change: Bug fix + new example Two related changes for the Megatron-Bridge Minitron prune/quantize launcher flows: 1. **Fix pruned-HF export crash on containers that reject config-only save.** `#2159` added a config-only HF export path gated only on `hasattr(AutoBridge, "from_hf_config")`. Some Megatron-Bridge versions (e.g. `nemo:26.04`) expose `from_hf_config` but reject a config-only `save_hf_pretrained` (`ValueError: save_hf_pretrained requires a pretrained HuggingFace model`), so `prune_minitron.py` crashed instead of using the intended dummy-model fallback. Now it attempts the config-only save and falls back to the dummy-model path on `ValueError`. 2. **Add Nemotron-3.5-Lightning-30B-A3B launcher examples** (`mbridge_prune.yaml`, `mbridge_quantize.yaml`) on `nemo:26.08`. Prune targets 3B active with an MMLU gate; quantize runs W4A16 NVFP4 4/6 PTQ via the `w4a16_nvfp4_4o6` recipe with `tp_size=1` (static-block NVFP4 MSE is unsupported with TP>1). ### Usage ```shell uv run launch.py --yaml examples/nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16/mbridge_prune.yaml --yes uv run launch.py --yaml examples/nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16/mbridge_quantize.yaml --yes ``` ### Testing Verified end-to-end on OCI-HSG: - **Nano prune (`nemo:26.04`)** — exercises the fallback path: config-only save raised the `ValueError`, the fallback caught it and exported via the dummy-model path. `mmlu_10pct_bs32 = 0.5196` (gate 0.50) PASS; vLLM gen PASS. - **Lightning prune (`nemo:26.08`)** — config-only export path: `score = 0.6000` (gate 0.58) PASS, 3.00B active params; vLLM gen PASS. - **Lightning quantize (`nemo:26.08`)** — recipe PTQ + unified-HF export; MMLU `0.7741` (gate 0.75) PASS. ### Before your PR is "*Ready for review*" - Is this change backward compatible?: ✅ - If you copied code from any other sources or added a new PIP dependency, did you follow guidance in `CONTRIBUTING.md`: N/A - Did you write any new necessary tests?: N/A <!-- launcher example configs + fallback path exercised by CI prune/quantize jobs --> - Did you update [Changelog](https://github.com/NVIDIA/Model-Optimizer/blob/main/CHANGELOG.rst)?: N/A <!-- fix is for a bug introduced in the same unreleased cycle (#2159); rest are example configs --> - Did you get Claude approval on this PR?: ❌ <!-- pending /claude review --> ### Additional Information The fallback fix addresses the `mbridge_prune` launcher CI failure introduced by #2159. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a pruning workflow for Nemotron-3.5-Lightning-30B-A3B with calibration, quality scoring, checkpoint export, and multi-GPU generation. - Added a four-GPU NVFP4 W4A16 quantization workflow with Hugging Face conversion and MMLU evaluation. - **Bug Fixes** - Improved hybrid model export by falling back to dummy-model export for supported configuration-only export failures. - Added clearer logging and handling for supported export failures while preserving unrelated errors for investigation. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
3d2522e447
commit
58ad6edc5f
@@ -712,21 +712,34 @@ def main(args: argparse.Namespace):
|
||||
|
||||
# Config-only bridge (hf_keys=None) keeps the embedding task when transformers' saved key
|
||||
# differs from the bridge mapping (NemotronH's backbone.embedding vs ...embeddings).
|
||||
use_config_only_export = (
|
||||
exported_config_only = False
|
||||
if (
|
||||
hasattr(AutoBridge, "from_hf_config")
|
||||
and isinstance(provider, _HYBRID_PROVIDER_TYPES)
|
||||
and not is_vlm
|
||||
)
|
||||
if use_config_only_export:
|
||||
):
|
||||
pruned_bridge = AutoBridge.from_hf_config(hf_cfg)
|
||||
# save_hf_pretrained reads trust_remote_code off the bridge to fetch source artifacts;
|
||||
# from_hf_config can't infer it since AutoConfig consumes the kwarg.
|
||||
pruned_bridge.trust_remote_code = args.trust_remote_code
|
||||
pruned_bridge.save_hf_pretrained(
|
||||
model, args.output_hf_path, source_path=args.hf_model_name_or_path
|
||||
)
|
||||
else:
|
||||
if isinstance(provider, _HYBRID_PROVIDER_TYPES) and not is_vlm:
|
||||
try:
|
||||
pruned_bridge.save_hf_pretrained(
|
||||
model, args.output_hf_path, source_path=args.hf_model_name_or_path
|
||||
)
|
||||
exported_config_only = True
|
||||
except ValueError as e:
|
||||
# nemo:26.06+ exposes from_hf_config but rejects config-only save_hf_pretrained;
|
||||
# fall back to the dummy-model path below.
|
||||
if "requires a pretrained HuggingFace model" not in str(e):
|
||||
raise
|
||||
warn_rank_0(f"Config-only HF export unsupported ({e}); using dummy-model export.")
|
||||
|
||||
if not exported_config_only:
|
||||
if (
|
||||
not hasattr(AutoBridge, "from_hf_config")
|
||||
and isinstance(provider, _HYBRID_PROVIDER_TYPES)
|
||||
and not is_vlm
|
||||
):
|
||||
warn_rank_0(
|
||||
"Megatron-Bridge lacks config-only HF export; falling back to the dummy-model "
|
||||
"path, which cannot round-trip a pruned native NemotronH config. Use "
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
# Nemotron-3.5-Lightning-30B-A3B (MoE) pruning to 3B active via Megatron-Bridge (4 GPUs), then vLLM gen.
|
||||
#
|
||||
# Slurm: uv run launch.py --yaml examples/nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16/mbridge_prune.yaml --yes
|
||||
# Local: uv run launch.py --yaml examples/nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16/mbridge_prune.yaml hf_local=/mnt/hf-local --yes
|
||||
|
||||
# NOTE: sized for fast CI; bump for production, e.g. --calib_num_samples 1024 --seq_length 8192 --top_k 10.
|
||||
# May need to reduce batch size if running out of memory at large seq_length.
|
||||
job_name: Nemotron-3.5-Lightning-30B-A3B_mbridge_prune
|
||||
pipeline:
|
||||
note: "Prune Nemotron-3.5-Lightning-30B-A3B -> 3B active (Megatron-Bridge) with MMLU gate, then vLLM gen"
|
||||
|
||||
global_vars:
|
||||
# Per-run scratch (fresh cicd_<id> dir) so each run prunes fresh
|
||||
output_dir: /scratchspace/Nemotron-3.5-Lightning-30B-A3B-Pruned-A3.0B
|
||||
|
||||
# 1) Prune and export as a HF checkpoint.
|
||||
# --score_lower_bound fails the job if the pruned model's MMLU drops below the floor.
|
||||
task_0:
|
||||
environment:
|
||||
- LAUNCH_SCRIPT: torchrun --nproc_per_node 4
|
||||
inline: >-
|
||||
$LAUNCH_SCRIPT modules/Model-Optimizer/examples/megatron_bridge/prune_minitron.py
|
||||
--hf_model_name_or_path nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16
|
||||
--trust_remote_code
|
||||
--pp_size 4
|
||||
--calib_batch_size 8
|
||||
--calib_num_samples 256
|
||||
--seq_length 512
|
||||
--prune_target_active_params 3e9
|
||||
--prune_target_params 24e9
|
||||
--prune_score_func mmlu_10pct_bs32
|
||||
--max_width_pruning 0.30
|
||||
--max_depth_pruning 0.15
|
||||
--hparams_to_skip num_attention_heads
|
||||
--top_k 5
|
||||
--score_lower_bound 0.58
|
||||
--output_hf_path <<global_vars.output_dir>>
|
||||
slurm_config: &sc
|
||||
_factory_: "slurm_factory"
|
||||
container: nvcr.io/nvidia/nemo:26.08
|
||||
modelopt_install_path: /opt/venv/lib/python3.12/site-packages/modelopt
|
||||
docker_user: root
|
||||
nodes: 1
|
||||
ntasks_per_node: 4
|
||||
gpus_per_node: 4
|
||||
|
||||
# 2) vLLM sanity generation on the pruned checkpoint.
|
||||
task_1:
|
||||
inline: >-
|
||||
python modules/Model-Optimizer/examples/megatron_bridge/generate_vllm.py
|
||||
--model <<global_vars.output_dir>>
|
||||
--trust_remote_code
|
||||
--tensor_parallel_size 4
|
||||
slurm_config:
|
||||
<<: *sc
|
||||
ntasks_per_node: 1
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
# Nemotron-3.5-Lightning-30B-A3B NVFP4 (W4A16 4/6) quantization + unified-HF export via Megatron-Bridge (4 GPUs).
|
||||
#
|
||||
# Slurm: uv run launch.py --yaml examples/nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16/mbridge_quantize.yaml --yes
|
||||
# Local: uv run launch.py --yaml examples/nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16/mbridge_quantize.yaml hf_local=/mnt/hf-local --yes
|
||||
|
||||
# NOTE: sized for fast run; bump for production, e.g. --calib_num_samples 512 --seq_length 8192.
|
||||
job_name: Nemotron-3.5-Lightning-30B-A3B_mbridge_quantize
|
||||
pipeline:
|
||||
note: "NVFP4 W4A16 PTQ Nemotron-3.5-Lightning-30B-A3B (Megatron-Bridge recipe), then unified-HF export"
|
||||
|
||||
global_vars:
|
||||
# Per-run scratch (fresh cicd_<id> dir) so each run quantizes fresh.
|
||||
output_dir: /scratchspace
|
||||
|
||||
# 1) NVFP4 Quantize via the ptq recipe and export to a deployable unified-HF checkpoint.
|
||||
# tp_size=1: static-block NVFP4 (MSE) weight quant is unsupported with TP>1.
|
||||
task_0:
|
||||
environment:
|
||||
- LAUNCH_SCRIPT: torchrun --nproc_per_node 4
|
||||
inline: >-
|
||||
$LAUNCH_SCRIPT modules/Model-Optimizer/examples/megatron_bridge/quantize.py
|
||||
--hf_model_name_or_path nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16
|
||||
--trust_remote_code
|
||||
--tp_size 1
|
||||
--recipe huggingface/models/nvidia/Nemotron-3.5-Lightning-30B-A3B-BF16/ptq/w4a16_nvfp4_4o6
|
||||
--calib_batch_size 8
|
||||
--calib_num_samples 256
|
||||
--seq_length 512
|
||||
--skip_generate
|
||||
--export_megatron_path <<global_vars.output_dir>>/Nemotron-3.5-Lightning-30B-A3B-NVFP4-megatron
|
||||
&&
|
||||
$LAUNCH_SCRIPT modules/Model-Optimizer/examples/megatron_bridge/export_quantized_megatron_to_hf.py
|
||||
--hf_model_name_or_path nvidia/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-BF16
|
||||
--megatron_path <<global_vars.output_dir>>/Nemotron-3.5-Lightning-30B-A3B-NVFP4-megatron
|
||||
--trust_remote_code
|
||||
--pp_size 4
|
||||
--export_unified_hf_path <<global_vars.output_dir>>/Nemotron-3.5-Lightning-30B-A3B-NVFP4-hf
|
||||
slurm_config: &sc
|
||||
_factory_: "slurm_factory"
|
||||
container: nvcr.io/nvidia/nemo:26.08
|
||||
modelopt_install_path: /opt/venv/lib/python3.12/site-packages/modelopt
|
||||
docker_user: root
|
||||
nodes: 1
|
||||
ntasks_per_node: 4
|
||||
gpus_per_node: 4
|
||||
|
||||
# 2) MMLU (10% sample) on the exported NVFP4 checkpoint via vLLM, gated on a lower bound.
|
||||
task_1:
|
||||
reqs_file: modules/Model-Optimizer/examples/llm_eval/requirements.txt
|
||||
inline: >-
|
||||
python modules/Model-Optimizer/examples/llm_eval/lm_eval_hf.py
|
||||
--model vllm
|
||||
--model_args pretrained=<<global_vars.output_dir>>/Nemotron-3.5-Lightning-30B-A3B-NVFP4-hf,tensor_parallel_size=4
|
||||
--trust_remote_code
|
||||
--tasks mmlu
|
||||
--limit 0.1
|
||||
--batch_size auto
|
||||
--output_path /scratchspace/mmlu_results
|
||||
--accuracy_lower_bound 0.75
|
||||
slurm_config:
|
||||
<<: *sc
|
||||
ntasks_per_node: 1
|
||||
Reference in New Issue
Block a user