MLX vs ollama を M5 Pro で実測:Mac のローカル LLM、どっちのランタイムが速いか

by ZeroZawa

Mac でローカル LLM を動かそうとすると、最初の分かれ道で必ず同じ質問にぶつかります。mlx-lm で動かすか、ollama で動かすか。どちらも Apple Silicon の GPU を使い、どちらも 4bit 量子化のモデルを走らせます。なのに「MLX のほうが速い」「ollama で十分」という相反する声が、同じ熱量で飛んできます。

この記事では、その二択に雰囲気ではなく数字で答えます。同じモデル(Qwen2.5-Coder-7B)を、同じプロンプトで、同じ M5 Pro 48GB の上で両方走らせ、最初のトークンが返るまでの時間・生成速度・メモリを並べて測りました。結論を先に言うと、生のスループットでは測ったすべての軸で MLX が速いという結果でした。意外だったのは、かつて MLX の弱点とされてきた「最初のトークンまでの時間」ですら、M5 では MLX が ollama を上回ったことです。それでも選択が一択にならないのは、速さの数字に出てこない取り回しの差があるからです。そして測っている最中に、この問い自体が 2026 年に書き換わりつつあることにも気づきました。

同じモデルが mlx-lm と ollama の二つのランタイムに分岐する概念図

「どっちが速い」の前に、土俵が変わっていた

ベンチを組む前に、一つ確認しておくべきことがあります。2026 年 3 月 30 日、Ollama は Apple Silicon 上の推論エンジンを MLX に切り替えると発表しました1。これまで ollama の中身は llama.cpp の Metal バックエンドでした。切り替える理由は二つで、MLX のほうが定常的な生成が速いこと、そして M5 世代の Neural Accelerator という新しいハードウェアの恩恵を llama.cpp からは取りに行けないことです。

つまり「MLX vs ollama」という対立は、もう「MLX エンジン vs llama.cpp エンジン」と同義ではありません。ollama がどちらのバックエンドを使うかは、与えるモデルの形式で決まります。GGUF を渡せば llama.cpp(Metal)、safetensors を渡せば MLX、という振り分けです1。ただしこの振り分けの条件はバージョンによって挙動が違い、ユニファイドメモリの量で切り替わるという別の説もあります。ですから計測の前には、実際にどちらのバックエンドが動いたかを ollama ps の出力で確かめる必要があります。思い込みで「llama.cpp を測っているつもりが MLX だった」となると、比較そのものが崩れてしまいます。

本記事では、ollama 側に GGUF の qwen2.5-coder:7b-instruct-q4_K_M を渡しています。形式ベースの振り分けが効くなら ollama の中身は llama.cpp Metal になるので、比較は「mlx-lm 直(MLX)vs ollama(llama.cpp Metal)」として今も成立します。実際に計測中の ollama を ollama ps で確認すると、常駐サイズとその VRAM 載り量が一致していました(5.85GB がまるごと GPU 上、PROCESSOR は 100% GPU)。GGUF を渡したこのケースでは、MLX バックエンドではなく llama.cpp Metal が動いていたことになります。つまり以下の数字は、想定どおり MLX エンジンと llama.cpp エンジンの一騎打ちです。

同じモデルを、同じ条件で測る

フェアな比較は、「何を揃えたか」と「何は揃えられないか」を先に開示してこそ意味を持ちます。

揃えたものはこうです。モデルは Qwen2.5-Coder-7B の 4bit で固定し、MLX 側は mlx-community/Qwen2.5-Coder-7B-Instruct-4bit、ollama 側は qwen2.5-coder:7b-instruct-q4_K_M を使います。プロンプトは実際のコードベース(このブログのソース)を連結したコーパスから 4,096 トークンと 16,384 トークンの 2 段に切り出し、両ランタイムにまったく同じテキストを渡します。temperature は 0、生成は 256 トークン上限、各条件 3 回測って中央値を取ります。ollama 側は既定の context window が大きく取られる(48GB 機では数万トークンに設定されうる)ので、num_ctx を明示固定して MLX と KV キャッシュの前提を揃えました2。モデルは事前にロードして常駐させ、初回のロード時間が計測に混ざらないようにしています。

揃えられないものもあります。一つは量子化です。MLX の 4bit はグループサイズ 64 のアフィン量子化、ollama 側の Q4_K_M は一部のテンソルを 6bit に上げる混合精度で、実効ビット数は MLX が約 4.5bpw、Q4_K_M が約 4.89bpw とされています34。同じ「4bit」でも中身は別物で、Q4_K_M のほうがわずかに情報を多く残します。ですから速度差を「量子化が同じ前提」で読んではいけません。もう一つはメモリの定義です。MLX は生成中のピークを内部 API で直接返しますが、ollama 側にその対応物はありません。ollama については ollama ps が報告する常駐サイズ(重み+KV キャッシュ)を使うしかなく、これは「生成中の作業集合のピーク」とは測っている対象が違います。並べて表に載せはしますが、同じ物差しではありません。

計測は自作のハーネスで機械的に回しています5。前に書いた 48GB Mac のローカル LLM 記事で使った MLX 用の計測スクリプトに、ollama 用のランナーを足したものです。TTFT は両方ともストリームの最初のトークンが届くまでの実時間で測り、生成速度は ollama 側は eval_count ÷ eval_duration、MLX 側はライブラリが返す generation_tps を使います。一つだけ注意したのは、3 回繰り返すときに毎回まったく同じプロンプトを送ると ollama がプロンプトのプレフィックスをキャッシュしてしまい、2 回目以降の prefill が「ほぼ無料」になってしまう点です。MLX は毎回フルで処理し直すので、これを放置すると比較が ollama 有利に大きく傾きます。そこで各回の先頭に短い識別子を差し込んでキャッシュを外し、両ランタイムに毎回フルの prefill を強制しました。

実測環境は Apple M5 Pro / 48GB、macOS 26.5.1、mlx-lm 0.31.3、ollama 0.30.10 です。所要時間は、モデルのダウンロード(MLX 約 4.3GB + ollama 約 4.7GB)と計測あわせて 30 分ほどでした。重み自体は無料でも、回すには時間とディスクが要ります。

結果:最初のトークンまでと、生成の速さ

数字から出します。各条件 3 回の中央値です。

最初のトークンまでの時間 (TTFT)

Qwen2.5-Coder-7B 4bit / Apple M5 Pro 48GB・低いほど速い

MLX (mlx-lm)ollama (llama.cpp)
16,3844,096コンテキスト長 (tok)024681012141618↑ TTFT (秒)
指標MLX 4,096ollama 4,096MLX 16,384ollama 16,384
TTFT (s)2.193.299.9318.07
prefill (tps)1,9041,2771,655916
decode (tps)61.353.451.245.4
peak mem (GB)4.885.455.55.45

数字はいずれも各条件 3 回の中央値で、プロンプト長は実測で 4,067 / 16,354 トークンでした。

結果は予想よりはっきりしていました。最初のトークンまでの時間、プロンプト処理の速度、生成の定常速度、その測ったすべての軸で MLX が上回りました。両者とも ollama ps と内部計測で GPU 100% 稼働を確認しているので、これは CPU 落ちによる不公平ではありません。Qwen2.5-Coder-7B は 4bit で 5GB 前後に収まり、48GB の機体ではメモリ崖(スワップ)にはまったく届かないため、swap も pressure も両ランタイムで終始 normal でした。

最初のトークンの壁は、M5 で逆転していた

ここが、測ってみて一番意外だったところです。MLX の歴史的な弱点は、生成の定常速度ではなく prefill、つまり最初のトークンが返ってくるまでが llama.cpp より遅いことでした。M1 Max の頃には、短いプロンプトでも MLX のほうが体感で遅いという報告が複数ありました6。ところが M5 Pro では、その弱点だったはずの TTFT で MLX が ollama を引き離します。4,096 トークンで 2.19 秒 対 3.29 秒、つまり MLX が約 1.5 倍の速さです。16,384 トークンになるとその差はさらに広がり、9.93 秒 対 18.07 秒で約 1.8 倍になります。prefill のスループットで見ても MLX の 1,904 tps に対し ollama は 1,277 tps、長いほうでは 1,655 対 916 と、差は context が伸びるほど開いていきます。

これは Apple が示していた方向と一致します。M5 の各 GPU コアに組み込まれた Neural Accelerator は、Qwen3-14B-4bit で TTFT を M4 比 4.06 倍に短縮しており1、その恩恵は MLX の計算パターン専用の回路によるものです。llama.cpp の Metal バックエンドは、この回路を取りに行けません。ですから M1 から M4 を前提に書かれた「MLX は prefill が遅い」という通説は、少なくとも M5 Pro のこのモデルでは逆転しています。MLX の最大の弱点だったところが、M5 では最大の差がつく軸になりました。

生成スループットとメモリ

生成スループット (decode)

Qwen2.5-Coder-7B 4bit / Apple M5 Pro 48GB・高いほど速い

MLX (mlx-lm)ollama (llama.cpp)
16,3844,096コンテキスト長 (tok)0102030405060↑ decode (tok/s)

定常生成の速度差は、prefill ほど劇的ではありませんが一貫しています。MLX は 4,096 トークンで 61.3 tok/s、ollama が 53.4 tok/s で、MLX が約 1.15 倍です。16,384 トークンでも 51.2 対 45.4 で約 1.13 倍と、どちらの context でも MLX が一歩前に出ます。context が長くなると両者とも生成が遅くなるのは、prefill 済みの長い KV キャッシュを抱えながら次のトークンを出すためで、これはランタイムによらない物理的なコストです。

メモリは定義が違うので、慎重に読む必要があります。MLX のピークは生成中の作業集合のピークで、4.88GB から 5.5GB へ context とともに増えます。ollama 側の 5.45GB は ollama ps が返す常駐サイズ(重み+KV キャッシュ)で、num_ctx を 20,480 に固定しているため context によらずほぼ一定です。短いプロンプトでは ollama の固定確保のぶん見かけ上やや重く、長いプロンプトでは両者がほぼ並びます。物差しが違うので「どちらが省メモリか」を一言で断ずるのは避けますが、少なくとも 7B・4bit の範囲では、48GB に対してどちらも余裕で収まります。

公開ベンチ(M1〜M4)と、何が違ったか

数字を出すと、つい既存のベンチと比べたくなります。ですが鵜呑みにはできません。よく引かれる数値、たとえば M4 Pro 64GB で Qwen3-Coder-30B-A3B を回すと MLX が約 130 tok/s、ollama が 43 tok/s で約 3 倍、というのは7、モデルが MoE の 30B で、機種も M4 世代です。別の検証では「MLX は 3 倍速い、ただし context が 40K を超えるまで」という条件付きの結論も出ています8

本記事の数字は、機種が M5 Pro、モデルが 7B の dense、context は数千〜1.6 万トークンの固定という、まったく別の条件で測ったものです。ですから「○倍速い」を一般論として持ち出すのではなく、「この機種・このモデル・この context でこうだった」という形でしか比べられません。

それを踏まえた上で、一つだけ通説と食い違った点は記録に値します。公開ベンチの多くが前提にしてきた「MLX は decode は速いが prefill(TTFT)で llama.cpp に負ける」という構図は、M5 Pro のこのモデルでは成り立ちませんでした。MLX は decode だけでなく prefill でも勝ち、しかも TTFT の差は context が長いほど開きました。世代をまたいで引用されてきた「3 倍速い、ただし長い context では縮む」8という相対関係も、ここでは「長い context ほど MLX 有利が広がる」と逆向きに出ています。これは M5 の Neural Accelerator が prefill 側に効いていることの一次的な傍証で、M1〜M4 のベンチをそのまま M5 に当てはめると、最も古くて有名な弱点の前提を踏み外すことになります。

数字に出ない差

速度が拮抗するなら、選択を決めるのは取り回しのほうです。ここは実際に両方を動かしてみないと書けません。

ollama の強みは、モデルの管理が ollama pull 一発で済むことに尽きます。レジストリから名前で引けて、常駐やアンロードも勝手にやってくれます。一方 MLX は Hugging Face から safetensors を自分で落とす形になり、初回のダウンロードでは認証トークンを設定しておかないとレート制限で詰まることがあります。API の素直さでいえば、ollama は /api/chat に JSON を投げるだけで OpenAI 風のインターフェースも持つので、既存のコードに差し込みやすいです。MLX は Python から直接叩く分、計測のように細かい数字を取りたいときには内部のメトリクスにそのまま手が届きます。

常駐まわりには一つ罠があります。ollama のモデル常駐時間(keep_alive)を環境変数で延ばそうとしても、シェルで export しただけでは ollama のバックグラウンドサービスには届きません。サービスが見える場所に設定しないと効きません。こういう、ベンチの数字には出てこないけれど毎日触ると効いてくる差が、実際の選択を左右します。

どっちを選ぶか

速さだけを見るなら、M5 Pro でこのクラスのモデルを動かす限り、答えは MLX です。最初のトークンも、生成の定常速度も、MLX が一貫して上回りました。とりわけ大きなコンテキストを一度に食わせて応答を待つような使い方では、TTFT の差がそのまま体感差になります。長いコードベースを丸ごと渡して質問するエージェント的な用途ほど、MLX の prefill 優位が効いてきます。

それでも ollama を選ぶ理由は、速さの外にあります。ollama pull 一発でモデルが手に入り、常駐やアンロードを気にせず、OpenAI 互換の API で既存のツールにそのまま差し込めます。1.1〜1.5 倍の速度差より、この取り回しの軽さのほうが効く場面は多いはずです。とくに「とりあえず動かしたい」「複数のモデルを頻繁に切り替える」段階では、ollama の手軽さは数字に出ない価値を持ちます。ですから現実的な指針はこうなります。速度を絞り出したいなら MLX を Python から直接、まず動かして回したいなら ollama、という住み分けです。

ただし、この境界は固定ではありません。2026 年に入って ollama 自身が Apple Silicon の推論を MLX に寄せ始めた以上、safetensors を渡す経路では ollama の中身も MLX になり、エンジン由来の速度差は縮んでいきます。今回測ったのは GGUF を渡したときの llama.cpp Metal との比較であり、その前提が来年も同じとは限りません。ローカルで動かせること自体がまだ新しく、どちらのランタイムも数ヶ月前より確実に速くなっています。その上での「どっちが速いか」は、来年にはまた違う答えになっているでしょう。

参考文献

Footnotes

  1. Ollama is switching to MLX / MLX vs llama.cpp on Apple Silicon (yage.ai, 2026-03-31) - ollama の MLX 採用、形式ベースのバックエンド振り分け、M5 Neural Accelerator の TTFT 改善。 2 3

  2. Context length — Ollama docs - 既定 num_ctx が VRAM 依存であること、変更方法。

  3. Quantization for local LLMs — Q4_K_M, MLX-4bit (llamaperf) - Q4_K_M の実効 bpw と混合精度。

  4. GGUF vs MLX: A Deep Dive (ThinkSmart.Life) - MLX 4bit のアフィン量子化と Q4_K_M との非等価。

  5. 計測ハーネス(自作)。Qwen2.5-Coder-7B を MLX と ollama で同条件計測する companion スクリプト。

  6. Performance of llama.cpp on Apple Silicon M-series (llama.cpp Discussion #4167) - llama.cpp の M-series 実測スレッド。

  7. MLX vs Ollama on Apple Silicon 2026 — Real Benchmarks (Will It Run AI) - M4 世代の MLX/ollama 比較ベンチ。

  8. Apple’s MLX 3x Faster Than llama.cpp Until 40K (Towards AI, 2026-05) - context 依存で MLX の優位が縮小する点。 2