2626
2727log = 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+
29142def _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