Coverage for  / home / jenkins / .local / lib / python3.10 / site-packages / hyper_parallel / distributed / _builder / forward_rewriter.py: 76%

498 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-10-25 05:45 +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# pylint: disable=missing-apache-license-header,forbidden-backend-import 

16"""forward_rewriter: forward-mutation machinery for the sharding applier. 

17 

18All boundary forward generation, validation and installation lives here: 

19the injection signature validators (4b seed), the bias-suppression / 

20deferred-bias forwards, the production/validate boundary wrappers, the 

21MoE local-region wrapper, the CP inner-attention adapter, and the D-02 

22vocab-parallel embedding wrapper. 

23 

24This module is the ONLY place in repo-owned code that assigns 

25``module.forward`` (AST gate, 05 §15.2.3): every other module returns a 

26replacement callable or a private :class:`_ForwardRewriteRequest`, and the 

27rewriter performs signature validation, installation and failure rollback. 

28The local-compute descendant adapters 

29(``install_local_compute_forward_adapters``) also live here; 

30``local_compute_context.py`` keeps only the region state. Qwen model-family 

31forward mutations remain in their transitional homes until changesets 

32M2/M3 (auto_models_adjust.md §5.3). 

33""" 

34 

35import functools 

36import inspect 

37import logging 

38import types 

39import weakref 

40from typing import Any, Callable, List, Optional, Sequence, Union 

41 

42import torch 

43from torch import nn 

44 

45from hyper_parallel.core.dtensor.dtensor import DTensor 

46from hyper_parallel.core.dtensor.device_mesh import DeviceMesh 

47from hyper_parallel.core.dtensor.placement_types import Shard 

48from hyper_parallel.distributed.recipe_spec import ( 

49 INNER_WRAPPER, 

50 PlacementMismatchError, 

51 require_injection_meta, 

52 resolve_placements, 

53) 

54from hyper_parallel.distributed._builder.local_compute_context import ( 

55 _LOCAL_COMPUTE_ACTIVE, # pylint: disable=protected-access 

56 local_compute_context, 

57) 

58from hyper_parallel.distributed._builder.parameter_sharding import ( 

59 _temp_local_params, 

60) 

61from hyper_parallel.distributed._builder.rule_resolver import ( 

62 _inner_target_name, 

63 _resolve_inner_output_placements, 

64 _resolve_inner_wrapper, 

65) 

66from hyper_parallel.distributed.tensor_parallel.head_count import ( 

67 maybe_update_head_counts, 

68) 

69 

70logger = logging.getLogger(__name__) 

71 

72 

73# ──────────────────────────────────────────────────────────────────────────── 

74# Runtime-layer signature validation (principle 1: the injected function's 

75# arguments must match the original function's) 

76# ──────────────────────────────────────────────────────────────────────────── 

77 

78def _is_subsequence(sub: List[str], full: List[str]) -> bool: 

79 """Return True if ``sub`` is an in-order subsequence of ``full``.""" 

80 it = iter(full) 

81 return all(name in it for name in sub) 

82 

83 

84def _compute_parameters(compute_fn: Callable[..., Any], owner: str) -> List[inspect.Parameter]: 

85 """Return the declared compute parameters after its module argument.""" 

86 try: 

87 params = list(inspect.signature(compute_fn).parameters.values()) 

88 except (TypeError, ValueError) as exc: 

89 raise TypeError(f"{owner}: cannot introspect the signature of the injected compute fn") from exc 

90 if not params: 

91 raise TypeError( 

92 f"{owner}: a compute fn needs at least the module first " 

93 "parameter -- the contract is fn(module, *forward_args)" 

94 ) 

95 return params[1:] 

96 

97 

98def _validate_explicit_compute_parameters(params: List[inspect.Parameter], owner: str) -> None: 

99 """Reject variadic compute parameters that hide signature mismatches.""" 

100 for param in params: 

101 if param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD): 

102 raise TypeError( 

103 f"{owner}: a compute fn must not use *args/**kwargs " 

104 f"(parameter {param.name!r}) -- its arguments must explicitly " 

105 "match the original forward" 

106 ) 

107 

108 

109def _validate_compute_parameter_names( 

110 fn_params: List[inspect.Parameter], 

111 fwd_params: List[inspect.Parameter], 

112 owner: str, 

113) -> None: 

114 """Validate compute parameter names and positional ordering.""" 

115 fwd_names = { 

116 param.name 

117 for param in fwd_params 

118 if param.kind not in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD) 

119 } 

120 for param in fn_params: 

121 if param.name not in fwd_names: 

122 raise TypeError( 

123 f"{owner}: compute-fn parameter {param.name!r} has no " 

124 f"same-named entry among the original forward parameters {sorted(fwd_names)} -- " 

125 "the injected function's arguments must match the original function's " 

126 "(the skeleton forwards the actual forward arguments, so a name mismatch " 

127 "becomes a runtime TypeError)" 

128 ) 

129 positional_kinds = (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD) 

130 fwd_pos = [param.name for param in fwd_params if param.kind in positional_kinds] 

131 fn_pos = [param.name for param in fn_params if param.kind in positional_kinds] 

132 if not _is_subsequence(fn_pos, fwd_pos): 

133 raise TypeError( 

134 f"{owner}: the compute fn's positional parameters {fn_pos} are not an in-order subsequence " 

135 f"of the original forward's positional parameters {fwd_pos} -- the skeleton forwards " 

136 "arguments positionally, so a reordering would bind them wrong" 

137 ) 

138 

139 

140def _validate_required_compute_parameters( 

141 fn_params: List[inspect.Parameter], 

142 fwd_params: List[inspect.Parameter], 

143 owner: str, 

144) -> None: 

145 """Require the compute function to accept every required forward parameter.""" 

146 fn_names = {param.name for param in fn_params} 

147 required = [] 

148 for param in fwd_params: 

149 if param.default is not inspect.Parameter.empty: 

150 continue 

151 if param.kind in (inspect.Parameter.VAR_POSITIONAL, inspect.Parameter.VAR_KEYWORD): 

152 continue 

153 required.append(param.name) 

154 missing = [name for name in required if name not in fn_names] 

155 if missing: 

156 raise TypeError( 

157 f"{owner}: the original forward's required parameters {missing} are not accepted by the " 

158 "compute fn (the compute fn's declared arguments must cover the original function's required ones)" 

159 ) 

160 

161 

162def validate_local_compute_signature(compute_fn: Callable[..., Any], 

163 forward: Callable[..., Any], 

164 *, 

165 owner: str) -> None: 

166 """Validate that a regional compute fn's arguments match the original 

167 forward (fail-fast at apply time). 

168 

169 Rules (compute_fn's first parameter is module and forward's first 

170 parameter is self; both are skipped): 

171 1. The compute fn must not have *args/**kwargs (the skeleton forwards 

172 the actual forward arguments, and swallowing them would hide 

173 mismatches); 

174 2. Every compute-fn parameter must have a **same-named** parameter in 

175 forward (the skeleton forwards by kwarg, so a name mismatch is a 

176 runtime TypeError); 

177 3. The compute fn's positional-parameter sequence must be an in-order 

178 **subsequence** of forward's positional-parameter sequence 

179 (positional forwarding must not reorder); 

180 4. All required (defaultless) parameters of forward must be accepted by 

181 the compute fn. 

182 

183 Args: 

184 compute_fn: The compute fn returned by the @local_compute factory. 

185 forward: The original module forward being replaced. 

186 owner: Call-site label prepended to error messages. 

187 

188 Raises: 

189 TypeError: If any of the rules above is violated. 

190 """ 

191 fn_params = _compute_parameters(compute_fn, owner) 

192 _validate_explicit_compute_parameters(fn_params, owner) 

193 fwd_params = list(inspect.signature(forward).parameters.values()) 

194 _validate_compute_parameter_names(fn_params, fwd_params, owner) 

195 _validate_required_compute_parameters(fn_params, fwd_params, owner) 

196 

197 

198def validate_wrapped_forward(orig_forward: Callable[..., Any], 

199 new_forward: Callable[..., Any], 

200 *, 

201 owner: str) -> None: 

202 """Validate that the forward replaced by inner_wrapper can receive all 

203 arguments of the original forward. 

204 

205 A dummy-bind probe is constructed from the original signature 

206 (*args/**kwargs parameters cannot be forged and are skipped); the 

207 replacement side may pass through tolerantly with *args/**kwargs (it 

208 must forward arguments it does not care about to the original 

209 implementation), but every named parameter of the original forward must 

210 remain bindable by name. 

211 

212 Args: 

213 orig_forward: The original module forward. 

214 new_forward: The replacement forward installed by the wrapper. 

215 owner: Call-site label prepended to error messages. 

216 

217 Raises: 

218 TypeError: If the replacement signature cannot be introspected or 

219 cannot bind the original arguments. 

220 """ 

221 orig_sig = inspect.signature(orig_forward) 

222 try: 

223 new_sig = inspect.signature(new_forward, follow_wrapped=False) 

224 except (TypeError, ValueError) as exc: 

225 raise TypeError( 

226 f"{owner}: cannot introspect the signature of the forward " 

227 "replaced by the injected wrapper") from exc 

228 args, kwargs = [], {} 

229 for p in orig_sig.parameters.values(): 

230 if p.kind in (inspect.Parameter.VAR_POSITIONAL, 

231 inspect.Parameter.VAR_KEYWORD): 

232 continue 

233 if p.kind is inspect.Parameter.POSITIONAL_ONLY: 

234 args.append(None) 

235 else: 

236 # Probe POSITIONAL_OR_KEYWORD by name (kwarg) -- the 

237 # name-dimension contract is what the injection discipline 

238 # cares about; purely positional passing of optional positional 

239 # arguments is not required 

240 kwargs[p.name] = None 

241 try: 

242 new_sig.bind(*args, **kwargs) 

243 except TypeError as exc: 

244 raise TypeError( 

245 f"{owner}: the forward replaced by the injected wrapper is " 

246 f"incompatible with the original forward's arguments ({exc}) -- " 

247 f"original signature {orig_sig}, replacement signature {new_sig}; " 

248 "the replacement forward must be able to receive all arguments " 

249 "of the original forward (it may pass through tolerantly with " 

250 "*args/**kwargs)") from exc 

251 

252 

253# ──────────────────────────────────────────────────────────────────────────── 

254# Boundary forward wrapping: bias suppression / deferred bias (05 §4.4) 

255# ──────────────────────────────────────────────────────────────────────────── 

256 

257def _make_bias_free_forward(owner: nn.Module, original: Callable[..., Any]) -> Callable[..., Any]: 

258 """Create a forward wrapper that temporarily hides one module bias.""" 

259 

260 @functools.wraps(original) 

261 def bias_free_forward(*args: Any, **kwargs: Any) -> Any: 

262 """Run the owner's forward with its bias temporarily hidden.""" 

263 bias = owner.bias 

264 owner._parameters["bias"] = None # pylint: disable=protected-access 

265 try: 

266 return original(*args, **kwargs) 

267 finally: 

268 owner._parameters["bias"] = bias # pylint: disable=protected-access 

269 

270 return bias_free_forward 

271 

272 

273def _install_bias_suppression(module, spec): 

274 """D-22: make each defer-listed Linear run bias-free inside the region. 

275 

276 The bias Parameter itself is never touched (same FQN / same object / 

277 state_dict / optimizer unchanged); the wrapper only hides it from 

278 ``F.linear`` for the duration of the region forward, so the boundary 

279 exit's Partial reduction sees a pure matmul contribution and the bias is 

280 added exactly once afterwards by :func:`_maybe_add_deferred_biases`. 

281 Both modes install the same wrapper (instruction-for-instruction 

282 identity, D-01''); nesting the suppression is idempotent. 

283 """ 

284 for param_path in spec._deferred_bias_params: # pylint: disable=protected-access 

285 owner_path = param_path.rpartition(".")[0] 

286 owner = module.get_submodule(owner_path) if owner_path else module 

287 original = owner.forward 

288 owner.forward = _make_bias_free_forward(owner, original) 

289 

290 

291def _add_bias_to_primary_output(output, bias, module_name): 

292 """Add a deferred bias to the primary Tensor while preserving output structure.""" 

293 if isinstance(output, torch.Tensor): 

294 primary_output = output 

295 rebuild = None 

296 elif isinstance(output, (tuple, list)): 

297 if not output or not isinstance(output[0], torch.Tensor): 

298 primary_type = type(output[0]).__name__ if output else "missing" 

299 raise TypeError( 

300 f"{module_name}: deferred bias requires output index 0 to be a Tensor, " 

301 f"got {primary_type}" 

302 ) 

303 primary_output = output[0] 

304 rebuild = list(output) 

305 else: 

306 raise TypeError( 

307 f"{module_name}: deferred bias requires a Tensor, tuple, or list output, " 

308 f"got {type(output).__name__}" 

309 ) 

310 

311 if not isinstance(primary_output, DTensor) and isinstance(bias, DTensor): 

312 bias = bias.to_local() 

313 biased_output = primary_output + bias 

314 if rebuild is None: 

315 return biased_output 

316 rebuild[0] = biased_output 

317 return tuple(rebuild) if isinstance(output, tuple) else rebuild 

318 

319 

320def _maybe_add_deferred_biases(module, spec, output): 

321 """D-22: add each deferred bias exactly once AFTER the boundary exit. 

322 

323 The bias is read at forward time (never captured in a closure), so 

324 production sees the unwrapped local tensor and validate sees the DTensor 

325 — whichever form the boundary output currently has: nested validate keeps 

326 the DTensor (dispatch add, Shard(1)+Replicate→Shard(1)); the outermost / 

327 production / local-region exits are local, and a DTensor bias is 

328 unwrapped to match. For structured attention outputs, index 0 is the 

329 primary hidden-state Tensor; metadata/cache entries are preserved. 

330 """ 

331 if not spec._deferred_bias_params: # pylint: disable=protected-access 

332 return output 

333 for param_path in spec._deferred_bias_params: # pylint: disable=protected-access 

334 owner_path = param_path.rpartition(".")[0] 

335 owner = module.get_submodule(owner_path) if owner_path else module 

336 bias = owner.bias 

337 if bias is None: 

338 continue 

339 output = _add_bias_to_primary_output(output, bias, type(module).__name__) 

340 return output 

341 

342 

343def _unwrap_dtensor_outputs(output): 

344 """Return local tensors while preserving tuple/list output structure.""" 

345 if isinstance(output, DTensor): 

346 return output.to_local() 

347 if isinstance(output, tuple): 

348 return tuple(_unwrap_dtensor_outputs(item) for item in output) 

349 if isinstance(output, list): 

350 return [_unwrap_dtensor_outputs(item) for item in output] 

351 return output 

352 

353 

354# ──────────────────────────────────────────────────────────────────────────── 

355# Production/validate boundary wrappers and output-contract validation 

356# ──────────────────────────────────────────────────────────────────────────── 

357 

358def _keep_loss_parallel_output(plan, spec): 

359 """Return whether a terminal vocab-sharded output must remain a DTensor.""" 

360 if not plan.loss_parallel or not spec._is_terminal: # pylint: disable=protected-access 

361 return False 

362 output_placements = (spec.out_dst or {}).get("output", {}) 

363 return any( 

364 isinstance(placement, Shard) and placement.dim == -1 

365 for placement in output_placements.values() 

366 ) 

367 

368 

369def _descendant_boundary_fqns(plan, module_fqn): 

370 """Relative FQNs of boundaries nested inside *module_fqn* (D-14). 

371 

372 Returned relative to module_fqn (matching the name space of 

373 module.named_parameters(recurse=True)); the root spec (fqn "") treats 

374 every other boundary as a descendant. 

375 """ 

376 boundaries = [fqn for fqn, spec in plan.modules.items() if spec.is_boundary] 

377 if module_fqn == "": 

378 return [f for f in boundaries if f] 

379 prefix = module_fqn + "." 

380 return [f[len(prefix):] for f in boundaries if f.startswith(prefix)] 

381 

382 

383def _bind_input_indices(boundary, module): 

384 """Bind the arg_name of in_plan to the positional index of the forward signature. 

385 

386 Inter-module calls are mostly positional (self.mlp(x) inside a layer), so 

387 RedistOp's kwargs lookup by name would miss -- the signature index is bound 

388 at compile time, and at runtime _get_arg checks kwargs first, then args. 

389 """ 

390 try: 

391 sig = inspect.signature(module.forward) 

392 except (TypeError, ValueError): 

393 sig = None 

394 if sig is not None: 

395 positional = [ 

396 name for name, p in sig.parameters.items() 

397 if p.kind in (p.POSITIONAL_ONLY, p.POSITIONAL_OR_KEYWORD) 

398 ] 

399 name_to_idx = {name: i for i, name in enumerate(positional)} 

400 for op in boundary.in_plan: 

401 if op.arg_index is None and op.arg_name in name_to_idx: 

402 op.arg_index = name_to_idx[op.arg_name] 

403 # Positional fallback: a single-input contract (in_plan has only 1 op) is 

404 # bound to the first positional parameter -- covers cases where the 

405 # template key (e.g. "hidden_states") differs from the leaf module's 

406 # signature (nn.Linear.forward(input)). 

407 if len(boundary.in_plan) == 1 and boundary.in_plan[0].arg_index is None: 

408 boundary.in_plan[0].arg_index = 0 

409 

410 

411def _wrap_production_forward( 

412 module, boundary, spec=None, keep_output_dtensor=False): 

413 """Production mode: pure local tensor computation + precompiled boundary communication (05 §4.4.1). 

414 

415 _local_params_context was already invoked at the Phase C entry (parameters 

416 permanently unpacked). 

417 """ 

418 original_forward = module.forward 

419 

420 @functools.wraps(original_forward) 

421 def production_forward(*args: Any, **kwargs: Any) -> Any: 

422 """Production boundary forward: precompiled entry communication, 

423 local computation, exit redistribution, then D-22 deferred biases.""" 

424 args, kwargs = boundary.redistribute_inputs(args, kwargs) 

425 outputs = original_forward(*args, **kwargs) 

426 outputs = boundary.redistribute_outputs( 

427 outputs, 

428 as_dtensor_input=keep_output_dtensor, 

429 ) 

430 # D-22: deferred rowwise biases — added once after the exit reduction 

431 return _maybe_add_deferred_biases(module, spec, outputs) \ 

432 if spec is not None else outputs 

433 

434 module.forward = production_forward 

435 

436 

437def _wrap_validate_forward( 

438 module, boundary, spec, mesh_dim_names, keep_output_dtensor=False): 

439 """Validate mode: DTensor propagation end to end -> validate out_src (core) + out_dst (terminal modules only). 

440 

441 The in-house DTensor is forward-only: validation covers only forward 

442 placement propagation; backward is local autograd in both modes (05 §1.0), 

443 and gradient equivalence is guaranteed by tests/ut/auto_models/distributed/grad_equiv.py. 

444 """ 

445 original_forward = module.forward 

446 module_name = type(module).__name__ 

447 

448 @functools.wraps(original_forward) 

449 def validate_forward(*args: Any, **kwargs: Any) -> Any: 

450 """Validate boundary forward: wrap inputs as DTensors, propagate 

451 placements through the original forward, validate out_src, then 

452 redistribute to out_dst.""" 

453 # D-14 nesting (05 §13.4): detect whether the call arrives from an 

454 # outer DTensor-propagating boundary BEFORE Step 1 wraps everything 

455 # into DTensors (Step 1 would make the check useless). 

456 nested = any(isinstance(a, DTensor) for a in args) or any( 

457 isinstance(v, DTensor) for v in kwargs.values()) 

458 # Step 1: inputs -> DTensor 

459 args, kwargs = boundary.redistribute_inputs(args, kwargs, as_dtensor=True) 

460 

461 # Step 2: parameters stay DTensors; placement propagates via __torch_function__ dispatch 

462 outputs = original_forward(*args, **kwargs) 

463 

464 # Step 3: [core validation] out_src -- native DTensor-propagated output vs declaration 

465 if spec.out_src is not None: 

466 _validate_out_src(outputs, spec, mesh_dim_names, module_name) 

467 

468 # Step 4: redistribute to out_dst 

469 outputs = boundary.redistribute_outputs(outputs, as_dtensor_input=True) 

470 

471 # Step 5: [defensive validation] out_dst -- terminal modules only 

472 if spec._is_terminal and spec.out_dst is not None: # pylint: disable=protected-access 

473 _validate_out_dst(outputs, spec, mesh_dim_names, module_name) 

474 

475 # D-22: deferred biases are added after the exit reduction while the 

476 # output is still a DTensor (Shard/Replicate + Replicate bias dispatch 

477 # add — the Partial reduction is already done, so every rank adds the 

478 # bias exactly once); Step 6 then unwraps as usual. 

479 outputs = _maybe_add_deferred_biases(module, spec, outputs) 

480 

481 # Step 6: return local (isomorphic to production boundary outputs) -- 

482 # but under an outer DTensor-propagating boundary (D-14 nesting, 05 

483 # §13.4) keep the DTensor so the outer forward's dispatch chain is 

484 # unbroken; the outermost boundary exit unwraps. 

485 if nested or keep_output_dtensor: 

486 return outputs 

487 return _unwrap_dtensor_outputs(outputs) 

488 

489 module.forward = validate_forward 

490 

491 

492def _validate_out_src(outputs, spec, mesh_dim_names, module_name): 

493 _validate_outputs(outputs, spec, mesh_dim_names, module_name, "out_src") 

494 

495 

496def _validate_out_dst(outputs, spec, mesh_dim_names, module_name): 

497 _validate_outputs(outputs, spec, mesh_dim_names, module_name, "out_dst") 

498 

499 

500def _normalize_placements_ndim(placements, ndim): 

501 """Normalize negative dims like Shard(-1) against the tensor ndim (Shard(-1) == Shard(ndim-1)).""" 

502 out = [] 

503 for p in placements: 

504 if isinstance(p, Shard) and p.dim < 0: 

505 out.append(Shard(p.dim + ndim)) 

506 else: 

507 out.append(p) 

508 return tuple(out) 

509 

510 

511def _validate_output_placement(tensor, expected_named, mesh_dim_names, module_name, stage): 

512 """Validate one DTensor output's declared placement.""" 

513 ndim = len(tensor.shape) 

514 expected = _normalize_placements_ndim( 

515 tuple(resolve_placements(expected_named, mesh_dim_names)), ndim) 

516 actual = _normalize_placements_ndim(tuple(tensor.placements), ndim) 

517 if expected != actual: 

518 raise PlacementMismatchError(module_name, expected, actual, stage) 

519 

520 

521def _validate_outputs(outputs, spec, mesh_dim_names, module_name, stage): 

522 """Placement validation for single/multi outputs (shared by out_src / out_dst). 

523 

524 Multi outputs are mapped to tuple positions via spec.out_names (falling 

525 back to declaration key order); outputs that are not returned or are not 

526 DTensors are skipped. Declared and actual placements are 

527 negative-dim-normalized before comparison. 

528 """ 

529 declared = getattr(spec, stage) 

530 if isinstance(outputs, (tuple, list)): 

531 out_names = getattr(spec, "out_names", None) or list(declared.keys()) 

532 name_to_idx = {name: i for i, name in enumerate(out_names)} 

533 items = list(outputs) 

534 else: 

535 name_to_idx = {name: 0 for name in declared} 

536 items = [outputs] 

537 for out_name, expected_named in declared.items(): 

538 idx = name_to_idx.get(out_name) 

539 if idx is None or idx >= len(items): 

540 continue 

541 tensor = items[idx] 

542 if not isinstance(tensor, DTensor): 

543 continue 

544 suffix = f"[{out_name}]" if len(declared) > 1 else "" 

545 _validate_output_placement( 

546 tensor, expected_named, mesh_dim_names, module_name, f"{stage}{suffix}") 

547 

548 

549# ──────────────────────────────────────────────────────────────────────────── 

550# MoE EP local region (05 §4.4.3 + D-03') 

551# ──────────────────────────────────────────────────────────────────────────── 

552 

553def _rewrap_local_outputs(output, spec, mesh, mesh_dim_names, module_name): 

554 """Wrap every declared local Tensor output with its ``out_src`` layout.""" 

555 declared = spec.out_src or {} 

556 if not declared: 

557 return output 

558 

559 is_sequence = isinstance(output, (tuple, list)) 

560 items = list(output) if is_sequence else [output] 

561 out_names = list(getattr(spec, "out_names", None) or declared.keys()) 

562 name_to_idx = {name: index for index, name in enumerate(out_names)} 

563 

564 for out_name, named_placement in declared.items(): 

565 index = name_to_idx.get(out_name) 

566 if index is None: 

567 raise ValueError( 

568 f"{module_name}: out_src declares output {out_name!r}, but " 

569 f"out_names={out_names!r} does not contain it" 

570 ) 

571 if index >= len(items): 

572 raise ValueError( 

573 f"{module_name}: out_src maps output {out_name!r} to index " 

574 f"{index}, but forward returned only {len(items)} output(s)" 

575 ) 

576 item = items[index] 

577 if item is None: 

578 continue 

579 if isinstance(item, DTensor): 

580 continue 

581 if not isinstance(item, torch.Tensor): 

582 raise TypeError( 

583 f"{module_name}: declared output {out_name!r} at index " 

584 f"{index} must be a Tensor or None, got {type(item).__name__}" 

585 ) 

586 placements = tuple(resolve_placements(named_placement, mesh_dim_names)) 

587 items[index] = DTensor.from_local(item, mesh, placements) 

588 

589 if isinstance(output, tuple): 

590 return tuple(items) 

591 if isinstance(output, list): 

592 return items 

593 if len(items) != 1: 

594 raise ValueError( 

595 f"{module_name}: scalar forward output cannot satisfy " 

596 f"{len(declared)} declared out_src entries" 

597 ) 

598 return items[0] 

599 

600 

601def rewrap_declared_outputs( 

602 output: Union[torch.Tensor, Sequence[Optional[torch.Tensor]]], 

603 entries: List[tuple[int, str, tuple]], 

604 mesh: DeviceMesh, 

605 *, 

606 label: str, 

607) -> Union[torch.Tensor, Sequence[Optional[torch.Tensor]]]: 

608 """Re-wrap declared local-region outputs with their ``out_src`` layout. 

609 

610 The codegen-runtime counterpart of :func:`_rewrap_local_outputs`: 

611 ``InstalledBoundary.rewrap_outputs`` calls this with placements it 

612 pre-resolved from the frozen plan at install time, so the forward-path 

613 work is a plain replay. ``None`` and already-DTensor items pass through. 

614 

615 Args: 

616 output: Forward output tensor, or tuple/list of optional tensors. 

617 entries: Pre-resolved ``(index, out_name, placements)`` rewrap plan. 

618 mesh: Dense mesh the declared outputs shard across. 

619 label: Caller label used in error messages. 

620 

621 Returns: 

622 The output with declared entries re-wrapped as DTensors. 

623 """ 

624 is_sequence = isinstance(output, (tuple, list)) 

625 items = list(output) if is_sequence else [output] 

626 for index, out_name, placements in entries: 

627 if index >= len(items): 

628 raise ValueError( 

629 f"{label}: out_src maps output {out_name!r} to index " 

630 f"{index}, but forward returned only {len(items)} output(s)" 

631 ) 

632 item = items[index] 

633 if item is None or isinstance(item, DTensor): 

634 continue 

635 if not isinstance(item, torch.Tensor): 

636 raise TypeError( 

637 f"{label}: declared output {out_name!r} at index " 

638 f"{index} must be a Tensor or None, got {type(item).__name__}" 

639 ) 

640 items[index] = DTensor.from_local(item, mesh, tuple(placements)) 

641 

642 if isinstance(output, tuple): 

643 return tuple(items) 

644 if isinstance(output, list): 

645 return items 

646 if len(items) != 1: 

647 raise ValueError( 

648 f"{label}: scalar forward output cannot satisfy " 

649 f"{len(entries)} declared out_src entries" 

650 ) 

651 return items[0] 

652 

653 

654def _wrap_local_region_forward(module, boundary, spec, mesh, mesh_dim_names, 

655 *, validate_mode=False, compute_fn=None, 

656 exclude_subtrees=()): 

657 """Generic local-region forward wrapper (D-03', formerly the _wrap_moe_forward skeleton). 

658 

659 Structure: boundary entry -> local region -> boundary exit. Applies to any 

660 module containing data-dependent logic that DTensor dispatch cannot express 

661 (e.g. MoE all-to-all) -- injected by _apply_phase_c when 

662 _resolve_local_compute_fn resolves to non-None (derived gate, 05 §4.4.3). 

663 

664 production: parameters were permanently unpacked at build time and inputs 

665 are local (boundary passthrough), and the output stays local for lowered 

666 boundary operations; validate: inputs are DTensors -> to_local -> 

667 temporarily unwrap parameters -> local computation -> re-wrap the output 

668 per the declared out_src via from_local (for data-dependent modules out_src 

669 is declarative validation -- the data dependence of all-to-all makes the 

670 placement underivable; this is an inherent limitation). Both modes share 

671 the same wrapper code (local_region tolerant passthrough semantics). 

672 

673 compute_fn: the function actually executed inside the region; defaults to 

674 the module's own forward. Resolved uniformly by 

675 _resolve_local_compute_fn (user local_compute_fn / region_dispatch=False 

676 gate), independent of the original forward. 

677 

678 spec.region_dispatch=True (dispatchable pure-ops injection): validate 

679 feeds the DTensors straight into compute_fn — strategy propagation runs 

680 THROUGH the injected fn and out_src is TRULY validated (propagated vs 

681 declared); production is unchanged (always local passthrough). 

682 """ 

683 original_forward = module.forward 

684 if compute_fn is None: 

685 compute_fn = original_forward 

686 

687 dispatch_through = bool(getattr(spec, "region_dispatch", None)) 

688 if validate_mode and not dispatch_through: 

689 install_local_compute_forward_adapters(module, exclude=exclude_subtrees) 

690 

691 @functools.wraps(original_forward) 

692 def local_region_forward(*args: Any, **kwargs: Any) -> Any: 

693 """Local-region forward: boundary entry → local region computation → 

694 validate re-wrap → boundary exit (both modes share this wrapper).""" 

695 # Step 1: PrecompiledBoundary entry (e.g. TP all-gather; identity passthrough) 

696 args, kwargs = boundary.redistribute_inputs( 

697 args, kwargs, as_dtensor=validate_mode) 

698 

699 # Step 2: local region -- the data-dependent computation (e.g. EP 

700 # dispatch/combine) executes on local tensors; region_dispatch=True 

701 # instead dispatches THROUGH the injected fn (pure standard ops) so 

702 # validate's strategy propagation covers it 

703 if validate_mode and dispatch_through: 

704 try: 

705 output = compute_fn(*args, **kwargs) 

706 except Exception as exc: 

707 raise type(exc)( 

708 f"{exc}\n[region_dispatch=True] dispatch failed while " 

709 "validate was dispatching through the injected " 

710 "function — does the injection contain " 

711 "non-dispatchable communication primitives/custom " 

712 "kernels? Declare region_dispatch=False instead " 

713 "(skeleton black-box hosting)" 

714 ) from exc 

715 # True validation: propagated result vs the out_src declaration 

716 # (a wrong declaration fails fast) 

717 if spec.out_src is not None: 

718 _validate_out_src(output, spec, mesh_dim_names, 

719 type(module).__name__) 

720 elif validate_mode: 

721 local_args = tuple( 

722 a.to_local() if isinstance(a, DTensor) else a for a in args) 

723 local_kwargs = { 

724 k: (v.to_local() if isinstance(v, DTensor) else v) 

725 for k, v in kwargs.items() 

726 } 

727 with local_compute_context(): 

728 with _temp_local_params(module, exclude=exclude_subtrees): 

729 output = compute_fn(*local_args, **local_kwargs) 

730 else: 

731 output = compute_fn(*args, **kwargs) 

732 

733 # Step 3: validate restores the DTensor metadata broken by all-to-all. 

734 # Production keeps the output local so lowered boundary operations can 

735 # execute directly; an unlowerable transition wraps only in its 

736 # necessary DTensor fallback inside RedistOp. 

737 if validate_mode and not isinstance(output, DTensor): 

738 output = _rewrap_local_outputs( 

739 output, spec, mesh, mesh_dim_names, type(module).__name__) 

740 

741 # Step 4: PrecompiledBoundary exit (e.g. TP reduce-scatter) 

742 output = boundary.redistribute_outputs( 

743 output, as_dtensor_input=validate_mode) 

744 # The final boundary exit is always local. 

745 output = _unwrap_dtensor_outputs(output) 

746 # D-22: deferred rowwise biases — added once after the exit reduction 

747 return _maybe_add_deferred_biases(module, spec, output) 

748 

749 module.forward = local_region_forward 

750 

751 

752# ──────────────────────────────────────────────────────────────────────────── 

753# CP inner attention wrapper (05 §4.4.2 + D-01'' + D-04) 

754# ──────────────────────────────────────────────────────────────────────────── 

755 

756def _apply_custom_inner_wrapper(custom_fn, context): 

757 """Apply a user-defined inner_wrapper (@inner_wrapper callable). 

758 

759 Contract: custom_fn must be decorated ``@inner_wrapper``; it is invoked 

760 with its declared context (anchor target_module + the mandatory mesh 

761 family, filled by name). It either replaces target.forward in place and 

762 returns None (the external contract) or RETURNS the replacement — a 

763 forward callable or _ForwardRewriteRequest(s) — for the rewriter to 

764 validate and install (the in-repo discipline, 05 §15.2.3). The 

765 replacement forward runs in a LOCAL-TENSOR world — the dual-mode 

766 adapter installed by _wrap_inner_attention owns all DTensor 

767 conversion (to_local / _temp_local_params / from_local rewrap per the 

768 declared placements), so custom wrappers never touch DTensor. 

769 """ 

770 meta = require_injection_meta( 

771 custom_fn, INNER_WRAPPER, source="spec.inner_wrapper") 

772 return custom_fn(**{k: context[k] for k in sorted(meta.context)}) 

773 

774 

775def _find_dtensor_argument(args, kwargs): 

776 """Return the first DTensor positional or keyword argument.""" 

777 return next( 

778 ( 

779 value 

780 for value in (*args, *kwargs.values()) 

781 if isinstance(value, DTensor) 

782 ), 

783 None, 

784 ) 

785 

786 

787def _validate_inner_dispatch_output( 

788 output, 

789 expected_placements, 

790 boundary_module, 

791 wrapper_name, 

792): 

793 """Validate DTensor outputs produced through a dispatchable inner wrapper.""" 

794 if expected_placements is None: 

795 return 

796 outputs = list(output) if isinstance(output, (tuple, list)) else [output] 

797 tensor_outputs = [tensor for tensor in outputs if isinstance(tensor, torch.Tensor)] 

798 if len(tensor_outputs) != len(expected_placements): 

799 raise RuntimeError( 

800 f"inner_wrapper {wrapper_name!r}: tensor output count " 

801 f"{len(tensor_outputs)} does not match the " 

802 f"{len(expected_placements)} declared placements — a " 

803 "multi-output contract must be declared name by name with " 

804 "matching counts" 

805 ) 

806 for tensor, placements in zip(tensor_outputs, expected_placements): 

807 if not isinstance(tensor, DTensor): 

808 raise RuntimeError( 

809 f"inner_wrapper {wrapper_name!r} [region_dispatch=True]: " 

810 f"the dispatch-propagated output is not a DTensor " 

811 f"({type(tensor).__name__}) — the injection appears to " 

812 "have left the dispatch chain, so true validation cannot " 

813 "complete" 

814 ) 

815 if tuple(tensor.placements) != tuple(placements): 

816 raise PlacementMismatchError( 

817 f"{type(boundary_module).__name__} " 

818 f"(inner_wrapper {wrapper_name!r})", 

819 tuple(placements), 

820 tuple(tensor.placements), 

821 "inner_out_src", 

822 ) 

823 

824 

825def _rewrap_inner_tensor(tensor, placements, mesh): 

826 """Wrap one local tensor with its declared layout and pass other values through.""" 

827 if not isinstance(tensor, torch.Tensor) or isinstance(tensor, DTensor): 

828 return tensor 

829 return DTensor.from_local(tensor, mesh, placements) 

830 

831 

832def _rewrap_inner_outputs(output, out_placements, mesh, wrapper_name): 

833 """Rewrap tensor outputs while preserving auxiliary non-tensor outputs.""" 

834 if not isinstance(output, (tuple, list)): 

835 return _rewrap_inner_tensor(output, out_placements[0], mesh) 

836 tensor_output_count = sum(isinstance(value, torch.Tensor) for value in output) 

837 if tensor_output_count != len(out_placements): 

838 raise RuntimeError( 

839 f"inner_wrapper {wrapper_name!r}: the replacement forward " 

840 f"returned {tensor_output_count} tensor outputs, which does " 

841 f"not match the {len(out_placements)} declared placements — " 

842 "a multi-output contract must be declared name by name with " 

843 "matching counts" 

844 ) 

845 placement_iter = iter(out_placements) 

846 wrapped = [ 

847 _rewrap_inner_tensor(value, next(placement_iter), mesh) 

848 if isinstance(value, torch.Tensor) 

849 else value 

850 for value in output 

851 ] 

852 return tuple(wrapped) if isinstance(output, tuple) else wrapped 

853 

854 

855def _install_inner_adapter(target, user_fwd, boundary_module, spec, mesh, 

856 mesh_dim_names, wrapper_name, validate_mode=False): 

857 """Unified dual-mode adapter: rewrap rules are resolved at install time, 

858 with zero runtime decisions (05 §4.4.2 + D-01''). 

859 

860 The replacement forward of a user wrapper only faces local tensors. The 

861 adapter handles: 

862 - validate (any input is a DTensor): every DTensor input is to_local'd 

863 (non-tensors pass through) + ``_temp_local_params(target)`` temporarily 

864 unwraps the parameters → call the user forward → rewrap the outputs 

865 back into DTensors per the declaration (the propagation chain is 

866 re-linked and boundary validation continues); 

867 - production (no DTensor inputs): straight passthrough, zero conversion 

868 overhead. 

869 

870 Source of the rewrap placements (the framework infers and guesses 

871 nothing — everything is explicitly declared): 

872 - case A (target is the boundary module itself): the boundary 

873 ``spec.out_src`` declaration (multiple outputs positionally per 

874 ``out_names``/declaration key order); 

875 - case B (an inner submodule): the explicit ``spec.inner_out_src`` 

876 declaration — the sentinel ``"first_input"`` (output layout == the 

877 runtime layout of the first DTensor input; for layout-preserving 

878 wrappers, single output only) or NamedPlacement / 

879 {name: NamedPlacement} (multiple outputs mapped to tuple positions per 

880 declaration key order); undeclared → fail-fast at install time. 

881 """ 

882 first_input_rule, out_placements = _resolve_inner_output_placements( 

883 spec, 

884 boundary_module, 

885 target, 

886 mesh_dim_names, 

887 wrapper_name, 

888 ) 

889 if validate_mode and not getattr(spec, "region_dispatch", None): 

890 install_local_compute_forward_adapters(target) 

891 

892 @functools.wraps(user_fwd) 

893 def adapted(*args: Any, **kwargs: Any) -> Any: 

894 """Dual-mode adapter around the user's replacement forward. 

895 

896 production (no DTensor input): straight passthrough; validate: 

897 unwrap DTensor inputs/parameters to local, run the user forward, and 

898 rewrap outputs per the declaration resolved at install time (or, with 

899 region_dispatch=True, dispatch through and truly validate instead). 

900 """ 

901 source_dtensor = _find_dtensor_argument(args, kwargs) 

902 if source_dtensor is None: 

903 return user_fwd(*args, **kwargs) # production: straight passthrough 

904 if getattr(spec, "region_dispatch", None): 

905 # Validate dispatch-through (region_dispatch=True): the injection 

906 # is pure standard ops — DTensors go straight in and dispatch 

907 # propagation runs through the inner region; the declared rewrap 

908 # rules are promoted to the true-validation baseline (propagated 

909 # result vs declaration, a mismatch fails fast). 

910 try: 

911 out = user_fwd(*args, **kwargs) 

912 except Exception as exc: 

913 raise type(exc)( 

914 f"{exc}\n[region_dispatch=True] dispatch failed " 

915 f"while validate was dispatching through " 

916 f"inner_wrapper {wrapper_name!r} — does the injection " 

917 "contain non-dispatchable communication " 

918 "primitives/custom kernels? Declare " 

919 "region_dispatch=False instead (adapter black-box " 

920 "hosting)") from exc 

921 expected = ( 

922 [tuple(source_dtensor.placements)] 

923 if first_input_rule 

924 else out_placements 

925 ) 

926 _validate_inner_dispatch_output( 

927 out, 

928 expected, 

929 boundary_module, 

930 wrapper_name, 

931 ) 

932 return out 

933 # validate: uniformly convert to local (parameters temporarily 

934 # unwrapped, restored on exit) 

935 local_args = tuple( 

936 a.to_local() if isinstance(a, DTensor) else a for a in args) 

937 local_kwargs = {k: (v.to_local() if isinstance(v, DTensor) else v) 

938 for k, v in kwargs.items()} 

939 with local_compute_context(): 

940 with _temp_local_params(target): 

941 out = user_fwd(*local_args, **local_kwargs) 

942 

943 if first_input_rule: 

944 if isinstance(out, (tuple, list)): 

945 raise RuntimeError( 

946 f"inner_wrapper {wrapper_name!r}: inner_out_src=" 

947 "'first_input' only supports a single output — for " 

948 "multiple outputs declare inner_out_src explicitly in " 

949 "the {name: {axis: placement}} form") 

950 return _rewrap_inner_tensor( 

951 out, 

952 tuple(source_dtensor.placements), 

953 source_dtensor.device_mesh, 

954 ) 

955 if out_placements is None: 

956 return out # case A with no out_src declaration: no rewrap 

957 return _rewrap_inner_outputs(out, out_placements, mesh, wrapper_name) 

958 

959 target.forward = adapted 

960 

961 

962def _wrap_inner_attention(module, cp_mesh, *, spec=None, mesh=None, 

963 mesh_dim_names=(), tp_mesh=None, ep_mesh=None, 

964 validate_mode=False, module_fqn=""): 

965 """Inject an inner forward wrapper (one-shot replacement at apply time, 05 §4.4.2). 

966 

967 General "weave into / replace the inner forward" mechanism — **not gated 

968 on CP**: whenever ``spec.inner_wrapper`` is declared the wrapper is 

969 applied (declaration == application; the resolution chain is the derived 

970 gate). The shipped CP wrappers (INNER_WRAPPER_REGISTRY) are its first-class 

971 built-in use case and still require an active cp axis (fail-fast in the 

972 resolution chain otherwise); custom callables/Targets receive 

973 ``cp_mesh=None`` when no cp axis exists and own their semantics. 

974 

975 Resolution (_resolve_inner_wrapper, a pure function of the chain) is 

976 separated from application; when resolution returns None (no explicit 

977 declaration), this returns None and injects nothing. Returns the resolved 

978 wrapper name (or None). 

979 

980 D-01'': production and validate inject **the same** wrapper, so the 

981 in-region computation is instruction-for-instruction identical 

982 (kernel-level equivalence). 

983 D-04: when is_causal and CP is active, replace it with an offset-aware 

984 explicit mask. 

985 Nothing is located silently: after injection an INFO log records the 

986 target/wrapper/source, and spec._resolved_inner_wrapper + 

987 spec._resolved_inner_target are written back for plan introspection. 

988 """ 

989 resolved = _resolve_inner_wrapper( 

990 module, spec, cp_mesh, mesh, tp_mesh=tp_mesh, ep_mesh=ep_mesh) 

991 if resolved is None: 

992 return None 

993 name, target = _apply_resolved_inner_wrapper( 

994 module, resolved, spec, mesh, mesh_dim_names, validate_mode, module_fqn) 

995 target_name = _inner_target_name(module, target) 

996 if spec is not None: 

997 spec._resolved_inner_wrapper = name # pylint: disable=protected-access 

998 spec._resolved_inner_target = target_name # pylint: disable=protected-access 

999 if name == "custom": 

1000 source = "custom callable" 

1001 elif spec is not None and isinstance( 

1002 getattr(spec, "inner_wrapper", None), str): 

1003 source = "explicitly specified (registry)" 

1004 else: 

1005 source = "explicitly specified (Target)" 

1006 logger.info("inner-wrap: %s target=%s <- wrapper %r (%s)", 

1007 type(module).__name__, target_name, name, source) 

1008 return name 

1009 

1010 

1011def _rollback_inner_rewrite(target, saved_state, committed_secondaries): 

1012 """Restore primary and secondary targets after a failed inner rewrite.""" 

1013 for secondary_target, secondary_state in reversed(committed_secondaries): 

1014 for attr, saved in secondary_state.items(): 

1015 _restore_attr(secondary_target, attr, saved) 

1016 for attr, saved in saved_state.items(): 

1017 _restore_attr(target, attr, saved) 

1018 

1019 

1020def _prepare_inner_rewrite(target, apply_fn, name): 

1021 """Apply an inner wrapper and retain the state needed for rollback.""" 

1022 orig_forward = target.forward 

1023 # Record the pre-rewrite state for failure rollback: an in-place wrapper 

1024 # writes an instance attribute, so __dict__ holds the full mutation. 

1025 saved_state = {"forward": target.__dict__.get("forward", _MISSING)} 

1026 committed_secondaries = [] 

1027 try: 

1028 primary, secondaries = _classify_rewrite_result( 

1029 apply_fn(), target, name) 

1030 for request in secondaries: 

1031 committed_secondaries.append( 

1032 (request.target, _commit_forward_rewrite(request)) 

1033 ) 

1034 if primary is None: 

1035 # In-place contract (external @inner_wrapper wrappers). Detect 

1036 # "a replacement really happened": attribute access on a bound 

1037 # method creates a new object each time, so an `is` comparison is 

1038 # always true — the underlying function objects (__func__) must 

1039 # be compared, otherwise a pure-probe wrapper (which does not 

1040 # replace forward) would also get an adapter installed by mistake 

1041 # and be forced to declare inner_out_src 

1042 new_forward = target.forward 

1043 replaced = (getattr(new_forward, "__func__", new_forward) 

1044 is not getattr(orig_forward, "__func__", orig_forward)) 

1045 else: 

1046 # In-repo discipline: the wrapper returned its replacement, the 

1047 # rewriter commits the companion attributes and installs. 

1048 saved_state.update({ 

1049 attr: target.__dict__.get(attr, _MISSING) 

1050 for attr in primary.companion_attrs 

1051 }) 

1052 for attr, value in primary.companion_attrs.items(): 

1053 setattr(target, attr, value) 

1054 new_forward = primary.forward 

1055 replaced = True 

1056 except Exception: 

1057 _rollback_inner_rewrite( 

1058 target, saved_state, committed_secondaries) 

1059 raise 

1060 return (orig_forward, new_forward, replaced, saved_state, 

1061 committed_secondaries) 

1062 

1063 

1064def _apply_resolved_inner_wrapper(module, resolved, spec, mesh, mesh_dim_names, 

1065 validate_mode, module_fqn): 

1066 """Apply, validate, and atomically install a resolved inner wrapper.""" 

1067 name, target, apply_fn = resolved 

1068 if validate_mode and getattr(spec, "region_dispatch", None) is False: 

1069 # A black-box inner wrapper receives local tensors and local parameter 

1070 # shards in validate mode. Cached head counts must therefore match the 

1071 # TP-local projection widths, just as they already do in production. 

1072 maybe_update_head_counts( 

1073 target, 

1074 spec, 

1075 module_fqn or type(module).__name__, 

1076 mesh, 

1077 mesh_dim_names, 

1078 ) 

1079 (orig_forward, new_forward, replaced, saved_state, 

1080 committed_secondaries) = _prepare_inner_rewrite( 

1081 target, apply_fn, name) 

1082 try: 

1083 if replaced: 

1084 # Principle 1: the replaced forward must accept all inputs of the 

1085 # original forward 

1086 validate_wrapped_forward( 

1087 orig_forward, new_forward, 

1088 owner=f"inner_wrapper {name!r} on {type(module).__name__}") 

1089 # Uniformly install the dual-mode adapter: the user wrapper only 

1090 # faces local tensors; DTensor conversion and declarative rewrap 

1091 # are managed by the adapter (local_map semantics; validate skips 

1092 # propagation checks for the inner region — the safety net is at 

1093 # the boundary layer) 

1094 _install_inner_adapter( 

1095 target, new_forward, module, spec, mesh, mesh_dim_names, name, 

1096 validate_mode=validate_mode) 

1097 except Exception: 

1098 _rollback_inner_rewrite( 

1099 target, saved_state, committed_secondaries) 

1100 raise 

1101 return name, target 

1102 

1103 

1104# ──────────────────────────────────────────────────────────────────────────── 

1105# D-02 vocab-parallel embedding wrapper 

1106# ──────────────────────────────────────────────────────────────────────────── 

1107 

1108def _is_vocab_parallel_embed(module, spec, tp_mesh) -> bool: 

1109 """production embed boundary check: nn.Embedding + weight Shard(0) on TP + TP>1.""" 

1110 if tp_mesh is None or tp_mesh.size() <= 1: 

1111 return False 

1112 if not isinstance(module, nn.Embedding): 

1113 return False 

1114 weight_named = spec.params.get("weight", {}) 

1115 return weight_named.get("tp") == Shard(0) 

1116 

1117 

1118def _wrap_vocab_parallel_embedding(module, tp_mesh): 

1119 """D-02: Megatron-style masked embedding (injected at the production embed boundary). 

1120 

1121 The vocab-range mask logic of DTensor dispatch is lost after the 

1122 parameter unwrap -- HF native F.embedding would index out of range when 

1123 given global token ids. The wrapper: tokens outside the local vocab 

1124 interval [lo, hi) are zeroed and indices are shifted by the offset, so the 

1125 output is naturally a Partial contribution and the boundary exit's 

1126 Partial->Shard(1) reduction is unchanged. 

1127 

1128 The interval must come from the *local* vocab shard. The applier reaches 

1129 this after the Phase C one-shot ``_local_params_context`` unwrap (plain 

1130 local parameter), but a caller may install the boundary while the weight 

1131 is still a DTensor -- ``DTensor.shape`` is the global shape and would give 

1132 a wrong interval -- so the local shard is read explicitly. 

1133 """ 

1134 original_forward = module.forward 

1135 weight = module.weight 

1136 to_local = getattr(weight, "to_local", None) 

1137 local_weight = to_local() if callable(to_local) else weight 

1138 v_local = local_weight.shape[0] 

1139 lo = tp_mesh.get_local_rank() * v_local 

1140 hi = lo + v_local 

1141 

1142 @functools.wraps(original_forward) 

1143 def masked_embedding_forward( 

1144 input_ids: torch.Tensor, *args: Any, **kwargs: Any, 

1145 ) -> torch.Tensor: 

1146 """Masked vocab-parallel embedding forward: zero out-of-range token 

1147 ids, shift indices by the local vocab offset, and mask the output so 

1148 it is a pure Partial contribution. 

1149 

1150 Args: 

1151 input_ids: Global token IDs at the vocab-parallel boundary. 

1152 *args: Additional original embedding arguments. 

1153 **kwargs: Additional original embedding keyword arguments. 

1154 """ 

1155 mask = (input_ids >= lo) & (input_ids < hi) 

1156 local_ids = torch.where(mask, input_ids - lo, torch.zeros_like(input_ids)) 

1157 out = original_forward(local_ids, *args, **kwargs) 

1158 return out * mask.unsqueeze(-1).to(out.dtype) 

1159 

1160 module.forward = masked_embedding_forward 

1161 

1162# ──────────────────────────────────────────────────────────────────────────── 

1163# Install primitives — the ONLY forward-assignment sites in repo-owned code 

1164# (AST gate, 05 §15.2.3). Everywhere else, a forward mutation is expressed as 

1165# a returned callable or _ForwardRewriteRequest and committed here. 

1166# ──────────────────────────────────────────────────────────────────────────── 

1167 

1168_MISSING = object() 

1169 

1170 

1171class _ForwardRewriteRequest: 

1172 """An atomic forward-rewrite request returned by wrapper factories. 

1173 

1174 Carries the target module, the replacement forward and the companion 

1175 attribute updates (e.g. ``attention_interface``/context flags) that must 

1176 commit together with the forward swap; the rewriter validates, commits 

1177 and rolls back as one unit (05 §15.2.3, P0 atomicity requirement). 

1178 """ 

1179 

1180 __slots__ = ("target", "forward", "companion_attrs") 

1181 

1182 def __init__(self, target: nn.Module, forward: Callable[..., Any], companion_attrs: Any = ()) -> None: 

1183 """Keep one forward replacement and its companion attribute updates.""" 

1184 self.target = target 

1185 self.forward = forward 

1186 self.companion_attrs = dict(companion_attrs) 

1187 

1188 

1189def _restore_attr(module, name, saved): 

1190 """Restore one attribute to its pre-rewrite state (_MISSING deletes it).""" 

1191 if saved is _MISSING: 

1192 vars(module).pop(name, None) 

1193 else: 

1194 setattr(module, name, saved) 

1195 

1196 

1197def _commit_forward_rewrite(request): 

1198 """Commit one rewrite request atomically, verbatim (no dual-mode adapter). 

1199 

1200 Used for secondary targets of a wrapper (e.g. the text-model input 

1201 sharding of the MLA/DSA Ulysses scheme); the primary target of a plan 

1202 injection goes through ``_wrap_inner_attention`` instead, which validates 

1203 the signature and installs the dual-mode adapter. 

1204 """ 

1205 target = request.target 

1206 saved = { 

1207 "forward": target.__dict__.get("forward", _MISSING), 

1208 **{name: target.__dict__.get(name, _MISSING) 

1209 for name in request.companion_attrs}, 

1210 } 

1211 try: 

1212 for attr_name, value in request.companion_attrs.items(): 

1213 setattr(target, attr_name, value) 

1214 target.forward = request.forward 

1215 except Exception: 

1216 for attr_name, value in saved.items(): 

1217 _restore_attr(target, attr_name, value) 

1218 raise 

1219 return saved 

1220 

1221 

1222def _classify_rewrite_result(returned, target, wrapper_name): 

1223 """Normalize a wrapper's return into (primary request, secondary requests). 

1224 

1225 Return contract for @inner_wrapper callables: None for in-place 

1226 replacement (the external contract — target.forward was assigned by the 

1227 wrapper itself); a replacement forward callable for the resolved target; 

1228 or _ForwardRewriteRequest(s) — the entry targeting the resolved module is 

1229 the primary (validated + dual-mode adapter installed), the rest are 

1230 committed verbatim. 

1231 """ 

1232 if returned is None: 

1233 return None, [] 

1234 entries = (list(returned) 

1235 if isinstance(returned, (list, tuple)) else [returned]) 

1236 requests = [] 

1237 for entry in entries: 

1238 if isinstance(entry, _ForwardRewriteRequest): 

1239 requests.append(entry) 

1240 elif callable(entry): 

1241 requests.append(_ForwardRewriteRequest(target, entry)) 

1242 else: 

1243 raise TypeError( 

1244 f"inner_wrapper {wrapper_name!r} returned " 

1245 f"{type(entry).__name__} — expected None (in-place forward " 

1246 "replacement), a replacement forward callable, or a " 

1247 "_ForwardRewriteRequest") 

1248 primaries = [request for request in requests if request.target is target] 

1249 if len(primaries) > 1: 

1250 raise TypeError( 

1251 f"inner_wrapper {wrapper_name!r} returned multiple rewrite " 

1252 "requests for the resolved target — exactly one primary " 

1253 "replacement is allowed") 

1254 secondaries = [request for request in requests 

1255 if request.target is not target] 

1256 return (primaries[0] if primaries else None), secondaries 

1257 

1258 

1259def _install_bound_forward(module, unbound_forward): 

1260 """Install ``unbound_forward(module, *args, **kwargs)`` as a bound forward. 

1261 

1262 The repo's only ``types.MethodType`` forward installation: for entry-point 

1263 binders whose replacement is written as a plain function taking the module 

1264 explicitly (e.g. the EP local-expert entry point); companion attributes 

1265 (``local_expert_count`` and friends) are set by the binder beforehand. 

1266 """ 

1267 module.forward = types.MethodType(unbound_forward, module) 

1268 

1269 

1270# ──────────────────────────────────────────────────────────────────────────── 

1271# Local-compute descendant adapters (moved from local_compute_context.py, 

1272# which keeps only the region state) 

1273# ──────────────────────────────────────────────────────────────────────────── 

1274 

1275_ADAPTED_MODULES = weakref.WeakSet() 

1276 

1277 

1278def install_local_compute_forward_adapters( 

1279 module: Any, 

1280 exclude: Sequence[str] = (), 

1281) -> None: 

1282 """Make descendant forwards expose their directly owned local parameters. 

1283 

1284 A descendant FSDP pre-hook executes before its wrapped ``forward``, so the 

1285 wrapper observes and temporarily unwraps the newly installed unsharded 

1286 DTensor. Its restoration finishes before the FSDP post-hook. The same 

1287 wrapper is a no-op when FSDP is disabled or execution is outside a local 

1288 compute region. 

1289 

1290 The root is intentionally omitted: the local-region skeleton already 

1291 handles all parameters visible when its forward starts. Descendant 

1292 installation is idempotent across overlapping local regions. 

1293 

1294 Args: 

1295 module: Root module of a trainer-managed local compute region. 

1296 exclude: Relative descendant FQNs that remain DTensor dispatch islands. 

1297 """ 

1298 excluded = tuple(name.rstrip(".") for name in exclude) 

1299 descendants = tuple(module.named_modules())[1:] 

1300 for relative_fqn, target in descendants: 

1301 if any( 

1302 relative_fqn == name or relative_fqn.startswith(name + ".") 

1303 for name in excluded 

1304 ): 

1305 continue 

1306 if target in _ADAPTED_MODULES: 

1307 continue 

1308 _wrap_module_forward(target) 

1309 _ADAPTED_MODULES.add(target) 

1310 

1311 

1312def _wrap_module_forward(module: Any) -> None: 

1313 """Wrap one descendant module without changing its public forward contract.""" 

1314 original_forward = module.forward 

1315 

1316 @functools.wraps(original_forward) 

1317 def local_param_forward(*args: Any, **kwargs: Any) -> Any: 

1318 """Run forward with directly owned DTensor parameters unwrapped locally.""" 

1319 if not _LOCAL_COMPUTE_ACTIVE.get(): 

1320 return original_forward(*args, **kwargs) 

1321 saved = [] 

1322 for name, parameter in module.named_parameters(recurse=False): 

1323 if isinstance(parameter, DTensor): 

1324 saved.append((name, parameter)) 

1325 module._parameters[name] = parameter.to_local() # pylint: disable=protected-access 

1326 try: 

1327 return original_forward(*args, **kwargs) 

1328 finally: 

1329 for name, parameter in saved: 

1330 module._parameters[name] = parameter # pylint: disable=protected-access 

1331 

1332 module.forward = local_param_forward