feat: repack quantized CLIP weights into the CPU i8mm buffer#179
Merged
Conversation
Vision-encoder weights (q8_0/q4_0 2D matmul matrices) were allocated in the default CPU buffer, so their mul_mat used the generic path. Allocate the repackable ones in ggml's CPU "repack" extra buffer type instead, so they get repacked into the interleaved layout at load and hit the fast i8mm/AVX2 GEMM. Selection is per-tensor via a ggml_backend_dev_supports_op probe (mirrors llama's buft_supported): only tensors the backend can actually repack+matmul go there, so conv weights / biases / norms stay in the default buffer, and on arches with no repack kernel it is a no-op. Weight loading is made per-tensor host-aware since weights now span the host default buffer and the non-host repack buffer. Output is bit-identical. Opt out with MTMD_CLIP_NO_REPACK=1. On Pixel 9 Pro (Qwen3.5-0.8B mmproj, q8_0, arm64 i8mm build) this cuts the CPU vision-encode from ~1807 ms to ~1114 ms.
Author
CPU vision-encode benchmark — repack ON vs OFF (same binary)Measured this PR's repack in the qvac VLM benchmark ( mmproj vision-encode time (lower = faster):
Benchmark results: https://github.com/tetherto/qvac/actions/runs/28658081618/job/84996939580 (run Mobile encode times are captured via the |
DmitryMalishev
approved these changes
Jul 6, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Speeds up the CPU vision encoder (mtmd/clip) by repacking quantized weights
into ggml's CPU i8mm buffer. On a Pixel 9 Pro (Qwen3.5-0.8B mmproj, q8_0,
4 threads) the vision encode drops from ~1807 ms → ~1114 ms (1.6×), with
bit-identical output.
Production change only — one file (
tools/mtmd/clip.cpp, +72/-2). The standaloneqwen3vl-encoderbenchmark tool used to find/validate this lives separately onbranch
feat/qwen3vl-standalone-encoder(PR #178) for testing.What it does
clip.cppallocated all weights in the default CPU buffer, so the q8_0/q4_0matmul matrices used the generic GEMM instead of the interleaved i8mm/AVX2
kernels. This allocates the repackable weights in ggml's CPU "repack" extra
buffer type, so they are repacked into the interleaved layout at load.
ggml_backend_dev_supports_opprobe (mirrorsllama's
buft_supported): only tensors the backend can actually repack+matmulgo to the repack buffer. Conv weights / biases / norms stay in the default
buffer (otherwise their non-matmul ops become unsupported and the scheduler
aborts). On arches/variants with no repack kernel the probe rejects everything
and this is a no-op.
default buffer and the non-host repack buffer.
golden). Opt out with
MTMD_CLIP_NO_REPACK=1.Production android already ships an i8mm variant (
GGML_CPU_ALL_VARIANTS→armv8.6_1), so this repack is the incremental win on top with no build-configchange needed.
Testing
(test[notask]: overlay qvac-fabric onto qwen3vl CPU-repack branch (fabric #178) qvac#3012).