Skip to content

fix(engine): stop making the unused vision encoder resident (852 MB, every tier) - #176

Merged
penta2himajin merged 1 commit into
mainfrom
claude/drop-unused-vision-tower
Aug 2, 2026
Merged

fix(engine): stop making the unused vision encoder resident (852 MB, every tier)#176
penta2himajin merged 1 commit into
mainfrom
claude/drop-unused-vision-tower

Conversation

@penta2himajin

Copy link
Copy Markdown
Owner

The checkpoint ships a vision encoder. qwisp is a text-only engine and never reads one of those tensors — but WeightStore.residentNonExperts() filtered only on .switch_mlp., so all of vision_tower.* went to MLX.eval() and was made resident on every run, on every tier. 333 tensors, 852 MB.

Measured

Byte-exact against the prediction made before running it:

tier before after
8GB (budgetC=64) 7,071 MB 6,219 MB
16GB (budgetC=128) 11,391 MB 10,539 MB

Which confirms the decomposition those predictions came from:

active = arena(40 x budgetC x 1.6875 MB) + language_model non-expert 1,325 + scratch 574

Output unchanged (it was never read).

Filtered at load, not at eval

Keeping the MLXArray alive holds its mmap slice, so removing it from the eval list alone would not have returned the bytes. residentAll() becomes correct for free — the tensors are simply not in the store.

Why this matters beyond the byte count

  • 8GB tier. It needs ~761 MB to hold coverage at or above the ~103-expert per-layer footprint (the LOOPY-safety line). 852 MB is more than the entire deficit, at zero quality cost. This session had been measuring whether non-expert weights survive 2-bit in order to find those bytes. They do not — GDN loses 31 points of teacher-forced agreement below its own same-bit round-trip floor (94.3% → 62.9%), lm_head 24.6, embed 6.3 — and quantizing every non-expert tensor would only have freed 589 MB anyway. The bytes were already there, being wasted.
  • 16GB tier. The bolt: decode command buffer fails with GPU OOM and cb.error is never checked → unbounded token-id-0 (!) output above ~2–6K prompt tokens #169 OOM cliff was measured at two experts per layer, ~150 MB (coverage 228 passes, 230 fails). 852 MB is 5.7x that margin.

Not claimed here

Whether this makes the 8GB tier actually fit a real 8GB Mac, and whether it moves the #169 threshold, are follow-up measurements — both need the wired-limit emulation and are not in this PR. This PR is the byte reclamation and its proof.

Gates

RAWTESTS 100/100 · BENCHBATCHTEST PASS · COMPTEST 97/97 · CBGUARD PASS

The new locked test asserts the predicate keeps engine tensors (embed, lm_head, switch_mlp, linear_attn, mlp.gate) and drops vision ones — a regression would silently cost 852 MB again. Runs without a model or GPU.

🤖 Generated with Claude Code

…every tier)

The checkpoint ships a vision encoder. qwisp is a text-only engine and never reads
one of those tensors — but WeightStore.residentNonExperts() filtered only on
`.switch_mlp.`, so all of `vision_tower.*` was handed to MLX.eval() and made
resident on every run of every tier. 333 tensors, 852 MB.

Measured, byte-exact against the prediction:

  8GB tier  active 7,071 -> 6,219 MB
  16GB tier active 11,391 -> 10,539 MB

which confirms the decomposition those numbers were predicted from:
active = arena(40 x budgetC x 1.6875) + language_model non-expert 1,325 + scratch 574.

Filtered at load, not at eval: keeping the MLXArray alive holds its mmap slice, so
dropping it from the eval list alone would not have returned the bytes. residentAll()
becomes correct for free, since the tensors are simply not in the store.

Why this matters beyond the byte count:

- The 8GB tier needs ~761 MB to hold coverage at or above the ~103 expert per-layer
  footprint, which is the LOOPY-safety line. 852 MB is more than the entire deficit,
  and it costs nothing in quality. The session had been measuring whether non-expert
  weights survive 2-bit to find those bytes — they do not (GDN loses 31 points of
  teacher-forced agreement below its own round-trip floor), and quantizing every
  non-expert tensor would only have freed 589 MB anyway. The bytes were already there,
  being wasted.
- On 16GB the #169 OOM cliff was measured at two experts per layer, about 150 MB.
  852 MB is 5.7x that margin.

RAWTESTS 100/100 (new locked test asserts the predicate keeps engine tensors and drops
vision ones; a regression silently costs 852 MB again), BENCHBATCHTEST PASS,
COMPTEST 97/97, CBGUARD PASS.

Co-Authored-By: Claude <noreply@anthropic.com>
@penta2himajin
penta2himajin merged commit ca2e124 into main Aug 2, 2026
1 check passed
@penta2himajin
penta2himajin deleted the claude/drop-unused-vision-tower branch August 2, 2026 14:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant