Sign inSign up

skyne98/tp906-engine

By skyne98

•Updated 6 months ago

Qwen3.5 inference for AMD MI50 -- TP, MTP, GGUF

Image
0

996

skyne98/tp906-engine repository overview

⁠tp906-engine

GPU inference engine for Qwen3.5 (Dense) hybrid models on AMD Instinct MI50 (gfx906).

Custom HIP kernels, flash attention, P2P tensor parallelism (TP=1..8), MTP speculative decoding. Reads GGUF model files.

⁠Quick Start

# Benchmark
docker run --device=/dev/kfd --device=/dev/dri --group-add video \
  --ipc=host -v /path/to/models:/models \
  skyne98/tp906-engine tp906-bench -m /models/model.gguf

# Chat
docker run -it --device=/dev/kfd --device=/dev/dri --group-add video \
  --ipc=host -v /path/to/models:/models \
  skyne98/tp906-engine tp906-chat /models/model.gguf

# OpenAI-compatible server
docker run --device=/dev/kfd --device=/dev/dri --group-add video \
  --ipc=host -v /path/to/models:/models -p 8080:8080 \
  skyne98/tp906-engine tp906-server /models/model.gguf --host 0.0.0.0

⁠Supported Models

Architecture: Qwen3.5 Dense (and MoE variants).

ModelTP=1TP=2TP=4
Qwen3.5-0.8Byesyesyes
Qwen3.5-2Byesyesyes
Qwen3.5-4Byesyesyes
Qwen3.5-9Byesyesyes
Qwen3.5-27B--yesyes

TP must evenly divide the model head count (32 for all dense Qwen3.5), so valid values are 1, 2, 4, 8, 16, 32.

⁠Supported Quantizations
FormatNotes
Q8_0Native, best quality/speed tradeoff
Q4_0Converted to Q8_0 in VRAM on load (fast GPU kernel)
Q4_1Converted to Q8_0 in VRAM on load (fast GPU kernel)
Q6_KConverted to Q8_0 in VRAM on load (fast GPU kernel)
Q5_K_MConverted to Q8_0 in VRAM on load (CPU dequant path)
Q4_K_MConverted to Q8_0 in VRAM on load (CPU dequant path)
Q3_KConverted to Q8_0 in VRAM on load (CPU dequant path)
Q2_KConverted to Q8_0 in VRAM on load (CPU dequant path)
F16Converted to Q8_0 in VRAM on load

Note: All quantizations are converted to Q8_0 at load time. Q4_0, Q4_1, and Q6_K use fast GPU requantization kernels; others go through CPU dequant. VRAM usage is always the Q8_0 size regardless of source format.

⁠MTP (Multi-Token Prediction) Speculative Decoding

MTP provides ~10-15% faster decode by speculatively predicting one token ahead.

⁠Getting MTP Weights

Pre-extracted weights for all Qwen3.5 sizes: raspbfox/tp906-mtp⁠

# Download for your model size — place next to the GGUF file
cd /path/to/models/
wget https://huggingface.co/raspbfox/tp906-mtp/resolve/main/Qwen3.5-9B/mtp_weights.bin

Available: 0.8B⁠ (39 MB) | 2B⁠ (116 MB) | 4B⁠ (230 MB) | 9B⁠ (465 MB) | 27B⁠ (811 MB)

⁠Using MTP

Auto-detect: place mtp_weights.bin in the same directory as your GGUF file. tp906 finds it automatically.

Explicit: --mtp /path/to/mtp_weights.bin

Server INI: use the mtp key (see models.ini section below).

⁠Extracting MTP Weights Yourself
# Requires: pip install huggingface_hub numpy
python3 tools/extract_mtp.py --repo Qwen/Qwen3.5-9B -o mtp_weights.bin

Downloads only the needed safetensor shards, extracts the 15 MTP tensors, converts BF16 to F16.

⁠Multi-GPU (Tensor Parallelism)

docker run --device=/dev/kfd --device=/dev/dri --group-add video \
  --ipc=host -v /path/to/models:/models \
  skyne98/tp906-engine tp906-bench -m /models/model.gguf --tp 4
  • P2P DMA with IPC shared memory -- --ipc=host is required
  • Decode: P2P allreduce (low latency)
  • Prefill: NCCL allreduce (high bandwidth)

⁠models.ini (Multi-Model Server)

Serve multiple models from one instance. Clients select via the model field in API requests. TP is automatically reconfigured when switching models.

; First entry loads at startup. Comments: ; or #

[Qwen3.5-9B]
path    = /models/Qwen3.5-9B-Q8_0.gguf
mtp     = /models/Qwen3.5-9B/mtp_weights.bin
tp      = 4
max_seq = 32768

[Qwen3.5-4B]
path    = /models/Qwen3.5-4B-Q8_0.gguf
tp      = 2

[Qwen3.5-0.8B]
path    = /models/Qwen3.5-0.8B-Q8_0.gguf
tp      = 1
KeyRequiredDescription
pathyesPath to GGUF model file
mtpPath to MTP weights (or auto-detect from model dir)
tpTensor parallelism degree (number of GPUs)
max_seqMaximum sequence length (default: 8192)
docker run --device=/dev/kfd --device=/dev/dri --group-add video \
  --ipc=host -v /path/to/models:/models -p 8080:8080 \
  skyne98/tp906-engine tp906-server --models /models/models.ini --host 0.0.0.0

⁠CLI Reference

⁠tp906-bench

Benchmark tool with llama-bench compatible output format.

FlagDefaultDescription
-m, --model <file>(required)GGUF model file
-p, --n-prompt <n>512Prompt tokens to benchmark
-n, --n-gen <n>128Generation tokens to benchmark
-d, --n-depth <n>0KV cache depth before benchmarking
-r, --repetitions <n>5Repetitions per test
--tp <n>1Tensor parallel across N GPUs
--max-seq <n>131072Maximum sequence length
--mtp <path>(auto-detect)MTP weights for speculative decoding
-o, --output <fmt>mdOutput format: md or csv
--no-warmupSkip warmup runs

Comma-separated values for sweeps: -p 128,256,512 -n 64,128

⁠tp906-chat

Interactive chat CLI.

FlagDefaultDescription
<model.gguf>(required)GGUF model file (positional)
--tp <n>1Tensor parallel across N GPUs
--max-seq <n>8192Maximum sequence length
--max-new-tokens <n>32768Max tokens to generate per turn
--system <text>System prompt
--prompt <text>One-shot prompt (non-interactive mode)
--no-thinkingDisable thinking/reasoning blocks
--temp <f>0.80Temperature
--top-k <n>40Top-K sampling
--top-p <f>0.95Top-P / nucleus sampling
--min-p <f>0.05Min-P sampling
--repeat-penalty <f>1.0Repetition penalty (1.0 = disabled)
--seed <n>(random)Random seed for reproducibility
--mtp <path>(auto-detect)MTP weights for speculative decoding

Interactive commands: /help /paste /file <path> /history /reset /quit

⁠tp906-server

OpenAI-compatible HTTP API server.

FlagDefaultDescription
<model.gguf>GGUF model file (single-model mode)
--models <ini>Model catalog INI file (multi-model mode)
--host <addr>0.0.0.0Bind address
--port <n>8080Port
--tp <n>1Tensor parallel across N GPUs
--max-seq <n>8192Maximum sequence length
--max-new-tokens <n>32768Max tokens to generate
--no-thinkingDisable thinking/reasoning blocks
--temp <f>0.80Default temperature
--top-k <n>40Default top-K
--top-p <f>0.95Default top-P
--min-p <f>0.05Default min-P
--seed <n>(random)Default random seed
--mtp <path>(auto-detect)MTP weights for speculative decoding

Endpoints:

MethodPathDescription
POST/v1/chat/completionsChat completion (streaming supported via stream: true)
GET/v1/modelsList available models
GET/healthHealth check

⁠Requirements

  • AMD Instinct MI50 (gfx906) GPU(s)
  • ROCm kernel driver (amdgpu) on the host
  • Docker flags: --device=/dev/kfd --device=/dev/dri --group-add video
  • --ipc=host for multi-GPU tensor parallelism
sudo sysctl -w kernel.numa_balancing=0   # prevent GPU DMA stalls
# Kernel parameter (GRUB): iommu=pt       # prevent IOMMU overhead

⁠Performance (MI50 x4, 1143 MHz comfort clocks)

ModelQuantTPPrefill (pp512)Decode (tg128)
Qwen3.5 0.8BQ8_014,050 t/s182 t/s
Qwen3.5 4BQ8_021,405 t/s89 t/s
Qwen3.5 9BQ8_041,223 t/s68 t/s

⁠Version

0.0.1-pre-alpha-1 -- early testing release.

Tag summary

Content type

Image

Digest

sha256:1e85a7d31…

Size

350.2 MB

Last updated

6 months ago

docker pull skyne98/tp906-engine