Fix Tunix state translation to handle Flax NNX rng count structures - #4660
Open
chiajunglien wants to merge 1 commit into
Open
Fix Tunix state translation to handle Flax NNX rng count structures#4660chiajunglien wants to merge 1 commit into
chiajunglien wants to merge 1 commit into
Conversation
chiajunglien
requested review from
abhinavclemson,
bvandermoon,
gobbleturk and
khatwanimohit
as code owners
July 29, 2026 07:53
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
chiajunglien
requested review from
A9isha,
NuojCheng,
RissyRan,
SurbhiJainUSC,
aireenmei,
darisoy,
dipannita08,
gagika,
hengtaoguo,
huytransformer,
igorts-git,
jiangjy1982,
richjames0,
shralex,
suexu1025,
vipannalla and
xibinliu
as code owners
July 29, 2026 07:53
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fix Tunix state translation (unstacking) crashes in
train_rl.pycaused by Flax NNX 1D arrays and scalar RNG states when syncing weights from MaxText to vLLM rollout engine.Root Cause
Tunix’s
transfer_state_directlylogic intunix/generate/utils.pydefaults to unstacking layers overscan_axis=1.This assumption fails critically against Flax NNX's state representations under
scan_layers=True, resulting in two distinctIndexErrorfailure modes depending on the model architecture:Llama-3.1-70B (1D Array Slicing IndexError):
State parameters like
dropout.rngs.params.countevaluate as 1D arrays (e.g., shape(80,)) when stacked over layers.Tunix attempts to slice this along
scan_axis=1, immediately throwingtuple index out of rangein_bulk_align_and_unstackbecause the requested axis does not exist.DAG Error Log
Shortened Error Trace:
[2026-07-29, 05:02:29 UTC] {xpk.py:365} INFO - [rank0]: File "/usr/local/lib/python3.12/site- packages/tunix/generate/utils.py", line 1697, in intersect_trees [2026-07-29, 05:02:29 UTC] {xpk.py:365} INFO - [rank0]: unstacked_cache[cache_key] = _bulk_align_and_unstack( [2026-07-29, 05:02:29 UTC] {xpk.py:365} INFO - [rank0]: ^^^^^^^^^^^^^^^^^^^^^^^^ [2026-07-29, 05:02:29 UTC] {xpk.py:365} INFO - [rank0]: File "/usr/local/lib/python3.12/site- packages/tunix/generate/utils.py", line 1257, in _bulk_align_and_unstack [2026-07-29, 05:02:29 UTC] {xpk.py:365} INFO - [rank0]: + (arr.shape[scan_axis],) [2026-07-29, 05:02:29 UTC] {xpk.py:365} INFO - [rank0]: ~~~~~~~~~^^^^^^^^^^^ [2026-07-29, 05:02:29 UTC] {xpk.py:365} INFO - [rank0]: IndexError: tuple index out of rangeGemma3-4B (Scalar Pure-Unstack Indexing limit):
Due to Gemma's sliding window attention blocks,
unroll_gemma_scanned_weightsbypasses scalardropoutandrngfields from being explicitly unrolled. When these scalars (shape()) reach Tunix,_unstack_scanned_paramnativelyprocesses them via the "pure unstacking" code path and returns a tuple of length 1 (i.e.
(src_val,)).However, vLLM expects values for all 34 independent layers. The subsequent state loading logic attempts to access
unstacked_cache[cache_key][layer_idx](e.g.,layer_idx=33), resulting in a criticalIndexErrortraversing the length-1 tuple.DAG Error Log
Shortened Error Trace:
[2026-07-29, 04:14:06 UTC] {xpk.py:365} INFO - [rank0]: File "/usr/local/lib/python3.12/site-packages/tunix/generate/utils.py", line 1767, in transfer_state_directly [2026-07-29, 04:14:06 UTC] {xpk.py:365} INFO - [rank0]: final_source, final_spec = intersect_trees(full_source_dict, full_target_spec) [2026-07-29, 04:14:06 UTC] {xpk.py:365} INFO - [rank0]: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ [2026-07-29, 04:14:06 UTC] {xpk.py:365} INFO - [rank0]: File "/usr/local/lib/python3.12/site-packages/tunix/generate/utils.py", line 1702, in intersect_trees [2026-07-29, 04:14:06 UTC] {xpk.py:365} INFO - [rank0]: sliced_val = unstacked_cache[cache_key][layer_idx] [2026-07-29, 04:14:06 UTC] {xpk.py:365} INFO - [rank0]: ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^ [2026-07-29, 04:14:06 UTC] {xpk.py:365} INFO - [rank0]: IndexError: tuple index out of rangeSolution
Expanded the
_tpu_inference_compat_patchescontext manager intrain_rl.pyto gracefully handle these NNX state edge cases duringtunix.generate.utilsoperations:1. Dynamic
scan_axisfallback: Intercepted both_bulk_align_and_unstackand_unstack_scanned_paramto check array dimensions prior to execution. If an array has insufficient dimensions (len(arr.shape) <= scan_axis), it safely assignsscan_axis=0to accommodate 1D state arrays smoothly.2. Broadcasting scalars robustly: Within
_compat_unstack, if the unwrapped result yields a length-1 tuple (due tosrc_shape == tgt_shapefor fully broadcast/scalar parameters), the tuple is replicated (res * 256) to guaranteesubsequent
[layer_idx]lookups succeed uniformly across diverse model depths.Tests
Log: https://cloudlogging.app.goo.gl/ebVYu3HB79cfkKxQA
Log: https://cloudlogging.app.goo.gl/2YAsHHGbKdfUNerm9
xpk workload create-pathways \ --cluster=v5p-128-bodaborg-europe-west4-b \ --workload=gemma3-rl \ --tpu-type=v5p-128 \ --num-slices=1 \ --priority=very-high \ --project=cloud-tpu-multipod-dev \ --zone=europe-west4-b \ --docker-image=[gcr.io/tpu-prod-env-multipod/gemma3-rl](http://gcr.io/tpu-prod-env-multipod/maxtext_post_training_nightly:28210168847):latest \ --env GCS_OUTPUT=gs://ml-auto-solutions/output/unowned/rl-f8c-v5p-128-2026-07-29-03-29-13/ \ --skip-validation \ --command='set -xue; export TPU_MIN_LOG_LEVEL=0 && export TF_CPP_MIN_LOG_LEVEL=0 && export TPU_STDERR_LOG_LEVEL=0 && export JAX_PLATFORMS=proxy,cpu && export JAX_BACKEND_TARGET=grpc://127.0.0.1:29000 && export ENABLE_PATHWAYS_PERSISTENCE=1 && bash tests/end_to_end/tpu/gemma3/4b/test_gemma3_rl.sh post-20260729T030450 true'Checklist
Before submitting this PR, please make sure (put X in square brackets):
gemini-reviewlabel.