Coverage for / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / platform / mindspore / fully_shard / scheduler.py: 84%
139 statements
« prev ^ index » next coverage.py v7.13.1, created at 2026-08-25 04:27 +0800
« prev ^ index » next coverage.py v7.13.1, created at 2026-08-25 04:27 +0800
1# Copyright 2026 Huawei Technologies Co., Ltd
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ============================================================================
15"""MindSpore HSDP scheduler"""
16from typing import List
17import mindspore as ms
18from mindspore._c_expression import _DisableMsDispatchMode
19from mindspore.common.api import _pynative_executor
20from mindspore.utils._pytree import tree_flatten, tree_unflatten
21from hyper_parallel.tools.logging import get_logger
22from hyper_parallel.core.fully_shard.hsdp_scheduler import HSDPSchedulerV2, FSDPSchedulerState
23from hyper_parallel.platform.mindspore.fully_shard.hook_function import PostBackwardFunction
24from hyper_parallel.platform.mindspore.fully_shard.state import MindSporeHSDPStateV2
25from hyper_parallel.platform import get_platform
27logger = get_logger("FSDP")
30class MindSporeHSDPSchedulerV2(HSDPSchedulerV2):
31 """MindSpore HSDP scheduler.
33 List-unit grouped forward hooks use :class:`HSDPSchedulerV2` defaults for
34 ``_grouped_forward_pre_hook_skip`` / ``_grouped_forward_post_hook_skip`` (no overrides here).
35 """
36 def zero_grad(self) -> None:
37 """Zero grad."""
38 self.hsdp_state.zero_grad()
40 def _register_hooks(self):
41 """Register hooks."""
42 self._register_forward_backward_hooks()
44 def _init_platform(self):
45 """Initialize the platform."""
46 from hyper_parallel.platform.mindspore.platform import MindSporePlatform
47 self.platform = get_platform()
48 if not isinstance(self.platform, MindSporePlatform):
49 raise ValueError(f"MindSporeHSDPSchedulerV2 expect MindSporePlatform, but got type: {type(self.platform)}")
51 def _new_cell_state(self):
52 """Create a new cell state for mindspore."""
53 self.hsdp_state = MindSporeHSDPStateV2(
54 self.modules,
55 self.mesh,
56 self.shard_placement_fn,
57 self.comm_fusion_policy,
58 self.mp_policy,
59 self.offload_policy,
60 self.ignored_params,
61 self.replicate_params,
62 self.platform,
63 self.scheduler_ctx,
64 self.device,
65 )
67 def _register_post_backward_hook(self, args, kwargs):
68 """Wrap forward args/kwargs through PostBackwardFunction to register backward hook."""
69 if not _pynative_executor.enable_grad():
70 return args, kwargs
71 args_list, args_spec = tree_flatten(args)
72 kwargs_list, kwargs_spec = tree_flatten(kwargs)
73 args_kwargs_list = list(args_list) + list(kwargs_list)
74 inp_tensor_indices: List[int] = []
75 inp_tensors: List[ms.Tensor] = []
76 for i, obj in enumerate(args_kwargs_list):
77 if isinstance(obj, ms.Tensor) and obj.requires_grad:
78 inp_tensor_indices.append(i)
79 inp_tensors.append(obj)
80 if len(inp_tensors) == 0:
81 return args, kwargs # no tensors that require gradients
82 processed_tensors = PostBackwardFunction.apply(self, *inp_tensors)
83 for inp_tensor_idx, processed_tensor in zip(inp_tensor_indices, processed_tensors):
84 args_kwargs_list[inp_tensor_idx] = processed_tensor
85 args_list = args_kwargs_list[: len(args_list)]
86 kwargs_list = args_kwargs_list[len(args_list):]
87 args = tree_unflatten(args_spec, args_list)
88 kwargs = tree_unflatten(kwargs_spec, kwargs_list)
89 return args, kwargs
91 def _forward_pre_hook(self, cell, args, kwargs):
92 """Execute forward pre hook and set up backward hook."""
93 args, kwargs = self._hsdp_forward_pre_hook(cell, args, kwargs)
94 return self._register_post_backward_hook(args, kwargs)
96 def _register_backward_pre_hook(self, outputs):
97 """Register output hook to trigger backward pre hook."""
98 flat_outputs, _ = tree_flatten(outputs)
99 for output in flat_outputs:
100 if isinstance(output, ms.Tensor) and output._requires_grad:
101 output.register_hook(self._backward_pre_hook)
102 return outputs
104 def _forward_hook(self, cell, inputs, outputs):
105 """Execute forward hook."""
106 if self.scheduler_state == FSDPSchedulerState.PRE_BACKWARD:
107 return
108 self._register_backward_pre_hook(outputs)
109 if self.scheduler_ctx.root_bp_state:
110 self._restore_forward_prefetch_after_recompute()
111 return
112 return self._hsdp_forward_hook(cell, inputs, outputs)
114 # pylint: disable=W0212
115 def _backward_pre_hook(self, grad):
116 """Execute backward pre hook."""
117 if self.scheduler_state == FSDPSchedulerState.PRE_BACKWARD:
118 return grad
119 if self._is_root:
120 _pynative_executor.queue_backward_final_callback(self._root_backward_hook)
121 self.scheduler_ctx.root_bp_state = True
122 self._hsdp_backward_pre_hook(self.cell, None)
123 return grad
125 def _root_backward_hook(self):
126 """Drain all DP pipelines, then run final TP reduction and apply gradients."""
127 logger.debug("hook=root_backward_hook enter module=%s", self.hsdp_state)
128 for hsdp_scheduler in self.scheduler_ctx.all_hsdp_schedulers:
129 hsdp_scheduler._backward_hook()
130 self.scheduler_ctx.root_bp_state = False
131 logger.debug(
132 "hook=root_backward_hook action=final_reduce module=%s",
133 self.hsdp_state,
134 )
135 self._finalize_comm_fusion_reductions()
136 self._finalize_per_param_reductions()
137 self.launch_tp_replicate_reduce_and_apply()
139 def _finalize_comm_fusion_reductions(self) -> None:
140 """Drain the comm_fusion=True reduce-scatter/all-reduce pipeline."""
141 comm_ctx = self.scheduler_ctx.param_group_comm_ctx
142 if comm_ctx.all_reduce_param_group is not None:
143 logger.debug(
144 "hook=root_backward_hook wait=comm_fusion_all_reduce module=%s",
145 self.hsdp_state,
146 )
147 comm_ctx.all_reduce_param_group.wait_all_reduce_and_save_grad()
148 comm_ctx.all_reduce_param_group = None
149 if comm_ctx.pre_param_group is not None:
150 logger.debug(
151 "hook=root_backward_hook wait=comm_fusion_reduce_scatter module=%s",
152 self.hsdp_state,
153 )
154 comm_ctx.pre_param_group.wait_reduce_scatter_and_issue_all_reduce()
155 comm_ctx.pre_param_group = None
156 if comm_ctx.all_reduce_param_group is not None:
157 comm_ctx.all_reduce_param_group.wait_all_reduce_and_save_grad()
158 comm_ctx.all_reduce_param_group = None
160 def _finalize_per_param_reductions(self) -> None:
161 """Drain the module-tree-local comm_fusion=False communication queues."""
162 previous_groups = self.hsdp_state._wait_prev_reduce_scatter()
163 self.hsdp_state._wait_prev_reduce_scatter_without_all_reduce()
164 self.hsdp_state._issue_prev_fused_all_reduce(previous_groups)
165 self.hsdp_state.wait_and_split_all_reduce_work_groups()
167 def launch_tp_replicate_reduce_and_apply(self) -> None:
168 """Run final source-layout reductions and apply gradients for all states."""
169 for hsdp_scheduler in self.scheduler_ctx.all_hsdp_schedulers:
170 hsdp_state = hsdp_scheduler.hsdp_state
171 if hsdp_state is None:
172 continue
173 need_synchronize = False
174 for hsdp_param in hsdp_state.hsdp_params:
175 reduced_grad = hsdp_param.all_reduce_comm_ctx.all_reduce_output
176 if reduced_grad is None:
177 reduced_grad = hsdp_param.reduce_scatter_comm_ctx.reduce_scatter_output
178 if reduced_grad is None:
179 continue
180 hsdp_param.all_reduce_tp_replicate_grad_inplace(
181 reduced_grad,
182 hsdp_state.reduce_op_type,
183 )
184 need_synchronize = hsdp_param.apply_reduced_grad(reduced_grad) or need_synchronize
185 hsdp_param.clear_all_reduce_output()
186 hsdp_param.clear_reduce_scatter_output()
187 hsdp_state._sync_current_stream_if_needed(need_synchronize)
189 def reset_iter_state(self) -> None:
190 """Reset MindSpore fully_shard iteration state after communication completes."""
191 super().reset_iter_state()
192 self.hsdp_state.reset_iter_state()
193 comm_ctx = self.scheduler_ctx.param_group_comm_ctx
194 comm_ctx.pre_param_group = None
195 comm_ctx.all_reduce_param_group = None
197 def _backward_hook(self):
198 """Execute backward hook."""
199 if self.scheduler_state == FSDPSchedulerState.BACKWARD:
200 return
201 self._hsdp_backward_hook(self.cell, None, None)
203 @staticmethod
204 def _without_ms_dispatch_mode(hook):
205 """Run HSDP hook internals outside any outer MsDispatchMode."""
206 def wrapped_hook(*args, **kwargs):
207 with _DisableMsDispatchMode():
208 return hook(*args, **kwargs)
209 return wrapped_hook
211 def _register_forward_backward_hooks(self):
212 """Register module forward and backward hook on all managed modules."""
213 if self._fsdp_group_post_pending is None:
214 for mod in self.modules:
215 mod.register_forward_pre_hook(
216 self._without_ms_dispatch_mode(self._forward_pre_hook),
217 with_kwargs=True,
218 )
219 mod.register_forward_hook(self._without_ms_dispatch_mode(self._forward_hook))
220 return
221 for mod in self.modules:
222 mod.register_forward_pre_hook(
223 self._without_ms_dispatch_mode(self._grouped_forward_pre_hook),
224 with_kwargs=True,
225 )
226 mod.register_forward_hook(
227 self._without_ms_dispatch_mode(self._make_grouped_forward_post_hook(mod))
228 )