|
66 | 66 | ) |
67 | 67 | from modelopt.torch.utils.image_processor import BaseImageProcessor, MllamaImageProcessor |
68 | 68 | from modelopt.torch.utils.memory_monitor import launch_memory_monitor |
| 69 | +from modelopt.torch.utils.nemotron_vlm_dataset_utils import get_nemotron_vlm_dataset_dataloader |
69 | 70 | from modelopt.torch.utils.speech_dataset_utils import get_speech_dataset_dataloader |
70 | 71 | from modelopt.torch.utils.vlm_dataset_utils import get_vlm_dataset_dataloader |
71 | 72 |
|
@@ -141,6 +142,7 @@ def make_calib_dataloader( |
141 | 142 | tokenizer: PreTrainedTokenizerBase | None, |
142 | 143 | device: torch.device, |
143 | 144 | model_type: str | None, |
| 145 | + full_model: torch.nn.Module | None = None, |
144 | 146 | ) -> tuple[DataLoader, str | None]: |
145 | 147 | calib_dataloader = None |
146 | 148 | first_text_speech_dataset = None |
@@ -402,18 +404,35 @@ def load_model(args: argparse.Namespace): |
402 | 404 | language_model = extracted_lm |
403 | 405 | model_type = extracted_model_type |
404 | 406 | else: |
| 407 | + # Check if this is a Nemotron VL model that needs a processor |
| 408 | + # Do this BEFORE setting default datasets so we can use image-text data for Nemotron-Parse |
| 409 | + is_nemotron_vl_model = is_nemotron_vl(full_model) |
| 410 | + |
| 411 | + # Check specifically for Nemotron-Parse to set appropriate dataset defaults |
| 412 | + config = full_model.config |
| 413 | + architectures = getattr(config, "architectures", []) |
| 414 | + is_nemotron_parse = any("nemotronparse" in arch.lower() for arch in architectures) |
| 415 | + |
405 | 416 | if args.dataset is None: |
406 | | - args.dataset = ["cnn_dailymail", "nemotron-post-training-dataset-v2"] |
407 | | - warnings.warn( |
408 | | - "No dataset specified. Defaulting to cnn_dailymail and nemotron-post-training-dataset-v2." |
409 | | - ) |
| 417 | + if is_nemotron_parse: |
| 418 | + # For Nemotron-Parse, default to Nemotron VLM Dataset v2 |
| 419 | + args.dataset = ["nemotron_vlm_v2"] |
| 420 | + print( |
| 421 | + "No dataset specified. Defaulting to 'nemotron_vlm_v2' for Nemotron-Parse " |
| 422 | + "(NVIDIA's image-text dataset for better calibration)." |
| 423 | + ) |
| 424 | + else: |
| 425 | + # For other models, use text-only datasets |
| 426 | + args.dataset = ["cnn_dailymail", "nemotron-post-training-dataset-v2"] |
| 427 | + warnings.warn( |
| 428 | + "No dataset specified. Defaulting to cnn_dailymail and nemotron-post-training-dataset-v2." |
| 429 | + ) |
| 430 | + |
410 | 431 | # Adjust calib_size to match dataset length by extending or truncating as needed |
411 | 432 | args.calib_size = (args.calib_size + [args.calib_size[-1]] * len(args.dataset))[ |
412 | 433 | : len(args.dataset) |
413 | 434 | ] |
414 | 435 |
|
415 | | - # Check if this is a Nemotron VL model that needs a processor |
416 | | - is_nemotron_vl_model = is_nemotron_vl(full_model) |
417 | 436 | if is_nemotron_vl_model: |
418 | 437 | # Load processor for Nemotron VL models (like Nemotron-Parse) |
419 | 438 | processor = get_processor( |
@@ -506,14 +525,23 @@ def mono_quantize( |
506 | 525 | "Consider reducing calib_size to reduce calibration time.\n####\n" |
507 | 526 | ) |
508 | 527 |
|
| 528 | + # Check if this is Nemotron-Parse |
| 529 | + config = full_model.config |
| 530 | + architectures = getattr(config, "architectures", []) |
| 531 | + is_nemotron_parse = any("nemotronparse" in arch.lower() for arch in architectures) |
| 532 | + original_forward = None # Track original forward method if we wrap it |
| 533 | + |
509 | 534 | # For Nemotron VL models, disable quantization of vision components |
510 | 535 | if is_nemotron_vl_model: |
511 | 536 | print("Disabling quantization for vision components in Nemotron VL model") |
512 | 537 | quant_cfg["quant_cfg"]["*vision*"] = {"enable": False} |
513 | 538 | quant_cfg["quant_cfg"]["*image*"] = {"enable": False} |
514 | | - # Also disable radio model components specifically |
| 539 | + # Also disable radio model components specifically (for Nemotron-Parse) |
515 | 540 | quant_cfg["quant_cfg"]["*radio*"] = {"enable": False} |
516 | 541 | quant_cfg["quant_cfg"]["*visual*"] = {"enable": False} |
| 542 | + quant_cfg["quant_cfg"]["*encoder*"] = {"enable": False} # Disable encoder |
| 543 | + quant_cfg["quant_cfg"]["*model_encoder*"] = {"enable": False} # Nemotron-Parse specific |
| 544 | + print("Quantization will only be applied to the decoder (text generation) component") |
517 | 545 |
|
518 | 546 | if not model_is_already_quantized or calibration_only: |
519 | 547 | if model_type == "gptoss" and args.qformat == "nvfp4_mlp_only": |
@@ -541,8 +569,15 @@ def mono_quantize( |
541 | 569 | else: |
542 | 570 | language_model = mtq.quantize(language_model, quant_cfg, forward_loop=calibrate_loop) |
543 | 571 |
|
544 | | - # For VL models, update full_model to use the quantized language model |
545 | | - if is_nemotron_vl_model: |
| 572 | + # Restore original forward method if we wrapped it for Nemotron-Parse |
| 573 | + if is_nemotron_parse and original_forward is not None: |
| 574 | + print("Restoring original forward method after calibration") |
| 575 | + language_model.forward = original_forward |
| 576 | + original_forward = None |
| 577 | + |
| 578 | + # For VL models (except Nemotron-Parse), update full_model to use the quantized language model |
| 579 | + # For Nemotron-Parse, language_model IS full_model, so no update needed |
| 580 | + if is_nemotron_vl_model and language_model is not full_model: |
546 | 581 | language_model_lineage = get_language_model_from_vl(full_model) |
547 | 582 | if language_model_lineage is not None: |
548 | 583 | print("Updating full_model with quantized language_model...") |
@@ -866,38 +901,12 @@ def quantize_main( |
866 | 901 | print(f"Use calib batch_size {args.batch_size}") |
867 | 902 |
|
868 | 903 | calib_dataloader, first_text_speech_dataset = make_calib_dataloader( |
869 | | - args, language_model, processor, tokenizer, device, model_type |
| 904 | + args, language_model, processor, tokenizer, device, model_type, full_model |
870 | 905 | ) |
871 | 906 |
|
872 | 907 | # Detect if this is a Nemotron VL model using architecture-based detection |
873 | 908 | is_nemotron_vl_model = is_nemotron_vl(full_model) |
874 | 909 |
|
875 | | - # For Nemotron-Parse, wrap the text-only dataloader to add dummy images |
876 | | - # Nemotron-Parse is an encoder-decoder model that requires pixel_values |
877 | | - if is_nemotron_vl_model and processor is not None: |
878 | | - config = full_model.config |
879 | | - architectures = getattr(config, "architectures", []) |
880 | | - is_nemotron_parse = any("nemotronparse" in arch.lower() for arch in architectures) |
881 | | - |
882 | | - if is_nemotron_parse: |
883 | | - # Check if we're quantizing just the decoder or the full model |
884 | | - decoder_only = language_model is not full_model |
885 | | - |
886 | | - if decoder_only: |
887 | | - print( |
888 | | - "Calibration will use text-only inputs for Nemotron-Parse decoder. " |
889 | | - "Vision encoder is excluded from quantization." |
890 | | - ) |
891 | | - else: |
892 | | - print( |
893 | | - "Wrapping calibration dataloader for Nemotron-Parse to add dummy images. " |
894 | | - "Nemotron-Parse requires pixel_values for full model calibration." |
895 | | - ) |
896 | | - |
897 | | - calib_dataloader = create_nemotron_parse_calib_wrapper( |
898 | | - calib_dataloader, processor, device, decoder_only=decoder_only |
899 | | - ) |
900 | | - |
901 | 910 | preview_input_ids, generated_ids_before_ptq = pre_quantize( |
902 | 911 | args, full_model, model_type, tokenizer, calib_dataloader, is_nemotron_vl_model |
903 | 912 | ) |
|
0 commit comments