Coverage for  / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / core / distributed_checkpoint / standard_planner.py: 80%

284 statements  

« 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"""Standard planner implementations for checkpoint save and load.""" 

16from dataclasses import dataclass 

17import dataclasses 

18import pickle 

19from typing import Any, Optional, Union 

20 

21from hyper_parallel.core.distributed_checkpoint.metadata import ( 

22 CHUNK_INFO, 

23 Metadata, 

24 MetadataIndex, 

25 ChunkStorageMetadata, 

26 ChunkInfo, 

27 TensorStorageMetadata, 

28 TensorProperties, 

29 BytesStorageMetadata 

30) 

31from hyper_parallel.core.distributed_checkpoint.planner import ( 

32 SavePlan, 

33 SavePlanner, 

34 LoadPlan, 

35 LoadPlanner, 

36 WriteItem, 

37 WriteItemType, 

38 ReadItem, 

39 LoadItemType 

40) 

41from hyper_parallel.core.distributed_checkpoint.reshard import infer_intersection 

42from hyper_parallel.core.distributed_checkpoint.ragged_utils import ( 

43 create_ragged_write_items, 

44 get_ragged_box_tensor, 

45) 

46from hyper_parallel.core.distributed_checkpoint.util import ( 

47 narrow_tensor_by_index, 

48 chunk_to_area, 

49 create_chunk_list_for_tensor, 

50 remove_redundant_plans, 

51 flatten_state_dict, 

52 set_element, 

53) 

54from hyper_parallel.core.dtensor.dtensor import DTensor 

55from hyper_parallel.core.dtensor.layout import Layout, infer_slice_area_by_layout 

56from hyper_parallel.platform import get_platform 

57 

58platform = get_platform() 

59Tensor = platform.Tensor 

60 

61 

62@dataclass(frozen=True) 

63class CachedSaveResult: 

64 """Cached finalized save result keyed by planner cache namespace.""" 

65 

66 final_plan: SavePlan 

67 metadata: Metadata 

68 

69 

70class StandardSavePlanner(SavePlanner): 

71 """Standard implementation of SavePlanner for distributed checkpoint saving.""" 

72 

73 _cached_save_result: dict[str, CachedSaveResult] = {} 

74 

75 def __init__( 

76 self, 

77 enable_plan_caching: bool = True, 

78 remove_redundancy: bool = True, 

79 save_to_minimum_rank: bool = False, 

80 ): 

81 self.state_dict: Optional[dict[str, Any]] = None 

82 self.is_coordinator: bool = False 

83 self.rank: int = 0 

84 self.remove_redundancy: bool = remove_redundancy 

85 self.save_to_minimum_rank: bool = save_to_minimum_rank 

86 self.flatten_state_dict: bool = True 

87 self._enable_plan_caching: bool = enable_plan_caching 

88 self._default_enable_plan_caching: bool = enable_plan_caching 

89 self._cached_plans_key: str = self.__class__.__name__ 

90 

91 def configure_planner(self, state_dict: dict[str, Any], **kwargs) -> None: 

92 """ 

93 Configure planner. 

94 

95 Args: 

96 state_dict (dict[str, Any]): The state_dict to save. 

97 **kwargs: Additional keyword arguments (e.g., is_coordinator, rank, remove_redundancy, 

98 save_to_minimum_rank). 

99 """ 

100 self.is_coordinator = kwargs.get("is_coordinator", False) 

101 self.rank = kwargs.get("rank", 0) 

102 self.remove_redundancy = kwargs.get("remove_redundancy", self.remove_redundancy) 

103 self.save_to_minimum_rank = kwargs.get("save_to_minimum_rank", self.save_to_minimum_rank) 

104 self.flatten_state_dict = kwargs.get("flatten_state_dict", True) 

105 

106 use_collectives = bool(kwargs.get("use_collectives", True)) 

107 self._enable_plan_caching = bool( 

108 kwargs.get("enable_plan_caching", self._default_enable_plan_caching) 

109 ) 

110 if not use_collectives: 

111 self.remove_redundancy = False 

112 self._enable_plan_caching = False 

113 

114 if self.flatten_state_dict: 

115 state_dict, self.name_mapping = flatten_state_dict(state_dict) 

116 self.state_dict = state_dict 

117 if any( 

118 isinstance(obj, DTensor) 

119 and obj.layout is not None 

120 and obj.layout.ragged_shard is not None 

121 for obj in state_dict.values() 

122 ): 

123 self._enable_plan_caching = False 

124 self._cached_plans_key = self._build_cache_key(state_dict) 

125 

126 def _build_cache_key(self, state_dict: dict[str, Any]) -> str: 

127 """Build a stable cache namespace from sorted state_dict keys.""" 

128 return f"{self.__class__.__name__}:{'||'.join(state_dict.keys())}" 

129 

130 def build_local_plan(self) -> SavePlan: 

131 """ 

132 Create local save plan. 

133 

134 Returns: 

135 SavePlan: Local save plan containing WriteItems for this rank. 

136 """ 

137 if self.state_dict is None: 

138 raise RuntimeError("Planner not set up") 

139 

140 def compute_global_offsets(global_shape: tuple[int, ...], dtensor_layout: Layout) -> tuple[int, ...]: 

141 """ 

142 Compute the offsets of local tensor in global tensor based on layout. 

143 

144 Args: 

145 global_shape (tuple[int, ...]): Global shape of the tensor. 

146 dtensor_layout (Layout): Layout of the DTensor. 

147 

148 Returns: 

149 tuple[int, ...]: Tuple of offsets for each dimension. 

150 """ 

151 if dtensor_layout is None: 

152 # If layout is None, return all zeros (no sharding) 

153 return tuple(0 for _ in global_shape) 

154 

155 # Validate layout attributes 

156 if not hasattr(dtensor_layout, 'mesh_shape') or dtensor_layout.mesh_shape is None: 

157 raise ValueError("Layout must have mesh_shape attribute") 

158 if not hasattr(dtensor_layout, 'tensor_map') or dtensor_layout.tensor_map is None: 

159 raise ValueError("Layout must have tensor_map attribute") 

160 if not hasattr(dtensor_layout, 'rank_list') or dtensor_layout.rank_list is None: 

161 raise ValueError("Layout must have rank_list attribute") 

162 

163 current_rank = self.rank 

164 if current_rank not in dtensor_layout.rank_list: 

165 raise ValueError( 

166 f"Current rank {current_rank} not found in layout's rank_list {dtensor_layout.rank_list}") 

167 

168 inner_rank_id = dtensor_layout.rank_list.index(current_rank) 

169 # Calculate slice area using infer_slice_area_by_rank 

170 slice_area = infer_slice_area_by_layout( 

171 dtensor_layout, 

172 inner_rank_id, 

173 global_shape, 

174 ) 

175 # Extract offsets (start values) from slice_area 

176 return tuple(start for start, _ in slice_area) 

177 

178 items = [] 

179 for fqn, obj in self.state_dict.items(): 

180 # Check if it's a DTensor 

181 if isinstance(obj, DTensor): 

182 if obj.layout is not None and obj.layout.ragged_shard is not None: 

183 items.extend(create_ragged_write_items(fqn, obj)) 

184 continue 

185 # Create write item for DTensor 

186 local_tensor = obj.to_local() 

187 layout = obj.layout 

188 

189 # Get chunk metadata with offsets 

190 if layout: 

191 offsets = compute_global_offsets(obj.shape, layout) 

192 else: 

193 offsets = (0,) * len(local_tensor.shape) 

194 

195 sizes = local_tensor.shape 

196 chunk = ChunkStorageMetadata(offsets=offsets, sizes=sizes) 

197 # Get tensor properties 

198 dtype_str = str(local_tensor.dtype) if hasattr(local_tensor, 'dtype') else 'unknown' 

199 properties = TensorProperties(dtype=dtype_str) 

200 # Create write item for this tensor 

201 index = MetadataIndex(fqn=fqn, offset=offsets, index=None) 

202 write_item = WriteItem( 

203 index=index, 

204 type=WriteItemType.TENSOR, 

205 tensor_data={ 

206 'chunk': chunk, 

207 'properties': properties, 

208 'size': obj.shape, 

209 } 

210 ) 

211 items.append(write_item) 

212 elif isinstance(obj, Tensor): 

213 # Create write item for platform.Tensor: build single chunk with tensor's own size 

214 dtype_str = str(obj.dtype) if hasattr(obj, 'dtype') else 'unknown' 

215 properties = TensorProperties(dtype=dtype_str) 

216 # handle Tensor with shard information 

217 if hasattr(obj, CHUNK_INFO): 

218 if not isinstance(getattr(obj, CHUNK_INFO), ChunkInfo): 

219 raise ValueError("The attr CHUNK_INFO should be a ChunkInfo instance") 

220 chunk = getattr(obj, CHUNK_INFO).chunk 

221 # Single chunk covering the whole tensor (offsets=0, sizes=shape) 

222 else: 

223 chunk = ChunkStorageMetadata( 

224 offsets=(0,) * len(obj.shape), 

225 sizes=obj.shape, 

226 ) 

227 index = MetadataIndex(fqn=fqn, offset=chunk.offsets, index=None) 

228 write_item = WriteItem( 

229 index=index, 

230 type=WriteItemType.TENSOR, 

231 tensor_data={ 

232 'chunk': chunk, 

233 'properties': properties, 

234 'size': getattr(obj, CHUNK_INFO).global_shape if hasattr(obj, CHUNK_INFO) else obj.shape, 

235 } 

236 ) 

237 items.append(write_item) 

238 else: 

239 # Handle non-tensor types (bytes, etc.) 

240 index = MetadataIndex(fqn=fqn) 

241 write_item = WriteItem( 

242 index=index, 

243 type=WriteItemType.BYTE_IO, 

244 bytes_io_data=None 

245 ) 

246 items.append(write_item) 

247 

248 plan = SavePlan(items=items) 

249 if self.flatten_state_dict: 

250 plan.planner_data = self.name_mapping 

251 return plan 

252 

253 def build_global_plan(self, all_plans: list[SavePlan]) -> tuple[list[SavePlan], Metadata]: 

254 """ 

255 Build global plan from all local plans. 

256 

257 Collects chunks from all ranks, validates consistency, and creates metadata for the checkpoint. 

258 

259 Args: 

260 all_plans (list[SavePlan]): List of local plans from all ranks. 

261 

262 Returns: 

263 tuple[list[SavePlan], Metadata]: Updated plans and checkpoint metadata. 

264 """ 

265 # Deduplicate plans if redundancy removal is enabled 

266 if self.remove_redundancy and len(all_plans) > 1: 

267 all_plans = remove_redundant_plans(all_plans, save_to_minimum_rank=self.save_to_minimum_rank) 

268 

269 # Collect all write items by FQN 

270 fqn_to_chunks: dict[str, list[ChunkStorageMetadata]] = {} 

271 fqn_to_properties: dict[str, TensorProperties] = {} 

272 fqn_to_size: dict[str, tuple] = {} 

273 state_dict_metadata: dict[str, Union[TensorStorageMetadata, BytesStorageMetadata]] = {} 

274 

275 final_global_plans: list[SavePlan] = [] 

276 for plan in all_plans: 

277 with_index_items = [] 

278 for item in plan.items: 

279 if item.type == WriteItemType.TENSOR and item.tensor_data: 

280 fqn = item.index.fqn 

281 chunk = item.tensor_data['chunk'] 

282 properties = item.tensor_data['properties'] 

283 size = item.tensor_data['size'] 

284 

285 # Validate consistency across ranks 

286 if fqn in fqn_to_chunks and (fqn_to_properties[fqn] != properties or fqn_to_size[fqn] != size): 

287 raise ValueError(f"The {fqn} in different rank has different properties and size.") 

288 

289 # Initialize FQN entry if not exists 

290 if fqn not in fqn_to_chunks: 

291 fqn_to_properties[fqn] = properties 

292 fqn_to_size[fqn] = size 

293 fqn_to_chunks[fqn] = [] 

294 

295 # Append chunk and set index (platform.Tensor has exactly one chunk) 

296 new_index = dataclasses.replace(item.index, index=len(fqn_to_chunks[fqn])) 

297 with_index_item = dataclasses.replace(item, index=new_index) 

298 with_index_items.append(with_index_item) 

299 fqn_to_chunks[fqn].append(chunk) 

300 

301 elif item.type == WriteItemType.BYTE_IO: 

302 with_index_items.append(item) 

303 state_dict_metadata[item.index.fqn] = BytesStorageMetadata() 

304 else: 

305 raise ValueError(f"Unsupported write item type: {item.type}") 

306 

307 final_global_plans.append(dataclasses.replace(plan, items=with_index_items)) 

308 

309 # Create metadata for all tensors 

310 for fqn, chunks in fqn_to_chunks.items(): 

311 state_dict_metadata[fqn] = TensorStorageMetadata( 

312 properties=fqn_to_properties[fqn], 

313 size=fqn_to_size[fqn], 

314 chunks=chunks 

315 ) 

316 

317 metadata = Metadata(state_dict_metadata=state_dict_metadata) 

318 if self.flatten_state_dict: 

319 merged_mapping = {} 

320 for p in all_plans: 

321 merged_mapping.update(p.planner_data) 

322 metadata.planner_data = merged_mapping 

323 return final_global_plans, metadata 

324 

325 def finalize_plan(self, plan: SavePlan) -> SavePlan: 

326 """ 

327 Finalize the plan. 

328 

329 Args: 

330 plan (SavePlan): Plan to finalize. 

331 

332 Returns: 

333 SavePlan: Finalized plan. 

334 """ 

335 return plan 

336 

337 def get_cached(self) -> Optional[CachedSaveResult]: 

338 """Return cached finalized plan and metadata when plan caching is enabled.""" 

339 if ( 

340 not self._enable_plan_caching 

341 or self._cached_plans_key not in StandardSavePlanner._cached_save_result 

342 ): 

343 return None 

344 return StandardSavePlanner._cached_save_result[self._cached_plans_key] 

345 

346 def cache_result(self, final_plan: SavePlan, metadata: Metadata) -> None: 

347 """Store finalized plan and metadata in the class-level planner cache.""" 

348 if not self._enable_plan_caching: 

349 return 

350 StandardSavePlanner._cached_save_result[self._cached_plans_key] = CachedSaveResult( 

351 final_plan=final_plan, 

352 metadata=metadata, 

353 ) 

354 

355 def get_data(self, item: WriteItem) -> Any: 

356 """ 

357 Get current runtime data from state_dict for a write item. 

358 

359 Args: 

360 item (WriteItem): Write item describing what to write. 

361 

362 Returns: 

363 Any: Runtime object to be written. 

364 """ 

365 if self.state_dict is None: 

366 raise RuntimeError("Planner not set up") 

367 fqn = item.index.fqn 

368 if fqn not in self.state_dict: 

369 raise KeyError(f"Key {fqn} not found in state_dict") 

370 obj = self.state_dict[fqn] 

371 if item.type == WriteItemType.TENSOR: 

372 if isinstance(obj, DTensor): 

373 if obj.layout is not None and obj.layout.ragged_shard is not None: 

374 return get_ragged_box_tensor(obj, item.index).detach().cpu() 

375 return obj.to_local().detach().cpu() 

376 if isinstance(obj, Tensor): 

377 return obj.detach().cpu() 

378 raise TypeError(f"Write item {fqn} expected tensor-like object, got {type(obj)}") 

379 if item.type == WriteItemType.BYTE_IO: 

380 return obj 

381 raise TypeError(f"Unsupported write item type: {item.type}") 

382 

383 

384def create_read_items_for_chunk_list( 

385 fqn: str, 

386 checkpoint_md: TensorStorageMetadata, 

387 local_chunks: list[ChunkStorageMetadata], 

388) -> list[ReadItem]: 

389 """ 

390 Create ReadItems by matching local chunks (what this rank needs) with 

391 saved chunks (checkpoint_md.chunks), including resharding overlaps. 

392 

393 Mirrors torch create_read_items_for_chunk_list behavior. 

394 

395 Args: 

396 fqn (str): Fully qualified name of the tensor. 

397 checkpoint_md (TensorStorageMetadata): Tensor storage metadata from checkpoint. 

398 local_chunks (list[ChunkStorageMetadata]): List of local chunks needed by this rank. 

399 

400 Returns: 

401 list[ReadItem]: List of ReadItems for loading the required data. 

402 """ 

403 read_items: list[ReadItem] = [] 

404 saved_chunks = checkpoint_md.chunks 

405 if not local_chunks or not saved_chunks: 

406 return read_items 

407 

408 for local_idx, local_chunk in enumerate(local_chunks): 

409 local_area = chunk_to_area(local_chunk) 

410 for storage_idx, storage_chunk in enumerate(saved_chunks): 

411 saved_area = chunk_to_area(storage_chunk) 

412 overlap = infer_intersection(local_area, saved_area) 

413 if overlap is None: 

414 continue 

415 

416 dest_offsets = tuple(overlap[i][0] - local_chunk.offsets[i] for i in range(len(overlap))) 

417 storage_offsets = tuple(overlap[i][0] - storage_chunk.offsets[i] for i in range(len(overlap))) 

418 lengths = tuple(overlap[i][1] - overlap[i][0] for i in range(len(overlap))) 

419 

420 read_items.append( 

421 ReadItem( 

422 type=LoadItemType.TENSOR, 

423 dest_index=MetadataIndex(fqn=fqn, offset=local_chunk.offsets, index=local_idx), 

424 dest_offsets=dest_offsets, 

425 storage_index=MetadataIndex(fqn=fqn, offset=storage_chunk.offsets, index=storage_idx), 

426 storage_offsets=storage_offsets, 

427 lengths=lengths, 

428 ) 

429 ) 

430 return read_items 

431 

432 

433class StandardLoadPlanner(LoadPlanner): 

434 """ 

435 Standard implementation of LoadPlanner. 

436 

437 Iterate state_dict and creates load plans via chunk list for resharding support. 

438 """ 

439 

440 def __init__(self, allow_partial_load: bool = False): 

441 """ 

442 Args: 

443 allow_partial_load (bool): If True, allow loading when checkpoint has fewer keys than state_dict. 

444 Default False. 

445 """ 

446 self.state_dict: Optional[dict[str, Any]] = None 

447 self.metadata: Optional[Metadata] = None 

448 self.is_coordinator: bool = False 

449 self.rank: int = 0 

450 self.allow_partial_load = allow_partial_load 

451 self.flatten_state_dict: bool = True 

452 

453 def configure_planner(self, state_dict: dict[str, Any], metadata: Metadata, **kwargs) -> None: 

454 """ 

455 Configure planner with state dict and metadata. 

456 

457 Args: 

458 state_dict (dict[str, Any]): The state_dict to load into (modified in-place). 

459 metadata (Metadata): Checkpoint metadata. 

460 **kwargs: Additional keyword arguments (e.g., is_coordinator, rank). 

461 """ 

462 self.state_dict = state_dict 

463 self.metadata = metadata 

464 self.is_coordinator = kwargs.get("is_coordinator", False) 

465 self.rank = kwargs.get("rank", 0) 

466 self.flatten_state_dict = kwargs.get("flatten_state_dict", True) 

467 self.original_state_dict = state_dict 

468 if self.flatten_state_dict: 

469 state_dict, self.name_mapping = flatten_state_dict(state_dict) 

470 self.state_dict = state_dict 

471 

472 def build_local_plan(self) -> LoadPlan: 

473 """ 

474 Build local load plan. 

475 

476 Iterate state_dict and creates load plans via chunk list for resharding support. 

477 

478 Returns: 

479 LoadPlan: Local load plan containing ReadItems for this rank. 

480 """ 

481 if self.state_dict is None or self.metadata is None: 

482 raise RuntimeError("Planner not configured") 

483 

484 requests: list[ReadItem] = [] 

485 strict = not self.allow_partial_load 

486 for fqn, obj in self.state_dict.items(): 

487 if fqn not in self.metadata.state_dict_metadata: 

488 if fqn.endswith(('matched_adamw_rms', 'step')): 

489 continue 

490 if strict: 

491 raise RuntimeError(f"Missing key in checkpoint state_dict: {fqn}.") 

492 continue 

493 md = self.metadata.state_dict_metadata[fqn] 

494 if isinstance(md, TensorStorageMetadata): 

495 obj_size = getattr(obj, CHUNK_INFO).global_shape if hasattr(obj, CHUNK_INFO) \ 

496 else getattr(obj, "shape", None) 

497 if obj_size is None or md.size != tuple(obj_size): 

498 raise ValueError( 

499 f"Size mismatch between saved {md.size} and current: {obj_size} for {fqn}", 

500 ) 

501 if isinstance(obj, DTensor): 

502 layout = getattr(obj, "layout", None) 

503 rank_list = getattr(layout, "rank_list", None) if layout else None 

504 if rank_list is None and layout is not None: 

505 rank_list = getattr(layout, "_rank_list", None) 

506 if layout is not None and rank_list is not None: 

507 if get_platform().get_rank() not in rank_list: 

508 continue 

509 # Both DTensor and platform.Tensor: create local chunks and read items 

510 local_chunks = create_chunk_list_for_tensor(obj) 

511 requests += create_read_items_for_chunk_list(fqn, md, local_chunks) 

512 else: 

513 requests.append( 

514 ReadItem( 

515 type=LoadItemType.BYTE_IO, 

516 dest_index=MetadataIndex(fqn=fqn), 

517 dest_offsets=(0,), 

518 storage_index=MetadataIndex(fqn=fqn), 

519 storage_offsets=(0,), 

520 lengths=(0,), 

521 ) 

522 ) 

523 return LoadPlan(items=requests) 

524 

525 def build_global_plan(self, all_plans: list[LoadPlan]) -> list[LoadPlan]: 

526 """ 

527 Build global plan from all local plans. 

528 

529 For now, returns plans as-is. In a more sophisticated implementation, you might need to coordinate across ranks. 

530 

531 Args: 

532 all_plans (list[LoadPlan]): List of local plans from all ranks. 

533 

534 Returns: 

535 list[LoadPlan]: Global plans (currently returns plans as-is). 

536 """ 

537 return all_plans 

538 

539 def finalize_plan(self, plan: LoadPlan) -> LoadPlan: 

540 """ 

541 Finalize the plan (no-op for default implementation). 

542 

543 Args: 

544 plan (LoadPlan): Plan to finalize. 

545 

546 Returns: 

547 LoadPlan: Finalized plan. 

548 """ 

549 return plan 

550 

551 def acquire_tensor(self, read_item: ReadItem) -> Any: 

552 """ 

553 Acquire the destination slice (narrow view) for this read_item. 

554 

555 StorageReader uses this to copy loaded data into the correct region. 

556 Torch-aligned behavior. 

557 

558 Args: 

559 read_item (ReadItem): The read item specifying what to load. 

560 

561 Returns: 

562 Any: The destination tensor slice where data should be written 

563 (tensor-like object). 

564 """ 

565 if self.state_dict is None: 

566 raise RuntimeError("Planner not configured") 

567 

568 fqn = read_item.dest_index.fqn 

569 if fqn not in self.state_dict: 

570 raise KeyError(f"Key {fqn} not found in state_dict") 

571 

572 target = self.state_dict[fqn] 

573 if ( 

574 isinstance(target, DTensor) 

575 and target.layout is not None 

576 and target.layout.ragged_shard is not None 

577 ): 

578 box_tensor = get_ragged_box_tensor(target, read_item.dest_index) 

579 return narrow_tensor_by_index( 

580 box_tensor, 

581 read_item.dest_offsets, 

582 read_item.lengths, 

583 ) 

584 

585 local_tensor = target.to_local().detach() if isinstance(target, DTensor) else target.detach() 

586 return narrow_tensor_by_index( 

587 local_tensor, 

588 read_item.dest_offsets, 

589 read_item.lengths, 

590 ) 

591 

592 def apply_tensor(self, read_item: ReadItem, tensor: Any) -> None: 

593 """ 

594 Apply tensor after reading. 

595 

596 After read_data copies into the slice, this is no-op when tensor is the 

597 same slice. When the backend has no copy_ (e.g. mindspore), read_data 

598 passes the loaded slice here; we copy it into the destination slice. 

599 

600 Args: 

601 read_item (ReadItem): The read item that was processed. 

602 tensor (Any): The tensor data to apply (tensor-like object). 

603 """ 

604 if tensor is None: 

605 return 

606 dest_slice = self.acquire_tensor(read_item) 

607 if dest_slice is tensor: 

608 return 

609 if hasattr(dest_slice, "copy_"): 

610 dest_slice.copy_(tensor) 

611 else: 

612 # Fallback: assign into state_dict if supported 

613 dest_slice[...] = tensor 

614 

615 def apply_bytes(self, read_item: ReadItem, value: bytes) -> None: 

616 """ 

617 Load bytes data into state_dict. 

618 

619 Args: 

620 read_item (ReadItem): The read item specifying the destination. 

621 value (bytes): The bytes data to deserialize and load. 

622 """ 

623 if self.state_dict is None: 

624 raise RuntimeError("Planner not set up") 

625 

626 fqn = read_item.dest_index.fqn 

627 # Deserialize bytes 

628 obj = pickle.loads(value) 

629 self.state_dict[fqn] = obj 

630 if self.flatten_state_dict: 

631 set_element(self.original_state_dict, self.name_mapping[fqn], obj) 

632 

633 

634 

635class _DcpMergeLoadPlanner(StandardLoadPlanner): 

636 """Load planner that builds distributed checkpoint from dcp into fully ``state_dict`` (in-place).""" 

637 

638 def __init__(self) -> None: 

639 super().__init__() 

640 

641 def configure_planner(self, state_dict: dict[str, Any], metadata: Metadata, **kwargs) -> None: 

642 if len(state_dict) > 0: 

643 raise ValueError( 

644 "state_dict must be empty for _DcpMergeLoadPlanner; " 

645 "it is populated in-place from checkpoint metadata." 

646 ) 

647 

648 if metadata is None: 

649 raise ValueError("metadata must not be None for _DcpMergeLoadPlanner.") 

650 

651 self.is_coordinator = kwargs.get("is_coordinator", False) 

652 for k, v in metadata.state_dict_metadata.items(): 

653 if isinstance(v, TensorStorageMetadata): 

654 v = platform.empty( 

655 platform.list_to_size(v.size), 

656 dtype=platform.str_to_dtype(v.properties.dtype), 

657 ) 

658 

659 state_dict[k] = v 

660 if metadata.planner_data is not None and k in metadata.planner_data: 

661 set_element(state_dict, metadata.planner_data[k], v) 

662 

663 super().configure_planner( 

664 state_dict, 

665 metadata, 

666 is_coordinator=self.is_coordinator, 

667 flatten_state_dict=True, 

668 )