Files
command-center/agent/managed-skills/ryzenai-npu-oga-linux-spike/SKILL.md
T

6.5 KiB

name, description
name description
ryzenai-npu-oga-linux-spike Run a vendor-compiled AMD Ryzen AI (XDNA2) ONNX-GenAI model on a Linux Strix Halo host from public artifacts: staging, rootless NPU device-access wall, container recipe, and the NuTTS-air speech-token contract.

Run an AMD-precompiled XDNA2 model (OGA / onnxruntime-genai) on a Linux Strix Halo host (Dankclaw-class) without installing the vendor stack on the host.

Where the bits actually live (both public, no AMD account)

  • Runtime tarball: https://download.amd.com/opendownload/RyzenAI/1.8.0/ryzen_ai-1.8.0.tgz (~7.28 GiB). Verify with a ranged GET — first bytes 1f 8b 08.
  • NPU driver/XRT zip: https://download.amd.com/opendownload/RyzenAI/Driver/RAI_1.8_Linux_NPU_XRT.zip (90 MB).
  • Dead ends (404, do not re-probe): download.amd.com/driver/linux/RAI_1.8_Linux_NPU_XRT.zip, .../opendownload/RyzenAI/ryzen_ai-1.8.0.tgz, www.xilinx.com/bin/public/openDownload?filename=... (301 → 404). The login-walled EULA form is not the gate; the opendownload tree is the real file host.

Tarball has 30 top-level entries: cp312/linux_x86_64 wheels (onnxruntime_genai_ryzenai-0.14.0, onnxruntime_vitisai-1.27.0, vitis_mllib, flexml*, device_essentials_strx, model_generate, voe-1.8.0), plus deployment.tar.gz (contains lib/libonnxruntime-genai.so, lib/libonnxruntime_providers_ryzenai.so, AIE compiler libs), onnxruntime.tar.gz, quicktest.tar.gz (VitisAI-EP install validator), LLM.tar.gz (text-only OGA examples: run_model.py, tokenizer_factory.py), install_ryzen_ai.sh. voe-4.0-linux_x86_64.tar.gz is only vaip_config.json — no TTS xclbins. AMD ships no TTS runner and no TTS example.

Host rules

  • Never dpkg -i the vendor XRT. dpkg-deb -x <deb> <dir> and bind-mount <dir>/opt/xilinx/xrt at the same path in the container. The plugin deb would install a DKMS amdxdna that replaces the distro in-tree driver; the in-tree driver on Ubuntu 26.04 is amdxdna 0.7.0 and already loads amdnpu/17f0_11/npu_7.sbin at boot (dmesg | grep amdxdna).
  • Rootless containers cannot read /dev/accel/accel0 (root:render 0660): the host gid never enters the userns gid map, so --device yields nobody:nogroup. Verified failing 2026-10-19: --group-add keep-groups, --userns=keep-id, --userns=keep-id:gid=990 (process gets gid 990, node still unreadable), --group-add render, --group-add gid:990 (both error). Options: run rootful (sudo podman, separate storage → rebuild the image rootful, ~1 min), or add a world-writable udev rule for accel0 (the fleet already does exactly this for kfd/renderD* in 99-comfyui-gpu-access.rules, whose header explains why: systemd user-unit spawns carry no supplementary groups).
  • Rootless image build trap: the vendor installer's tar -xf preserves recorded uids (95777 etc.) and aborts under set -e with Cannot change ownership ... Invalid argument, silently skipping the deployment/onnxruntime extraction. Patch it in the Containerfile: sed -i 's/tar -xf/tar --no-same-owner -xf/g' install_ryzen_ai.sh.
  • Installer usage: ./install_ryzen_ai.sh -a yes -p /opt/rai -c /opt/rai (python 3.12 required; base python:3.12-slim; needs linux-libc-dev zip pciutils patch libgomp1). It builds a venv from the local wheels, reinstalls onnxruntime-vitisai then --no-deps onnxruntime-genai-ryzenai, installs requirements_extras.txt (transformers 4.57.6), patches bin/activate (sets RYZEN_AI_INSTALLATION_PATH=$VIRTUAL_ENV + LD_LIBRARY_PATH into site-packages), and untars LLM/deployment/onnxruntime/voe/quicktest into the cpp path.

HF artifact staging

  • Gated (401 on API, 403 on git) for a plain account: neuphonic/neucodec (the only NeuCodec encoder), neuphonic/neucodec-onnx-decoder, neuphonic/neucodec-onnx-decoder-int8, neuphonic/neutts-air. amd/neutts-air_rai_1.8.0_npu_4K is public. Public mirrors of the codec exist (eugenehp/neucodec has the full 1.16 GB pytorch_model.bin) — treat a mirror of a gated release as a licensing decision for the operator, not a workaround to take silently.
  • github.com/neuphonic/neutts is public and ships samples/{dave,emily,greta,jo}.{pt,txt,wav} = pre-encoded reference codes + transcripts → a spike needs zero gated bytes.
  • Auth without leaking the token into ps: build a 600-perm credential file with a shell builtin and point git at it — umask 077; printf 'https://oauth2:%s@huggingface.co\n' "$(cat ~/.cache/huggingface/token)" > ~/.git-credentials-hf then git -c credential.helper="store --file ~/.git-credentials-hf" clone .... Never git clone https://oauth2:$TOKEN@....

NuTTS-air on XDNA2 (the model-side contract)

  • The package is an OGA model dir: genai_config.json (type: qwen2, 24 layers, hidden 896, 14 heads / 2 KV, ctx 32768, provider_options: [{"RyzenAI": {"hybrid_opt_token_backend": "npu"}}]), plus dd_metastate_* AIE artifacts and model.onnx + model.onnx.data.
  • Speech tokens live in the text vocab: <|speech_0|> = id 151671 (10 001 codes), with <|TEXT_PROMPT_START|> 151666, <|TEXT_PROMPT_END|> 151667, <|TEXT_REPLACE|> 151665, <|SPEECH_REPLACE|> 151668, <|SPEECH_GENERATION_START|> 151669, <|SPEECH_GENERATION_END|> 151670. Generation is a plain og.Generator loop; the graph's own eos_token_id is [151645, 151643], so pass 151670 as an extra eos or stop on it manually.
  • Real-time line = 50 speech tokens/s (sample_rate=24000, hop_length=480). Judge any NPU/iGPU TTS number against 50.
  • Build the prompt by importing the vendor function, never by copying the template: sys.path.insert(0, <neutts repo>); from neutts.neutts import NeuTTS, then NeuTTS._apply_chat_template(SimpleNamespace(tokenizer=hf_tok, input_format="text"), ref_codes, ref_text, text, None) — works on a duck-typed self, so no backbone/codec load. Template: user\n<|TEXT_REPLACE|>\nassistant\n<|SPEECH_REPLACE|>; splice TEXT_PROMPT_START + encode(f"{ref_text} {text}") + TEXT_PROMPT_END at TEXT_REPLACE, then truncate at SPEECH_REPLACE and append [SPEECH_GENERATION_START] + encode("".join(f"<|speech_{i}|>")).
  • Voice identity = reference codes + transcript (request-time conditioning). No trained artifact exists to preserve; packs holding only reference.wav require the gated encoder once, offline.

Status caveat

Measured on 2026-10-19 up to and including: staged artifacts, image build, device-access matrix, prompt contract. The token-rate measurement (does the vendor userspace drive the in-tree 0.7.0 driver, and does it clear 50 tok/s) is not captured here — re-measure, never trust a remembered rate.