geniex infer and then behind the local server.
Verified on: Snapdragon X2 Elite,
llama_cpp runtime, --compute npu, target + draft both Q4_0.Speculative decoding is
llama_cpp-only. On the qairt runtime these flags are ignored with a warning rather than an error — qairt “SSD” bundles carry their own NPU acceleration that GenieX applies automatically.MTP is text-only — upstream llama.cpp’s speculative path doesn’t currently combine with image / audio inputs. If
--spec-type is set on a model that GenieX classified as multimodal (mmproj sibling in the repo), GenieX runs the LLM path and drops any image / audio content with a warning; the model itself is unchanged and remains usable for multimodal inference without --spec-type.Prerequisites
- The CLI installed — see Install.
- A Snapdragon X-series device.
- ~20 GB free disk, and enough free RAM to hold both models at once — the target alone is ~15 GB at
Q4_0.
Step 1: Pull the model pair
MTP requires a draft trained against the exact target you’re running. GenieX builds the draft context wired into the live target context (LLAMA_CONTEXT_TYPE_MTP), so an arbitrary small GGUF cannot be substituted — a mismatched pair fails the graph shape check at load time rather than silently degrading.
A4B is the smallest target with a matching published draft — the RachidAR/*-assistant draft is trained against A4B, so pairing it with the smaller E2B target fails. Q4_0 on both sides has the best Hexagon NPU support.
Step 2: Run it in geniex infer
Take a baseline first, so you have a number to compare against:
-p "your prompt" for a one-shot run instead of an interactive session.
Reading the acceptance rate
With speculation active, the profiling block gains adraft accept line — accepted draft tokens over total proposed:
Tuning
Start at
3. Raise it only if acceptance is high — with mediocre acceptance a longer window makes things worse, since every rejected token was wasted target work. Lower it to 2 if acceptance is marginal.
Raising
--draft-tokens costs less memory than you’d expect: GenieX caps the draft context’s batch at max(64, draft-tokens) instead of inheriting the target’s, which otherwise allocates ~2.3 GiB of HTP scratch and OOMs.Step 3: Serve it over HTTP
geniex serve has no --spec-type flag; speculation is per-request. Either let geniex run forward the same flags you used above:
POST /v1/chat/completions:
These fields are part of the model cache key. Changing any of them rebuilds the model on the next request, so keep them stable across a benchmark run or you’ll be measuring reload time. Full schema in the Swagger UI at
http://127.0.0.1:18181 — see Local server.Troubleshooting
No draft accept line in the output
No draft accept line in the output
Speculation never ran. Setup failure is non-fatal by design — an unrecognized type or a draft context that won’t build logs
speculative decoding setup failed; falling back to plain decoding and continues at normal speed. Check the log for that line, and confirm the flag reached the process.Load fails with a graph shape / tensor mismatch
Load fails with a graph shape / tensor mismatch
The draft doesn’t match the target. The
RachidAR/*-assistant draft is built for gemma-4-26B-A4B — not E2B or other sizes. Re-check both names and precisions against Step 1.Server: resolve draft model ... error
Server: resolve draft model ... error
The server does not auto-pull. Run
geniex pull for the draft repo with the same :precision suffix you’re sending, then confirm with geniex list.Out of memory on load
Out of memory on load
Target + draft need substantial free RAM together. Close other models (the server’s
--keepalive may be holding one resident), lower --nctx, or switch to ngram-mod, which loads no second model.Warning: speculative decoding is only supported by llama_cpp
Warning: speculative decoding is only supported by llama_cpp
Your model resolved to the
qairt runtime, which doesn’t implement it — the flags are dropped and inference continues normally. Use a GGUF model for the llama_cpp runtime.Other speculative types
--spec-type forwards to llama.cpp’s type parser, so it accepts more names than GenieX validates. One other is exercised on Snapdragon:
ngram-mod— self-speculative, no draft model, works with any GGUF. Verified on X Elite across CPU, GPU, and NPU. Weaker than a matched MTP pair on open-ended text, but useful on repetitive output, and free to try.
Next steps
- CLI reference — every
geniex inferflag. - Local server — the full OpenAI-compatible API.
- Platforms & runtimes — compute units, and how
npudiffers fromhybrid.
Was this page helpful?