Skip to content

[NNX] Emergency checkpoint: build the manager with a checkpoint-layout abstract - #4372

Merged
copybara-service[bot] merged 1 commit into
mainfrom
fix/nnx-emc-linen-abstract
Jul 13, 2026
Merged

copybara-service[bot] merged 1 commit into
mainfrom
fix/nnx-emc-linen-abstract

Conversation

@ecnal-cienet

@ecnal-cienet ecnal-cienet commented Jul 7, 2026 •

Copy link
Copy Markdown
Collaborator

Description

This PR aims to fix issue b/530068041

The maxtext_emc_resume_from_gcs e2e job fails when a pure_nnx run resumes from its GCS checkpoint:

ValueError: User-provided restore item and on-disk value metadata tree structures do not match
  model:     - Source: {'decoder': ...}   - Target: MISSING
  opt_state: - Source: MISSING            - Target: [{'count': ...}, ...]

A pure_nnx run saves in the on-disk checkpoint layout — Linen params/opt_state/step plus an nnx_aux subtree, via to_checkpoint_dict — so pure_nnx and Linen checkpoints stay interchangeable. Both the regular and the emergency manager save that way.

The difference is on the restore side. The regular manager restores against the item it is given at restore time. The emergency manager instead bakes in the abstract it is constructed with and restores against that, ignoring the restore-time item. create_orbax_emergency_checkpoint_manager was handing it get_abstract_state's NNX-native tree (model/optimizer), so Orbax compared a checkpoint-layout tree on disk against an NNX target and raised. This is also why converting the restore-time item alone did not help: the emergency manager never looks at that item.

Fix: convert the abstract with to_checkpoint_dict in create_orbax_emergency_checkpoint_manager when it is an nnx.State, so the blueprint the manager holds matches what maybe_save_checkpoint writes. split_for_checkpoint already requires that save and restore partition the state identically; the manager's baked-in abstract is a third copy of that partition, and it now goes through the same function as the other two. The restore path reshapes back to NNX, so the state we train on is still NNX, and the on-disk format is unchanged. Six lines, in the constructor. A Linen state is not an nnx.State, so it is passed through untouched.

Tests

tests/unit/checkpointing_emergency_nnx_test.py (5) — the emergency-manager counterpart of checkpointing_nnx_roundtrip_test.py:

  • the manager is handed the checkpoint layout (params/opt_state/step/nnx_aux), not the NNX model/optimizer roots. Orbax is mocked, so this one runs in normal CI and catches a regression here without an emergency-checkpoint setup.
  • a Linen state is passed through unchanged.
  • a full round trip through a real EmergencyCheckpointManager is leaf-exact: weights, optimizer moments, dropout rng, batch stats.
  • nnx_aux is genuinely restored rather than reset to a fresh init — checked by value (rng count, batch-norm mean, optimizer step), since a reset keeps the tree structure intact and would slip past the structural check.
  • caches stay ephemeral: excluded from the baked-in abstract, so they keep their init value on restore while the rng beside them still comes back from nnx_aux.

Reverting the six lines fails four of the five (the fifth is the Linen pass-through case, which correctly still passes).

End-to-end on a v6e-8 (jax 0.10.0, orbax-checkpoint 0.12.1)

  1. Save checkpoint for later tests: (passed, log)
  2. EMC resume WITHOUT fix (failed expected, log)
  3. EMC resume WITH fix (passed, log)

Checklist

Before submitting this PR, please make sure (put X in square brackets):

  • I have performed a self-review of my code. For an optional AI review, add the gemini-review label.
  • I have necessary comments in my code, particularly in hard-to-understand areas.
  • I have run end-to-end tests tests and provided workload links above if applicable.
  • I have made or will make corresponding changes to the doc if needed, including adding new documentation pages to the relevant Table of Contents (toctree directive) as explained in our documentation.

@ecnal-cienet
ecnal-cienet force-pushed the fix/nnx-emc-linen-abstract branch from 0e7124b to 03d1b36 Compare July 7, 2026 20:32
@codecov

codecov Bot commented Jul 7, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@ecnal-cienet
ecnal-cienet force-pushed the fix/nnx-emc-linen-abstract branch 5 times, most recently from 1c96f5c to 27a1688 Compare July 13, 2026 14:43
@ecnal-cienet ecnal-cienet changed the title [NNX] Emergency checkpoint: build the manager with a Linen-layout abstract [NNX] Emergency checkpoint: build the manager with a checkpoint-layout abstract Jul 13, 2026
@ecnal-cienet
ecnal-cienet marked this pull request as ready for review July 13, 2026 15:36
restored = self._restore(manager, _Model)

self.assertEqual(jax.tree_util.tree_structure(saved), jax.tree_util.tree_structure(restored))
matches = jax.tree_util.tree_map(_leaf_equal, saved, restored)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be better adding is_leaf=lambda...

…t abstract

pure_nnx saves in the on-disk checkpoint layout (Linen params/opt_state/step plus an
nnx_aux subtree) for both the regular and emergency managers. But the emergency manager
is constructed with the NNX-native abstract (model/optimizer) from get_abstract_state,
and unlike the regular manager it bakes that abstract in and restores against it,
ignoring the restore-time item. So on resume Orbax compared a checkpoint-layout tree on
disk against an NNX target and raised 'User-provided restore item and on-disk value
metadata tree structures do not match', failing the EMC resume-from-GCS job.

Convert the abstract with to_checkpoint_dict in create_orbax_emergency_checkpoint_manager
so the baked-in blueprint matches what maybe_save_checkpoint writes; the restore path
reshapes it back to NNX. Save, restore and the manager's blueprint now all partition the
state the same way, through to_checkpoint_dict.

Tests mirror checkpointing_nnx_roundtrip_test for the emergency manager: a mock guard that
it is handed the checkpoint layout rather than the NNX roots, plus real save/restore round
trips showing weights, optimizer moments, the dropout rng and batch stats all come back
from nnx_aux, and that caches stay ephemeral.
@ecnal-cienet
ecnal-cienet force-pushed the fix/nnx-emc-linen-abstract branch from 27a1688 to 9dc7704 Compare July 13, 2026 18:04
@copybara-service
copybara-service Bot merged commit a6320df into main Jul 13, 2026
42 of 45 checks passed
@copybara-service
copybara-service Bot deleted the fix/nnx-emc-linen-abstract branch July 13, 2026 18:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants