Skip to content
Draft

Cl 834 #5145

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.git
maxtext_venv
.venv
venv13
209 changes: 209 additions & 0 deletions run_custom_qwen3_next_on_xpk.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#!/bin/bash
set -e

# Activate Python virtual environment
source /usr/local/google/home/muskansh/maxtext_env/bin/activate

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

This script contains several hardcoded user-specific paths and resource names, which makes it non-portable and difficult for other developers to use.

For example:

  • Line 5: source /usr/local/google/home/muskansh/maxtext_env/bin/activate
  • Line 30: cd /usr/local/google/home/muskansh/maxtext
  • Line 180: client.bucket("muskansh-data")
  • Line 186: PYTHONPATH=/usr/local/google/home/muskansh/xpk/src

These should be parameterized, for instance, by using environment variables defined at the top of the script or passed as arguments. This would greatly improve the script's reusability.

Suggestion:

At the top of the script, define variables for these paths and names, allowing them to be overridden by environment variables if they are already set:

# --- User-configurable paths and names ---
MAXTEXT_DIR="${MAXTEXT_DIR:-/usr/local/google/home/muskansh/maxtext}"
VENV_PATH="${VENV_PATH:-/usr/local/google/home/muskansh/maxtext_env}"
XPK_DIR="${XPK_DIR:-/usr/local/google/home/muskansh/xpk}"
GCS_BUCKET="${GCS_BUCKET:-muskansh-data}"

Then use these variables throughout the script, for example:

# line 5
source "${VENV_PATH}/bin/activate"

# line 30
cd "${MAXTEXT_DIR}" && \

# line 180
... client.bucket(\"${GCS_BUCKET}\") ...

# line 186
PYTHONPATH="${XPK_DIR}/src" python3 -P -m xpk.main workload create \


# --- Environment Variables ---
export PROJECT_ID="tpu-prod-env-one-vm"
export CLUSTER_NAME="v6e-256-c2b3-b478935789"
export ZONE="us-central2"

# --- Configuration & Automated Image Build ---
TIMESTAMP=$(date +%m%d%H%M%S)
export WORKLOAD_IMAGE="gcr.io/tpu-prod-env-one-vm/param3_21jul:muskansh_${TIMESTAMP}"
export WORKLOAD_NAME="muskansh-qn80b-${TIMESTAMP}"
export DEVICE_TYPE="v6e-256"
export NUM_SLICES=1
export PRIORITY="very-high"
export MAX_RESTARTS=0
export NUM_STEPS=15
export MODEL_NAME="qwen3-next-80b-a3b"
export BASE_OUTPUT_DIR="/tmp/qwen3-next-80b-profiles/run-${TIMESTAMP}"

echo "========================================================================"
echo "Building and uploading Docker runner image from /usr/local/google/home/muskansh/maxtext"
echo "Target Image: ${WORKLOAD_IMAGE}"
echo "========================================================================"

(
cd /usr/local/google/home/muskansh/maxtext && \
CLOUD_IMAGE_NAME="${WORKLOAD_IMAGE}" \
BASE_IMAGE="gcr.io/tpu-prod-env-one-vm/param3_21jul:latest" \
bash src/dependencies/scripts/docker_upload_runner.sh
)

echo "Docker image upload complete: ${WORKLOAD_IMAGE}"

# --- XLA Flags ---
XLA_FLAGS_ARRAY=(
"--xla_msa_enable_sync_slice_replacement=false"
"--xla_tpu_enable_sparse_core_collective_offload_2d_all_gather=true"
"--xla_tpu_enable_sparse_core_collective_offload_reduce_scatter=true"
"--xla_msa_enable_sync_copy_replacement=false"
"--xla_tpu_scoped_vmem_limit_kib=81000"
"--xla_tpu_enable_sparse_core_collective_offload_all_gather=true"
"--xla_tpu_enable_sparse_core_collective_offload_all_reduce=true"
"--xla_tpu_enable_concurrent_sparse_core_offloading=true"
"--xla_tpu_enable_sparse_core_offload_queuing_in_lhs=true"
"--xla_tpu_enable_layer_scheduler_for_dependent_collectives=true"
"--xla_tpu_use_single_sparse_core_for_all_gather_offload=true"
"--xla_tpu_sparse_core_all_gather_latency_multiplier=1"
"--xla_tpu_sparse_core_reduce_scatter_latency_multiplier=3"
"--xla_tpu_offload_gather_to_sparsecore=true"
"--xla_tpu_dvfs_p_state=7"
"--xla_tpu_disable_sparse_core_collective_offload_remover=true"
"--xla_tpu_use_tc_device_shape_on_sc=true"
"--xla_sc_enable_instruction_fusion=false"
"--xla_sc_disable_megacore_partitioning=true"
"--xla_tpu_enable_async_collective_fusion=true"
"--xla_tpu_overlap_compute_collective_tc=true"
"--xla_tpu_enable_async_collective_fusion_multiple_steps=true"
"--xla_tpu_enable_async_collective_fusion_fuse_all_gather=false"
"--xla_tpu_enable_async_collective_fusion_fuse_reduce_scatter=false"
"--xla_tpu_enable_async_collective_fusion_fuse_all_reduce=false"
"--xla_tpu_enable_latency_hiding_scheduler=true"
"--xla_latency_hiding_scheduler_rerun=10"
"--xla_tpu_all_gather_collective_matmul_mode=post_spmd_conservative"
"--xla_tpu_reduce_scatter_collective_matmul_mode=post_spmd_conservative"
"--xla_latency_hiding_scheduler_enable_selective_resources=true"
"--xla_tpu_enable_scheduler_memory_pressure_tracking=true"
"--xla_tpu_host_transfer_overlap_limit=4"
"--xla_tpu_aggressive_opt_barrier_removal=ENABLED"
"--xla_lhs_prioritize_async_depth_over_stall=ENABLED"
"--xla_should_allow_loop_variant_parameter_in_chain=ENABLED"
"--xla_should_add_loop_invariant_op_in_chain=ENABLED"
"--xla_max_concurrent_host_send_recv=100"
"--xla_tpu_rerun_latency_hiding_scheduler_post_sc_assignment=true"
"--xla_tpu_scheduler_percent_shared_memory_limit=150"
)
export XLA_FLAGS="${XLA_FLAGS_ARRAY[*]}"

# --- MaxText Workload Overrides ---
MAXTEXT_ARGS_ARRAY=(
"model_name=${MODEL_NAME}"
"base_output_directory=${BASE_OUTPUT_DIR}"
"run_name=${WORKLOAD_NAME}"
"dataset_type=synthetic"
"dataset_name=synthetic"
"dtype=bfloat16"
"allow_split_physical_axes=True"
"ici_expert_parallelism=4"
"use_ring_of_experts=True"
"custom_mesh=hybrid_ring_64x4"
"use_ragged_sort=True"
"use_random_routing=False"
"per_device_batch_size=4"
"num_moe_token_chunks=2"
"opt_type=muon"
"max_target_length=2048"
"ragged_buffer_factor=1.5"
"remat_policy=custom"
"decoder_layer_input=device"
"context=device"
"reuse_example_batch=1"
"ici_fsdp_parallelism=-1"
"steps=${NUM_STEPS}"
"sa_block_q=1024"
"sa_block_kv=1024"
"sa_block_kv_compute=512"
"sa_block_q_dkv=1024"
"sa_block_kv_dkv=1024"
"sa_block_kv_dkv_compute=1024"
"sa_fuse_reciprocal=false"
"use_splash_scheduler=true"
"sa_use_base2_exp=true"
"dq_reduction_steps=3"
"hardware=tpu"
"skip_jax_distributed_system=False"
"attention=flash"
"use_tokamax_splash=True"
"sa_use_fused_bwd_kernel=True"
"sparse_matmul=True"
"megablox=True"
"wi_tile_fwd_batch_seq=512"
"wi_tile_dlhs_batch_seq=512"
"wi_tile_drhs_batch_seq=512"
"wo_tile_fwd_batch_seq=512"
"wo_tile_dlhs_batch_seq=512"
"wo_tile_drhs_batch_seq=512"
"wi_tile_fwd_embed_dim=3072"
"wi_tile_fwd_mlp_dim=1536"
"wi_tile_dlhs_embed_dim=3072"
"wi_tile_dlhs_mlp_dim=1536"
"wi_tile_drhs_embed_dim=3072"
"wi_tile_drhs_mlp_dim=1536"
"wo_tile_fwd_embed_dim=3072"
"wo_tile_fwd_mlp_dim=1536"
"wo_tile_dlhs_embed_dim=3072"
"wo_tile_dlhs_mlp_dim=1536"
"wo_tile_drhs_embed_dim=3072"
"wo_tile_drhs_mlp_dim=1536"
"use_tokamax_gmm=True"
"use_gmm_v2=True"
"optimizer_memory_host_offload=False"
"parameter_memory_host_offload=False"
"enable_checkpointing=False"
"async_checkpointing=False"
"tokenizer_type=huggingface"
"tokenizer_path=assets/tokenizers/qwen3-tokenizer"
"override_model_config=true"
"mhc_expansion_rate=4"
"enable_mhc_lite=True"
"use_mhc_pallas_kernel=True"
"mhc_pallas_kernel_fwd_block_size=256"
"mhc_pallas_kernel_bwd_block_size=256"
"use_gdn_kernel=True"
"use_hybrid_gdn=True"
"profiler=xplane"
"profiler_steps=2"
"skip_first_n_steps_for_profiler=1"
"enable_tpu_profiling_options=True"
"upload_all_profiler_results=False"
"enable_tensorboard=False"
"abort_on_nan_loss=False"
"abort_on_inf_loss=False"
)
MAXTEXT_ARGS="${MAXTEXT_ARGS_ARRAY[*]}"

USER_TOKEN=$(gcloud auth application-default print-access-token 2>/dev/null || gcloud auth print-access-token 2>/dev/null || true)

# The command to run inside the container
RUN_COMMAND="set -e && \
export LIBTPU_INIT_ARGS=\"${XLA_FLAGS}\" && \
export JAX_PLATFORMS='tpu,cpu' && \
export ENABLE_PJRT_COMPATIBILITY='true' && \
export JAX_DISTRIBUTED_INITIALIZE_TIMEOUT=1800 && \
export PYTHONPATH=/deps:/deps/src:/deps/src/maxtext/src && \
export CLOUDSDK_AUTH_ACCESS_TOKEN='${USER_TOKEN}' && \
python3 src/maxtext/trainers/pre_train/train.py src/maxtext/configs/base.yml ${MAXTEXT_ARGS} && \
(python3 -c 'import os, glob; from google.cloud import storage; import google.oauth2.credentials; token = os.environ.get(\"CLOUDSDK_AUTH_ACCESS_TOKEN\"); client = storage.Client(credentials=google.oauth2.credentials.Credentials(token), project=\"tpu-prod-env-one-vm\") if token else storage.Client(project=\"tpu-prod-env-one-vm\"); bucket = client.bucket(\"muskansh-data\"); [bucket.blob(f\"qwen3-next-80b-profiles/{os.path.relpath(p, \"/tmp/qwen3-next-80b-profiles\")}\").upload_from_filename(p) for p in glob.glob(\"/tmp/qwen3-next-80b-profiles/**/*\", recursive=True) if os.path.isfile(p)]' || true) && \
sleep 3600"

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 RUN_COMMAND ends with sleep 3600. This will keep the container running for an hour after the main training command finishes. While this can be useful for debugging, it's not ideal for a script in a shared repository as it can lead to resource wastage if not intended.

It would be better to make this behavior optional or configurable. For example, you could add an environment variable KEEP_ALIVE_SECS that defaults to 0.

Suggested change
sleep 3600"
sleep 0"


# --- XPK Workload Creation ---
echo "Creating XPK workload: ${WORKLOAD_NAME} on cluster: ${CLUSTER_NAME}"

PYTHONPATH=/usr/local/google/home/muskansh/xpk/src python3 -P -m xpk.main workload create \
--cluster="${CLUSTER_NAME}" \
--project="${PROJECT_ID}" \
--zone="${ZONE}" \
--priority="${PRIORITY}" \
--max-restarts="${MAX_RESTARTS}" \
--device-type="${DEVICE_TYPE}" \
--num-slices="${NUM_SLICES}" \
--docker-image="${WORKLOAD_IMAGE}" \
--enable-debug-logs \
--workload="${WORKLOAD_NAME}" \
--command="${RUN_COMMAND}"

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}"

echo "========================================================================"
echo "📋 Pantheon Cloud Logging (Worker 0 Logs):"
echo "${LOGS_URL}"
echo ""
echo "☸️ GKE Workload Details:"
echo "${GKE_URL}"
echo ""
echo "========================================================================"
3 changes: 3 additions & 0 deletions src/dependencies/dockerfiles/maxtext_runner.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ ENV MAXTEXT_REPO_ROOT=/deps
# Set the working directory in the container
WORKDIR /deps

# Install GDN v3 Tokamax commit
RUN pip install --no-deps --no-cache-dir --force-reinstall git+https://github.com/openxla/tokamax.git@b626dd8b54d708047788cf2ec538cba63a4e3739

# Copy assets separately
COPY ${PACKAGE_DIR}/maxtext/assets/ "${MAXTEXT_ASSETS_ROOT}"

Expand Down
3 changes: 3 additions & 0 deletions src/maxtext/common/checkpointing.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,9 @@ def create_orbax_checkpoint_manager(
enable_autocheckpoint: bool = False,
todelete_subdir: str | None = None,
todelete_full_path: str | None = None,
checkpoint_storage_target_data_file_size_bytes: int | None = None,
*args,
**kwargs,
):
"""Returns specified Orbax (async or not) CheckpointManager or None if checkpointing is disabled."""
if not enable_checkpointing:
Expand Down
11 changes: 10 additions & 1 deletion src/maxtext/configs/base.yml
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ use_2d_fsdp_sharding: false
# deepseek moe
first_num_dense_layers: 0 # number of initial dense layers in the model
shared_experts: 0
moe_shared_expert_gate: false
routed_scaling_factor: 1.0 # scaling factor for routing scores
routed_score_func: "" # scoring function for routing
routed_bias: false # a flag if a learnable bias is added for routing
Expand All @@ -317,6 +318,8 @@ topk_routing_group: -1 # number of top groups to route inputs. For EP,
use_batch_split_schedule: false # a flag if splitting batch into micro-batches to hide communications that yields performance benefits.
batch_split_factor: 1 # the factor by which to split the batch. Only used if use_batch_split_schedule is true.

full_attention_layer_offset: 0

# For complex architectures like llama4 there are repeated sets of
# inhomogeneous layers. E.g. maverick uses [dense+rope, moe+rope, dense+rope, moe+nope]
# which can only be scanned together in one large block of inhomogeneous_layer_cycle_interval=4 layers.
Expand Down Expand Up @@ -792,7 +795,7 @@ sft_train_on_completion_only: false

# dataset_type must be synthetic, hf, grain, tfds
# details in: https://github.com/AI-Hypercomputer/maxtext/blob/main/docs/guides/data_input_pipeline.md
dataset_type: tfds
dataset_type: synthetic
# for TFDS input pipeline (dataset_type=tfds)
dataset_path: "" # your path given as argument in download_dataset.sh, e.g. "gs://my-maxtext-dataset/"
dataset_name: 'c4/en:3.1.0'
Expand Down Expand Up @@ -1019,6 +1022,8 @@ mu_dtype: "" # data type to store "mu" of AdamW tracking the first moment. Inher
muon_beta: 0.95 # Decay rate for the exponentially weighted average of grads.
muon_weight_decay: 0 # Strength of the weight decay regularization. This is multiplied with the learning rate.
muon_consistent_rms: None # If None, apply width scaling to updates. If float, apply consistent rms scaling (recommend 0.2).
muon_ns_steps: 5 # Number of Newton-Schulz iterations for Muon optimizer.
muon_use_all_to_all: true # Whether to use all-to-all communication during Newton-Schulz iterations in Muon.


# Use iota operator in Embed
Expand Down Expand Up @@ -1344,6 +1349,10 @@ gdn_chunk_size: 64
use_qk_norm_in_gdn: true
# The ratio of dimension to apply ROPE on
partial_rotary_factor: 1.0
# Whether to use GDN Pallas kernel
use_gdn_kernel: false
# Whether to use hybrid GDN v3 Tokamax forward + Custom VJP backward
use_hybrid_gdn: false

use_tokamax_splash: false
# Setting this flag will use a non-pallas implementation.
Expand Down
12 changes: 12 additions & 0 deletions src/maxtext/configs/custom_mesh_and_rule/shard-exp-on-fsdp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ logical_axis_rules: [
['activation_q_length', ['context']],
['activation_kv_batch', ['data', 'fsdp', 'fsdp_transpose', 'expert']],
# Attention Weights
['heads', ['fsdp_transpose', 'expert']],
['q_heads', ['fsdp_transpose', 'expert']],
['kv_heads', ['fsdp_transpose', 'expert']],
['qkv', []],
['kv', []],
['kv_head_dim', []],
['q_lora', ['fsdp', 'fsdp_transpose', 'expert']],
["q_lora_up_proj", []],
['kv_lora', ['fsdp', 'fsdp_transpose', 'expert']],
Expand Down Expand Up @@ -68,8 +74,14 @@ logical_axis_rules: [
['activation_stage', 'stage'],
# General Weights
['mlp', ['fsdp_transpose']],
['gdn_head', ['fsdp_transpose', 'expert']],
['embed', ['fsdp', 'fsdp_transpose', 'context', 'expert']],
['embed', ['fsdp', 'context', 'expert']],
Comment on lines +78 to 79

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

There appear to be duplicate logical axis rules for 'embed'. Depending on how this configuration is parsed, the first rule might be overridden by the second, or it could lead to unexpected behavior. It's best to remove the redundant or incorrect entry to avoid confusion and potential issues.

['embed_attn', ['fsdp', 'context', 'expert']],
['norm', []],
['layers', 'stage'],
['dense_layers', []],
['moe_layers', []],
['local_layers', []],
['mhc', []],
]
87 changes: 87 additions & 0 deletions src/maxtext/configs/models/qwen3-next-80b-a3b-256e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# maxtext/configs/models/qwen3-next-80b-a3b-256e.yml

# Set the decoder block to our new implementation
decoder_block: "qwen3_next"

# Core Architectural Parameters
base_emb_dim: 3072
base_num_decoder_layers: 40
base_num_query_heads: 64
base_num_kv_heads: 8
head_dim: 64
vocab_size: 128008
normalization_layer_epsilon: 1.0e-6

# MoE Specific Parameters
# base_mlp_dim sizes the dense-prefix layer's MLP (see first_num_dense_layers below);
# base_moe_mlp_dim sizes every other (MoE) layer's routed + shared experts.
base_mlp_dim: 10240
base_moe_mlp_dim: 1536
num_experts: 256
shared_experts: 1
num_experts_per_tok: 8
norm_topk_prob: true
# Router parity with reference: fp32 gate-logit matmul.
float32_gate_logits: true

# DeepSeek-V3-style router: sigmoid scoring, aux-loss-free expert-bias balancing
# (primary mechanism) plus a small complementary aux loss (secondary safety net,
# matching DeepSeek-V3's own combined approach), and a top-k weight scaling factor.
routed_score_func: "sigmoid"
routed_bias: true
routed_bias_update_rate: 1.0e-3
routed_scaling_factor: 2.5
load_balance_loss_weight: 1.0e-3

# Explicit (diverges from the reference's False): keeps the shared-expert gate
# that real Qwen3-Next uses.
moe_shared_expert_gate: true

# The first layer is a dense MLP (no MoE) and always uses full attention,
# mirroring DeepSeek V3's dense-prefix pattern.
first_num_dense_layers: 1

# Qwen3-Next Specific Parameters for Linear Attention (Gated Delta Net).
# Attention schedule (2 GDN : 1 full-attention, full-attention first in each cycle):
# [0,1,1,0,1,1,0,1,1,...] where 0=full attention, 1=Gated Delta Net.
inhomogeneous_layer_cycle_interval: 3
full_attention_layer_offset: 0
gdn_conv_kernel_dim: 4
gdn_key_head_dim: 128
gdn_value_head_dim: 128
gdn_num_key_heads: 16
gdn_num_value_heads: 32
gdn_chunk_size: 64
# L2-norm on Q/K inside the Gated Delta Rule is standard practice for linear-attention
# architectures (stabilizes the recurrent state, since linear attention lacks softmax's
# implicit boundedness) and matches real Qwen3-Next's own Gated Delta Net. This is also
# MaxText's own default (base.yml); kept explicit here for clarity.
use_qk_norm_in_gdn: true

# RoPE Settings
rope_max_timescale: 10000
partial_rotary_factor: 1

# Hyper-connections: mHC-lite enabled with Pallas kernel
mhc_expansion_rate: 4
enable_mhc_lite: true
use_mhc_pallas_kernel: true
mhc_pallas_kernel_fwd_block_size: 256
mhc_pallas_kernel_bwd_block_size: 256

# General Model Settings
enable_dropout: false
Loading
Loading