Skip to content

Commit d70c48c

Browse files
authored
Fix HF PTQ empty-init dtype kwargs (#1857)
## Summary Fixes NVBug 6359821: `hf_ptq.py` can fail for remote/custom architectures like `DeciLMForCausalLM` when dtype-related kwargs are forwarded into model construction paths that do not accept them. This change keeps the fix scoped to the observed DeciLM/Llama Nemotron path. It resolves the init config used for empty-weight construction, derives dtype consistently from the resolved config, forwards the supported dtype kwarg for the DeciLM empty-weight probe, and drops unsupported dtype forwarding from the DeciLM real `from_pretrained()` load. NVBug: https://nvbugspro.nvidia.com/bug/6359821 ## Validation - `pre-commit run --files examples/hf_ptq/example_utils.py tests/examples/hf_ptq/test_example_utils.py` - `pytest_pwd tests/examples/hf_ptq/test_example_utils.py -q -x` (15 passed) - Actual `Llama-3_3-Nemotron-Super-49B-v1` end-to-end `hf_ptq.py` export on one node with 6 GPUs, Transformers 4.48.3: #1857 (comment) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved model loading for Hugging Face remote-code scenarios by safely re-deriving the initialization configuration when needed, with a warning-based fallback. * Ensured precision is derived consistently from the resolved config (including dtype name handling) with a safe default when unspecified. * Tightened forwarding of precision-related kwargs and `trust_remote_code`, and avoided passing `max_memory` during config loading. * **Tests** * Added unit coverage for initialization config resolution (including failure fallback). * Extended integration-style coverage to validate dtype/kwarg forwarding, `trust_remote_code` behavior, and eval-mode initialization. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Signed-off-by: realAsma <akuriparambi@nvidia.com>
1 parent 43c2034 commit d70c48c

2 files changed

Lines changed: 104 additions & 3 deletions

File tree

examples/hf_ptq/example_utils.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -750,18 +750,29 @@ def has_pack_quantized_config(config):
750750
auto_model_module = getattr(transformers, architecture)
751751
from_config = auto_model_module._from_config
752752

753+
is_decilm = "DeciLM" in architecture
753754
config_for_init = _resolve_init_config(
754755
hf_config, auto_model_module, ckpt_path, config_kwargs
755756
)
756757

757758
with init_empty_weights(include_buffers=True):
758759
# When computing the device_map, assuming bfloat16 precision by default,
759760
# unless specified by the hf_config.
760-
torch_dtype = getattr(config_for_init, "torch_dtype", torch.bfloat16)
761+
config_dtype = (
762+
getattr(config_for_init, "dtype", None)
763+
or getattr(config_for_init, "torch_dtype", None)
764+
or torch.bfloat16
765+
)
766+
if isinstance(config_dtype, str):
767+
config_dtype = getattr(torch, config_dtype)
761768
model_kwargs2 = model_kwargs.copy()
762769
if auto_model_module not in [AutoModelForCausalLM, AutoModel]:
763770
model_kwargs2.pop("trust_remote_code", None)
764-
model_kwargs2["dtype"] = torch_dtype
771+
if is_decilm:
772+
model_kwargs2["torch_dtype"] = config_dtype
773+
model_kwargs2.pop("dtype", None)
774+
else:
775+
model_kwargs2["dtype"] = config_dtype
765776
model_kwargs2.pop("max_memory", None)
766777
model = from_config(config_for_init, **model_kwargs2)
767778

@@ -783,10 +794,13 @@ def has_pack_quantized_config(config):
783794
)
784795
model_kwargs["max_memory"] = max_memory
785796

797+
model_kwargs2 = model_kwargs.copy()
798+
if is_decilm:
799+
model_kwargs2.pop("dtype", None)
786800
model = auto_model_module.from_pretrained(
787801
ckpt_path,
788802
device_map=device_map,
789-
**model_kwargs,
803+
**model_kwargs2,
790804
)
791805
model.eval()
792806
if has_pack_quantized_config(hf_config):

tests/examples/hf_ptq/test_example_utils.py

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,11 @@
1919
"""
2020

2121
import json
22+
from contextlib import nullcontext
2223
from types import SimpleNamespace
2324
from unittest.mock import patch
2425

26+
import pytest
2527
import torch
2628
from _test_utils.examples.hf_ptq_example_utils import example_utils
2729
from safetensors.torch import save_file
@@ -229,3 +231,88 @@ def test_resolve_init_config_falls_back_when_rederive_raises():
229231
cfg = _remote_config()
230232
with patch.object(example_utils.AutoConfig, "from_pretrained", side_effect=ValueError()):
231233
assert example_utils._resolve_init_config(cfg, object, "/ckpt", {}) is cfg
234+
235+
236+
@pytest.mark.parametrize(
237+
(
238+
"architecture",
239+
"model_class_name",
240+
"expected_config_dtype_kwarg",
241+
"unexpected_config_dtype_kwarg",
242+
),
243+
[
244+
("DeciLMForCausalLM", "AutoModelForCausalLM", "torch_dtype", "dtype"),
245+
("LlamaForCausalLM", "LlamaForCausalLM", "dtype", "torch_dtype"),
246+
],
247+
)
248+
def test_get_model_uses_expected_dtype_kwarg(
249+
monkeypatch,
250+
architecture,
251+
model_class_name,
252+
expected_config_dtype_kwarg,
253+
unexpected_config_dtype_kwarg,
254+
):
255+
calls = {}
256+
hf_config = SimpleNamespace(
257+
architectures=[architecture],
258+
dtype=torch.float16,
259+
model_type="llama",
260+
torch_dtype=torch.bfloat16,
261+
)
262+
263+
class FakeModel:
264+
def eval(self):
265+
calls["eval"] = True
266+
267+
class FakeAutoModelForCausalLM:
268+
@staticmethod
269+
def from_config(config, **kwargs):
270+
calls["from_config"] = kwargs
271+
assert config is hf_config
272+
assert kwargs[expected_config_dtype_kwarg] is torch.float16
273+
assert unexpected_config_dtype_kwarg not in kwargs
274+
assert "max_memory" not in kwargs
275+
return FakeModel()
276+
277+
@staticmethod
278+
def from_pretrained(*args, **kwargs):
279+
calls["from_pretrained"] = kwargs
280+
assert "dtype" not in kwargs
281+
assert "torch_dtype" not in kwargs
282+
return FakeModel()
283+
284+
class FakeLlamaForCausalLM(FakeAutoModelForCausalLM):
285+
_from_config = FakeAutoModelForCausalLM.from_config
286+
287+
@staticmethod
288+
def from_pretrained(*args, **kwargs):
289+
calls["from_pretrained"] = kwargs
290+
assert kwargs["dtype"] == "auto"
291+
assert "torch_dtype" not in kwargs
292+
return FakeModel()
293+
294+
monkeypatch.setattr(
295+
example_utils.AutoConfig,
296+
"from_pretrained",
297+
lambda *args, **kwargs: hf_config,
298+
)
299+
if model_class_name == "AutoModelForCausalLM":
300+
monkeypatch.setattr(example_utils, "AutoModelForCausalLM", FakeAutoModelForCausalLM)
301+
monkeypatch.delattr(example_utils.transformers, architecture, raising=False)
302+
else:
303+
monkeypatch.setattr(example_utils.transformers, model_class_name, FakeLlamaForCausalLM)
304+
monkeypatch.setattr(example_utils, "is_nemotron_vl", lambda config: False)
305+
monkeypatch.setattr(example_utils, "is_speculative", lambda config: False)
306+
monkeypatch.setattr(example_utils, "init_empty_weights", lambda include_buffers: nullcontext())
307+
monkeypatch.setattr(example_utils, "get_max_memory", lambda: {0: 1024})
308+
monkeypatch.setattr(example_utils, "infer_auto_device_map", lambda model, max_memory: {"": 0})
309+
310+
model = example_utils.get_model("checkpoint", device="cpu", trust_remote_code=True)
311+
312+
assert isinstance(model, FakeModel)
313+
assert calls["eval"]
314+
if expected_config_dtype_kwarg == "torch_dtype":
315+
assert calls["from_config"]["trust_remote_code"] is True
316+
else:
317+
assert "trust_remote_code" not in calls["from_config"]
318+
assert calls["from_pretrained"]["trust_remote_code"] is True

0 commit comments

Comments
 (0)