Core AI model zoo

Youtu-LLM-2B — dense MLA on iPhone (Core AI port notes)

Verified engineering notes from porting tencent/Youtu-LLM-2B (dense DeepSeek-V2/V3 Multi-head Latent Attention, 1.96B) to Core AI. This is the zoo’s first MLA model that runs on iPhone and its first dense MLAGLM-4.7-Flash brought MLA but as a 30B Mac-only MoE. The whole port is mostly reuse of the GLM MLA path.

The reuse: dense MLA == GLM’s MLA minus the MoE

Youtu’s attention (YoutuAttention) is bit-identical to glm4_moe_lite’s MLA. The only structural differences from GLM-4.7-Flash are:

So models/macos/youtu.py is glm4_moe_lite.py with the MoE decoder swapped for a dense MLP and a simpler weight loader (HF names == authored names, no expert stacking, no MTP skip). The absorbed-MLA decode (youtu_absorbed.py) imports GLM’s glm4_moe_lite_absorbed (Glm4MoeLiteMLAAbsorbed, AbsorbedKVCache, build_absorbed_decode_state, the stateful wrapper) and just re-points it at the Youtu model — those classes are fully config-driven and duck-type on .model.layers[i].self_attn + the config attrs.

Two things that made the reuse exact

  1. Interleaved decoupled RoPE is the same function. HF’s apply_rotary_pos_emb_interleave (even/odd pair form) and glm4_moe_lite’s apply_rope_interleave (de-interleave → rotate-half) are algebraically identical; the cos/sin are built over rd = qk_rope_head_dim (64) with config.head_dim = qk_rope_head_dim. Verified by the fp32 gate (0 flips) — the convention is load-bearing (the non-interleaved path shifts attention scores by ~25).
  2. The absorbed-MLA flash-decode Metal kernel already bakes Youtu’s config. mla_metal_sdpa.py was written for kv_lora 512 / qk_rope 64 with the scale hard-coded per model — and it explicitly lists 192**-0.5 (DeepSeek-V2-Lite) as a supported scale. Youtu’s qk_head_dim = 128+64 = 192 and its asymmetric K(576)≠V(512) shape (v_head_dim 128 ≠ qk 192) is the DeepSeek-V2-Lite shape the kernel was designed for. Register bounds (_MAX_EPTL = 512/32 = 16, _MAX_EPTR = 64/32 = 2) fit Youtu exactly. Zero kernel changes.

The absorbed form is also why a dense 2B MLA fits iPhone: it caches only the compressed latent [512] + shared rope key [64] (2×[288] halves) per token, not a full per-head K/V — a tiny KV even at 128K context.

Gates (all PASS)

Findings worth keeping

Reproduce

cd coreai-models   # with the youtu overlay (../conversion)
.venv/bin/python ../coreai-models-community/conversion/export_youtu_decode_pipelined.py \
    --hf-id tencent/Youtu-LLM-2B --split-g 8         # int8 body+head, absorbed+msdpa; ~2.2 GB

Overlay: models/macos/youtu.py (+ youtu_absorbed.py). See the pipelined engine notes for the decode-only static-[1,1] run contract, and the GLM-4.7-Flash card for the shared MLA / absorbed-cache machinery.