はじめに
しばらくの間、Ollamaをローカルで動かすLLMツールとして毎日使っていました。普通のアプリみたいにインストールして、起動してモデルを選ぶだけ。シンプルで余計なことを考えなくていいし、これで十分だと思ってたんですよね。
そんなとき、YouTubeで偶然あるビデオを見かけました。「vLLMを使えばローカルLLMの速度を40%上げられる」という内容で。その数字を見たとき、思わず動画を止めました。別に今の速度で不満があったわけじゃないんですが、自分がやってる方法にそんなに無駄が生まれてる可能性があるなんて、正直考えたこともなかったんです。それからvLLMを調べ始めました。
MacBookに乗り換えたときはまた別の発見があって、Apple Silicon向けのネイティブな推論フレームワーク MLX-LM というものがあって、Ollamaとは違うアプローチでメモリを活用できるんです。これも面白かったんですよね。
この記事は、そういった流れで実際に触ってみた記録です。vLLM(Nvidia GPU向け)とMLX-LM(Apple Silicon向け)の両方を、正直なところ「良かった点」も「困った点」も含めてまとめました。
まず知っておきたい:OllamaとLM Studio
vLLMとMLX-LMの話に入る前に、ローカルLLMを初めて触れる方にとって知っておいてほしいツールを2つ紹介しておきます。
Ollama は今やチャット専用のUIが付いていて、ターミナルを使わなくてもいいんです。インストールして起動するとモデルの一覧が表示されて、選ぶだけでダウンロードが始まり、終わったらそのままチャットできます。まだダウンロードしていないモデルでも、選択した瞬間に自動で取得してくれるので、難しい操作は何もありません。チャットUIの他にOpenAI互換APIも localhost:11434 で使えるので、コードに組み込むのも簡単です。
LM Studio(lmstudio.ai)も同じ感覚で使えます。モデルの検索・ダウンロード・チャットが全部アプリ内でできて、コマンドラインなしでも細かい設定を調整できます。GUIで全部完結させたい方にはこちらもおすすめです。
多くの方はOllamaかLM Studioで十分だと思います。ただ、servingの挙動を細かくコントロールしたい、自分でモデルを量子化したい、バッチ処理のパイプラインを本格的に組みたい、となるとどちらも少し物足りない部分が出てきます。そこでvLLMとMLX-LMです。
vLLM
vLLMが速い理由:PagedAttentionの話
vLLMはUC Berkeleyの研究チームが2023年に公開したフレームワークです。最初にペーパーを読んだとき、核心のアイデアが思ったより直感的で、何度か読み直してしまいました。
ちょっと背景から説明しますね。モデルが推論するとき、生成中のトークンごとに KVキャッシュ(key-valueキャッシュ)を保持する必要があります。従来の方法は、リクエストごとに連続したメモリ領域を最初に確保する方式でした。でも返答がどのくらい長くなるか事前には分からないので、最悪のケースを想定してメモリを確保するしかない。その結果として、VRAMの60〜80%が internal fragmentation と使われない memory reservation で無駄になっていたんです。
PagedAttention はOSの 仮想メモリとページング の仕組みをヒントにこれを解決しています。KVキャッシュを固定サイズの「ページ」に分割して、それらがメモリ上で連続して並んでいる必要をなくしました。必要になったときだけ新しいページを確保する。それだけでmemory wasteが4%以下まで下がります。
これはメモリの節約だけじゃないんです。同じVRAMでより多くのリクエストを並列処理できるようになる、つまりスループットが大幅に上がります。
もう一つ、継続的バッチ処理(continuous batching) もあります。従来のstatic batchingはバッチ全体が終わるまで次のリクエストを受け付けませんでしたが、vLLMは1つのリクエストが完了した瞬間に新しいリクエストをすぐに受け入れられます。複数のユーザーが同時に使うAPIサーバーを作るなら、これはかなり重要な機能です。
インストールと使い方
RTX 5070 Ti(16GB GDDR7、Blackwellアーキテクチャ)のマシンで動かしています。この容量なら7〜8BモデルはFP16でも問題なく動かせて、13Bは4-bit量子化すれば動きます。
インストールはシンプルです:
pip install vllm
動作環境:Python 3.9以上、CUDA 11.8以上、Nvidia GPU。
Pythonライブラリとして使う場合:
from vllm import LLM, SamplingParams
llm = LLM(model="Qwen/Qwen2.5-7B-Instruct")
sampling_params = SamplingParams(
temperature=0.7,
max_tokens=512,
)
outputs = llm.generate(
["supervisedとunsupervised learningの違いを説明してください"],
sampling_params,
)
print(outputs[0].outputs[0].text)
OpenAI互換APIサーバーとして起動する場合:
vllm serve Qwen/Qwen2.5-7B-Instruct --host 0.0.0.0 --port 8000
あとはOpenAI APIと同じように呼び出せます:
from openai import OpenAI
client = OpenAI(
api_key="dummy-key",
base_url="http://localhost:8000/v1"
)
response = client.chat.completions.create(
model="Qwen/Qwen2.5-7B-Instruct",
messages=[{"role": "user", "content": "FibonacciをPythonで実装してください"}]
)
print(response.choices[0].message.content)
LangChainでもLlamaIndexでも、OpenAI APIを使っているコードならほぼそのまま動きます。既存のプロジェクトへの差し込みがすごく楽でした。
大きいモデルを量子化して動かす場合:
# 量子化済みモデルを使う(AWQ 4-bit)
vllm serve Qwen/Qwen2.5-14B-Instruct-AWQ --quantization awq
# bitsandbytesでINT8
vllm serve meta-llama/Llama-3.1-8B-Instruct \
--quantization bitsandbytes \
--load-format bitsandbytes
GPUが複数あれば、Tensor Parallelismも1行で有効にできます:
vllm serve <model> --tensor-parallel-size 2
モデルが自動で分散されるので、追加の設定は不要です。
実際に使ってみて
スループットは本当に上がりました。バッチ処理でベンチマークしてみると、HuggingFace Transformersをそのまま使うより3〜4倍速い感じです。APIサーバーを立ち上げたらそのまま既存プロジェクトに組み込めるのも、正直かなり便利でした。
ただ完璧ではなくて。モデルの初回ロードに7Bで数分かかるのは、再起動のたびにちょっとストレスでした。新しいアーキテクチャのモデルがすぐ対応されないことがあるのも、タイミングによっては困ることがあります。
MLX-LM
Unified Memoryが思ったより効いてた
MLX-LMを試す前は、Mac上でもOllamaを使っていて、それはそれでちゃんと動いていました。でも自分でモデルを量子化したり、samplingの設定をいじったり、メモリのフットプリントを確認したりしようとすると、Ollamaでは少し手が届かない部分が出てきます。そこでMLX-LMに切り替えてみました。
Apple Siliconの特徴は Unified Memory Architecture(UMA) にあります。CPUとGPUが同じメモリプールを共有している構造です。普通のPCだとシステムRAMとGPUのVRAMが完全に分離されていて、モデルがVRAMに収まらないとすぐに詰まります。Mac M系列にはその境界がありません。搭載しているメモリをそのまま推論に使えます。
MacBook M3の16GBで試してみると、7B 4-bitモデルは余裕で動きました。モデル自体に4〜5GB程度使って、残りはシステムに回る感じです。実際に動かすまでここまで普通に動くとは思ってなかったです。
インストールと使い方
pip install mlx-lm
動作環境:macOS 13.5以上、Apple Siliconチップ(M1以降)。
コマンドラインで推論する場合:
mlx_lm.generate \
--model mlx-community/Qwen2.5-7B-Instruct-4bit \
--prompt "Transformerのattentionの仕組みを説明してください" \
--max-tokens 512
Pythonライブラリとして使う場合:
from mlx_lm import load, generate
model, tokenizer = load("mlx-community/Qwen2.5-7B-Instruct-4bit")
response = generate(
model,
tokenizer,
prompt="素数判定をするPythonの関数を書いてください",
max_tokens=512,
verbose=True,
)
print(response)
OpenAI互換APIサーバー:
mlx_lm.server --model mlx-community/Qwen2.5-7B-Instruct-4bit --port 8080
from openai import OpenAI
client = OpenAI(
api_key="dummy-key",
base_url="http://localhost:8080/v1"
)
response = client.chat.completions.create(
model="mlx-community/Qwen2.5-7B-Instruct-4bit",
messages=[{"role": "user", "content": "こんにちは!"}]
)
print(response.choices[0].message.content)
HuggingFaceからモデルを自分で変換する場合:
HuggingFaceの mlx-community にはすでに変換済みのモデルがたくさん公開されています。もし欲しいモデルのMLX版が見つからなければ、自分で変換できます:
mlx_lm.convert \
--hf-path Qwen/Qwen2.5-7B-Instruct \
--mlx-path ./Qwen2.5-7B-Instruct-4bit \
-q \
--q-bits 4
変換時はオリジナルのprecisionでモデル全体をロードできるだけのRAMが必要です。7Bモデルなら16GB以上が目安です。変換には10〜20分程度かかります。
実際に使ってみて
MLX-LMに対してはあまり期待していなかったんですが、良い意味で驚かされました。驚いたのは速度じゃなくて、セットアップのシンプルさでした。
CUDAなし、ドライバのバージョン問題なし、「CUDA 12.1はPyTorch 2.xと互換性あるの?」みたいな調査も不要です。pip install mlx-lm してモデルを取ってきて動かすだけ。ゼロからLLMがローカルで動くまで15分くらいでした。vLLMを最初にセットアップしたとき、CUDAの依存関係で夜を費やしたのと比べると、全然違う体験でした。
7B 4-bitモデルで1秒あたり15〜25トークンくらいの速度で、インタラクティブなチャットには十分です。大量のバッチ処理には向かないですが、日常作業には普通に使えます。MacBookのファンが推論中でもまったく回らないのも地味に嬉しくて、消費電力が専用GPUよりかなり低いです。
便利なツールたち
使い始める前に、自分のマシンでどのモデルが動かせるかを確認できるツールをまとめておきます。
ハードウェアチェックとモデル候補の確認:
- Can I Use LLM? - GPU/CPU/RAMを入力すると、動かせるモデルと適切な量子化レベルを提案してくれます
- LLM Checker - CLIでハードウェアをスキャンして、Ollamaと連携しながら動かせるモデルを教えてくれます
- VRAM Calculator - モデルと量子化フォーマットごとに必要なVRAMを計算できます
トークン生成速度の事前確認:
- LLM Token Generation Simulator - GPUとモデルの組み合わせでトークン生成速度をシミュレートできます
- GPU Benchmarks on LLM Inference - 実機での測定ベンチマーク結果をまとめたリポジトリです
比較まとめ
| Ollama / LM Studio | vLLM | MLX-LM | |
|---|---|---|---|
| 対応ハードウェア | Nvidia / Apple Silicon / CPU | Nvidia GPU(CUDA) | Apple Silicon |
| セットアップ難易度 | とても簡単 | 中程度 | 簡単 |
| スループット | 普通 | とても高い | 中程度 |
| 制御の細かさ | 低い | 高い | 高い |
| OpenAI互換API | あり | あり | あり |
| 量子化 | GGUF | AWQ, GPTQ, FP8, INT8 | 4-bit, 8-bit(MLX native) |
| 同時リクエスト | 普通 | 得意(continuous batching) | 制限あり |
| 向いている用途 | 誰でも、素早く始めたい | サーバー、本番環境 | Mac、開発用途 |
どれを選べばいい?
ローカルLLMを初めて試してみたい、何が必要かまだよく分からない:Ollama または LM Studio でいいと思います。何も考えなくても動きます。
Nvidia GPUがあって、複数ユーザーへの同時提供やバッチ処理をやりたい:vLLM です。OpenAI互換APIがそのまま使えて、スループットが高く、既存プロジェクトへの組み込みがほぼ手間なしです。
Mac M系列を使っていて、Ollamaより細かいコントロールがほしい:MLX-LM です。セットアップが簡単で、ユニファイドメモリを上手く活かせて、HuggingFaceの mlx-community に変換済みモデルが揃っています。
自分の場合は3つ全部を使い分けています。新しいモデルを素早く試したいときはOllama、MacBook上での日常作業にはMLX-LM、ドキュメント処理の大量バッチが必要なときはデスクトップのvLLMという感じです。
おわりに
色々試してみて一番驚いたのは、ベンチマークの数字でも機能の多さでもなくて、ローカルLLMを始めるハードルがここまで下がっていたということでした。
2年前なら、これはGPUサーバーやクラスターを持っている人の話でした。今は中程度のNvidia GPUかMac M系列があれば、どのデベロッパーでもできます。半日もあれば環境を整えられます。
まだ試したことがないなら、ぜひ一度触ってみてください。