Google Earth 上を VRM アバターが音声ガイドするデモ EarthTourGuide を、母艦の OS 更新
(Ubuntu 24.04 → 26.04)と ROCm 7.2.1 → 7.14 に追随させました。
結論から言うと、アプリ側で直したのは起動スクリプトの 2 箇所だけでした。残りはドキュメント
更新です。「AI パイプラインを別リポジトリに寄せて symlink で共有する」という構成が、こういう
基盤更新のときにちゃんと効いた、という話でもあります。
- EarthTourGuide とは: Google Earth 上を VRM アバターが音声ガイドする「EarthTourGuide」を作った
- 母艦側の移行手順: Ubuntu 26.04 + ROCm 7.14 で gfx1151(Ryzen AI Max+ 395) の WhisperX / ローカル音声AIを動かす
リポジトリ: https://github.com/kotetsuy/EarthTourGuide
環境
| 項目 | 移行前 | 移行後 |
|---|---|---|
| OS | Ubuntu 24.04 | Ubuntu 26.04 (resolute) |
| GPU | AMD Ryzen AI Max+ 395 / Radeon 8060S (gfx1151, 48GB VRAM) | 同じ |
| ROCm | 7.2.1 |
7.14.0 (/opt/rocm) |
| Python | 3.12 | system 3.14 / 各 venv は 3.12 |
| PyTorch | multi-arch ROCm ホイール |
gfx1151 専用ホイール (torch==2.8.0+rocm7.12.0) |
なぜ変更が 2 箇所で済んだのか
EarthTourGuide は、音声パイプライン(STT/LLM/TTS/VRM)を別リポジトリ
AIassistant から相対 symlink で流用する構成に
なっています。
EarthTourGuide/
├─ earth-controller/ 新規: Playwright + CDP screencast、Earth 操作
├─ earth-bridge/ 新規: フレーム → WebSocket 中継 (8002)
├─ tour/ 新規: 進行サービス (8003) + tours/*.json
├─ three-vrm/ コピー: 背景ライブ化の改造が入るのでコピー
├─ ttllm/ symlink → ../AIassistant/ttllm
├─ voicevox/ symlink → ../AIassistant/voicevox
├─ whisperX-rocm/ symlink → ../AIassistant/whisperX-rocm
├─ qwen3.6/ symlink → ../AIassistant/qwen3.6
└─ llama.cpp/ symlink → ../AIassistant/llama.cpp
ROCm 7.14 移行でいちばん厄介だったのは、
- PyTorch を gfx1151 専用インデックスのホイールに差し替える
-
torch を ctranslate2 より先に import する(
ttllm/server.pyの先頭でimport torch) - torchaudio を 2.9 未満に固定する(pyannote が 2.9 で消えた API を使う)
といった STT まわりでしたが、これらは全部 symlink の向こう側(AIassistant / whisperX-rocm)の
話です。AIassistant 側を直した時点で EarthTourGuide にも自動的に反映されるので、こちら側で
やることは残りませんでした。詳細は前回の記事へ。
残ったのが、EarthTourGuide 実体のファイルである start_all.sh の 2 箇所です。
変更① HSA_OVERRIDE_GFX_VERSION をやめる
gfx1151 は長らく「ROCm が正式サポートしていないので gfx1150(11.5.1) として偽装する」という
運用が必要で、起動スクリプトにもそれが埋まっていました。
# Before
export HSA_OVERRIDE_GFX_VERSION="${HSA_OVERRIDE_GFX_VERSION:-11.5.1}"
ROCm 7.14 では話が逆になります。repo.amd.com の gfx1151 専用 PyTorch ホイールも、
自前ビルドの CTranslate2-ROCm も llama.cpp も、すべて gfx1151 ネイティブビルドなので、
アーキテクチャを override すると壊れます。
# After
# gfx1151 (Ryzen AI Max+ 395) 向け ROCm env (ROCm 7.14 / Ubuntu 26.04)。
# HSA_OVERRIDE_GFX_VERSION は設定しない。
# repo.amd.com の gfx1151 wheel も llama.cpp も gfx1151 ネイティブビルドなので
# override すると壊れる(shell profile 等で export されている場合に備えて unset)。
unset HSA_OVERRIDE_GFX_VERSION
export ROCM_PATH="${ROCM_PATH:-/opt/rocm}"
export HIP_VISIBLE_DEVICES="${HIP_VISIBLE_DEVICES:-0}"
export AMDGPU_TARGETS="${AMDGPU_TARGETS:-gfx1151}"
export LD_LIBRARY_PATH="/usr/local/lib:/opt/rocm/lib:/opt/rocm/lib/llvm/lib:${LD_LIBRARY_PATH:-}"
ポイントは「設定しない」ではなく unset することです。.bashrc や .profile に
昔の export HSA_OVERRIDE_GFX_VERSION=11.5.1 が残っている環境は多いので、スクリプト側で
明示的に消しておかないと、ユーザーのシェル設定次第で挙動が変わってしまいます。
llama-server の起動コマンドにも同じ変数を渡していたので、そちらからも削除しました。
# Before
LLAMA_CMD="HSA_OVERRIDE_GFX_VERSION=${HSA_OVERRIDE_GFX_VERSION} \
ROCM_PATH=${ROCM_PATH} HIP_VISIBLE_DEVICES=${HIP_VISIBLE_DEVICES} \
...
# After
LLAMA_CMD="ROCM_PATH=${ROCM_PATH} HIP_VISIBLE_DEVICES=${HIP_VISIBLE_DEVICES} \
...
なお LD_LIBRARY_PATH に /opt/rocm/lib を含めるのは引き続き必須です。torch は自前の
ROCm(rocm-sdk-libraries-gfx1151, 7.12)を同梱していて、システム ROCm 7.14 を使う
CTranslate2 と 1 プロセスで共存させるために必要になります。
変更② three-vrm を「aiohttp が入った python」で起動する
Ubuntu 26.04 では system python が 3.14 になります。ここで踏んだのがこれです。
ModuleNotFoundError: No module named 'aiohttp'
VRM ビューア兼 TTS ハブの three-vrm/server.py は aiohttp 製で、起動スクリプトは長らく
素朴に python3 server.py と書いていました。24.04 時代は system python(3.12) に aiohttp が
入っていたのでそれで動いていましたが、26.04 の python 3.14 には当然入っていません。
「sudo apt install python3-aiohttp すればいい」で済ませたくなかったのは、この構成には
すでに aiohttp を持っている venv が 2 つあるからです(WhisperX 用と earth-controller 用)。
そこで、aiohttp を import できる python を探して使うようにしました。
# 起動スクリプト冒頭
# WhisperX-ROCm の venv (ttllm と共有)。Ubuntu 26.04 更新時に旧 ~/AIzunda 側の venv が
# 壊れたため ~/whisperx に統一(ttllm/run.sh の既定と揃える)。
WHISPERX_VENV="${WHISPERX_VENV:-/home/$USER/whisperx/whisperX-rocm/.venv}"
# preflight
# three-vrm は aiohttp に依存する。Ubuntu 26.04 の system python3 (3.14) には aiohttp が
# 入っていないため、aiohttp を持つ python を venv から探す(WhisperX venv → earth-controller/.venv)。
THREE_VRM_PY=""
for cand in "${WHISPERX_VENV}/bin/python" "${EARTH_CONTROLLER_DIR}/.venv/bin/python" "$(command -v python3 || true)"; do
[[ -n "$cand" && -x "$cand" ]] || continue
if "$cand" -c 'import aiohttp' >/dev/null 2>&1; then THREE_VRM_PY="$cand"; break; fi
done
[[ -n "$THREE_VRM_PY" ]] || die "aiohttp 入りの python が見つかりません (例: VIRTUAL_ENV=${WHISPERX_VENV} uv pip install aiohttp)"
log "three-vrm python: ${THREE_VRM_PY}"
# 起動時
new_window "three-vrm" "cd ${THREE_VRM_DIR} && ${THREE_VRM_PY} server.py"
このスクリプトは 7 サービスを順に立ち上げてヘルスチェックで待ち合わせる作りなので、
失敗を後ろのフェーズまで持ち越さないことを重視しています。python が見つからない場合は
サービスを 1 つも起動する前に die させて、原因が分かるメッセージを出すようにしました
(three-vrm は 6 番目に起動するので、そこまで進んでから落ちると原因が埋もれます)。
実行するとどの python が選ばれたかログに出ます。
[launch] three-vrm python: $HOME/whisperx/whisperX-rocm/.venv/bin/python
ついでに venv のパスも統一
26.04 に上げたタイミングで、3.12 で作った古い venv のインタプリタ参照が切れました
(.venv/bin/python のリンク先が消える)。作り直しついでに WhisperX の置き場所を
~/AIzunda/whisperX-rocm から ~/whisperx/whisperX-rocm に統一し、ttllm/run.sh の
既定値・symlink の向き先・start_all.sh の WHISPERX_VENV を全部そこに揃えています。
ドキュメント側の更新
READMEJ / TECHNICALJ(と英語版)も現況に合わせて更新しました。
- 前提表を Ubuntu 26.04 / ROCm 7.14.0 / system python 3.14・venv 3.12 に更新。
26.04 なら apt でネイティブ導入できること、カーネル同梱 amdgpu が gfx1151 対応済みなので
DKMS 不要であることも明記。 - 「
HSA_OVERRIDE_GFX_VERSIONは設定しないこと」を警告ブロックで追加。 - gfx1151 専用 torch ホイール / torchaudio<2.9 /
import torchの順序を「ベース由来の制約」に追記。 - トラブルシュート表に、今回踏んだエラーの症状 → 対処を追加。
| 症状 | 対処 |
|---|---|
three-vrm が ModuleNotFoundError: aiohttp
|
system python3 (3.14) で起動している。aiohttp 入りの venv python を使う |
STT で undefined symbol: _ZN9rocRoller...
|
torch が ctranslate2 より後に import されている。ttllm/server.py 冒頭の import torch を確認 |
torch で hipErrorInvalidImage / kpack_load_code_object failed
|
汎用 multi-arch の torch が入っている。gfx1151 専用インデックス版に入れ替える |
module 'torchaudio' has no attribute 'AudioMetaData' |
torchaudio が 2.9 以上。2.8.x (2.8.0a0+rocm7.12.0) に下げる |
| GPU が使われない / HIP エラー |
HSA_OVERRIDE_GFX_VERSION が export されていないか確認(gfx1151 では設定してはいけない) |
あわせて、ドキュメントに残っていた export DISPLAY=:10.0(旧 GNOME Remote Desktop 前提)を、
実機に合わせて :0 に直しました。earth-controller は headed Chrome を出すので、
DISPLAY が実在しないと Earth のライブ背景が出ません。start_all.sh は X ソケットの実在を
preflight で確認して fail-fast するようにしてあります。
動作確認
./start_all.sh を通しで実行して確認しました。
[launch] three-vrm python: $HOME/whisperx/whisperX-rocm/.venv/bin/python
[launch] VOICEVOX is up
[launch] llama-server is up
[launch] ttllm is up
[launch] WhisperX を warmup ...
[launch] warmup 完了
[launch] earth-bridge is up
[launch] earth-controller connected
[launch] three-vrm is up
[launch] tour is up
各サービスのヘルスチェック:
$ curl -s http://localhost:8001/health
{"ok":true,"whisper":{"model":"large-v3-turbo","device":"cuda","loaded":true},
"llama":{"url":"http://localhost:8080","reachable":true}}
$ curl -s http://localhost:8002/health
{"status": "ok", "controller_connected": true, "viewers": 1, "have_frame": true}
$ curl -s http://localhost:8000/status
{"clients": 1, "voicevox": "http://localhost:50021", "vrm_dir": "$HOME/AIassistant/vroid"}
warmup 完了 が出た時点で、gfx1151 ネイティブビルドの torch と CTranslate2 が同一プロセスで
共存して WhisperX がロードできていることの確認になります(ここが移行でいちばん壊れやすい)。
device: cuda と出ていますが、ROCm の HIP レイヤが CUDA API を翻訳しているだけで、
実体は AMD GPU です。
そのあと flyTo とワールドツアーも動かして、Earth のライブ背景 → LLM ナレーション →
VOICEVOX → 口パク、まで通ることを確認しました。
curl -X POST http://localhost:8002/control \
-H 'Content-Type: application/json' -d '{"cmd":"flyto","place":"Eiffel Tower"}'
curl -X POST http://localhost:8003/tour/start \
-H 'Content-Type: application/json' -d '{"id":"world"}'
タグで基盤バージョンを刻んでおく
今回のように「アプリは変わっていないが足回りが変わった」変更は、あとから
**「あの頃はどの ROCm で動いていたのか」**が分からなくなりがちです。そこで
AIassistant / EarthTourGuide の両リポジトリに、同じ命名でタグを打つようにしました。
git tag ROCM_7_2_1 # 移行前の最終コミット
git tag ROCM_7_14_0 # 移行後のコミット
git push origin ROCM_7_14_0
こうしておくと、移行差分を丸ごと見返すのも一発です。
git diff ROCM_7_2_1..ROCM_7_14_0
実際、今回 EarthTourGuide 側を直すときも、AIassistant 側の
git diff ROCM_7_2_1..ROCM_7_14_0 を並べて「どれが symlink の向こうで解決済みで、
どれが自分のリポジトリの実体ファイルか」を仕分けるところから始めました。
まとめ
-
ROCm 7.14 / gfx1151 では
HSA_OVERRIDE_GFX_VERSIONを設定してはいけない。
もう偽装は不要で、むしろ壊れる。シェル設定に残っている可能性があるのでunsetまで書く。 -
Ubuntu 26.04 の system python は 3.14。 system python 前提のスクリプトは落ちる。
venv の python を「機能があるか」で選ぶようにすると環境差に強い。 -
共有部分を symlink に寄せておくと、基盤更新の影響範囲が小さくなる。
STT まわりのハマりどころは全部 AIassistant 側で解決済みとして流用でき、
こちらの変更は起動スクリプト 2 箇所とドキュメントだけで済みました。 - 基盤バージョンは git タグで刻む。 「動いていた組み合わせ」を後から再現できます。