444 lines
12 KiB
Markdown
444 lines
12 KiB
Markdown
# Qwen3-4B on llama.cpp with ROCm (AMD BC-250)
|
||
|
||
> Running **Qwen3-4B-Q8_0** via **llama.cpp** with **ROCm HIP** GPU acceleration on the **AMD BC-250 (gfx1010)**.
|
||
|
||
---
|
||
|
||
## Table of Contents
|
||
|
||
- [System Overview](#system-overview)
|
||
- [Prerequisites](#prerequisites)
|
||
- [Step 1: Clone llama.cpp](#step-1-clone-llamacpp)
|
||
- [Step 2: Build llama.cpp with ROCm HIP](#step-2-build-llamacpp-with-rocm-hip)
|
||
- [Step 3: Download the Model](#step-3-download-the-model)
|
||
- [Step 4: Run Inference (Interactive Chat)](#step-4-run-inference-interactive-chat)
|
||
- [Step 5: Run Inference (One-Shot / Batch)](#step-5-run-inference-one-shot--batch)
|
||
- [Step 6: Run as API Server](#step-6-run-as-api-server)
|
||
- [Performance Results](#performance-results)
|
||
- [VRAM / Memory Breakdown](#vram--memory-breakdown)
|
||
- [Useful Parameters Reference](#useful-parameters-reference)
|
||
- [Troubleshooting](#troubleshooting)
|
||
- [Notes & Tips](#notes--tips)
|
||
|
||
---
|
||
|
||
## System Overview
|
||
|
||
| Component | Value |
|
||
|------------------|-----------------------------------------------|
|
||
| **GPU** | AMD BC-250 (Navi 10, gfx1010) |
|
||
| **VRAM** | ~14.4 GiB (14750 MiB) |
|
||
| **Wave Size** | 32 |
|
||
| **ROCm Version** | 7.2.0 |
|
||
| **HIP Version** | 7.2.26043-9999 |
|
||
| **HIP Compiler** | AMD clang 22.0.0git (ROCm LLVM) |
|
||
| **OS** | CachyOS (Arch-based), Kernel 6.18.8-3-cachyos |
|
||
| **CPU** | 12 threads |
|
||
| **RAM** | 14 GiB system + 14 GiB swap |
|
||
| **llama.cpp** | Build b8184 (commit `3191462`) |
|
||
| **CMake** | 4.2.3 |
|
||
|
||
---
|
||
|
||
## Prerequisites
|
||
|
||
Before starting, ensure you have:
|
||
|
||
1. **ROCm installed and working** — verify with:
|
||
```bash
|
||
rocm-smi
|
||
rocminfo | grep -E "Name:|gfx"
|
||
```
|
||
|
||
2. **Required packages**:
|
||
```bash
|
||
# Arch/CachyOS
|
||
sudo pacman -S git cmake base-devel aria2
|
||
|
||
# Ubuntu/Debian
|
||
sudo apt install git cmake build-essential aria2
|
||
```
|
||
|
||
3. **ROCm development libraries** (hipblas, rocblas):
|
||
```bash
|
||
# Verify they exist
|
||
ls /opt/rocm/lib/libhipblas.so
|
||
ls /opt/rocm/lib/librocblas.so
|
||
ls /opt/rocm/lib/llvm/bin/clang++
|
||
```
|
||
|
||
4. **Know your GPU architecture**:
|
||
```bash
|
||
rocminfo | grep "Name:" | grep gfx
|
||
# Output: gfx1010 (for BC-250)
|
||
```
|
||
|
||
---
|
||
|
||
## Step 1: Clone llama.cpp
|
||
|
||
```bash
|
||
cd ~
|
||
git clone https://github.com/ggml-org/llama.cpp.git
|
||
cd llama.cpp
|
||
```
|
||
|
||
If already cloned, update:
|
||
```bash
|
||
cd ~/llama.cpp
|
||
git stash # if you have local changes
|
||
git pull
|
||
```
|
||
|
||
---
|
||
|
||
## Step 2: Build llama.cpp with ROCm HIP
|
||
|
||
### Configure
|
||
|
||
```bash
|
||
cd ~/llama.cpp
|
||
rm -rf build
|
||
mkdir build && cd build
|
||
|
||
cmake .. \
|
||
-DGGML_HIP=ON \
|
||
-DAMDGPU_TARGETS="gfx1010" \
|
||
-DCMAKE_BUILD_TYPE=Release \
|
||
-DCMAKE_HIP_COMPILER=/opt/rocm/lib/llvm/bin/clang++ \
|
||
-G "Unix Makefiles"
|
||
```
|
||
|
||
**Key flags explained:**
|
||
|
||
| Flag | Purpose |
|
||
|------|---------|
|
||
| `-DGGML_HIP=ON` | Enable HIP/ROCm GPU backend |
|
||
| `-DAMDGPU_TARGETS="gfx1010"` | Target GPU architecture (BC-250 = gfx1010) |
|
||
| `-DCMAKE_HIP_COMPILER=/opt/rocm/lib/llvm/bin/clang++` | Use ROCm's clang directly (required for CMake ≥ 4.x, `hipcc` wrapper is rejected) |
|
||
| `-G "Unix Makefiles"` | Use Make instead of Ninja |
|
||
|
||
> **Important (CMake 4.x):** Do NOT use `-DCMAKE_HIP_COMPILER=/opt/rocm/bin/hipcc` — CMake 4.x explicitly rejects the hipcc wrapper. You must point to the clang++ binary inside ROCm's LLVM directory.
|
||
|
||
### Verify Configuration
|
||
|
||
```bash
|
||
grep "GGML_HIP" CMakeCache.txt
|
||
# Should show: GGML_HIP:BOOL=ON
|
||
```
|
||
|
||
### Build
|
||
|
||
```bash
|
||
make -j$(nproc)
|
||
```
|
||
|
||
> **Build time:** HIP compilation is slow (~15-25 minutes on 12 threads). Each `.cu` template gets compiled to AMDGPU ISA for gfx1010. Be patient.
|
||
|
||
### Verify Build Output
|
||
|
||
```bash
|
||
ls -lh build/bin/llama-cli build/bin/llama-server
|
||
|
||
# Verify HIP linkage
|
||
ldd build/bin/llama-cli | grep -i "hip\|rocm"
|
||
```
|
||
|
||
Expected output:
|
||
```
|
||
libggml-hip.so.0 => .../libggml-hip.so.0
|
||
libhipblas.so.3 => /opt/rocm/lib/libhipblas.so.3
|
||
librocblas.so.5 => /opt/rocm/lib/librocblas.so.5
|
||
libamdhip64.so.7 => /opt/rocm/lib/libamdhip64.so.7
|
||
librocsolver.so.0 => /opt/rocm/lib/librocsolver.so.0
|
||
libhsa-runtime64.so.1 => /opt/rocm/lib/libhsa-runtime64.so.1
|
||
```
|
||
|
||
---
|
||
|
||
## Step 3: Download the Model
|
||
|
||
### Using aria2 (Recommended — Maximum Speed)
|
||
|
||
```bash
|
||
mkdir -p ~/models
|
||
|
||
aria2c \
|
||
-x 16 \
|
||
-s 16 \
|
||
-k 1M \
|
||
-d ~/models \
|
||
-o Qwen3-4B-Q8_0.gguf \
|
||
"https://huggingface.co/Qwen/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q8_0.gguf"
|
||
```
|
||
|
||
| aria2 Flag | Purpose |
|
||
|------------|---------|
|
||
| `-x 16` | 16 connections per server |
|
||
| `-s 16` | Split into 16 segments |
|
||
| `-k 1M` | Minimum split size 1MB |
|
||
|
||
### Using wget (Fallback)
|
||
|
||
```bash
|
||
wget -c \
|
||
"https://huggingface.co/Qwen/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q8_0.gguf" \
|
||
-O ~/models/Qwen3-4B-Q8_0.gguf
|
||
```
|
||
|
||
### Verify Download
|
||
|
||
```bash
|
||
ls -lh ~/models/Qwen3-4B-Q8_0.gguf
|
||
# Expected: ~4.0 GiB (4,280,404,704 bytes)
|
||
```
|
||
|
||
> **Model Source:** [Qwen/Qwen3-4B-GGUF](https://huggingface.co/Qwen/Qwen3-4B-GGUF) on Hugging Face (official Qwen repo).
|
||
|
||
---
|
||
|
||
## Step 4: Run Inference (Interactive Chat)
|
||
|
||
```bash
|
||
cd ~/llama.cpp/build/bin
|
||
|
||
./llama-cli \
|
||
-m ~/models/Qwen3-4B-Q8_0.gguf \
|
||
-ngl 99 \
|
||
-c 4096 \
|
||
--temp 0.6 \
|
||
--top-k 20 \
|
||
--top-p 0.95
|
||
```
|
||
|
||
**Expected startup output:**
|
||
```
|
||
ggml_cuda_init: found 1 ROCm devices:
|
||
Device 0: AMD BC-250, gfx1010:xnack- (0x1010), VMM: no, Wave Size: 32
|
||
|
||
build : b213-3191462
|
||
model : Qwen3-4B-Q8_0.gguf
|
||
modalities : text
|
||
```
|
||
|
||
You'll get an interactive `>` prompt. Type your question and press Enter.
|
||
|
||
**In-chat commands:**
|
||
| Command | Action |
|
||
|-------------|---------------------------------|
|
||
| `/exit` | Exit the chat |
|
||
| `/clear` | Clear chat history |
|
||
| `/regen` | Regenerate last response |
|
||
| `/read` | Load a text file into context |
|
||
| `Ctrl+C` | Force exit |
|
||
|
||
### Disable Thinking Mode
|
||
|
||
Qwen3-4B has a "thinking" mode enabled by default (responses start with `[Start thinking]`). To disable it and get direct answers:
|
||
|
||
```bash
|
||
./llama-cli \
|
||
-m ~/models/Qwen3-4B-Q8_0.gguf \
|
||
-ngl 99 \
|
||
-c 4096 \
|
||
--temp 0.7 \
|
||
--top-k 20 \
|
||
--top-p 0.8 \
|
||
--jinja \
|
||
--chat-template-file ~/llama.cpp/models/templates/qwen3.jinja \
|
||
-e
|
||
```
|
||
|
||
Or append `/no_think` to your prompt for per-message control.
|
||
|
||
---
|
||
|
||
## Step 5: Run Inference (One-Shot / Batch)
|
||
|
||
For scripting or single-prompt usage without interactive mode:
|
||
|
||
```bash
|
||
cd ~/llama.cpp/build/bin
|
||
|
||
./llama-cli \
|
||
-m ~/models/Qwen3-4B-Q8_0.gguf \
|
||
-ngl 99 \
|
||
-p "Explain what ROCm is in 2 sentences." \
|
||
-n 200 \
|
||
--no-display-prompt \
|
||
--no-conversation
|
||
```
|
||
|
||
---
|
||
|
||
## Step 6: Run as API Server
|
||
|
||
llama.cpp includes an OpenAI-compatible HTTP API server:
|
||
|
||
```bash
|
||
cd ~/llama.cpp/build/bin
|
||
|
||
./llama-server \
|
||
-m ~/models/Qwen3-4B-Q8_0.gguf \
|
||
-ngl 99 \
|
||
-c 4096 \
|
||
--host 0.0.0.0 \
|
||
--port 8080
|
||
```
|
||
|
||
### Test with curl
|
||
|
||
```bash
|
||
curl http://localhost:8080/v1/chat/completions \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"model": "qwen3-4b",
|
||
"messages": [
|
||
{"role": "user", "content": "What is ROCm?"}
|
||
],
|
||
"max_tokens": 200,
|
||
"temperature": 0.7
|
||
}'
|
||
```
|
||
|
||
### Web UI
|
||
|
||
Open `http://localhost:8080` in a browser for the built-in chat UI.
|
||
|
||
---
|
||
|
||
## Performance Results
|
||
|
||
Benchmarked on AMD BC-250 with full GPU offload (`-ngl 99`):
|
||
|
||
| Metric | Value |
|
||
|----------------------|----------------|
|
||
| **Prompt Processing** | ~84–267 t/s |
|
||
| **Generation Speed** | ~55–57 t/s |
|
||
| **Context Size** | 2048–4096 |
|
||
| **GPU Offload** | All 36 layers |
|
||
|
||
> Prompt processing speed varies by prompt length (shorter prompts = higher t/s due to overhead ratio). Generation speed is consistently **~56-57 tokens/second**.
|
||
|
||
---
|
||
|
||
## VRAM / Memory Breakdown
|
||
|
||
From `llama_memory_breakdown_print` at exit (context size 2048):
|
||
|
||
| Location | Total | Free | Model | Context | Compute |
|
||
|------------------|---------|--------|--------|---------|---------|
|
||
| **ROCm0 (BC-250)** | 14750 MiB | 8382 MiB | 4076 MiB | 288 MiB | 301 MiB |
|
||
| **Host (CPU)** | — | — | 394 MiB | 0 MiB | 14 MiB |
|
||
|
||
- **Model weights**: ~4.0 GiB VRAM (matches the Q8_0 file size)
|
||
- **Remaining free VRAM**: ~8.4 GiB (plenty of room for larger context windows)
|
||
- **Host RAM**: ~394 MiB for metadata
|
||
|
||
With context size 4096, VRAM usage for context doubles to ~576 MiB, still well within the 14.4 GiB available.
|
||
|
||
---
|
||
|
||
## Useful Parameters Reference
|
||
|
||
| Parameter | Default | Description |
|
||
|-----------|---------|-------------|
|
||
| `-m` | — | Path to GGUF model file |
|
||
| `-ngl 99` | 0 | Number of layers to offload to GPU (99 = all) |
|
||
| `-c` | 4096 | Context window size (in tokens) |
|
||
| `-n` | -1 | Max tokens to generate (-1 = unlimited) |
|
||
| `-p` | — | Initial prompt text |
|
||
| `--temp` | 0.6 | Sampling temperature (lower = more deterministic) |
|
||
| `--top-k` | 20 | Top-K sampling |
|
||
| `--top-p` | 0.95 | Top-P (nucleus) sampling |
|
||
| `--no-display-prompt` | off | Don't echo the prompt in output |
|
||
| `--no-conversation` | off | Exit after first response (no interactive loop) |
|
||
| `-t` | auto | Number of CPU threads |
|
||
| `--host` | 127.0.0.1 | Server bind address |
|
||
| `--port` | 8080 | Server port |
|
||
|
||
---
|
||
|
||
## Troubleshooting
|
||
|
||
### CMake Error: "CMAKE_HIP_COMPILER is set to the hipcc wrapper"
|
||
|
||
**Cause:** CMake ≥ 4.x rejects the `hipcc` wrapper script.
|
||
**Fix:** Point to the ROCm clang directly:
|
||
```bash
|
||
-DCMAKE_HIP_COMPILER=/opt/rocm/lib/llvm/bin/clang++
|
||
```
|
||
|
||
### Build Error: "No rule to make target 'libserver-context.a'"
|
||
|
||
**Cause:** Race condition from running multiple `make` processes in the same build directory simultaneously.
|
||
**Fix:** Kill all builds, `rm -rf build`, and rebuild from scratch with a single `make -j$(nproc)`.
|
||
|
||
### "GGML_HIP:BOOL=OFF" in CMakeCache
|
||
|
||
**Cause:** ROCm dev libraries not found during cmake configuration.
|
||
**Fix:** Ensure `/opt/rocm/lib/libhipblas.so` and `/opt/rocm/lib/llvm/bin/clang++` exist. Re-run cmake.
|
||
|
||
### Model file is 0 bytes after download
|
||
|
||
**Cause:** Incorrect URL (case-sensitive) — Hugging Face returns 404.
|
||
**Fix:** The correct filename is `Qwen3-4B-Q8_0.gguf` (capital Q, capital B). Full URL:
|
||
```
|
||
https://huggingface.co/Qwen/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q8_0.gguf
|
||
```
|
||
|
||
### Slow GPU performance / "low-power state" warning
|
||
|
||
```
|
||
WARNING: AMD GPU device(s) is/are in a low-power state
|
||
```
|
||
The BC-250 may throttle. Force performance mode:
|
||
```bash
|
||
sudo sh -c 'echo high > /sys/class/drm/card1/device/power_dpm_force_performance_level'
|
||
```
|
||
|
||
### "Exception caught: map::at" in rocm-smi
|
||
|
||
Known BC-250 issue with rocm-smi power monitoring. Does not affect inference. Ignore safely.
|
||
|
||
---
|
||
|
||
## Notes & Tips
|
||
|
||
- **Qwen3 Thinking Mode**: By default, Qwen3 wraps responses in `[Start thinking]...[End thinking]` blocks showing its reasoning chain. This is a feature, not a bug. Use `--jinja` with the official template or `/no_think` to disable it.
|
||
|
||
- **Q8_0 Quantization**: This is the highest quality GGUF quantization (8-bit). The 4B parameter model at Q8_0 uses ~4 GiB VRAM, leaving plenty of headroom on the BC-250's ~14.4 GiB.
|
||
|
||
- **Full GPU Offload**: With `-ngl 99`, all 36 transformer layers are offloaded to the GPU. No CPU fallback needed for this model size.
|
||
|
||
- **Other Quant Options**: Qwen also provides Q4_K_M (~2.5 GiB) and Q4_0 (~2.3 GiB) variants on the same Hugging Face repo if you want to save VRAM for larger context windows.
|
||
|
||
- **Multiple Models**: The BC-250 has enough VRAM to potentially run larger models like Qwen3-8B at Q4_K_M quantization (~5 GiB).
|
||
|
||
---
|
||
|
||
## Quick Reference
|
||
|
||
```bash
|
||
# Build (one-time)
|
||
cd ~/llama.cpp && rm -rf build && mkdir build && cd build
|
||
cmake .. -DGGML_HIP=ON -DAMDGPU_TARGETS="gfx1010" -DCMAKE_BUILD_TYPE=Release \
|
||
-DCMAKE_HIP_COMPILER=/opt/rocm/lib/llvm/bin/clang++ -G "Unix Makefiles"
|
||
make -j$(nproc)
|
||
|
||
# Download model (one-time)
|
||
mkdir -p ~/models
|
||
aria2c -x 16 -s 16 -k 1M -d ~/models -o Qwen3-4B-Q8_0.gguf \
|
||
"https://huggingface.co/Qwen/Qwen3-4B-GGUF/resolve/main/Qwen3-4B-Q8_0.gguf"
|
||
|
||
# Run interactive chat
|
||
~/llama.cpp/build/bin/llama-cli -m ~/models/Qwen3-4B-Q8_0.gguf -ngl 99 -c 4096
|
||
|
||
# Run API server
|
||
~/llama.cpp/build/bin/llama-server -m ~/models/Qwen3-4B-Q8_0.gguf -ngl 99 -c 4096 --host 0.0.0.0 --port 8080
|
||
```
|
||
|
||
---
|
||
|
||
*Documentation generated on March 1, 2026. Based on llama.cpp build b8184, ROCm 7.2.0, AMD BC-250 (gfx1010).*
|