apple envy moe implementation - #4645
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
|
🤖 Hi @RissyRan, I've received your request, and I'm working on it now! You can track my progress in the logs for more details. |
|
🤖 I'm sorry @RissyRan, but I was unable to process your request. Please see the logs for more details. |
JamesDeng42
left a comment
There was a problem hiding this comment.
left some comments, otherwise, it looks good to me.
d4cb0d7 to
9194371
Compare
|
🤖 Hi @RissyRan, I've received your request, and I'm working on it now! You can track my progress in the logs for more details. |
There was a problem hiding this comment.
This Pull Request successfully implements the Apple Envy MoE model (specifically supporting the Switch-Base, Switch-Large, and Switch-XXL models) in MaxText. The alternating inhomogeneous dense and sparse layers, RMSNorm configurations, and parameters are precisely matched (reaching an exact 100% parameter count match of 22.07B parameters for Switch-Base). The changes are exceptionally well-structured, follow existing design conventions, and are verified by unit tests.
🔍 General Feedback
- Rigorous Validation: The detailed parameter equivalence report comparing AXLearn and MaxText structure and shape mappings is exemplary and ensures high correctness.
- Clean Architectural Integration: Adding Envy as an inhomogeneous decoder block option integrates perfectly across Linen (
decoders.py) and NNX (nnx_decoders.py) layer builders. - Comprehensive Test Coverage: The unit test
tests/unit/envy_test.pycovers the compilation, initialization, and training forward pass.
| cfg = self.config | ||
|
|
||
| inputs = nn.with_logical_constraint(inputs, ("activation_batch", "activation_norm_length", "activation_embed")) | ||
| inputs = checkpoint_name(inputs, "decoder_layer_input") |
There was a problem hiding this comment.
🟡 Performance/Correctness: In EnvyScannableBlock.__call__, the logical constraint on inputs is hardcoded to "activation_norm_length". In MODEL_MODE_PREFILL mode, the sequence length dimension is named "prefill_activation_norm_length". Leaving this hardcoded can cause a sharding constraint conflict with EnvyDecoderLayer (which correctly selects the axis name based on model_mode), potentially leading to unnecessary compilation layout transitions on accelerators.
To align with EnvyDecoderLayer and ensure optimal sharding behavior across both prefill and decoding modes, dynamically select the axis names based on model_mode.
| inputs = checkpoint_name(inputs, "decoder_layer_input") | |
| activation_axis_names = ( | |
| ("activation_batch", "prefill_activation_norm_length", "activation_embed") | |
| if model_mode == MODEL_MODE_PREFILL | |
| else ("activation_batch", "activation_norm_length", "activation_embed") | |
| ) | |
| inputs = nn.with_logical_constraint(inputs, activation_axis_names) |
| @property | ||
| def moe_block(self): | ||
| return self.MoeBlock_0 |
There was a problem hiding this comment.
🟢 Maintainability/Robustness: In EnvyDecoderLayer, the moe_block property directly returns self.MoeBlock_0. However, when is_moe_layer is False (for dense layers), self.MoeBlock_0 is not initialized, so accessing self.moe_block will raise an AttributeError.
Although the current layer implementation only calls moe_block when is_moe_layer is True, other tooling/utilities (such as model visualization, parameter counting, weight inspection, or serialization) might inspect properties unconditionally. Making this safe with getattr prevents potential runtime crashes.
| @property | |
| def moe_block(self): | |
| return self.MoeBlock_0 | |
| @property | |
| def moe_block(self): | |
| return getattr(self, "MoeBlock_0", None) |
| "nope_layer_interval": self.config.nope_layer_interval, | ||
| "interleave_moe_layer_step": self.config.interleave_moe_layer_step, | ||
| } | ||
| if cfg.decoder_block == DecoderBlockType.ENVY: |
There was a problem hiding this comment.
🟢 Style: Since cfg.decoder_block can only match one block type, use elif instead of a separate if statement to align with the rest of the conditional checks.
| if cfg.decoder_block == DecoderBlockType.ENVY: | |
| elif cfg.decoder_block == DecoderBlockType.ENVY: |
| "is_nope_layer": llama4.determine_is_nope_layer(lyr, self.config.nope_layer_interval), | ||
| "is_moe_layer": llama4.determine_is_moe_layer(lyr, self.config.interleave_moe_layer_step), | ||
| } | ||
| if cfg.decoder_block == DecoderBlockType.ENVY: |
There was a problem hiding this comment.
🟢 Style: Use elif here as well to make the conditional block evaluation more efficient and clean.
| if cfg.decoder_block == DecoderBlockType.ENVY: | |
| elif cfg.decoder_block == DecoderBlockType.ENVY: |
RissyRan
left a comment
There was a problem hiding this comment.
LGTM at high level. Will you test logits alignment in next PR for the model?
| rope_max_timescale: 500000 | ||
| num_experts: 128 | ||
| num_experts_per_tok: 1 | ||
| capacity_factor: 2.0 |
There was a problem hiding this comment.
For capacity_factor is a implementation details (dropping/dropless), not related to model config itself.
Recommend to remove from here. If you'd like to assert this always happen, you could add an assertion in types.py file and ensure envy code block is called with capacity_factor=2
There was a problem hiding this comment.
Similar comments for other envy configs.
| load_balance_loss_weight: 0.01 | ||
| interleave_moe_layer_step: 2 | ||
| inhomogeneous_layer_cycle_interval: 2 | ||
| max_target_length: 8192 |
There was a problem hiding this comment.
Similar comment with capacity factor.
| import numpy as np | ||
|
|
||
|
|
||
| class EnvyTest(unittest.TestCase): |
There was a problem hiding this comment.
Does this test functionality of this model? If so, you could write a compile test like this:
maxtext/tests/unit/train_compile_test.py
Line 866 in 025f83f
Description
Implements Apple Envy MoE model as described here
Tests
Envy MoE Parameter Equivalence Report
This report compares the parameter structures of Apple's Envy Switch-Base model between AXLearn and MaxText to verify architectural correctness.
1. Parameter Shape Mapping
Here is the direct mapping of parameter tensors for the 12-layer Switch-Base model (6 repeat blocks of Alternating Dense and Sparse MoE layers):
decoder/emb/token_emb/weight[32768, 1536]token_embedder/embedding(32768, 1536)logits_via_embedding: true)decoder/output_norm/scale[1536]decoder_norm/scale(1536,)self_attention/norm/scale(6, 1536)pre_self_attention_layer_norm/scale(1536, 6)self_attention/attention/i_proj/i_proj/qkv_proj/weight(6, 1536, 36, 128)-
query/kernel(1536, 6, 12, 128)-
key/kernel(1536, 6, 12, 128)-
value/kernel(1536, 6, 12, 128)AXLearn groups QKV along the projection axis:
attention/scale_query/norm/scale(6, 128)attention/scale_key/norm/scale(6, 128)query_norm/scale(128, 6)key_norm/scale(128, 6)self_attention/attention/o_proj/weight(6, 1536, 12, 128)out/kernel(12, 6, 128, 1536)feed_forward/prenorm/scale(6, 1536)post_self_attention_layer_norm/scale(1536, 6)feed_forward/postnorm/scale(6, 1536)post_ffw_norm/scale(1536, 6)use_post_ffw_norm: true)feed_forward/linear1_0/weight(6, 1536, 6144)feed_forward/linear1_1/weight(6, 1536, 6144)feed_forward/linear2/weight(6, 6144, 1536)wi_0/kernel(1536, 6, 6144)wi_1/kernel(1536, 6, 6144)wo/kernel(6144, 6, 1536)feed_forward/prenorm/scale(6, 1536)post_self_attention_layer_norm/scale(1536, 6)feed_forward/postnorm/scale(6, 1536)post_ffw_norm/scale(1536, 6)use_post_ffw_norm: true)feed_forward/gate_weight(6, 1536, 128)MoeBlock_0/gate/kernel(1536, 6, 128)feed_forward/wi_0_weight(6, 128, 1536, 6144)feed_forward/wi_1_weight(6, 128, 1536, 6144)feed_forward/wo_weight(6, 128, 6144, 1536)MoeBlock_0/wi_0(128, 6, 1536, 6144)MoeBlock_0/wi_1(128, 6, 1536, 6144)MoeBlock_0/wo(128, 6, 6144, 1536)2. Parameter Counts Analysis
22,077,958,656(22.07B)22,077,958,656(22.07B)0parameters (100% exact match)Key Configurations Enabled:
logits_via_embedding: true: Shares the token embedding parameters with the output logits projection.use_post_ffw_norm: true: Activates the post-FFN normalization layer (post_ffw_normin MaxText, mapping topostnormin AXLearn'shybridnormFFN structure).Ran test:
Checklist
Before submitting this PR, please make sure (put X in square brackets):
gemini-reviewlabel.