統合メモリ構成とグラボ構成を比べた回で、ひとつ宿題が残っていました。-ngl 99 を付けると起動に失敗し、省略すると llama.cpp が勝手に載る分だけ載せてくれて 44.2 tok/s 出る——ここまでは分かったのですが、その先の「自分で細かく指定する」領域は手つかずだったのです。
ローカルLLMには 「モデルのどの部分をGPUに置き、どの部分をCPU側のメモリに逃がすか」を手で指定する仕組みがあります。今回はそこに踏み込みます。
そして、確かめたい問いがもうひとつ。前回まで見てきたとおり、手元には性質の違う3つの構成があります。統合メモリのApple M4、同じく統合メモリのRadeon 780M、そして専用VRAMを持つRTX 3060。「メモリの持ち方」が違うと、この指定の効き方も変わるのでしょうか。
・llama.cppの3つの指定手段(
-ngl / -ot / --n-cpu-moe)が実際に何をしているのか・★統合メモリなら逃がしても損は小さい、という予想が外れた話
・★M4では専門家をCPUへ回した瞬間、全部CPUに置くより10倍遅くなった
・その原因を突き止めるまで(外れた仮説も含めて)
・★真犯人はmmap。
--no-mmap で6.6倍まで回復した——警告は最初から出ていました・32GBのMacは30B級のMoEをQ6でも丸ごと抱えられる
「自分で決める」領域が残っていた
大きなモデルを動かすとき、GPUのメモリに全部は載りません。そこで llama.cpp は載る分だけGPUに置き、残りをCPU側に回すという折衷をします。既定ではこれを自動でやってくれます。
ただ、この自動配分は「レイヤー(層)単位」で行われます。バイト単位ではありません。そして1トークン生成するたびに全部の層を通るので、CPU側に置かれた層があるとそこで足を引っ張られます。
「もっと賢い置き方があるのでは?」——そう思うのが自然です。実際、llama.cpp にはもっと細かく指定する手段が用意されています。今回はそれを実測で確かめました😊
用語集
| 用語 | 意味 |
|---|---|
| オフロード | 本来GPUで動かしたいものをCPU側へ「逃がす」こと。GPUのメモリに収まらないときの逃げ道です |
| 統合メモリ | CPUとGPUが同じメモリを分け合う作り。Apple Siliconや内蔵GPUがこの形で、専用VRAMを持ちません |
| 専用VRAM | グラフィックボードが自前で持っているメモリ。メインメモリとは物理的に別物で、間をPCIeという通り道でつなぎます |
| tg(生成) | 返事を1文字ずつ書く速度(tok/s)。体感速度に直結。メモリ帯域が主役の処理 |
| pp(読解) | 読ませた文章をまとめて処理する速度。演算力が主役 |
| MoE | Mixture of Experts。たくさんの「専門家」を用意しておいて、1回の処理では一部だけを使う作り。容量は大きいのに動く量は少なくて済みます |
| 専門家(expert) | MoEの中の部品。今回のモデルは全体で30B規模ですが、1トークンあたり動くのは3B相当だけです |
| テンソル | モデルを構成する数値のかたまり。ひとつひとつに名前が付いていて、名前で指定して行き先を変えられます |
| 量子化(Q4 / Q6) | モデルの数値を粗くして容量を減らすこと。数字が小さいほど軽く、粗くなります |
| mmap | ファイルを「読み込む」のではなく「メモリ上にあることにする」仕組み。実際に触った部分だけが読まれるので、起動が速くなります |
| スワップ | メモリが足りなくなったとき、中身をディスクへ一時退避すること。退避したものを使うたびに読み直すので、極端に遅くなります |
指定の手段は3つある
llama.cpp で配置を指定する方法は、大きく3つです(バージョン b10090 で確認)。
| オプション | 何をするか |
|---|---|
-ngl N | GPUに置く層の数を指定。既定は auto で、空きを見て自動で決めます |
-ot( --override-tensor) | テンソルの名前を正規表現で指定して、行き先を個別に変える。いちばん細かく指定できます |
--n-cpu-moe N( -ncmoe) | 先頭N層ぶんの「専門家」だけCPUへ。MoE向けの近道です |
ここで大事なのが、-ngl と後ろの2つでは「切り方」が違うことです。
MoEなら効くはず、という理屈
なぜ「中身で縦に切る」のがMoEと相性がいいのか。ここがこの記事の出発点なので、丁寧に書きます。
MoEというのは、たくさんの「専門家」を用意しておいて、1回の処理ではそのうち一部だけを使う作りです。今回使ったモデル(Qwen3-30B-A3B)は全体で30B規模ですが、1トークンあたり実際に動くのは3B相当だけです。
ここに面白いズレがあります。
容量の大部分を占めるのは専門家なのに、1トークンで動くのはそのごく一部。逆に「毎回必ず使う部分(注意機構など)」は小さい。
ならば 「小さくて毎回使う部分をGPUに、大きくてたまにしか使わない部分をCPUに」 が最適な配置になるはずです。これが --n-cpu-moe の狙いです。
「逃がす先」が構成によって違う
ただし、いま書いた理屈には隠れた前提があります。「VRAMとRAMが別物である」という前提です。
・M4と780M(統合メモリ)はほぼ同じ挙動になる。逃がす先が同じ器だから
・RTX 3060だけ違う結果になる。VRAMとRAMが物理的に別だから
これはあくまで予想です。前々回も予想が外れて、それが記事のいちばん面白い部分になりました。今回も外れたらそのまま書きます。
検証の設計と、始める前に崩れた前提
測定条件はp960・p962と揃えました。プロンプト512トークン/生成128トークン/3回平均です。モデルは Qwen3-30B-A3B-Instruct-2507(48層)。
モデルのサイズ選びには理屈があります。3つの構成すべてで「分割が起きる」サイズを選ばないと、「設定が効かなかった」のか「そもそも分割が起きていない」のか区別できません。そこでQ6_K(23.36GiB)を選びました——M4の上限が約24GBだと想定していたためです。
llama.cpp が報告するM4のGPUメモリ上限は 25,559 MiB(約24.96 GiB)。想定の24GBより多く、Q6_K は丸ごと載ってしまいます。
実際
-v で確認すると offloaded 49/49 layers to GPU。32GBのMacは30B級のMoEをQ6でも抱えられるわけです(12GBのRTX 3060・16.28GBの780Mでは載りません)。そこでMac側は「載らないから分割される」ではなく、わざと分割させて、その代償を測る方針に切り替えました。
Mac(M4)の結果
まず数字を出します。tg(生成速度)が体感に効く数字です。
| 設定 | pp512 | tg128 | 意味 |
|---|---|---|---|
| 自動フィット | 375.44 | 38.62 | おまかせ |
-ncmoe 0 | 392.12 | 37.77 | 全部GPU |
-ncmoe 8 | 205.13 | 33.31 | |
-ncmoe 16 | 136.29 | 31.96 | |
-ncmoe 24 | 97.33 | 24.89 | 半分 |
-ncmoe 32 | 40.29 | 12.34 | |
-ncmoe 40 | 17.51 | 6.19 | |
-ncmoe 48 | 13.86 | 2.53 | 専門家を全部CPU |
-ngl 0 | 38.08 | 25.76 | 全部CPU(比較の基準) |
Qwen3-30B-A3B-Instruct-2507 Q4_K_M(17.28 GiB)/Apple M4・llama.cpp b10090(Metal)
混ぜると、どちらの極端よりも遅くなります。
全部GPU=37.77、全部CPU=25.76。ところが「専門家だけCPU」は2.53——全部CPUに置くより10倍遅いのです。
「一部をGPUに残しているのに、全部CPUより遅い」。これは直感に反します😳
グラフにすると、落ち方がよく分かります。
もうひとつ、モデルが大きいほど落ち方が急になります。同じ設定でも、Q6_K(23.36GiB)では比べものにならない落ち方をしました。
| 設定 | Q4_K_M(17.28GiB) | Q6_K(23.36GiB) |
|---|---|---|
| 全部GPU | 37.77 | 31.41 |
-ncmoe 8 | 33.31 | 20.47 |
-ncmoe 24 | 24.89 | 1.67 |
-ncmoe 48 | 2.53 | 0.35 |
| 全部CPU | 25.76 | 21.69 |
単位はいずれも tg(生成)tok/s。0.35 tok/s は1トークン出すのに約3秒で、この1条件の測定に約18分かかりました
23.36GiBのQ6_Kを全部CPUで動かすと 21.69 tok/s。ちゃんと使える速度です。
つまり「32GBのMacにこのモデルは大きすぎる」わけではありません。混ぜたときだけ壊れる——問題はサイズではなく置き方だ、ということです。
ついでに分かったこと
--n-cpu-moe 48と-otの正規表現指定は同じ結果(2.53 と 2.54)。つまり--n-cpu-moeは下の書き方を省略できるようにしたもの、という関係が実測で確かめられました-ot '\.ffn_(up|down|gate)_exps\.=CPU'
- Denseなモデルでは
--n-cpu-moeは黙って無視される。Qwen2.5-Coder の 7B に-ncmoe 8(17.39 → 18.48)、14B に-ncmoe 24(10.65 → 10.97)を付けても、いずれも誤差の範囲です。エラーも警告も出ませんので、効いているつもりで効いていない事故が起こり得ます - 発熱のせいではありません。1時間ぶん回した後に最初の条件を測り直したところ 37.77 → 39.78 と、むしろ僅かに速くなりました
外れた仮説:コピーのせいではなかった
さて、なぜこんなことになるのか。最初に立てた仮説はこうでした。
llama.cpp には --op-offload という既定ONの設定があって、「重みはCPU側にあるが、計算はGPUに投げる」という動きをする。だとすると毎トークン、専門家の重みをGPUへコピーしているのではないか。専門家は約16GBあるので、毎回運んでいれば桁は合う。
筋は通っています。というわけで -nopo 1 で切ってみました。
| 設定 | op-offload | tg128 |
|---|---|---|
-ncmoe 48 | ON(既定) | 2.46 |
-ncmoe 48 | OFF | 2.15 |
-ncmoe 24 | ON(既定) | 24.89 |
-ncmoe 24 | OFF | 20.73 |
-ngl 0 | ON(既定) | 25.76 |
-ngl 0 | OFF | 29.82 |
外れました。 切っても改善しないどころか、混在配置ではむしろ僅かに遅くなっています。--op-offload は犯人ではなく、むしろ助けていたわけです。
(余談ですが、全部CPU(-ngl 0)のときだけは切ったほうが速いのが面白いところです。25.76 → 29.82。GPUに投げる判断が空振りしていた分が消えた、と読めます。CPUだけで動かすつもりなら --no-op-offload を付けると1割ちょっと得をする、という実用的な話でもあります)
原因:片方に寄せたつもりで、両方に居座っていた
仮説が外れたので、ロード時のログを見ることにしました。-v を付けると、どのバッファに何バイト確保したかが出ます。
全部GPUに載せた場合:
load_tensors: offloaded 49/49 layers to GPU
load_tensors: CPU_Mapped model buffer size = 166.92 MiB
load_tensors: MTL0_Mapped model buffer size = 17691.34 MiB
合計 ≒ 17.4 GiB
専門家をCPUへ逃がした場合(-ncmoe 48):
load_tensors: offloaded 49/49 layers to GPU
load_tensors: CPU_Mapped model buffer size = 166.92 MiB
load_tensors: CPU_REPACK model buffer size = 16740.00 MiB ← CPU向けに並べ替えた実体
load_tensors: MTL0_Mapped model buffer size = 17583.34 MiB ← Metal側は依然ほぼ全体を保持
合計 ≒ 34.3 GiB ← 物理32GBを超えている
これが答えでした。
① CPU側はCPU向けに並べ替えた実体を新たに確保する(16.7GB)
② ところがMetal側は元のマップをほぼ全量そのまま保持している(17.6GB)
③ 合計34.3GBで物理32GBを突き破る。しかもMetal側は固定されていて追い出せないので、追い出せる側=CPU側の実体がディスクへ退避される
④ 退避したものを毎トークン読み直すので、極端に遅くなる
実際、測定中のシステムの状態を記録すると、はっきり出ていました。
| 状況 | 固定されたメモリ | スワップ(ディスクへの退避) |
|---|---|---|
| 何もしていないとき | 2.20 GB | 4GB確保 / 2.45GB使用 |
Q4_K_M -ncmoe 24 | 21.07 GB | 4GB確保 / 2.63GB使用 |
Q6_K -ncmoe 24 | 25.85 GB | 12GBまで拡張 / 11.27GB使用 |
Q6_K -ncmoe 48 | 25.49 GB | 23.5GBまで拡張 / 22.04GB使用 |
22GBもディスクへ退避していたのです。これでは速いはずがありません。「モデルが大きいほど落ち方が急」だったのも、器(32GB)を突き破るのが早いからと考えれば筋が通ります。
なぜ「全部CPU」なら平気なのか
ここで疑問が湧きます。全部CPUに置いたときも、CPU向けの実体は作られるはずです。なのになぜそちらは平気なのでしょう。
プロセスが実際に使ったメモリを測ると、答えが出ました。「固定されていて追い出せないメモリ」と「退避できるメモリ」を分けて見るのがコツです。
| 条件 | 退避できるメモリ | 固定されたメモリ | 合計 | スワップ |
|---|---|---|---|---|
| 全部GPU | 0.16 GB | 14.80 GB | 約15.0 GB | 2.7 GB |
| 全部CPU | 17.18 GB | 2.42 GB | 約19.6 GB | 2.7 GB |
-ncmoe 24 | 8.33 GB | 19.27 GB | 約27.6 GB | 2.7 GB |
-ncmoe 48 | 16.49 GB | 19.17 GB | 約35.7 GB | 10.3 GB |
MoE Q4_K_M(17.28GiB)/生成8トークンのみの短時間実行で計測
全部CPUのときは、固定されたメモリが2.42GBしかありません。 Metalを使っていないので、固定するものが無いのです。だからOSは残りを自由にやりくりでき、19.6GBに収まります。
ところが混在させると、Metal側が19GBを固定したままになります。「専門家はCPUに置いた」はずなのに、です。固定された19GBは動かせないので、しわ寄せは退避できる側=CPUの実体に全部いきます。合計35.7GBで32GBを超え、10GBがディスクへ落ちる——これが正体でした。
図Aで描いたとおり、統合メモリはCPUとGPUが同じメモリを分け合います。だから逃がしても引っ越しは起きないはずだった。
ところが実装のうえでは、片方に寄せたつもりで両方に居座っていた。「同じメモリを使っている」ことと「llama.cppがそう扱ってくれる」ことは別だったわけです。
Windows(780M / RTX 3060)の結果
ここまではMacの話でした。同じことを、同じマシンの中で内蔵GPUと外付けグラボを切り替えながら測ってもらいました。Windows側は llama.cpp の Vulkan 版を使います。
まず結果を出します。
| 設定 | RTX 3060 (専用VRAM 12GB) | Radeon 780M (統合メモリ 16.28GB) |
|---|---|---|
| 自動フィット | 34.43 | 17.16 |
-ncmoe 16 | 起動失敗 | 14.81 |
-ncmoe 24 | 30.10 | 13.13 |
-ncmoe 32 | 25.72 | 12.48 |
-ncmoe 40 | 21.80 | — |
-ncmoe 48 | 18.93 | 11.97 |
| 48→24 の変化 | +59% | +10% |
MoE Q4_K_M(17.28GiB)/単位は tg(生成)tok/s
予想どおりでした。 専用VRAMのRTX 3060では設定を変えると大きく動き(+59%)、統合メモリの780Mではほとんど動きません(+10%)。Q6_Kに至っては780Mは+6%でほぼ横ばいでした。
理屈も素直です。780Mでは「GPUに置く」も「CPUに逃がす」も行き先が同じDDR5メモリなので、そもそも移動していないに等しい。だから数字が動かない。一方RTX 3060では、GPU側はGDDR6、CPU側はPCIe越しのDDR5と物理的に別の器なので、どちらに置くかが直接速度に出ます。
ところが、2台の統合メモリ機は正反対だった
ここで、3つを並べてみます。
| 構成 | メモリの持ち方 | 自動フィット | -ncmoe 48 | 変化 |
|---|---|---|---|---|
| Apple M4 | 統合メモリ | 38.62 | 2.53 | −93% |
| Radeon 780M | 統合メモリ | 17.16 | 11.97 | −30% |
| RTX 3060 | 専用VRAM | 34.43 | 18.93 | −45% |
「780MとRTX 3060は違う挙動になる」——これは当たり。
「M4と780Mは統合メモリどうしだから似た挙動になる」——これは大外れ。いちばん違ったのがM4でした。
同じ「統合メモリ」なのに、片方は設定がほとんど効かず、もう片方は設定で壊れる。これでは説明がつきません😳
説明のカギは、GPUメモリの使用量にありました。-ncmoe 48(専門家を全部CPUへ)を指定したとき、それぞれのGPUが実際に確保した量です。
| 構成 | GPUの窓口 | GPUが確保した量 |
|---|---|---|
| Radeon 780M | Vulkan | 1,166 MB |
| RTX 3060 | Vulkan | 1,137 MB |
| Apple M4 | Metal | 17,583 MiB |
Windowsの2台は、逃がした分だけきちんと減っています。 専門家をCPUに置いたのだから、GPU側に残るのは1.1GBほど——当たり前の挙動です。統合メモリの780Mも、専用VRAMのRTX 3060も、そこは同じでした。
Macだけが、17.6GBを抱えたままでした。
つまり、Macで起きていたことは「統合メモリだから」ではありませんでした。同じ統合メモリの780Mは普通に振る舞っています。MacのGPUを動かす窓口(Metal)の側の事情だったわけです。
真犯人はmmapだった(そして警告は最初から出ていた)
Windows側の報告に、見逃せない一文がありました。--n-cpu-moe を使うと llama.cpp がこんな警告を出す、というのです。
llama_model_loader: tensor overrides to CPU are used with mmap enabled
- consider using --no-mmap for better performance
「テンソルの行き先をCPUに変える指定をmmap有効のまま使っています。性能のために --no-mmap を検討してください」。
Macのログを見返しました。出ていました。 最初から、毎回。読み飛ばしていたのはこちらでした😅
そこで --no-mmap を付けて測り直したところ、バッファの内訳がこうなりました。
| バッファ | 既定(mmapあり) | --no-mmap |
|---|---|---|
| CPU(並べ替え済みの実体) | 16,740 MiB | 16,740 MiB |
| Metal側 | 17,583 MiB | 784 MiB |
| 合計 | 約34.3 GiB | 約17.3 GiB |
Metal側が17.6GBから784MBに落ちました。 Windows(1,137MB / 1,166MB)とほぼ同じ水準です。二重確保が消え、実行中の固定メモリも25GB前後から3.29GBに、スワップも通常の水準に戻りました。
mmapは「ファイルをメモリ上にあることにする」仕組みです。llama.cppはこれを使ってモデルを素早く読み込みます。
ところがMetalバックエンドは、そのマップ全体をひとかたまりのGPUバッファとして掴みます。中の一部をCPUに移したところで、掴んだ範囲は変わりません。
だから「専門家はCPUに置いた」つもりでも、Metal側はモデル全体を抱えたまま。そこにCPU側の実体が加わって、二重になっていた——というわけです。
速度も、当然のように戻りました。
| 設定 | 既定(mmapあり) | --no-mmap | 改善 |
|---|---|---|---|
| 自動フィット | 38.62 | 40.29 | +4% |
-ncmoe 24 | 24.89 | 29.50 | +19% |
-ncmoe 48 | 2.53 | 16.69 | 6.6倍 |
ただし、直しても2つの事実が残りました
ここで終われば「めでたし」なのですが、直した後の数字をよく見ると、まだ腑に落ちない点が2つあります。
ひとつめ。--no-mmap で直したあとのM4は、780MではなくRTX 3060寄りの振る舞いをします。
| 構成 | メモリの持ち方 | -ncmoe 48→24 の変化 |
|---|---|---|
Apple M4(--no-mmap) | 統合メモリ | +77% |
| RTX 3060 | 専用VRAM | +59% |
| Radeon 780M | 統合メモリ | +10% |
この図が、今回の検証のすべてです。紫(780M)はほぼ真横——設定を動かしても変わりません。青(RTX 3060)は素直に右肩上がり。そして緑の破線(--no-mmap にしたM4)は、青にぴったり重なります。赤(既定のM4)だけが左端で崩れ落ちている、という構図です。
mmapの問題を取り除いてもなお、統合メモリどうしのM4と780Mは似ませんでした。 似ているのは、むしろM4とRTX 3060のほうです。
そう考えると、効き方を決めているのは「統合メモリか専用VRAMか」ではなく、GPU側とCPU側の実力差がどれだけ開いているかだと読めます。780Mは内蔵GPUが非力でCPUとの差が小さいので、どちらに置いてもさほど変わらない。M4はGPUが強いぶん、CPUへ逃がすと素直に損をする。RTX 3060はVRAMとPCIe越しのRAMという差がある——理由は違っても、「差が大きければ設定が効く」という一点で説明がつきます。
ふたつめ。直した後でも、混ぜると「全部CPU」より遅いままです。
| Mac(M4)の置き方 | tg |
|---|---|
全部GPU(--no-mmap) | 40.29 |
全部CPU(--no-op-offload付き) | 29.82 |
| 全部CPU | 25.76 |
混在(-ncmoe 48 --no-mmap) | 16.69 |
二重確保が消えても、混在はどちらの極端より遅いままでした。--no-op-offload を足しても17.23で、ほとんど変わりません。
残っているのはおそらく1層ごとにGPU側とCPU側を行き来する、その切り替えそのもののコストです。48層を毎トークン通るので、回数がそのまま効いてきます。ただしこれは数字から逆算した解釈で、切り替えの回数や時間を直接測ったわけではありません——そこは正直に書いておきます。
実務の使い分け
3構成を測って分かったことを、使い方の形にまとめます。
| やりたいこと | 選ぶべき設定 |
|---|---|
| とにかく速く | -ngl を省略して自動フィットに任せる。3構成すべてで自動が最速でした |
| VRAMを他の用途に空けたい | --n-cpu-moe を上げる(RTX 3060なら48で1.1GBまで削減。速度は約半分) |
| 起動を速くしたい | --n-cpu-moe を上げる(780Mで78.8秒 → 6.4秒。GPUへ送る量が減るため) |
| 限界まで詰めたい | -ot で個別指定。ただしKVキャッシュのぶんを残すこと |
| Macで逃がすなら | 必ず --no-mmap を付ける |
| 統合メモリ機(780M)で | チューニングの効果は小さい。自動フィットで十分 |
「載る」と「使える」は別物
もうひとつ、Windows側で出た大事な教訓です。
- 780Mでは
-ncmoe 48で、前回載らなかったQ4_K_Mが載りました。「設定次第で載せられる」は事実です。ただし載っても速くはなりません(11.97 < 自動フィットの17.16)。載せること自体が目的になると、むしろ遅くなります - RTX 3060では逆に、詰めすぎると落ちました。
-ncmoe 16は重みこそVRAMに収まるものの、KVキャッシュを置く余地が無くなって起動に失敗します。チューニングの上限は「重みが入る限界」ではなく「KVキャッシュぶんを残した位置」です
条件が完全には揃っていないこと
正直に書いておきます。Mac側とWindows側では、llama.cppのバージョンもバックエンドも違います(Mac=Homebrew b10090 / Metal、Windows=LM Studio同梱 2.25.2 / Vulkan)。ですので「Metalだからこうなる」と言い切るには、本当は同じ版で揃えたいところです。
ただ、Mac側で --no-mmap を付けるだけで挙動がWindows側と揃ったことから、mmapとテンソル個別指定の組み合わせが引き金である点は確かだと考えています。
まとめ
- 割り当ては自分で決められます。
-ngl(層で切る)/-ot(テンソル名で切る)/--n-cpu-moe(MoEの専門家を切る)の3つ --n-cpu-moe Nは-otの便利版。実測でも、専用VRAM使用量がMB単位まで一致しました。Denseなモデルでは警告もなく無視されます- ★Windows側では予想どおりでした。 専用VRAMのRTX 3060は設定で+59%動く一方、統合メモリの780Mは+10%。「行き先が同じ器」なら、そもそも移動していないのと同じです
- ★ところが統合メモリどうしのM4と780Mは、正反対でした。 780Mは効かないだけ、M4は全部CPUに置くより10倍遅くなる。予想は半分当たって半分外れです
- ★M4が壊れた原因はメモリ構造ではなく、mmapとの組み合わせ。 Metalはmmapした範囲をまるごと掴むので、中身をCPUに移してもGPU側が抱えたまま二重になり、スワップが22GBまで膨らんでいました。
--no-mmapで6.6倍まで回復します - ★そして直した後も、M4は780Mに似ませんでした。 似ていたのはRTX 3060のほう。効き方を決めるのは「統合メモリか専用VRAMか」ではなく「GPU側とCPU側の実力差がどれだけ開いているか」だと考えると、3台とも説明がつきます
- そして、その警告はllama.cppが最初から出していました。 読み飛ばしていたのはこちらです
「統合メモリか専用VRAMか」という構造の違いから素直に予想を立てて始めた検証でしたが、実際に効いていたのは実装の都合と、単純な実力差でした。構造の名前が同じでも中身は同じではない、というのは前回の「同じ統合メモリでも速度は同じにならない」とも重なる話で、2回続けて同じ落とし穴に足を取られたことになります😅
それと、今回いちばん反省したのは警告を読み飛ばしていたことです。原因を探して丸一日ぶん回した末に、答えはログの最初のほうに書いてありました。
それでは、今回はここまで。最後までありがとうございました😊
【実測環境】Mac: Apple M4 / macOS 26.5.2 / RAM 32GB(LPDDR5X-7500)/llama.cpp b10090(7347430f4・Metal)。GPUメモリ上限は recommendedMaxWorkingSetSize = 26800.60 MB(llama.cppの報告値 25,559 MiB)、iogpu.wired_limit_mb は既定の0。Windows: Windows 11 Pro 25H2 (26200.8875) / Ryzen 7 7840HS 内蔵 Radeon 780M + RTX 3060(OCuLink接続のeGPU)/ RAM 31.3GB(DDR5)/llama.cpp は LM Studio 同梱の署名済み Vulkan ランタイム 2.25.2(cb295bf)。モデルは Qwen3-30B-A3B-Instruct-2507(48層・MoE)の Q4_K_M(17.28 GiB)と Q6_K(23.36 GiB)、対照群に Qwen2.5-Coder 7B/14B Q4_K_M。計測は prompt 512トークン・生成128トークン・3回平均(ウォームアップは各ツールの内蔵機能を使用)。Mac側とWindows側でllama.cppの版もバックエンドも異なるため、構成間の絶対値比較ではなく「設定を変えたときの動き方」の比較として読んでください。数値は2026年7月時点の実測で、版により変わる可能性があります。