Skip to content

Commit 401cf5a

Browse files
authored
Merge branch 'main' into alm-base-model-class
2 parents 157f7a2 + 08692e3 commit 401cf5a

29 files changed

Lines changed: 429 additions & 121 deletions

.github/dependabot.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
version: 2
2+
updates:
3+
- package-ecosystem: "github-actions"
4+
directory: "/"
5+
schedule:
6+
interval: "weekly"
7+
cooldown:
8+
default-days: 7
9+
groups:
10+
actions:
11+
patterns: ["*"]

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ def run(self):
325325

326326
setup(
327327
name="transformers",
328-
version="5.8.0.dev0", # expected format is one of x.y.z.dev0, or x.y.z.rc1 or x.y.z (no to dashes, yes to dots)
328+
version="5.10.0.dev0", # expected format is one of x.y.z.dev0, or x.y.z.rc1 or x.y.z (no to dashes, yes to dots)
329329
author="The Hugging Face team (past and future) with the help of all our contributors (https://github.com/huggingface/transformers/graphs/contributors)",
330330
author_email="transformers@huggingface.co",
331331
description="Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and multimodal models, for both inference and training.",

src/transformers/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
# to defer the actual importing for when the objects are requested. This way `import transformers` provides the names
1919
# in the namespace without actually importing anything (and especially none of the backends).
2020

21-
__version__ = "5.8.0.dev0"
21+
__version__ = "5.10.0.dev0"
2222

2323
import importlib
2424
import sys

src/transformers/conversion_mapping.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1174,9 +1174,14 @@ def get_model_conversion_mapping(
11741174

11751175
is_root_model = module_name == ""
11761176
if not is_root_model:
1177-
# Scope each transform so it only matches keys under this sub-module's prefix.
1177+
# Scope each transform so it only matches keys under this sub-module's prefix - but we still allow to
1178+
# arbitrary add/remove base_model_prefix to load ForXXX model from BaseModel and the opposite
1179+
# Note that we need 2 removeprefix calls here, as only one level of nesting would not have the ending dot to module_name
1180+
scope_prefix = module_name.removeprefix(model.base_model_prefix)
1181+
scope_prefix = module_name.removeprefix(".")
11781182
for transform in conversions:
1179-
transform.scope_prefix = module_name
1183+
transform.scope_prefix = scope_prefix
1184+
transform.base_model_prefix = model.base_model_prefix
11801185
weight_conversions.extend(conversions)
11811186

11821187
seen_identifiers[class_name].append(module_name)

src/transformers/core_model_loading.py

Lines changed: 50 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,12 @@
3838

3939

4040
_torch_distributed_available = torch.distributed.is_available()
41+
if _torch_distributed_available:
42+
from torch.distributed.tensor import DTensor
4143

4244
if 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

4848
logger = 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

10111030
def 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

src/transformers/integrations/accelerate.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,9 @@ def accelerate_disk_offload(
469469

470470
# Update the weight names according to the `weight_mapping`
471471
weight_renaming_map = {
472-
rename_source_key(k, renamings, [], prefix=model.base_model_prefix, meta_state_dict=meta_state_dict)[0]: k
472+
rename_source_key(
473+
k, renamings, [], base_model_prefix=model.base_model_prefix, meta_state_dict=meta_state_dict
474+
)[0]: k
473475
for k in weight_map
474476
}
475477

src/transformers/integrations/deepspeed.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def _apply_weight_conversions_to_state_dict(model, state_dict, weight_mapping):
352352
# Preserve metadata from the original state dict
353353
metadata = getattr(state_dict, "_metadata", None)
354354

355-
prefix = model.base_model_prefix
355+
base_model_prefix = model.base_model_prefix
356356

357357
# Build a meta state dict for matching - only keys/shapes, no actual tensor data
358358
# This minimizes memory since we don't duplicate the model's parameters
@@ -368,7 +368,7 @@ def _apply_weight_conversions_to_state_dict(model, state_dict, weight_mapping):
368368
new_state_dict = {}
369369
for original_key, tensor in state_dict.items():
370370
renamed_key, _ = rename_source_key(
371-
original_key, renamings, [], prefix=prefix, meta_state_dict=model_state_dict
371+
original_key, renamings, [], base_model_prefix=base_model_prefix, meta_state_dict=model_state_dict
372372
)
373373
if renamed_key in model_state_dict:
374374
new_state_dict[renamed_key] = tensor
@@ -389,7 +389,7 @@ def _apply_weight_conversions_to_state_dict(model, state_dict, weight_mapping):
389389
for original_key in sorted_keys:
390390
tensor = state_dict.pop(original_key)
391391
renamed_key, source_pattern = rename_source_key(
392-
original_key, renamings, converters, prefix=prefix, meta_state_dict=model_state_dict
392+
original_key, renamings, converters, base_model_prefix=base_model_prefix, meta_state_dict=model_state_dict
393393
)
394394

395395
# Only process if the renamed key is in the model's state dict

src/transformers/integrations/flash_attention.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@
1212
def get_target_dtype(query: torch.Tensor, module: torch.nn.Module) -> torch.dtype:
1313
"""If the query is in float32, return a target dtype compatible with flash attention. Return None otherwise."""
1414
if query.dtype == torch.float32:
15-
if torch.is_autocast_enabled("cuda"):
16-
return torch.get_autocast_dtype("cuda")
15+
device_type = query.device.type
16+
if torch.is_autocast_enabled(device_type):
17+
return torch.get_autocast_dtype(device_type)
1718
# Handle the case where the model is quantized
1819
elif hasattr(module.config, "_is_quantized"):
1920
return module.config.dtype

src/transformers/modeling_rope_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -719,7 +719,9 @@ def convert_rope_params_to_dict(self, **kwargs):
719719
partial_rotary_factor = kwargs.get("partial_rotary_factor", getattr(self, "partial_rotary_factor", None))
720720
if partial_rotary_factor is not None:
721721
self.rope_parameters.setdefault("partial_rotary_factor", partial_rotary_factor)
722-
self.ignore_keys_at_rope_validation = self.ignore_keys_at_rope_validation | {"partial_rotary_factor"}
722+
self.ignore_keys_at_rope_validation = set(self.ignore_keys_at_rope_validation or []) | {
723+
"partial_rotary_factor"
724+
}
723725

724726
self.standardize_rope_params()
725727
return kwargs

src/transformers/modeling_utils.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4188,6 +4188,12 @@ def from_pretrained(
41884188

41894189
if distributed_config is not None:
41904190
device_mesh = init_device_mesh(distributed_config)
4191+
# When using any distributed setup, we simply set the device_map here to the current rank so that we correctly
4192+
# load the params on the right device
4193+
if device_mesh.device_type == "cpu":
4194+
device_map = {"": torch.device("cpu")}
4195+
else:
4196+
device_map = {"": torch.device(device_mesh.device_type, int(os.environ["LOCAL_RANK"]))}
41914197
else:
41924198
# Accelerate path
41934199
if device_map == "auto" and int(os.environ.get("WORLD_SIZE", "0")):
@@ -4342,10 +4348,9 @@ def from_pretrained(
43424348

43434349
if distributed_config is not None:
43444350
model = distribute_model(model, distributed_config, device_mesh)
4345-
else:
4346-
# Accelerate path: auto device mapping
4347-
if device_map is not None:
4348-
device_map = _get_device_map(model, device_map, max_memory, hf_quantizer)
4351+
elif device_map is not None:
4352+
# Expand device_map if it was passed as a `str`, i.e. `device_map="auto"`
4353+
device_map = _get_device_map(model, device_map, max_memory, hf_quantizer)
43494354

43504355
# Finalize model weight initialization
43514356
active_tp_plan = (
@@ -4907,7 +4912,7 @@ def mark_tied_weights_as_initialized(self, loading_info):
49074912
later as they will be tied (overwritten) anyway.
49084913
This is very important as most embeddings are tied, and they are huge params (vocabularies are often 256k), so
49094914
running inits on them is very costly."""
4910-
for tied_param in self.all_tied_weights_keys.keys():
4915+
for tied_param in getattr(self, "all_tied_weights_keys", {}).keys():
49114916
param = self.get_parameter(tied_param)
49124917
setattr(param, "_is_hf_initialized", True)
49134918

@@ -5041,7 +5046,7 @@ def get_total_byte_count(
50415046

50425047
total_byte_count = defaultdict(lambda: 0)
50435048
tied_param_names = model.all_tied_weights_keys.keys()
5044-
tp_plan = model._tp_plan if _is_torch_distributed_initialized() else []
5049+
tp_plan = model.tp_plan if _is_torch_distributed_initialized() else []
50455050

50465051
for param_name, device in accelerator_device_map.items():
50475052
# Skip if the parameter has already been accounted for (tied weights)

0 commit comments

Comments
 (0)