Skip to content

Commit 246de58

Browse files
committed
fix rotary/embedding config hf compat with older models and older hf
1 parent e501b9d commit 246de58

1 file changed

Lines changed: 120 additions & 0 deletions

File tree

gptqmodel/utils/hf.py

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,119 @@
2626

2727
log = setup_logger()
2828

29+
30+
# Older remote model files sometimes store tied-weight metadata as a plain list
31+
# like `["lm_head.weight"]`, but transformers 5.x now expects `{target: source}`.
32+
def _resolve_legacy_tied_weights_mapping(model: PreTrainedModel, tied_mapping) -> dict[str, str]:
33+
if not isinstance(tied_mapping, (list, tuple, set)):
34+
return {}
35+
36+
if not getattr(model.config, "tie_word_embeddings", False):
37+
return {}
38+
39+
input_embeddings = model.get_input_embeddings()
40+
input_weight = getattr(input_embeddings, "weight", None)
41+
if input_weight is None:
42+
return {}
43+
44+
source_name = None
45+
for name, param in model.named_parameters(remove_duplicate=False):
46+
if param is input_weight:
47+
source_name = name
48+
break
49+
50+
if source_name is None:
51+
return {}
52+
53+
return {
54+
# Legacy list entries only name the tied target, so resolve them back
55+
# to the input embedding weight name expected by transformers 5.x.
56+
target_name: source_name
57+
for target_name in tied_mapping
58+
if isinstance(target_name, str) and target_name != source_name
59+
}
60+
61+
62+
# Rewrite legacy list-based `_tied_weights_keys` in-place so newer HF save/load
63+
# helpers stop tripping over remote code that still uses the old format.
64+
def _normalize_legacy_tied_weights_keys(model: PreTrainedModel) -> None:
65+
for _name, submodule in model.named_modules(remove_duplicate=False):
66+
tied_mapping = getattr(submodule, "_tied_weights_keys", None)
67+
if not isinstance(tied_mapping, (list, tuple, set)):
68+
continue
69+
70+
if isinstance(submodule, PreTrainedModel):
71+
submodule._tied_weights_keys = _resolve_legacy_tied_weights_mapping(submodule, tied_mapping)
72+
else:
73+
submodule._tied_weights_keys = {}
74+
75+
76+
# Bridge a few transformers 5.x API/config changes so older trust_remote_code
77+
# model files still import and initialize without patching their cached source.
78+
def _patch_transformers_remote_code_compat() -> None:
79+
try:
80+
from transformers.utils import import_utils
81+
except Exception:
82+
return
83+
84+
if not hasattr(import_utils, "is_torch_fx_available"):
85+
# transformers 5.x dropped this helper, but a number of remote model
86+
# implementations still import it from transformers.utils.import_utils.
87+
def is_torch_fx_available() -> bool:
88+
return hasattr(torch, "fx")
89+
90+
import_utils.is_torch_fx_available = is_torch_fx_available
91+
92+
if not getattr(PreTrainedModel, "_gptqmodel_legacy_tied_weights_patch", False):
93+
original_get_expanded_tied_weights_keys = PreTrainedModel.get_expanded_tied_weights_keys
94+
95+
def get_expanded_tied_weights_keys(self, all_submodels: bool = False) -> dict:
96+
# transformers 5.x expects `_tied_weights_keys` to be a dict, while
97+
# older trust_remote_code models still declare it as `["lm_head.weight"]`.
98+
tied_mapping = getattr(self, "_tied_weights_keys", None)
99+
if not isinstance(tied_mapping, (list, tuple, set)):
100+
return original_get_expanded_tied_weights_keys(self, all_submodels=all_submodels)
101+
102+
if all_submodels:
103+
expanded_tied_weights = {}
104+
for prefix, submodule in self.named_modules(remove_duplicate=False):
105+
if isinstance(submodule, PreTrainedModel):
106+
submodel_tied_weights = submodule.get_expanded_tied_weights_keys(all_submodels=False)
107+
if prefix != "":
108+
submodel_tied_weights = {
109+
f"{prefix}.{k}": f"{prefix}.{v}" for k, v in submodel_tied_weights.items()
110+
}
111+
expanded_tied_weights.update(submodel_tied_weights)
112+
return expanded_tied_weights
113+
114+
if not getattr(self.config, "tie_word_embeddings", False):
115+
return {}
116+
117+
return _resolve_legacy_tied_weights_mapping(self, tied_mapping)
118+
119+
PreTrainedModel.get_expanded_tied_weights_keys = get_expanded_tied_weights_keys
120+
PreTrainedModel._gptqmodel_legacy_tied_weights_patch = True
121+
122+
123+
# Restore the pre-transformers-5 RoPE config shape expected by older remote
124+
# MiniCPM code before HF instantiates the architecture from config.
125+
def _normalize_remote_code_config_compat(config: Any) -> None:
126+
# transformers 5.x normalizes RoPE config to `rope_type`, but older
127+
# remote MiniCPM code still expects `rope_scaling["type"]` or `None`.
128+
rope_scaling = getattr(config, "rope_scaling", None)
129+
if not isinstance(rope_scaling, dict) or "type" in rope_scaling:
130+
return
131+
132+
rope_type = rope_scaling.get("rope_type")
133+
factor = rope_scaling.get("factor")
134+
135+
if rope_type in (None, "default") and factor is None:
136+
config.rope_scaling = None
137+
return
138+
139+
config.rope_scaling = dict(rope_scaling)
140+
config.rope_scaling["type"] = rope_type
141+
29142
def _sanitize_generation_config(cfg: GenerationConfig, *, drop_sampling_fields: bool = False) -> bool:
30143
changed = False
31144
if cfg is None:
@@ -154,6 +267,10 @@ def build_shell_model(
154267
del init_kwargs["_fast_init"]
155268
# All nn.Parameters and buffers are created
156269

270+
if trust_remote_code:
271+
_patch_transformers_remote_code_compat()
272+
_normalize_remote_code_config_compat(config)
273+
157274
# All nn.Parameters and buffers are created on 'meta' and initializers are skipped.
158275
pb = log.spinner(title="Model loading...", interval=0.1)
159276
try:
@@ -167,4 +284,7 @@ def build_shell_model(
167284
finally:
168285
pb.close()
169286

287+
if trust_remote_code and isinstance(shell, PreTrainedModel):
288+
_normalize_legacy_tied_weights_keys(shell)
289+
170290
return shell

0 commit comments

Comments
 (0)