tl;dr: GGML_CUDA_ENABLE_UNIFIED_MEMORY=1 and --n-cpu-moe 999
Qwen 3.6 35b a3b is a Mixture of Experts model, which means it can efficiently be split between system RAM and your GPU’s VRAM. 35b means 35 billion total parameters, and a3b means 3 billion active parameters.
You’ll usually want at least a Q4 quantization (average of 4 to 5 bits per parameter). IQ4 will also work but it can be slow on the CPU and we’ll be running this partially on the CPU. You might also want to try an APEX quantization, I haven’t tried those yet.
I’ll write this for llama.cpp, but it’s actually pretty similar if you’re using LM Studio except that’s a GUI. I’m testing with a Ryzen 2600, 32GB of DDR4, and an RTX 2080.
To run this on low VRAM GPUs use --n-cpu-moe in llama.cpp. Set the number higher for more layers in system RAM, and set it lower to put more layers into VRAM. This model has 40 layers, but you can set it to 999 just to do all of the layers without remembering how many it has.
./build/bin/llama-bench -m '/path-to-model/Qwen_Qwen3.6-35B-A3B-Q4_K_S.gguf' --n-cpu-moe 99 -p 8192
This can maybe run in 4GB of VRAM, especially if you’re running Linux headless (no GUI).
| model | size | params | backend | ngl | n_cpu_moe | test | t/s |
|---|---|---|---|---|---|---|---|
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | pp8192 | 316.97 ± 3.92 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | tg128 | 30.92 ± 0.71 |
pp8192 means prompt processing for 8192 input tokens. 316 tokens per second isn’t great here, but we can improve it by using more VRAM later. tg128 means generating 128 output tokens, 30 tokens per second is pretty decent, comfortable enough to use.
Let’s use some more VRAM to make our pp faster than 316. We can increase --batch-size and --ubatch-size from their default of 512. A cool thing about llama-bench is you can give it comma separated values to test multiple values.
$ ./build/bin/llama-bench -m '/path-to-model/Qwen_Qwen3.6-35B-A3B-Q4_K_S.gguf' --n-cpu-moe 99 -p 8192 --batch-size 4096 --ubatch-size 512,1024,2048,4096
| model | size | params | backend | ngl | n_cpu_moe | n_batch | n_ubatch | test | t/s |
|---|---|---|---|---|---|---|---|---|---|
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 4096 | 512 | pp8192 | 317.11 ± 3.42 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 4096 | 512 | tg128 | 30.17 ± 0.76 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 4096 | 1024 | pp8192 | 529.78 ± 2.53 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 4096 | 1024 | tg128 | 30.79 ± 1.04 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 4096 | 2048 | pp8192 | 835.52 ± 9.61 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 4096 | 2048 | tg128 | 31.34 ± 0.20 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 4096 | 4096 | pp8192 | 1188.90 ± 6.49 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 4096 | 4096 | tg128 | 31.55 ± 0.47 |
--ubatch-size 4096 seems to require about 6GB of VRAM to run this benchmark. You can see the higher ubatch size gave us a huge boost to pp speed, especially since I only have PCIe 3.0.
We can also compress the KV cache so we can handle larger input sizes with less VRAM/RAM used. I find Q8_0 to be good quality for input sizes up to about 80000 tokens. To do this add the arguments --cache-type-k q8_0 --cache-type-v q8_0
If you want to make sure you never crash due to running out of VRAM and you’re on Linux with Nvidia you can use the GGML_CUDA_ENABLE_UNIFIED_MEMORY=1 environment variable. This can save frustration if you’re running background prompts/agents (I like Zoo Code) and especially when using your computer while it’s running.
This may also allow you to squeeze out some extra speed if you’re smart and only overflow a little bit, maybe for extra --ubatch-size.
$ GGML_CUDA_ENABLE_UNIFIED_MEMORY=1 ./build/bin/llama-bench -m '/path-to-model/Qwen_Qwen3.6-35B-A3B-Q4_K_S.gguf' --n-cpu-moe 99 -p 8192 --batch-size 8192 --ubatch-size 8192
| model | size | params | backend | ngl | n_cpu_moe | n_batch | n_ubatch | test | t/s |
|---|---|---|---|---|---|---|---|---|---|
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 8192 | 8192 | pp8192 | 1458.73 ± 2.46 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 99 | 8192 | 8192 | tg128 | 29.70 ± 0.44 |
This fails to load without GGML_CUDA_ENABLE_UNIFIED_MEMORY=1 because I have my web browser and other programs open. Even still, I can push this a bit farther. The pp stage and the tg stage use different pieces of memory, so the swapping can be pretty minimal if you tune according to that. For the pp stage it only needs to work with 1 layer at a time but it uses a lot of memory for large ubatches, and the tg stage frees up the memory of the ubatch but it reads every layer for every token. So we can keep more of the model layers in VRAM so they can swap in for tg.
$ GGML_CUDA_ENABLE_UNIFIED_MEMORY=1 ./build/bin/llama-bench -m '/path-to-model/Qwen_Qwen3.6-35B-A3B-Q4_K_S.gguf' --n-cpu-moe 34,35,36 -p 8192 --batch-size 8192 --ubatch-size 8192
| model | size | params | backend | ngl | n_cpu_moe | n_batch | n_ubatch | test | t/s |
|---|---|---|---|---|---|---|---|---|---|
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 34 | 8192 | 8192 | pp8192 | 1139.85 ± 157.82 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 34 | 8192 | 8192 | tg128 | 32.51 ± 1.25 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 35 | 8192 | 8192 | pp8192 | 1525.79 ± 5.10 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 35 | 8192 | 8192 | tg128 | 32.81 ± 0.64 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 36 | 8192 | 8192 | pp8192 | 1502.14 ± 7.80 |
| qwen35moe 35B.A3B Q4_K - Small | 19.17 GiB | 34.66 B | CUDA | -1 | 36 | 8192 | 8192 | tg128 | 32.66 ± 0.69 |
For me with my current workload, it seems like --n-cpu-moe 35 is the fastest, but not much faster than 99.
You can also try disabling hardware acceleration in your web browser if you want to save VRAM.
You might also get slightly faster results (especially on Windows?) with --mmap 0 to disable memory mapping, which locks the model into memory. But this can cause more swap memory. I don’t like disabling it on Linux with 32GB of RAM with other programs open, but if I had 64GB I probably would.
If you’re using an --mmproj file for image processing, you can use --no-mmproj-offload = true to force it to stay on system RAM instead of VRAM, but it will be extremely slow when processing images.
You can try MTP to speedup the tg, but I don’t think it’s a great combo with a MoE model and on low VRAM. I’ll need to test it, but it can’t be tested in llama-bench.
This template file might help you with tool call issues https://huggingface.co/froggeric/Qwen-Fixed-Chat-Templates
There’s been a lot of talk about KAT-Coder-V2.5-Dev which is just a fine tune, so it’s the same size as 35b a3b. It might be better for programming.
If you want to do similar for Gemma 4 26b a4b, which is another great Mixture of Experts model, know that it has 30 layers instead of 40. But I’m actually finding it hard to beat the performance of --n-cpu-moe 99 by any significant amount, probably because Gemma has a very different sparsity ratio (26b a4b instead of 35b a3b).


Thank you very much!
This was immensely informative and helpful at the very least to get a better understanding of the whole picture…
Great and quality post!