SERIES Part 1 Part 2 Part 3 Part 4 Part 5 Part 6 Part 7 Part 8 Part 9 Part 10
AMD Field AI Enthusiast · by Pradeep Nallimelli · Part 1 of 10+ · May 2026

Meet the Radeon AI PRO R9700.
A 32 GB workstation card built for local AI.

Most teams do not need a data-center GPU. They need one good workstation card on a developer's bench. This series tests one — across vLLM, llama.cpp, dense models, Mixture-of-Experts models, and 16-way concurrency — and reports what a small AMD AI stack actually does in practice. Part one is the bring-up story, with live system snapshots from the bench.

The card32 GB
GDDR6 on a 256-bit bus · 640 GB/s · RDNA 4 (Navi 48), 64 CUs, 128 second-gen AI accelerators.
The platformEPYC
Genoa-X host (96 cores), Ubuntu 24.04, ROCm 7.2.1, vLLM 0.16 in a vendor Docker container.
The first run7.5
tokens / sec, dense 14B AWQ model, single-stream. Functional on the first try — and informative.
The card

What is the R9700, exactly.

The Radeon AI PRO R9700 is a workstation-class GPU built on AMD RDNA 4 (Navi 48, TSMC 4 nm). It targets local AI development — the workload where you want to keep model weights and data on the desk rather than in a cloud account.

ElementValue
ArchitectureAMD RDNA 4 · Navi 48 · gfx1201
Compute units64 CUs · 4 shader engines · 2 SIMDs/CU · wavefront 32 · 4,096 stream processors
AI accelerators128 (second generation, WMMA matrix instructions)
Memory32 GB GDDR6 · 256-bit · 640 GB/s · 64 MB Infinity Cache
Matrix math (dense)FP16 191 TFLOPS · INT8 383 TOPS · INT4 766 TOPS · FP8 383 TFLOPS
Board power300 W TBP · dual-slot blower · PCIe 5.0 · 4× DP 2.1a
List priceFrom $1,299 USD (board-partner cards from ASRock, ASUS, GIGABYTE, PowerColor, Sapphire, XFX)
Why 32 GB matters. It is the smallest VRAM number that comfortably holds a 30B-class model at 4-bit quantization with meaningful KV cache for several concurrent users. Below this you trade either model quality or concurrency. The R9700 is sized exactly for the "small agent fleet" workload.
First contact

The card the OS sees — lspci and rocminfo.

Before any model runs, you want to confirm the host actually agrees the card is there, on PCIe Gen 5 x16, with the amdgpu kernel driver bound. Two snapshots from the bench — first what the PCI bus says, then what the ROCm runtime says.

$ lspci -s 83:00.0 -vvnn
83:00.0 VGA compatible controller [0300]: Advanced Micro Devices, Inc. [AMD/ATI] Device [1002:7551] (rev c0)
        Subsystem: XFX Limited Device [1eae:9801]
        Control: I/O+ Mem+ BusMaster+ ...
        Region 0: Memory at c0000000 (64-bit, prefetchable) [size=256M]
        NUMA node: 0
        IOMMU group: 31
        Kernel driver in use: amdgpu
        Kernel modules: amdgpu
$ rocminfo | grep -A 6 gfx1201
  Name:                    gfx1201
  Uuid:                    GPU-b0a58d8599315bb9
  Marketing Name:          AMD Radeon AI PRO R9700
  Vendor Name:             AMD
  Compute Unit:            64
  Shader Engines:          4
  Wavefront Size:          32
Reading the snapshot. Device ID 1002:7551 is RDNA 4 Navi 48; the subsystem 1eae:9801 identifies this particular sample as an XFX board partner card. amdgpu driver bound, IOMMU group clean, on the right NUMA node. ROCm 7.2.1 sees it as gfx1201 — the target architecture vLLM and llama.cpp will compile for.
The setup

vLLM came up cleanly on the first try.

The runtime is the open-source vLLM project, pulled from a vendor-published Docker image that pairs vLLM 0.16 with the matching ROCm compute stack. Everything in this series uses publicly available containers and publicly available models from Hugging Face. No proprietary builds.

docker run -d --name vllm-server \
  --device=/dev/kfd --device=/dev/dri \
  --group-add video --ipc=host --shm-size=16g --network=host \
  rocm/vllm-dev:rocm7.2.1_navi_ubuntu24.04_py3.12_pytorch_2.9_vllm_0.16.0 \
  vllm serve <your-AWQ-model> \
    --dtype float16 --max-model-len 32768 \
    --gpu-memory-utilization 0.92 \
    --enable-prefix-caching \
    --enable-auto-tool-choice --tool-call-parser hermes \
    --served-model-name qwen3-moe --host 0.0.0.0 --port 8000

Every flag earns its place. --dtype float16 matches the activation precision the AWQ kernels expect. --max-model-len 32768 reserves attention positions for a 32K context. --gpu-memory-utilization 0.92 tells vLLM to claim 92% of VRAM for its weights + KV cache pool. --enable-prefix-caching reuses shared prompt prefixes across requests — meaningful for agent loops. --enable-auto-tool-choice --tool-call-parser hermes turns on OpenAI-compatible tool calling. A few minutes later, the OpenAI-compatible chat endpoint was live on port 8000.

The container ecosystem has matured. Bring-up on a workstation card is the same one-liner as bring-up on a data-center card. No source build. No kernel patches. No vendor-specific glue beyond the Docker image tag.
Inside the engine boot

What vLLM did with the card's 32 GB.

The interesting lines in the vLLM startup log are not the banner — they are the memory math. With the flags above, vLLM logs exactly how it carves the card up.

(EngineCore_DP0) INFO core.py:97  Initializing a V1 LLM engine
                          model='cyankiwi/Qwen3-30B-A3B-Instruct-2507-AWQ-4bit'
                          dtype=torch.float16, max_seq_len=32768
                          quantization=compressed-tensors
                          enable_prefix_caching=True
                          enable_chunked_prefill=True
                          cudagraph_mode=FULL_AND_PIECEWISE
(EngineCore_DP0) INFO gpu_model_runner.py:4221  Model loading took 17.54 GiB memory and 15.02 seconds
(EngineCore_DP0) INFO gpu_worker.py:373         Available KV cache memory: 7.71 GiB
(EngineCore_DP0) INFO kv_cache_utils.py:1307    GPU KV cache size: 84,224 tokens
(EngineCore_DP0) INFO kv_cache_utils.py:1312    Maximum concurrency for 32,768 tokens/req: 2.57x
(EngineCore_DP0) INFO gpu_model_runner.py:5246  Graph capturing finished in 13 secs, took 0.21 GiB
(EngineCore_DP0) INFO core.py:278               init engine (profile, create kv cache, warmup) took 59.66 seconds
Model weights17.54
GiB held in VRAM (4-bit AWQ weights + tokenizer + small overhead).
KV cache pool7.71
GiB pre-allocated up front. Holds 84,224 tokens of attention state ready for whichever requests arrive first.
CUDA graphs0.21
GiB. vLLM pre-captures graphs for batch sizes 1, 2, 4, 8, 16, 24 … 512 so each step skips Python overhead.
The "VRAM is 100% full" question

Idle versus under load — same memory, different work.

Once vLLM is serving, rocm-smi will say the card is roughly 92% full from the moment it boots — long before any inference request arrives. This is the most common "is something wrong?" question from someone watching the card for the first time, so it deserves a direct answer. Two snapshots from the same card, ten seconds apart.

Idle — no requests in flight
GPU[0] Temp edge       31 °C
GPU[0] Temp junction   33 °C
GPU[0] Power           15 W
GPU[0] Engine clock     41 MHz
GPU[0] Memory clock     96 MHz
GPU[0] GPU use          3 %
GPU[0] VRAM used    27.61 GiB / 29.86 GiB
                   (92 % — the KV pool)
Under load — 16 concurrent requests
GPU[0] Temp edge       41 °C
GPU[0] Temp junction   69 °C
GPU[0] Power          339 W
GPU[0] Engine clock   3198 MHz
GPU[0] Memory clock   1258 MHz
GPU[0] GPU use        100 %
GPU[0] VRAM used    27.67 GiB / 29.86 GiB
                   (unchanged — KV pool reused)
The answer: --gpu-memory-utilization 0.92 tells vLLM to claim 92% of the card's VRAM at startup and hold it for the lifetime of the process — model weights plus a pre-sized KV cache pool. Reactive allocation per request would cost milliseconds of latency on every token; pre-allocation costs nothing at runtime. So the card looks "100% full" the second the engine warms up, because the cache slots are sitting there ready, not because anything is leaking. The active-request signal lives in engine clock (41 → 3,198 MHz), memory clock (96 → 1,258 MHz), power (15 → 339 W), and "GPU use" (3 → 100%) — not in VRAM-used.
The first benchmark

7.5 tokens per second. Then the silicon told us what it was waiting for.

One user, distinct prompt, 512 output tokens, temperature 0 — the simplest possible benchmark on a dense 14B AWQ 4-bit model. Result: 7.5 tokens per second. Functional. Useful for coding-assistant work. But the card looked like it should be doing more.

The diagnostic experiment was small. We tried a model that was roughly half the parameter count at the same quantization. Throughput roughly doubled. That is the textbook signature of a memory-bandwidth-bound decode loop. At batch size 1, the GPU spends most of its time pulling weights from GDDR6, and the compute units sit waiting. Throughput is essentially memory bandwidth ÷ model bytes per token.

Single-stream throughput scales inversely with model size — proof of bandwidth-bound decode

Source: Radeon AI PRO R9700 · vLLM 0.16 · AWQ 4-bit · single-stream chat completion · 2026-05-28
This is true on every GPU at batch 1, including the most expensive data-center cards. The difference is just how much bandwidth you have. The two ways out: add concurrent users so the bandwidth amortizes, or change the model so each output token reads fewer weights. Both lead into part two of the series.
What you can take away from part one

Three things to know before reading part two.

It works1×
A 14B-class model serves cleanly on a 32 GB R9700 with public containers and public models. Bring-up is a single Docker command.
Single-stream is a memory gameGDDR6
At batch 1, throughput is gated by VRAM bandwidth, not compute. Halving the model size doubles the tokens per second.
There are two ways forward2
Serve more users in parallel, or pick a model shape that reads fewer weights per token. Part two does both, and lands the headline 6.8× speedup of the series.
Next in the series. Part two — the Mixture-of-Experts breakthrough and the 16-user concurrency sweep. Same card. Same VRAM budget. A bigger model that runs 6.8× faster, and a per-user throughput curve that holds up at fleet scale.