Move TrainerRank checkpoint-slot and dynamic-optimizer management into trainer_rank/_slots and _optimizer - #1001
Conversation
|
Schulman — no blocking findings in the reviewed scope. Reviewed head The method bodies match after narrowly accounting for Four bounded framework-free CPU cases passed using the actual extracted source: sentinel identity, instance graph-guard dispatch, optimizer creation and existing optimizer/state preservation during configuration updates. Syntax and stacked/cumulative source comparisons passed. No full Torch/ART import-order test, broad pytest, real optimizer numerics, distributed/GPU execution or package build was performed by this review. Nonblocking documentation nit: this head has 184 total/83 remaining methods under the review's count, rather than the description's 183/82; the extraction totals are correct. Changed function/frame metadata also means frozen source-authenticating diagnostics need explicit adoption rather than silent repinning. |
|
Independent source review by Stark and his review delegate; posted by Jarvis at Brad's request. Scope and validation statements below describe that review. Source review of ART #1001 at 5867bd4, stacked base 35db954: no introduced blocker found. All 41 extracted slot/optimizer method bodies match after explicit qualification/self-annotation normalization; ownership stays on TrainerRank and dispatch remains through self. Import order supplies definition-time defaults before module extraction bindings. This is source-only, not runtime qualification. Trainer-v1 integration must port its consumed-graph markers into _slots, post-step DP0 head-buffer synchronization into optim_step, and accumulated-version validation/cleanup into _dynamic_optim_step. The full stack also predates main #998 and must preserve its GDN scan fix. Caladan observer source pins/digests need a reviewed update after any integration. These are future reconciliation obligations, not introduced #1001 defects. Reviewed with a fresh task-local source reviewer; this lane did not author the extraction. No application imports, tests, GPU/provider work or GitHub posting occurred. Exact source evidence is recorded in the reviewer’s retained local report and source-proof file. |
35db954 to
ced0776
Compare
Extract the 31 checkpoint-slot bookkeeping methods (prefetch registry, slot loading and validation, the slot stack push/pop, slot-graph liveness guards) from TrainerRank into a new _slots module. Bodies are moved verbatim as module functions taking the rank as self; TrainerRank binds them in its class body so self._x(...) dispatch, class-level access and per-instance monkeypatches keep working, and module globals (torch, dist, sibling helpers) are still resolved through _impl at call time so tests that patch _impl.torch and friends keep intercepting them. _slots is imported immediately before the class body (alongside _memory and _micro_batch_planner) because _resolve_slot_ref and _ensure_checkpoint_slots_for read _impl.Unset as a definition-time default. Behavior-preserving code motion only.
…mizer Extract the 10 dynamic (per-checkpoint) optimizer methods (optim_step and its configuration guard, dynamic optimizer creation, extension and restore, padding masks and step flags) from TrainerRank into a new _optimizer module, using the same mechanics as _slots: bodies moved verbatim as module functions taking the rank as self, bound in the TrainerRank class body, with module globals (torch, dist, _telemetry_phase and other _impl helpers) resolved through _impl at call time so tests that patch _impl.torch and friends keep intercepting them. Drops the now-unused hashlib import and LocalOptimizerState type import from _impl. Behavior-preserving code motion only.
5867bd4 to
e2c832f
Compare
Summary
Third and last of the stacked
TrainerRankextractions (base: #1000, which is on #999). Moves 41 methods out ofsrc/art/trainer_rank/_impl.py:src/art/trainer_rank/_slots.py(_resolve_slot_ref,_ensure_checkpoint_slots/_for,_register_checkpoint_prefetch,_load_checkpoint_slot,_load_registered_checkpoint,_guard_slot_can_load,_guard_checkpoint(s)_can_step,_validate_checkpoint_adapter_config,_validate_loaded_checkpoint_config,_validate_checkpoint_consistency,_selected_dynamic_checkpoints,_checkpoint_grad_flags,_track_slot_graph_outputs,_slot_graphs,_prune_slot_graphs,_has_live_slot_graph,_push_checkpoint(_sync),_discard_snapshot_checkpoint,_resolve_checkpoint_name,_checkpoint_group,_set_default_slot,_iter_slot_parameters,_resolve_custom_checkpoint,_checkpoint_prefetch_waiter,_prefetched_checkpoint, and the publicprefetch_checkpoints,load_checkpoint,pop_checkpoint).src/art/trainer_rank/_optimizer.py(optim_step,_dynamic_optim_step,_guard_optim_step_configuration,_dynamic_optimizer,_new_dynamic_optimizer,_extend_dynamic_optimizer,_restore_canonical_optimizer,_dynamic_param_step_flags,_zero_dynamic_optimizer_padding,_dynamic_optimizer_padding_masks).Same pattern as #999/#1000 and the existing
_gdn_memory.py/_planner_evidence.py: module-level functionsdef name(self: TrainerRank, ...)with verbatim bodies, bound in the class body by assignment. No collaborator object, no delegators, no__init__change; sibling calls stayself._x(...)so the ~29 per-instance monkeypatches and theTrainerRank.__new__-built ranks in the test suite keep working, and the 42 call sites in_checkpoint.py(untouched) still resolve through the rank. None of the 41 originals was decorated. Names tests patch on_impl(torch,dist,_telemetry_phase) plus the_impl-defined classes/helpers the bodies use are read as_impl.Xat call time._resolve_slot_refhas a def-time= _impl.Unsetdefault, so both modules are imported on the shared pre-class import line. The module was named_optimizer.py(not_dynamic_optimizer.py) to avoid colliding with the method of that name.Stateless
@staticmethods referenced widely from_checkpoint.pyand tests (_slot_ref,_slot_state_error,_checkpoint_source,_checkpoint_source_key,_await_checkpoint_prefetch) and the thin public I/O wrappers (snapshot_checkpoint,save_checkpoint,export_lora, …) stay in_impl.py.Equivalence and stacking
main's current method bodies (modulo_impl.qualification and theselfannotation). None of the 41 was edited onmainsince the fork (Price warm waves by the fit later plans measured, not the first plan's #991/Validate canonical checkpoint optimizer counters #992/Preserve GPU image smoke and downstream dispatch #993 checked per method), so nothing needed porting.forward_micro_batchesimplementation separately from its@overloadstubs), all AST-identical tomain's, and 101 bindings (26 memory, 34 planner, 31 slots, 10 optimizer); defs ∩ bindings = ∅ and defs ∪ bindings =main's 183-method set. The rebase was done by regenerating both files from Move TrainerRank micro-batch planning into trainer_rank/_micro_batch_planner #1000's_impl.pywith the extraction generator rather than hand-resolving markers, so no stitched methods are possible. Newly dead imports (deepcopy,hashlib,LocalOptimizerState) removed;ruff --select F401clean across_impl.pyand all four extraction modules.TrainerRank.__new__smoke passing under each.Validation
tests/unit/test_trainer_rank_*.pyat-n 4: 1,311 passed / 19 failed on both the Move TrainerRank micro-batch planning into trainer_rank/_micro_batch_planner #1000 baseline and this branch, identical failure sets (pre-existing megatron/distributed environment failures).test_trainer_rank_backward_work.pyserially: 23 passed; the eight methods itsactual_rankharness extracts from_impl.pyby name are all still defs.ruff check,ruff format --checkclean;ty checkshows the same 6 pre-existing_checkpoint.pydiagnostics asmain._impl.Xtable cross-checked against every_implname patched in tests, identical failure sets on base and branch across 1,613 tests. Verdict: safe to land; its one nit (the module/method name collision) is resolved by the_optimizer.pyname._impl.py: 9,843 → 5,632 lines across the three PRs, with 101 methods relocated into four concern-named modules.Note for xdist runs:
test_trainer_rank_gpu_ci.pyparametrizes from a set, so workers collect in different orders unlessPYTHONHASHSEEDis fixed — pre-existing onmain.