Skip to content

Cl 974697834 - #5127

Draft
muskansh-google wants to merge 9 commits into
AI-Hypercomputer:mainfrom
muskansh-google:cl-974697834
Draft

Cl 974697834#5127
muskansh-google wants to merge 9 commits into
AI-Hypercomputer:mainfrom
muskansh-google:cl-974697834

Conversation

@muskansh-google

Copy link
Copy Markdown
Contributor

Description

Start with a short description of what the PR does and how this is a change from
the past.

The rest of the description includes relevant details and context, examples:

  • why is this change being made,
  • the problem being solved and any relevant context,
  • why this is a good solution,
  • some information about the specific implementation,
  • shortcomings of the solution and possible future improvements.

If the change fixes a bug or a Github issue, please include a link, e.g.,:
FIXES: b/123456
FIXES: #123456

You can also provide a comma-separated list. If you don't want to close a bug but
simply to reference it, use BUGS, e.g.:
BUGS: b/123456

Notice 1: Once all tests pass, the "pull ready" label will automatically be assigned.
This label is used for administrative purposes. Please do not add it manually.

Notice 2: For external contributions, our settings currently require an approval from a MaxText maintainer to trigger CI tests.

Tests

Please describe how you tested this change, and include any instructions and/or
commands to reproduce.

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.

darisoy and others added 9 commits August 25, 2026 21:19
…uon sharding, and mHC-lite Pallas/Mosaic kernels on TPU v6e-256.

- Integrate DeepSeek mHC-lite architecture and high-performance Mosaic/Pallas TPU kernels with custom VJP rules and SPMD shard_map integration.
- Support Qwen3-Next 80B architecture with Gated Delta Net (GDNv3) and Pallas custom VJP in hybrid_gdn.py.
- Configure Muon optimizer and sharding rules for MoE parameters (shard-exp-on-fsdp).
- Update AOT compile, XManager Borg, and XPK launch scripts for Qwen3-Next 80B on TPU v6e-256 (glp_16x16) topology to enable mHC-lite and Pallas kernel flags.
- Add and update unit tests for mHC, GDN, Muon utilities, NNX decoders, and parameter mapping.
- Validated clean AOT compilation on TPU v6e-256 via qn80b-v6e256-compile.sh and unit tests via mhc_test.
- Integrates sharding-aware Muon optimizer supporting Newton-Schulz iterations and partition padding into MaxText.
- Fixes weight dimension indexing in muon_utils.py to account for layer scanning, 1D tensor exclusions, and rank-aware 2D attention projection handling.
- Fixes routing gate exclusion logic to use exact segment matching across gate and router variants.
- Plumbs NamedSharding in sharding.py by collecting momentum trees across multi-branch partitioned optimizers, extracting MuonState NamedTuples, and filtering optax.MaskedNode placeholders.
- Threads mesh through train_utils.py, train_compile.py, and maxtext_engine.py to get_optimizer.
- Add some minor tests throughout.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for the Qwen3-Next model architecture, adds experimental SFT and evaluation pipelines for the Omni (Gemma 3 Vision + Qwen 3 LLM) model, transitions checkpointing to the Orbax v1 API, and implements various kernel and optimizer enhancements such as hybrid GatedDeltaNet (GDN) and Muon improvements. The code review identified several critical runtime bugs, including invalid JAX API usage (such as jax.typeof and an unsupported mode argument in .at().set()), missing epath imports in GCS utilities, potential IndexError and KeyError exceptions in utility functions, and a region mismatch in the XPK runner script.

# Scatter the per-slot dot back to flat slot order; dropped slots stay zero.
dot_local = jnp.sum(gathered.astype(jnp.float32) * sorted_tokens_local.astype(jnp.float32), axis=-1)
slots = jnp.where(mask, sliced_idx_inv, n)
grad_topk_weights = jnp.zeros((n,), jnp.float32).at[slots].set(dot_local, mode="drop")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

The mode argument is not supported by JAX's .at[...].set(...) method and will raise a TypeError at runtime. Since JAX automatically ignores/drops out-of-bounds indices by default, the mode="drop" argument is both invalid and unnecessary.

Suggested change
grad_topk_weights = jnp.zeros((n,), jnp.float32).at[slots].set(dot_local, mode="drop")
grad_topk_weights = jnp.zeros((n,), jnp.float32).at[slots].set(dot_local)

Comment on lines +47 to +48
activation_spec = jax.typeof(y).sharding.spec
scale_spec = jax.typeof(scale).sharding.spec

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

jax.typeof is not a valid JAX API and will raise an AttributeError at runtime. You can directly access the .sharding property of JAX arrays (e.g., y.sharding.spec and scale.sharding.spec).

Suggested change
activation_spec = jax.typeof(y).sharding.spec
scale_spec = jax.typeof(scale).sharding.spec
activation_spec = y.sharding.spec
scale_spec = scale.sharding.spec

Comment on lines +44 to +46
while isinstance(hf_source_keys, list):
depth += 1
hf_source_keys = hf_source_keys[0]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

If hf_source_keys is an empty list [], accessing hf_source_keys[0] will raise an IndexError: list index out of range. We should defensively check that the list is not empty before accessing its first element.

Suggested change
while isinstance(hf_source_keys, list):
depth += 1
hf_source_keys = hf_source_keys[0]
while isinstance(hf_source_keys, list) and hf_source_keys:
depth += 1
hf_source_keys = hf_source_keys[0]

Comment on lines +80 to +84
if not destination_gcs_name.startswith("gs://"):
dest = epath.Path(destination_gcs_name)
dest.parent.mkdir(parents=True, exist_ok=True)
epath.Path(source_file_name).copy(dest, overwrite=True)
return

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

epath is not imported in gcs_utils.py, which will lead to a NameError at runtime. Since gcs_utils.py already imports os and shutil, we can use standard library functions os.makedirs and shutil.copy to perform these local filesystem operations safely and cleanly.

Suggested change
if not destination_gcs_name.startswith("gs://"):
dest = epath.Path(destination_gcs_name)
dest.parent.mkdir(parents=True, exist_ok=True)
epath.Path(source_file_name).copy(dest, overwrite=True)
return
if not destination_gcs_name.startswith("gs://"):
os.makedirs(os.path.dirname(destination_gcs_name), exist_ok=True)
shutil.copy(source_file_name, destination_gcs_name)
return

Comment on lines +102 to +115
if not target_dir.startswith("gs://"):
dest_dir = epath.Path(target_dir)
dest_dir.mkdir(parents=True, exist_ok=True)
for root, _, files in os.walk(local_dir):
for file in files:
if module_name and module_name not in file:
continue
else:
max_logging.log(f"Uploading {file}")
local_path = os.path.join(root, file)
relative_path = os.path.relpath(local_path, local_dir)
dest_path = dest_dir / relative_path
dest_path.parent.mkdir(parents=True, exist_ok=True)
epath.Path(local_path).copy(dest_path, overwrite=True)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

epath is not imported in gcs_utils.py, which will lead to a NameError at runtime. Since gcs_utils.py already imports os and shutil, we can use standard library functions os.makedirs and shutil.copy to perform these local filesystem operations safely and cleanly.

Suggested change
if not target_dir.startswith("gs://"):
dest_dir = epath.Path(target_dir)
dest_dir.mkdir(parents=True, exist_ok=True)
for root, _, files in os.walk(local_dir):
for file in files:
if module_name and module_name not in file:
continue
else:
max_logging.log(f"Uploading {file}")
local_path = os.path.join(root, file)
relative_path = os.path.relpath(local_path, local_dir)
dest_path = dest_dir / relative_path
dest_path.parent.mkdir(parents=True, exist_ok=True)
epath.Path(local_path).copy(dest_path, overwrite=True)
if not target_dir.startswith("gs://"):
os.makedirs(target_dir, exist_ok=True)
for root, _, files in os.walk(local_dir):
for file in files:
if module_name and module_name not in file:
continue
else:
max_logging.log(f"Uploading {file}")
local_path = os.path.join(root, file)
relative_path = os.path.relpath(local_path, local_dir)
dest_path = os.path.join(target_dir, relative_path)
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
shutil.copy(local_path, dest_path)

Comment on lines +194 to +195
LOGS_URL="https://console.cloud.google.com/logs/query;query=resource.type%3D%22k8s_container%22%0Aresource.labels.project_id%3D%22${PROJECT_ID}%22%0Aresource.labels.location%3D%22southamerica-west1%22%0Aresource.labels.cluster_name%3D%22${CLUSTER_NAME}%22%0Aresource.labels.namespace_name%3D%22default%22%0Aresource.labels.pod_name%3A%22${WORKLOAD_NAME}-slice-job-0-0-%22%0Aseverity%3E%3DDEFAULT;storageScope=project;duration=P1D?project=${PROJECT_ID}"
GKE_URL="https://console.cloud.google.com/kubernetes/service/southamerica-west1/${CLUSTER_NAME}/default/${WORKLOAD_NAME}/details?project=${PROJECT_ID}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The region southamerica-west1 is hardcoded in both LOGS_URL and GKE_URL, but the script configures ZONE="us-central2". This discrepancy will generate incorrect links. We should use the ${ZONE} variable dynamically in the URLs instead of hardcoding a different region.

Suggested change
LOGS_URL="https://console.cloud.google.com/logs/query;query=resource.type%3D%22k8s_container%22%0Aresource.labels.project_id%3D%22${PROJECT_ID}%22%0Aresource.labels.location%3D%22southamerica-west1%22%0Aresource.labels.cluster_name%3D%22${CLUSTER_NAME}%22%0Aresource.labels.namespace_name%3D%22default%22%0Aresource.labels.pod_name%3A%22${WORKLOAD_NAME}-slice-job-0-0-%22%0Aseverity%3E%3DDEFAULT;storageScope=project;duration=P1D?project=${PROJECT_ID}"
GKE_URL="https://console.cloud.google.com/kubernetes/service/southamerica-west1/${CLUSTER_NAME}/default/${WORKLOAD_NAME}/details?project=${PROJECT_ID}"
LOGS_URL="https://console.cloud.google.com/logs/query;query=resource.type%3D%22k8s_container%22%0Aresource.labels.project_id%3D%22${PROJECT_ID}%22%0Aresource.labels.location%3D%22${ZONE}%22%0Aresource.labels.cluster_name%3D%22${CLUSTER_NAME}%22%0Aresource.labels.namespace_name%3D%22default%22%0Aresource.labels.pod_name%3A%22${WORKLOAD_NAME}-slice-job-0-0-%22%0Aseverity%3E%3DDEFAULT;storageScope=project;duration=P1D?project=${PROJECT_ID}"
GKE_URL="https://console.cloud.google.com/kubernetes/service/${ZONE}/${CLUSTER_NAME}/default/${WORKLOAD_NAME}/details?project=${PROJECT_ID}"

Comment on lines +670 to +678
def _batch_axis_size(self, axis_names: Any) -> int:
"""Product of mesh dims backing one PartitionSpec entry (None -> 1)."""
if axis_names is None:
return 1
names = axis_names if isinstance(axis_names, tuple) else (axis_names,)
size = 1
for name in names:
size *= self._mesh.shape[name]
return size

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

If name is not present in self._mesh.shape (e.g., due to a mismatch or custom mesh rules), accessing self._mesh.shape[name] will raise a KeyError. Using .get(name, 1) is safer and prevents potential runtime errors.

Suggested change
def _batch_axis_size(self, axis_names: Any) -> int:
"""Product of mesh dims backing one PartitionSpec entry (None -> 1)."""
if axis_names is None:
return 1
names = axis_names if isinstance(axis_names, tuple) else (axis_names,)
size = 1
for name in names:
size *= self._mesh.shape[name]
return size
def _batch_axis_size(self, axis_names: Any) -> int:
"""Product of mesh dims backing one PartitionSpec entry (None -> 1)."""
if axis_names is None:
return 1
names = axis_names if isinstance(axis_names, tuple) else (axis_names,)
size = 1
for name in names:
size *= self._mesh.shape.get(name, 1)
return size

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants