DEV Community

bigkijimon
bigkijimon

Posted on

M1 Max 64GBでローカルLLMは何tok/s出るか — 手持ち4モデルを実測したら「でかい方が速い」逆転が出た

4年前のM1 Max(64GB)で、いまローカルLLMは実際に何tok/s出るのか。ベンチマークサイトを探すとM4/M5世代の数字ばかりで、M1 Maxの行がまるで無い。無いなら測るしかない、と手持ちの4モデルを同じ条件で実測した。出てきた表には、直感に反する一行があった。ディスクで3.6倍でかいモデルが、小さいモデルより1.5倍速い。この記事はその実測と、なぜそうなるかの話。

数字はすべて自機(M1 Max 64GB / Ollama 0.30.8)の実測。各モデル3回の中央値で、憶測や他機からの流用はしていない。測れなかった項目は「測れなかった」と書く。

結論の表:手持ち4モデルの実測tok/s

計測条件は全モデル共通。/api/generateに同じ日本語プロンプトを投げ(num_predict=300, temperature=0.7, think=false)、レスポンスのeval_count ÷ eval_durationからdecode(生成)tok/sを算出。各3回の中央値をとった。計測前にGPU利用率0%・他の生成ジョブ無しを確認している。

モデル アーキ 総params active/token サイズ decode tok/s
qwen3.6 MoE 36.0B 約3B 23.9GB 60.4
qwen3.6-uncensored-cc MoE 34.7B 約3B 21.2GB 59.5
gemma4 dense 8.0B 8.0B 9.6GB 56.6
qwen3.5 dense 9.7B 9.7B 6.6GB 40.5

3回の値は順に、qwen3.6が60.4/60.1/60.5、uncensoredが59.5/59.6/59.1、gemma4が56.6/56.5/56.6、qwen3.5が40.6/40.5/40.5。振れ幅はどれも0.1〜0.5 tok/s と小さい。単発ではなく中央値なので信頼できる。いずれもQ4_K_M量子化。

表を上から見ると素直に読めない。一番サイズの大きいqwen3.6(23.9GB)が一番速く(60.4)、一番小さいqwen3.5(6.6GB)が一番遅い(40.5)。ディスク上のサイズと速度が逆順になっている。ここが本題だ。

なぜ大きい方が速いのか:decodeを決めるのは「active params」

LLMのdecode速度(1トークンずつ吐く速度)は、ざっくり「メモリ帯域 ÷ 1トークンで実際に読むパラメータのバイト数」で決まる。同じマシン=同じメモリ帯域なら、1トークンあたりに使うパラメータが少ないほど速い。

ここで効くのがMoE(Mixture of Experts)とdenseの違いだ。ollama showで中を見ると、アーキテクチャがはっきり分かれる。

  • qwen3.6qwen35moeexpert_count=256expert_used_count=8。総パラメータは36Bあるが、1トークンを作るとき、使うのは256個のExpertのうち8個だけ。実際に動くのは約3Bだ。
  • qwen3.5qwen35(denseにexpertキーは無い)。9.7Bを毎トークンぜんぶ使う。
  • gemma4gemma4、dense 8.0B。こちらも毎トークン8Bを使う。

つまり「1トークンぶんの実仕事量」は、qwen3.6が約3B、gemma4が8B、qwen3.5が9.7B。実仕事量の少ない順が、そのまま速い順。実測もその通りに並んだ。qwen3.6が3.6倍のディスクサイズを抱えながらqwen3.5より速いのは、24GBぶんの重みをストレージ(というより統合メモリ)に置いてはいるが、毎トークン読み出すのはその一部(約3B)だけだからだ。

4モデルのdecode tok/sを比較した横棒グラフ。上からqwen3.6(60.4・MoE24GB)、qwen3.6-unc(59.5・MoE21GB)、gemma4(56.6・dense9.6GB)、qwen3.5(40.5・dense6.6GB)。ディスクサイズの大きい順に並べても速度順と一致していない。
ディスクサイズの大きい順(上から)に並べても、decode速度の順と一致しない。速度を決めるのは総サイズでなく1トークンあたりの active params。MoEのqwen3.6は「でかいのに速い」。

dense同士は素直にサイズ順

MoEを別にすると、dense 2つは教科書通りに並ぶ。gemma4(8.0B)が56.6、qwen3.5(9.7B)が40.5。小さいdenseの方が速い。8.0B対9.7Bで約1.2倍の差だが、実測は56.6対40.5で約1.4倍開いた。パラメータ数の比より差が大きいのは、アテンション実装やKVキャッシュの扱いなどモデルごとの差が乗るためで、ここは「概ねサイズ順」とだけ言える。厳密な比例は主張しない。

逆に言えば、「軽いモデルが欲しい=ディスクサイズの小さいモデルを選ぶ」は、denseの中でだけ正しい。MoEを候補に入れた瞬間、その直感は崩れる。qwen3.6はqwen3.5の3.6倍のディスクを食うのに、速度では上回る。

prefill(プロンプト読み込み)は別の話

ここまではdecode(出力)速度。入力を読み込むprefill(prompt eval)は挙動が違うので分けて測った。

モデル prefill tok/s
gemma4 639
qwen3.6-uncensored 613
qwen3.6 543
qwen3.5 394

prefillはdecodeの10倍前後の速度が出る(入力トークンをまとめて並列処理できるため)。ここで一つ、計測の落とし穴を正直に書いておく。最初にqwen3.6のprefillを測ったら、他の8倍にあたる4876 tok/s という異常値が出た。明らかにおかしい。直前に同じモデルでdecodeを回していたため、プロンプトの一部がキャッシュに残っていて「読み込み済み」扱いになったのが原因だ。ユニークなプロンプトで測り直したら543 tok/sに落ち着いた。キャッシュが効くと速度計測は簡単に嘘をつく。だからprefillは毎回新しい入力で測るべきだ(上の表は測り直した値)。

M1 Maxという「空白」について

そもそもこの計測を始めた動機は、ベンチマークサイトを探してもM1 Maxの数字が出てこなかったことだった。新しいモデルのtok/s一覧はたいていM4 Ultra / M5 Max / M4 Maxで埋まっていて、2021年のM1 Maxの行は空白か、あっても出典の怪しい単発値だ。中古で64GBのM1 Maxを買おうか検討している人にとって、これは判断材料が無いに等しい。

今回の数字はあくまで自機1台・M1 Max 64GB・Q4_K_M・Ollama 0.30.8という一点の実測で、一般化はしていない。それでも、「4年前のM1 Maxでも、active 3BのMoEなら60 tok/s、8Bクラスのdenseで40〜57 tok/s出る」という一点は、空白よりはるかにマシな手がかりになるはずだ。体感で言えば、60 tok/sは読む速度より速く出力が流れ、40 tok/sでも待たされる感覚はほぼ無い。ローカルで実用に足る。

再現できる学び

  1. decode速度はディスクサイズでなくactive params/tokenで決まる。モデル選びで「軽い=速い」と思ったら、まずMoEかdenseかを見る。MoEは「でかいのに速い」がありうる。
  2. 速度計測はキャッシュに注意。特にprefillは、同じプロンプトを続けて投げると前回のキャッシュで異常に速い値が出る。毎回ユニークな入力で測る。
  3. 数字は3回の中央値で。単発だと外れ値を掴む。今回は振れ幅0.1〜0.5に収まったので、この4つの値は信頼していい。

手元の環境(機種・OllamaやMLXのバージョン・量子化)が違えば数字は変わる。もしM1 Maxで別モデルを回している人がいたら、その実測値を知りたい。特にMoE系(qwen3.6の他)と、量子化を変えたときのtok/sは、M1 Max世代の情報がまだ足りていない。

Top comments (0)