Skip to content

Commit 86b500f

Browse files
Back-port HF PTQ dtype/init-config fixes (#1839, #1857, #1869)
Transplant the combined get_model fix from PRs #1839, #1857 and #1869 onto release/0.45.0's examples/llm_ptq/example_utils.py. These PRs could not be cherry-picked directly because the file was renamed llm_ptq -> hf_ptq (#1759) and surrounding get_model code diverged on main, but the actual fix targets the init_empty_weights / from_config block that already exists on the release branch: - _resolve_init_config: re-derive a built-in config for remote-code checkpoints so device-map inference matches the model definition's version (fixes Nemotron-H moe_latent_size AttributeError on transformers 5.x, #1839). - _get_config_dtype / _apply_dtype_to_config: derive dtype from the resolved config and forward the DeciLM-supported dtype kwarg, dropping unsupported dtype forwarding on the real from_pretrained load (#1857, #1869). Ports the accompanying unit tests (path-adjusted to llm_ptq). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Keval Morabia <28916987+kevalmorabia97@users.noreply.github.com>
1 parent 20a4a85 commit 86b500f

2 files changed

Lines changed: 171 additions & 5 deletions

File tree

examples/llm_ptq/example_utils.py

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,44 @@ def get_original_hf_quant_method(config) -> str | None:
552552
return None
553553

554554

555+
def _resolve_init_config(hf_config, auto_model_module, ckpt_path, config_kwargs):
556+
"""Re-derive a built-in config when a remote-code config is used with a built-in model
557+
class, so it matches the model definition's version; fall back to hf_config otherwise.
558+
"""
559+
if auto_model_module in [AutoModelForCausalLM, AutoModel]:
560+
return hf_config
561+
if not type(hf_config).__module__.startswith("transformers_modules"):
562+
return hf_config
563+
builtin_config_kwargs = {k: v for k, v in config_kwargs.items() if k != "trust_remote_code"}
564+
try:
565+
return AutoConfig.from_pretrained(ckpt_path, **builtin_config_kwargs)
566+
except Exception as e:
567+
warnings.warn(
568+
f"Could not re-derive a built-in config for {ckpt_path} ({e}); using the "
569+
"remote-code config for device-map inference."
570+
)
571+
return hf_config
572+
573+
574+
def _get_config_dtype(config):
575+
config_dtype = (
576+
getattr(config, "dtype", None) or getattr(config, "torch_dtype", None) or torch.bfloat16
577+
)
578+
if isinstance(config_dtype, str):
579+
config_dtype = getattr(torch, config_dtype)
580+
return config_dtype
581+
582+
583+
def _apply_dtype_to_config(model_kwargs, config_dtype, architecture, apply_config_dtype=False):
584+
model_kwargs = model_kwargs.copy()
585+
if "DeciLM" in architecture:
586+
model_kwargs["torch_dtype"] = config_dtype
587+
model_kwargs.pop("dtype", None)
588+
elif apply_config_dtype:
589+
model_kwargs["dtype"] = config_dtype
590+
return model_kwargs
591+
592+
555593
def get_model(
556594
ckpt_path,
557595
device="cuda",
@@ -701,16 +739,21 @@ def has_pack_quantized_config(config):
701739
auto_model_module = getattr(transformers, architecture)
702740
from_config = auto_model_module._from_config
703741

742+
config_for_init = _resolve_init_config(
743+
hf_config, auto_model_module, ckpt_path, config_kwargs
744+
)
745+
704746
with init_empty_weights(include_buffers=True):
705747
# When computing the device_map, assuming bfloat16 precision by default,
706748
# unless specified by the hf_config.
707-
torch_dtype = getattr(hf_config, "torch_dtype", torch.bfloat16)
708-
model_kwargs2 = model_kwargs.copy()
749+
config_dtype = _get_config_dtype(config_for_init)
750+
model_kwargs2 = _apply_dtype_to_config(
751+
model_kwargs, config_dtype, architecture, apply_config_dtype=True
752+
)
709753
if auto_model_module not in [AutoModelForCausalLM, AutoModel]:
710754
model_kwargs2.pop("trust_remote_code", None)
711-
model_kwargs2["dtype"] = torch_dtype
712755
model_kwargs2.pop("max_memory", None)
713-
model = from_config(hf_config, **model_kwargs2)
756+
model = from_config(config_for_init, **model_kwargs2)
714757

715758
max_memory = get_max_memory()
716759
inferred_device_map = infer_auto_device_map(model, max_memory=max_memory)
@@ -730,10 +773,11 @@ def has_pack_quantized_config(config):
730773
)
731774
model_kwargs["max_memory"] = max_memory
732775

776+
model_kwargs2 = _apply_dtype_to_config(model_kwargs, config_dtype, architecture)
733777
model = auto_model_module.from_pretrained(
734778
ckpt_path,
735779
device_map=device_map,
736-
**model_kwargs,
780+
**model_kwargs2,
737781
)
738782
model.eval()
739783
if has_pack_quantized_config(hf_config):

tests/examples/llm_ptq/test_example_utils.py

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

2121
import json
22+
from contextlib import nullcontext
2223
from types import SimpleNamespace
24+
from unittest.mock import patch
2325

26+
import pytest
2427
import torch
2528
from _test_utils.examples.llm_ptq_example_utils import example_utils
2629
from safetensors.torch import save_file
@@ -194,3 +197,122 @@ def test_get_original_hf_quant_method_none_for_unquantized():
194197
example_utils.get_original_hf_quant_method(SimpleNamespace(quantization_config=None))
195198
is None
196199
)
200+
201+
202+
# ---------- _resolve_init_config ---------------------------------------------
203+
204+
205+
def _remote_config():
206+
# Config whose class module lives under "transformers_modules" (remote code).
207+
cls = type("_RemoteConfig", (), {"__module__": "transformers_modules.ckpt.config"})
208+
return cls()
209+
210+
211+
def test_resolve_init_config_rederives_for_remote_config():
212+
builtin_cfg = SimpleNamespace()
213+
with patch.object(
214+
example_utils.AutoConfig, "from_pretrained", return_value=builtin_cfg
215+
) as mock:
216+
out = example_utils._resolve_init_config(
217+
_remote_config(), object, "/ckpt", {"trust_remote_code": True}
218+
)
219+
assert out is builtin_cfg
220+
mock.assert_called_once_with("/ckpt") # trust_remote_code stripped
221+
222+
223+
def test_resolve_init_config_keeps_non_remote_config():
224+
cfg = SimpleNamespace() # module is "types", not remote
225+
with patch.object(example_utils.AutoConfig, "from_pretrained") as mock:
226+
assert example_utils._resolve_init_config(cfg, object, "/ckpt", {}) is cfg
227+
mock.assert_not_called()
228+
229+
230+
def test_resolve_init_config_falls_back_when_rederive_raises():
231+
cfg = _remote_config()
232+
with patch.object(example_utils.AutoConfig, "from_pretrained", side_effect=ValueError()):
233+
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 kwargs["torch_dtype"] is torch.float16
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)