Summary
apr run fails at the final lm_head matmul on tied-embedding .apr models with:
error: Inference failed: Invalid shape: matmul weight has EMPTY data buffer
(in_dim=896, out_dim=151936, qtype=0); likely a MoE per-expert tensor was
registered with len-0 data — see aprender#1789
The error's MoE hypothesis (#1789, closed, was Qwen3-30B-MoE) is a red herring — this model is not MoE. The real cause is tied word embeddings.
Repro
apr run /home/noah/models/qwen2.5-coder-0.5b-instruct.apr --prompt "What is 2+2?" --max-tokens 16
# fails on --no-gpu, --backend cpu, AND wgpu — backend-independent
Diagnosis
apr tensors shows the lm_head is a 0-byte placeholder, while embed_tokens holds the real data:
│ lm_head.weight │ [151936, 896] │ f32 │ 0 B │ <-- empty
│ model.embed_tokens.weight │ [151936, 896] │ bf16 │ 259.7 MB │ <-- real data
Qwen2.5-0.5B uses tie_word_embeddings=true: lm_head == embed_tokens (transposed for the output projection). The .apr file correctly stores lm_head as a shape-only placeholder, but the loader registers the empty lm_head for the output matmul instead of tying it to embed_tokens.weight.
apr inspect / apr qa PASS (checksum valid, 291 tensors pass PMAT-235 contracts) — the file is well-formed; the loader is at fault.
Scope
- Fails: tied-embedding models (small Qwen: 0.5B; any model with a 0-byte lm_head placeholder).
- Works: models with a real/untied lm_head — e.g. qwen2.5-coder-1.5b-instruct-q4k publishes "4" correctly.
Regression status
NOT a v0.60.0 regression — the 0.57.0 dev build (/mnt/nvme-raid0/targets/aprender/release/apr) fails identically. Pre-existing (≥0.57.0). Surfaced by post-release dogfooding of the v0.60.0 crates.io binary.
Proposed fix
In the quantized-model loader (OwnedQuantizedModel::from_apr / the output-projection wiring): when lm_head.weight has a 0-byte data buffer AND embed_tokens.weight exists with a matching [vocab, hidden] shape, tie the output projection to embed_tokens.weight (transposed) rather than registering the empty buffer. Add a falsification test that apr run on a tied-embedding fixture produces a non-empty decode (RED before fix, GREEN after), per the contract-ratchet doctrine.
Also: fix the misleading error message to name the tied-embedding case, not just MoE #1789.
Summary
apr runfails at the final lm_head matmul on tied-embedding.aprmodels with:The error's MoE hypothesis (#1789, closed, was Qwen3-30B-MoE) is a red herring — this model is not MoE. The real cause is tied word embeddings.
Repro
Diagnosis
apr tensorsshows the lm_head is a 0-byte placeholder, while embed_tokens holds the real data:Qwen2.5-0.5B uses
tie_word_embeddings=true: lm_head == embed_tokens (transposed for the output projection). The.aprfile correctly stores lm_head as a shape-only placeholder, but the loader registers the empty lm_head for the output matmul instead of tying it toembed_tokens.weight.apr inspect/apr qaPASS (checksum valid, 291 tensors pass PMAT-235 contracts) — the file is well-formed; the loader is at fault.Scope
Regression status
NOT a v0.60.0 regression — the 0.57.0 dev build (
/mnt/nvme-raid0/targets/aprender/release/apr) fails identically. Pre-existing (≥0.57.0). Surfaced by post-release dogfooding of the v0.60.0 crates.io binary.Proposed fix
In the quantized-model loader (OwnedQuantizedModel::from_apr / the output-projection wiring): when
lm_head.weighthas a 0-byte data buffer ANDembed_tokens.weightexists with a matching[vocab, hidden]shape, tie the output projection toembed_tokens.weight(transposed) rather than registering the empty buffer. Add a falsification test thatapr runon a tied-embedding fixture produces a non-empty decode (RED before fix, GREEN after), per the contract-ratchet doctrine.Also: fix the misleading error message to name the tied-embedding case, not just MoE #1789.