Dual R9700's AMD VLLM-Container woes

I should pull another build then that’s exciting.

I finally made huge gains with speculative decoding and mirostat

llama-server 
  --presence-penalty 2.0  
  --repeat-penalty 1.05 
  -hf unsloth/Qwen3-Coder-30B-A3B-Instruct-GGUF:Q4_K_M 
  -c 126200 
  -n 65536 
  -b 31600 
  -ub 2048 
  --parallel 1 
  --threads 22 
  --n-gpu-layers all 
  -sm row 
  --flash-attn on 
  --tensor-split 2,1 // 32gb / 16gb split 
  --main-gpu 0 -
  -mlock 
  --temperature 0.1 
  --top-p .95
  --top-k 60 
  -cram 32356 //64gb system
  --no-context-shift 
  -kvu 
  --chat-template-file ~/dev/qwen-3-coder.jinja 
  -sps .2 
  --cache-reuse 1000 //don't cache tool calls 
  --mirostat 2 
  --spec-default //n-gram-mod by default
  --spec-draft-device ROCm0,ROCm1

On the May 13th Lemonade getting 380-850 t/s and accurate coding results. Ran for 12 hrs unattended and was stable, wrote a bunch of tsx that compiled and ran clean.

2 Likes

I gave llama.cpp a try again last night for giggles on the main system, and its slower on every level unfortunately, decode, prefill, prefix hit loading, etc. Roughly 1/5 prefill and 1/2 decode with much worse endurance across long context, plus it has the kv management overhead reducing efficiency of bandwidth available.

Upcoming exciting news for VLLM users…
In process of validating my new dynamic quantization work, it quantizes, serves, runs. I have run logprob benches, perplexity benches, and throughput benches against it and found a clear and beneficial gain vs pure NVFP4. Recovers ~70% of the loss between FP8 and NVFP4 at the cost of 1bpw of extra space usage compared to NVFP4, or, framed another way is essentially indistinguishable from FP8 output quality during actual inference for only 68% of the space and can be configured to regain ~93% of the loss whilst still saving space vs pure FP8 Block 128 quantization.

Conceptually similar to the many flavors of GGUF out there, which will allow precise vram space targeting for vllm. Will be incorporating a user argument to input a desired memory space target, model folder, and desired context length, it will generate the accuracy settings to maximize quality for available space and provide the quantized model ideal for your footprint available.

Relevant for dual card users as it will allow you to gain ~FP8 accuracy tailored to your GPUs VRAM footprint and simplify the complexity of getting vllm to behave.

2 Likes

Just gave it a go, can confirm im getting 47 tk/s on the nose, wow the performance improvement of MTP is really a gamechanger for how quickly and responsive chats now feel

Too bad Gemma doesn’t have a model with baked-in MTP and llama-server doesn’t support seperate assistant draft models yet, i prefer gemma 31b over qwen 27b for writing/drafting email but the the performance of qwen 27b has now roughly doubled making gemma 31b hard to justify :sweat_smile:

edit:

it’s all very fresh though, so probably will be included as an option soonish

It absolutely does!

[draft_Qwen3.6-27B-Q4_0]
mmap=0
cache-type-k=q8_0
cache-type-v=q8_0
ctx-size=256000
flash-attn=on
model=/opt/working2/llm/models.1/Qwen3.6-27B-Q4_K_M.gguf
n-gpu-layers=999
threads=1
temp        = 0.7
top-p       = 0.8
top-k       = 20
split-mode=none
device=Vulkan0
chat-template-kwargs={"enable_thinking": false}
model-draft=/opt/working2/llm/models.1/Qwen3.5-0.8B-Q8_0.gguf
spec-draft-n-max = 6
spec-draft-ngl = 99
spec-draft-type-k = q8_0
spec-draft-type-v = q8_0

It doesn’t support DFlash draft models yet, but standard models work just fine.

In other news related to this thread, Lemonade now have a portable vLLM package bundled with ROCm too:

1 Like

so it specifically doesnt support gemma4 yet then?

edit (Guess i’ll just have to sit tight for a bit, good to know about the option though i was trying it with –-mtp-head):

Loading model… -0.14.204.289 E llama_model_load: error loading model: unknown model architecture: ‘gemma4_assistant’
0.14.204.306 E llama_model_load_from_file_impl: failed to load model
0.14.204.308 E srv load_model: failed to load draft model, ‘/mnt/steam/models/gemma-4-31B-it-assistant.Q4_K_M.gguf’

Failed to load the model

Aww sweet ill give the vllm a go

MTP+Qwen27B +nous hermes is nothing short of miraculous :sweat_smile:, -np2/3 also really scales well with it for throughput,

i’m maxing out the vram on this one multiple 200K contexts, its pretty much redlining at 660 watts continuous

2 Likes

I am blown away, i can’t wait for gemma31b to be supported by mtp, i’ll give 35b a try as well, but i’m never really a fan of smaller MoE’s

This makes me feel 2 gpu’s are not enough……i need 4 i want more context more subagents

,……oh god my wallet

1 Like

I’ve just tried the latest llama.cpp build with the MTP fixes from ggerganov - it’s great. I’m working at the moment, so I’ve only had time to try the Qwen 3.6 35B Q8_0 (my daily-driver model), and…it’s actually pretty good. Prefill is down to ~3200t/s from ~5200t/s, which is still totally acceptable, but decode is consistently up from 105t/s to 130-140t/s in a mix of text and code generation.

Even more awesomely, you can combine speculative decoding strategies, so I’ve got MTP generating model drafts as well as the ngram-mod self-speculation generating drafts from the KV cache. In my usual test (“Show me a combination of two novel algorithms in Ruby” → “Now make it an API using Sinatra. Code only, no commentary”), it’s hitting over 200t/s decode.

In terms of overall feel, it’s a definite improvement in agentic use cases.

Yeah i’m not getting those numbers with a dense model but MTP has definitely been a game changer for me XD

I’ll give the 35b another shot

The bit that I neglected to mention is that before the MTP cleanup PR, my prefill on that model was ~2000t/s, so it’s a +60% improvement for me there.

That would probably have been relevant information :smiley:

I’m once again thanking you for helping to improve my setup:

llm-serve \
  --presence-penalty 1.5 \
  --repeat-penalty 1.15 \
  -hf unsloth/Qwen3.6-27B-MTP-GGUF:Q4_K_M \
  -c 160000 \
  -cpent 32000 \
  -n 32000 \
  -b 32000 \
  -ub 2048 \
  --parallel 1 \
  --threads 22 \
  --n-gpu-layers all \
  -sm row \
  --flash-attn on \
  --tensor-split 2,1 \
  --main-gpu 0 \
  --mlock \
  --temperature 0.1 \
  --top-p .8 \
  --top-k 100 \
  -cram 32356 \
  --no-context-shift \
  -kvu \
  -sps .9 \
  --cache-reuse 1000 \
  --mirostat 0 \
  --spec-draft-device ROCm0 \
  --spec-draft-ngl 33 \
  --spec-type ngram-mod \
  --spec-ngram-mod-n-min 32 \
  --spec-ngram-mod-n-max 48 \
  --spec-ngram-mod-n-match 10 \
  --spec-draft-p-split 0.3 \
  --spec-draft-n-min 2 \
  --spec-draft-n-max 8 \
  --spec-draft-p-min 0.6 \
  --reasoning off

Mirostat was slowing this down when I brought my settings over from qwen 3 coder. But now I’m getting 275-550 prefill and 20 t/s generation. When I first switched models to Qwen3.6 was getting about 12 t/s prior to changing this up.

Lemonade release: Release b1275 · lemonade-sdk/llamacpp-rocm · GitHub

Slower but much higher quality output for agentic coding. As I’ve been trying to tune for speed and quality I’m finding I feel like theres a constant trade-off and you gotta figure out what’s right for you. I’d rather leave some performance on the table in exchange for consistent accurate results.

I’ll have to compare now with a vllm build if lemonades providing it easy I hit instant road blocks with ROCm a month ago trying it.

A few things on that config…

  • -sm row - this is, generally-speaking, the worst way to do it with ROCm and a dense model. If you must use two GPUs, then use layer instead.
  • Why are you splitting it across two GPUs? The R9700 can fit the whole 27B Q4_K_M model, plus MTP layers, plus maximum context. It’ll be much faster.
  • Again if you must use two GPUs, then specifying one of them for the drafting is actually slower than splitting it across both.
  • The llama.cpp guys recommend setting --threads 1 if all the layers are on the GPU(s), because anything else just adds overhead.
1 Like
  • The only reason that’s in there was because I saw it in here I’ll try without it: llama.cpp - Qwen

  • I’ve just been generally taking the approach that splitting gives more room for larger context. Are you suggesting change the tensor split to 1, 0? or fully just not even leveraging it (how I’m understanding)

  • Interesting, I thought I had seen better performance setting this higher, my cpu is fine, I only really see 3 active threads at any given time and only 1 per gpu is doing substantial work.

So I guess my question then is how do I best utilize the other gpu in this scenario just running a smaller model in parallel there?

Answering my own question here a bit:

llama-server \                                
  --host 127.0.0.1 \
  --port 8001 \
  --main-gpu 1 \
  --n-gpu-layers all \
  --split-mode none \
  -hf Jackrong/Qwopus3.5-9B-Coder-MTP-GGUF:Q8_0

llama-server \
  --presence-penalty 1.5 \
  --repeat-penalty 1.15 \
  -hf unsloth/Qwen3.6-27B-MTP-GGUF:Q4_K_M \
  -c 160000 \
  -cpent 32000 \
  -n 32000 \
  -b 32000 \
  -ub 2048 \
  --parallel 1 \
  --threads 1 \
  --n-gpu-layers all \
  --flash-attn on \
  -sm none \
  --mlock \
  --temperature 0.1 \
  --top-p .8 \
  --top-k 100 \
  -cram 32356 \
  --no-context-shift \
  -kvu \
  -sps .9 \
  --cache-reuse 1000 \
  --mirostat 0 \
  --spec-draft-ngl 33 \
  --spec-type ngram-mod \
  --spec-ngram-mod-n-min 32 \
  --spec-ngram-mod-n-max 48 \
  --spec-ngram-mod-n-match 8 \
  --spec-draft-p-split 0.4 \
  --spec-draft-n-min 2 \
  --spec-draft-n-max 8 \
  --spec-draft-p-min 0.5 \
  --reasoning off

Well, in my experience, uneven splits have always performed lower than even splits, and even splits have always performed lower than a single GPU (for decode, at least).

I would suggest getting rid of the split entirely, and specifying --device ROCm0 instead. You can’t use tensor split effectively because you have mismatched GPUs, so that would - to me - be the best way to do it.

The only caveat, to my knowledge, is that you might need to quantise the KV cache to q8_0. That’s no real sacrifice, though, and you would only notice the (marginal) difference in quality if your model was Q8 or BF16.

So…yeah, my recommendation would be to put the whole model on the R9700, including MTP layers, whack the context up to the max and quantise it to q8_0. That’s basically how I run it, and I’ve had up to 65t/s out of it in ROCm with MTP.

As for using the other GPU…you could put a smaller model on there with lower context and use it for watchdog work or similar (ie sense-checking the work of the primary model in an agent), or maybe run Qwen3.5-9B without MTP for parallel subagents (since MTP prevents that on the main model).

1 Like

Looking into load balancing the 2 now :grin: thanks!


Anyone running the Qwen3.6 27B MTP should try swapping this in Jackrong/Qwopus3.6-27B-v2-MTP-GGUF · Hugging Face

Model notes better results with --temp 1.0

are you using kv cache quantisation for your agentic work btw? so far i haven’t messed with the ctv and ctk yet beyond a quick test to see the reduction in vram usage, is there any noticeable degradation for agentic work to not use the standard f16 there?

i’ve been running this as my daily driver for the past week:

/opt/llamacpp/llama-b9222/llama-server --host 0.0.0.0 --models-preset /mnt/vfio-nas/models/config.ini -ngl 999 -fa 1 --cache-ram 32000 --ctx-checkpoints 16 --no-mmap --sleep-idle-seconds 900 --models-max 1 -np 1

the Spec draft stuff i load from the models config.ini and looks like this:

model = /mnt/vfio-nas/models/Qwen3.6-27B-uncensored-heretic-v2-Native-MTP-Preserved-Q8_0.gguf
mmproj = /mnt/vfio-nas/models/Qwen3.6-27B-mmproj-BF16.gguf
ctx-size = 262000
spec-type = draft-mtp
spec-draft-n-max = 3

I’ve run it both ways - when I was running a separate completion model, I used q8_0 on both just to avoid hitting the limit of my VRAM. Now that I’m just running one model, I don’t bother (the Q8_0 GGUF plus MTP and full context comes to about 46.5GB, which still leaves me a bit of room to play with other models should I need it). I haven’t noticed any quality difference, although - and I haven’t tested this exhaustively - prefill seems about 6% faster on average, and MTP decode might be about 2% faster; treat this as entirely anecdotal.