Skip to content

feat(models): add Phixtral (phixtral) text model support #844

Closed

Description

@inureyes

Corrected against references/mlx-lm (commit 15b522f, 2026-07-11) on 2026-08-05.

The detection arm in the original body would never fire

The original acceptance criteria ask for "phixtral" => ... in src/models/detection.rs. No phixtral checkpoint declares that string. mlabonne/phixtral-4x2_8 declares "model_type": "phi-msft", and upstream reaches the implementation through a rename table, not the config value:

# mlx_lm/utils.py
MODEL_REMAPPING = { ..., "phi-msft": "phixtral", ... }

mlxcel already has an arm for that string, and it points somewhere else:

// src/models/detection.rs:154
"phi" | "phi-msft" => Ok(ModelType::Phi),

So a phixtral checkpoint currently routes to the dense Phi decoder. The port therefore has to discriminate an existing arm rather than add a new one. The reliable discriminator is num_local_experts in the config (4 on phixtral-4x2_8, absent on dense Phi-2), the same signal upstream's config carries.

Validated checkpoint

mlabonne/phixtral-4x2_8 ships fp16 only, so a local conversion is needed. Done and verified:

mlx_lm convert --hf-path mlabonne/phixtral-4x2_8 -q --q-bits 4 --q-group-size 64

produces a 4.1 GB 4-bit checkpoint (models/phixtral-4x2_8-4bit, 4.503 bits/weight) that keeps model_type: phi-msft, n_layer: 32, n_embd: 2560, rotary_dim: 32, num_local_experts: 4, num_experts_per_tok: 2.

Architecture, as upstream implements it

Confirmed accurate in the original body, with two additions worth naming:

  • Routing is mx.softmax(scores, axis=-1, precise=True) over the top-k gate logits, and the gate is a plain nn.Linear.
  • Upstream has a real sanitize that rewrites per-expert keys; the Model.sanitize loop iterates range(self.args.num_local_experts), so the checkpoint's expert layout has to be mapped rather than consumed as-is. Check the converted checkpoint's actual key layout before assuming the pre-stacked SwitchGLU path applies.

nn.LayerNorm (with bias) rather than RMSNorm, partial rotary over rotary_dim only, and the Phi-2 single-LayerNorm parallel-residual block are all as described.


Original issue body (retained for history)

Summary

Add native mlxcel support for Phixtral (model_type: phixtral), a Mixtral-style sparse MoE built on the Phi-2 backbone. Each block keeps the Phi-2 single-LayerNorm parallel-residual layout (attention and MLP share one input LayerNorm and run in parallel) and uses partial-rotary RoPEAttention, but replaces the dense MLP with top-k routing over num_local_experts experts. Porting brings the family to the same load-and-generate path as the other text models.

Upstream reference

Public checkpoint

  • mlabonne/phixtral-4x2_8 (4 experts, top-2). Confirm an existing MLX SafeTensors conversion or produce one before validation. Real-checkpoint validation is a hard gate.

Architecture notes

  • Mixtral-style sparse MoE on a Phi-2 backbone.
  • RoPEAttention with partial rotary (rotary_dim): only the first rotary_dim slots are rotated.
  • nn.LayerNorm (with bias), not RMSNorm.
  • Phi-2 block shape: a single input LayerNorm per block feeding attention and MLP in PARALLEL (parallel residual), summed into the residual.
  • Routing: an nn.Linear gate selects top-num_experts_per_tok (default 2) of num_local_experts experts per token.

Implementation plan

Cite and reuse existing mlxcel modules:

  • Phi attention + LayerNorm + parallel-residual block: reuse src/models/phi3.rs / src/models/phi3small.rs for the Phi attention and LayerNorm handling. Note src/models/phimoe.rs already combines a Phi-family backbone (LayerNorm with bias, attention proj bias) with MoE routing and is the closest existing reference; start from it.
  • Mixtral-style top-k MoE: reuse the routing pattern in src/models/mixtral.rs and the expert compute in src/models/switch_layers.rs.
  • The distinctive work is combining Phi-2 partial rotary (rotary_dim) + the single-LayerNorm parallel-residual block with switch-based top-k MoE (gate as nn.Linear, softmax over top-k logits).

Touchpoints & acceptance criteria

Follow docs/adding-models.md. Done only when it loads and generates from a real checkpoint.

  • Config struct + serde parse for phixtral (rotary_dim, num_local_experts, num_experts_per_tok, LayerNorm eps, Phi-2 dims), with sensible #[serde(default)]s.
  • from_weights constructs the model from a real WeightMap, including gate + per-expert weights.
  • sanitize handles the checkpoint's expert key layout / stacking.
  • Detection arm added in src/models/detection.rs ("phixtral" => ...).
  • Registration added via for_each_model_registration! in src/model_metadata.rs.
  • TP / distributed arch-string wired if the family is served in that path.
  • Unit tests in a _tests.rs file beside the implementation (config parse, partial-rotary dims, parallel-residual block, top-k gate selection).
  • docs/supported-models.md updated with the new family.
  • Real-checkpoint validation: mlxcel list shows the arch and ./target/release/mlxcel generate -m <path> -p "..." -n <N> produces coherent output.

Effort

MEDIUM. Phi attention/LayerNorm and Mixtral top-k routing both exist (phimoe.rs already fuses a Phi backbone with MoE); the new logic is Phi-2 partial rotary + parallel residual combined with the switch MoE gate.

Activity

  1. added
    type:enhancementNew features, capabilities, or significant additions
    area:modelsModel architectures, weights, loading, metadata
    on Jul 21, 2026
  2. added
    modelsize:small4-bit checkpoint <= 10GB; fast iteration, safe for smoke tests
    arch:moeSparse mixture-of-experts decoder
    on Aug 5, 2026
  3. added a commit that references this issue on Aug 20, 2026
    dfdf946
  4. self-assigned this
    on Aug 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

arch:moeSparse mixture-of-experts decoderarea:modelsModel architectures, weights, loading, metadatamodelsize:small4-bit checkpoint <= 10GB; fast iteration, safe for smoke testsmodeltype:textText-only language modelpriority:mediumMedium prioritystatus:doneCompletedtype:enhancementNew features, capabilities, or significant additions

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions