Skip to content

Commit 793d421

Browse files
Merge pull request #2487 from AI-Hypercomputer:parambole/maxtext_qwen3_next_v1
PiperOrigin-RevId: 821851030
2 parents 1c138f7 + 0e03921 commit 793d421

8 files changed

Lines changed: 1845 additions & 8 deletions

File tree

src/MaxText/common_types.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ class DecoderBlockType(enum.Enum):
8686
GEMMA3 = "gemma3"
8787
QWEN3 = "qwen3"
8888
QWEN3_MOE = "qwen3_moe"
89+
QWEN3_NEXT = "qwen3_next"
8990
GPT3 = "gpt3"
9091
GPT_OSS = "gpt_oss"
9192
SIMPLE = "simple"

src/MaxText/configs/base.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -860,3 +860,19 @@ subslice_shape: ""
860860
# NNX
861861
enable_nnx: false
862862
shard_optimizer_over_data: False
863+
864+
################################## Qwen3-Next Specific Configs ##################################
865+
# Kernel size for the 1D convolution in the Gated Delta Net
866+
gdn_conv_kernel_dim: 4
867+
# Head dimension for the key/query in the Gated Delta Net
868+
gdn_key_head_dim: 128
869+
# Head dimension for the value in the Gated Delta Net
870+
gdn_value_head_dim: 128
871+
# Number of key/query heads in the Gated Delta Net
872+
gdn_num_key_heads: 16
873+
# Number of value heads in the Gated Delta Net
874+
gdn_num_value_heads: 32
875+
# Chunk size for the parallel scan algorithm in the Gated Delta Net.
876+
gdn_chunk_size: 64
877+
# Whether to apply L2 normalization to query and key tensors inside the Gated Delta Rule kernel.
878+
use_qk_norm_in_gdn: True
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Copyright 2025 Google LLC
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# https://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
# MaxText/configs/models/qwen3-next-80b-a3b.yml
16+
17+
# Set the decoder block to our new implementation
18+
decoder_block: "qwen3_next"
19+
20+
# Core Architectural Parameters
21+
base_emb_dim: 2048
22+
base_num_decoder_layers: 48
23+
base_num_query_heads: 16
24+
base_num_kv_heads: 2
25+
head_dim: 256
26+
vocab_size: 151936
27+
normalization_layer_epsilon: 1.0e-6
28+
29+
# MoE Specific Parameters
30+
# Set base_mlp_dim to match base_moe_mlp_dim to pass validation for fully MoE models.
31+
base_mlp_dim: 512
32+
base_moe_mlp_dim: 512
33+
num_experts: 512
34+
num_experts_per_tok: 10
35+
norm_topk_prob: True
36+
37+
# Qwen3-Next Specific Parameters for Linear Attention (Gated Delta Net)
38+
inhomogeneous_layer_cycle_interval: 4
39+
gdn_conv_kernel_dim: 4
40+
gdn_key_head_dim: 128
41+
gdn_value_head_dim: 128
42+
gdn_num_key_heads: 16
43+
gdn_num_value_heads: 32
44+
gdn_chunk_size: 64
45+
46+
# RoPE Settings
47+
rope_max_timescale: 10000000

src/MaxText/layers/decoders.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,8 @@ def get_decoder_layers(self):
401401
return [qwen3.Qwen3DecoderLayerToLinen]
402402
case DecoderBlockType.QWEN3_MOE:
403403
return [qwen3.Qwen3MoeDecoderLayerToLinen]
404+
case DecoderBlockType.QWEN3_NEXT:
405+
return [qwen3.Qwen3NextScannableBlockToLinen] if self.config.scan_layers else [qwen3.Qwen3NextDecoderLayerToLinen]
404406
case DecoderBlockType.SIMPLE:
405407
return [simple_layer.SimpleDecoderLayerToLinen]
406408
case DecoderBlockType.SIMPLE_MLP:
@@ -452,6 +454,7 @@ def get_norm_layer(self, num_features: int):
452454
DecoderBlockType.GEMMA3,
453455
DecoderBlockType.QWEN3,
454456
DecoderBlockType.QWEN3_MOE,
457+
DecoderBlockType.QWEN3_NEXT,
455458
DecoderBlockType.GPT_OSS,
456459
DecoderBlockType.SIMPLE,
457460
DecoderBlockType.SIMPLE_MLP,
@@ -824,6 +827,8 @@ def __call__(
824827
"is_nope_layer": llama4.determine_is_nope_layer(lyr, self.config.nope_layer_interval),
825828
"is_moe_layer": llama4.determine_is_moe_layer(lyr, self.config.interleave_moe_layer_step),
826829
}
830+
if cfg.decoder_block == DecoderBlockType.QWEN3_NEXT:
831+
layer_kwargs = {"layer_idx": lyr}
827832
if cfg.decoder_block == DecoderBlockType.GPT_OSS:
828833
layer_kwargs = {"attention_type": gpt_oss.get_attention_type(layer_id=lyr)}
829834
layer = RemattedBlockLayer(

src/MaxText/layers/normalizations.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from MaxText import max_utils
2626
from MaxText.layers import nnx_wrappers
2727
from MaxText.layers.initializers import Initializer, variable_to_logically_partitioned
28+
from MaxText.common_types import Array
2829

2930

3031
class RMSNorm(nnx.Module):
@@ -93,3 +94,19 @@ def rms_norm(
9394
metadata_fn=variable_to_logically_partitioned,
9495
)
9596
return module
97+
98+
99+
def l2norm(x: Array, dim: int = -1, eps: float = 1e-6) -> Array:
100+
"""L2 normalization function. Normalizes a vector to have a length of 1.
101+
102+
Args:
103+
x: Input array.
104+
dim: The axis or axes along which to normalize. Defaults to the last axis.
105+
eps: Small epsilon to prevent division by zero.
106+
107+
Returns:
108+
L2 normalized array with the same shape as x.
109+
"""
110+
111+
inv_norm = jax.lax.rsqrt((x * x).sum(axis=dim, keepdims=True) + jnp.array(eps, dtype=x.dtype))
112+
return x * inv_norm

0 commit comments

Comments
 (0)