Pull requests / #2060

#2060 Linux AMD: images on the GPU through Vulkan, on a chosen card or the integrated GPU (vision.device)

open · @ChangXiang-SCU · 0 comentarios · En GitHub

Setup & installServer & APIMulti-GPUAMD / HIPNVIDIA / CUDAModels & quantsDocumentationWindowsLinux

Descripción

## Title
Linux AMD: images on the GPU through Vulkan, on a chosen card or the integrated GPU (`vision.device`)

Issue: none. Related: #1768 (Windows AMD, Vulkan encoder in setup), #1521.

## Summary
On Linux with an AMD card, setup builds the image encoder for the CPU only. Built with ggml's Vulkan backend, the same encoder runs on a Radeon through Mesa's RADV driver, 20-30x faster. What was missing is a way to say **which GPU** it runs on. With two cards, mtmd takes the first discrete GPU in Vulkan's order, which can be the engine's own card. On a Ryzen APU it never picks the integrated GPU while a discrete one is present.

This PR adds that choice, plus the build option and the Linux docs:

- `strata-vision --device <GPU>` (with `--gpu`) takes a PCI address (`0000:03:00.0`, or `03:00.0`) or ggml's name for the device (`Vulkan1`, `CUDA0`), and hands it to mtmd as `mtmd_context_params.device`.
- `strata-vision --list-devices` prints the GPUs the build sees and exits.
- `"device"` in the config's `"vision"` section is passed as `--device`. It is a hand-edited key, and a setup run again keeps it.
- `STRATA_VISION_VULKAN` in `tools/vision`: the same two lines as #1768, so the two PRs merge in either order. I checked this with `git merge-tree` against #1768's head.
- `docs/AMD_HIP.md`: how to build and set it up on Linux by hand, with measurements. `docs/DETAILS.md`: the `"device"` key.

Without `"device"` / `--device` nothing changes. On the test PC the default picked the same card as before, and its embeddings were bit-identical to `--device 0000:03:00.0` and `--device Vulkan1`. The new stderr line naming the GPU is printed only with `--device`.

### Measured
**Setup**
- Ryzen 7 7840U (Radeon 780M), 64 GB RAM, 2x RX 6950 XT (gfx1030, 16 GB) on OCuLink.
- Ubuntu 26.04, kernel 7.0, Mesa 26.0.8 RADV.
- Engine: 0.1.42, IQ3_XXS, on the 6950 XT at `0000:06:00.0`.
- BF16 mmproj, one 1024x768 picture.
- Times are the encoder's own (`OK ... ms`), 3 runs after the warm-up.

`--list-devices` output on this PC:
```
Vulkan0    0000:6a:00.0  integrated   33054 MiB  AMD Radeon 780M Graphics (RADV PHOENIX)
Vulkan1    0000:03:00.0  discrete     16368 MiB  AMD Radeon RX 6950 XT (RADV NAVI21)
Vulkan2    0000:06:00.0  discrete     16368 MiB  AMD Radeon RX 6950 XT (RADV NAVI21)
```

| Encoder | 300 image tokens | 768 image tokens |
| --- | --- | --- |
| CPU, 8 threads (AVX-512 build) | 3.0-3.8 s | 11.0-11.2 s |
| RX 6950 XT, the other card (`"device": "0000:03:00.0"`) | 0.15 s | 0.36-0.37 s |
| Radeon 780M, integrated (`"device": "0000:6a:00.0"`) | 0.79-0.80 s | 2.11-2.12 s |
| RX 6950 XT, the engine's card, `--vram-reserve-mib 700` | 0.51-0.52 s | 3.0-3.5 s |
| RX 6950 XT, the engine's card, `--vram-reserve-mib 1300` | 0.15 s | 0.36 s |

- **Sharing the engine's card:** the encoder needs about 1 GB at 1,024 image tokens. With the default 700 MiB reserve it still runs, with no error, but 3-10x slower. With 1300 it runs at full speed, and the expert cache has 3,593 slots instead of 3,954 (5.86 instead of 6.45 GiB).
- **Accuracy vs the CPU encoder:** the per-token cosine is 0.9997 on average on both GPUs. The lowest single token is 0.953 (6950 XT) and 0.892 (780M). The two 6950 XT give bit-identical embeddings.
- **End to end through the server**, with `"device"` set in the config: the same correct answer (three shapes, their colours, the text `ZX-4096`), in 8.8 s on the 6950 XT, 10.7 s on the 780M, and 19.7 s on the CPU.

## What changed
- `tools/vision/strata_vision.cpp`:
  - `--device` and `--list-devices`.
  - An `ERR` line on stdout, as for the other start errors, when the GPU is not found or `--device` is given without `--gpu`.
  - One stderr line naming the chosen GPU (only with `--device`).
  - It uses only ggml's device API (`ggml_backend_dev_get_props().device_id`), so it is the same for every backend.
- `tools/vision/CMakeLists.txt`: the `STRATA_VISION_VULKAN` option (builds ggml-vulkan).
- `serve/server.py`: `Vision` passes `vision.device` as `--device`, only when it is set.
- `serve/test_server.py`: `--device` is passed only when set.
- `tools/test_setup_config.py`: a setup run again keeps `"device"`.
- `docs/AMD_HIP.md`: "Images on the GPU through Vulkan (Linux, by hand)", and the two lines that said images are CPU-only now link to it.
- `docs/DETAILS.md`: the `"device"` key, next to `"cuda_device"`.

`setup.py` is untouched; #1768 already adds `--vision gpu` for AMD there.

## How I checked
**Builds of `tools/vision`**
- CPU and Vulkan (Linux, GCC): on the PC above.
- CUDA 12.8, `sm_120`: on a 4x RTX 5090 Linux box.

**Runtime**
- Vulkan, `--device` by address and by name: on the 6950 XTs and the 780M, as measured above.
- CUDA:
  - `--list-devices` gives `CUDA0..3` with `0000:01:00.0`, `0000:02:00.0`, `0000:41:00.0` and `0000:85:00.0`.
  - `--device 01:00.0` and `--device CUDA3` select those cards.
  - With `CUDA_VISIBLE_DEVICES=2`, the card at `0000:41:00.0` becomes `CUDA0`. That renumbering is why the address is the stable name.
  - That box has no model files, so the CUDA run stopped at loading the model, after the device was chosen.
- CPU build: `--list-devices` says there is no GPU, and `--device` without `--gpu` ends with an `ERR` line. An unknown address ends with `ERR no GPU ... here`.

**Tests**
- On `main` + this PR: `python -m unittest serve.test_server` (297), `tools/test_setup_config.py` (15) and `tools/test_setup_amd.py` (36) pass.
- The same changes on the 0.1.42 install pass `serve.test_server` (292).

## Extra Notes
- **Not tested:**
  - Windows. #1768 covers the Windows build. `--device` uses the same ggml calls there, but I have not run it.
  - Other Radeon generations.
  - A Vulkan encoder beside a multi-GPU layer split.
- **Possible follow-up**, not in this PR: setup could write `"device"` itself, choosing a card the engine does not use or the integrated GPU, and raise the reserve when it has to share.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_01JokSyf43q6Br7d5XnWwCgN

En el sitio

Enlaces a install, modelos, releases.