メインコンテンツへ移動
AIチュートリアル

vLLMとPiで2台のDGX SparkにDeepSeek-V4.1-Flashをサービングする

このチュートリアルでは、EXL3量子化されたDeepSeek-V4.1-Flashチェックポイントを2台のNVIDIA DGX Sparkノードにまたがってデプロイし、RoCEテンソル並列処理を構成し、OpenAI互換APIを検証して、モデルをPiコーディングエージェントに接続する方法を説明します。

vLLMとPiで2台のDGX SparkにDeepSeek-V4.1-Flashをサービングする

構築するもの

このプロジェクトは、vLLMを使用して2台のNVIDIA DGX Sparkノード間でDeepSeek-V4.1-Flashを提供するスクリプトを用意します。テンソル並列処理はQSFP/RoCEリンク経由でノード間にまたがって実行され、ヘッドノードはポート8000でOpenAI互換APIを公開します。

デプロイでは0xSero/DeepSeek-V4.1-Flash-Sparkチェックポイントを使用します。ルーティングされるバックボーンエキスパートはEXL3トレリスデータとしてエンコードされ、報告された重みあたりの平均ビット数は2.77です。アテンション、共有エキスパート、ルーター、Engramテーブル、ドラフト層、ビジョンコンポーネント、埋め込み、出力ヘッドは、アップストリームのチェックポイントのまま維持されます。

デプロイ後は、API経由でモデルを直接使用することも、Piコーディングエージェントに接続してコーディングやツール支援ワークフローに利用することもできます。

性能と機能

READMEには、RoCE経由のテンソル並列処理、FP8 KVキャッシュ、7トークンのDSpark投機的デコーディング、ディスクバックのEngramテーブル、2つの同時シーケンスを使用した、2台のDGX Spark GB10ノードでの測定結果が記載されています。

  • 8kプロンプトのプリフィル:約2,050トークン/秒。
  • 32kプロンプトのプリフィル:約2,061トークン/秒。
  • コードのデコーディング:1ストリームで約39~41トークン/秒。
  • 2ストリームのコードデコーディング:合計60トークン/秒。
  • 文章のデコーディング:1ストリームで約29トークン/秒。
  • リクエストあたりの最大コンテキスト:262,144トークン。
  • KVキャッシュプール:2,023,717トークン。
  • ビジョン入力、ツール呼び出し、推論:スモークテストに成功。
  • 175kトークンのコンテキスト想起:報告された6つのラボゲートすべてに合格。

初回起動には約11~13分かかります。これは、重みとEXL3バンクの読み込み、カーネルのコンパイル、CUDAグラフのキャプチャが行われるためです。

前提条件

DGX OSを実行するDGX Sparkノードが2台必要です。1台をAPIを提供するヘッド、もう1台をワーカーとして選択します。

  • RoCEが有効な状態でノードを接続するQSFPケーブル。
  • rdma linkで確認した、各ノード上でACTIVE状態にあるRDMAポートが少なくとも1つ。
  • 各ノードに対応するファブリックネットワーク上のIPv4アドレス。例:10.10.10.13と10.10.10.11。
  • ワーカーのファブリックアドレスを使用した、ヘッドからワーカーへのパスワードなしSSH。
  • 両ノードにインストールされたNVIDIAランタイム付きDocker。
  • ユーザーがdockerグループに所属していること。
  • ヘッドに約700 GB、ワーカーに470 GBの空きNVMe容量。
  • 両ノード上のpython3、rsync、curl。
  • Piを実行するマシン上のNode.jsとnpm。

リポジトリをクローンしてワーカーを定義する

ヘッドノードで次のコマンドを実行します。SSHターゲットをワーカーのファブリックアドレスに置き換えてください。

git clone https://github.com/0xSero/DeepSeek-V4.1-Flash-Two-Sparks
cd DeepSeek-V4.1-Flash-Two-Sparks
export WORKER=user@10.10.10.11

スクリプトはWORKERを使用して2台目のSparkに接続します。続行する前に、SSHキー認証が機能することを確認してください。

チェックポイントをダウンロードして配布する

約462 GBのチェックポイントをヘッドのデフォルトモデルディレクトリにダウンロードします。

scripts/download.sh

ダウンロードスクリプトはEngramシャードの再構成も行います。Hugging Faceでは個別ファイルの容量が50 GBに制限されているため、ネイティブシャード2個は.partNNファイルとして保存されます。スクリプトはこれらを再構成し、6個のネイティブシャードをsha256-manifest.txtと照合して検証した後、パートファイルを削除します。パートファイルを保持する場合はKEEP_PARTS=1を設定してください。

完成したモデルをファブリック経由でワーカーにコピーします。

scripts/copy-to-peer.sh

別の方法として、ワーカー上でもscripts/download.shを直接実行できます。デフォルトのモデルパスは~/models/DeepSeek-V4.1-Flash-Sparkです。ワーカーが別のパスを使用する場合は、起動前にWORKER_MODEL_DIRを設定してください。

サービングイメージを取得する

このプロジェクトでは、EXL3 mixture-of-expertsパスとB12X Sparkカーネルを含むvLLMイメージを使用します。固定されたイメージを両方のノードで取得します。

docker pull ghcr.io/0xsero/deepseek-v4.1-flash-spark@sha256:5668e35e5ee021da4b9ce88a1964caf0e082e8ca01d81d1d64b6213a55c6add5

起動スクリプトは、イメージがまだ利用できない場合に自動で取得するため、この手順は起動中に実行することもできます。

テンソル並列ランクを両方起動する

ヘッドから2ノードサーバーを起動します。

scripts/launch.sh

ランチャーはアクティブなファブリックインターフェースを検出し、~/.dsv41-two-sparks/api_keyにAPIキーを作成し、両ノードでメモリガードを起動し、ワーカーでランク1を起動してから、ヘッドでランク0を起動します。APIが利用可能になるまで待機し、起動には最大45分を許容します。

同じスクリプトでデプロイの確認や管理ができます。

scripts/launch.sh status
scripts/launch.sh logs r0
scripts/launch.sh logs r1
scripts/launch.sh stop

サーバーはヘッド上のhttp://127.0.0.1:8000でローカルに待ち受けます。クライアントはヘッドの到達可能なアドレスを使用できますが、ランク間の通信にはQSFP/RoCEファブリックを使用する必要があります。

スモークテストを実行する

次のコマンドで、テキスト生成、ツール呼び出し、ビジョン入力を検証します。

python3 scripts/smoke.py http://127.0.0.1:8000

各チェックはPASSまたはFAILを報告します。オプションのベンチマークも実行できます。

python3 scripts/bench.py --out bench.json --conc 1 2

このベンチマークでは、出力上限を設けずに、プリフィル、デコード、長文脈での速度を測定します。

OpenAI互換エンドポイントを使用する

サーバーは次のAPI情報を公開します。

  • ベースURL: http://<head-ip>:8000/v1
  • モデル名: deepseek-v4.1-flash
  • 認証: ~/.dsv41-two-sparks/api_keyにあるBearerトークン

たとえば、ヘッドノードからキーを取得するには、次を実行します。

ssh <head> cat ~/.dsv41-two-sparks/api_key

その後、ベースURL、モデル名、Bearerキーを設定すれば、任意のOpenAI互換クライアントでこのエンドポイントを使用できます。

Piをモデルに接続する

Node.jsとnpmがあるマシンで、Piプロバイダーをインストールして登録します。このコマンドには、末尾のモデルパスを含まないAPIベースURLを指定します。

pi/install.sh http://<head-ip>:8000/v1

Piを起動するシェルでAPIキーを設定します。

export DSV41_API_KEY=$(ssh <head> cat ~/.dsv41-two-sparks/api_key)
pi --model dsv41-sparks/deepseek-v4.1-flash

インストーラーは、PATHにPiがまだ存在しない場合はPiをインストールし、Piのモデル設定ではdsv41-sparksプロバイダーだけを追加または置換します。最初にタイムスタンプ付きのバックアップを作成し、他のプロバイダーには変更を加えません。

enabledModelsリストを使用している場合、インストーラーは提供されるモデルをそのリストに追加します。SET_DEFAULT=1を設定すると、このモデルがPiの起動モデルになります。

インストールされた拡張機能は、このプロバイダーに対するPiの出力トークン上限を削除し、応答が自然に終了できるようにします。リクエスト時にDSV41_API_KEYを読み取り、キーをPiの設定に書き込みません。

デフォルト設定を理解する

scripts/launch.shは、測定に使用したサービング設定を再現します。主な設定は次のとおりです。

  • KV_BYTES=2700000000を使用するFP8 KVキャッシュ。
  • 最大コンテキスト長は262144トークン。
  • 同時実行シーケンス数は最大2。
  • 最大バッチトークン数は2048。
  • ドラフトトークン7個と適応型検証を使用するDSpark投機的デコーディング。
  • ディスク上に保持するEngramテーブル。
  • B12Xアテンション、線形、MoEカーネル。
  • ST_EXL3_PREFILL=stを使用するEXL3ルーティングエキスパート。
  • FULL_DECODE_ONLY CUDAグラフ。
  • B12X RoCEワンショットall-reduce、および残りの分散処理にはNCCL over RoCE。
  • マルチモーダルプロンプトあたり画像1枚。
  • deepseek_v41の推論パーサーとツール呼び出しパーサー。

ほとんどの設定は環境変数で上書きできます。モデルディレクトリはMODEL_DIR、ワーカーのモデルディレクトリはWORKER_MODEL_DIR、永続ランタイムデータはSTATE_DIRで指定します。デフォルトの状態ディレクトリは~/.dsv41-two-sparksです。

ランチャーはモデルを/modelに読み取り専用でマウントします。EXL3の割り当てプランを状態ディレクトリにコピーし、マウントされたEXL3ディレクトリを指すようにそのバンクパスを書き換えます。

トラフィックを正しいネットワークに維持する

vLLM、NCCL、Glooのプロセスは、Wi-Fi、Ethernet、Tailscaleのインターフェースではなく、QSFP/RoCEアドレスにバインドする必要があります。ランチャーは通常、アクティブなRoCEポートを検出し、次のような変数を設定します。

  • VLLM_HOST_IP
  • NCCL_SOCKET_IFNAME
  • GLOO_SOCKET_IFNAME
  • NCCL_IB_HCA

自動検出で誤ったインターフェースが選択された場合は、HEAD_IP、WORKER_IP、HEAD_IFNAME、WORKER_IFNAME、HEAD_HCAS、またはWORKER_HCASを明示的に設定します。正しいアドレスとRDMAデバイスを特定するには、ip -br aとrdma linkを使用します。

メモリを安全に管理する

DGX Sparkでは、CPUとGPUが128 GBのメモリプールを共有します。利用可能なメモリがゼロになると、コンテナが正常に終了せず、ホストが応答しなくなる可能性があります。ランチャーは両方のノードでscripts/memguard.shを起動し、利用可能なメモリが設定した下限を下回るとdsv41-r*コンテナを停止します。

メモリガードのログは次の場所で確認できます。

~/.dsv41-two-sparks/memguard.log

デフォルト設定では、定常状態の利用可能メモリは約2~3 GiBと報告されます。ガードが作動した場合は、MEMGUARD_GIBを増やす前にKV_BYTESまたはGPU_UTILを下げてください。

一般的な問題のトラブルシューティング

起動が遅い

初回起動では、重みの読み込み、EXL3バンクの準備、B12Xカーネルのコンパイル、CUDAグラフのキャプチャに約12分かかる場合があります。カーネルキャッシュはSTATE_DIR/cacheに保存されるため、2回目以降の起動は速くなる可能性があります。

Engramファイルが見つからない

model-00005-of-00006.safetensorsのようなファイルが見つからないという報告が起動時に表示された場合、Engramシャードが再結合されていない可能性があります。scripts/download.shをもう一度実行してください。未完了の処理は再開され、完了済みの手順はスキップされます。

ファブリック検出で誤ったインターフェースが選択される

ip -br aでアドレスを、rdma linkでRDMAの状態を確認します。その後、前述のヘッドとワーカーのインターフェース、IP、HCA変数を明示的に指定してください。

ダウンロードが遅い

SparkがWi-Fi経由でしかインターネットに接続できない場合は、アップリンクが最も良いノードでチェックポイントをダウンロードし、scripts/copy-to-peer.shを使ってファブリック経由で転送します。

Piからモデルが見えない

Piを起動するのと同じシェルでDSV41_API_KEYがエクスポートされていることを確認します。Pi内で/modelを実行してモデル一覧を再読み込みします。

Piの印刷モードが無期限に待機する

標準入力がターミナルでない場合、pi -p は標準入力からも読み取ります。スクリプトでは、標準入力を /dev/null からリダイレクトしてください。

pi -p < /dev/null

まとめ

このリポジトリには、2台のDGX SparkでDeepSeek-V4.1-Flashを実行するために必要なモデル、サービングイメージ、分散起動スクリプト、メモリ保護、検証ツール、Pi連携が含まれています。RoCEファブリックを準備し、両ノードでチェックポイントをダウンロードして検証し、2つのランクを起動してスモークテストを実行します。その後、互換性のあるクライアントまたはPiを、ヘッドノードのOpenAI互換エンドポイントに接続してください。