12のビルド

パススルーGPU上でのOpenAI互換エンドポイントを用いたローカル推論

G-L40S上で、ドライバ、ランタイム、モデルをセットアップし、TLSとAPIキーで保護されたサーバーとして公開。負荷テストでは、ベンダーのスライドではなく、実際のトークン毎秒を報告します。

これで作れるもの

1台のGPUインスタンスが、OpenAI互換スキーマを話すHTTP API経由でオープンウェイトモデルを提供します。あなたが既に持っているすべてのクライアントライブラリは、ベースURLを1つ変更するだけで動作します。背後にはnginx、TLS、APIキー、再起動後も存続するsystemdユニットがあります。

G-L40Sで書かれています。1枚のカードに48ギガバイトのVRAMがあり、テナント間でタイムスライスされるのではなく、PCIe経由でインスタンスにパススルーされます。その違いは、予測可能なレイテンシと、他人のトレーニングジョブの後ろで待つことの違いです。カードはキャンセルするまであなたのものです。

始める前に

  • Debian 13を搭載したG-L40S。20ギガバイトのG-ADAは小さめのモデルに使えます。ステップ4の計算で、どのモデルが対応可能かがわかります。
  • このプランでは2テラバイトのNVMeがあり、ウェイトの保存に適しています。ルートファイルシステムにキャッシュがあったせいで40ギガバイトを2回ダウンロードするのは、時間を無駄にする厄介な方法です。
  • インスタンスを指すホスト名。llm.example.comを参照。

1. ドライバ

sed -i "s/ main$/ main contrib non-free-firmware non-free/" /etc/apt/sources.list.d/debian.sources
apt update
apt install -y nvidia-driver firmware-misc-nonfree build-essential
reboot

戻ってきたら:

nvidia-smi

カードがリストされ、ドライバのバージョンが表示され、メモリ使用量がゼロに近いことを確認します。この時点でカードが見つからない場合は、ほとんどの場合、initramfsが古いことが原因です。update-initramfs -uを実行して、チケットを開く前に一度再起動してください。

nvidia-smi -q -d PERFORMANCE | grep -A3 "Clocks Event Reasons"
nvidia-smi -pm 1

パーシステンスモードは、プロセス間でドライバをロードしたままにし、再起動のたびに初期化に数秒かかるのを省きます。

2. ランタイム

apt install -y python3-venv python3-pip
install -d -o root -g root /srv/models /opt/vllm
python3 -m venv /opt/vllm/venv
/opt/vllm/venv/bin/pip install --upgrade pip
/opt/vllm/venv/bin/pip install vllm

インストールは大きなCUDAリンク済みホイールセットをプルするため、時間がかかります。その間にモデルを決めましょう。

3. 収まるものを選ぶ

ウェイトは下限であり、上限ではありません。16ビット精度のモデルは、パラメータ10億あたり約2ギガバイトのVRAMに加えて、同時リクエストごとのキーバリューキャッシュ、さらに1ギガバイト程度のランタイムオーバーヘッドが必要です。

カード16ビットでのウェイト現実的なモデルサイズキャッシュ用の残り
L40S、48 GB10億あたり2 GB約200億まで6〜8 GB
L40S、48 GB、8ビット10億あたり1 GB約340億まで10 GB
RTX 4000 Ada、20 GB10億あたり2 GB約70億まで5 GB
L40S×2、96 GB10億あたり2 GB約400億まで12 GB

キャッシュ列が、同時にエンドポイントを使用できる人数を決定します。ウェイトでカードをいっぱいにすると、非常に高速なシングルユーザーのおもちゃができあがります。

4. サービング

キャッシュをNVMeに向けてサーバーを起動します。選択したオープンウェイトモデルのリポジトリIDを置き換えてください。ランタイムは最初の起動時にそれを取得します。

cat > /etc/systemd/system/vllm.service <<EOF
[Unit]
Description=vLLM inference server
After=network-online.target

[Service]
Environment=HF_HOME=/srv/models
Environment=VLLM_API_KEY=<a long random string>
ExecStart=/opt/vllm/venv/bin/vllm serve <org>/<model> \\
  --host 127.0.0.1 --port 8000 \\
  --served-model-name local \\
  --max-model-len 16384 \\
  --gpu-memory-utilization 0.92 \\
  --max-num-seqs 32
Restart=on-failure
RestartSec=10
TimeoutStartSec=1800

[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload && systemctl enable --now vllm
journalctl -fu vllm

ループバックにバインドするのは意図的です。ランタイムのAPIキーチェックは、レート制限のない単一の共有シークレットです。したがって、nginxが露出を担当し、ランタイムはパブリックインターフェースに触れることはありません。

開始タイムアウトが大きいのは、最初の起動が数十ギガバイトをダウンロードしてからカーネルをコンパイルするためです。以降の起動は1分未満です。

5. プロキシとTLS

server {
  listen 443 ssl;
  listen [::]:443 ssl;
  http2 on;
  server_name llm.example.com;

  ssl_certificate     /etc/letsencrypt/live/llm.example.com/fullchain.pem;
  ssl_certificate_key /etc/letsencrypt/live/llm.example.com/privkey.pem;

  location /v1/ {
    proxy_pass http://127.0.0.1:8000;
    proxy_buffering off;
    proxy_read_timeout 600s;
    proxy_set_header Host $host;
  }
}

proxy_buffering offはストリーミング応答をストリーミングさせるための行です。これをオンにしておくと、nginxがバッファがいっぱいになるたびにトークンが丁寧なバッチで到着します。これはモデルが遅いように見えますが、実際はそうではありません。

検証

カードから始めます:

nvidia-smi --query-gpu=memory.used,memory.total,utilization.gpu --format=csv

使用メモリは合計の約90%になるはずです。なぜなら、それが--gpu-memory-utilizationが要求したものだからです。次にエンドポイント:

curl -s https://llm.example.com/v1/models -H "Authorization: Bearer <the key>" | head -20

localという名前の1つのモデル。次に実際の完了を試し、時間を計測します:

time curl -s https://llm.example.com/v1/chat/completions \
  -H "Authorization: Bearer <the key>" \
  -H "Content-Type: application/json" \
  -d '{"model":"local","messages":[{"role":"user","content":"List three prime numbers."}],"max_tokens":64}'

最後に、1リクエストずつではなく、負荷下で測定します。それは引用する価値のある唯一の数値です:

/opt/vllm/venv/bin/vllm bench serve \
  --backend openai-chat \
  --base-url https://llm.example.com \
  --endpoint /v1/chat/completions \
  --model local --num-prompts 200 --request-rate 8

出力から3つの数値を読み取ります:総出力トークン/秒、中央値の最初のトークンまでの時間、99パーセンタイルのエンドツーエンド時間。単一のL40Sで100億から200億の範囲のモデルの場合、総出力スループットが毎秒数百トークンで、最初のトークンまでの時間が1秒未満であるのが期待される形です。最初のトークンまでの時間が並行性とともに増加する場合は、キーバリューキャッシュが小さすぎるため、--max-model-lenまたは--max-num-seqsを下げて再実行してください。

その後

最初の1週間はnvidia-smi dmonで温度とクロックスロットリングを監視してください。持続的な負荷で熱スロットリングが発生するカードは、ネットワークのせいにされるような断続的な遅さを正確に引き起こします。請求に関しては、GPUインスタンスのコストはカードがビジーかアイドルかに関係なく同じであるため、ウォームなままにするのではなく、作業をバッチ処理してください。価格はGPUページを参照してください。

準備はできている

都市を選べ。サイズを選べ。コインで支払え。

あなたが誰かに関するフォームも、承認する人間を待つ必要も、確認のための電話もありません。請求が完了すれば、認証情報があなたの受信トレイに届きます。