-
Notifications
You must be signed in to change notification settings - Fork 536
[NVBug: 6563509] Harden meta-device skeleton build; drop Phi-3-vision / Phi-4-multimodal PTQ support #2115
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[NVBug: 6563509] Harden meta-device skeleton build; drop Phi-3-vision / Phi-4-multimodal PTQ support #2115
Changes from all commits
90c984e
d94911b
876dd8c
8444c11
1b062da
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -177,12 +177,6 @@ def _is_multimodal_config(config): | |||||||||
| """Check if a config indicates a multimodal model (config-only version of is_multimodal_model).""" | ||||||||||
| return ( | ||||||||||
| hasattr(config, "vision_config") # Standard vision config (e.g., Qwen2.5-VL) | ||||||||||
| or getattr(config, "model_type", "") == "phi4mm" # Phi-4 multimodal | ||||||||||
| or hasattr(config, "vision_lora") # Vision LoRA configurations | ||||||||||
| or hasattr(config, "audio_processor") # Audio processing capabilities | ||||||||||
| or ( | ||||||||||
| hasattr(config, "embd_layer") and hasattr(config.embd_layer, "image_embd_layer") | ||||||||||
| ) # Image embedding layers | ||||||||||
| or getattr(config, "is_encoder_decoder", False) # Encoder-decoder VL models | ||||||||||
| or any( # Architecture-based detection for custom VL models (e.g., Nemotron-Parse) | ||||||||||
| "conditionalgeneration" in arch.lower() for arch in getattr(config, "architectures", []) | ||||||||||
|
|
@@ -663,6 +657,41 @@ def _resolve_init_config(hf_config, auto_model_module, ckpt_path, config_kwargs) | |||||||||
| return hf_config | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def _build_meta_skeleton(from_config, config_for_init, model_kwargs, architecture): | ||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This addresses the implementation shape, but the prior critical test request is still unresolved: none of the changed files adds tests for this helper. Please commit mocked coverage for (1)
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Both points addressed in 1b062da — and you were right that the retry needed justifying. It did not survive the justification, so it is gone. Design. The probe answers exactly one boolean: will the model spill to CPU, so should So the probe only has to reproduce the module tree, and the binding constraint is that it must be no stricter than the loader it predicts:
So the answer to "why not just use the existing One note on Tests. Added in |
||||||||||
| """Build a throwaway meta-device model used only to size ``infer_auto_device_map``. | ||||||||||
|
|
||||||||||
| ``compute_module_sizes`` needs shapes and dtypes, never values or storage, so this | ||||||||||
| probe only has to reproduce the module tree. It must also be *no stricter than the | ||||||||||
| loader it predicts*, or it kills runs ``from_pretrained`` would have completed: | ||||||||||
|
|
||||||||||
| - Transformers 4.x builds under ``init_empty_weights()``, i.e. ``include_buffers=False``. | ||||||||||
| - Transformers 5.x builds under ``torch.device("meta")`` plus | ||||||||||
| ``meta_device_safe_creation_ops()``, which redirects ``torch.linspace`` to CPU so | ||||||||||
| remote code that derives scalars from it in ``__init__`` keeps working. | ||||||||||
|
|
||||||||||
| ``include_buffers=True`` is stricter than both: accelerate implements it as a bare | ||||||||||
| global ``torch.device("meta")`` context, so *every* tensor built in ``__init__`` lands | ||||||||||
| on meta and any ``int(torch.tensor(...))`` raises. ``include_buffers=False`` patches | ||||||||||
| only ``nn.Module.register_parameter``, leaving ``__init__`` arithmetic on a real | ||||||||||
| device; buffers stay materialized, which costs nothing here because their shape and | ||||||||||
| dtype size the same either way. | ||||||||||
|
|
||||||||||
| Returns ``None`` (after warning) if the model cannot be built at all; the caller then | ||||||||||
| skips the estimate rather than failing a load ``from_pretrained`` can still do. | ||||||||||
| """ | ||||||||||
| try: | ||||||||||
| with init_empty_weights(include_buffers=False): | ||||||||||
| return from_config(config_for_init, **model_kwargs) | ||||||||||
| except Exception as e: | ||||||||||
| warnings.warn( | ||||||||||
| f"Could not build a meta-device skeleton of {architecture} ({e!r}). " | ||||||||||
| "Skipping the device-map memory estimate and letting from_pretrained map the " | ||||||||||
| "model. If you hit GPU OOM, rerun with --use_seq_device_map (which applies " | ||||||||||
| "--gpu_max_mem_percentage) or lower --batch_size." | ||||||||||
| ) | ||||||||||
| return None | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def _get_config_dtype(config): | ||||||||||
| config_dtype = ( | ||||||||||
| getattr(config, "dtype", None) or getattr(config, "torch_dtype", None) or torch.bfloat16 | ||||||||||
|
|
@@ -873,17 +902,19 @@ def has_pack_quantized_config(config): | |||||||||
| hf_config, auto_model_module, ckpt_path, config_kwargs | ||||||||||
| ) | ||||||||||
|
|
||||||||||
| with init_empty_weights(include_buffers=True): | ||||||||||
| # When computing the device_map, assuming bfloat16 precision by default, | ||||||||||
| # unless specified by the hf_config. | ||||||||||
| config_dtype = _get_config_dtype(config_for_init) | ||||||||||
| model_kwargs2 = _apply_dtype_to_config( | ||||||||||
| model_kwargs, config_dtype, architecture, apply_config_dtype=True | ||||||||||
| ) | ||||||||||
| if auto_model_module not in [AutoModelForCausalLM, AutoModel]: | ||||||||||
| model_kwargs2.pop("trust_remote_code", None) | ||||||||||
| model_kwargs2.pop("max_memory", None) | ||||||||||
| model = from_config(config_for_init, **model_kwargs2) | ||||||||||
| # When computing the device_map, assuming bfloat16 precision by default, | ||||||||||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. how about we make this a util function?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 8444c11 — extracted as
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Follow-up: |
||||||||||
| # unless specified by the hf_config. | ||||||||||
| config_dtype = _get_config_dtype(config_for_init) | ||||||||||
| model_kwargs2 = _apply_dtype_to_config( | ||||||||||
| model_kwargs, config_dtype, architecture, apply_config_dtype=True | ||||||||||
| ) | ||||||||||
| if auto_model_module not in [AutoModelForCausalLM, AutoModel]: | ||||||||||
| model_kwargs2.pop("trust_remote_code", None) | ||||||||||
| model_kwargs2.pop("max_memory", None) | ||||||||||
|
|
||||||||||
| # Only a sizing aid for ``infer_auto_device_map`` below; ``None`` when the model | ||||||||||
| # cannot be built on meta, in which case the estimate is skipped. | ||||||||||
| model = _build_meta_skeleton(from_config, config_for_init, model_kwargs2, architecture) | ||||||||||
|
|
||||||||||
| max_memory = get_max_memory() | ||||||||||
|
|
||||||||||
|
|
@@ -903,7 +934,7 @@ def has_pack_quantized_config(config): | |||||||||
| f"Offload folder: {offload_folder}\n" | ||||||||||
| "Weights exceeding GPU+CPU budgets will be streamed from disk." | ||||||||||
| ) | ||||||||||
| else: | ||||||||||
| elif model is not None: | ||||||||||
| inferred_device_map = infer_auto_device_map(model, max_memory=max_memory) | ||||||||||
| if "cpu" in inferred_device_map.values(): | ||||||||||
| for _device in max_memory: | ||||||||||
|
|
||||||||||
This file was deleted.
This file was deleted.
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This still says Phi-3-vision “no longer loads on any version ModelOpt supports,” but the author’s reply confirms it was not tested on supported Transformers 4.57 and that its identified
_tied_weights_keysblocker is a 5.x failure. If the removal is a product decision because the model is superseded, document that rationale instead of making an unverified compatibility claim (or provide the 4.57 repro/blocker).