3838
3939
4040_torch_distributed_available = torch .distributed .is_available ()
41+ if _torch_distributed_available :
42+ from torch .distributed .tensor import DTensor
4143
4244if TYPE_CHECKING :
4345 from .modeling_utils import LoadStateDictConfig , PreTrainedModel
4446 from .quantizers import HfQuantizer
45- elif _torch_distributed_available :
46- from torch .distributed .tensor import DTensor
4747
4848logger = get_logger (__name__ )
4949
@@ -602,6 +602,7 @@ class WeightTransform:
602602 "_original_target_patterns" ,
603603 "_was_used" ,
604604 "scope_prefix" ,
605+ "base_model_prefix" ,
605606 )
606607
607608 def __init__ (self , source_patterns : str | list [str ], target_patterns : str | list [str ]):
@@ -619,9 +620,11 @@ def __init__(self, source_patterns: str | list[str], target_patterns: str | list
619620
620621 # Flag to notice if the Transform was used
621622 self ._was_used = False
622- # Optional prefix scope: when set, this transform only applies to keys starting with
623- # `scope_prefix + "."`, stripping / re-attaching the prefix around the pattern match.
623+
624+ # Optional scope_prefix/base_model_prefix. When used, the transform will only match and apply to keys containing
625+ # either `base_model_prefix.scope_prefix.` or `scope_prefix.` prefixes
624626 self .scope_prefix : str | None = None
627+ self .base_model_prefix : str | None = None
625628
626629 # We need to process a few exceptions here when instantiating the reverse mapping (i.e. the targets become
627630 # sources, and sources become targets). The issues lie in the sources usually, so here we need to check the
@@ -689,23 +692,34 @@ def add_tensor(self, target_key: str, source_key: str, source_pattern: str, futu
689692
690693 def _scoped_match (self , source_key : str ) -> tuple [str | None , str , re .Match [str ]] | None :
691694 """
692- Apply `scope_prefix` stripping (if any), then match `compiled_sources` against the suffix.
695+ Strip `scope_prefix` (if any) from `source_key`, then match `compiled_sources` against the
696+ remaining suffix.
693697
694- Returns `(prefix_dot, key_to_match, match_object)` when a branch matches, where `prefix_dot` is `None`
695- if `scope_prefix` is unset, else `f"{scope_prefix}."`. Returns `None` when out of scope or unmatched.
698+ Returns `(prefix_dot, key_to_match, match_object)` on match, else `None`. `prefix_dot` is
699+ the prefix consumed from `source_key`: either `f"{scope_prefix}."` or that same string with
700+ one `base_model_prefix` level stripped or prepended when the former didn't match.
701+ `None` when `scope_prefix` is unset.
696702 """
697- prefix_dot = None
698703 key_to_match = source_key
704+ prefix = None
699705 if self .scope_prefix is not None :
700- prefix_dot = self .scope_prefix + "."
701- if not source_key .startswith (prefix_dot ):
706+ scope_prefix = f"{ self .scope_prefix } ." if self .scope_prefix != "" else ""
707+ base_model_prefix = f"{ self .base_model_prefix } ." if self .base_model_prefix != "" else ""
708+ # First, try to match the longest sequence, i.e. base_model_prefix + scope_prefix
709+ if source_key .startswith (base_model_prefix + scope_prefix ):
710+ prefix = base_model_prefix + scope_prefix
711+ # Then, try to strip the base_model_prefix, in case we load a ForXXX model from BaseModel weights
712+ elif source_key .startswith (scope_prefix ):
713+ prefix = scope_prefix
714+ # In this case, no match is ever possible
715+ else :
702716 return None
703- key_to_match = source_key [ len ( prefix_dot ) :]
717+ key_to_match = source_key . removeprefix ( prefix )
704718
705719 match_object = self .compiled_sources .search (key_to_match )
706720 if match_object is None :
707721 return None
708- return (prefix_dot , key_to_match , match_object )
722+ return (prefix , key_to_match , match_object )
709723
710724 def rename_source_key (self , source_key : str ) -> tuple [str , str | None ]:
711725 """
@@ -762,6 +776,7 @@ def reverse_transform(self) -> WeightTransform:
762776 ** kwargs ,
763777 )
764778 reverse_transform .scope_prefix = self .scope_prefix
779+ reverse_transform .base_model_prefix = self .base_model_prefix
765780 return reverse_transform
766781
767782 def materialize_tensors (self ) -> dict [str , list [torch .Tensor ]]:
@@ -784,7 +799,9 @@ def materialize_tensors(self) -> dict[str, list[torch.Tensor]]:
784799 tensors = [future .result () for future in tensors if future .result () is not None ]
785800 # Sync loading
786801 elif callable (tensors [0 ]):
787- tensors = [tensor for func in tensors if (tensor := func ()) is not None ]
802+ tensors = [func () for func in tensors ]
803+ # Some may be None for some distributed setups
804+ tensors = [tensor for tensor in tensors if tensor is not None ]
788805 # Add them to the new dictionary
789806 collected_tensors [key ] = tensors
790807
@@ -884,6 +901,7 @@ def reverse_transform(self) -> WeightTransform:
884901 prefix_to_add = self .prefix_to_remove , prefix_to_remove = self .prefix_to_add , model_prefix = self .model_prefix
885902 )
886903 result .scope_prefix = self .scope_prefix
904+ result .base_model_prefix = self .base_model_prefix
887905 return result
888906
889907
@@ -1003,9 +1021,10 @@ def _job():
10031021
10041022 if thread_pool is not None :
10051023 return thread_pool .submit (_job )
1006- # Return the Callable here, not the Tensor itself, so we actually delay loading
1007- # to avoid saturating cpu memory during Conversion
1008- return _job
1024+ else :
1025+ # Return the Callable here, not the Tensor itself, so we actually delay loading to avoid saturating cpu
1026+ # memory during Conversion
1027+ return _job
10091028
10101029
10111030def dot_natural_key (s : str ):
@@ -1142,7 +1161,7 @@ def rename_source_key(
11421161 source_key : str ,
11431162 weight_renamings : list [WeightRenaming ],
11441163 weight_converters : list [WeightConverter ],
1145- prefix : str | None = None ,
1164+ base_model_prefix : str | None = None ,
11461165 meta_state_dict : dict | None = None ,
11471166) -> tuple [str , str | None ]:
11481167 """
@@ -1160,10 +1179,10 @@ def rename_source_key(
11601179 Applied in order; every matching renaming fires (they may chain).
11611180 weight_converters (`list[WeightConverter]`):
11621181 Applied after all renamings; at most one may match. Subsequent converters are skipped.
1163- prefix (`str`, *optional*):
1164- Base-model prefix to add or strip when both `prefix ` and `meta_state_dict` are given.
1182+ base_model_prefix (`str`, *optional*):
1183+ Base-model prefix to add or strip when both `base_model_prefix ` and `meta_state_dict` are given.
11651184 meta_state_dict (`dict`, *optional*):
1166- Meta state dict used to decide whether `prefix ` should be added or stripped.
1185+ Meta state dict used to decide whether `base_model_prefix ` should be added or stripped.
11671186
11681187 Returns:
11691188 `tuple[str, str | None]`: The renamed key and the matched converter's source pattern
@@ -1183,15 +1202,15 @@ def rename_source_key(
11831202 if source_pattern is not None :
11841203 break
11851204
1186- # 3. check if we need to add or remove prefix if necessary (only during loading, not saving)
1187- if prefix is not None and meta_state_dict is not None :
1205+ # 3. check if we need to add or remove base_model_prefix if necessary (only during loading, not saving)
1206+ if base_model_prefix is not None and meta_state_dict is not None :
11881207 if (
1189- renamed_key .startswith (prefix )
1190- and meta_state_dict .get (re .sub (f"^{ prefix } ." , "" , renamed_key , count = 1 )) is not None
1208+ renamed_key .startswith (base_model_prefix )
1209+ and meta_state_dict .get (re .sub (f"^{ base_model_prefix } ." , "" , renamed_key , count = 1 )) is not None
11911210 ):
1192- renamed_key = re .sub (f"^{ prefix } ." , "" , renamed_key , count = 1 )
1193- elif meta_state_dict .get (f"{ prefix } .{ renamed_key } " ) is not None :
1194- renamed_key = f"{ prefix } .{ renamed_key } "
1211+ renamed_key = re .sub (f"^{ base_model_prefix } ." , "" , renamed_key , count = 1 )
1212+ elif meta_state_dict .get (f"{ base_model_prefix } .{ renamed_key } " ) is not None :
1213+ renamed_key = f"{ base_model_prefix } .{ renamed_key } "
11951214
11961215 return renamed_key , source_pattern
11971216
@@ -1289,23 +1308,11 @@ def convert_and_load_state_dict_in_model(
12891308 ```
12901309
12911310 """
1292- prefix = model .base_model_prefix
1311+ base_model_prefix = model .base_model_prefix
12931312 tp_plan = tp_plan or {}
1313+ device_map = load_config .device_map or {"" : "cpu" }
12941314 hf_quantizer = load_config .hf_quantizer
12951315 dtype = load_config .dtype
1296- device_mesh = load_config .device_mesh
1297-
1298- if load_config .device_map is not None :
1299- device_map = load_config .device_map
1300- elif device_mesh is not None :
1301- if device_mesh .device_type == "cpu" :
1302- device_map = {"" : torch .device ("cpu" )}
1303- else :
1304- device_map = {
1305- "" : torch .device (device_mesh .device_type , getattr (torch , device_mesh .device_type ).current_device ())
1306- }
1307- else :
1308- device_map = {"" : "cpu" }
13091316 disk_offload_folder = load_config .disk_offload_folder
13101317 offload_buffers = load_config .offload_buffers
13111318 dtype_plan = load_config .dtype_plan or {}
@@ -1349,12 +1356,12 @@ def convert_and_load_state_dict_in_model(
13491356 for original_key , tensor in state_dict :
13501357 # 1. Rename the key according to all renaming and weight conversion patterns.
13511358 renamed_key , source_pattern = rename_source_key (
1352- original_key , renamings , converters , prefix = prefix , meta_state_dict = meta_model_state_dict
1359+ original_key , renamings , converters , base_model_prefix , meta_model_state_dict
13531360 )
13541361 if renamed_key not in meta_model_state_dict and original_key in meta_model_state_dict :
13551362 # Key should probably not have been renamed but we might need the `prefix` to be added.
13561363 renamed_key , source_pattern = rename_source_key (
1357- original_key , [], [], prefix = prefix , meta_state_dict = meta_model_state_dict
1364+ original_key , [], [], base_model_prefix = base_model_prefix , meta_state_dict = meta_model_state_dict
13581365 )
13591366
13601367 # 2. finally, collect the tensor into the proper converter
0 commit comments