Maple-Preview, MiniCPM5-2B or Spark-X2.5, which CPU-only LLM to pick for an arm64 machine
Table of contents
- Key takeaways
- What Maple-Preview, MiniCPM5-2B and Spark-X2.5-4B are
- Which llama.cpp version each model needs
- How I measured: machine, build and load
- How fast each model runs on a CPU without a GPU
- How many threads to use for generation on a CPU
- How much memory and disk each model takes
- How they handled five tasks in Spanish
- What reasoning mode costs on a CPU
- Which model to use for which task
- Frequently asked questions
- Can you run an LLM without a GPU at a usable speed?
- Do you need a llama.cpp fork for Maple-Preview or Spark-X2.5?
- Which of the three answers best in Spanish?
- Conclusion
- Sources
Without a GPU, on an 18-core arm64 CPU with llama.cpp v0.4.1, Maple-Preview generated 172.84 tokens/s on 6 threads: twice MiniCPM5-2B and 3.6 times Spark-X2.5-4B. The trade-off is 5.79 GiB of RAM and reasoning it cannot switch off. MiniCPM5 fits in 3.27 GiB and Spark writes the best Spanish. All three made facts up.
On an arm64 CPU with no GPU, Maple-Preview generates text faster than MiniCPM5-2B and Spark-X2.5-4B even though it weighs 20,214 million parameters, because each token only activates about 1,000 million of them and its weights are ternary. The price is 5.49 GiB on disk, and none of the three models got the general-knowledge question I asked right. On 14 and 15 September 2026 I ran them with the same llama.cpp v0.4.1 build on an 18-core Linux arm64 machine, with Gemma 4 E2B as a well-known baseline, and measured speed, memory and five tasks in Spanish.
This reference collects the figures, the commands and a summary of the raw answers, with the machine load noted next to every measurement because I shared the machine with other jobs. The Spanish version is at Maple-Preview, MiniCPM5-2B o Spark-X2.5, qué LLM sin GPU elegir.
Key takeaways
- On 6 threads, Maple-Preview generated a median of 172.84 tokens/s, against 83.19 for MiniCPM5-2B, 64.53 for Gemma 4 E2B and 47.41 for Spark-X2.5-4B.
- All three official GGUFs load in llama.cpp v0.4.1 without forks, even though the Maple and Spark GGUF cards still point to their own llama.cpp forks.
- With a 16,384-token context, peak resident memory was 5.79 GiB for Maple, 3.27 GiB for MiniCPM5 and 5.56 GiB for Spark.
- All four models, Gemma included, made up the date and the stations of the first Madrid Metro line.
- In reasoning mode, Spark used up the 4,096-token cap on the shopping sum and Gemma on the code function; Maple does not let you turn that mode off.
- More threads is not better: all four generated fastest on 6 and fell to between 5.90 and 7.78 tokens/s on 16.
What Maple-Preview, MiniCPM5-2B and Spark-X2.5-4B are
They are three open-weight models released between August and September 2026 that their authors pitch for devices without a dedicated GPU, and each gets there by a different route. These are the facts I read in their Hugging Face repositories and in the file metadata:
| Model | Author | Released | Licence | Parameters | Architecture | GGUF tested | Size |
|---|---|---|---|---|---|---|---|
| Maple-Preview | DeepGrove | 4 August 2026 | MIT | 20,214,030,336 | Ternary MoE, 256 experts, 8 active | TQ2_0 with Q4_K head | 5.49 GiB |
| MiniCPM5-2B | OpenBMB | 7 September 2026 | Apache 2.0 | 2,516,756,480 | Dense, LlamaForCausalLM |
Q4_K_M | 1.45 GiB |
| Spark-X2.5-4B | XHToken | 24 August 2026 | Apache 2.0 | 4,112,079,360 | Dense, hybrid attention | Q4_K_M | 2.42 GiB |
| Gemma 4 E2B (baseline) | Google, GGUF by ggml-org | 31 March 2026 | Apache 2.0 | 4.63 B per llama-bench | Dense | Q4_0 | 2.63 GiB |
Maple-Preview[1] is a mixture-of-experts (MoE) model: 24 layers with 256 experts, of which the router picks 8 per token. Its weights are ternary: each one is -1, 0 or +1 times a per-block scale factor, and the TQ2_0 format stores them at 2.06 bits per weight. On a CPU, generation speed depends mostly on how many bytes of weights have to be read from memory for each token. Maple reads about 1,000 million parameters per token (the "A1B" in its name), at just over 2 bits each.
The card claims it solves "IMO-level problems" and exceeds 200 tokens/s on a Mac mini M4, but it also admits its weak spot:
"this preview is focused primarily on raw reasoning and, as such, may underperform on agentic benchmarks." (DeepGrove, Maple-Preview model card on Hugging Face)

MiniCPM5-2B[2] uses the standard Llama architecture, with 42 layers and 2 key-value heads, so it needs no model-specific support in llama.cpp. OpenBMB lists it for English and Chinese, not Spanish.
Spark-X2.5-4B[3] interleaves three sliding-window attention layers (512 tokens) with one full-attention layer. Its card claims a native context of 1,048,576 tokens and more than 200 languages. Do not confuse it with Meta’s Muse Spark, which is a different model. Gemma 4 E2B is the baseline because it is a well-known small model; its sizes are covered in Gemma 4 locally with Ollama.
Which llama.cpp version each model needs
All three work with v0.4.1, released on 14 September 2026. Maple arrived with PR 27000[4], merged that same day, and its author describes it as "CPU-only for now", with Metal and CUDA to follow. Spark2.5 arrived with PR 27868[5], merged on 6 September, and the first nightly build that includes it is b10828. MiniCPM5-2B needs nothing new.
The cards lag behind the code. The Maple GGUF[6] card points to the deepgrove-ai/llama.cpp fork. The Spark GGUF[7] card points to the XHToken/llama.cpp fork, including for use with Ollama and LM Studio. I tested the official files, without reconverting them, on the upstream build, and all three loaded and generated text.
If you do not have llama.cpp yet, the guide to installing llama.cpp on Linux, macOS and Docker covers the four channels. Here I used a source build of the v0.4.1 tag. Download the GGUFs from each author’s official repository and run the measurement like this:
llama-bench -m maple-preview-TQ2_0-head-Q4_K.gguf \
-p 512 -n 128 -r 3 -t 4,8,16 -o json
-p 512 measures processing a 512-token prompt (prefill), -n 128 generating 128 tokens, -r 3 repeats each test three times and -t sets the threads.
How I measured: machine, build and load
The machine is a Linux arm64 VM on Apple silicon with 18 cores, 121 GB of RAM and no usable GPU. I built llama.cpp v0.4.1 (commit b29c606) with GCC 13.3 in an Ubuntu 24.04 container. CMake detected dotprod, i8mm and bf16, and built without SVE or KleidiAI. The four GGUFs sat on a tmpfs, that is, in RAM, so the load times in this article include no disk reads.
I ran five rounds between 23:26 on 14 September and 00:15 on 15 September (UTC). I rotated the model order every round, so any interference would hit all of them equally. Each round runs llama-bench -p 512 -n 128 -r 3 on 4, 6, 8 and 16 threads, and the tables give the median of the five rounds with the minimum and maximum in brackets.
I started when the 1-minute load average dropped below 6 (it was at 5.60), after waiting 68 minutes for the load from the other jobs on the machine to drop. During the rounds it ranged from 1.33 to 16.70, and that figure includes the benchmark’s own threads: a 16-thread run adds up to 16. I ran the five Spanish tasks earlier, on 2 threads at a load of 12 to 37, so from those I count tokens, not seconds.
How fast each model runs on a CPU without a GPU
Maple-Preview was the fastest at generation on every thread count: 172.84 tokens/s on 6, twice MiniCPM5-2B and 3.6 times Spark-X2.5-4B. These are the median speeds for generating 128 tokens, in tokens/s:
| Model | 4 threads | 6 threads | 8 threads | 16 threads |
|---|---|---|---|---|
| Maple-Preview TQ2_0 | 144.43 (101.61–147.33) | 172.84 (161.40–181.16) | 133.65 (115.49–151.65) | 7.78 (6.88–8.06) |
| MiniCPM5-2B Q4_K_M | 72.95 (65.97–74.40) | 83.19 (74.12–84.62) | 68.03 (55.18–79.14) | 6.61 (6.28–6.83) |
| Spark-X2.5-4B Q4_K_M | 40.85 (33.32–41.09) | 47.41 (44.47–48.25) | 46.57 (34.58–49.81) | 6.87 (6.84–7.22) |
| Gemma 4 E2B Q4_0 | 57.14 (48.56–58.43) | 64.53 (63.53–67.34) | 61.29 (30.10–66.33) | 5.90 (5.50–5.94) |
For processing a 512-token prompt the order is the same, and there adding threads does pay off all the way to 16:
| Model | 4 threads | 6 threads | 8 threads | 16 threads |
|---|---|---|---|---|
| Maple-Preview TQ2_0 | 253.95 (211.70–257.21) | 337.68 (330.21–343.25) | 425.99 (419.16–429.76) | 584.06 (568.10–633.25) |
| MiniCPM5-2B Q4_K_M | 182.20 (170.44–183.57) | 241.69 (226.29–260.84) | 283.49 (253.61–286.02) | 455.48 (422.29–457.99) |
| Spark-X2.5-4B Q4_K_M | 95.63 (83.25–97.85) | 130.30 (123.15–133.04) | 157.80 (133.60–159.38) | 253.73 (225.45–260.14) |
| Gemma 4 E2B Q4_0 | 154.11 (135.96–157.21) | 212.96 (209.98–216.66) | 266.88 (238.81–268.15) | 413.03 (267.98–427.84) |
The Maple GGUF card publishes, for this same file on an M5 Pro CPU with 16 threads, 610.48 tokens/s of prefill and 252.74 of generation. My 16-thread prefill came in 4% lower, at 584.06, but 16-thread generation collapsed and my best figure, on 6 threads, was 32% below theirs. The author of PR 27000 measured about 216 tokens/s of prefill and 88 of generation on an M4 CPU, without stating the thread count or prompt length.
The 218 tokens/s on a Mac mini M4 in the main card do not come from llama.cpp: the card itself says that result uses "a separate on-device runtime". The Show HN from 4 August[8], with 173 points, put 120 tokens/s on an iPhone in its title, which I could not verify. With llama.cpp on a CPU, my maximum was 172.84.
How many threads to use for generation on a CPU
On this VM, generation peaked at 6 threads and collapsed from 10 onwards, while prefill kept climbing up to 16. The points at 4, 6, 8 and 16 threads are the five-round medians. The ones at 2, 10, 12 and 14 come from a single llama-bench call with two repetitions per model, at a load of 6.59 to 11.46.

Generating a token means reading every active weight from memory, so the speed depends more on memory bandwidth than on cores. On top of that, llama.cpp splits every operation of the compute graph across the threads and does not move on until all of them finish, so one late thread holds up the rest. On a shared VM, the more threads you run, the more likely the host delays one of them. I have not isolated which of the two effects weighs more here.
With the machine busy with other processes, the sweet spot drops further. At a load average of 37 on 18 cores, before the rounds, llama-bench gave these figures for MiniCPM5-2B:
| Threads | 16-token prefill (tokens/s) | 32-token generation (tokens/s) |
|---|---|---|
| 2 | 33.00 | 9.15 |
| 4 | 21.92 | 2.96 |
| 8 | 15.61 | 1.43 |
In my first run of the five tasks, with 8 threads at that load, MiniCPM5 took 560 s to answer the shopping sum. The install guide hit the same wall with Gemma 4: without -t, the model did not finish reading the prompt within 60 s.
How much memory and disk each model takes
Maple asks for the most RAM, but the gap is smaller than its size on disk suggests. I started llama-server with a 16,384-token context and a single slot, sent it a short request and read VmHWM from /proc. I repeated it three times per model, with a warm page cache and a load average of 23 to 27:
| Model | File | Peak RSS | Mapped weights | Repacked weights | KV cache | Until the first 200 from /health |
|---|---|---|---|---|---|---|
| Maple TQ2_0 | 5.49 GiB | 5.79 GiB | 5,456 MiB | 167 MiB | 228 MiB | 0.69 to 1.41 s |
| MiniCPM5 Q4_K_M | 1.45 GiB | 3.27 GiB | 1,268 MiB | 1,340 MiB | 672 MiB | 1.90 to 1.96 s |
| Spark Q4_K_M | 2.42 GiB | 5.56 GiB | 2,461 MiB | 2,474 MiB | 684 MiB | 2.38 to 2.46 s |
| Gemma 4 E2B Q4_0 | 2.63 GiB | 4.24 GiB | 2,695 MiB | 1,407 MiB | 108 MiB | 1.97 to 2.05 s |
The repacked-weights column explains the surprise. On ARM, llama.cpp copies Q4_K and Q4_0 tensors into a CPU_REPACK buffer in a layout its NEON kernels process better. That is why the MiniCPM5 and Spark weights show up twice in the RSS: the mapped copy of the file and the repacked one. Maple’s TQ2_0 tensors are used as they are, and only the output head gets repacked.
On a normal disk, the kernel can drop mapped pages that are no longer read; here, on tmpfs, they counted as shared memory.
The KV cache differs too. MiniCPM5 has the largest because its 42 layers all use full attention. Maple and Spark limit three out of every four layers to a 512-token window, and Gemma 4 E2B also uses a sliding window. To estimate your own case with another context size, use the local LLM calculator.
How they handled five tasks in Spanish
This is a sanity check, not a benchmark suite: five questions in Spanish and one sample per question. I used temperature 1.0, top_p 0.95, min_p 0 and top_k disabled (what the MiniCPM5 card recommends; the Spark card agrees on temperature and top_p), with a fixed seed. I sent them to llama-server with each model’s default reasoning mode and a 4,096-token cap. These are the tasks:
- Fact: date and stations of the first Madrid Metro line (17 October 1919, Cuatro Caminos to Sol).
- Summary: a 101-word paragraph about an email migration, in at most two sentences and 40 words.
- Extraction: an email turned into JSON with contact, company, date, time and the amount before VAT (12,500 EUR).
- Sum: 12 notebooks at 2.35 EUR with a 10% discount, 3 pens at 1.20 EUR and a 50 EUR note (the change is 21.02 EUR).
- Code: a Python function that validates the letter of a Spanish DNI, which I ran against 9 cases in a container with no network.
| Task | Maple-Preview | MiniCPM5-2B | Spark-X2.5-4B | Gemma 4 E2B |
|---|---|---|---|---|
| 1. Fact | Wrong | Wrong | Wrong | Wrong |
| 2. Summary | Partial | Wrong | Correct | Correct |
| 3. JSON | Correct | Correct | Correct | Correct |
| 4. Sum | Correct | Correct, in English | No answer within 4,096 tokens | Correct |
| 5. Code | Correct, 9 of 9 | Correct, 9 of 9 | Correct, 9 of 9 | No answer within 4,096 tokens |
| Total tokens generated | 2,755 | 2,792 | 8,199 | 6,361 |
Every model failed the general-knowledge question, and none of them said it did not know.
Maple answered "10 April 1919, between Atocha and Moncloa". MiniCPM5 said "1914" and stations called "Cívico and Urraca", and Spark said "28 July 1910" between "Plaza de Toros and Champernowy". Gemma settled on "20 June 1919", between Argüelles and Sol. For concrete facts, these models need you to hand them the text or a search tool.
The Spanish showed clear differences. Spark and Maple reasoned in Spanish; MiniCPM5 and Gemma did it in English, and MiniCPM5 even answered the whole sum in English, with LaTeX and \boxed{21.02}.
MiniCPM5’s summary opened with "Las incidentes nocturnos": the gender agreement is wrong, and the original text never says the incidents happened at night. Maple’s turned the two affected users into "Tres usuarios sin correo en móvil" (three users without mail on their phones) and went over 40 words. On the sum, Maple got the 21.02 EUR right with a meaningless sentence in the middle, saying the customer gets back "double the amount paid".
The first version of task 3 asked for an ambiguous nombre (name) key, because the email mentions three people. Maple picked the recipient, MiniCPM5 the sender and Gemma the person attending the meeting. I renamed the key to contacto, clarified it as "the person the meeting is with", and reran those three answers; with that wording all four got it right.
What reasoning mode costs on a CPU
Reasoning multiplied the tokens by 4.7 for MiniCPM5, by 9.1 for Spark and by 2.6 for Gemma, and on a CPU every token is paid for in seconds. I repeated the five tasks with "chat_template_kwargs": {"enable_thinking": false} in the request, which turns reasoning off in the MiniCPM5, Spark and Gemma templates:
| Model | Tokens with reasoning | Tokens without reasoning | Correct without reasoning |
|---|---|---|---|
| MiniCPM5-2B | 2,792 | 588 | 2 of 5 |
| Spark-X2.5-4B | 8,199 | 903 | 2 of 5, plus 2 partial |
| Gemma 4 E2B | 6,361 | 2,459 | 2 of 5, plus 1 partial |
At the speed measured on 6 threads, Spark’s five answers with reasoning add up to about 173 s of generation, against 19 s without it. For Gemma it is 99 s against 38 s, and for MiniCPM5, 34 s against 7 s. Maple generated all of them in about 16 s. These are lower bounds, because llama-bench measures generation with an empty context and it runs somewhat slower with thousands of tokens already in context.
Without reasoning, quality dropped for all three. MiniCPM5 wrote a function with a syntax error (if not digit.isdigit() for digit in digits:) and Gemma invented a weighted sum that does not exist in the DNI algorithm. Spark wrapped the JSON in a code block although the prompt said "write nothing else". Spark, on the other hand, solved the sum in 549 tokens without reasoning, the same sum it did not finish within 4,096 tokens with reasoning.
Maple has no switch. Its template opens the thinking tag on every answer and never reads enable_thinking. I also tried starting llama-server with --reasoning-budget 0, and with the same seed the five answers came out identical, character for character, to the run without that option. Even so it was the most restrained: 2,755 tokens in total, the cap never touched it and, at its speed, it thinks and answers before the others.
Which model to use for which task
The answer depends on whether you have spare RAM or spare CPU:
- Fastest generation with 6 GiB of free RAM: Maple-Preview. It generated 172.84 tokens/s on 6 threads and processed the prompt at 425.99 tokens/s on 8. Assume it always reasons and that it makes facts up.
- Little memory or a small machine: MiniCPM5-2B, with a 1.45 GiB file and 3.27 GiB of RSS at 16,384 tokens. Turn reasoning off only for extraction or formatting, and keep in mind its Spanish is the weakest of the three.
- Spanish and multi-step tasks, with time to spare: Spark-X2.5-4B. It summarised and reasoned best in Spanish, but it is the slowest per token and its reasoning runs long: raise
max_tokensor turn it off for short tasks. - Vision or audio: none of the three, which only generate text. The Gemma 4 E2B GGUF repository does include the multimodal projector (
mmproj).
To place these models among the other recent releases, read which open models of August 2026 are worth running. And if you want the opposite, an MoE of hundreds of GB on a modest machine, Colibri streams the experts from disk.
Frequently asked questions
Can you run an LLM without a GPU at a usable speed?
Yes, if you pick a small model or one with few active parameters. On this arm64 VM, on 6 threads, Maple-Preview generated 172.84 tokens/s, MiniCPM5-2B 83.19 and Spark-X2.5-4B, the slowest, 47.41. On a loaded machine, limit the threads with -t.
Do you need a llama.cpp fork for Maple-Preview or Spark-X2.5?
Not since v0.4.1. Maple needs a build that includes PR 27000 (merged on 14 September 2026) and Spark one at or after b10828. The official GGUFs loaded without reconversion, even though their cards still link to forks.
Which of the three answers best in Spanish?
In this test, Spark-X2.5-4B: it reasoned in Spanish, wrote the only correct summary of the three and solved the sum in Spanish without reasoning. Maple also reasoned in Spanish, with the odd grammatical slip, and MiniCPM5, which only lists English and Chinese, answered one whole task in English.
Conclusion
Without a GPU, Maple-Preview is the pick when generation speed matters most and you have about 6 GiB free. MiniCPM5-2B fits when memory is the limit, and Spark-X2.5-4B when Spanish text matters more than seconds. None of them works as a source of facts without context: all four made up the date of the first Madrid Metro line. If you want to know why llama.cpp gets this much out of a CPU, read about the llama.cpp optimisations that keep surprising.
Sources
- Maple-Preview
- MiniCPM5-2B
- Spark-X2.5-4B
- PR 27000
- PR 27868
- Maple GGUF
- Spark GGUF
- Show HN from 4 August
- llama.cpp v0.4.1 release notes
- PR 8151: TQ1_0 and TQ2_0 ternary packing
- MiniCPM repository on GitHub
- Official MiniCPM5-2B GGUF
- Gemma 4 E2B GGUF by ggml-org
- Gemma release history (Google AI for Developers)
- Madrid Metro Line 1 on Spanish Wikipedia