|
| 1 | +# Docker Support for VoxCPM Training WebUI |
| 2 | + |
| 3 | +Run the VoxCPM LoRA fine-tuning WebUI in a Docker container with full GPU support and nginx reverse proxy. |
| 4 | + |
| 5 | +## Prerequisites |
| 6 | + |
| 7 | +- Docker Engine 19.03+ with [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html) |
| 8 | +- NVIDIA GPU with CUDA 12.4+ compatible drivers |
| 9 | +- At least 16 GB GPU VRAM (24 GB+ recommended for larger models) |
| 10 | + |
| 11 | +## Quick Start |
| 12 | + |
| 13 | +```bash |
| 14 | +# From the project root directory: |
| 15 | +docker compose -f docker/docker-compose.yml up --build |
| 16 | +``` |
| 17 | + |
| 18 | +This starts: |
| 19 | +- **training-webui** — the Gradio-based training interface on port 7860 |
| 20 | +- **nginx** — reverse proxy serving the WebUI at `http://localhost/webui/` |
| 21 | + |
| 22 | +Access the WebUI at **http://localhost/webui/**. |
| 23 | + |
| 24 | +## Volume Mounts |
| 25 | + |
| 26 | +The compose file maps host directories to container paths. Create these directories at the project root before starting: |
| 27 | + |
| 28 | +``` |
| 29 | +VoxCPM/ |
| 30 | +├── docker/ |
| 31 | +│ ├── docker-compose.yml |
| 32 | +│ ├── Dockerfile |
| 33 | +│ └── nginx.conf |
| 34 | +├── models/ ← Pretrained model weights (or auto-downloaded via HF) |
| 35 | +│ ├── openbmb__VoxCPM2/ |
| 36 | +│ └── openbmb__VoxCPM1.5/ |
| 37 | +├── data/ ← Training manifests + audio files |
| 38 | +│ ├── train.jsonl |
| 39 | +│ ├── val.jsonl (optional) |
| 40 | +│ └── audio/ |
| 41 | +│ ├── speaker1_001.wav |
| 42 | +│ └── ... |
| 43 | +├── lora/ ← LoRA training output (created automatically) |
| 44 | +│ └── my-voice-2024/ |
| 45 | +│ ├── checkpoints/ |
| 46 | +│ ├── logs/ |
| 47 | +│ └── train_config.yaml |
| 48 | +└── output/ ← Additional training artifacts |
| 49 | +``` |
| 50 | + |
| 51 | +### Mount Reference |
| 52 | + |
| 53 | +| Host Path | Container Path | Purpose | |
| 54 | +|-----------|---------------|---------| |
| 55 | +| `./models/` | `/app/models` | Pretrained model weights and HF cache (`HF_HOME`). Pre-populate with model dirs (e.g., `openbmb__VoxCPM2/`) or leave empty — models auto-download on first run and persist here. | |
| 56 | +| `./data/` | `/app/data` | Training data. Put JSONL manifests and audio files here. In the WebUI, reference paths as `/app/data/train.jsonl`. | |
| 57 | +| `./lora/` | `/app/lora` | LoRA checkpoint output. After training, find results in `lora/<run-name>/checkpoints/`. Also used to resume training from existing checkpoints. | |
| 58 | +| `./output/` | `/app/output` | Miscellaneous training artifacts. | |
| 59 | + |
| 60 | +### Training Data Format |
| 61 | + |
| 62 | +The train manifest is a JSONL file where each line references an audio file: |
| 63 | + |
| 64 | +```json |
| 65 | +{"audio_path": "/app/data/audio/speaker1_001.wav", "text": "Hello world", "speaker": "speaker1"} |
| 66 | +``` |
| 67 | + |
| 68 | +Use absolute container paths (`/app/data/...`) in your manifest so the container can find the files. |
| 69 | + |
| 70 | +### Models |
| 71 | + |
| 72 | +If `models/openbmb__VoxCPM2/` exists on the host, the app loads directly from that path — no network access needed. If the directory is empty or missing, `from_pretrained` falls back to `snapshot_download` from HuggingFace Hub. |
| 73 | + |
| 74 | +The Dockerfile sets `HF_HOME=/app/models` so any Hub downloads land in the same mounted volume. This means models persist across container restarts regardless of whether they were pre-populated or auto-downloaded. |
| 75 | + |
| 76 | +**Recommended:** Pre-populate to avoid first-run download delay: |
| 77 | + |
| 78 | +```bash |
| 79 | +huggingface-cli download openbmb/VoxCPM2 --local-dir ./models/openbmb__VoxCPM2 |
| 80 | +``` |
| 81 | + |
| 82 | +The Dockerfile creates empty `/app/models`, `/app/lora`, `/app/output` directories, but the volume mounts override them with your host directories. |
| 83 | + |
| 84 | +## Health Check |
| 85 | + |
| 86 | +The nginx proxy forwards `GET /` to the training-webui backend, so load balancer health checks (AWS ALB, etc.) reflect real application health — returning 502 when the backend is down. This is separate from the WebUI at `/webui/`. |
| 87 | + |
| 88 | +```bash |
| 89 | +curl http://localhost/ |
| 90 | +``` |
| 91 | + |
| 92 | +## Direct Access (no proxy) |
| 93 | + |
| 94 | +If you want to bypass nginx and access Gradio directly: |
| 95 | + |
| 96 | +```bash |
| 97 | +docker compose -f docker/docker-compose.yml up --build training-webui |
| 98 | +``` |
| 99 | + |
| 100 | +Set `GRADIO_ROOT_PATH=` (empty) in the compose file when running without the proxy, then access at `http://localhost:7860`. |
| 101 | + |
| 102 | +## Building Manually |
| 103 | + |
| 104 | +```bash |
| 105 | +# Build the image |
| 106 | +docker build -f docker/Dockerfile -t voxcpm-training . |
| 107 | + |
| 108 | +# Run with GPU access (no reverse proxy) |
| 109 | +docker run --gpus all -p 7860:7860 \ |
| 110 | + -v ./models:/app/models \ |
| 111 | + -v ./data:/app/data \ |
| 112 | + -v ./lora:/app/lora \ |
| 113 | + -v ./output:/app/output \ |
| 114 | + voxcpm-training |
| 115 | +``` |
| 116 | + |
| 117 | +## Environment Variables |
| 118 | + |
| 119 | +| Variable | Default | Description | |
| 120 | +|----------|---------|-------------| |
| 121 | +| `GRADIO_SERVER_PORT` | `7860` | Port for the WebUI server | |
| 122 | +| `GRADIO_ROOT_PATH` | `""` | URL prefix when behind a reverse proxy (e.g., `/webui`) | |
| 123 | + |
| 124 | +## Reverse Proxy |
| 125 | + |
| 126 | +The included `docker-compose.yml` ships with an nginx reverse proxy that serves the WebUI at `/webui/`. The `GRADIO_ROOT_PATH=/webui` env var ensures Gradio generates correct URLs for assets and WebSocket connections. |
| 127 | + |
| 128 | +### Custom nginx config |
| 129 | + |
| 130 | +Edit `docker/nginx.conf` to change the location prefix or add TLS. |
| 131 | + |
| 132 | +### Traefik Example (labels) |
| 133 | + |
| 134 | +```yaml |
| 135 | +labels: |
| 136 | + - "traefik.http.routers.voxcpm.rule=PathPrefix(`/webui`)" |
| 137 | + - "traefik.http.services.voxcpm.loadbalancer.server.port=7860" |
| 138 | +``` |
| 139 | +
|
| 140 | +## Viewing Training Logs |
| 141 | +
|
| 142 | +Training subprocess output is streamed to stdout, visible via: |
| 143 | +
|
| 144 | +```bash |
| 145 | +docker compose -f docker/docker-compose.yml logs -f training-webui |
| 146 | +``` |
| 147 | + |
| 148 | +## Troubleshooting |
| 149 | + |
| 150 | +- **"no NVIDIA GPU detected"**: Ensure the NVIDIA Container Toolkit is installed and `docker run --gpus all nvidia-smi` works. |
| 151 | +- **OOM errors**: Reduce batch size in the WebUI or use a GPU with more VRAM. |
| 152 | +- **WebUI not accessible**: Check that port 80 (nginx) or 7860 (direct) isn't blocked by a firewall. |
| 153 | +- **WebSocket errors behind proxy**: Ensure your proxy forwards `Upgrade` and `Connection` headers (the included nginx.conf handles this). |
| 154 | +- **Health check failing**: Ensure the training-webui container is running — `curl http://localhost/` proxies to the backend and returns 502 if it's unreachable. |
| 155 | +- **Mixed-content / audio not playing over HTTPS**: The nginx config uses `map $http_x_forwarded_proto` to pass the correct protocol through to Gradio. This ensures `https://` file URLs are generated when accessed via HTTPS through a load balancer. |
0 commit comments