AMD GPU acceleration for AudioMuse-AI: musicnn and the CLAP audio encoder on the GPU via ONNX Runtime's MIGraphX provider, and lyrics transcription on faster-whisper.
Two pieces, and you need both:
| What | Why | |
|---|---|---|
| Worker image | ghcr.io/schaka/audiomuse-ai-rocm:7.14-<arch> |
AudioMuse-AI's published image rebuilt on a ROCm base, with a MIGraphX-enabled onnxruntime and CTranslate2's ROCm build |
| Plugin | ROCm Accelerator (AMD), installed from the Plugins page |
Wires those into the analysis pipeline |
A plugin cannot install a ROCm stack (a PyPI onnxruntime would replace the
MIGraphX build with a CPU-only one), so the runtime has to come from the image.
On any other image the plugin registers nothing.
Requires AudioMuse-AI 3.1.0 or newer.
rocminfo | grep gfxOne tag per arch — several arches' ROCm kernels do not fit in one image.
| Tag | GPUs |
|---|---|
latest-gfx1201, -gfx1200 |
RDNA4 (RX 9070 …) — gfx1201 validated on RX 9070 XT |
latest-gfx1100, -gfx1101, -gfx1102, -gfx1103 |
RDNA3 (RX 7000, RDNA3 APUs) |
latest-gfx1150, -gfx1151, -gfx1152, -gfx1153 |
Phoenix / Strix / Strix Halo APUs |
latest-gfx1030, -gfx1031, -gfx1032, -gfx1034, -gfx1035, -gfx1036 |
RDNA2 (RX 6000, RDNA2 APUs) — not gfx1033 (Steam Deck): no rocm7.14-gfx1033 base image upstream. gfx1031 validated on Sapphire GPRO X080 (RX 6700 equivalent) |
latest-gfx1010, -gfx1011, -gfx1012 |
RDNA1 (RX 5000) — gfx1010 validated on RX 5700 XT |
latest-gfx900, -gfx90c, -gfx906, -gfx908, -gfx90a, -gfx942, -gfx950 |
Vega / CDNA |
latest-gfx803 |
Polaris (RX 460–590) — experimental, see docs/ARCH_NOTES.md. gfx806 (RX 470 8GB UEFI Mining) also validated, runs under this tag |
latest-gfx803 moved onto the ROCm 7.14 base as of plugin 1.1 — the
same base every other arch already used. If you'd rather stay on the older
ROCm 6.4.4 gfx803 base (for stability, or any other reason), pin the plugin
to 1.0.1, the last version built against it; 1.1+ assumes the 7.14
worker image and is not tested against the 6.4.4 one.
Also published: :<version>-<arch> pinned to an upstream AudioMuse-AI
release (e.g. :3.1.0-gfx1030), for locking your worker to a specific
upstream version instead of tracking latest. Unrelated to the plugin's own
version — the plugin never ships inside this image. :unstable-<arch> /
:unstable-<YYYYMMDD>-<arch> are built nightly against upstream's :devel.
If you already run upstream's
docker-compose.yaml,
the change is: swap the worker's image, pass through the GPU, and mount a
cache volume. Nothing else in your existing stack needs to move.
audiomuse-ai-worker:
image: ghcr.io/schaka/audiomuse-ai-rocm:latest-gfx1030 # <- your arch from step 1
container_name: audiomuse-ai-worker-instance
devices:
- /dev/kfd
- /dev/dri
# image ships no render/video group; pass the host's numeric GIDs
# (getent group render video)
group_add:
- "105"
- "39"
security_opt:
- seccomp:unconfined
- label=disable # SELinux hosts (Fedora/RHEL/CentOS) - see below
ipc: host
volumes:
- migraphx-cache:/app/.cache/migraphx
- miopen-cache:/app/.cache/miopenImportant
On an SELinux-enforcing host (Fedora, RHEL, CentOS) label=disable is not
optional. /dev/kfd is labelled hsa_device_t, and the stock container
policy has no rule permitting a container to mmap it — the
container_use_dri_devices rule that covers /dev/dri does not extend to
it. Open and ioctl are permitted, so the GPU is detected and models begin
compiling; only libhsakmt's HDP-flush MMIO page fails to map, and the worker
then dies mid-compile with SIGABRT (exit 134):
Failed to map remapped mmio page on gpu_mem 0
Memory critical error by agent node-0 (Agent handle: 0x…) on address 0x…. Reason: Memory in use.
Every album then fails and retries forever. If you would rather keep the
container SELinux-confined, the narrower fix is to leave label=disable out
and have an administrator enable the container_use_devices boolean instead,
which grants containers device-node access system-wide. On hosts where
SELinux is not enforcing, label=disable changes nothing.
podman-compose users: do not rely on ipc: host to cover this.
podman-compose (1.6.0 and earlier) does not implement the compose ipc: key
at all — it is parsed and silently dropped, so the container gets podman's
default. It happens to mask the SELinux problem when it is applied, because
sharing a host namespace makes podman drop label separation as a side effect;
that is a coincidence, not the mechanism. security_opt is honoured.
The two cache volumes hold MIGraphX's and MIOpen's compiled-kernel caches. See
MIGraphX cache details
for why it's split into fp16/fp32 subdirectories internally.
Important
The first analysis is slow — this is expected, not a hang or a crash.
MIGraphX has to compile musicnn/CLAP for your GPU's arch before it can run
them. That compile can take anywhere from several minutes to over an
hour, during which the log repeats WARN/error-looking lines between
Model Compile: Begin and Model Compile: End — those are normal compiler
chatter, not failures. Let it run; once Model Compile: End shows up,
inference is fast for the rest of your library. fp16_enable is a knob you
can try either way — whether fp16 or fp32 compiles faster or infers faster
is not a fixed rule, it depends on arch and model (MIGraphX has open
upstream issues where fp16 ends up slower than fp32:
#763,
#4170). Check
ARCH_NOTES.md for what's actually been measured on
your GPU generation before assuming either direction.
Recompiles happen again whenever MIGraphX sees a graph shape it hasn't
cached yet — inputs are fixed-size per model, so this isn't per-track, but
it can happen after toggling fp16_enable, or on a fresh container without
the cache volumes mounted (a restart with no volume wipes everything and
forces every model to compile from scratch again). Mounting
migraphx-cache/miopen-cache as shown above is what makes that a one-time
cost instead of a recurring one.
A complete stack — Postgres, Redis, both services, GPU passthrough, group ids,
cache volumes — is at
examples/docker-compose.yaml, written as a
direct diff against upstream's own compose file so it's clear exactly what
changed. Copy it, replace the arch in both image: lines, fill in your media
server, docker compose up -d.
Settings, environment variables and the compiled-model cache layout are documented in the plugin README — edit them from Plugins → ROCm Accelerator (AMD) → Settings in the UI, which opens a raw JSON editor for the whole settings object.
Two routes, publishing the same plugin id — use one, not both (an unstable build sorts above the stable release it was built from).
Listed in the community catalog, which AudioMuse-AI ships as a repository out of the box — nothing to add, install AMD GPU Hardware Acceleration straight from the Catalog tab. Stable releases only.
Only needed for the unstable channel, which the community catalog does not carry. Published as GitHub release assets — there is no server behind it.
# stable, tracks the latest release
https://github.com/Schaka/audiomuse-rocm-plugin/releases/latest/download/repository.json
# unstable: rebuilt from main on every plugin change, untested
https://github.com/Schaka/audiomuse-rocm-plugin/releases/download/unstable/repository.json
Add it in Plugins → Repositories, refresh the catalog, install ROCm Accelerator (AMD) from the Catalog tab, apply the restart.
Replacing the community catalog entirely (rather than adding to it) is possible
with PLUGIN_DEFAULT_REPO_URL, but then no other community plugin is
installable. Adding a repository in the UI is the better option.
Check it worked: the worker log should show a MIGraphX provider chain for
musicnn and faster-whisper for lyrics; rocm-smi on the host should show the
worker using the GPU during an analysis.
- Plugin behavior, settings and environment
- Per-arch findings — what was measured on which GPU, and why the plugin behaves differently there
- Adding an arch profile — wiring in behavior for a GPU generation that needs it
Building the image or plugin from source, running the test suite, iterating against a working tree or an unreleased core: see DEVELOPMENT.md.
Nothing in this repo is written back by CI — the catalog is built from release assets, so no workflow can retrigger itself.
| Workflow | Trigger | Publishes |
|---|---|---|
plugin-release.yml |
v* tag here |
Release with the plugin zip, plugin.json, repository.json |
plugin-unstable.yml |
push to main touching plugin/** |
Rolling unstable prerelease, same three assets |
image-stable.yml |
poll, every 30 min | :<version>-<arch> + :latest-<arch> when upstream cuts a release |
image-unstable.yml |
poll, nightly | :unstable-<arch> when upstream's :devel digest changes |
The image workflows poll because a push in a repository we do not own cannot trigger a workflow here. Both keep their "last built against" marker in the Actions cache, keyed on the upstream digest or version.
The ROCm bases come from
Schaka/rocm-migraphx-ort-builder:
rocm-migraphx-ort-torch-builder:rocm7.14-<arch>, one tag per arch. gfx803
(Polaris) is the exception - ROCm 7 dropped Polaris support outright, so its
rocm7.14-gfx803 tag is published by a separate repo,
Schaka/rocm-gfx803, which carries a
from-source ROCR-Runtime/CLR rebuild restoring enumeration for it. Same
package, same tag scheme either way - this repo's workflow doesn't need to
know which upstream repo actually built a given arch's tag. gfx1033 (Steam
Deck) has no rocm7.14-gfx1033 base image at all, so it is dropped from the
build matrix here.