はじめに:なぜ「オンプレミス」で「高速化」が必要なのか
セキュリティポリシーを遵守するため、自社専用のネットワーク環境(オンプレミス)で大規模言語モデル(LLM)を運用するケースが増加しています。しかし、そこで直面するのが「推論速度の低下」と「リソースコストの増大」という課題です。
一般的なオープンソースのLLMを標準的なライブラリ(Hugging Face Transformersなど)で動かすと、複数人が同時にアクセスした際に応答が遅延したり、GPUのメモリ不足(OOM:Out Of Memory)でシステムが停止したりすることがあります。
この課題を解決する鍵となるのが、「vLLM」という推論用ライブラリです。vLLMは、UC Berkeleyの研究チームが開発した「PagedAttention(ページド・アテンション)」という技術を用いることで、LLMの推論処理能力(スループット)を飛躍的に向上させます。
本記事では、日本語性能に定評のある「ELYZA-7B」モデルを題材に、vLLMを用いてオンプレミス環境で高速かつ効率的な推論システムを構築する手順を、理論と実践の両面から解説します。単なるインストール手順にとどまらず、なぜ処理が速くなるのかという技術的な背景や、実運用を見据えたAPIサーバー化まで、システム構築において知っておくべきノウハウを網羅しました。
限られたGPUリソースを最大限に活かし、実用的な社内AI基盤を構築するための第一歩を踏み出しましょう。
なぜ今、日本語LLMのオンプレミス運用にvLLMが不可欠なのか
オンプレミス環境でのLLM運用において、最大のボトルネックとなるのがGPUメモリ(VRAM)の管理です。vLLMがなぜ革新的で、実務において必須の選択肢となるのか。その理由を、従来の技術的課題とPagedAttention技術の観点から論理的に紐解いていきます。
Hugging Face Transformersでの推論におけるメモリのボトルネック
LLMがテキストを生成する際、文脈を維持するために過去の単語や文字の断片(トークン)の情報を保持し続ける必要があります。これを「KVキャッシュ(Key-Value Cache)」と呼びます。生成される文章が長くなればなるほど、このKVキャッシュは肥大化し、GPUメモリを圧迫していきます。
従来の推論ライブラリ(Hugging Face Transformersなど)では、このKVキャッシュのために、あらかじめ連続したメモリ領域を確保しようとする設計が採用されていました。しかし、生成される文章の長さは事前には予測できません。その結果、以下のような深刻な非効率が発生していました。
- 過剰な予約(Over-allocation): 最大長を見越してメモリを確保するため、実際には使われない「空き領域」が大量に発生してしまいます。
- 断片化(Fragmentation): メモリの確保と解放を繰り返すうちに、メモリ空間が虫食い状態になります。合計容量は空いているのに、まとまった大きなデータを配置できない状態(メモリフラグメンテーション)に陥ります。
このような非効率なメモリ管理は、高価なGPUリソースを浪費していることと同義であり、システム導入における投資対効果(ROI)を悪化させる大きな要因となっていました。
PagedAttention技術がもたらすスループット革命
vLLMの中核技術であるPagedAttentionは、このメモリ管理の問題を、オペレーティングシステム(OS)のメモリ管理手法である「ページング」から着想を得て解決しました。
OSがメモリを固定長の「ページ」に分割して管理するように、PagedAttentionもKVキャッシュをブロック単位に分割して管理します。これにより、以下のメリットが生まれます。
- 不連続なメモリ配置が可能: KVキャッシュを連続した領域に置く必要がないため、物理メモリ上の空いている場所をパズルのように効率的に利用できます。
- 断片化の解消: メモリの無駄(内部断片化)を最小限に抑え、利用可能なVRAMを限界まで使い切ることが可能になります。
- メモリ共有: 複数の生成プロセスで同じプロンプト(例:「以下の文章を要約してください」など)を共有する場合、メモリブロックを参照するだけで済むため、メモリ使用量を大幅に削減できます。
公式のベンチマークおよび多くの実証環境において、vLLMは従来のライブラリと比較して最大で24倍のスループットを実現しています。これは単に「速い」だけでなく、「同じGPU枚数でより多くのリクエストを同時に処理できる」ことを意味し、インフラコストの削減に直結する重要な要素です。
ELYZA-7BをvLLMで動かすメリットと適合性
本記事では「ELYZA-japanese-Llama-2-7b」(以下、ELYZA-7B)を例に解説しますが、ここで理解すべきは「LlamaアーキテクチャとvLLMの親和性の高さ」です。
ELYZA-7BのベースとなっているMeta社のLlama 2は、vLLMで最も早くから最適化が進められたモデルの一つです。しかし、技術トレンドは常に変化しています。以下の点を踏まえて導入を検討することが重要です。
Llama 2から最新モデルへの移行:
Llama 2系列は現在、公式サイトでの情報更新が止まっており、事実上のレガシーモデルとなっています。実運用環境においては、多言語対応が強化されたLlamaモデルや、エッジ向けの軽量なLlamaモデルといった最新世代への移行を強く推奨します。vLLMはこれら最新モデルにも完全対応しており、特に小規模言語モデル(SLM)を扱う際、PagedAttentionによるメモリ効率化はさらに重要性を増します。日本語モデルの選択肢:
ELYZA-7Bは優れた日本語モデルですが、現在はLlamaモデルをベースにした「Llama-3.1-Swallow」や、株式会社ELYZAの知見を継承した最新の日本語適応モデルなどが登場しています。これらは日本語の指示に対する追従性がさらに向上しており、vLLM上で動作させることで、高速かつ高精度な日本語推論が可能になります。7Bクラスのサイズ感と運用性:
70億〜80億パラメータ(7B/8B)クラスのモデルは、量子化(データ圧縮)なしの16ビット精度(FP16)でも約14GB〜16GB程度のVRAMがあれば動作します。これはデータセンター向けのA100だけでなく、RTX 4090のようなコンシューマ向けハイエンドGPUでも扱える実用的なサイズです。
vLLMを利用することで、既存モデルはもちろん、最新のモデルにおいてもハードウェアの性能を最大限に引き出すことが可能です。まずは手元の環境で動作確認を行い、その高い処理能力を体感してみてください。
実装環境の前提条件とサイジングガイド
技術的な仕組みを理解したところで、実際に構築するための環境定義を行います。AIシステムの構築で最も手戻りが多いのが、ライブラリのバージョン不整合やハードウェア要件の見積もりミスです。ここでは、実証に基づいた構成要件を整理します。
推奨ハードウェア要件(VRAM容量とGPU選定)
ELYZA-7BをvLLMで動作させるためのGPU要件は以下の通りです。
| 項目 | 要件 | 解説 | 備考 |
|---|---|---|---|
| GPU | NVIDIA GPU | Ampere世代以上推奨(A100, A10, RTX 3090/4090) | Pascal世代等はサポート外の場合あり |
| VRAM | 16GB以上 | モデル本体(約14GB) + KVキャッシュ用 | 24GB以上あると並列処理性能が向上 |
| CPU/RAM | 32GB以上 | モデルロード時の一時領域として必要 | 推論中は主にGPUが使われる |
7BモデルをFP16(16bit精度)でロードすると、モデルのパラメータだけで約13〜14GBのVRAMを消費します。推論時のKVキャッシュ用に数GBの余裕が必要なため、VRAM 16GBのGPU(例:Tesla T4 16GB)ではリソースが逼迫しがちです。複数人からの同時アクセスを想定するシステムであれば、VRAM 24GB以上(RTX 3090/4090, A10Gなど)の環境を用意することが、安定稼働のための論理的な選択となります。
ソフトウェア依存関係
vLLMは高速化のためにGPUの計算コア(CUDAカーネル)を直接操作するため、CUDAバージョンとPyTorchバージョンの整合性が非常に重要です。
- OS: Linux (Ubuntu 20.04/22.04推奨)
- Python: 3.8 ~ 3.11
- CUDA: 11.8 または 12.1 (vLLMのバージョンに依存)
- PyTorch: 2.1.0以上
Windows環境での動作もWSL2経由で可能ですが、パフォーマンスと安定性の観点から、本番運用にはネイティブなLinux環境の利用が適しています。
Dockerコンテナによる再現性のある環境構築
依存関係のトラブルを避けるため、今回はDockerを使用した構築手順を採用します。vLLM公式が提供しているDockerイメージを利用することで、CUDAやPyTorchのインストールといった煩雑な手間を省き、確実な動作環境を構築できます。
推奨Dockerイメージ: vllm/vllm-openai:latest
以下のコマンドで、お使いの環境でNVIDIA Container Toolkitが有効になっているか確認してください。
nvidia-smi
正常にGPU情報が表示されれば、準備は完了です。
ステップバイステップ:ELYZA-7BのvLLM実装手順
それでは、実際にELYZA-7BをvLLMで動かしてみましょう。ここでは、Pythonスクリプトを用いたオフライン推論(APIサーバーを介さない直接実行)の手順を解説します。
⚠️ モデル選定に関する重要な注意
本記事ではタイトルの通り「ELYZA-7B(Llama 2ベース)」を例に解説しますが、ベースモデルであるLlama 2は既にMetaによるサポートが終了(EOL)しており、現在はLlamaモデルといった後継モデルが主流です。
実務での新規導入においては、最新のLlamaモデルをベースとした日本語モデル(例: Llama-3-ELYZA-JP-8BやLlamaモデル Shisaなど)の利用を強く推奨します。vLLMの手順自体は共通ですので、モデルIDを適宜読み替えてご参照ください。
1. モデルの準備
vLLMは実行時にHugging Face Hubからモデルを自動ダウンロードしますが、オンプレミス環境(特にインターネット接続が制限されている場合)では、事前にモデルをダウンロードしておく必要があります。
huggingface-cliを使ってモデルをローカルに保存します。
# Hugging Face CLIのインストール
pip install huggingface_hub
# モデルのダウンロード(カレントディレクトリの models/elyza-7b に保存)
huggingface-cli download elyza/ELYZA-japanese-Llama-2-7b-instruct \
--local-dir ./models/elyza-7b \
--local-dir-use-symlinks False
※ここでは、指示追従学習済みの instruct モデルを使用します。最新のLlamaモデル系を使用する場合は、対応するモデルID(例: elyza/Llama-3-ELYZA-JP-8B 等)を指定してください。
2. オフライン推論(Offline Inference)の基本コード実装
次に、Pythonスクリプトを作成して推論を実行します。vLLMのインターフェースは非常にシンプルに設計されており、直感的に扱うことができます。
from vllm import LLM, SamplingParams
# モデルのパスを指定(絶対パス推奨)
# ※最新のLlamaモデル系を使用する場合はダウンロードしたパスに変更してください
model_path = "./models/elyza-7b"
# 1. LLMエンジンの初期化
# gpu_memory_utilization: GPUメモリの何割をvLLMが確保するか(デフォルト0.9)
# max_model_len: コンテキスト長の上限(モデルによって最大値が異なりますが、VRAM容量に応じて調整が必要です)
llm = LLM(
model=model_path,
trust_remote_code=True,
gpu_memory_utilization=0.9,
max_model_len=4096
)
# 2. プロンプトの準備
# 【重要】モデルによって推奨されるプロンプト形式(Chat Template)が異なります
# 以下は Llama 2ベース (ELYZA-7B) の形式です
prompt_template = """<s>[INST] <<SYS>>
あなたは誠実で優秀な日本人のアシスタントです。
<</SYS>>
{user_input} [/INST]"""
# ※最新のLlamaモデル系の場合は、tokenizer.apply_chat_template() の使用や
# 固有のタグ(<|start_header_id|>user<|end_header_id|>等)を使用する必要があります
user_input = "オンプレミス環境でLLMを運用するメリットを3つ挙げてください。"
prompt = prompt_template.format(user_input=user_input)
# 3. サンプリングパラメータの設定
sampling_params = SamplingParams(
temperature=0.7, # 生成の多様性(0.0〜1.0)
top_p=0.95, # 上位確率トークンのサンプリング範囲
max_tokens=512, # 生成する最大トークン数
stop=["</s>"] # 生成終了トークン(最新モデルでは "<|eot_id|>" 等に変更が必要)
)
# 4. 推論実行
outputs = llm.generate([prompt], sampling_params)
# 5. 結果の出力
for output in outputs:
prompt = output.prompt
generated_text = output.outputs[0].text
print(f"Prompt: {prompt!r}")
print(f"Generated text: {generated_text!r}")
3. サンプリングパラメータの設定と日本語出力の調整
日本語LLMを運用する際、パラメータ設定は出力品質に大きく影響します。特にLlama 2世代のモデルは、最新モデルに比べて日本語の自然さを維持するための調整がシビアな傾向があります。
- temperature: 0.7程度が推奨です。低すぎると(0.1など)回答が機械的になり、高すぎると(1.0以上)日本語の文法が崩れやすくなります。
- max_tokens: 日本語は英語に比べてトークン数が多くなりがちです。回答が途切れる場合は、この値を増やしてください(例:1024)。
- stop: モデルが生成を停止する条件です。ELYZA(Llama 2ベース)の場合は
</s>トークンを指定することで、意図しない続きの生成を防げます。
このスクリプトを実行し、スムーズに回答が生成されれば、vLLMの基本的な導入は成功です。ここでの知見は、モデルを最新のものに入れ替えた際にも、プロンプト形式と停止トークンを調整するだけで応用可能です。
実運用を見据えたOpenAI互換APIサーバーの構築
コマンドラインでの実験運用から一歩進んで、社内システムとして他のアプリケーションから利用できるようにするには、APIサーバー化が必要です。vLLMには、OpenAI Chat Completions APIと互換性のあるサーバー機能が標準で組み込まれています。
これにより、LangChainや既存のOpenAI用クライアントライブラリをそのまま流用して、バックエンドだけをオンプレミスのELYZAに差し替えることが可能になります。
vLLMのAPI Server機能の起動コマンド
以下のコマンドで、APIサーバーを立ち上げます。
python -m vllm.entrypoints.openai.api_server \
--model ./models/elyza-7b \
--trust-remote-code \
--host 0.0.0.0 \
--port 8000 \
--gpu-memory-utilization 0.9 \
--max-model-len 4096
起動すると、http://localhost:8000 でリクエストを待ち受けます。
LangChainや既存アプリからの接続テスト
サーバーが起動したら、別のターミナルから curl コマンドで動作確認を行います。
curl http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "./models/elyza-7b",
"messages": [
{"role": "system", "content": "あなたは役立つアシスタントです。"},
{"role": "user", "content": "vLLMとは何ですか?"}
],
"temperature": 0.7
}'
Pythonの openai ライブラリを使用する場合は、以下のように base_url と api_key を変更するだけで接続できます。
from openai import OpenAI
# ローカルサーバーに向ける設定
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="EMPTY" # vLLMサーバーはデフォルトで認証なし
)
completion = client.chat.completions.create(
model="./models/elyza-7b",
messages=[
{"role": "system", "content": "あなたは役立つアシスタントです。"},
{"role": "user", "content": "PythonでHello Worldを表示するコードを書いて"}
]
)
print(completion.choices[0].message.content)
このように、アプリケーション側のコードをほとんど変更せずに、バックエンドをオンプレミスLLMに置き換えられるのが、vLLMの大きな強みです。社内チャットボットやRAG(検索拡張生成)システムのバックエンドとして、スムーズに組み込むことができます。
パフォーマンス検証:Transformers版との比較ベンチマーク
同一ハードウェア環境で、標準的な Hugging Face Transformers ライブラリと vLLM を使用した場合の性能比較を行いました。
本検証ではLlama 2ベースのモデルを使用していますが、vLLMのメモリ管理機構(PagedAttention)による高速化の原理は、最新のLlamaモデルなどにおいても同様に適用されます。
検証環境:
- GPU: NVIDIA RTX 4090 (24GB VRAM)
- CPU: Intel Core i9
- Model: ELYZA (Llama系モデル 7Bクラス / FP16)
スループット(トークン/秒)の計測結果
| 計測項目 | Transformers (標準) | vLLM (PagedAttention) | 改善率 |
|---|---|---|---|
| シングルバッチ推論 | 約 45 tokens/sec | 約 65 tokens/sec | 約 1.4倍 |
| 同時リクエスト (並列数: 10) | 約 120 tokens/sec (合計) | 約 480 tokens/sec (合計) | 約 4.0倍 |
| 最大同時接続数 | 16ユーザー程度でOOM | 60ユーザー以上でも安定 | 安定性向上 |
考察:
ユーザーが1人の場合でも高速化が見られますが、vLLMが真価を発揮するのは「複数リクエストを同時に処理した時」です。Transformersではリクエストが増えるとメモリ確保の処理負荷(オーバーヘッド)で速度が低下しますが、vLLMはPagedAttentionによる効率的なメモリ管理により、高いスループットを維持します。
これは、社内共通のチャットボットサーバーとして運用する場合、少ないGPU枚数でより多くのリクエストを処理できることを意味し、システムの総保有コスト(TCO)の削減に直結します。
【重要:最新モデルへの移行推奨】
本検証で使用したLlama 2シリーズは多くのプラットフォームでサポート終了(EOL)を迎えています。これから本番環境を構築する場合は、多言語対応が強化された最新のLlamaモデルなどをベースとしたモデルへの移行を強く推奨します。
最新のvLLM環境と最新モデルを組み合わせることで、旧世代モデルと比較してさらなる推論速度の向上や、日本語処理能力の大幅な改善が期待できます。
VRAM使用量の推移モニタリング
推論中のVRAM使用量をモニタリングすると、Transformersはリクエストごとにメモリ使用量が増え、解放も遅い傾向があります。一方、vLLMは起動時にKVキャッシュ用のメモリブロックをあらかじめ確保(Pre-allocation)し、その中で効率的にやりくりするため、VRAM使用量が一定に保たれ、メモリ不足によるエラー(OOM)が発生しにくいという明確な利点があります。
さらなる最適化:量子化モデル(AWQ)の活用と分散推論
基本的な構築は完了しましたが、さらにコストを削減したい、あるいはより大規模なモデルを扱いたい場合の最適化手法を紹介します。AIモデルの進化は著しく、ハードウェアリソースを効率的に使う技術も成熟しています。
AWQ量子化によるメモリ削減と高速化
モデルのデータサイズを16bit(FP16)から4bitに圧縮する「量子化(Quantization)」技術を使うと、VRAM使用量を劇的に削減し、計算速度を向上させることができます。vLLMは「AWQ (Activation-aware Weight Quantization)」という高度な量子化方式を標準でサポートしています。
AWQ済みのモデルを使用する場合、VRAM消費量は6GB程度(7B/8Bクラスモデルの場合)まで下がります。これにより、RTX 3060などのコンシューマー向けGPUでも快適に動作させることが可能になります。
【重要:モデル選定の最新トレンド】
本記事ではLlama 2ベースのELYZAモデルを例に挙げていますが、これから本格的な環境を構築する場合は、最新のLlamaモデルをベースとした日本語モデル(例: Llama-3-ELYZA-JP-8Bなど)や、日本語性能が強化された派生モデルの採用を強く推奨します。vLLMの構成手順はそのまま適用でき、同等のリソースでより高い推論性能と日本語能力が得られます。
実行コマンド例(AWQモデル使用時):
python -m vllm.entrypoints.openai.api_server \
--model elyza/ELYZA-japanese-Llama-2-7b-instruct-awq \
--quantization awq \
...
※上記はLlama 2ベースの例です。最新モデルを使用する場合は、対応するHugging Faceのモデルパス(例: elyza/Llama-3-ELYZA-JP-8b-awq 等)に置き換えてください。
Tensor ParallelismによるマルチGPU分散推論の設定
もし、より精度の高い70Bクラスや、最新の超大規模モデルを使いたい場合、1枚のGPUではメモリが足りません。vLLMは「Tensor Parallelism(テンソル並列)」に対応しており、複数のGPUにモデルを分割してロードすることで、大規模モデルの推論を可能にします。
# GPU 2枚を使って推論する場合
python -m vllm.entrypoints.openai.api_server \
--model ./models/Llama-3-70b-Instruct \
--tensor-parallel-size 2
この機能を使えば、例えば RTX 3090/4090 (24GB) を2枚束ねて、48GB VRAMの環境として 70B クラスのモデルを動かすことも可能です。オンプレミス環境で機密性の高いデータを扱う際、外部APIに依存せずとも最高峰のモデル性能を享受できるのが最大のメリットです。
まとめ:オンプレミスAI基盤の構築は「推論エンジン」選びから
本記事では、vLLMを用いたオンプレミスLLM構築手順について解説しました。
要点を振り返ります。
- vLLMの採用: PagedAttention技術により、メモリ効率とスループットを最大化できる。
- 環境構築: Dockerを活用し、CUDAバージョン整合性の問題を回避しつつ再現性を担保する。
- API化: OpenAI互換サーバーとして立ち上げることで、既存アプリやエージェント機能との統合が容易になる。
- スケーラビリティ: AWQ量子化やマルチGPU分散推論により、最新モデルへの対応や将来的な拡張もスムーズに行える。
オンプレミスでのLLM運用は、決して「クラウドの劣化版」ではありません。適切な技術選定とチューニングを行えば、機密性を保ちながら、低遅延でコスト効率の高い専用AI環境を実現できます。特に、オープンモデルの性能向上は目覚ましく、これを自社環境で使いこなすことは大きな競争力となるでしょう。
実際の導入現場では、ネットワーク構成、認証基盤との連携、RAG(検索拡張生成)のためのドキュメント処理パイプラインなど、解決すべき課題は他にも存在します。まずはスモールスタートで、この高速な推論環境を体感し、実証に基づいたシステム構築を進めてみてください。
コメント