mcpField
S
serving-llms-on-instinct

serving-llms-on-instinct

github.com/amdクラウド・DevOps470916 回インストール2 日前に更新
リポジトリ

serving-llms-on-instinct について

AMD Instinct GPU で vLLM エンドポイントを構築する手順を示すスキルです。GPU の検出、環境検証、モデル設定と VRAM の見積もりを行い、ローカルまたはリモートホストでの起動と確認を支援します。

主な機能

  1. 01ローカルまたは SSH 経由で GPU を検出
  2. 02実行環境の検証
  3. 03モデルレシピと GPU 設定の読み込み
  4. 04VRAM とテンソル並列度の見積もり
  5. 05vLLM エンドポイントの起動と確認

活用シーン

  1. 01AMD Instinct GPU 向けのモデルサービングコマンドの準備
  2. 02利用可能な GPU メモリへのモデル適合性の確認
  3. 03リモート GPU ホストでのエンドポイント起動と検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/amd/skills --skill serving-llms-on-instinct

インストール後、Claude Code で/serving-llms-on-instinctを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

reference.md
skill-card.md
data/
blacklist.json
gpu_overrides.json
evals/
evals.json
hooks.py
machine.yml
scripts/
detect.py
estimate_vram.py
sync_recipes.py
validate.py

詳細

AMD Instinct で LLM を提供する

AMD Instinct GPU ハードウェアで vLLM エンドポイントを起動します。

前提条件

  • GPU ホストに ROCm ドライバーと amd-smi がインストールされていること
  • Docker が稼働していて、アクセス可能であること(docker ps で確認します)
  • GPU ホストに /dev/kfd と /dev/dri が存在すること
  • HF_TOKEN 環境変数に HuggingFace トークンが設定されていること(ゲート付きモデルで必要です。Qwen3 または Gemma では不要です)。ゲート付きモデル(Llama 3.2、Gemma など)の場合、HF トークンは huggingface.co/<model_id> でモデルのライセンスに同意済みのアカウントに属している必要があります。ライセンスに同意せずに有効なトークンを使うと、詳細不明の「Engine core initialization failed」エラーが発生します。
  • リモート GPU の場合:SSH キーアクセスが設定されていること(ssh <user>@<host> をパスワード入力なしで実行できる必要があります)。パスワードでのアクセスしか使えない場合は、まずキーを設定します:ssh-copy-id <user>@<host>

データファイル

モデルと GPU の設定を確認するには、これらのファイルを直接読み取ります。

  • data/recipes_cache.json -- vllm-project/recipes から同期されたモデル設定です。models.<HF_ID>.recipe の各エントリーには、model.base_args、model.base_env、features.tool_calling.args、features.reasoning.args、hardware_overrides.amd.extra_args、hardware_overrides.amd.extra_env を含む完全なレシピが格納されています。トップレベルの docker_image フィールドには、解決済みの最新 vLLM ROCm イメージが格納されています。

  • data/gpu_overrides.json -- GPU 固有の設定です。docker_flags(すべての AMD Instinct に必須)、env_defaults と workarounds を含む gfx_version 別の gpu_configs、および vLLM のレシピにまだ含まれていないモデル用の legacy_models が格納されています。

  • data/blacklist.json -- vLLM のレシピには含まれているものの、LLM エンドポイントとして提供できないモデルです。拡散・画像・音声生成モデル、埋め込みモデル、リランキングモデル、音声パイプラインが必要な ASR モデル、未リリースの vLLM ナイトリービルドが必要なモデルが含まれます。モデルの提供を試みる前に、このファイルを確認してください。ユーザーがブラックリスト対象のモデルを指定した場合は、動作しない理由を説明し、代替案を提案してください。

ユーザーがモデルを指定しない場合は、Qwen/Qwen3.5-9B をデフォルトとして使用します。MTP に対応した高密度マルチモーダルモデルで、Apache 2.0 ライセンス(HF トークン不要)、単一 GPU に収まり、優れた推論性能とツール呼び出し機能を備えています。

ステップ 1:GPU を検出する

python3 scripts/detect.py
# Remote:
python3 scripts/detect.py --host user@hostname

gfx_version、vram_gb、gpu_count、rocm_version を含む JSON が返されます。

gfx_versionハードウェアVRAM
gfx950MI350X / MI355X288 GB HBM3E
gfx942MI300X(192 GB)/ MI325X(256 GB)/ MI300A(128 GB)さまざま

gfx_version が unknown の場合、amd-smi は実行されましたが GPU が見つかりませんでした。lsmod | grep amdgpu を確認してください。

ステップ 2:環境を検証する

python3 scripts/validate.py --auto-fix
# Remote:
python3 scripts/validate.py --auto-fix --host user@hostname

ready(ブール値)、errors、warnings、fixes_applied を含む JSON が返されます。 ready が false の場合は先に進まないでください。

ステップ 3:レシピを更新する(古くなっている場合)

data/recipes_cache.json の fetched_at を確認します。24 時間以上前の値になっている場合、またはファイルが見つからない場合は、更新します。

python3 scripts/sync_recipes.py

GitHub から vllm-project/recipes をシャロークローンし、Docker Hub から最新の Docker タグを取得します。所要時間は約 10 秒です。失敗しても、既存のキャッシュを引き続き使用できます。

ステップ 4:Docker コマンドを組み立てる

data/recipes_cache.json と data/gpu_overrides.json を直接読み取ります。次の情報を組み合わせて Docker コマンドを作成します。

  1. gpu_overrides.json > docker_flags の Docker フラグ(すべての AMD GPU で必須)
  2. HF キャッシュのマウント:-v ~/.cache/huggingface:/root/.cache/huggingface (ホストに共有モデルキャッシュディレクトリがある場合は、models--* ディレクトリがキャッシュルートにあるか、hub/ サブディレクトリ内にあるかを確認し、/root/.cache/huggingface または /root/.cache/huggingface/hub に適切にマウントしてください)
  3. ポート:-p <port>:<port>(デフォルトは 8000)
  4. 環境変数:gpu_configs.<gfx_version>.env_defaults とレシピの model.base_env および hardware_overrides.amd.extra_env をマージします。必ず --env HF_TOKEN=${HF_TOKEN} を追加してください。
  5. Docker イメージ:recipes_cache.json のトップレベルにある docker_image を使用します(モデルに固定イメージが必要な場合を除きます。たとえば GLM-4.5 には v0.15.1 が必要です)。ユーザーが Docker イメージのバージョンを指定した場合は、レシピの model.min_vllm_version と照合してください。イメージが古い場合は警告してください。起動時に不透明な「Engine core initialization failed」エラーが発生して、モデルがクラッシュする可能性があります。
  6. モデル ID:--model <HF_ID>
  7. vLLM 引数:レシピの model.base_args、hardware_overrides.amd.extra_args、features.tool_calling.args、features.reasoning.args を組み合わせます。存在しない場合は --enable-auto-tool-choice を追加してください。マルチ GPU の場合は --tensor-parallel-size N を追加してください(以下の VRAM 推定を参照)。マルチ GPU で MoE モデルを使用する場合は、--distributed-executor-backend mp も追加してください。
  8. ポート引数:--port <port>

正確なモデル ID が recipes_cache.json にない場合は、日付やバージョンの接尾辞を取り除いてベースモデルと一致するか確認してください(例:Kimi-K2-Instruct は Kimi-K2-Instruct-0905 に一致します)。見つかった場合は、ベースモデルのレシピを使用してください。

レシピが見つからない場合は、gpu_overrides.json の legacy_models を確認してください。そこにもない場合は、--enable-auto-tool-choice --trust-remote-code --tool-call-parser hermes を指定した汎用構成を使用してください。

精度バリアントの選択: レシピにはバリアント(デフォルト、fp8、nvfp4)が用意されている場合があります。バリアントを選択する前に、gpu_overrides.json の gpu_configs.<gfx_version>.precision.native を確認してください。gfx942(MI300X)では、ハードウェアネイティブなのは bf16、fp16、fp8_fnuz、int8 のみです。MXFP4 と NVFP4 の演算はエミュレーションされます(行列積中に BF16 へデクォントされます)が、重みは VRAM 内で圧縮されたままなので、量子化モデルはより少ないメモリに収まります。gfx950(MI350X)では、MXFP4 はハードウェアネイティブです。

VRAM の推定と適合性の確認: Docker コマンドを作成する前に、モデルが利用可能なハードウェアに収まるかを推定してください。

python3 scripts/estimate_vram.py --model-id <HF_ID> --vram-gb <per_gpu_vram> --tp <N>

これは HuggingFace Hub API に問い合わせ(モデルのダウンロードは行いません)、次の情報を含む JSON を返します。

  • weight_memory_gb — 重みの合計サイズ
  • kv_cache_bytes_per_token — BF16 でのトークンあたりの KV キャッシュ使用量
  • fit.weights_fit — 指定された TP で重みが収まるかどうか
  • fit.recommended_max_model_len — GPU が処理できる最大コンテキスト長
  • fit.context_limited — KV キャッシュの制限により、コンテキスト長がモデルのネイティブ上限を下回る場合は true
  • fit.min_tp_required — 必要な最小 TP(重みが収まらない場合のみ)

オーバーヘッドについて: スクリプトは、vLLM のランタイムオーバーヘッド(アクティベーションのプロファイリング、HIP グラフのキャプチャ、内部バッファー)のために約 4 GB を確保します。起動時、vLLM はピーク時のアクティベーションを測定するためにプロファイリング用のフォワードパスを実行し、その後、デコードを最適化するために HIP グラフをキャプチャします。この起動時のピークは、定常状態よりも高くなります。remaining_for_kv_gb フィールドは、重みとこのオーバーヘッドを差し引いた後に残る容量を示します。

次の判断には remaining_for_kv_gb を使用してください。

  1. remaining_for_kv_gb >= 6:安全に実行できます。context_limited: true の場合は、vLLM の引数に --max-model-len <recommended_max_model_len> を追加してください。ユーザーがより長いコンテキストを必要としている場合は、FP8 KV キャッシュのオプション(--kv-cache-dtype fp8)についても説明してください(fit.max_seq_len_fp8_kv に改善幅が示されます)。
  2. remaining_for_kv_gb が 2~6:余裕は少ないものの、試す価値があります。通常どおり起動してください。HIP グラフキャプチャ中に vLLM が OOM になる場合(コンテナログで "capturing CUDA/HIP graphs" の後に "out of memory" が出ているか確認してください)は、vLLM の引数に --enforce-eager を追加して再試行してください。これによりグラフキャプチャがスキップされ、1~2 GB のメモリが解放されます。代償はデコード遅延がわずかに増えることだけです。
  3. remaining_for_kv_gb < 2:余裕がなさすぎます。アクティベーションのプロファイリング中に OOM になる可能性が高いため、試さないでください。
  4. 複数の GPU があり、weights_fit: false の場合:--tp <min_tp_required> を指定して再実行し、再度確認してください。
  5. weights_fit: false で、GPU の数が不足している場合:次の順序で量子化モデルを探してください。 a. レシピのバリアント:レシピに、量子化済みチェックポイントを指す別の model_id を持つ fp8 または mxfp4 バリアントがある場合があります。 b. 同じプロバイダー:多くのプロバイダーは、ベースモデルとともに量子化バージョンも公開しています(例:Qwen の Qwen/Qwen3.5-122B-FP8)。HuggingFace で <provider>/<model-name> を FP8/GPTQ/AWQ のサフィックスと組み合わせて検索してください。 c. AMD の量子化モデル:AMD の Quark チームは、HuggingFace の amd/ 組織で量子化モデルを公開しています(例:amd/Kimi-K2-Instruct-w-mxfp4-a-fp8)。amd/<model-name> のバリアントを検索してください。 量子化モデルの ID に対して estimate_vram.py を実行し、適合することを確認してから、そのモデル ID を使用してください。
  6. それでも適合しない場合:モデルの実行には利用可能な VRAM より多くの VRAM が必要であることをユーザーに伝え、より小さなモデルまたはマルチ GPU ハードウェアを提案してください。起動を試みないでください。

Docker コマンドのテンプレート:

docker run -d --name vllm-<model-slug> \
  <docker_flags> \
  -v <hf_cache_mount> \
  -p <port>:<port> \
  --env <key>=<value> (for each env var) \
  --env HF_TOKEN=${HF_TOKEN} \
  <docker_image> \
  --model <model_id> \
  <vllm_args> \
  --port <port>

ステップ 5:ユーザーに確認する

起動前に概要を提示し、ユーザーに確認を求めてください。

  • モデル:HuggingFace ID の完全な表記(例:Qwen/Qwen3.5-122B-Instruct)
  • 精度:使用するバリアント(例:BF16、FP8)とその理由
  • 重みのメモリ:estimate_vram.py の結果
  • GPU:検出されたハードウェアと VRAM
  • TP:テンソル並列度(1、2、4、8)
  • コンテキスト:達成可能な最大コンテキスト長(および制限の有無)
  • ポート:エンドポイントが使用するポート

量子化された代替モデルを選択した場合(ステップ 4 の適合性確認)、元のモデルは適合せず、どの代替モデルを使用するのかを説明してください。

続行する前に、ユーザーの確認を待ってください。

ステップ 6:起動して確認する

起動する前に、ポートの競合を確認します:

ss -tlnp 2>/dev/null | grep ':<port> '

そのポートを Docker コンテナが使用している場合は、docker rm -f <name> で停止します。

Docker コマンドを実行します。次に、次のループでヘルスチェックを行います:

while docker inspect --format='{{.State.Running}}' <container_name> 2>/dev/null | grep -q true; do
  curl -sf http://localhost:<port>/health && echo "READY" && exit 0
  sleep 60
done
echo "FAILED -- container exited"

読み込み中に 503 が返されるのは正常です。モデルのサイズに応じて (hf-mem による重みのメモリ使用量)、ポーリング方法を選択します:

  • 小型モデル(重みが 100 GB 未満):Bash ツールの timeout を 600000(10 分)に設定して、ポーリングをブロッキングコマンドとして実行します。キャッシュ済みモデルのほとんどは、2~5 分で準備が完了します。
  • 大型モデル(重みが 100 GB 以上):Bash ツールの run_in_background を true に設定して、ポーリングを実行します。その後、TaskOutput を block: true および timeout: 600000 とともに使い、各チェックで最大 10 分待ちます。その後もタスクが実行中の場合は、同じパラメーターで TaskOutput を再度呼び出します。これにより、チェックのたびにターンを消費せず、10 分待つごとに 1 ターンだけ使用できます。バックグラウンドのループは、コンテナが正常な状態になるか停止するまで実行されます。

ヘルスチェックで 200 が返されたら、ウォームアップリクエストを送信します(HIP カーネルのコンパイルが開始されます。gfx942 では約 40~45 秒かかります):

curl -s http://localhost:<port>/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"<model_id>","messages":[{"role":"user","content":"say hi"}],"max_tokens":5}'

ウォームアップが成功したら、ユーザーがすぐにエンドポイントを呼び出せるよう、接続情報の表を提示します:

項目値
モデル<model_id>
サービス提供モデル名<served-model-name or model_id>
ベース URLhttp://<host>:<port>/v1
API キーなし(ローカル)
ポート<port>
テンソル並列処理<tp>
最大コンテキスト<context>
GPU<detected GPU>

次に、これらの値をそのまま使用した、すぐに実行できる例を示します:

curl -s http://<host>:<port>/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"<model_id>","messages":[{"role":"user","content":"Hello"}]}'

リモートとローカルの違い

すべてのスクリプトは --host user@hostname を受け付けます。指定すると、対象のホストに SSH 接続します。 毎回 --host を渡さずに済むよう、ROCM_SSH_HOST と ROCM_SSH_USER の環境変数を設定します。

リモートの Docker コマンドは、SSH 経由で実行します:

ssh user@host 'docker run -d ...'

ヘルスチェックとウォームアップの curl URL には localhost を使用します(curl はリモートホスト上で実行されます)。

注意事項

CUDA_VISIBLE_DEVICES を空文字列に設定 -- ROCm はこの変数を HIP_VISIBLE_DEVICES に割り当てます。空文字列に設定すると、すべての GPU が非表示になります。 GPU を制限する場合は CUDA_VISIBLE_DEVICES=0,1 を使用できます( HIP_VISIBLE_DEVICES=0,1 と同じです)。ホストで空文字列に設定されている場合は、設定を解除してください: unset CUDA_VISIBLE_DEVICES。空の --env CUDA_VISIBLE_DEVICES= を Docker に渡さないでください。コンテナ内のすべての GPU も非表示になります。

gfx942(MI300X)での FP4BMM クラッシュ -- コンテナがセグメンテーション違反または不正な命令で直ちに終了する場合:gfx942 では VLLM_ROCM_USE_AITER_FP4BMM を 0 にする必要があります。gfx942 用の gpu_overrides.json では、正しく設定されています。 vLLM の issue #34641 を参照してください。

HIP error: no kernel image -- Docker イメージに、GPU の gfx バージョン向けにコンパイルされたカーネルがありません。gfx942 および gfx950 のカーネルを含む vllm/vllm-openai-rocm:latest を使用してください。

MLA モデルには --block-size 1 が必要です -- DeepSeek-R1/V3、Kimi-K2.5。 指定しない場合、MLA アテンションバックエンドは、より遅いパスに警告なくフォールバックします。 これらのモデルのレシピ引数に設定されています。

マルチ GPU で MoE モデルを実行するには --distributed-executor-backend mp が必要です -- Qwen3-235B、GLM-4.5、MiniMax-M2。デフォルトの分散エグゼキューターは、ROCm 上の MoE で安定して動作しません。

HIP グラフのキャプチャ中に OOM が発生する -- コンテナのログに「capturing CUDA graphs」または「capturing HIP graphs」の後で「out of memory」と表示される場合、モデルは VRAM に収まっていますが、グラフのキャプチャに必要な余裕がありません。vLLM の引数に --enforce-eager を追加して再試行してください。グラフのキャプチャが無効になり、1~2 GB のメモリが解放されます。トレードオフとして、デコードのレイテンシーがわずかに高くなりますが、モデルは動作します。

「Engine core initialization failed」 -- この不明瞭なエラーは、エンジンコアのサブプロセスが停止したことを意味します。コンテナの起動直後のログを確認してください:docker logs <name> 2>&1 | head -50。よくある原因は、ゲート付きモデルへのアクセス拒否(HF でライセンスに同意していない)、この vLLM バージョンでサポートされていないアーキテクチャ、重みの読み込み中の OOM、カスタムアーキテクチャで --trust-remote-code が指定されていないこと、またはモデルに対して vLLM のバージョンが古すぎることです(レシピの min_vllm_version を確認してください)。

/dev/kfd のアクセス許可が拒否される -- ユーザーが video または render グループに属していません。次のコマンドで修正してください:sudo usermod -aG video,render $USER(再ログインが必要です)。

SSH キーが設定されていない -- スクリプトは BatchMode=yes の SSH を使用します。SSH が Permission denied (publickey) で失敗する場合は、先に鍵ベースのアクセスを設定してください。

共有ホストで GPU を制限する -- GPU をインデックスで指定するには、--env HIP_VISIBLE_DEVICES=0,1 または --env CUDA_VISIBLE_DEVICES=0,1 を使用してください。 HIP_VISIBLE_DEVICES は AMD の標準変数です。CUDA_VISIBLE_DEVICES も使用できます(ROCm が割り当てます)。どちらも空文字列に設定しないでください。


リファレンス

精度の互換性、VRAM の見積もり、Docker フラグ、既知の注意点: reference.md

コメント