9月20日、Terminal Bytesが「Ollama vs llama.cpp vs MLX on a Mac Studio, measured」と題した記事を公開した。この記事では、Mac Studio M3 UltraでOllama・llama.cpp・MLXの3つのLLM推論ランタイムを同一モデルで実測比較した結果が詳しく紹介されている。数値の差はそのまま「動くか動かないか」「APIが使えるか否か」という実用上の選択に直結する。
結論から:MLXが最速、Ollamaのメモリ消費には要注意
同記事の測定結果を先に示す。モデルはQwen3.5 9B(4bit量子化)、マシンはM3 Ultra(256GB統合メモリ)だ。
| ランタイム | 重みフォーマット | 生成速度 | メモリ使用量 |
|---|---|---|---|
| Ollama 0.32.13(GGUF) | Q4_K_M | 77.7 tokens/s | 15 GB |
| llama-bench build 10809 | Q4_K_M | 77.8 tokens/s | — |
| Ollama 0.32.13(MLX) | NVFP4 | 90.5 tokens/s | 9 GB |
| rapid-mlx 0.14.1 | 4-bit affine | 105.9 tokens/s | — |
| mlx-lm 0.31.3 | 4-bit affine | 107.5 tokens/s | 5.24 GB |
最速はmlx-lmの107.5 tokens/s、最遅はOllamaのGGUFパスの77.7 tokens/sで、差は約38%だ。
なお、llama-benchとrapid-mlxのメモリ欄が「—」となっているのは、これらのツールがollama ps相当のメモリ監視機能を持たず、今回の計測対象外だったためだ。
比較対象モデル「Qwen3.5 9B」について
今回の比較に使われたQwen3.5 9BはAlibabaが開発するQwenシリーズの最新世代モデルだ。従来のQwen2.5とは別系統で、Multi-Token Prediction(MTP)用の予測ヘッドを標準搭載しているのが特徴である。Hugging Faceのmlx-communityリポジトリでは4-bit affine量子化済みの重みが公開されており、mlx-lmから直接利用できる。
なぜ38%の差が生まれるのか
M3 Ultraのメモリバス帯域は約800 GB/sだ。生成フェーズでは、1トークンを出力するたびに全重みをメモリから読み出す必要があり、帯域がボトルネックになる。
記事での試算によれば:
- llama.cpp(GGUF、5.28 GB)× 77.8 tokens/s → 約440 GB/s(バス帯域の約55%)
- mlx-lm(MLX、6.0 GB)× 107.5 tokens/s → 約645 GB/s(バス帯域の約81%)
同じApple Siliconの統合メモリを使いながら、MLXのカーネルはllama.cppのMetalカーネルよりもバス帯域を効率的に使い切っている。ランタイムの差がそのまま速度差に直結している。
Ollamaの「MLXタグ」は何者か
ollama pull qwen3.5:9b-mlxで取得できるMLXタグは90.5 tokens/sと、GGUFタグとmlx-lmの中間に位置する。この数字の裏にある仕掛けが興味深い。
Ollama 0.32.6のリリースノートによれば、Qwen3.5のMLXエンジンではMTP(Multi-Token Prediction:多トークン予測)による投機的デコードが自動で有効になる。Qwen3.5が持つ小さな予測ヘッドが次の数トークンを先読みし、本体モデルが一括で検証する仕組みだ。正解すれば1パスで複数トークンを出力できる。
一方、mlx-lm 0.31.3はMTPパスを未実装、後述するrapid-mlxはベンチマーク時にデフォルトでオフにしている(マシン間で比較可能にするため)。つまりOllamaの90.5 tokens/sはMTP込みの数字であり、MLXカーネル単体の性能ではない。それでもmlx-lmに17 tokens/s届かない理由は、量子化形式(NVFP4 vs 4-bit affine)の違いなのか、Ollamaのサービング層のオーバーヘッドなのかは不明だと記事は述べている。
もう一点、プロンプト処理速度に奇妙な挙動がある。OllamaのMLXタグは34トークンのプロンプトを1回目26 tokens/s、2回目37 tokens/sで処理したが、同じMLX重みを使うrapid-mlxは512トークンを469ms(約1,091 tokens/s相当)でこなしている。Ollamaのプロンプト処理コストは、レート制限ではなく固定の起動コストだと著者は見ている。
rapid-mlxとmlx-lmの関係
表中に登場するrapid-mlxは、mlx-lmをベースにOpenAI互換APIサーバー機能を追加したラッパーツールだ。mlx-lmが提供するCLIインターフェースに対し、rapid-mlxはHTTPエンドポイントを持ち、既存のOpenAI APIクライアントからそのまま利用できる。今回の計測ではmlx-lmとの速度差は2%以内(107.5 vs 105.9 tokens/s)であり、APIが必要な場面では現実的な選択肢となる。
メモリが決定的な差になる場面
256GBマシンでは誤差の範囲だが、16GB Mac miniではランタイム選択の話ではなく動くか動かないかの話になる。
Ollamaはollama psで確認すると、GGUFタグで15 GB、MLXタグで9 GBを確保している。Qwen3.5 9BのモデルファイルはGGUFで6.6 GBしかないにもかかわらず、OllamaはデフォルトでKVキャッシュを262,144トークン分確保するためだ。このKVキャッシュがモデル本体より大きくなっている。
NAME ID SIZE PROCESSOR CONTEXT
qwen3.5:9b-mlx 203e30078279 9.0 GB 100% GPU 262144
qwen3.5:9b 6488c96fa5fa 15 GB 100% GPU 262144
mlx-lmは必要なぶんだけ動的にキャッシュを確保するため、ピークメモリは5.24 GBに収まる。メモリが逼迫しているなら、Ollamaでもnum_ctxを実際に使う値に設定することで削減できる。
Ollamaがダウンロードしたモデルはllama.cppで読めない
著者が~/.ollama/models/blobs内のGGUFファイルを直接llama-benchに食わせようとしたところ、エラーが出た:
llama_model_load: error loading model: error loading model hyperparameters:
key qwen35.rope.dimension_sections has wrong array length; expected 4, got 3
OllamaはQwen3.5向けに独自フォークのllama.cppでGGUFを生成しており、アップストリームのllama.cppと互換性がない。Ollamaがダウンロードしたモデルは、ファイル先頭4バイトは同じGGUFマジックでも、アップストリームでは使えないカスタムファイルだ。 llama-benchで計測したい場合はHugging Faceから別途ダウンロードする必要がある。
使い分けの指針
記事の結論をまとめると:
- 速度最優先かつCLI利用でよい →
mlx-lm。pip install mlx-lmとmlx-communityのHugging Faceリポジトリのモデル名だけで動く。Ollamaのモデルレジストリは使えなくなるが、速度は38%速く、メモリは3分の1以下だ - OpenAI互換APIが必要 →
rapid-mlx。mlx-lmと2%差でAPIサーバーを提供する - Ollamaを使い続けるなら → 必ず
-mlxタグを指定する。ディスク使用量は2.3 GB増えるが、メモリは6 GB減り、速度は16%向上し、MTPが自動で有効になる
なお「OllamaはGGUF処理が遅い」という従来の評価について、著者は今回の計測でOllama GGUFとllama-benchが77.7 vs 77.8 tokens/sで一致したことから再検討が必要だとしている。以前の27B規模のモデルでの差異については別途検証予定だという。
詳細はOllama vs llama.cpp vs MLX on a Mac Studio, measuredを参照していただきたい。