ローカルLLMの分散推論

なぜローカルLLMで分散推論を検討するのか

ローカルLLMでは、モデルの重みや推論中の作業領域が、単一GPUのメモリ容量に収まらないことがあります。このときの選択肢の一つが、モデルの処理を複数のGPUやPCへ分割する分散推論です。

ただし、VRAMが不足した場合に必ず分散推論が必要になるわけではありません。モデルの小型化、量子化、CPU・RAMへのオフロード、コンテキスト長や同時実行数の調整でも対応できる場合があります。Hugging Face Accelerateにも、GPUに収まらないモデルの重みをCPUやディスクへ配置する仕組みがあります。

分散推論は、こうした方法では必要なモデルや性能要件を満たせない場合に検討します。目的は「大きなモデルを動かすこと」「単一リクエストの応答を速くすること」「複数リクエストを効率よく処理すること」に分けて考える必要があります。

GPUメモリ制限とモデルサイズの関係

推論に必要なメモリは、パラメータ数だけでは決まりません。少なくとも、次の要素を考慮します。

  • モデルの重み
  • 過去のトークンに対応するKVキャッシュ
  • 演算用バッファや一時的な中間データ
  • 推論エンジンや通信処理が確保する領域

重みだけの理論容量は、概ね「パラメータ数 × 1パラメータあたりの保存ビット数 ÷ 8」で見積もれます。

例えば、130億パラメータの重みをすべて同じ精度で保存すると仮定した場合、次の容量になります。

保存精度 重みだけの理論容量
FP32・32bit 約52GB
FP16/BF16・16bit 約26GB
8bit 約13GB
4bit 約6.5GB

※GBは10進表記です。量子化用の付加情報、一部を高精度で保持する重み、KVキャッシュなどは含みません。実際の必要メモリは、この表より大きくなります。

したがって、「130億パラメータなら40GB必要」と一律には判断できません。量子化方式に加え、コンテキスト長や同時実行数を固定した状態で、実測する必要があります。4bit・8bit量子化によるメモリ削減は、Hugging Face Transformersでも提供されています。

リソース共有と性能向上は分けて考える

複数のデバイスへモデルを分割すれば、単一デバイスに収まらない重みを配置できる可能性があります。ただし、GPUメモリが一つの高速な共有メモリになるわけではありません。各デバイスは、自分が担当する重みや状態を保持し、必要な中間データを通信で受け渡します。

また、分散化そのものが高速化や可用性を保証するわけでもありません。通信待ちや処理能力の差によって、単一デバイスより遅くなることがあります。

なお、モデル全体の複製を複数台に配置してリクエストを振り分ける「データ並列」は、同時処理能力の向上に使う方法です。一つのモデルを分割する方法とは異なり、各複製にモデルを保持するメモリが必要になります。

分散推論における主要な並列化手法と選択の判断基準

並列化手法は、DenseモデルかMoEモデルかだけでは決まりません。GPU間接続の速度、ノード数、モデルの対応状況、単一リクエストの遅延と全体スループットのどちらを重視するかを合わせて判断します。

テンソル並列・パイプライン並列・エキスパート並列の違い

手法 主な分割対象 主な通信・制約
テンソル並列 レイヤー内の行列演算や重み レイヤー内で頻繁な通信・同期が発生し、高速で低遅延な接続が重要
パイプライン並列 連続するレイヤー群 ステージ境界で中間データを転送。単一リクエストでは各ステージが順番に動く
エキスパート並列 MoE層のエキスパート トークンの配送・結果の集約が必要。負荷の偏りにも注意

これらは組み合わせて使うこともあります。例えば、ノード内をテンソル並列、ノード間をパイプライン並列にする構成が考えられます。vLLMの公式資料でも、このような組み合わせが案内されています。

Denseモデルでは接続と処理目的に応じて選ぶ

Denseモデルをレイヤー単位で分割する方法は、メモリ不足に対応する選択肢です。ただし、単純にレイヤーを順番に実行するだけでは、複数GPUが常に同時稼働するわけではありません。

パイプライン並列では、複数のリクエストやマイクロバッチを異なるステージで重ねて処理することで、稼働率を高められます。一方、単一の対話リクエストでは、各トークンがステージを順番に通過するため、GPUを増やしても生成速度が上がるとは限りません。

テンソル並列は、複数GPUで同じレイヤーの演算を分担できますが、通信性能が重要です。vLLMでは、単一ノード内のテンソル並列に加え、NVLinkがない構成などでパイプライン並列を検討する指針も示されています。

MoEモデルでは計算量と通信量を区別する

MoEモデルは、各トークンについて一部のエキスパートを選択して計算します。例えばMixtral 8x7Bは、総パラメータ数が約467億であるのに対し、1トークンあたりに使うパラメータ数は約129億とされています。

ただし、アクティブなパラメータが少ないからといって、必要メモリやノード間通信も同じ比率で減るわけではありません。通常は、選択され得るエキスパートの重み全体を保持できる配置が必要です。

エキスパート並列では、選択されたエキスパートを持つGPUへ中間データを送り、結果を戻して集約します。実装によってはAll-to-all系の通信が使われ、エキスパートへの負荷の偏りも性能に影響します。そのため、低速LANに適していると一律には判断できません。

通信コストとスケーラビリティの関係

テンソル並列では、All-reduceなどの集合通信が性能上の制約になることがあります。ただし、具体的な通信方式や回数は実装によって異なります。

設計時には、帯域幅だけでなく通信遅延も確認します。小さな通信を頻繁に行う構成では、帯域幅に余裕があっても、通信ごとの待ち時間が積み重なるためです。

ノードを増やす判断は、メモリ容量の合計だけで行わず、計算時間と通信時間の実測に基づいて行います。

実環境に即した分散推論の実装アプローチ

llama.cppのRPCやexoは、複数端末を利用するための選択肢です。ただし、提供する機能や対応環境は異なります。利用するモデル、量子化形式、OS、GPU、接続方式を確認したうえで選定します。

llama.cppのRPCを利用する構成

llama.cppのRPCバックエンドは、別のホストにあるデバイスへ計算をオフロードする仕組みです。モデルを実行する側がRPCサーバーへ接続し、リモートの計算資源を利用します。

これは、複数の独立した推論APIへリクエストを振り分ける構成とは異なります。また、RPCを使えば任意の並列化手法を選べるわけではありません。モデル分割の方法や対応機能は、利用バージョンの実装を確認する必要があります。

公式READMEでは、RPCバックエンドは概念実証段階であり、機能や安全性に制約があると明記されています。公開ネットワークや機密性が求められる環境では利用しないよう案内されているため、本番用途の標準構成として無条件に推奨することはできません。

exoを利用する構成

exoは、デバイスの自動検出やトポロジーを考慮したモデル配置、APIの提供などを備えるプロジェクトです。公式資料にはテンソル並列などの機能が記載されています。

ただし、「マルチノードならexo」と一律に選ぶのは適切ではありません。対応OS、推論バックエンド、GPU、モデル、通信方式の組み合わせを確認する必要があります。特に、Apple Silicon向けの構成が、そのまま任意のWindows・NVIDIA環境で利用できるとは限りません。導入時点のREADMEと対象バージョンで対応状況を確認します。

KVキャッシュの管理と適用範囲

KVキャッシュは、生成済みのトークンに対するAttentionの計算で得られたKeyとValueを保持し、再計算を減らすための仕組みです。使用量はモデル構造、キャッシュのデータ型、保持するトークン数、同時実行数などに依存します。

レイヤーを分割する構成では、担当レイヤーに対応するKVキャッシュを各デバイスに配置できます。一方、入力処理のprefillとトークン生成のdecodeを別ワーカーに分ける構成では、両者の間でKVキャッシュを転送する必要があります。

NIXLは推論データの転送に使われるライブラリで、NVIDIA Dynamoではprefillとdecodeの間のKVキャッシュ転送などに利用されています。LMCacheは、KVキャッシュの退避や再利用を扱う仕組みです。両者は役割が異なり、利用には推論エンジン側の対応も必要です。

KVキャッシュの管理は、主にメモリ効率や応答時間を改善するためのものです。キャッシュを量子化・圧縮する場合は、出力品質への影響も別途評価します。

推論エンドポイントの統一

分散推論エンジンがAPIを提供していれば、そのAPIをアプリケーションから直接利用できます。別のゲートウェイは必須ではありません。

複数の推論サービスを統合し、認証、流量制御、モデル選択、障害時の振り分けを共通化したい場合には、ゲートウェイを設ける方法が有効です。

ただし、APIを統一するだけでKVキャッシュが共有されるわけではありません。キャッシュの再利用には、同じモデルや入力トークン列などの整合性が必要で、エンジン間の転送には対応する形式や仕組みも求められます。一般的なプレフィックスキャッシュも、共通する入力の先頭部分に対する計算結果を再利用する仕組みです。

運用フェーズで直面する課題と設計上の対策

分散推論では、計算性能に加えて通信、状態管理、障害時の復旧手順が重要になります。複数台で動作したことと、継続運用できることを分けて検証します。

ネットワーク帯域と遅延の影響評価

通信性能は、推論のフェーズごとに評価します。

  • Prefill:入力トークン列を処理する段階
  • Decode:次のトークンを逐次生成する段階

同じ構成でも、長い入力を処理する場合と、短い入力から長文を生成する場合では、ボトルネックが変わることがあります。

TCPを使う構成では、パケットロスに伴う再送や輻輳制御が遅延を増やす場合があります。ただし、影響の大きさは、損失率、通信パターン、使用する通信方式などによって異なります。

性能評価では、少なくとも次の指標を確認します。

指標 確認する内容
最初のトークンまでの時間 入力処理や待ち行列を含む応答開始の速さ
トークン間の時間・生成速度 生成中の応答性
全体スループット 複数リクエストを含む処理能力
各ノードの計算・通信時間 計算待ちや通信待ちの偏り
メモリ使用量 重み・KVキャッシュ・作業領域の余裕
高負荷時の遅延分布 一部のリクエストだけ極端に遅くならないか

複数リクエストをまとめるバッチ処理は、処理効率を高める一方で待ち時間を増やす場合があります。用途に必要な応答性を決めたうえで調整します。

ノード障害と状態の復旧

モデルを分割している場合、一つのノードが停止すると、そのノードが担当していた重みやKVキャッシュを利用できなくなります。

このため、再接続や通信経路の変更だけで生成を継続できるとは限りません。実装によっては、分散実行グループの再起動、モデルの再配置、入力からの再計算が必要になります。

復旧設計では、次の点を明確にします。

  • タイムアウトと異常検知の条件
  • 実行中リクエストを失敗として扱う条件
  • モデルや実行グループの再起動手順
  • 会話履歴や入力から推論を再実行する方法
  • 自動再試行による重複処理の扱い

可用性を高めたい場合は、モデルを分割する構成に加えて、独立した推論グループの複製も検討します。ただし、その分だけ追加の計算資源とメモリが必要です。

デバッグと監視

各ノードで、GPU使用率、メモリ使用量、通信量、待機時間、エラーを記録します。リクエストIDを共通化すると、どの処理がどのノードで停滞しているかを追いやすくなります。

GPU使用率が低い場合でも、計算資源が余っているとは限りません。通信や別ステージの完了を待っている可能性があるため、計算時間と待機時間を分けて確認します。

結論:自環境に最適な分散戦略を選ぶためのロードマップ

ローカルLLMの分散推論は、大きなモデルを動かすための有効な選択肢です。ただし、メモリ容量を増やせることと、応答速度や可用性が向上することは別の問題です。

モデルの保存精度、コンテキスト長、同時実行数、GPU間接続、推論エンジンの対応機能を合わせて判断します。

導入から拡張までの手順

  1. 必要なモデルと性能要件を決める

回答品質、入力長、同時利用数、許容する応答時間を明確にします。

  1. 単一デバイスで成立するか確認する

小型モデル、量子化、コンテキスト長の調整、CPUへのオフロードを評価します。

  1. 不足している資源を特定する

重みを配置できないのか、KVキャッシュが不足するのか、計算速度が足りないのかを切り分けます。

  1. 単一ノード内の複数GPU構成を評価する

対応モデルとGPU間接続を確認し、テンソル並列やパイプライン並列を比較します。

  1. 必要に応じてマルチノードへ拡張する

接続するノード数を増やしたときの通信時間と生成速度を測定します。

  1. 障害時の復旧とAPI運用を整える

再起動、再試行、監視、認証、流量制御を整備します。

これは導入を進めるための一つの手順です。既存機器の構成によっては、最初からマルチノードを評価することもあります。

継続運用のためのTips

クライアント向けAPIを安定させておくと、背後の推論エンジンや接続方式を変更しやすくなります。ただし、APIの共通化だけで、モデルの再配置やKVキャッシュの移動まで自動化されるわけではありません。

ノードの増減に応じた構成変更は、推論エンジンが対応している場合に利用します。対応していなければ、計画的な停止や再起動を含めて運用を設計します。

構成を比較するときは、モデル、量子化方式、入力長、出力長、同時実行数をそろえて計測します。総メモリ容量に加えて、実際の応答時間と運用負荷を確認することが、適切な分散構成を選ぶ判断材料になります。

参考資料

関連記事


タグ

GPUリソース, llama.cpp, システム設計, ローカルllm, 分散推論


おすすめの記事

>
Success message!
Warning message!
Error message!