Coverage for  / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / platform / platform.py: 66%

434 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-08-21 04:29 +0800

1# Copyright 2025-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"""framework platform api""" 

16# Backend platform modules intentionally import this abstraction to register 

17# their implementations; the resulting import cycle is architectural. 

18# pylint: disable=cyclic-import 

19import os 

20from datetime import timedelta 

21from enum import auto, Enum 

22from typing import Any, Optional, Sequence, Union 

23 

24import numpy as np 

25 

26# Environment variable name used to specify the AI framework platform to use 

27HYPER_PARALLEL_PLATFORM = "HYPER_PARALLEL_PLATFORM" 

28 

29# Identifier for the MindSpore framework 

30HYPER_PARALLEL_PLATFORM_MINDSPORE = "mindspore" 

31 

32# Identifier for the PyTorch framework 

33HYPER_PARALLEL_PLATFORM_TORCH = "torch" 

34 

35 

36class AsyncHandle: 

37 """Idempotent wait handle for an async collective operation. 

38 

39 Wraps the async tensor returned by 

40 :meth:`Platform.differentiable_all_to_all_single_async` and provides a 

41 :meth:`wait` method that is safe to call multiple times. 

42 """ 

43 

44 def __init__(self, async_tensor) -> None: 

45 self._tensor = async_tensor 

46 self._waited = False 

47 

48 def wait(self): 

49 """Wait for the async collective to complete. 

50 

51 Idempotent — the first call blocks until the collective finishes; 

52 subsequent calls are no-ops. 

53 

54 Returns: 

55 The now-materialised result tensor. 

56 """ 

57 if not self._waited: 

58 get_platform().wait_async_tensor(self._tensor) 

59 self._waited = True 

60 return self._tensor 

61 

62 

63class PlatformType(Enum): 

64 """Enumeration class for AI framework platform types. 

65 

66 Used to identify different deep learning framework platform types. 

67 """ 

68 MINDSPORE = auto() 

69 PYTORCH = auto() 

70 

71 

72# Global platform instance, used to cache the created platform object 

73platform = None 

74 

75 

76def get_mindspore_platform(): 

77 """Create and return a MindSpore platform instance. 

78 

79 Returns: 

80 MindSporePlatform: A MindSpore platform instance. 

81 """ 

82 # pylint: disable=C0415 

83 from hyper_parallel.platform.mindspore.platform import MindSporePlatform 

84 global platform 

85 platform = MindSporePlatform() 

86 return platform 

87 

88 

89def get_torch_platform(): 

90 """Create and return a PyTorch platform instance. 

91 

92 Returns: 

93 TorchPlatform: A PyTorch platform instance. 

94 """ 

95 # pylint: disable=C0415 

96 from hyper_parallel.platform.torch.platform import TorchPlatform 

97 global platform 

98 platform = TorchPlatform() 

99 return platform 

100 

101 

102def get_platform(): 

103 """Obtain a framework platform instance. 

104 

105 Returns the appropriate AI framework platform instance based on environment variables or a default priority order. 

106 The lookup priority is as follows: 

107 1. Platform specified by environment variable 

108 2. MindSpore platform (default preferred choice) 

109 3. PyTorch platform (fallback option) 

110 

111 Returns: 

112 Platform: An instance of the framework platform 

113 

114 Raises: 

115 ImportError: Raised when none of the supported frameworks are available 

116 """ 

117 if platform is not None: 

118 return platform 

119 platform_type = os.environ.get(HYPER_PARALLEL_PLATFORM) 

120 if platform_type is not None and isinstance(platform_type, str): 

121 platform_type = platform_type.lower() 

122 if platform_type == HYPER_PARALLEL_PLATFORM_MINDSPORE: 

123 return get_mindspore_platform() 

124 if platform_type == HYPER_PARALLEL_PLATFORM_TORCH: 

125 return get_torch_platform() 

126 try: 

127 return get_mindspore_platform() 

128 except ImportError: 

129 return get_torch_platform() 

130 

131 

132EXISTING_COMM_GROUPS = {} 

133 

134 

135class Platform: 

136 """Platform api""" 

137 current_grad_handle = None 

138 post_grad_handle_process = None 

139 grad_sync_stream = None 

140 

141 @property 

142 def custom_ops(self): 

143 """Return the platform-specific custom ops interface. 

144 

145 Subclasses MUST override this property to return an object that 

146 exposes the platform-specific custom operator implementations. 

147 

148 Returns: 

149 object: Platform-specific custom ops class instance. 

150 """ 

151 raise NotImplementedError( 

152 "Platform subclasses must implement custom_ops" 

153 ) 

154 

155 @staticmethod 

156 def get_swap_optimizer(): 

157 """Return the active backend's optimizer-state swap wrapper class.""" 

158 raise NotImplementedError("Platform subclasses must implement get_swap_optimizer") 

159 

160 @staticmethod 

161 def get_rank(): 

162 """Get the rank of the current process in the default process group. 

163 

164 Returns: 

165 int: The rank of the current process. 

166 """ 

167 raise NotImplementedError("Platform subclasses must implement get_rank") 

168 

169 @staticmethod 

170 def get_global_rank(group, group_rank): 

171 """Convert a group rank to its global rank. 

172 

173 Args: 

174 group: The process group to query. 

175 group_rank (int): The rank within the group. 

176 

177 Returns: 

178 int: The global rank corresponding to the group rank. 

179 """ 

180 raise NotImplementedError("Platform subclasses must implement get_global_rank") 

181 

182 @staticmethod 

183 def get_group_rank(group): 

184 """Return this process's rank within *group*.""" 

185 raise NotImplementedError("Platform subclasses must implement get_group_rank") 

186 

187 @staticmethod 

188 def get_world_size(): 

189 """Get the total number of processes in the default process group. 

190 

191 Returns: 

192 int: The world size (total number of processes). 

193 """ 

194 raise NotImplementedError("Platform subclasses must implement get_world_size") 

195 

196 @staticmethod 

197 def get_op_name(func): 

198 """Get the canonical name of an operator function. 

199 

200 Args: 

201 func: The operator function to query. 

202 

203 Returns: 

204 str: The canonical name of the operator. 

205 """ 

206 raise NotImplementedError("Platform subclasses must implement get_op_name") 

207 

208 @staticmethod 

209 def differentiable_all_gather_concat(data, group, concat_size, concat_dim, rank_list=None): 

210 """Perform differentiable all-gather and concatenate tensors along a dimension. 

211 

212 Args: 

213 data: The input tensor to gather. 

214 group: The process group for collective communication. 

215 concat_size (int): The size to concatenate along concat_dim. 

216 concat_dim (int): The dimension along which to concatenate. 

217 rank_list: Optional rank order expected by the logical layout. 

218 

219 Returns: 

220 The concatenated tensor after all-gather operation. 

221 """ 

222 raise NotImplementedError("Platform subclasses must implement differentiable_all_gather_concat") 

223 

224 @staticmethod 

225 def chunk(data, split_dim, split_size, index): 

226 """Split tensor along a dimension and return the chunk at the given index. 

227 

228 Args: 

229 data: The input tensor to split. 

230 split_dim (int): The dimension along which to split. 

231 split_size (int): The size of each split chunk. 

232 index (int): The index of the chunk to return. 

233 

234 Returns: 

235 The tensor chunk at the specified index. 

236 """ 

237 raise NotImplementedError("Platform subclasses must implement chunk") 

238 

239 @staticmethod 

240 def differentiable_all_to_all(input_data, output_shape, group): 

241 """Perform differentiable all-to-all communication. 

242 

243 Args: 

244 input_data: The input tensor to redistribute. 

245 output_shape: The shape of the output tensor. 

246 group: The process group for collective communication. 

247 

248 Returns: 

249 The output tensor after all-to-all operation. 

250 """ 

251 raise NotImplementedError("Platform subclasses must implement differentiable_all_to_all") 

252 

253 @staticmethod 

254 def tensor_type_cast(input_data, cast_type): 

255 """Cast tensor to a specified dtype. 

256 

257 Args: 

258 input_data: The input tensor to cast. 

259 cast_type: The target dtype to cast to. 

260 

261 Returns: 

262 The tensor cast to the specified dtype. 

263 """ 

264 raise NotImplementedError("Platform subclasses must implement tensor_type_cast") 

265 

266 @staticmethod 

267 def is_tensor(obj: Any) -> bool: 

268 """Return True if ``obj`` is this framework's tensor type.""" 

269 raise NotImplementedError("Platform subclasses must implement is_tensor") 

270 

271 @staticmethod 

272 def get_tensor_storage_size(tensor: Any) -> int: 

273 """Return serialized byte size (numel * element size) for this framework's tensor.""" 

274 raise NotImplementedError("Platform subclasses must implement get_tensor_storage_size") 

275 

276 @staticmethod 

277 def differentiable_all_reduce(data, op, group): 

278 """Perform differentiable all-reduce operation. 

279 

280 Args: 

281 data: The input tensor to reduce. 

282 op: The reduction operation (e.g., sum, max, min). 

283 group: The process group for collective communication. 

284 

285 Returns: 

286 The reduced tensor with gradients supported. 

287 """ 

288 raise NotImplementedError("Platform subclasses must implement differentiable_all_reduce") 

289 

290 @staticmethod 

291 def differentiable_reduce_scatter(data, dev_num, axis, op, group): 

292 """Perform differentiable reduce-scatter operation. 

293 

294 Args: 

295 data: The input tensor to reduce and scatter. 

296 dev_num (int): The number of devices to scatter across. 

297 axis (int): The axis along which to scatter. 

298 op: The reduction operation (e.g., sum, max, min). 

299 group: The process group for collective communication. 

300 

301 Returns: 

302 The scattered tensor chunk with gradients supported. 

303 """ 

304 raise NotImplementedError("Platform subclasses must implement differentiable_reduce_scatter") 

305 

306 @staticmethod 

307 def init_parameters(module, stage_index): 

308 """Initialize parameters for a module at a specific pipeline stage. 

309 

310 This method is primarily needed for MindSpore platform which requires 

311 explicit parameter initialization interface. 

312 

313 Args: 

314 module: The module whose parameters need to be initialized. 

315 stage_index (int): The pipeline stage index for the module. 

316 

317 Raises: 

318 ValueError: If module is None or stage_index is negative. 

319 """ 

320 if module is None: 

321 raise ValueError("input module must not be none.") 

322 if stage_index < 0: 

323 raise ValueError("input stage_index must be positive.") 

324 

325 @staticmethod 

326 def get_cell_construct(cell): 

327 """Get the construct (forward) function of a cell/module. 

328 

329 Args: 

330 cell: The cell or module to get the construct function from. 

331 

332 Returns: 

333 The construct/forward callable of the cell. 

334 """ 

335 raise NotImplementedError("Platform subclasses must implement get_cell_construct") 

336 

337 @staticmethod 

338 def get_cells_and_names(cell): 

339 """Get all nested cells/modules and their names. 

340 

341 Args: 

342 cell: The root cell or module to traverse. 

343 

344 Returns: 

345 list: A list of tuples containing (name, cell) pairs. 

346 """ 

347 raise NotImplementedError("Platform subclasses must implement get_cells_and_names") 

348 

349 @staticmethod 

350 def get_modules(module): 

351 """Return all sub-modules contained in the given module.""" 

352 raise NotImplementedError("Platform subclasses must implement get_modules") 

353 

354 @staticmethod 

355 def search_parameter_by_name(cell, param_name: str): 

356 """Search for a parameter by name within a cell/module. 

357 

358 Args: 

359 cell: The cell or module to search in. 

360 param_name (str): The name of the parameter to find. 

361 

362 Returns: 

363 The parameter if found, otherwise None. 

364 """ 

365 raise NotImplementedError("Platform subclasses must implement search_parameter_by_name") 

366 

367 @staticmethod 

368 def update_parameter_by_name(cell, result: tuple, new_param) -> bool: 

369 """Update a parameter by name within a cell/module. 

370 

371 Args: 

372 cell: The cell or module containing the parameter. 

373 result (tuple): A tuple containing (param_name, parameter) to update. 

374 new_param: The new parameter value to set. 

375 

376 Returns: 

377 bool: True if update was successful, False otherwise. 

378 """ 

379 raise NotImplementedError("Platform subclasses must implement update_parameter_by_name") 

380 

381 @staticmethod 

382 def set_layout_into_parameter(param, layout): 

383 """Attach a DTensor layout to a parameter. 

384 

385 Args: 

386 param: The parameter to attach the layout to. 

387 layout: The DTensor layout describing tensor distribution. 

388 """ 

389 raise NotImplementedError("Platform subclasses must implement set_layout_into_parameter") 

390 

391 @staticmethod 

392 def get_param_local_shape(param): 

393 """Get the local shape of a distributed parameter. 

394 

395 Args: 

396 param: The parameter to query. 

397 

398 Returns: 

399 tuple: The local shape of the parameter shard. 

400 """ 

401 raise NotImplementedError("Platform subclasses must implement get_param_local_shape") 

402 

403 @staticmethod 

404 def get_param_local_data(param): 

405 """Get the local data tensor of a distributed parameter. 

406 

407 Args: 

408 param: The parameter to query. 

409 

410 Returns: 

411 The local tensor data of the parameter shard. 

412 """ 

413 raise NotImplementedError("Platform subclasses must implement get_param_local_data") 

414 

415 @staticmethod 

416 def update_param_data(param, data): 

417 """Update the data of a parameter with new tensor data. 

418 

419 Args: 

420 param: The parameter to update. 

421 data: The new tensor data to assign. 

422 """ 

423 raise NotImplementedError("Platform subclasses must implement update_param_data") 

424 

425 @staticmethod 

426 def get_param_type_size(param): 

427 """Get the size in bytes of a parameter's dtype. 

428 

429 Args: 

430 param: The parameter to query. 

431 

432 Returns: 

433 int: The size in bytes of the parameter's data type. 

434 """ 

435 raise NotImplementedError("Platform subclasses must implement get_param_type_size") 

436 

437 @staticmethod 

438 def new_zero_parameter(param_shape, param_type, requires_grad, device): 

439 """Create a new parameter initialized with zeros. 

440 

441 Args: 

442 param_shape (tuple): The shape of the parameter. 

443 param_type: The dtype of the parameter. 

444 requires_grad (bool): Whether the parameter requires gradients. 

445 device: The device on which to create the parameter. 

446 

447 Returns: 

448 A new parameter tensor filled with zeros. 

449 """ 

450 raise NotImplementedError("Platform subclasses must implement new_zero_parameter") 

451 

452 @staticmethod 

453 def new_tensor(tensor_shape, tensor_type, device): 

454 """Create a new tensor with the specified shape, dtype, and device. 

455 

456 Args: 

457 tensor_shape (tuple): The shape of the tensor. 

458 tensor_type: The dtype of the tensor. 

459 device: The device on which to create the tensor. 

460 

461 Returns: 

462 A new tensor with uninitialized values. 

463 """ 

464 raise NotImplementedError("Platform subclasses must implement new_tensor") 

465 

466 @staticmethod 

467 def full_like(tensor, fill_value, dtype=None): 

468 """Create a tensor filled with a value, with same shape as input. 

469 

470 Args: 

471 tensor: The input tensor to copy shape from. 

472 fill_value: The value to fill the new tensor with. 

473 dtype: Optional dtype for the new tensor. If None, uses input tensor's dtype. 

474 

475 Returns: 

476 A new tensor filled with the specified value. 

477 """ 

478 raise NotImplementedError("Platform subclasses must implement full_like") 

479 

480 @staticmethod 

481 def set_tensor_requires_grad(input_tensor): 

482 """Enable gradient tracking for a tensor in-place. 

483 

484 Args: 

485 input_tensor: The tensor to enable gradients for. 

486 

487 Returns: 

488 The same tensor with requires_grad set to True. 

489 """ 

490 raise NotImplementedError("Platform subclasses must implement set_tensor_requires_grad") 

491 

492 @staticmethod 

493 def all_gather_into_tensor(data, group_info, async_op=False): 

494 """Gather tensors from all ranks into a single output tensor. 

495 

496 Args: 

497 data: The input tensor to gather. 

498 group_info: The process group for collective communication. 

499 async_op (bool): If True, returns a work handle for async operation. 

500 

501 Returns: 

502 The gathered tensor, or a tuple of (tensor, handle) if async_op is True. 

503 """ 

504 raise NotImplementedError("Platform subclasses must implement all_gather_into_tensor") 

505 

506 @staticmethod 

507 def all_reduce(data, group_info, async_op=False): 

508 """Reduce tensors across all ranks using specified operation. 

509 

510 Args: 

511 data: The input tensor to reduce. 

512 group_info: The process group for collective communication. 

513 async_op (bool): If True, returns a work handle for async operation. 

514 

515 Returns: 

516 The reduced tensor, or a tuple of (tensor, handle) if async_op is True. 

517 """ 

518 raise NotImplementedError("Platform subclasses must implement all_reduce") 

519 

520 @staticmethod 

521 def broadcast(data, src=None, group=None, async_op=False, group_src=None): 

522 """Broadcast tensor from source rank to all ranks in group.""" 

523 raise NotImplementedError("Platform subclasses must implement broadcast") 

524 

525 @staticmethod 

526 def scatter(output, scatter_list, src=None, group=None, async_op=False, group_src=None): 

527 """Scatter tensor list from source rank to all ranks in group.""" 

528 raise NotImplementedError("Platform subclasses must implement scatter") 

529 

530 @staticmethod 

531 def isend(tensor, dst=None, group=None, tag=0): 

532 """Send tensor asynchronously to destination rank. 

533 

534 Args: 

535 tensor: The tensor to send. 

536 dst (int, optional): The destination rank. Defaults to None. 

537 group: The process group for communication. Defaults to None. 

538 tag (int): A tag to identify the send operation. Defaults to 0. 

539 

540 Returns: 

541 A work handle that can be waited on. 

542 """ 

543 raise NotImplementedError("Platform subclasses must implement isend") 

544 

545 @staticmethod 

546 def irecv(tensor, src=None, group=None, tag=0): 

547 """Receive tensor asynchronously from source rank. 

548 

549 Args: 

550 tensor: The tensor buffer to receive data into. 

551 src (int, optional): The source rank. Defaults to None. 

552 group: The process group for communication. Defaults to None. 

553 tag (int): A tag to identify the receive operation. Defaults to 0. 

554 

555 Returns: 

556 A work handle that can be waited on. 

557 """ 

558 raise NotImplementedError("Platform subclasses must implement irecv") 

559 

560 @staticmethod 

561 def p2p_op(op_type, tensor, peer, group=None): 

562 """Build a batched-P2P descriptor (no launch). 

563 

564 Returns an opaque object understood by :meth:`batch_isend_irecv`. 

565 Lets callers assemble a mixed send/recv batch that the backend can 

566 run concurrently (e.g. TX/RX duplex on one link) in a single op. 

567 

568 Args: 

569 op_type (str): ``"isend"`` or ``"irecv"``. 

570 tensor: Tensor to send, or the buffer to receive into. 

571 peer (int): Global rank of the peer. 

572 group: Process group. ``None`` uses the default group. 

573 

574 Returns: 

575 A backend P2P-op descriptor. 

576 """ 

577 raise NotImplementedError("Platform subclasses must implement p2p_op") 

578 

579 @staticmethod 

580 def batch_isend_irecv(p2p_ops): 

581 """Launch a batch of :meth:`p2p_op` descriptors as one async op. 

582 

583 The whole batch shares a single completion handle (the backend runs 

584 the items concurrently on one comm stream), so a send and a recv to 

585 the same peer overlap on the duplex link. 

586 

587 Args: 

588 p2p_ops (list): Descriptors from :meth:`p2p_op`. 

589 

590 Returns: 

591 A single work handle covering the whole batch, or ``None`` when 

592 ``p2p_ops`` is empty. 

593 """ 

594 raise NotImplementedError("Platform subclasses must implement batch_isend_irecv") 

595 

596 @staticmethod 

597 def prepare_batch_p2p_group(group: Any = None) -> None: 

598 """Prepare a process group before its first batched P2P operation. 

599 

600 Backends that require full-group participation before subset batched 

601 P2P should synchronize the group here. Other backends may implement 

602 this as a no-op. 

603 

604 Args: 

605 group: The process group used by the batched P2P operations. 

606 ``None`` uses the default group. 

607 """ 

608 raise NotImplementedError("Platform subclasses must implement prepare_batch_p2p_group") 

609 

610 @staticmethod 

611 def p2p_exchange(tensor, peer_rank: int, group=None): 

612 """Differentiable symmetric P2P exchange (send local tensor, receive peer's tensor). 

613 

614 Sends ``tensor`` to ``peer_rank`` and simultaneously receives the peer's 

615 tensor. The operation is differentiable: the backward pass performs the 

616 same symmetric exchange on the upstream gradient. 

617 

618 Args: 

619 tensor: Local tensor to send. 

620 peer_rank (int): Global rank of the communication peer. 

621 group: Process group. ``None`` uses the default group. 

622 

623 Returns: 

624 Tensor received from ``peer_rank``, with the same shape and dtype as 

625 the input ``tensor``. 

626 """ 

627 raise NotImplementedError("Platform subclasses must implement p2p_exchange") 

628 

629 @staticmethod 

630 def send_object_list(obj_list, dst=None, group=None): 

631 """Send a list of Python objects to destination rank. 

632 

633 Args: 

634 obj_list (list): The list of Python objects to send. 

635 dst (int, optional): The destination rank. Defaults to None. 

636 group: The process group for communication. Defaults to None. 

637 """ 

638 raise NotImplementedError("Platform subclasses must implement send_object_list") 

639 

640 @staticmethod 

641 def recv_object_list(obj_list, src=None, group=None): 

642 """Receive a list of Python objects from source rank. 

643 

644 Args: 

645 obj_list (list): The list buffer to receive objects into. 

646 src (int, optional): The source rank. Defaults to None. 

647 group: The process group for communication. Defaults to None. 

648 """ 

649 raise NotImplementedError("Platform subclasses must implement recv_object_list") 

650 

651 @staticmethod 

652 def reduce_scatter_tensor(data, group_info, async_op=False): 

653 """Reduce and scatter tensor across all ranks in group. 

654 

655 Args: 

656 data: The input tensor to reduce and scatter. 

657 group_info: The process group for collective communication. 

658 async_op (bool): If True, returns a work handle for async operation. 

659 

660 Returns: 

661 The scattered tensor chunk, or a tuple of (tensor, handle) if async_op is True. 

662 """ 

663 raise NotImplementedError("Platform subclasses must implement reduce_scatter_tensor") 

664 

665 @staticmethod 

666 def all_gather_single(input_tensor, output_shape, group, async_op=False): 

667 """All-gather tensor shards with optional async execution. 

668 

669 Args: 

670 input_tensor: Input tensor whose leading dimension is gathered. 

671 output_shape: Shape of the gathered output tensor. 

672 group: Process group (ProcessGroup for torch, group name string for mindspore). 

673 async_op: If True, returns an async work handle. 

674 

675 Returns: 

676 Tuple ``(output, work)`` where *output* is the gathered tensor and 

677 *work* is the async handle (``None`` when ``async_op=False``). 

678 """ 

679 raise NotImplementedError("Platform subclasses must implement all_gather_single") 

680 

681 @staticmethod 

682 def reduce_scatter_single(input_tensor, output_shape, group, async_op=False): 

683 """Reduce-scatter a tensor with optional async execution. 

684 

685 Args: 

686 input_tensor: Input tensor whose leading dimension is split across ranks. 

687 output_shape: Shape of the local reduced output tensor. 

688 group: Process group (ProcessGroup for torch, group name string for mindspore). 

689 async_op: If True, returns an async work handle. 

690 

691 Returns: 

692 Tuple ``(output, work)`` where *output* is the local shard and 

693 *work* is the async handle (``None`` when ``async_op=False``). 

694 """ 

695 raise NotImplementedError("Platform subclasses must implement reduce_scatter_single") 

696 

697 @staticmethod 

698 def all_to_all_single(input_tensor, output_shape, group, async_op=False): 

699 """All-to-all single collective with optional async execution. 

700 

701 Args: 

702 input_tensor: Input tensor to scatter. 

703 output_shape: Shape of the pre-allocated output tensor. 

704 group: Process group (ProcessGroup for torch, group name string for mindspore). 

705 async_op: If True, returns a work handle; the output tensor is 

706 filled only after ``work.wait()`` is called. 

707 

708 Returns: 

709 Tuple ``(output, work)`` where *output* is the result tensor and 

710 *work* is the async handle (``None`` when ``async_op=False``). 

711 

712 Raises: 

713 NotImplementedError: Must be implemented by platform subclasses. 

714 """ 

715 raise NotImplementedError("Platform subclasses must implement all_to_all_single") 

716 

717 @staticmethod 

718 def differentiable_variable_all_gather( 

719 input_tensor: Any, output_splits: Sequence[int], group: Any) -> Any: 

720 """Gather variable dim-zero shards on every rank with gradient support. 

721 

722 Args: 

723 input_tensor: Local input shaped ``[local_rows, *feature_dims]``. 

724 output_splits: Dim-zero rows contributed by each group rank. 

725 group: Raw platform process group. 

726 

727 Returns: 

728 Tensor concatenated in group-rank order along dim zero. 

729 

730 Raises: 

731 NotImplementedError: Must be implemented by platform subclasses. 

732 """ 

733 raise NotImplementedError( 

734 "Platform subclasses must implement differentiable_variable_all_gather" 

735 ) 

736 

737 @staticmethod 

738 def differentiable_async_allgather_wait(x, work, out_perm, group, world_size, gather_dim, 

739 handle_box=None): 

740 """Differentiable wrapper that waits for a pre-launched async all-gather. 

741 

742 Forward waits for the all-gather handle and reconstructs the tensor by 

743 moving the gathered leading dimension back to ``gather_dim``. 

744 

745 Backward launches the reverse reduce-scatter. If ``handle_box`` is a 

746 mutable list, the reduce-scatter handle is appended there and a zero 

747 gradient is returned to be replaced by the caller's backward pre-hook. 

748 If ``handle_box`` is ``None``, the reduce-scatter is waited immediately 

749 and its local result is returned, preserving composability with an 

750 upstream autograd communication op. 

751 

752 Args: 

753 x: Original input tensor; anchors the op in the autograd graph. 

754 work: Async work handle from all-gather. 

755 out_perm: Output buffer filled by all-gather. 

756 group: Communication group for backward reduce-scatter. 

757 world_size: Group size. 

758 gather_dim: Dimension gathered in forward. 

759 handle_box: Optional mutable list for deferred backward wait. 

760 

761 Returns: 

762 Gathered tensor connected to the autograd graph through *x*. 

763 """ 

764 raise NotImplementedError("Platform subclasses must implement differentiable_async_allgather_wait") 

765 

766 @staticmethod 

767 def differentiable_async_a2a_wait(x, work, out_perm, group, world_size, concat_dim, split_dim, 

768 handle_box=None): 

769 """Differentiable wrapper that waits for a pre-launched async A2A. 

770 

771 Wraps the wait-and-reconstruct step in the platform autograd mechanism 

772 so gradients flow correctly through the all-to-all communication. 

773 

774 The A2A direction is seq→head (forward): the output gathers along 

775 ``concat_dim`` (sequence grows from S/cp to S) and scatters along 

776 ``split_dim`` (heads shrink from H to H/ws). 

777 

778 In backward, launches an async head→seq A2A on the incoming gradient 

779 and appends ``(work, out_perm)`` to ``handle_box`` so the caller can 

780 wait just before the projection GEMM, achieving GEMM–A2A overlap. 

781 

782 Args: 

783 x: Original projection output tensor; anchors the op 

784 in the autograd graph. 

785 work: Async work handle from ``all_to_all_single(async_op=True)``. 

786 out_perm: Output buffer filled once ``work.wait()`` completes 

787 (shape ``[ws, ...]``). 

788 group: Process group for the reverse A2A in backward. 

789 world_size: CP/Ulysses degree. 

790 concat_dim: Dimension that is gathered (concatenated) in forward; 

791 typically the sequence dimension. 

792 split_dim: Dimension that is scattered (split) in forward; 

793 typically the head dimension. 

794 handle_box: Optional mutable list ``[]``. In backward, ``(work, out_perm)`` 

795 for the reverse A2A is appended here so the pre-hook can wait. 

796 

797 Returns: 

798 Result tensor with ``concat_dim`` gathered and ``split_dim`` split, 

799 connected to the autograd graph through *x*. 

800 

801 Raises: 

802 NotImplementedError: Must be implemented by platform subclasses. 

803 """ 

804 raise NotImplementedError("Platform subclasses must implement differentiable_async_a2a_wait") 

805 

806 @staticmethod 

807 def differentiable_sync_hook(x, hook_name: str, coordinator): 

808 """Identity operation that intercepts both forward and backward to call 

809 coordinator rendezvous, enabling deterministic comm/compute overlap. 

810 

811 This is the differentiable building block for dual-pipe schedules. 

812 In the forward pass the coordinator is invoked with the forward-side 

813 roles for ``hook_name``; in the backward pass it is invoked with the 

814 backward-side roles. The tensor value and gradient flow through 

815 unchanged. 

816 

817 Args: 

818 x: Input tensor. Returned as-is; gradients flow through. 

819 hook_name: One of ``"A"``, ``"B"``, ``"C"``, ``"D"`` identifying 

820 the position relative to MoE dispatch/combine. 

821 coordinator: A :class:`HookCoordinator` instance shared between the 

822 forward and backward threads. 

823 

824 Returns: 

825 The same tensor *x*, attached to the autograd graph so that the 

826 backward hook will fire. 

827 """ 

828 raise NotImplementedError("Platform subclasses must implement differentiable_sync_hook") 

829 

830 @staticmethod 

831 def differentiable_all_to_all_single(input_tensor, input_splits, output_splits, group): 

832 """Variable-split all-to-all single that supports gradient flow. 

833 

834 Unlike ``all_to_all_single`` (which is not differentiable), this method 

835 wraps the collective in an autograd function so gradients are correctly 

836 routed back through the reverse all-to-all in the backward pass. 

837 Intended for Expert Parallelism token dispatch / combine. 

838 

839 Args: 

840 input_tensor: Input tensor to scatter. Shape ``[sum(input_splits), *feature_dims]``. 

841 input_splits: Per-rank sizes of data sent from this rank (list of ints, 

842 length equal to ep_degree). 

843 output_splits: Per-rank sizes of data received by this rank (list of ints, 

844 length equal to ep_degree). 

845 group: Process group (ProcessGroup for torch, group name str for mindspore). 

846 

847 Returns: 

848 Output tensor of shape ``[sum(output_splits), *feature_dims]``. 

849 

850 Raises: 

851 NotImplementedError: Must be implemented by platform subclasses. 

852 """ 

853 raise NotImplementedError("Platform subclasses must implement differentiable_all_to_all_single") 

854 

855 @staticmethod 

856 def differentiable_all_to_all_single_async(input_tensor, input_splits, output_splits, group): 

857 """Async variant of :meth:`differentiable_all_to_all_single`. 

858 

859 Same semantics but launches the collective with ``async_op=True`` and 

860 only performs a stream-level ``wait`` — the host returns immediately 

861 after dispatching the kernel. Intended for dual-pipe comm/compute 

862 overlap paths where the paired COMPUTE side's rendezvous notify must 

863 fire right after kernel launch (not after the collective actually 

864 completes on device). 

865 

866 Args: 

867 input_tensor: Input tensor to scatter. Shape ``[sum(input_splits), *feature_dims]``. 

868 input_splits: Per-rank sizes of data sent from this rank. 

869 output_splits: Per-rank sizes of data received by this rank. 

870 group: Process group. 

871 

872 Returns: 

873 Output tensor of shape ``[sum(output_splits), *feature_dims]``. 

874 

875 Raises: 

876 NotImplementedError: Must be implemented by platform subclasses. 

877 """ 

878 raise NotImplementedError( 

879 "Platform subclasses must implement differentiable_all_to_all_single_async" 

880 ) 

881 

882 @staticmethod 

883 def wait_async_tensor(tensor): 

884 """Wait for an async collective tensor to become materialised. 

885 

886 Intended for use with :class:`AsyncHandle` so that callers can 

887 wait on an async all-to-all result without importing framework-specific 

888 modules directly. The call is **idempotent** — waiting on an already- 

889 completed tensor is a no-op. 

890 

891 Args: 

892 tensor: An async collective tensor (e.g. PyTorch 

893 ``AsyncCollectiveTensor``) whose values have not yet been 

894 fully written by the remote ranks. 

895 

896 Returns: 

897 The same *tensor*, now guaranteed to be fully materialised. 

898 

899 Raises: 

900 NotImplementedError: Must be implemented by platform subclasses. 

901 """ 

902 raise NotImplementedError( 

903 "Platform subclasses must implement wait_async_tensor" 

904 ) 

905 

906 @staticmethod 

907 def arange(start, end=None, step=1, dtype=None, device=None): 

908 """Create a 1-D tensor with evenly spaced values. 

909 

910 Args: 

911 start: Start of interval (inclusive). If *end* is ``None``, 

912 treated as the stop value and *start* defaults to 0. 

913 end: End of interval (exclusive). Defaults to ``None``. 

914 step: Step size. Defaults to ``1``. 

915 dtype: Data type. ``None`` uses the framework default (int64). 

916 device: Target device. 

917 

918 Returns: 

919 1-D tensor ``[start, start+step, ..., end)``. 

920 

921 Raises: 

922 NotImplementedError: Must be implemented by platform subclasses. 

923 """ 

924 raise NotImplementedError("Platform subclasses must implement arange") 

925 

926 @staticmethod 

927 def zeros(size, dtype=None, device=None): 

928 """Create a zero-filled tensor of the given shape. 

929 

930 Args: 

931 size: Shape of the tensor (a single tuple/list). 

932 dtype: Desired data type. ``None`` uses the framework default (float32). 

933 device: Target device. ``None`` uses the framework default. 

934 

935 Returns: 

936 Zero-filled tensor of the specified shape. 

937 

938 Raises: 

939 NotImplementedError: Must be implemented by platform subclasses. 

940 """ 

941 raise NotImplementedError("Platform subclasses must implement zeros") 

942 

943 @staticmethod 

944 def parameters_dict(cell): 

945 """Get the parameters dictionary of a cell/module. 

946 

947 Args: 

948 cell: The cell or module to get parameters from. 

949 

950 Returns: 

951 dict: A dictionary mapping parameter names to parameters. 

952 """ 

953 raise NotImplementedError("Platform subclasses must implement parameters_dict") 

954 

955 @staticmethod 

956 def buffers_dict(cell: Any) -> Any: 

957 """Get the named buffers of a cell/module. 

958 

959 Args: 

960 cell: The cell or module to get buffers from. 

961 

962 Returns: 

963 An iterable of ``(name, buffer)`` pairs, including non-persistent 

964 buffers and buffers registered by child modules. 

965 """ 

966 raise NotImplementedError("Platform subclasses must implement buffers_dict") 

967 

968 @staticmethod 

969 def get_model_state_dict(model: Any, *, options: Any = None) -> dict[str, Any]: 

970 """Get the state dictionary of a model. 

971 

972 Args: 

973 model: The model to extract state from. 

974 options: Optional configuration for state dict extraction. 

975 

976 Returns: 

977 dict: The state dictionary containing model parameters and buffers. 

978 

979 Raises: 

980 NotImplementedError: Platform subclasses must implement this method. 

981 """ 

982 raise NotImplementedError( 

983 "Platform subclasses must implement get_model_state_dict" 

984 ) 

985 

986 @staticmethod 

987 def set_model_state_dict(model: Any, model_state_dict: dict[str, Any], *, options: Any = None) -> None: 

988 """Set the state dictionary of a model. 

989 

990 Args: 

991 model: The model to load state into. 

992 model_state_dict: The state dict to load into the model. 

993 options: Optional configuration for state dict loading. 

994 

995 Returns: 

996 None. 

997 

998 Raises: 

999 NotImplementedError: Platform subclasses must implement this method. 

1000 """ 

1001 raise NotImplementedError( 

1002 "Platform subclasses must implement set_model_state_dict" 

1003 ) 

1004 

1005 @staticmethod 

1006 def save_checkpoint(cell, file_path: str, ckpt_format: str = "safetensors") -> None: 

1007 """Save a cell/module checkpoint to file. 

1008 

1009 Args: 

1010 cell: The cell or module to save. 

1011 file_path (str): The path to save the checkpoint to. 

1012 ckpt_format (str): The file format. 

1013 """ 

1014 raise NotImplementedError("Platform subclasses must implement save_checkpoint") 

1015 

1016 @staticmethod 

1017 def load_checkpoint(file_path: str, ckpt_format: str = "safetensors") -> dict: 

1018 """Load a checkpoint from file. 

1019 

1020 Args: 

1021 file_path (str): The path to load the checkpoint from. 

1022 ckpt_format (str): The file format. 

1023 

1024 Returns: 

1025 dict: The loaded checkpoint state dictionary. 

1026 """ 

1027 raise NotImplementedError("Platform subclasses must implement load_checkpoint") 

1028 

1029 def _create_group(self, rank_list): 

1030 """Create a new process group with the specified ranks. 

1031 

1032 Internal method to be implemented by subclasses. 

1033 

1034 Args: 

1035 rank_list (list): List of ranks to include in the group. 

1036 

1037 Returns: 

1038 The newly created process group. 

1039 """ 

1040 raise NotImplementedError("Platform subclasses must implement _create_group") 

1041 

1042 def new_stream(self): 

1043 """Create a new compute stream for asynchronous operations. 

1044 

1045 Returns: 

1046 A new stream object for the current device. 

1047 """ 

1048 raise NotImplementedError("Platform subclasses must implement new_stream") 

1049 

1050 def get_stream_context(self): 

1051 """Get a context manager for executing operations on a specific stream. 

1052 

1053 Returns: 

1054 A context manager that can be used with 'with' statement to set stream. 

1055 """ 

1056 raise NotImplementedError("Platform subclasses must implement get_stream_context") 

1057 

1058 @staticmethod 

1059 def get_tensor_transform(): 

1060 """Get the tensor transformation utilities for the current framework. 

1061 

1062 Returns: 

1063 A module or object containing tensor transformation functions. 

1064 """ 

1065 raise NotImplementedError("Platform subclasses must implement get_tensor_transform") 

1066 

1067 @staticmethod 

1068 def construct_strided_slice(x, begin, end, stride): 

1069 """Construct a strided slice operation on a tensor. 

1070 

1071 Args: 

1072 x: The input tensor to slice. 

1073 begin: The starting indices for each dimension. 

1074 end: The ending indices for each dimension. 

1075 stride: The stride for each dimension. 

1076 

1077 Returns: 

1078 The sliced tensor. 

1079 """ 

1080 raise NotImplementedError("Platform subclasses must implement construct_strided_slice") 

1081 

1082 @staticmethod 

1083 def micro_batch(micro_batch_num, args_batch_dim=None, kwargs_batch_dim=None): 

1084 """Split inputs into micro-batches for pipeline parallelism. 

1085 

1086 Args: 

1087 micro_batch_num (int): The number of micro-batches to create. 

1088 args_batch_dim (list, optional): Batch dimension for each positional arg. 

1089 kwargs_batch_dim (dict, optional): Batch dimension for each keyword arg. 

1090 

1091 Returns: 

1092 A decorator that splits function inputs into micro-batches. 

1093 """ 

1094 raise NotImplementedError("Platform subclasses must implement micro_batch") 

1095 

1096 @staticmethod 

1097 def get_symmetric_memory_handler(): 

1098 """Return a platform-specific symmetric memory handler instance.""" 

1099 raise NotImplementedError("Platform subclasses must implement get_symmetric_memory_handler") 

1100 

1101 @staticmethod 

1102 def load_into_param(param, data): 

1103 """Load data into a parameter, handling framework-specific semantics.""" 

1104 raise NotImplementedError("Platform subclasses must implement load_into_param") 

1105 

1106 def create_group(self, rank_list): 

1107 """Create or retrieve a communication group with the specified ranks. 

1108 

1109 If a group with the same rank list already exists, returns the existing 

1110 group instead of creating a new one. 

1111 

1112 Args: 

1113 rank_list (list): List of ranks to include in the group. 

1114 

1115 Returns: 

1116 The process group for the specified ranks. 

1117 """ 

1118 group_key = str(tuple(sorted(rank_list))) 

1119 if group_key in EXISTING_COMM_GROUPS: 

1120 return EXISTING_COMM_GROUPS[group_key] 

1121 

1122 group = self._create_group(rank_list) 

1123 EXISTING_COMM_GROUPS[group_key] = group 

1124 return group 

1125 

1126 @staticmethod 

1127 def _process_current_handle(): 

1128 """Wait for the current gradient handle and execute post-process callback. 

1129 

1130 Internal method to synchronize pending gradient operations. 

1131 """ 

1132 if Platform.current_grad_handle is None: 

1133 return 

1134 

1135 Platform.current_grad_handle.wait() 

1136 if Platform.post_grad_handle_process is None: 

1137 return 

1138 # pylint: disable=E1102 

1139 Platform.post_grad_handle_process() 

1140 

1141 def set_grad_reduce_handle(self, handle, post_process=None): 

1142 """Set a new gradient reduction handle after waiting for the current one. 

1143 

1144 Waits for any pending gradient handle on the grad sync stream, then 

1145 sets the new handle and optional post-process callback. 

1146 

1147 Args: 

1148 handle: The async work handle for gradient reduction. 

1149 post_process (callable, optional): Callback to run after handle completes. 

1150 """ 

1151 if Platform.grad_sync_stream is None: 

1152 Platform.grad_sync_stream = self.new_stream() 

1153 stream_context = self.get_stream_context() 

1154 with stream_context(Platform.grad_sync_stream): 

1155 Platform._process_current_handle() 

1156 Platform.current_grad_handle = handle 

1157 Platform.post_grad_handle_process = post_process 

1158 

1159 def wait_grad_handle(self): 

1160 """Wait for the current gradient handle to complete. 

1161 

1162 Blocks until the current gradient reduction handle completes and 

1163 clears the handle state. 

1164 """ 

1165 if Platform.current_grad_handle is None: 

1166 return 

1167 if Platform.grad_sync_stream is None: 

1168 Platform.grad_sync_stream = self.new_stream() 

1169 stream_context = self.get_stream_context() 

1170 with stream_context(Platform.grad_sync_stream): 

1171 Platform._process_current_handle() 

1172 sync_event = Platform.grad_sync_stream.record_event() 

1173 sync_event.wait() 

1174 Platform.current_grad_handle = None 

1175 Platform.post_grad_handle_process = None 

1176 

1177 @staticmethod 

1178 def all_gather_object(object_list, obj, group=None) -> None: 

1179 """Gather Python objects from all ranks into a list. 

1180 

1181 Each rank contributes its object, and all ranks receive the complete list. 

1182 

1183 Args: 

1184 object_list (list): List to store gathered objects (output parameter). 

1185 obj: The Python object from this rank to contribute. 

1186 group: The process group for communication. Defaults to None (default group). 

1187 """ 

1188 raise NotImplementedError("Platform subclasses must implement all_gather_object") 

1189 

1190 @staticmethod 

1191 def barrier(group=None, async_op: bool = False, device_ids=None) -> Any: 

1192 """Synchronize all processes in the given process group. 

1193 

1194 Each rank blocks until every rank in the group enters this collective (when ``async_op`` 

1195 is False), or returns an async handle that must be completed before proceeding. 

1196 

1197 Args: 

1198 group: The process group or communication group. ``None`` uses the default group. 

1199 async_op (bool): If True, returns a backend-specific async work handle. Default: False. 

1200 device_ids: Optional device id list; semantics depend on the backend. 

1201 

1202 Returns: 

1203 Async work handle when ``async_op`` is True; otherwise ``None`` (unless the rank 

1204 is not in the group, in which case the backend may return ``None``). 

1205 """ 

1206 raise NotImplementedError("Platform subclasses must implement barrier") 

1207 

1208 @staticmethod 

1209 def init_process_group( 

1210 backend: Optional[str] = None, 

1211 *, 

1212 init_method: Optional[str] = None, 

1213 timeout: Optional[timedelta] = None, 

1214 world_size: int = -1, 

1215 rank: int = -1, 

1216 store: Any = None, 

1217 pg_options: Any = None, 

1218 device_id: Any = None 

1219 ) -> None: 

1220 """ 

1221 Initialize the default distributed process group. 

1222 

1223 Args: 

1224 backend: The backend to use for distributed communication 

1225 init_method: URL specifying how to initialize the process group 

1226 timeout: Timeout for operations executed against the process group 

1227 world_size: Number of processes participating in the job 

1228 rank: Rank of the current process 

1229 store: Key/value store for exchanging connection information 

1230 pg_options: Process group options for backend-specific configurations 

1231 device_id: Specific device this process will work on 

1232 

1233 Raises: 

1234 NotImplementedError: This method must be implemented by subclasses 

1235 """ 

1236 raise NotImplementedError("Platform subclasses must implement init_process_group") 

1237 

1238 @staticmethod 

1239 def destroy_process_group(group=None) -> None: 

1240 """ 

1241 Destroy a given process group. 

1242 

1243 Args: 

1244 group: The process group to be destroyed. If None, destroys the default group. 

1245 

1246 Raises: 

1247 NotImplementedError: This method must be implemented by subclasses 

1248 """ 

1249 raise NotImplementedError("Platform subclasses must implement destroy_process_group") 

1250 

1251 @staticmethod 

1252 def get_process_group_ranks(group=None) -> list[int]: 

1253 """ 

1254 Get rank list of the given process group. 

1255 

1256 Args: 

1257 group: The process group to get ranks from. If None, uses the default group. 

1258 

1259 Returns: 

1260 List of ranks in the specified process group. 

1261 

1262 Raises: 

1263 NotImplementedError: This method must be implemented by subclasses 

1264 """ 

1265 raise NotImplementedError("Platform subclasses must implement get_process_group_ranks") 

1266 

1267 @staticmethod 

1268 def get_backend(group=None): 

1269 """ 

1270 Get the backend of the given process group. 

1271 Args: 

1272 group: The process group to get backend from. If None, uses the default group. 

1273 

1274 Returns: 

1275 The backend name of the specified process group. 

1276 

1277 Raises: 

1278 NotImplementedError: This method must be implemented by subclasses 

1279 """ 

1280 raise NotImplementedError("Platform subclasses must implement get_backend") 

1281 

1282 @staticmethod 

1283 def split_group(parent_pg: Any = None, 

1284 split_ranks: Optional[list] = None, 

1285 timeout: Optional[timedelta] = None, 

1286 pg_options: Optional[Any] = None, 

1287 group_desc: Optional[str] = None, 

1288 ) -> Any: 

1289 """Create a split group relative to the parent process group. 

1290 

1291 Args: 

1292 parent_pg: The parent process group to split from. 

1293 split_ranks (list, optional): Ranks to include in the split group. 

1294 timeout (timedelta, optional): Timeout for operations. 

1295 pg_options: Process group options for backend-specific configurations. 

1296 group_desc (str, optional): Description of the group. 

1297 

1298 Returns: 

1299 The new split process group. 

1300 """ 

1301 raise NotImplementedError("Platform subclasses must implement split_group") 

1302 

1303 @staticmethod 

1304 def get_group_local_rank(group=None) -> int: 

1305 """Get the local rank within the given process group. 

1306 

1307 Args: 

1308 group: The process group to query. If None, uses the default group. 

1309 

1310 Returns: 

1311 int: The local rank within the group. 

1312 """ 

1313 raise NotImplementedError("Platform subclasses must implement get_group_local_rank") 

1314 

1315 @staticmethod 

1316 def no_grad(): 

1317 """Get a context manager to disable gradient computation. 

1318 

1319 Returns: 

1320 A context manager that disables gradient tracking. 

1321 """ 

1322 raise NotImplementedError("Platform subclasses must implement no_grad") 

1323 

1324 @staticmethod 

1325 def preserve_version_counter(tensor): 

1326 """Get a context manager that preserves version for an internal tensor update.""" 

1327 raise NotImplementedError("Platform subclasses must implement preserve_version_counter") 

1328 

1329 @staticmethod 

1330 def relu(tensor): 

1331 """Apply ReLU activation element-wise. 

1332 

1333 Args: 

1334 tensor: Input tensor. 

1335 

1336 Returns: 

1337 Tensor with ReLU applied (max(0, x)). 

1338 """ 

1339 raise NotImplementedError("Platform subclasses must implement relu") 

1340 

1341 @staticmethod 

1342 def cat(tensors, dim=0): 

1343 """Concatenate tensors along a dimension.""" 

1344 raise NotImplementedError("Platform subclasses must implement cat") 

1345 

1346 @staticmethod 

1347 def empty_like(tensor, *, dtype=None, device=None, pin_memory=False): 

1348 """Create an uninitialized tensor with the same shape as input. 

1349 

1350 Args: 

1351 tensor: The input tensor to copy shape from. 

1352 dtype: Optional dtype for the new tensor. If None, uses input tensor's dtype. 

1353 device: Optional device for the new tensor. If None, uses input tensor's device. 

1354 pin_memory (bool): If True, allocate pinned memory for faster CPU-GPU transfer. 

1355 

1356 Returns: 

1357 An uninitialized tensor with the same shape as input. 

1358 """ 

1359 raise NotImplementedError("Platform subclasses must implement empty_like") 

1360 

1361 def get_current_stream(self): 

1362 """Get the current compute stream for the device. 

1363 

1364 Returns: 

1365 The current stream object. 

1366 """ 

1367 raise NotImplementedError("Platform subclasses must implement get_current_stream") 

1368 

1369 def new_event(self): 

1370 """Create a new event for stream synchronization. 

1371 

1372 Returns: 

1373 A new event object. 

1374 """ 

1375 raise NotImplementedError("Platform subclasses must implement new_event") 

1376 

1377 def tree_map(self, fn, tree): 

1378 """Apply a function to all tensors in a nested structure. 

1379 

1380 Args: 

1381 fn (callable): Function to apply to each tensor. 

1382 tree: Nested structure (list, tuple, dict) containing tensors. 

1383 

1384 Returns: 

1385 The same nested structure with fn applied to all tensors. 

1386 """ 

1387 raise NotImplementedError("Platform subclasses must implement tree_map") 

1388 

1389 @staticmethod 

1390 def is_linear_module(module) -> bool: 

1391 """Check whether *module* is a linear/dense layer for the current framework. 

1392 

1393 Args: 

1394 module: The module instance to check. 

1395 

1396 Returns: 

1397 True if *module* is the framework's linear layer type. 

1398 """ 

1399 raise NotImplementedError("Platform subclasses must implement is_linear_module") 

1400 

1401 @staticmethod 

1402 def is_embedding_module(module) -> bool: 

1403 """Check whether *module* is an embedding layer for the current framework. 

1404 

1405 Args: 

1406 module: The module instance to check. 

1407 

1408 Returns: 

1409 True if *module* is the framework's embedding layer type. 

1410 """ 

1411 raise NotImplementedError("Platform subclasses must implement is_embedding_module") 

1412 

1413 @staticmethod 

1414 def register_forward_pre_hook(module, hook, prepend=False, with_kwargs=False): 

1415 """Register a forward pre-hook on a module. 

1416 

1417 Args: 

1418 module: The module to register the hook on. 

1419 hook (callable): The hook function to register. 

1420 prepend (bool): If True, prepend the hook to existing hooks. 

1421 with_kwargs (bool): If True, hook receives both args and kwargs. 

1422 

1423 Returns: 

1424 A handle that can be used to remove the hook. 

1425 """ 

1426 return module.register_forward_pre_hook(hook, prepend=prepend, with_kwargs=with_kwargs) 

1427 

1428 @staticmethod 

1429 def register_full_backward_hook(module, hook, prepend=False): 

1430 """Register a full backward hook on a module. 

1431 

1432 Args: 

1433 module: The module to register the hook on. 

1434 hook (callable): The hook function to register. 

1435 prepend (bool): If True, prepend the hook to existing hooks. 

1436 

1437 Returns: 

1438 A handle that can be used to remove the hook. 

1439 """ 

1440 return module.register_full_backward_hook(hook, prepend) 

1441 

1442 @staticmethod 

1443 def register_full_backward_pre_hook(module, hook, prepend=False): 

1444 """Register a full backward pre-hook on a module. 

1445 

1446 Args: 

1447 module: The module to register the hook on. 

1448 hook (callable): The hook function to register. 

1449 prepend (bool): If True, prepend the hook to existing hooks. 

1450 

1451 Returns: 

1452 A handle that can be used to remove the hook. 

1453 """ 

1454 return module.register_full_backward_pre_hook(hook, prepend) 

1455 

1456 @property 

1457 def checkpoint(self): 

1458 """Get the checkpoint function for activation checkpointing. 

1459 

1460 Returns: 

1461 The checkpoint function for the current framework. 

1462 """ 

1463 raise NotImplementedError("Platform subclasses must implement checkpoint") 

1464 

1465 @staticmethod 

1466 def checkpoint_wrapper(module, **checkpoint_kwargs): 

1467 """Wrap a module with activation checkpointing functionality. 

1468 

1469 Args: 

1470 module: The module or callable to wrap with activation checkpointing. 

1471 **checkpoint_kwargs: Keyword arguments forwarded to the framework 

1472 checkpoint wrapper implementation. 

1473 

1474 Returns: 

1475 The wrapped module with activation checkpointing enabled. 

1476 """ 

1477 raise NotImplementedError("Platform subclasses must implement checkpoint_wrapper") 

1478 

1479 @staticmethod 

1480 def checkpoint_exclude_wrapper(module: Any, *, save_output: bool = True) -> Any: 

1481 """Wrap a callable whose activations should be saved instead of recomputed. 

1482 

1483 Args: 

1484 module: The module or callable to exclude from activation recomputation. 

1485 save_output: Whether to retain the excluded region output for replay. 

1486 

1487 Returns: 

1488 The wrapped module or callable. 

1489 """ 

1490 raise NotImplementedError("Platform subclasses must implement checkpoint_exclude_wrapper") 

1491 

1492 @staticmethod 

1493 def swap_wrapper(module, policy_fn=None, group_swap=False): 

1494 """Wrap a module with activation swap functionality. 

1495 

1496 Args: 

1497 module: The module to wrap with activation swap. 

1498 policy_fn: Optional per-tensor swap policy function. 

1499 group_swap (bool, optional): Whether tensors participate in group copy fusion. Default: ``False``. 

1500 

1501 Returns: 

1502 The wrapped module with activation swap enabled. 

1503 """ 

1504 raise NotImplementedError("Platform subclasses must implement swap_wrapper") 

1505 

1506 @staticmethod 

1507 def swap_tensor_wrapper(target, tag=None, group_swap=False): 

1508 """Register target tensors into the current swap group. 

1509 

1510 Args: 

1511 target: A tensor or nested container of tensors to register. 

1512 tag: Optional debug tag associated with the wrapped tensors. 

1513 group_swap (bool, optional): Whether tensors participate in group copy fusion. Default: ``False``. 

1514 

1515 Returns: 

1516 The original target structure, unchanged semantically. 

1517 """ 

1518 raise NotImplementedError("Platform subclasses must implement swap_tensor_wrapper") 

1519 

1520 @staticmethod 

1521 def get_class_activation_wrapper(): 

1522 """Return the platform-specific activation wrapper class.""" 

1523 raise NotImplementedError("Platform subclasses must implement get_class_activation_wrapper") 

1524 

1525 @property 

1526 def noop_context_fn(self): 

1527 """Get a no-op context function for checkpointing. 

1528 

1529 Returns: 

1530 A context function that performs no operation. 

1531 """ 

1532 raise NotImplementedError("Platform subclasses must implement noop_context_fn") 

1533 

1534 @staticmethod 

1535 def create_selective_checkpoint_contexts(policy_fn_or_list, allow_cache_entry_mutation=False, group_swap=False): 

1536 """Create contexts for selective activation checkpointing. 

1537 

1538 Args: 

1539 policy_fn_or_list: A policy function or list of layer names to checkpoint. 

1540 allow_cache_entry_mutation (bool): Whether to allow cache entry mutation. 

1541 group_swap (bool, optional): Whether MUST_SWAP tensors participate in group copy fusion. Default: ``False``. 

1542 

1543 Returns: 

1544 Context functions for selective checkpointing. 

1545 """ 

1546 raise NotImplementedError("Platform subclasses must implement create_selective_checkpoint_contexts") 

1547 

1548 @staticmethod 

1549 def async_save_on_cpu(policy_fn=None, group_swap: bool = False): 

1550 """Create an async CPU offload context for activation checkpointing. 

1551 

1552 Args: 

1553 policy_fn: Optional policy function to determine which activations to offload. 

1554 group_swap (bool): Whether swapped tensors participate in group copy fusion. 

1555 Default: ``False``. 

1556 

1557 Returns: 

1558 Context manager for async CPU offloading during checkpointing. 

1559 """ 

1560 raise NotImplementedError("Platform subclasses must implement async_save_on_cpu") 

1561 

1562 @staticmethod 

1563 def recompute_handle_collector_ctx(): 

1564 """Context manager that collects recompute handles created in its scope. 

1565 

1566 Yields: 

1567 A list populated with one opaque recompute handle per checkpointed 

1568 block executed during the forward pass within the context. Each 

1569 handle can later be fired via :meth:`recompute_handle`. 

1570 """ 

1571 raise NotImplementedError("Platform subclasses must implement recompute_handle_collector_ctx") 

1572 

1573 @staticmethod 

1574 def recompute_handle(handle, session_id): 

1575 """Eagerly fire one checkpointed block's forward re-run. 

1576 

1577 Materializes and caches the block's activations under ``session_id`` so 

1578 a later backward in the same session reuses them instead of re-running. 

1579 

1580 Args: 

1581 handle: An opaque recompute handle from 

1582 :meth:`recompute_handle_collector_ctx`. 

1583 session_id: Stable key shared by the producing re-run and the 

1584 consuming backward. 

1585 """ 

1586 raise NotImplementedError("Platform subclasses must implement recompute_handle") 

1587 

1588 @staticmethod 

1589 def recompute_session_ctx(session_id, retain_on_unpack=False): 

1590 """Context manager binding recompute unpack to a caller-provided session. 

1591 

1592 Args: 

1593 session_id: Required stable session key. Recompute caches are keyed 

1594 by this instead of the transient autodiff engine id, so a re-run 

1595 fired under one engine can be reused by another. Must not be 

1596 ``None``. 

1597 retain_on_unpack (bool): When ``True``, unpack returns recomputed 

1598 tensors without popping them, so a later backward can consume 

1599 them. Default: ``False``. 

1600 

1601 Returns: 

1602 A context manager activating the session for its scope. 

1603 

1604 Yields: 

1605 The supplied session id. 

1606 """ 

1607 raise NotImplementedError("Platform subclasses must implement recompute_session_ctx") 

1608 

1609 @staticmethod 

1610 def clear_recompute_session(session_id): 

1611 """Release retained recompute data for a session. 

1612 

1613 Args: 

1614 session_id: The session key whose cached recompute data is cleared. 

1615 """ 

1616 raise NotImplementedError("Platform subclasses must implement clear_recompute_session") 

1617 

1618 @staticmethod 

1619 def get_element_size(tensor): 

1620 """Get Tensor Element Size""" 

1621 raise NotImplementedError("Platform subclasses must implement get_element_size") 

1622 

1623 @staticmethod 

1624 def alloc_tensor_buffer(numel: int, dtype, device, pin_memory: bool = False): 

1625 """Allocate an uninitialized 1-D tensor buffer.""" 

1626 raise NotImplementedError("Platform subclasses must implement alloc_tensor_buffer") 

1627 

1628 @staticmethod 

1629 def tensor_to_numpy(tensor) -> np.ndarray: 

1630 """Convert a framework tensor to a NumPy array. 

1631 

1632 Args: 

1633 tensor: The tensor to convert. 

1634 

1635 Returns: 

1636 np.ndarray: The tensor data as a NumPy array. 

1637 """ 

1638 raise NotImplementedError("Platform subclasses must implement tensor_to_numpy") 

1639 

1640 @staticmethod 

1641 def from_numpy(np_array): 

1642 """Create a host-resident tensor from a NumPy array (inverse of tensor_to_numpy). 

1643 

1644 The result stays on the host regardless of the active device context, so it 

1645 remains asnumpy-able even when built under ``ms.DeviceCtx("meta")`` (e.g. while 

1646 ``fully_shard`` lazily constructs a default device mesh). Use it for rank/mesh 

1647 bookkeeping tensors, which are only ever read back via ``tensor_to_numpy``. 

1648 """ 

1649 raise NotImplementedError("Platform subclasses must implement from_numpy") 

1650 

1651 @staticmethod 

1652 def profiler_record(name): 

1653 """Record a profiler event with the given name. 

1654 

1655 Args: 

1656 name (str): The name of the profiler event. 

1657 

1658 Returns: 

1659 A context manager or decorator for profiling a code region. 

1660 """ 

1661 raise NotImplementedError("Platform subclasses must implement profiler_record") 

1662 

1663 def cast_fp_tensor(self, dtype, x): 

1664 """Cast floating-point tensor to target dtype if applicable. 

1665 

1666 Args: 

1667 dtype: The target dtype to cast to. 

1668 x: The input tensor. 

1669 

1670 Returns: 

1671 The tensor cast to target dtype, or unchanged if not floating-point. 

1672 """ 

1673 raise NotImplementedError("Platform subclasses must implement cast_fp_tensor") 

1674 

1675 def apply_to_tensors(self, fn, container): 

1676 """Recursively apply a function to all tensors in a container. 

1677 

1678 Supports nested structures including lists, tuples, and dicts. 

1679 

1680 Args: 

1681 fn (callable): Function to apply to each tensor. 

1682 container: Nested structure containing tensors. 

1683 

1684 Returns: 

1685 The same structure with fn applied to all tensors. 

1686 """ 

1687 raise NotImplementedError("Platform subclasses must implement apply_to_tensors") 

1688 

1689 @staticmethod 

1690 def clip_grad_norm_( 

1691 parameters, max_norm: float, norm_type: float = 2.0, 

1692 error_if_nonfinite: bool = False, foreach=None, 

1693 ): 

1694 """Compute and clip gradient norms for distributed models. 

1695 

1696 Communication is derived from each parameter's DTensor spec. 

1697 Subclasses must implement this method. 

1698 

1699 Args: 

1700 parameters: An ``nn.Module``, a single ``Tensor``, or an 

1701 iterable of ``Tensor`` s whose gradients to clip. 

1702 max_norm: Maximum allowed gradient norm. 

1703 norm_type: Type of the norm (default ``2.0``). 

1704 error_if_nonfinite: If ``True``, raise when total norm is 

1705 non-finite. Default ``False``. 

1706 foreach: Unused, accepted for API compatibility. 

1707 

1708 Returns: 

1709 The total (unclipped) gradient norm. 

1710 """ 

1711 raise NotImplementedError( 

1712 "Platform subclasses must implement clip_grad_norm_" 

1713 ) 

1714 

1715 @staticmethod 

1716 def get_created_group(rank_list: Union[list[int], tuple[int]]): 

1717 """Get an existing process group by rank list. 

1718 

1719 Args: 

1720 rank_list (Union[list[int], tuple[int]]): Tuple or list of ranks. 

1721 

1722 Returns: 

1723 The process group corresponding to the rank list if it exists, else None. 

1724 """ 

1725 group_key = str(tuple(sorted(rank_list))) 

1726 if group_key in EXISTING_COMM_GROUPS: 

1727 return EXISTING_COMM_GROUPS[group_key] 

1728 return None 

1729 

1730 @classmethod 

1731 def mark_created_groups(cls, process_group: Union[Any, list[Any]]) -> None: 

1732 """Register process groups in the global cache for reuse. 

1733 

1734 Args: 

1735 process_group (Union[Any, list[Any]]): A process group or a list of process groups. 

1736 """ 

1737 if not isinstance(process_group, list): 

1738 process_group = [process_group] 

1739 for group in process_group: 

1740 rank_list = cls.get_process_group_ranks(group) 

1741 group_key = str(tuple(sorted(rank_list))) 

1742 EXISTING_COMM_GROUPS[group_key] = group 

1743 

1744 @property 

1745 def meta_device(self): 

1746 """Get the framework-specific meta device for tensor shape inference. 

1747 

1748 The meta device allows creating tensors without allocating actual storage, 

1749 useful for shape inference and model initialization. 

1750 

1751 Returns: 

1752 The meta device object for the current framework. 

1753 """ 

1754 raise NotImplementedError("Platform subclasses must implement meta_device") 

1755 

1756 def init_on_device(self, device, include_buffers=False): 

1757 """Get a context manager for initializing module parameters on a device. 

1758 

1759 Args: 

1760 device: The target device for parameter initialization. 

1761 include_buffers (bool): If True, also initialize buffers on the device. 

1762 

1763 Returns: 

1764 A context manager for device-specific initialization. 

1765 """ 

1766 raise NotImplementedError("Platform subclasses must implement init_on_device") 

1767 

1768 def str_to_dtype(self, dtype_str: str) -> Any: 

1769 """ 

1770 Map a framework-style dtype string (e.g. ``torch.float32``) to the backend dtype object. 

1771 

1772 Args: 

1773 dtype_str (str): Serialized dtype identifier produced by checkpoint metadata. 

1774 

1775 Returns: 

1776 Framework dtype object (e.g. ``torch.dtype`` or MindSpore dtype). 

1777 """ 

1778 raise NotImplementedError("Platform subclasses must implement str_to_dtype") 

1779 

1780 def list_to_size(self, size_list: list[int]) -> Any: 

1781 """ 

1782 Convert a shape list from checkpoint metadata to the framework's size type (e.g. ``torch.Size``). 

1783 

1784 Args: 

1785 size_list (list[int]): Tensor global shape as a list of ints. 

1786 

1787 Returns: 

1788 Framework-specific size object. 

1789 """ 

1790 raise NotImplementedError("Platform subclasses must implement list_to_size")