diff --git a/Dockerfile b/Dockerfile index 980584d1..c7bb79e3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,15 @@ # ============================================================ -# Voicebox — Local TTS Server with Web UI (CPU) +# Voicebox — Local TTS Server with Web UI # 3-stage build: Frontend → Python deps → Runtime +# +# Build variants: +# CPU (default): docker compose up --build +# ROCm (AMD GPU): docker compose -f docker-compose.yml -f docker-compose.rocm.yml up --build # ============================================================ +# Top-level ARG so it is visible to all stages. +ARG PYTORCH_VARIANT=cpu + # === Stage 1: Build frontend === FROM oven/bun:1 AS frontend @@ -24,6 +31,9 @@ RUN cd web && bunx --bun vite build # === Stage 2: Build Python dependencies === FROM python:3.11-slim AS backend-builder +# Re-declare ARG inside the stage (Docker scoping requirement). +ARG PYTORCH_VARIANT=cpu + WORKDIR /build RUN apt-get update && apt-get install -y --no-install-recommends \ @@ -34,6 +44,21 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ RUN pip install --no-cache-dir --upgrade pip COPY backend/requirements.txt . + +# ROCm version to pull PyTorch wheels for. Default is 6.3 (supports RDNA1/2/3). +# Set ROCM_VERSION=7.2 for RDNA 4 (RX 9000 series) support. +ARG ROCM_VERSION=6.3 + +# When building the ROCm variant, install the ROCm-enabled PyTorch wheels +# first so that the subsequent requirements.txt install sees them as already +# satisfying the torch/torchaudio constraints and leaves them in place. +# The CPU path skips this step and installs torch from PyPI as before. +RUN if [ "$PYTORCH_VARIANT" = "rocm" ]; then \ + pip install --no-cache-dir --prefix=/install \ + torch torchaudio \ + --index-url "https://download.pytorch.org/whl/rocm${ROCM_VERSION}"; \ + fi + RUN pip install --no-cache-dir --prefix=/install -r requirements.txt RUN pip install --no-cache-dir --prefix=/install --no-deps chatterbox-tts RUN pip install --no-cache-dir --prefix=/install --no-deps hume-tada @@ -44,10 +69,31 @@ RUN pip install --no-cache-dir --prefix=/install \ # === Stage 3: Runtime === FROM python:3.11-slim +# Re-declare ARG inside the stage (Docker scoping requirement). +ARG PYTORCH_VARIANT=cpu + +# ROCm device access requires the container user to belong to the render +# and video groups. GIDs are parameterised to match the host; Ubuntu 22.04+ +# defaults are used here. Override via env vars (docker-compose.rocm.yml +# passes them through automatically): +# export RENDER_GID=$(getent group render | cut -d: -f3) +# export VIDEO_GID=$(getent group video | cut -d: -f3) +ARG RENDER_GID=992 +ARG VIDEO_GID=44 +RUN if [ "$PYTORCH_VARIANT" = "rocm" ]; then \ + groupadd -f -g ${RENDER_GID} render && \ + groupadd -f -g ${VIDEO_GID} video; \ + fi + # Create non-root user for security RUN groupadd -r voicebox && \ useradd -r -g voicebox -m -s /bin/bash voicebox +# ROCm: add voicebox user to render+video so it can open /dev/kfd and /dev/dri. +RUN if [ "$PYTORCH_VARIANT" = "rocm" ]; then \ + usermod -aG render,video voicebox; \ + fi + WORKDIR /app # Install only runtime system dependencies diff --git a/docker-compose.rocm.yml b/docker-compose.rocm.yml new file mode 100644 index 00000000..957c1d31 --- /dev/null +++ b/docker-compose.rocm.yml @@ -0,0 +1,64 @@ +# ROCm (AMD GPU) overlay for Voicebox +# +# Usage: +# docker compose -f docker-compose.yml -f docker-compose.rocm.yml up --build +# +# Prerequisites on the host: +# 1. ROCm drivers installed — https://rocm.docs.amd.com/projects/install-on-linux +# 2. Current user in the 'render' and 'video' groups: +# sudo usermod -aG render,video $USER (then log out/in) +# +# If the render/video GIDs on your host differ from the Ubuntu 22.04 defaults +# (render=992, video=44), export them before running compose so the build arg +# and group_add values both stay in sync automatically: +# export RENDER_GID=$(getent group render | cut -d: -f3) +# export VIDEO_GID=$(getent group video | cut -d: -f3) +# docker compose -f docker-compose.yml -f docker-compose.rocm.yml up --build +# +# ROCm version (ROCM_VERSION): +# Default is 6.3 (supports RDNA1/2/3). For RDNA 4 (RX 9000 series) use 7.2: +# export ROCM_VERSION=7.2 +# docker compose -f docker-compose.yml -f docker-compose.rocm.yml up --build + +services: + voicebox: + build: + context: . + args: + PYTORCH_VARIANT: rocm + # These build args read from env vars so a single export covers both the + # Dockerfile group creation and the runtime group_add below. + RENDER_GID: ${RENDER_GID:-992} + VIDEO_GID: ${VIDEO_GID:-44} + ROCM_VERSION: ${ROCM_VERSION:-6.3} + + # Pass the AMD GPU device nodes into the container. + # /dev/kfd — ROCm compute interface (required for GPU inference) + # /dev/dri — DRM render nodes (required for display/memory access) + devices: + - /dev/kfd + - /dev/dri + + # Grant access to the render and video groups so the non-root user + # inside the container can open the GPU device nodes. + # These reference the same env vars used in build.args above so a + # single export keeps Dockerfile groups and runtime group_add in sync. + group_add: + - "${RENDER_GID:-992}" # render + - "${VIDEO_GID:-44}" # video + + environment: + # HSA_OVERRIDE_GFX_VERSION forces the ROCm runtime to treat the GPU as a + # specific GFX version when auto-detection fails or the GPU is newer than + # the ROCm release. app.py sets 10.3.0 (RDNA2) by default; override here + # for your GPU family: + # RDNA4 / RX 9000 series: 12.0.0 (requires ROCM_VERSION=7.2) + # RDNA3 / RX 7000 series / Strix Halo: 11.0.0 + # RDNA2 / RX 6000 series: 10.3.0 + # RDNA1 / RX 5000 series: 10.1.0 + # Vega / GCN5: 9.0.0 + - HSA_OVERRIDE_GFX_VERSION=11.0.0 + + # Tune the ROCm memory allocator to reduce fragmentation during + # multi-engine inference (TTS + STT + LLM running concurrently). + - PYTORCH_HIP_ALLOC_CONF=garbage_collection_threshold:0.8,max_split_size_mb:512 diff --git a/docker-compose.yml b/docker-compose.yml index 0e49d526..2c85fb61 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,7 @@ +# Voicebox — CPU build (default) +# For AMD ROCm GPU acceleration use the overlay: +# docker compose -f docker-compose.yml -f docker-compose.rocm.yml up --build + services: voicebox: build: .