Skip to content

Commit c2282b2

Browse files
authored
fix: ROCm setup for Linux AMD GPUs (#817)
* Fix ROCm setup for Linux AMD GPUs - Ensure Docker ROCm builds resolve PyTorch packages from the ROCm wheel index so later dependency installs do not replace them with CUDA wheels. - Move ROCm device group handling to a runtime entrypoint that joins the groups owning /dev/kfd and /dev/dri, avoiding distro-specific render/video GID defaults. - Leave HSA_OVERRIDE_GFX_VERSION unset by default in the ROCm compose overlay so newer RDNA GPUs can use native ROCm detection. - Add Linux GPU detection to the Unix setup recipe so AMD systems install ROCm torch wheels and NVIDIA systems install CUDA wheels before backend dependencies. * docs(changelog): add Linux ROCm setup entry * fix(setup): pin ROCm torch wheels and prefer NVIDIA over amdgpu - Install torch/torchaudio from the ROCm index only, before the pooled requirements install, so a plain PyPI (CUDA) wheel can't outrank +rocm - Detect NVIDIA before AMD and gate ROCm on /dev/kfd, so hybrid AMD+NVIDIA hosts get CUDA instead of ROCm
1 parent cabef1b commit c2282b2

5 files changed

Lines changed: 66 additions & 71 deletions

File tree

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,17 @@
55

66
# Changelog
77

8+
## [Unreleased]
9+
10+
### Linux
11+
12+
- **ROCm setup works on Linux AMD systems.** Docker ROCm builds now keep PyTorch
13+
on the ROCm wheel index during dependency installation, so later installs do
14+
not replace it with CUDA wheels. The ROCm compose overlay no longer assumes
15+
Ubuntu render/video group IDs; the container joins the groups that own the GPU
16+
device nodes at startup. Native Linux setup now picks ROCm wheels for AMD GPUs
17+
and CUDA wheels for NVIDIA GPUs before installing backend dependencies.
18+
819
## [0.5.0] - 2026-04-22
920

1021
**The Capture release.** Voicebox stops being just a voice-cloning studio and becomes a full AI voice studio. Hold a key anywhere on your machine, speak, release — the transcript lands in the focused text field. Flip the primitive around and any MCP-aware agent — Claude Code, Cursor, Spacebot — speaks back through an on-screen pill in one of your cloned voices. A local LLM sits between the two, so transcripts come out clean and voice profiles can carry a personality that reshapes what the agent says before it gets spoken.

Dockerfile

Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,16 @@ RUN pip install --no-cache-dir --upgrade pip
4545

4646
COPY backend/requirements.txt .
4747

48-
# ROCm version to pull PyTorch wheels for. Default is 6.3 (supports RDNA1/2/3).
49-
# Set ROCM_VERSION=7.2 for RDNA 4 (RX 9000 series) support.
48+
# ROCm wheel index. Default 6.3 (RDNA1/2/3); set ROCM_VERSION=7.2 for RDNA4.
5049
ARG ROCM_VERSION=6.3
5150

52-
# When building the ROCm variant, install the ROCm-enabled PyTorch wheels
53-
# first so that the subsequent requirements.txt install sees them as already
54-
# satisfying the torch/torchaudio constraints and leaves them in place.
55-
# The CPU path skips this step and installs torch from PyPI as before.
51+
# For ROCm, make the PyTorch ROCm index primary so every install below resolves
52+
# torch to ROCm wheels instead of the default CUDA build.
5653
RUN if [ "$PYTORCH_VARIANT" = "rocm" ]; then \
5754
pip install --no-cache-dir --prefix=/install \
58-
torch torchaudio \
59-
--index-url "https://download.pytorch.org/whl/rocm${ROCM_VERSION}"; \
55+
--index-url "https://download.pytorch.org/whl/rocm${ROCM_VERSION}" \
56+
torch torchaudio && \
57+
printf '[global]\nindex-url = https://download.pytorch.org/whl/rocm%s\nextra-index-url = https://pypi.org/simple\n' "$ROCM_VERSION" > /etc/pip.conf; \
6058
fi
6159

6260
RUN pip install --no-cache-dir --prefix=/install -r requirements.txt
@@ -69,37 +67,17 @@ RUN pip install --no-cache-dir --prefix=/install \
6967
# === Stage 3: Runtime ===
7068
FROM python:3.11-slim
7169

72-
# Re-declare ARG inside the stage (Docker scoping requirement).
73-
ARG PYTORCH_VARIANT=cpu
74-
75-
# ROCm device access requires the container user to belong to the render
76-
# and video groups. GIDs are parameterised to match the host; Ubuntu 22.04+
77-
# defaults are used here. Override via env vars (docker-compose.rocm.yml
78-
# passes them through automatically):
79-
# export RENDER_GID=$(getent group render | cut -d: -f3)
80-
# export VIDEO_GID=$(getent group video | cut -d: -f3)
81-
ARG RENDER_GID=992
82-
ARG VIDEO_GID=44
83-
RUN if [ "$PYTORCH_VARIANT" = "rocm" ]; then \
84-
groupadd -f -g ${RENDER_GID} render && \
85-
groupadd -f -g ${VIDEO_GID} video; \
86-
fi
87-
88-
# Create non-root user for security
70+
# Create non-root user; the entrypoint joins GPU device groups at runtime.
8971
RUN groupadd -r voicebox && \
9072
useradd -r -g voicebox -m -s /bin/bash voicebox
9173

92-
# ROCm: add voicebox user to render+video so it can open /dev/kfd and /dev/dri.
93-
RUN if [ "$PYTORCH_VARIANT" = "rocm" ]; then \
94-
usermod -aG render,video voicebox; \
95-
fi
96-
9774
WORKDIR /app
9875

99-
# Install only runtime system dependencies
76+
# Install only runtime system dependencies (gosu drops root in the entrypoint)
10077
RUN apt-get update && apt-get install -y --no-install-recommends \
10178
ffmpeg \
10279
curl \
80+
gosu \
10381
&& rm -rf /var/lib/apt/lists/*
10482

10583
# Copy installed Python packages from builder stage
@@ -115,15 +93,14 @@ COPY --from=frontend --chown=voicebox:voicebox /build/web/dist /app/frontend/
11593
RUN mkdir -p /app/data/generations /app/data/profiles /app/data/cache \
11694
&& chown -R voicebox:voicebox /app/data
11795

118-
# Switch to non-root user
119-
USER voicebox
120-
12196
# Expose the API port
12297
EXPOSE 17493
12398

12499
# Health check — auto-restart if the server hangs
125100
HEALTHCHECK --interval=30s --timeout=10s --retries=3 --start-period=60s \
126101
CMD curl -f http://localhost:17493/health || exit 1
127102

128-
# Start the FastAPI server
103+
# Entrypoint joins GPU groups then drops to the voicebox user
104+
COPY --chmod=755 scripts/rocm-entrypoint.sh /usr/local/bin/entrypoint.sh
105+
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
129106
CMD ["uvicorn", "backend.main:app", "--host", "0.0.0.0", "--port", "17493"]

docker-compose.rocm.yml

Lines changed: 8 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,36 @@
1+
---
12
# ROCm (AMD GPU) overlay for Voicebox
23
#
3-
# Usage:
44
# docker compose -f docker-compose.yml -f docker-compose.rocm.yml up --build
55
#
6-
# Prerequisites on the host:
7-
# 1. ROCm drivers installed — https://rocm.docs.amd.com/projects/install-on-linux
8-
# 2. Current user in the 'render' and 'video' groups:
9-
# sudo usermod -aG render,video $USER (then log out/in)
10-
#
11-
# If the render/video GIDs on your host differ from the Ubuntu 22.04 defaults
12-
# (render=992, video=44), export them before running compose so the build arg
13-
# and group_add values both stay in sync automatically:
14-
# export RENDER_GID=$(getent group render | cut -d: -f3)
15-
# export VIDEO_GID=$(getent group video | cut -d: -f3)
16-
# docker compose -f docker-compose.yml -f docker-compose.rocm.yml up --build
17-
#
18-
# ROCm version (ROCM_VERSION):
19-
# Default is 6.3 (supports RDNA1/2/3). For RDNA 4 (RX 9000 series) use 7.2:
20-
# export ROCM_VERSION=7.2
21-
# docker compose -f docker-compose.yml -f docker-compose.rocm.yml up --build
6+
# Requires ROCm drivers on the host:
7+
# https://rocm.docs.amd.com/projects/install-on-linux
8+
# RDNA4 (RX 9000): export ROCM_VERSION=7.2 (default 6.3 covers RDNA1-3).
229

2310
services:
2411
voicebox:
2512
build:
2613
context: .
2714
args:
2815
PYTORCH_VARIANT: rocm
29-
# These build args read from env vars so a single export covers both the
30-
# Dockerfile group creation and the runtime group_add below.
31-
RENDER_GID: ${RENDER_GID:-992}
32-
VIDEO_GID: ${VIDEO_GID:-44}
3316
ROCM_VERSION: ${ROCM_VERSION:-6.3}
3417

35-
# Pass the AMD GPU device nodes into the container.
36-
# /dev/kfd — ROCm compute interface (required for GPU inference)
37-
# /dev/dri — DRM render nodes (required for display/memory access)
3818
devices:
3919
- /dev/kfd
4020
- /dev/dri
4121

42-
# Grant access to the render and video groups so the non-root user
43-
# inside the container can open the GPU device nodes.
44-
# These reference the same env vars used in build.args above so a
45-
# single export keeps Dockerfile groups and runtime group_add in sync.
46-
group_add:
47-
- "${RENDER_GID:-992}" # render
48-
- "${VIDEO_GID:-44}" # video
49-
5022
environment:
5123
# HSA_OVERRIDE_GFX_VERSION forces the ROCm runtime to treat the GPU as a
5224
# specific GFX version when auto-detection fails or the GPU is newer than
5325
# the ROCm release. app.py sets 10.3.0 (RDNA2) by default; override here
5426
# for your GPU family:
55-
# RDNA4 / RX 9000 series: 12.0.0 (requires ROCM_VERSION=7.2)
27+
# RDNA4 / RX 9000 series: 12.0.0
28+
# (requires ROCM_VERSION=7.2)
5629
# RDNA3 / RX 7000 series / Strix Halo: 11.0.0
5730
# RDNA2 / RX 6000 series: 10.3.0
5831
# RDNA1 / RX 5000 series: 10.1.0
5932
# Vega / GCN5: 9.0.0
60-
- HSA_OVERRIDE_GFX_VERSION=11.0.0
33+
- HSA_OVERRIDE_GFX_VERSION=${HSA_OVERRIDE_GFX_VERSION:-}
6134

62-
# Tune the ROCm memory allocator to reduce fragmentation during
63-
# multi-engine inference (TTS + STT + LLM running concurrently).
35+
# Tune the ROCm memory allocator
6436
- PYTORCH_HIP_ALLOC_CONF=garbage_collection_threshold:0.8,max_split_size_mb:512

justfile

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,26 @@ setup-python:
4343
fi
4444
echo "Installing Python dependencies..."
4545
{{ pip }} install --upgrade pip -q
46+
if [ "$(uname)" = "Linux" ]; then
47+
torch_index=""
48+
if [ -e /proc/driver/nvidia/version ] || [ -d /sys/module/nvidia ]; then
49+
echo "Detected NVIDIA GPU — installing CUDA PyTorch..."
50+
torch_index="https://download.pytorch.org/whl/cu128"
51+
elif [ -e /dev/kfd ]; then
52+
if [ -n "${VOICEBOX_ROCM_VERSION:-}" ]; then
53+
rocm_ver="$VOICEBOX_ROCM_VERSION"
54+
elif lspci 2>/dev/null | grep -qi "Navi 4"; then
55+
rocm_ver=7.2
56+
else
57+
rocm_ver=6.3
58+
fi
59+
echo "Detected AMD GPU — installing ROCm PyTorch (rocm${rocm_ver})..."
60+
torch_index="https://download.pytorch.org/whl/rocm${rocm_ver}"
61+
fi
62+
if [ -n "$torch_index" ]; then
63+
{{ pip }} install torch torchaudio --index-url "$torch_index"
64+
fi
65+
fi
4666
{{ pip }} install -r {{ backend_dir }}/requirements.txt
4767
# Chatterbox pins numpy<1.26 / torch==2.6 which break on Python 3.12+
4868
{{ pip }} install --no-deps chatterbox-tts

scripts/rocm-entrypoint.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/sh
2+
set -e
3+
# Join whatever groups own the mounted GPU nodes so /dev/kfd and /dev/dri work
4+
# on any host (no RENDER_GID/VIDEO_GID needed), then drop to the app user.
5+
for dev in /dev/kfd /dev/dri/render*; do
6+
[ -e "$dev" ] || continue
7+
gid=$(stat -c %g "$dev")
8+
grp=$(getent group "$gid" | cut -d: -f1)
9+
[ -n "$grp" ] || {
10+
grp="gpu$gid"
11+
groupadd -g "$gid" "$grp"
12+
}
13+
usermod -aG "$grp" voicebox
14+
done
15+
exec gosu voicebox "$@"

0 commit comments

Comments
 (0)