Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
7c84339
init
3outeille Mar 25, 2026
69bc48e
Merge branch 'main' into distributed_api
3outeille Mar 25, 2026
b7ec958
Merge branch 'main' into distributed_api
3outeille Apr 13, 2026
45a01a5
Merge remote-tracking branch 'origin/main' into distributed_api
3outeille Apr 13, 2026
a5c2554
FSDP2 (fully_shard) integration
3outeille Apr 13, 2026
739332c
DistributedConfig + shard-on-read loading
3outeille Apr 13, 2026
11b55a2
TPStyle API + dense model tensor parallelism
3outeille Apr 13, 2026
eeefc9e
Merge branch 'main' into distributed_api
3outeille Apr 13, 2026
9038475
Merge branch 'distributed_api' into fsdp-vs-ddp
3outeille Apr 13, 2026
abfd57e
revert some files
3outeille Apr 13, 2026
23a2c05
Merge branch 'fsdp-vs-ddp' of https://github.com/huggingface/transfor…
3outeille Apr 13, 2026
c33873e
Add distributed training scripts
3outeille Apr 13, 2026
e783231
Merge branch 'distributed_api' of https://github.com/huggingface/tran…
3outeille Apr 13, 2026
34db840
Remove train_fsdp_tp_torchtitan_style.py
3outeille Apr 13, 2026
6f9e2b6
unify the utils for fsdp
3outeille Apr 13, 2026
5e017cf
Merge branch 'distributed_api' into fsdp-vs-ddp
3outeille Apr 14, 2026
37dcc14
Fix CI: re-export moved FSDP utils + remove stale type: ignore
3outeille Apr 14, 2026
c1dab9e
Merge branch 'fsdp-vs-ddp' into fsdp-core-model-loading
3outeille Apr 14, 2026
e0c4e06
Merge branch 'fsdp-core-model-loading' into refactor-tp-dtensor
3outeille Apr 14, 2026
21f0561
Fix ruff formatting in core_model_loading.py
3outeille Apr 14, 2026
cd45107
Fix ruff linting and formatting
3outeille Apr 14, 2026
52c390f
Merge branch 'fsdp-core-model-loading' into refactor-tp-dtensor
3outeille Apr 14, 2026
ba3990f
Backport new TP/FSDP API from orchestration-save-load branch
3outeille Apr 14, 2026
92a3491
Fix DTensor imports in Copied-from model files
3outeille Apr 14, 2026
7ca7911
MoE expert parallelism + sequence parallelism (#45408)
3outeille Apr 14, 2026
d4400d5
do monkey patching for rotary
3outeille Apr 14, 2026
6793503
Revert modeling file diffs to match fsdp-core-model-loading base
3outeille Apr 14, 2026
b943512
Migrate all model TP plans from strings to TPStyle
3outeille Apr 14, 2026
5ce6faa
Restore mxfp4.py to match base branch
3outeille Apr 14, 2026
b694f36
Drop mla_kv_a_proj and moe_identity_expert from TP plans
3outeille Apr 14, 2026
1b82460
more comments
3outeille Apr 15, 2026
48f8d6f
fix tp for most models. PyTorch doesn't implement all placement conv…
3outeille Apr 15, 2026
91b4824
fix tp through _replicate_dtensor
3outeille Apr 16, 2026
44706eb
revert small change
3outeille Apr 16, 2026
aa45f5b
push temporary fix for TP and strided shard for backward
3outeille Apr 16, 2026
0a566c5
refactor a bit
3outeille Apr 16, 2026
11a55d4
patches for rotary
3outeille Apr 16, 2026
53490d9
refactor MoEExpertsParallel
3outeille Apr 16, 2026
0c09915
fix tp for last models
3outeille Apr 18, 2026
ebd03ec
refactor moe expert parallels
3outeille Apr 18, 2026
c08c071
linting
3outeille Apr 18, 2026
4804d0d
add sp plan for models
3outeille Apr 18, 2026
1a51928
add deepseek v2 sp plan
3outeille Apr 18, 2026
fd3a722
undo sp plan for some tricky models
3outeille Apr 18, 2026
253b89e
remove lm_head from config
3outeille Apr 20, 2026
3ff1fee
first pass of refactoring dtensor shard operator
3outeille Apr 20, 2026
4d96b2d
better refacto
3outeille Apr 20, 2026
04521bf
batter explanation of DtensorShardOperation
3outeille Apr 22, 2026
f710f0d
refactor dtensor test to reflect real world scenario
3outeille Apr 22, 2026
a35993c
more comments
3outeille Apr 22, 2026
8529d7c
fix tp olmo hybrid and exaone
3outeille Apr 22, 2026
43b792b
Enhance tensor parallel weight tying logic to prevent clobbering of l…
3outeille Apr 22, 2026
0dbef90
fix fsdp mixin test due to missing args
3outeille Apr 28, 2026
da83f32
fix test non model
3outeille Apr 28, 2026
3903757
skip sp plan for exaone and olmo hybrid
3outeille Apr 28, 2026
e51f663
linting
3outeille Apr 28, 2026
96f3f29
fix import for ci
3outeille Apr 28, 2026
dfb448e
test distributed config
3outeille Apr 28, 2026
0a74b7d
attempt to fix guarding import ci
3outeille Apr 28, 2026
c50e49c
fix ci check repro
3outeille Apr 28, 2026
f9daf7b
add ALL_PARALLEL_STYLES registry alongside TPStyle
3outeille Apr 28, 2026
8a1a9e5
route apply_tensor_parallel through ALL_PARALLEL_STYLES
3outeille Apr 28, 2026
7819783
migrate modular files to string-based TP plans
3outeille Apr 28, 2026
e70ac37
migrate standalone configs and modelings to string-based TP plans
3outeille Apr 28, 2026
061d4e6
delete TPStyle dataclass
3outeille Apr 28, 2026
8e0f60c
fix use_local_output defaults for SequenceParallel and PrepareModuleI…
3outeille Apr 28, 2026
5b336bd
use parallel style from torch
3outeille Apr 30, 2026
465d029
revert changes in weight converter
3outeille May 1, 2026
bc6d6f9
remove dead code in set_param_for_module
3outeille May 1, 2026
f305f92
remove dead code
3outeille May 1, 2026
39db8c1
cleaning again
3outeille May 1, 2026
951d4ae
cleaning
3outeille May 1, 2026
1b040ef
revert change
3outeille May 1, 2026
85ef27c
linting
3outeille May 1, 2026
1fd7b1d
refactor dtensor shard ops
3outeille May 4, 2026
4547eb3
revert some stuff in core model loading
3outeille May 4, 2026
43086d3
core model loading clean
3outeille May 5, 2026
1b7ebe1
guarding import
3outeille May 10, 2026
6d86746
better separation tensor parall and generic utils
3outeille May 10, 2026
ff49346
isolate DtensorShardOperation into a separate file
3outeille May 10, 2026
a806b3d
no need to patch rotary
3outeille May 10, 2026
98d2dc5
better seperation
3outeille May 11, 2026
14e02aa
simplify gather_full_state_dict
3outeille May 11, 2026
9acf944
simplify _replicate_dtensor
3outeille May 11, 2026
20cf4e8
fix and clean _replicate_dtensor
3outeille May 11, 2026
ca6d06b
better doc for DtensorShardOperation
3outeille May 11, 2026
7e2115f
fix saving optimizer with DCP for fused weights
3outeille May 12, 2026
1c6f848
save_pretrained(distributed_checkpoint=true)
3outeille May 13, 2026
41bc6eb
linting
3outeille May 13, 2026
27fc8a9
refactor into a single function _dtensor_from_local_like
3outeille May 13, 2026
1e25f1f
zeros_like instead of empty_like
3outeille May 13, 2026
7405892
move tp and fsdp under distributed
3outeille May 13, 2026
ed45c91
distribute_model
3outeille May 13, 2026
f97c3a4
fix deadlock when saving
3outeille May 13, 2026
b59c4bf
clip grad norm function
3outeille May 13, 2026
242e814
maybe_disable_foreach_and_fused_for_mixed_dtensor_groups
3outeille May 13, 2026
8fe831f
better TP api for ease of understanding
3outeille May 14, 2026
bf30f0a
remove shard_param to make it easier
3outeille May 14, 2026
261c59b
fix import in test
3outeille May 14, 2026
f0f5f67
_swap_dtensor_params_for_local
3outeille May 14, 2026
c135d0e
fix qwen3 nanochat dots1
3outeille May 14, 2026
10c6563
Merge branch 'main' into fsdp-vs-ddp
3outeille May 14, 2026
5db32b8
Merge branch 'fsdp-vs-ddp' into refactor-tp-dtensor
3outeille May 14, 2026
920ade5
add tpu
3outeille May 14, 2026
13646c8
move TP refactor experimentation scripts to backup branch
3outeille May 14, 2026
c49e9ab
linting
3outeille May 14, 2026
a4c6ba8
register distributed sharding_utils and utils in __init__
3outeille May 14, 2026
65b0311
rename TP plan styles to match new ALL_PARALLEL_STYLES registry
3outeille May 14, 2026
dbf0c60
enable EP
3outeille May 14, 2026
51068ca
Add enable_expert_parallel configuration option in test_distributed_c…
3outeille May 14, 2026
bf0696f
no more auto mode
3outeille May 16, 2026
d13ab2e
edit fsdp plan to every other models
3outeille May 16, 2026
4165209
update fsdp mixin tests
3outeille May 16, 2026
6f5dbfb
linting
3outeille May 17, 2026
d075668
fix test fsdp
3outeille May 18, 2026
9472436
fsdp linting
3outeille May 18, 2026
9a835eb
revert gitignore
3outeille May 19, 2026
86dc7b4
_apply within for loop
3outeille May 19, 2026
9378ccb
rename
3outeille May 19, 2026
e878594
doc sp plan
3outeille May 19, 2026
8caa870
fix
3outeille May 19, 2026
e0e787b
unified settattr + torch no grad + _local_tensor
3outeille May 19, 2026
9158d99
revert
3outeille May 19, 2026
1c8203a
linting
3outeille May 19, 2026
7fb37af
Merge branch 'main' into refactor-tp-dtensor
3outeille May 19, 2026
0fdc61f
Merge branch 'main' into refactor-tp-dtensor
3outeille May 19, 2026
7e2f686
fix ruff
3outeille May 19, 2026
e6484d3
make check-repository-consistency
3outeille May 19, 2026
4b649ed
trigger fsdp mixin test in CI
3outeille May 19, 2026
5d673d3
Merge branch 'main' into refactor-tp-dtensor
3outeille May 19, 2026
6b835cb
fix fsdp ci
3outeille May 19, 2026
a38bc32
Merge branch 'refactor-tp-dtensor' of https://github.com/huggingface/…
3outeille May 19, 2026
d563a9c
Reset tests/test_modeling_common.py to main
3outeille May 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion .circleci/create_circleci_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,15 @@ def job_name(self):
parallelism=6,
)

fsdp_ci_job = CircleCIJob(
"fsdp_ci",
additional_env={"RUN_FSDP_TESTS": True},
docker_image=[{"image": "huggingface/transformers-torch-light"}],
install_steps=["uv pip install .", "uv pip install torchao"],
marker="is_fsdp_test",
parallelism=6,
)

# We also include a `dummy.py` file in the files to be doc-tested to prevent edge case failure. Otherwise, the pytest
# hangs forever during test collection while showing `collecting 0 items / 21 errors`. (To see this, we have to remove
# the bash output redirection.)
Expand Down Expand Up @@ -429,7 +438,8 @@ def job_name(self):
DOC_TESTS = [doc_test_job]
TRAINING_CI_TESTS = [training_ci_job]
TENSOR_PARALLEL_CI_TESTS = [tensor_parallel_ci_job]
ALL_TESTS = REGULAR_TESTS + EXAMPLES_TESTS + PIPELINE_TESTS + REPO_UTIL_TESTS + DOC_TESTS + [custom_tokenizers_job] + [exotic_models_job] + TRAINING_CI_TESTS + TENSOR_PARALLEL_CI_TESTS # fmt: skip
FSDP_CI_TESTS = [fsdp_ci_job]
ALL_TESTS = REGULAR_TESTS + EXAMPLES_TESTS + PIPELINE_TESTS + REPO_UTIL_TESTS + DOC_TESTS + [custom_tokenizers_job] + [exotic_models_job] + TRAINING_CI_TESTS + TENSOR_PARALLEL_CI_TESTS + FSDP_CI_TESTS # fmt: skip


def create_circleci_config(folder=None):
Expand Down
1 change: 1 addition & 0 deletions src/transformers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
"debug_utils": [],
"dependency_versions_check": [],
"dependency_versions_table": [],
"distributed": [],
"dynamic_module_utils": [],
"feature_extraction_sequence_utils": ["SequenceFeatureExtractor"],
"feature_extraction_utils": ["BatchFeature", "FeatureExtractionMixin"],
Expand Down
13 changes: 13 additions & 0 deletions src/transformers/configuration_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ class PreTrainedConfig(PushToHubMixin, RotaryEmbeddingConfigMixin):
naming of attributes.
- **base_model_tp_plan** (`dict[str, Any]`) -- A dict that maps sub-modules FQNs of a base model to a tensor
parallel plan applied to the sub-module when `model.tensor_parallel` is called.
- **base_model_sp_plan** (`dict[str, Any]`) -- A dict that maps sub-modules FQNs of a base model to a sequence
parallel plan, used in place of `base_model_tp_plan` when `distributed_config.enable_sequence_parallel` is set.
Same key/value shape as the TP plan; values are style names registered in `ALL_PARALLEL_STYLES`
(e.g. `"vocab_reduce_scatter"`, `"rowwise_reduce_scatter"`, `"activation"`, `"module_allgather"`).
- **base_model_fsdp_plan** (`dict[Any, str]`) -- A dict that maps sub-modules of a base model to an FSDP2
sharding strategy (e.g. `"free_full_weight"` / `"keep_full_weight"`). Keys can be wildcard module paths
Comment thread
3outeille marked this conversation as resolved.
(e.g. `"layers.*"`) or tuples of paths (grouped into a single `fully_shard` call).
- **base_model_pp_plan** (`dict[str, tuple[list[str]]]`) -- A dict that maps child-modules of a base model to a
pipeline parallel plan that enables users to place the child-module on the appropriate device.

Expand Down Expand Up @@ -218,6 +225,8 @@ class PreTrainedConfig(PushToHubMixin, RotaryEmbeddingConfigMixin):
keys_to_ignore_at_inference: ClassVar[list[str]] = []
attribute_map: ClassVar[dict[str, str]] = {}
base_model_tp_plan: ClassVar[dict[str, Any] | None] = None
base_model_sp_plan: ClassVar[dict[str, Any] | None] = None
base_model_fsdp_plan: ClassVar[dict[Any, str] | None] = None
base_model_pp_plan: ClassVar[dict[str, Sequence[list[str]]] | None] = None
base_model_ep_plan: ClassVar[dict[str, Sequence[list[str]]] | None] = None
_auto_class: ClassVar[str | None] = None
Expand Down Expand Up @@ -1018,6 +1027,9 @@ def to_dict(self) -> dict[str, Any]:
# Pop "kwargs" since they are unpacked and set in the post init
output.pop("kwargs", None)

if "distributed_config" in output and hasattr(output["distributed_config"], "to_dict"):
output["distributed_config"] = output["distributed_config"].to_dict()

def to_list(value):
if isinstance(value, tuple):
value = [to_list(item) for item in value]
Expand Down Expand Up @@ -1163,6 +1175,7 @@ def _remove_keys_not_serialized(self, d: dict[str, Any]) -> None:
"_experts_implementation_internal",
"ignore_keys_at_rope_validation",
"base_model_tp_plan",
"base_model_sp_plan",
"base_model_pp_plan",
]:
d.pop(key_to_remove, None)
Expand Down
144 changes: 62 additions & 82 deletions src/transformers/core_model_loading.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@

import torch

from .distributed.sharding_utils import DtensorShardOperation, _dtensor_from_local_like
from .integrations.accelerate import get_device, offload_weight
from .integrations.tensor_parallel import ALL_PARALLEL_STYLES
from .utils import is_env_variable_true
from .utils.loading_report import LoadStateDictInfo
from .utils.logging import get_logger, tqdm
Expand All @@ -40,10 +40,10 @@
_torch_distributed_available = torch.distributed.is_available()

if TYPE_CHECKING:
from .integrations.tensor_parallel import TensorParallelLayer
from .modeling_utils import LoadStateDictConfig, PreTrainedModel
from .quantizers import HfQuantizer

elif _torch_distributed_available:
from torch.distributed.tensor import DTensor

logger = get_logger(__name__)

Expand Down Expand Up @@ -384,7 +384,7 @@ def __init__(self):

def _apply(self, tensor: torch.Tensor) -> torch.Tensor:
dim1, dim2 = tensor.shape
n_heads = self.config.getattr("num_attention_heads", 1)
n_heads = getattr(self.config, "num_attention_heads", 1)

tensor = tensor.view(n_heads, dim1 // n_heads // 2, 2, dim2)
tensor = tensor.transpose(1, 2).reshape(dim1, dim2)
Expand All @@ -400,11 +400,10 @@ def convert(
**kwargs,
) -> dict[str, list[torch.Tensor]]:
self.config = config
output: dict[str, list[torch.Tensor]] = {}
output = {}
for key, tensors in input_dict.items():
if len(tensors) != 1:
raise ValueError("PermuteForRope expects a single tensor per key.")
output[key] = [self._apply(tensors[0])]
tensor = tensors[0] if isinstance(tensors, list) else tensors
output[key] = self._apply(tensor)
return output


Expand Down Expand Up @@ -605,7 +604,7 @@ def __init__(self, source_patterns: str | list[str], target_patterns: str | list
self._original_target_patterns = self.target_patterns.copy()

# Init fields that will be used during conversion
self.distributed_operation: TensorParallelLayer | None = None
self.distributed_operation: Any = None
self.quantization_operation: ConversionOps | None = None
self.collected_tensors: dict[str, list[Future]] = defaultdict(list)
self.layer_targets: dict[str, set[str]] = defaultdict(set)
Expand Down Expand Up @@ -750,7 +749,9 @@ def reverse_transform(self) -> WeightTransform:
kwargs["operations"] = [op.reverse_op for op in self.operations[::-1]]

reverse_transform = self.__class__(
source_patterns=self._original_target_patterns, target_patterns=self._original_source_patterns, **kwargs
source_patterns=self._original_target_patterns,
target_patterns=self._original_source_patterns,
**kwargs,
)
reverse_transform.scope_prefix = self.scope_prefix
return reverse_transform
Expand All @@ -775,7 +776,7 @@ def materialize_tensors(self) -> dict[str, list[torch.Tensor]]:
tensors = [future.result() for future in tensors if future.result() is not None]
# Sync loading
elif callable(tensors[0]):
tensors = [func() for func in tensors]
tensors = [tensor for func in tensors if (tensor := func()) is not None]
# Add them to the new dictionary
collected_tensors[key] = tensors

Expand Down Expand Up @@ -977,36 +978,26 @@ def spawn_materialize(
tensor: torch.Tensor,
device=None,
dtype=None,
sharding_op: DtensorShardOperation | None = None,
tensor_idx: int | None = None,
) -> Future | Callable:
"""Materialize a tensor from file asynchronously if `thread_pool` is provided, or return a Callable that will
load the tensor synchronously when called."""
"""Materialize (and optionally shard) a tensor, asynchronously if a thread pool is provided.

def _job():
return _materialize_copy(tensor, device, dtype)

if thread_pool is not None:
return thread_pool.submit(_job)
else:
# Return the Callable here, not the Tensor itself, so we actually delay loading to avoid saturating cpu
# memory during Conversion
return _job


def spawn_tp_materialize(
thread_pool: ThreadPoolExecutor | None, tensor: torch.Tensor, sharding_method, tensor_idx, device=None, dtype=None
) -> Future | Callable:
"""Materialize and shard a tensor (according to the TP-plan) from file asynchronously if `thread_pool` is provided, or
return a Callable that will load the tensor synchronously when called."""
When ``sharding_op`` is given the tensor is sharded according to the DTensor
placement strategy; otherwise it is simply copied to *device*/*dtype*.
Without a thread pool a deferred callable is returned instead of a Future.
"""

def _job():
return sharding_method.shard_tensor(tensor, tensor_idx=tensor_idx, device=device, dtype=dtype)
if sharding_op is not None:
return sharding_op.shard_tensor(tensor, tensor_idx=tensor_idx, device=device, dtype=dtype)
return _materialize_copy(tensor, device, dtype)

if thread_pool is not None:
return thread_pool.submit(_job)
else:
# Return the Callable here, not the Tensor itself, so we actually delay loading to avoid saturating cpu
# memory during Conversion
return _job
# Return the Callable here, not the Tensor itself, so we actually delay loading
# to avoid saturating cpu memory during Conversion
return _job


def dot_natural_key(s: str):
Expand Down Expand Up @@ -1072,12 +1063,12 @@ def _format_op_name(curr_op: list[ConversionOps] | ConversionOps | None) -> str
raise SkipParameters()


@torch.no_grad()
def set_param_for_module(
model: PreTrainedModel,
target_name: str,
param_value: torch.Tensor,
loading_info: LoadStateDictInfo,
distributed_operation: TensorParallelLayer | None,
hf_quantizer: HfQuantizer,
):
module_path, _, param_name = target_name.rpartition(".")
Expand All @@ -1092,27 +1083,25 @@ def set_param_for_module(
if ref is None:
loading_info.unexpected_keys.add(target_name)
else:
if not isinstance(param_value, torch.nn.Parameter):
if not isinstance(param_value, torch.nn.Parameter) and not isinstance(ref, DTensor):
if param_name not in module_obj._buffers:
param_value = torch.nn.Parameter(param_value, requires_grad=param_value.is_floating_point())

# Remove from missing keys (it's either mismatched, or all good)
loading_info.missing_keys.discard(target_name)

# Determine expected shape: for TP, use sharded shape; otherwise, use full shape
if distributed_operation is not None:
expected_shape = torch.Size(distributed_operation.get_expected_sharded_shape(ref.shape))
else:
expected_shape = ref.shape
expected_shape = ref._local_tensor.shape if isinstance(ref, DTensor) else ref.shape

if ref is not None and param_value.shape != expected_shape and hf_quantizer is None:
loading_info.mismatched_keys.add((target_name, param_value.shape, expected_shape))
else:
if isinstance(ref, DTensor):
local_param = param_value.detach() if isinstance(param_value, torch.nn.Parameter) else param_value
dtensor_param = _dtensor_from_local_like(local_param, ref)
param_value = torch.nn.Parameter(dtensor_param, requires_grad=ref.requires_grad)
# super important otherwise _init_weight will re-init the param
param_value._is_hf_initialized = True
setattr(module_obj, param_name, param_value)
Comment on lines +1101 to +1104

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NICE

if distributed_operation is not None:
distributed_operation.update_module_attributes(module_obj)


def offload_and_maybe_resave_param(
Expand Down Expand Up @@ -1294,10 +1283,21 @@ def convert_and_load_state_dict_in_model(
"""
prefix = model.base_model_prefix
tp_plan = tp_plan or {}
device_map = load_config.device_map or {"": "cpu"}
hf_quantizer = load_config.hf_quantizer
dtype = load_config.dtype
device_mesh = load_config.device_mesh

if load_config.device_map is not None:
device_map = load_config.device_map
elif device_mesh is not None:
if device_mesh.device_type == "cpu":
device_map = {"": torch.device("cpu")}
else:
device_map = {
"": torch.device(device_mesh.device_type, getattr(torch, device_mesh.device_type).current_device())
}
else:
device_map = {"": "cpu"}
Comment on lines +1290 to +1300

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check if can be reverted cuz this should be covered

disk_offload_folder = load_config.disk_offload_folder
offload_buffers = load_config.offload_buffers
dtype_plan = load_config.dtype_plan or {}
Expand Down Expand Up @@ -1332,10 +1332,6 @@ def convert_and_load_state_dict_in_model(
converters = [entry for entry in weight_mapping if isinstance(entry, WeightConverter)]
param_name_to_load: dict[str, WeightRenaming | WeightConverter] = {}

# build '(?P<g0>.*.*\\.block_sparse_moe\\..*)' and group to source {'g0': '*.block_sparse_moe.'}
# and target to source {'g0': '*.mlp.'}. This allows us to quickly find which pattern matched.
if tp_plan != {}:
tp_plan_alt, tp_plan_by_group_name, _ = build_glob_alternation(list(tp_plan.keys()))
if dtype_plan != {}:
dtype_policy_alt, dtype_policy_by_group_name, _ = build_glob_alternation(list(dtype_plan.keys()))

Expand Down Expand Up @@ -1399,32 +1395,23 @@ def convert_and_load_state_dict_in_model(
elif empty_param is not None and empty_param.dtype != _dtype:
_dtype = empty_param.dtype # usually correct when initializing

# 4. Handle TP sharding or device_map placement
future_or_tensor = None
if device_mesh and tp_plan:
if matched_tp_pattern := tp_plan_alt.search(renamed_key):
matched_tp_pattern = tp_plan_by_group_name[matched_tp_pattern.lastgroup]
if getattr(mapping, "distributed_operation", None) is None:
tp_layer = ALL_PARALLEL_STYLES[model.tp_plan[matched_tp_pattern]].__class__
mapping.distributed_operation = tp_layer(
device_mesh=device_mesh, rank=device_mesh.get_local_rank(), empty_param=empty_param.clone()
)
shard_index = (
len(mapping.collected_tensors.get(source_pattern, []))
if isinstance(mapping, WeightConverter) and isinstance(mapping.operations[0], MergeModulelist)
else None
)
future_or_tensor = spawn_tp_materialize(
thread_pool,
tensor,
mapping.distributed_operation,
shard_index,
device_map[""],
_dtype,
)

if future_or_tensor is None:
param_device = get_device(device_map, renamed_key, valid_torch_device=True)
# 4. Materialize tensor — shard-on-read for DTensor params, plain copy otherwise
param_device = get_device(device_map, renamed_key, valid_torch_device=True)
Comment thread
3outeille marked this conversation as resolved.
if isinstance(empty_param, DTensor):
Comment thread
3outeille marked this conversation as resolved.
tensor_idx = (
len(mapping.collected_tensors.get(source_pattern, []))
if isinstance(mapping, WeightConverter) and isinstance(mapping.operations[0], MergeModulelist)
else None
)
future_or_tensor = spawn_materialize(
thread_pool,
tensor,
param_device,
_dtype,
sharding_op=DtensorShardOperation(empty_param),
Comment thread
3outeille marked this conversation as resolved.
tensor_idx=tensor_idx,
)
else:
future_or_tensor = spawn_materialize(thread_pool, tensor, param_device, _dtype)

mapping.add_tensor(renamed_key, original_key, source_pattern, future_or_tensor)
Expand Down Expand Up @@ -1454,14 +1441,7 @@ def convert_and_load_state_dict_in_model(
target_name, param, loading_info, disk_offload_folder, disk_offload_index, mapping
)
else:
set_param_for_module(
model,
target_name,
param,
loading_info,
mapping.distributed_operation,
hf_quantizer,
)
set_param_for_module(model, target_name, param, loading_info, hf_quantizer)

# Cleanup all the tensors that were gathered before next iteration
del realized_value
Expand Down
14 changes: 14 additions & 0 deletions src/transformers/distributed/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,27 @@

_import_structure = {
"configuration_utils": ["DistributedConfig"],
"fsdp": ["is_fsdp_enabled", "is_fsdp_managed_module"],
"sharding_utils": [],
"tensor_parallel": [
"ALL_PARALLEL_STYLES",
"apply_tensor_parallel",
"verify_tp_plan",
],
"utils": [],
}


if TYPE_CHECKING:
from .configuration_utils import (
DistributedConfig,
)
from .fsdp import is_fsdp_enabled, is_fsdp_managed_module
from .tensor_parallel import (
ALL_PARALLEL_STYLES,
apply_tensor_parallel,
verify_tp_plan,
)

else:
import sys
Expand Down
Loading
Loading