rocmforge - LLM inference on AMD GPUs (HIP) with a CPU fallback path.
- The project currently works for local Qwen GGUF runs, Gemma4 models, and custom
.rfmmodel architectures. - The GPU path is AMD-only and pure HIP. There is no CUDA or cross-vendor backend here.
- Recent optimization passes introduced features: GPU Decode Graph, F16 Embedding Support, TurboQuant KV Cache, and Pareto Synthesis (VideoMLA/AdaState/MPO + GPU SVD + MoE VRAM optimizations).
- Measured token generation speed for a 0.5B model (e.g., Qwen2.5-0.5B Q8_0) reaches ~340 tok/s on an AMD Radeon RX 7900 XT via the pre-compiled GPU Decode Graph path.
- Gemma4 12B Q4_0 achieves ~24 tok/s decode on AMD RX 7900 XT with hybrid attention support.
- Robust runtime safety rules dynamically select the fastest inference path based on model-profile routing.
- GPU Decode Graph: Captures the entire token generation execution sequence (including QKV projection, split, norms, attention, activations, and projection kernels) into a single HIP graph to bypass runtime host-to-device kernel launch overhead.
- F16 Embedding Support: High-performance half-precision (FP16) input embeddings.
- TurboQuant KV Cache: Ultra-low latency Key-Value cache management with automatic bounds and deadlock resolution.
- Pareto Synthesis: Hardware-aware combined optimization path featuring GPU SVD, MPO kernel compression, and mixture of experts (MoE) VRAM paging.
- Inference Path Router: Dynamically matches model traits to targeted hardware-optimized HIP fastpaths.
GPU compute path
- HIP / ROCm kernels, AMD-only — RDNA2 DP4A and RDNA3 WMMA matrix instructions
- GPU Decode Graph — the entire token-generation sequence (QKV projection, split, norms, attention, activations, output projection) captured into a single HIP graph to eliminate per-launch host→device overhead
- F16 (half-precision) input embeddings
- TurboQuant KV cache — low-latency paged KV management with automatic bounds and deadlock resolution
Pareto Synthesis — hardware-aware combined optimization path
- GPU SVD correction kernels for attention
- MPO (Matrix Product Operator) kernel compression
- Mixture-of-Experts (MoE) VRAM paging
- VideoMLA / AdaState routing variants
Quantization kernels (GPU) — Q4_0, Q4_K, Q6_K, Q8_0 (Q5_0 not implemented on GPU)
Inference Path Router — model-profile-driven selection across BatchedPrefill, DecodeStyle, SvdOptimized, and CpuFallback
CPU fallback — pure-Rust decode path when no GPU is available or the profile is unsafe
Model formats — GGUF (Qwen2.5, Gemma4) plus custom .rfm architectures; speculative decoding via --draft-model
Keyword index: AMD GPU inference · HIP · ROCm · LLM inference · GGUF · GPU decode graph · DP4A · WMMA · RDNA2 · RDNA3 · F16 embeddings · TurboQuant KV cache · Pareto Synthesis · GPU SVD · MPO compression · mixture of experts · MoE VRAM paging · Q4_0 · Q4_K · Q6_K · Q8_0 · inference path router · speculative decoding · CPU fallback · Rust
| Quantization | Status | Notes |
|---|---|---|
| Q4_0 | Supported | Optimized with DP4A (RDNA2) and WMMA (RDNA3) |
| Q4_K | Supported | Mixed quantization |
| Q6_K | Supported | Works with graph capture |
| Q8_0 | Supported | 8-bit quantization |
Note: Q5_0 is not currently implemented on GPU.
- Rust 1.81+
- ROCm/HIP toolkit (tested locally on ROCm 7.2)
- ROCm runtime libraries visible at execution time, for example via your ROCm environment setup so
libamdhip64.so.7resolves - A GGUF model file
- Current development and validation focus: Qwen2.5 GGUF models
cargo build --release
cargo build --release --features gpuGPU:
./target/release/rocmforge \
--model /path/to/model.gguf \
--prompt "Hello" \
--gpuCPU fallback:
./target/release/rocmforge \
--model /path/to/model.gguf \
--prompt "Hello"Supported CLI options (from --help):
| Option | Description |
|---|---|
--model <path> |
GGUF or RFM model path |
--prompt <text> |
Prompt text |
--gpu |
Use GPU backend |
--max-tokens N |
Max generated tokens (default: 256) |
--temperature F |
Sampling temperature (default: 1.0) |
--top-p F |
Nucleus sampling threshold (default: 0.9) |
--no-template |
Disable chat template |
--list-tensors |
Print tensors and exit |
--debug |
Print debug logits info |
--kv-dump <path> |
Dump post-prefill KV cache to binary file (research tool) |
--prefill-only-validate |
Run prefill only, exit 0 on valid logits, 1 on NaN/Inf |
--draft-model <path> |
Draft model path for speculative decoding |
--speculative-tokens N |
Number of speculative tokens per step (default: 4) |
Note: --device is not a valid flag in the current binary.
ROCmForge uses a model-profile-driven router to select the optimal inference path:
[Router] Model profile: arch=qwen2, quant=Q4_0
[Router] Selected path: BatchedPrefill(max_seq=512)
The router inspects loaded model metadata (quantization type, SVD/MPO/sparse flags, architecture) and selects from:
| Path | When Selected | Description |
|---|---|---|
BatchedPrefill |
Q4_0 model, prompt 2-512 tokens | Fastest path, processes all prompt tokens in one kernel launch |
DecodeStyle |
Mixed quant, single token, or unsafe model | Token-by-token processing, universal fallback |
SvdOptimized |
SVD model + experimental flag enabled | Uses SVD correction kernels for attention |
CpuFallback |
Incompatible or unsafe configuration | Falls back to CPU inference |
Safety rules:
- Sparse/MPO models always route to
DecodeStyle(experimental kernels are opt-in) - MoE/SSM models route to
DecodeStyle(no batched kernels yet) - SVD models only use
SvdOptimizedwhenROCMFORGE_ENABLE_EXPERIMENTAL_GPU_KERNELS=1
Engineering note:
- Inference-path, converter, router, or kernel-dispatch changes should follow the repo checklist in
docs/inference-change-checklist.mdso GGUF and.rfmpaths are audited together.
-
ROCMFORGE_GPU_SAFE_MODE=1- Forces conservative mode for this process.
- Disables decode graph and experimental fastpaths.
-
ROCMFORGE_ENABLE_DECODE_GRAPH=1- Enables decode graph replay.
-
ROCMFORGE_ENABLE_EXPERIMENTAL_Q8_ACTIVATION_FASTPATH=1- Enables the Q8 activation fastpath used in decode kernels.
-
ROCMFORGE_DESKTOP_VRAM_GB=<float>- Configures VRAM reserved for desktop/compositor (default: 4.0).
- Lower for single-monitor setups (2.0), higher for multi-monitor 4K (6.0+).
- Prevents inference from stealing memory needed by the display.
-
ROCMFORGE_GPU_LOCK_TIMEOUT=<seconds>- Configures how long GPU tests wait for the shared cross-process GPU lock.
- Cargo-launched tests default to
30, so separatecargo testruns queue instead of colliding.
-
ROCMFORGE_ENABLE_EXPERIMENTAL_GPU_KERNELS=1- Enables sparse CSR and MPO kernels (potentially unsafe on display-attached GPUs).
- Only use when testing compressed
.rfmmodels with sparse/MPO weights.
-
ROCMFORGE_Q4_0_Q8_DP4A=1- Enables the DP4A int8 dot-product path for Q4_0 × Q8_0 kernels (GEMV, gate-up, SwiGLU) on supported GPUs.
- Software fallback is used automatically on architectures without DP4A.
-
ROCMFORGE_Q4_0_Q8_SINGLE_ROW=1- Forces the single-row high-occupancy launch configuration for Q4_0 × Q8_0 kernels.
- Useful on RDNA3 wave32 hardware when occupancy matters more than column parallelism.
-
ROCMFORGE_OBSERVE_DECODE_GRAPH_HEALTH=1- Enables atomic telemetry for HIP decode graph capture/replay/cache/fallback events.
- Query the live snapshot via
GpuDecodeGraphHealthSnapshotinsrc/gpu/decode_graph_health.rs.
Conservative run:
ROCMFORGE_GPU_SAFE_MODE=1 ./target/release/rocmforge --model /path/to/model.gguf --prompt "Hello" --gpuTuned run:
ROCMFORGE_ENABLE_DECODE_GRAPH=1 \
ROCMFORGE_ENABLE_EXPERIMENTAL_Q8_ACTIVATION_FASTPATH=1 \
./target/release/rocmforge --model /path/to/model.gguf --prompt "Hello" --gpu7B tuned example used during current development:
ROCMFORGE_ENABLE_DECODE_GRAPH=1 \
ROCMFORGE_ENABLE_EXPERIMENTAL_Q8_ACTIVATION_FASTPATH=1 \
./target/release/rocmforge \
--gpu \
--model /home/feanor/Projects/Memoria/models/Qwen2.5-7B-Instruct-Q4_0-Pure.gguf \
--prompt Hello --no-template --top-p 1.0 --temperature 0.0 --max-tokens 64- Gemma4 E2B GPU crash: Gemma4 E2B (2.3B effective parameters, hybrid attention with mixed head dimensions) loads successfully with optimized PLE VRAM allocation (4.3GB, 35× improvement) but crashes during decode with GPU memory access faults. Root cause: flash attention kernel assumes uniform cache stride incompatible with hybrid attention's mixed head_dim (256/512 across layers). Use Gemma4 12B or CPU fallback for E2B models until specialized kernel support is implemented.
Machine path references in this section are from local runs on April 10, 2026.
- Qwen2.5-0.5B-Instruct Q4_0 (graph path, benchmark harness)
ROCMFORGE_RUN_REAL_MODEL_GPU_TESTS=1 \
ROCMFORGE_BENCH_RUNS=10 ROCMFORGE_BENCH_WARMUP=1 ROCMFORGE_BENCH_TOKENS=128 \
cargo test --release --features gpu --test gpu_decode_real \
test_gpu_greedy_decode_benchmark_real_model_multi_run \
-- --ignored --nocapture --test-threads=1cargo test already inherits RUST_TEST_THREADS=1, ROCMFORGE_GPU_LOCK_TIMEOUT=30, and ROCMFORGE_DESKTOP_VRAM_GB=4.0 from .cargo/config.toml. The explicit --test-threads=1 in examples is retained for clarity, but sequential execution and conservative VRAM gating are the default.
- Prefill average:
408.7 tok/s - Decode average:
526.8 tok/s
- Qwen2.5-7B-Instruct Q4_0 (
Qwen2.5-7B-Instruct-Q4_0-Pure.gguf, CLI, 3 runs)
ROCMFORGE_ENABLE_DECODE_GRAPH=1 \
ROCMFORGE_ENABLE_EXPERIMENTAL_Q8_ACTIVATION_FASTPATH=1 \
./target/release/rocmforge \
--gpu \
--model /home/feanor/Projects/Memoria/models/Qwen2.5-7B-Instruct-Q4_0-Pure.gguf \
--prompt Hello --no-template --top-p 1.0 --temperature 0.0 --max-tokens 64- Prefill:
31.5 / 32.4 / 32.0 tok/s(avg32.0 tok/s) - Decode:
106.7 / 106.7 / 106.5 tok/s(avg106.6 tok/s)
- Qwen2.5-0.5B-Instruct Q4_0 with decode graph disabled (for comparison)
ROCMFORGE_RUN_REAL_MODEL_GPU_TESTS=1 \
ROCMFORGE_DISABLE_DECODE_GRAPH=1 \
ROCMFORGE_BENCH_RUNS=5 ROCMFORGE_BENCH_WARMUP=1 ROCMFORGE_BENCH_TOKENS=128 \
cargo test --release --features gpu --test gpu_decode_real \
test_gpu_greedy_decode_benchmark_real_model_multi_run \
-- --ignored --nocapture --test-threads=1- Decode average:
486.0 tok/s
- Qwen2.5-0.5B-Instruct Q8_0 (
qwen2.5-0.5b-instruct-q8_0.rfm/.gguf, CLI, greedy--top-p 1.0)
./target/release/rocmforge \
--model /path/to/qwen2.5-0.5b-instruct-q8_0.rfm \
--prompt "Hello" \
--gpu \
--top-p 1.0 \
--max-tokens 128- Prefill speed:
151.8 tok/s - Decode speed (baseline / graph capture disabled or invalidated):
87.7 tok/s - Decode speed (optimized / graph capture active):
340.4 tok/s - Reference Native
llama.cppspeed:239.2 tok/s(ROCmForge is ~42% faster with decode graph replay active)
ROCmForge automatically detects your GPU architecture at runtime to enable hardware-specific optimizations:
The GpuFeatures module (src/gpu/features.rs) detects:
- GPU Architecture: Maps device names to architecture strings (gfx1010/gfx1030/gfx1100)
- DP4A Support:
v_dot4_i32_i8instruction for 4-way int8 multiply-accumulate (RDNA2+) - WMMA Support: Wave matrix multiply for 16×16×16 matrix operations (RDNA3+)
- dot2 Support:
v_dot2_f32_f16instruction for FP16 operations
| Architecture | GPUs | DP4A | WMMA | dot2 |
|---|---|---|---|---|
| RDNA1 (gfx1010) | RX 5700 XT | ❌ | ❌ | ❌ |
| RDNA1 (gfx1013) | BC-250 APU | ❌ | ❌ | ❌ |
| RDNA2 (gfx1030) | RX 6900 XT, RX 6800 XT | ✅ | ❌ | ✅ |
| RDNA3 (gfx1100) | RX 7900 XT, RX 7800 XT | ✅ | ✅ | ✅ |
-
Packed 32-bit Loads (
hip_kernels/quant/q4_0_gemv.hip)- Load 16 bytes as 4×uint32_t instead of 16×uint8_t
- 4× fewer load instructions, better memory coalescing
- Applied to Q4_0 GEMV kernels
-
DP4A Q4_0/Q8_0 Decode Kernels (
hip_kernels/quant/common.hip,q4_0_gemv.hip,q4_0_fused_q8.hip)- Uses
__ockl_sdot4for 4-way signed int8 multiply-accumulate on gfx1030/gfx1100+ - Integrated into GEMV, gate-up, and SwiGLU dispatch paths
- Enabled via
ROCMFORGE_Q4_0_Q8_DP4A=1 - Software fallback on architectures without DP4A
- Bit-level nibble extraction matches the scalar path exactly
- Uses
-
High-Occupancy Multi-Head Prefill Attention (
hip_kernels/attention.hip)- Replaced the single-head, thread-serial prefill kernel with a
dim3(seq_len, num_heads)cooperative kernel - Each (position, head) block scans its causal key range and reduces over
head_dim - Preserves KV-lora reconstruction and causal mask semantics
- Replaced the single-head, thread-serial prefill kernel with a
-
Decode Graph Health Telemetry (
src/gpu/decode_graph_health.rs)- Non-intrusive atomic counters for graph captures, replays, cache hits/misses, updates, fallbacks, and runtime disables
- Enable with
ROCMFORGE_OBSERVE_DECODE_GRAPH_HEALTH=1
-
Multi-row GEMV (
hip_kernels/quant/q4_0_gemv.hip)- Processes 4 output columns per wave for better occupancy
- Uses packed loads for dequantization
- Shared memory input tiling for large rows
Implemented:
- ✅ GPU architecture and feature detection
- ✅ Performance profiling infrastructure (
src/gpu/profile.rs) - ✅ Packed load optimization for Q4_0 GEMV
- ✅ DP4A Q4_0/Q8_0 kernels integrated into decode/prefill pipeline
- ✅ High-occupancy multi-head prefill attention kernel
- ✅ Decode graph health observability
- ✅ Kernel correctness tests (
tests/integration_gpu.rs,tests/gpu_q4_0_q8_dispatch.rs) - ✅ Performance benchmarks (
benches/kernel_performance.rs)
Not Yet Implemented:
- ⏳ WMMA-optimized kernel variant for RDNA3+
- ⏳ Automatic kernel dispatch based on detected features
Measured and projected improvements on Qwen2.5-0.5B Q4_0:
| GPU | Architecture | Baseline | Expected | Speedup |
|---|---|---|---|---|
| RX 5700 XT | RDNA1 (gfx1010) | ~150 tok/s | 180-200 | 1.2-1.3× |
| RX 6900 XT | RDNA2 (gfx1030) | ~150 tok/s | 250-300 | 1.7-2.0× |
| RX 7900 XT | RDNA3 (gfx1100) | ~150 tok/s | 250-350 | 1.7-2.3× |
| BC-250 APU | RDNA1 (gfx1013) | ~150 tok/s | 200-220 | 1.3-1.4× |
Note: DP4A and multi-head prefill paths are now integrated and verified against CPU oracles. Absolute speedups depend on batch size and model width; run the real-model harness for your GPU.
DP4A kernel uses the same Q4_0/Q8_0 quantization layout as the scalar path:
- Low nibble holds element
i, high nibble holds elementi+16, zero-point bias-8 - Bit-level packing via unsigned nibble extraction avoids signed-shift overflow
- Verified numerically against CPU and scalar GPU references
Run DP4A correctness tests:
ROCMFORGE_Q4_0_Q8_DP4A=1 \
cargo test --features gpu --release --test gpu_q4_0_q8_dispatch -- --test-threads=1Benchmark DP4A vs scalar baseline decode (merge 7B split shards first, see MANUAL):
ROCMFORGE_RUN_GPU_BENCHES=1 \
ROCMFORGE_DISABLE_DECODE_GRAPH=1 \
ROCMFORGE_BENCH_MODEL=/home/feanor/Projects/models/qwen2.5-7b-instruct-q4_0.gguf \
ROCMFORGE_BENCH_TOKENS=64 \
cargo bench --features gpu --bench gpu_decode_dp4a_vs_baselineMeasured on RX 7900 XT with a merged Qwen2.5-7B-Instruct-Q4_0 model:
- Baseline scalar fastpath: ~50 tok/s decode
- DP4A Q4_0/Q8_0: ~79 tok/s decode
- Speedup: ~1.57×
Run multi-head prefill correctness:
cargo test --features gpu --release --test integration_gpu \
test_flash_attn_prefill_strided_kernel_correctness \
-- --test-threads=1Run decode graph health unit tests:
cargo test --features gpu --release --lib decode_graph_health -- --test-threads=1Run performance benchmarks:
cargo bench --bench kernel_performance- Main manual: MANUAL.md
- Project changelog: CHANGELOG.md
- Developer instructions: AGENTS.md
- License terms: LICENSE
- The main value today is that it is a small pure-HIP codebase that AMD developers can inspect, build, profile, and compare against other runtimes.
- VRAM safety first: The inference engine now respects your GPU by checking available VRAM before allocating, reserving headroom for the desktop compositor, and gating experimental kernels behind explicit opt-in flags.
- Model-aware routing: The router automatically selects the best inference path based on model metadata — no manual tuning needed for standard models.
- Expect more work on decode throughput, launch tuning, and profiling workflow before calling it broadly production-ready.
GPL-3.0. See LICENSE.