概要
- 2026-08 100 万円くらいの GPU で Qwen 3.8 27B が 150 tok/s くらいの速度で動く。SLM (Small Language Model) と言われるもので、パソコンで動くもの。Opus 4.8 Low に匹敵する性能、3 倍速(Qwen 3.8 は Overthinking なのでよりよいとは思わないけど)
- Qwen 3.8 27B、ローカルで動く小さいモデルなのに DeepSeek V4 Flash 0731 (294B) 並の知能が出てる点で、2026-08 時点で明らかなブレークスルー。Artificial Analysis によると Sonnet 4.6 Max より頭いいらしい。
- llm-jp-4-33b-thinking が 2026-08 に出て、日本語能力が gpt-4o 級で実用水準になったものの、数学とかコーディングとかエージェントについてはそもそもターゲットに入れていないという雰囲気を感じます。DeepSWE などのベンチは公開されてすらいない。
- 2025 年秋から学習開始し 2026-08 に公開、なので、そもそもコーディングエージェント系の知見が学習開始時点でなさそうです。
- 超計算資源不足でベストを尽くしているようなので、そちらは頑張っていただきたいのですが、それとは別に llm-jp のモデルを使う必要性はライセンスの問題などを除けば性能的にはない (2026-08 にリリースされた Qwen 3.8 を使えばよい)。
- llm-jp コミュニティで大事そうな人 Odashi, kodama26985649, kwashizzz, Bluecode.net
環境
以下数値例はすべてこの環境を前提
| 項目 | 値 |
|---|---|
| GPU | NVIDIA GeForce RTX 3070 Ti |
| GPU のメモリ | 8 GB |
| システムメモリ | 94 GB |
| CPU | Intel Core i9-11900K(16スレッド) |
| OS | Ubuntu |
目次
- 1. パラメータとは何か
- 2. 量子化 — なぜ小さくできるのか
- 3. 量子化で何が失われるか
- 4. 混合エキスパート(MoE)
- 5. 必要なメモリと速度を見積もる
- 6. モデルのスペックの読み方
- 7. モデルを動かすソフトウェア
- 8. この環境で何が動くか
- 9. 実際に動かす
- 10. 実測 — MoE と Dense を同じ条件で比べる
- 11. Claude Code でローカルモデルは使えるか
- 12. モデルを作る側のコスト
- 13. モデルの良し悪しをどう判断するか
- 14. まとめ
- 出典
1. パラメータとは何か
言語モデルは、大量の数値の集まりである。この数値ひとつひとつを パラメータ と呼ぶ。
パラメータは学習によって決まる。学習前は乱数が入っており、大量の文章を読ませる過程で少しずつ調整され、最終的に「この単語の次にはこの単語が来やすい」という知識を担う値に落ち着く。学習が終わったパラメータの集合を 重み と呼ぶ。重みとパラメータはほぼ同じ意味で使われる。
パラメータの個数がモデルの規模を表す。個数が多いほど複雑な知識を蓄えられるが、その分だけ記憶領域を消費する。
B という単位
モデル名によく現れる 8B 30B 2.4T は、パラメータの個数である。
| 表記 | 読み | 個数 |
|---|---|---|
8B | 8 billion | 80億 |
30B | 30 billion | 300億 |
70B | 70 billion | 700億 |
2.4T | 2.4 trillion | 2兆4000億 |
B は billion(10億)、T は trillion(1兆)の頭文字である。
トークンという単位
モデルは文章を1文字ずつでも1単語ずつでもなく、トークンという単位で扱う。トークンは「よく現れる文字のかたまり」で、英語なら単語かその一部、日本語なら1〜2文字程度が1トークンになることが多い。
以降、文章の長さも生成の速さも、すべてトークンで数える。
- 「コンテキスト長 32768」= 一度に 32,768 トークンまで扱える
- 「12 トークン/秒」= 1秒に 12 個のトークンを生成する
モデルが1回の処理で行うのは、次の1トークンを決めることである。 文章はこれを繰り返して作られる。
2種類のメモリ — VRAM とシステムRAM
計算に入る前に、メモリが2種類あることを押さえる必要がある。この区別が、以降のすべての判断の土台になる。
| VRAM | システムRAM | |
|---|---|---|
| 正式名称 | Video RAM(ビデオメモリ) | メインメモリ |
| どこにあるか | GPU の基板上 | マザーボード上 |
| 誰が使うか | GPU | CPU |
| この環境の容量 | 8 GB | 94 GB |
| 読み出し速度 | 約 608 GB/秒 | 約 50 GB/秒 |
| 増やせるか | 不可(GPUごと交換) | 可(メモリを挿す) |
VRAM とは、GPU が直接読み書きできる専用メモリである。パソコンを組むときに挿すメモリ(システムRAM)とは物理的に別の部品で、グラフィックボードに最初から載っている。だから容量は買った時点で決まり、後から増やせない。
読み出し速度が 12倍違う 点が決定的である。この差が、ローカルLLMの速度をほぼ単独で決める。
なぜ GPU 専用のメモリが必要なのかというと、GPU は数千個の演算器を同時に動かすため、CPU 用のメモリでは供給が追いつかないからである。そこで GPU の隣に高速なメモリを直結している。その代償として容量が小さい。
物理的な配置を図にする。
Loading diagram...
図の読み方。CPU とシステムRAM、GPU と VRAM が、それぞれ別々に直結している。2つの島の間は PCI Express という通路でつながっているが、ここは VRAM の直結より20倍以上遅い。
だから「VRAM に入りきらない分をその都度 PCI Express 経由で送る」という方式は成立しない。実際 llama.cpp はそれをせず、どちらの島に置くかを起動時に決めて固定する。RAM 側に置かれた重みは CPU が計算し、VRAM 側の重みは GPU が計算する。往復するのは計算の途中結果だけで、これは数KBしかない。
「GPU に載る」とは何を意味するか
以降この文書で 「GPU に載る」 と書いたら、そのデータが VRAM に収まっているという意味である。
- VRAM に収まる → GPU が 608 GB/秒で読める → 速い
- VRAM に収まらない → システムRAM に置いて 50 GB/秒で読む → 遅い
現在の状態を確認するコマンドは次のとおり。
nvidia-smi --query-gpu=name,memory.total,memory.used,memory.free --format=csv
この環境での実行結果である。
NVIDIA GeForce RTX 3070 Ti, 8192 MiB, 3517 MiB, 4423 MiB
左から順に、GPU名・VRAM総量(8 GB)・使用中(3.5 GB)・空き(4.4 GB)である。
判断の軸は2つある。動かせるかどうかはシステムRAM の容量で決まり、速いかどうかは VRAM の容量で決まる。 第5章でその計算方法を示す。
必要なメモリの計算
パラメータ1個あたり何バイトで記録するかが決まれば、必要なメモリは掛け算で出る。
学習時の標準的な形式は BF16 で、これは1個あたり2バイトを使う。したがって、
30B のモデルを BF16 で保持する場合
300億個 × 2バイト = 600億バイト = 約 60 GB
この60GBを、モデルを動かしている間ずっとメモリ上に置いておく必要がある。GPUのメモリが8GBしかない環境では、当然入らない。
この問題を解決するのが次章の量子化である。
2. 量子化 — なぜ小さくできるのか
量子化 とは、パラメータを記録する精度を落として、容量を減らす操作である。
BF16 の2バイト(16ビット)を4ビットに落とせば、容量は4分の1になる。ただし4ビットで表せるのは16通りの値だけである。もともと連続的な数値だったものを16段階に押し込めることになる。
なぜそんな乱暴なことが成立するのか。素朴にやると失敗する例から見る。
素朴な方法は失敗する
パラメータの実際の値は、たとえばこのような小さな数値の並びである。
0.0231, -0.0187, 0.0142, -0.0203, 0.0119, ...
ここで「-1.0 から +1.0 までを16段階に区切る」という素朴な方法を取ると、目盛りの間隔は 2.0 ÷ 16 = 0.125 になる。各値を最も近い目盛りに丸めると、
0.0231 → 0
-0.0187 → 0
0.0142 → 0
すべてゼロになる。値の違いが完全に消え、モデルは機能しなくなる。目盛りが粗すぎるためである。
ブロック単位のスケーリング
そこで実際の量子化は次のようにする。
パラメータを32個ずつの塊に区切る。この塊を ブロック と呼ぶ。そしてブロックごとに、そのブロックに含まれる値の範囲を調べる。
上の例のブロックでは、絶対値の最大が 0.0231 だった。ならば「-0.0231 から +0.0231 までを16段階」で区切ればよい。目盛りの間隔は 0.0462 ÷ 16 ≒ 0.003 になる。
0.0231 → 0.0231 (目盛り 15)
-0.0187 → -0.0185 (目盛り 3)
0.0142 → 0.0139 (目盛り 12)
値の違いが保たれている。
このとき「このブロックは 0.0231 を基準にした」という情報を、ブロックごとに1個だけ別に保存する。この基準値を スケール係数 と呼ぶ。使うときは「目盛り番号 × スケール係数」で元の値に近い数を復元する。
追加で保存するのは32個につきスケール係数1個だけなので、容量の増加はごくわずかである。それでいて、値が小さくまとまっている場所では細かい目盛りを、値が大きい場所では粗い目盛りを、それぞれ自動的に使い分けられる。
一言でいえば、全体を1本の物差しで測るのをやめ、32個ごとにその範囲にぴったり合った物差しを使い分ける。これが量子化が成立する理由である。
ファイル名の読み方
量子化されたモデルのファイルには、Q4_K_M のような記号が付く。分解すると次の意味になる。
| 部分 | 意味 |
|---|---|
Q4 | パラメータ1個を4ビットで記録する |
Q5 Q8 | それぞれ5ビット、8ビット |
_K | K-quants。ブロック単位スケーリングの改良版 |
_S _M _L | Small / Medium / Large。同じビット数でも、重要な層により多くのビットを配分する度合い |
IQ | I-quants。後述の重要度行列を使った方式 |
重要度行列(importance matrix、略して imatrix)とは、実際の文章をモデルに流して「どのパラメータがよく使われるか」を測定したものである。よく使われるパラメータには精度を厚く配分することで、同じ容量でも品質を保ちやすくなる。
Q4_K_M が標準的な選択肢である。後述の llama.cpp も、指定がなければ Q4_K_M を取得しようとする。
量子化後の容量
パラメータ1個あたりのバイト数が変わるだけなので、計算は簡単である。
ここで注意すべき点がある。Q4 という名前は「4ビット」だが、実際の保存コストは4ビットより大きい。
理由は前節の仕組みそのものにある。量子化した値(4ビット)に加えて、ブロックごとのスケール係数を保存する必要があるためである。さらに llama.cpp は、出力に強く効くテンソルを自動的に Q6_K(6ビット)に格上げする。
llama.cpp の公式資料は Q4_K_M の実際のコストを 4.8944 bpw(bits per weight、1パラメータあたりのビット数)と記載している。実装のコメントにも // Effectively 4.5 bits per weight とある。
したがって実際の計算はこうなる。
| 形式 | 実際の1個あたり | 30B の場合 |
|---|---|---|
| BF16(元の形式) | 2 バイト | 60 GB |
| Q8_0(8ビット) | 約 1.06 バイト | 32 GB |
| Q4_K_M | 約 0.61 バイト | 約 18 GB |
Q4 なら「Bの数字に 0.6 を掛けるとGB」 という覚え方になる。
| モデル | Q4_K_M での概算 |
|---|---|
| 8B | 約 5 GB |
| 30B | 約 18 GB |
| 70B | 約 43 GB |
| 2.4T(=2400B) | 約 1,460 GB |
最後の行が、2.4T のモデルを個人の環境で動かせない理由である。1.4テラバイトを超えるメモリが必要になる。
なお、この 0.6 という係数は目安である。第8章に実測したファイルサイズの一覧があるので、実際に動かす前にはそちらを確認すること。
3. 量子化で何が失われるか
容量が4分の1になるなら、何かを失っているはずである。何をどう失うのかを正確に理解しておかないと、実務で判断を誤る。
モデルは確率で単語を選んでいる
前提として、言語モデルの動作を確認する。
「東京は日本の___」という入力に対して、モデルは内部で次の単語の候補に確率を割り当てる。
首都 75%
中心 12%
都市 8%
(以下略)
そして最も確率の高いものを選ぶ。この確率の計算にパラメータを使うので、パラメータを丸めると確率がわずかにずれる。
ずれ方には偏りがある
llama.cpp には、量子化の前後で出力の確率分布がどれだけ変わるかを測る機能がある(llama-perplexity --kl-divergence)。Llama 3 8B を Q4_K_M にしたときの出力である。
| 指標 | 値 | 意味 |
|---|---|---|
| Mean Δp | -0.024% | 正解トークンに与える確率の平均変化。わずかに下がる |
| RMS Δp | 5.519% | 同じ変化の二乗平均。1トークンあたりの典型的なずれの大きさ |
| Same top p | 91.9% | 量子化前と最も確率の高いトークンが一致した割合 |
Δp とは、正解のトークンに与えられた確率の「量子化後 − 量子化前」である。符号付きなので、上がった場合と下がった場合が打ち消し合う。
読み方は2つある。
平均はほぼゼロだが、典型的なずれはゼロではない。 平均が -0.024% なのは打ち消し合った結果であって、1トークンごとのずれが小さいという意味ではない。打ち消し合わないよう二乗して測った RMS は 5.519%、平均の 230 倍ある。
8.1% のトークンで、選ばれるトークンそのものが変わる。 Same top p が 91.9% なので、残り 8.1% では量子化前と違うトークンが1位になっている。なおこの指標が見ているのは「1位が一致したか」だけで、入れ替わった先が元の2位だったかは測っていない。
選ばれるトークンが変わるのは、どういう場面か。「首都 75%、中心 12%」のように大差がついている場面では、確率が多少ずれても順位は変わらない。しかし、
選択肢A 34%
選択肢B 33%
このように僅差の場面では、0.5% ずれただけで逆転する。
つまり、もともと僅差だった判断だけが、ひっくり返る。平均的な誤差はほぼゼロなのに、一部が壊れているのはこのためである。
僅差の場面とは、モデルが迷っている場面
では、モデルが僅差になるのはどういうときか。難しい問題を解いているときである。簡単な問題ならモデルは確信を持って答えられるが、難しい問題では複数の候補が拮抗する。
この予測は実測と一致する。同じモデル・同じタスクで、量子化の方式だけを変えて測った結果がある。出典は arXiv:2504.04823(COLM 2025)Table 1、DeepSeek-R1-Distill-Qwen-32B。
| 設定 | 何を4ビットにしたか | AIME-120(難) | MATH-500(中) | GSM8K(易) | 5指標平均 |
|---|---|---|---|---|---|
| BF16(元) | — | 61.7 | 96.3 | 94.2 | — |
| W4A16 / AWQ | 重みだけ | 63.6(+1.9) | 95.9(-0.4) | 94.4(+0.2) | -0.4 |
| W4A16 / GPTQ | 重みだけ | 57.5(-4.2) | 95.9(-0.4) | 94.3(+0.1) | -1.9 |
| W4A4KV4 / FlatQuant | 重み+活性値+KVキャッシュ | 57.8(-3.9) | 95.1(-1.2) | 94.2(0.0) | -2.9 |
llama.cpp の Q4_K_M は「重みだけ」を4ビットにする方式である。したがって対応するのは W4A16 の2行であり、最下行の W4A4KV4 ではない。論文の要旨もこう述べている。
lossless quantization can be achieved with W8A8 or W4A16 quantization, lower bit-widths introduce significant accuracy risks
(W8A8 または W4A16 なら無損失の量子化が達成できる。それより低いビット幅は重大な精度リスクを生む)
まず押さえるべきは、weight-only の4ビットは平均では実質無損失だということである。 「4ビットにすると賢さが落ちる」という素朴な理解は正しくない。
そのうえで W4A16 の2行を見比べる。同じ4ビット weight-only でも、アルゴリズムが違うだけで AIME は +1.9 にも -4.2 にもなる。一方 GSM8K はどちらも ±0.1 に収まっている。平均は無損失でも、難しいタスクだけが大きく振れる。 論文もこれを主要な発見として挙げている。
Harder tasks (e.g., AIME-120) suffer up to 4× greater degradation than simpler ones (e.g., GSM8K).
(難しいタスクは、簡単なタスクの最大4倍の劣化を被る)
機序を直接述べた研究もある。arXiv:2405.00632(NAACL 2024 Findings)より。
quantization disproportionately affects samples where the full model exhibited low confidence levels in the first place.
(量子化は、元のモデルが最初から自信の低かったサンプルに不釣り合いに影響する)
一言でまとめると、量子化は、モデルが迷っていた答えから先に奪う。
実務上の危険
この性質が厄介なのは、簡単なテストでは異常が検出できないことである。手元で軽い質問をして正常に答えたからといって、難しいケースで正常とは限らない。「ベンチマークのスコアが落ちていないから大丈夫」という判断は成立しない。
日本語と長文は特に危険
ここまでで「weight-only の4ビットは平均では実質無損失」と述べた。これは短い入力での平均の話である。入力が長くなると話が変わる。
日本語で長い文章を扱う場合、さらに強い注意が必要である。arXiv:2505.20276(EMNLP 2025)の測定結果。
on average, 8-bit quantization preserves accuracy (~0.8% drop), whereas 4-bit methods lead to substantial losses, especially for tasks involving long-context inputs (drops of up to 59%). This degradation tends to worsen when the input is in a language other than English.
要点は次の2つである。
- 8ビット量子化なら劣化は約 0.8% で済む
- 4ビットでは長文の処理が最大 59% 低下し、英語以外の入力ではさらに悪化する
先の「実質無損失」と矛盾しない。 前者は短い入力での平均、こちらは 64,000 トークンを超える長文脈での測定である。同じ4ビット weight-only でも、入力の長さで結果が変わる。なお 59% は BNB-nf4 という特定の手法・特定モデルでの最悪値で、平均は手法により -1.8% から -6.9% である。
実数では、英語入力の低下が -2.1% から -4.6% であるのに対し、英語以外では -14% だった。
したがって、日本語で長文を扱うなら Q5_K_M 以上を選ぶ。これは好みの問題ではなく、測定に基づく判断である。
コード生成の場合
コード生成での実測値も出ている(arXiv:2503.07103)。数値は pass@1、すなわち 1回だけ答えさせて正解した割合 である。
| ベンチマーク / モデル | 元の精度 | 4ビット | 3ビット | 2ビット |
|---|---|---|---|---|
| MultiPL-E Python / CodeLlama 7B | 29.8 | 29.1 | 24.3 | 16.4 |
| MultiPL-E Java / CodeLlama 7B | 32.2 | 30.7 | 26.5 | 14.1 |
| McEval Python / DeepSeek-Coder 7B | 41.8 | 40.7 | 36.2 | 13.7 |
4ビットまでは低下が1ポイント未満で収まっているが、3ビットで明確に落ち、2ビットでは半減する。4ビットが実用の下限と考えてよい。
同論文は4ビットでの失敗の様態も記録している。
the quantized model mainly failed due to assertion errors or calls to non-existent APIs.
(量子化されたモデルの失敗は主に、アサーションエラー、または存在しないAPIの呼び出しによるものだった)
もっともらしいコードを書くが、細部で間違える。これも「迷っていた判断が壊れる」という性質の表れである。
4. 混合エキスパート(MoE)
モデルの構造には大きく2種類ある。この違いが、限られたメモリで動かすときに決定的な差を生む。
密なモデル(Dense)
従来型の構造。1単語を生成するたびに、全パラメータを使って計算する。30B のモデルなら毎回300億個すべてを読み出す。
混合エキスパート(Mixture of Experts、MoE)
モデル内部の一部を、多数の小さな部品に分割した構造。この部品を エキスパート と呼ぶ。そして1トークンごとに、そのうち一部のエキスパートだけを使う。
正確には、分割されるのは各層のうち FFN(Feed-Forward Network、前段の計算結果を変換する部分)だけである。文脈を読み取る attention の部分は分割されず、全トークンで共有される。
どのエキスパートを使うかは、各層に置かれた ルーター と呼ばれる小さな仕組みが選ぶ。ルーターは層ごと・トークンごとに選び直す。
なお「数学が得意なエキスパート、コードが得意なエキスパート」という説明をよく見かけるが、これは俗説である。Mixtral の論文は、トピックやドメインによる明白な専門化のパターンは観測されないと報告している。実際の分業は、意味的な分野ではなく構文レベルで生じている。
2つの構造の違い
まず密なモデル。1トークンが通る経路は一本道である。
Loading diagram...
次に MoE。FFN の位置にルーターとエキスパートが入る。
Loading diagram...
図の読み方。2枚を見比べると、違いは FFN の部分だけである。入口の attention は両者とも同じで、分割されない。
数値はこの環境で動かしている gpt-oss-20b の実測値である。起動ログに次のとおり出る。
n_expert = 32 各層のエキスパートの個数
n_expert_used = 4 そのうち毎回使う個数
密なモデルは FFN の全パラメータを通る。MoE はルーターが選んだ4個だけを通り、残り28個は経路に入らない。これが「30B-A3B」の A3B、すなわち活性30億の意味である。
エキスパートの個数はモデルによって違う。 32個のものもあれば128個のものもある。自分が使うモデルの値は、起動時のログで確認できる。
ここで読者が必ず引っかかる点を先に説明する。使わないエキスパートも、メモリには置いておく必要がある。 次にどのエキスパートが選ばれるかは、そのトークンを処理してみるまで分からないためである。だから「メモリは総パラメータ分、計算は活性パラメータ分」という非対称が生じる。
30B-A3B という表記
MoE のモデル名には、30B-A3B のような表記が付く。
- 30B = 総パラメータ 300億。メモリはこの分だけ必要
- A3B = Active 30億。計算に使うのはこの分だけ
A は Active(活性)の頭文字である。
つまり 30B-A3B は、約18 GB のメモリを占有するが、3B 相当の速さで動く モデルである。
18 GB という数字の根拠は第2章の計算式である。Q4 は1パラメータあたり約0.61バイトなので、
300億パラメータ × 0.61バイト ≒ 18.3 GB
実測でも GLM-4.7-Flash(31.2B、Q4_K)が 18.24 GB、Qwen3.6-35B-A3B(36.0B、Q4_K_M)が 20.42 GB で一致する。
なぜこの構造が重要なのか
メモリと速度が別々に決まるからである。
| 必要メモリ(Q4) | 1単語あたりの計算量 | |
|---|---|---|
| 30B Dense | 約 18 GB | 300億パラメータ分 |
| 30B-A3B MoE | 約 18 GB | 30億パラメータ分 |
同じ15GBを占有していても、MoE は密なモデルの10分の1の計算しかしない。
これが、GPUのメモリが少なくシステムメモリが多い環境で決定的に効く。後述の方法でエキスパートをシステムメモリ側に置いた場合、密なモデルは毎トークンごとに全体を読み出す必要があるが、MoE は一部しか読まない。同じサイズなら MoE を選ぶべき理由である。
5. 必要なメモリと速度を見積もる
ここまでで「総パラメータ分のメモリが要る」と述べたが、実際に必要なのはそれだけではない。この節では、モデルを選んだときに自分で必要量を見積もる方法を示す。
必要なメモリは3つの合計
必要メモリ = ① 重み + ② KVキャッシュ + ③ 計算バッファ
① 重み は第2章の計算式で出る。総パラメータ × 0.61バイト(Q4の場合)。MoEでも総パラメータ分が必要で、活性パラメータの数は関係ない。
② KVキャッシュ は、これまで読んだ文章を覚えておく領域である。トークンを1つ処理するたびに、その内容を要約した数値が各層に1組ずつ追加され、以降ずっと保持される。だから長い文章を扱うほど大きくなる。計算式は次のとおり。
KVキャッシュ = 2 × 層数 × KVヘッド数 × ヘッド次元 × 最大トークン数 × 2バイト
先頭の 2 は Key と Value の2種類があることを表す。層数やヘッド数はモデルごとに違うので、起動時のログに出る実測値を見るのが確実である。
③ 計算バッファ は計算の途中結果を置く作業領域で、数百MB程度である。
実測値で確かめる
この環境で gpt-oss-20b を -cmoe -c 32768 で起動したときの、llama.cpp 自身が出力した内訳である。
| memory breakdown [MiB] | total free | self = model + context + compute |
| - Vulkan0 (RTX 3070 Ti)| 8438 6798 | 2265 = 1242 + 792 + 231 |
| - Host | | 10338 = 10294 + 0 + 44 |
読み方を表にする。model が重み、context が KVキャッシュ、compute が計算バッファである。
| 重み | KVキャッシュ | 計算バッファ | 合計 | |
|---|---|---|---|---|
| GPU(8 GB) | 1.2 GB | 0.8 GB | 0.2 GB | 2.3 GB |
| システムRAM | 10.7 GB | 0 | 0.04 GB | 10.3 GB |
重みの合計 1.2 + 10.7 = 11.9 GB が、ファイルサイズ 12.1 GB とほぼ一致する。モデル全体がメモリに載っていることが確認できる。
なお KVキャッシュの 792 MiB は、32,768トークン分を確保した結果である。内訳もログに出ている。
size = 768.00 MiB (32768 cells, 12 layers, K (f16): 384.00 MiB, V (f16): 384.00 MiB)
-c の値を半分にすれば、この 768 MiB も半分になる。 GPU に載らないときに真っ先に削るべき場所である。
何が GPU に載り、何が RAM に載るのか
-cmoe を指定したとき、llama.cpp は次のように振り分ける。
| 部分 | 置き場所 | この例でのサイズ |
|---|---|---|
| attention(文脈を読む部分) | GPU | 1.2 GB |
| KVキャッシュ | GPU | 0.8 GB |
| 計算バッファ | GPU | 0.2 GB |
| エキスパート(FFN) | システムRAM | 10.7 GB |
つまり 重みの9割はRAM側にある。GPU に載っているのは attention と作業領域だけである。
この振り分けが成立する理由は、エキスパートが「毎回一部しか使われない」ためである。次節でその読み出し順序を追う。
1トークン生成するときに実際に起きること
gpt-oss-20b の実測パラメータで具体的に追う。ログから次の値が読める。
n_layer = 24 層が24段ある
n_expert = 32 各層にエキスパートが32個
n_expert_used = 4 そのうち毎回4個だけ使う
1トークンを生成するとき、24段の層を順番に通過する。各層で起きることは次のとおり。
Loading diagram...
図の読み方。「19GB全体を読む」のではなく、層ごとに必要な部分だけを読む。
各層で読み出す量を計算する。エキスパートは全部で 10.7 GB、これが 24層 × 32個 に分かれているので、1層・1個あたり 10.7 ÷ 24 ÷ 32 ≒ 14 MB。1層で使うのは4個なので約 56 MB、24層で約 1.3 GB である。これに GPU 側の attention を足したものが、1トークンで読む量になる。
| 1トークンあたりに読む量 | |
|---|---|
| もし密なモデルなら | 重み全体 11.9 GB |
| MoE(32個中4個) | 約 2.1 GB(活性3.6B × 0.58バイト、MXFP4) |
速度を決めるのは計算能力ではなくデータ供給速度
ここが最も重要な原則である。LLM の生成速度は、GPU の計算能力ではなく、メモリからデータを読み出す速さで決まる。
1トークン生成するのに必要な計算そのものは、現代の GPU にとって軽い。問題は、その計算に使う重みを毎回メモリから読み直さなければならないことである。読み出しが間に合わず、演算器が待たされる。この状態を メモリIOバウンド(memory-bound)と呼ぶ。
実際に確認できる。nvtop または次のコマンドで、生成中の GPU 使用率を見る。
nvidia-smi --query-gpu=utilization.gpu,memory.used --format=csv -l 1
生成中でも GPU 使用率は 30% 前後にしかならない。残りの7割は、データが届くのを待っている時間である。GPU をより高性能なものに替えても、メモリが同じなら速度はほとんど変わらない。
この原則から、実務的な帰結が2つ出る。
- モデルを小さくすると速くなる。 読む量が減るため。量子化と MoE はどちらもこれを狙っている
- より速いメモリに置くと速くなる。 VRAM に載せる意味はここにある
メモリからデータを読み出す速さの上限を メモリ帯域 と呼ぶ。単位は GB/秒である。
| 装置 | メモリ帯域 |
|---|---|
| GPU(RTX 3070 Ti) | 約 608 GB/秒 |
| システムRAM(DDR4 デュアルチャネル) | 約 50 GB/秒 |
RAM 側は GPU の12分の1しかない。したがって RAM に置いた 10.7 GB のうち毎回読む分が速度を支配する。
理論上の上限 ≒ 50 GB/秒 ÷ 1トークンあたり約2 GB ≒ 25 トークン/秒
実測は 12〜19 トークン/秒だった。理論値の半分程度に収まっており、桁は合っている。
メモリ帯域は GPU によって桁が違う
VRAM の帯域は製品によって大きく異なる。データセンター向けの GPU は、個人向けとは別の種類のメモリを使う。
| GPU | VRAM 容量 | メモリ帯域 | メモリの種類 |
|---|---|---|---|
| RTX 3070 Ti(この環境) | 8 GB | 608 GB/秒 | GDDR6X |
| RTX 4090 | 24 GB | 約 1,000 GB/秒 | GDDR6X |
| H100 | 80 GB | 3,350 GB/秒 | HBM3 |
| H200 | 141 GB | 4,800 GB/秒 | HBM3e |
| B200 | 192 GB | 8,000 GB/秒 | HBM3e |
HBM(High Bandwidth Memory)は、メモリをGPUチップの真上に積層する構造である。配線距離が極端に短いため帯域が桁違いに高い。その代わり非常に高価で、個人向け製品には使われない。
同じ Qwen3.8-27B を Q4_K_M(ファイル 19.0 GB。1トークンあたりその全体を読む)で各環境に載せた場合の理論値を出す。
| 環境 | どこから読むか | 計算 | 理論値 |
|---|---|---|---|
| RTX 3070 Ti(8 GB) | システムRAM(VRAMに載らない) | 50 ÷ 19 | 2.6 t/s |
| RTX 4090(24 GB) | VRAM | 1,008 ÷ 19 | 53 t/s |
| H100(80 GB) | VRAM | 3,350 ÷ 19 | 176 t/s |
| B200(192 GB) | VRAM | 8,000 ÷ 19 | 421 t/s |
H100 でこの環境の 68倍、B200 なら 162倍 になる。
さらに、BF16 のまま(量子化なし、56 GB)でも VRAM に収まる環境がある。第3章で述べた量子化による劣化を、そもそも考える必要がなくなる。
| GPU | VRAM | Qwen3.8-27B を BF16(56 GB)で |
|---|---|---|
| RTX 4090 | 24 GB | 載らない |
| H100 | 80 GB | 載る |
| H200 | 141 GB | 載る |
| B200 | 192 GB | 載る |
BF16 で載せた場合、1トークンあたり 56 GB を読むことになるので、H100 なら 3,350 ÷ 56 ≒ 60 t/s、B200 なら 8,000 ÷ 56 ≒ 143 t/s になる。量子化した場合より遅いが、劣化はない。容量に余裕があれば、速度と品質を選べるということである。
個人環境とデータセンターの差は、GPU の計算能力ではなくメモリにある。 容量が足りないから量子化が要り、帯域が足りないから遅い。
密なモデルを避けるべき理由も、この式で説明できる。 同じ 11.9 GB でも密なモデルなら毎トークン全部を読むので、
50 GB/秒 ÷ 11.9 GB ≒ 4 トークン/秒
MoE の5分の1以下になる。これが第8章で「Dense を避ける」と述べる根拠である。
この式が当たらない場合がある — 投機デコード
ここまでの式は「1トークン生成するごとに、必要な重みを1回ずつ読む」という前提に立っている。この前提を崩す仕組みがあり、その場合は実測が式の2倍以上になる。
投機デコード(speculative decoding)と呼ばれる。手順はこうである。
- 小さな「先読みヘッド」が、次の数トークンをまとめて推測する(軽い)
- 本体がその数トークンを1回の読み出しでまとめて検証する(重い読み出しは1回だけ)
- 推測が当たっていればまとめて進み、外れた分だけ捨てる
重い読み出しの回数が減るので、1回あたりに進むトークン数が増える。当たる割合を受理率と呼び、これが高いほど効く。
Qwen3.8 系はこの先読みヘッドをモデル自身に内蔵している(MTP、Multi-Token Prediction)。外部に別のモデルを用意する必要がない。
実測例 — 式の予測と2倍以上ずれる
第三者が RTX 5090(VRAM 32 GB)で測った値がある。
| 条件 | 速度 |
|---|---|
| 式による予測(投機なし) | 約 65 tok/s |
| 実測(投機あり、受理率 74%) | 148 tok/s |
出典: https://note.com/(2026-08-15、Qwen3.8-27B を RTX 5090 で実測した記事)。同じ環境で Ollama を使った別の記事も 152 tok/s を報告している。
一見遅くなるはずの選択が、実際には速い
ここに重要な逆転がある。より大きい量子化を選んだほうが速くなる場合がある。
| 量子化 | ファイル | 素の読み出し速度(理論) | 投機の受理率 | 実効速度 |
|---|---|---|---|---|
| Q4_K_M | 19.0 GB | 1792 ÷ 19.0 = 94 tok/s | 0%(壊れる) | 約 65 tok/s |
| UD-Q5_K_XL | 約 23 GB | 1792 ÷ 23.0 = 78 tok/s | 73% | 約 148 tok/s |
ファイルが大きい Q5 のほうが、素の読み出しでは遅いにもかかわらず、2倍以上速い。
理由は、先読みヘッドを担う層まで4ビットに落とすと、推測の精度が壊れて投機が全く働かなくなるためである。前掲の記事より。
Qwen3.6-27B のとき、同じ Unsloth の UD-Q4_K_XL 量子化では投機デコードの受理率が 0% になるという罠がありました。MTP ヘッドを担う最終ブロックが Q4_K に量子化されると、先読みの精度が壊れて投機が全滅するのです。一段上の UD-Q5_K_XL では MTP 層が Q5_K 以上で維持され、受理率 73% で正常に働きました。
「Q4 が標準」という本文の記述は、投機デコードを使う場合には当てはまらない。
150 tok/s を出すのに必要な3条件
上の数字は、次の3つがすべて揃ってはじめて出る。
| # | 条件 | 満たさないと |
|---|---|---|
| ① | 重みが VRAM に収まる(19〜23 GB なら 32 GB 級) | RAM 読みになり 2〜3 tok/s |
| ② | 先読みヘッドの層が Q5 以上に保たれた量子化を選ぶ | 受理率 0%、速度は半分以下 |
| ③ | 投機デコードを明示的に有効化する | 働かない。既定では無効 |
③ を忘れやすい。 llama.cpp では起動時にパラメータで指定する必要がある。
教訓 — モデル固有の事情を先に調べる
この事例が示すのは、一般的な原則だけでは最適設定にたどり着けないということである。
本文の式(帯域 ÷ 読む量)は、どのモデルにも当てはまる下限を与える。しかし実際の速度は、そのモデルが持つ固有の仕組みによって大きく変わる。
- 先読みヘッドを内蔵しているか
- そのヘッドが何ステップ先まで学習されているか(先読みの深さの最適値が変わる)
- どの層を量子化すると壊れるか
- アテンションの構成(KVキャッシュの量が変わり、扱えるコンテキスト長が変わる)
前掲の記事では、先読みの深さ(n_max)の最適値が世代で変わったことも報告されている。前世代は 2 が最適だったが、新世代は学習方法が変わったため 3 が最適になった。前世代の設定をそのまま使うと性能を取り逃す。
したがって、新しいモデルを使うときは次を先に調べる。
- モデルカードと config を読む — アーキテクチャ名、先読みヘッドの有無、層構成
- 同じモデルの実測報告を探す — 「モデル名 + GPU名 + tok/s」で検索する。他人が踏んだ罠を踏まずに済む
- 前世代の最適値を疑う — 学習方法が変わったと書かれているパラメータは、振り直す
数十 GB をダウンロードする前に、数KBの config.json を読む。 数分の調査で、数時間の試行錯誤と2倍の速度差が決まる。
まとめ:自分で見積もる手順
新しいモデルを試すとき、次の順に計算する。
- 重み = 総パラメータ(B)× 0.6 GB
- KVキャッシュ =
-cの値に比例。32k で 0.5〜1 GB 程度(モデル構造による) - 合計がシステムRAMに収まるかを確認する(GPU ではなく RAM で判断する)
- 速度の目安 = 50 GB/秒 ÷(活性パラメータ B × 0.6 GB)
- 起動後、ログの
memory breakdownで答え合わせをする
6. モデルのスペックの読み方
モデルを比較するとき、見るべき数値は複数ある。それぞれ意味が違い、何を左右するかも違う。混同すると選択を誤る。
6つの軸
この環境で動かしている gpt-oss-20b の実測値を例に整理する。値はすべて起動ログから取れる。
| 軸 | この例の値 | 何を意味するか | 何を左右するか |
|---|---|---|---|
| 総パラメータ | 20.91 B | モデル全体の大きさ | 必要メモリ |
| 活性パラメータ | 3.6 B | 1トークンごとに使う量 | 速度 |
| コンテキスト長 | 131,072 | 一度に読める最大の長さ | 扱える文章量 |
| 層数 | 24 | 処理を何段重ねるか | 深さ(間接的に賢さ) |
| エキスパート数 | 32 | 各層の部品の個数 | 知識の幅 |
| 同時に使う数 | 4 | そのうち毎回使う個数 | 速度(活性パラメータの決定要因) |
最も重要なのは上の2つ、総パラメータと活性パラメータである。 この2つが「メモリがいくら要るか」と「どれだけ速いか」を別々に決める。
自分で確認する方法
起動ログに出る。次のコマンドで抜き出せる。
# 起動ログをファイルに落としてから読む。-lv 5 を付けないと出力されない
llama serve -m モデルのパス -c 4096 -lv 5 > /tmp/model.log 2>&1 &
sleep 20
grep -E "n_ctx_train|n_layer|n_expert|model params" /tmp/model.log
pkill -f "llama serve"
llama serve はサーバなので自分では終了しない。ログをファイルに落とし、別途 grep で読む。
この環境での実行結果である。
n_ctx_train = 131072
n_layer = 24
n_expert = 32
n_expert_used = 4
model params = 20.91 B
各軸の詳細
総パラメータ(model params) — 第2章の計算式の入力になる。20.91 B × 0.58バイト ≒ 12.1 GB で、実際のファイルサイズと一致する。MoE でもこの全体をメモリに置く必要がある。
活性パラメータ — 起動ログには直接出ないが、モデルカードに記載されている。30B-A3B の A3B がこれである。第5章で見たとおり、速度は メモリ帯域 ÷ (活性パラメータ × 0.6 GB) で概算できる。
コンテキスト長(n_ctx_train) — 学習時に想定された最大の長さである。131,072 は日本語でおよそ6〜13万文字、文庫本1冊分に相当する。ただしこれは上限であって、実際に使う長さは起動時の -c で決める。長くするほど KVキャッシュがメモリを食うので、必要な分だけ指定する。
層数(n_layer) — 24段の処理を順に通ることを意味する。層が深いほど複雑な処理ができるが、その分1トークンあたりの計算量が増える。
エキスパート数(n_expert)と同時に使う数(n_expert_used) — MoE 特有の値である。32個のうち4個を使うので、FFN 部分の計算量は 4/32 = 8分の1 になる。この比率が MoE の効率を決める。
比較するときの手順
2つのモデルを比べるとき、次の順に見る。
- 総パラメータ × 0.6 GB がシステムRAMに収まるか — 収まらなければ検討対象外
- 活性パラメータ × 0.6 GB を 50 GB/秒 で割ると何トークン/秒か — MoE のエキスパートは
-cmoeでシステムRAM 側に固定されるので、活性分は VRAM ではなく RAM から読まれる。10 tok/s を下回るなら対話には使えない - コンテキスト長が用途に足りるか — 長文を扱うなら重要
- 同じ活性パラメータなら、総パラメータが大きいほうが賢い傾向 — 知識量が多いため
具体例で比べる
この環境(VRAM 8 GB、システムRAM 94 GB)で3つを比較する。
| gpt-oss-20b | GLM-4.7-Flash | Qwen3.8-27B | |
|---|---|---|---|
| 構造 | MoE | MoE | Dense |
| 量子化 | MXFP4 | Q4_K | Q4_K_M |
| 総パラメータ | 20.9 B | 31.2 B | 27.8 B |
| 活性パラメータ | 3.6 B | 3 B | 27.8 B(全部) |
| ファイルサイズ | 12.1 GB | 18.2 GB | 19.0 GB |
| ① RAMに収まるか | ⭕ | ⭕ | ⭕ |
| ② 1トークンで読む量 ÷ 50 GB/s | ⭕ 2.1 GB → 約24 t/s | ⭕ 1.8 GB → 約28 t/s | ❌ 19.0 GB → 約2.6 t/s |
| 速度 | 12〜19 t/s(実測) | 約15〜20 t/s | 約2.6 t/s |
判定の分かれ目は②である。 Qwen3.8-27B(Q4_K_M)は Dense なので活性パラメータ=総パラメータであり、毎回 19 GB を読む。MoE の9倍の量を、同じ 50 GB/秒 で読むことになる。
一方 GLM-4.7-Flash は総パラメータが Qwen より大きい(31.2 B)にもかかわらず、活性が 3 B しかないので7倍速い。
「大きいほど遅い」ではなく「毎回読む量が多いほど遅い」。 ここが MoE を理解する要点である。
Dense のモデルを MoE に変えることはできない
ここで当然の疑問が出る。量子化が後からできるなら、MoE 化も後からできないのか。
できない。 両者は性質が違う。
| 量子化 | MoE 化 | |
|---|---|---|
| 何をするか | 重みの記録精度を落とす | 構造そのものを変える |
| いつ可能か | 学習後でも可能 | 学習時にしか決められない |
理由は2つある。
ルーターが存在しない。 どのエキスパートを使うかを選ぶルーターは、学習を通じて「この入力ならこれを使う」という判断を獲得したものである。Dense モデルにはそもそもルーターがない。後から付け足しても、何を基準に選べばよいか分からない。
エキスパートに分かれていない。 Dense の FFN は一つの大きな塊であり、全体を通ることを前提に学習されている。これを機械的に32分割しても、「一部だけ使えば正しく動く」ようには作られていない。
したがって Qwen3.8-27B や Muse Glimmer 30B のような Dense モデルは、この環境では遅いまま使うか、使わないかの二択になる。
VRAM が増えれば判断は変わる
ただし Dense が一般的に劣るわけではない。 判断は自分の VRAM 容量によって変わる。
| GPU | VRAM | メモリ帯域 | Qwen3.8-27B Q4_K_M(19 GB)の理論値 |
|---|---|---|---|
| RTX 3070 Ti(この環境) | 8 GB | 50 GB/s(RAM側で読む) | 約 2.6 t/s |
| RTX 4090 | 24 GB | 1,008 GB/s | 約 53 t/s |
| RTX 5090 | 32 GB | 1,792 GB/s | 約 94 t/s |
なお Q8_0(30 GB)を選ぶと 24 GB の VRAM には収まらないため、RTX 4090 でも速度が落ちる。量子化の選択が、そのまま速度の分岐になる。
VRAM に収まりさえすれば、Dense でも十分に速い。しかも同じ総パラメータなら Dense のほうが賢い傾向がある(全パラメータが毎回働くため)。
つまり Dense と MoE の優劣はモデル側にあるのではなく、使う側の VRAM 容量で決まる。8 GB なら MoE 一択、24 GB 以上なら Dense も選択肢に入る。
7. モデルを動かすソフトウェア
ここまでがモデルの側の話である。次に、それを実際に動かす道具を見る。
全体は4つの部品からなる。誰が何を担当し、データがどう流れるかを図にする。
Loading diagram...
図の読み方。左から右へ、モデルが配布されてから自分が使うまでの流れである。
- ①→② は最初の1回だけ。12〜18 GB のダウンロードが走る
- ②→③ は起動のたび。ファイルをメモリに読み込む
- ③→④ が実際の利用。推論エンジンが HTTP サーバとして待ち受け、アプリはそこへ質問を送る
ここで重要なのは、④のアプリが③と HTTP で会話している ことである。だからアプリ側は「どのモデルが動いているか」を意識せずに済み、モデルだけ差し替えられる。
① Hugging Face
学習済みモデルの重みを配布するウェブサイト。ソフトウェアにおける GitHub に相当する。Qwen/Qwen3.8-27B のように「組織名/モデル名」で識別する。略称は HF。
なお、ここで配布されているモデルを オープンウェイト と呼ぶ。「オープンソース」とは区別される。公開されているのは学習済みの重みであって、訓練データや訓練コードではないことがほとんどだからである。ライセンスも Apache-2.0 のような自由なものから、独自の制限付きまで様々なので、業務で使うなら必ず条文を確認する。
② GGUF
重みを1つのファイルにまとめた形式。次に述べる llama.cpp が読む形式である。
Hugging Face で「◯◯-GGUF」というリポジトリを見かけたら、それは llama.cpp で動かすために変換済みの重み を意味する。中に Q4_K_M Q8_0 などのファイルが並んでいるのは、量子化の強さごとに別ファイルが用意されているためである。
GGUF は誰が作っているのか
モデルを開発した会社は、GGUF を出さないことが多い。 彼らが公開するのは safetensors 形式の元データ(BF16)だけで、これは llama.cpp では読めない。
そこで、有志や企業が変換して配布している。新しいモデルが公開されると、数時間から数日で GGUF 版が現れる。
OpenAI や Alibaba が safetensors を公開
↓ 第三者が変換
ggml-org / unsloth / bartowski などが GGUF を配布
↓
llama.cpp で動かす
GGUF を探すと繰り返し出てくるのが次の3者である。
| アカウント | 正体 | 特徴 |
|---|---|---|
| ggml-org | llama.cpp の開発チーム自身 | 形式の正しさが最も信頼できる。標準的な量子化のみ |
| unsloth | 学習・推論の高速化ツールを作る企業 | 種類が豊富。独自の UD- 付き量子化を持つ |
| bartowski | 個人 | 網羅性が高い。1モデルで29種類を出すこともある |
選び方は、まず ggml-org を見て、無ければ unsloth か bartowski。 これで実務上は困らない。
ただし Hugging Face は誰でもアップロードできる場であることは意識しておく。上記3者は実績があるが、無名のアカウントが配布するファイルは避けるほうがよい。変換の過程で品質を損なっている可能性を検証できないためである。
元が4ビットのモデルは変換版を使わない
gpt-oss-20b のように学習時から4ビットで公開されたモデルは、第三者の変換版を選ぶ意味がない。
元が4ビットなので、それを展開して Q4_K_M に変換しても情報は増えず、変換の誤差が乗るだけである。Q8_0 に変換すればファイルは倍になるが、中身の情報量は4ビットのままで、容量を無駄にする。
この種のモデルは公式が配布する形式をそのまま使う。 量子化の選択肢が意味を持つのは、BF16 で学習されたモデルの場合である。
名前の由来は、llama.cpp が土台にしている ggml というライブラリである。
サーバ向けのもう一つの形式として safetensors がある。これは Hugging Face の標準形式で、量子化されていない元の重みが置かれる。
③ 推論エンジン
モデルを読み込んで実際に計算する本体。主に2系統ある。
llama.cpp — 手元の1台で動かすための実装。リポジトリの説明は「LLM inference in C/C++」。
よくある誤解として「llama.cpp は CPU 専用」というものがあるが、これは誤りである。CUDA(NVIDIA)、Metal(Apple)、Vulkan、HIP(AMD)に対応している。有名になったきっかけが「GPUがなくてもCPUだけで動く」ことだったため、そう思われがちなだけである。
llama.cpp の本当の特徴は、CPU と GPU を混ぜて使えること である。モデルの一部だけを GPU のメモリに載せ、残りをシステムメモリ側で処理できる。この性質が、GPU メモリが少ない環境で決定的に効く。
vLLM / SGLang — データセンターで多数のリクエストを処理するための実装。全パラメータが GPU メモリに載ることを前提としており、システムメモリへの退避は想定していない。読む形式は safetensors。同時に多数の利用者を捌く用途では圧倒的に速いが、個人の1台では llama.cpp が適する。
Ollama — llama.cpp を土台に、使いやすさを重視して被せたもの。ollama run gemma4 の一発で動く。ただし公式ドキュメントに次の記載がある。
Ollama defaults to the following context lengths based on VRAM:
- < 24 GiB VRAM: 4k context
GPU メモリが 24 GB 未満の環境では、扱える文章の長さが自動的に 4,000 トークン程度に制限される。コーディング用途にはまったく足りない。環境変数で上書きは可能だが、後述の細かい制御ができないため、この環境では llama.cpp を直接使うほうがよい。
④ 使う側のアプリ
推論エンジンは OpenAI互換API としてサービスを提供する。これは OpenAI が定めたAPIの形式に合わせるという意味で、これに対応したアプリならコードを書き換えずにモデルだけ差し替えられる。
8. この環境で何が動くか
ここまでの知識を、冒頭の環境(GPUメモリ 8 GB、システムメモリ 94 GB)に当てはめる。
基本戦略
VRAM は 8 GB しかないが、システムRAM は 94 GB ある。したがって MoE のモデルを選び、エキスパートをシステムRAM 側に置く(-cmoe)のが最適である。
この指定で何がどこに置かれるか、なぜ「活性分だけ VRAM に載せる」ことができないかは第5章で詳しく述べた。ここでは結論だけ使う。
- メモリに必要なのは総パラメータ分(活性分ではない)
- 速度を決めるのは1トークンで読む量(総パラメータ分ではない)
候補となるモデル
すべて Hugging Face で実在を確認し、ファイルサイズを実測した。
| モデル | 量子化 | ファイルサイズ | 総/活性 | ライセンス | 評価 |
|---|---|---|---|---|---|
| gpt-oss-20b | MXFP4 | 12.1 GB | 21B / 3.6B | Apache-2.0 | 最初に試すもの |
| GLM-4.7-Flash | Q4_K | 18.2 GB | 30B / 3B | MIT | コーディング用途の本命 |
| gemma-4-26B-A4B-it | Q4_0 | 14.6 GB | 25.2B / 3.8B | Apache-2.0 | 画像も扱える |
| Qwen3.6-35B-A3B | Q4_K_M | 20.4 GB | 35B / 3B | Apache-2.0 | 汎用 |
| Qwen3.8-27B | Q4_K_M | 19.0 GB | 27B(Dense) | Apache-2.0 | 避ける(後述) |
| gpt-oss-120b | MXFP4 | 63.4 GB | 117B / 5.1B | Apache-2.0 | メモリには載る |
| Qwen3.8-2.4T-A95B | Q4_K_M 想定 | 約 1,460 GB | 2.4T / 95B | 独自 | 不可能 |
ファイルサイズは量子化の形式ごとに変わる。 上の表はいずれも4ビット級での値である。同じモデルでも Q8_0 を選べばおよそ倍、BF16 なら約4倍になる。
密なモデルを避ける理由
Qwen3.8-27B の Q4_K_M は 19 GB でシステムRAM には収まる。しかし Dense なので毎トークン 19 GB 全体を読む。同じ 50 GB/秒 で読む以上、MoE の9倍の時間がかかる。実測で 1.94 tok/s、MoE の gpt-oss-20b の6.5分の1だった(第10章)。
同程度のファイルサイズなら、必ず MoE を選ぶ。
なお表のファイルサイズは重みの分だけである。実際にはこれに KVキャッシュと計算バッファが加わる(第5章)。
9. 実際に動かす
何がどこに置かれるか
作業を始める前に、ファイルの配置を確認しておく。次はこの環境で実際にインストールした後の状態である。
Loading diagram...
要点は3つ。
- 実行ファイルは
~/.local/bin/llamaの1個だけ。 インストーラはこれを置くだけなので、消したいときはこのファイルと~/.llama-app/を削除すればよい - モデルは
~/.cache/llama.cpp/に溜まる。 1個 12〜18 GB あるので、複数試すとすぐに 100 GB を超える。ディスクを空けたいときはここを見る - 管理者権限は不要。 すべてホームディレクトリ内で完結する
インストール
公式インストーラを使う。CUDA、ROCm、Vulkan、CPU の順に環境を自動判定し、適したビルドを ~/.local/bin/llama に配置する。
curl -LsSf https://llama.app/install.sh | sh
~/.local/bin が PATH に入っていない場合は追加する。
export PATH="$HOME/.local/bin:$PATH"
インストールされたか確認する。
llama --version
llama serve --list-devices
--list-devices で GPU が表示されれば、GPU が使える状態である。
起動
llama serve -hf ggml-org/gpt-oss-20b-GGUF -cmoe -c 32768 \
--host 127.0.0.1 --port 8080 --jinja
各オプションの意味は次のとおり。
| オプション | 意味 |
|---|---|
-hf 組織名/リポジトリ名 | Hugging Face から自動で取得する |
-cmoe | MoE のエキスパートをシステムメモリ側に置く |
-c 32768 | 扱える文章の長さ(トークン数) |
--host --port | 待ち受けるアドレスとポート |
--jinja | モデル付属の会話テンプレートを使う |
-hf を指定すればモデルは自動的にダウンロードされるので、手動で用意する必要はない。
量子化の強さを指定する場合はコロンで続ける。
llama serve -hf ggml-org/GLM-4.7-Flash-GGUF:Q8_0 -cmoe -c 32768
指定できるのは、そのリポジトリに実在するファイル名だけである。 ggml-org/GLM-4.7-Flash-GGUF にあるのは Q4_K と Q8_0 の2つで、中間の Q5_K_M は無い。欲しい場合は unsloth か bartowski の同名リポジトリを探す。なお gpt-oss-20b は MXFP4 固定なので、そもそもこの指定は使えない。
複数のモデルを使い分ける
モデルを2つ以上入れると、起動コマンドを毎回打つのが面倒になる。この環境には切り替え用のスクリプトを置いてある。
~/.cache/llama.cpp/run.sh # 使えるモデルの一覧
~/.cache/llama.cpp/run.sh gpt-oss # gpt-oss-20b を起動(MoE・速い)
~/.cache/llama.cpp/run.sh qwen # Qwen3.8-27B を起動(Dense・遅い)
~/.cache/llama.cpp/run.sh stop # 停止
別のモデルを起動すると、動いていたモデルは自動的に停止する。
環境変数で挙動を変えられる。
PORT=8081 ~/.cache/llama.cpp/run.sh gpt-oss # 別ポートで起動
CTX=8192 ~/.cache/llama.cpp/run.sh qwen # 文脈長を減らしてメモリを節約
なお run.sh は起動前に既存のサーバを停止するため、このスクリプトでは2つを同時に動かせない。同時に動かすなら llama serve を直接2回起動する。
スクリプトの中で、モデルの構造に応じてオプションを変えている。
| モデル | 指定しているオプション | 理由 |
|---|---|---|
| gpt-oss-20b | -cmoe | MoE なのでエキスパートをシステムRAMへ |
| Qwen3.8-27B | なし | Dense には -cmoe が効かない(エキスパートが存在しないため) |
動作確認
サーバが起動したら、別の端末から確認する。
curl -s http://127.0.0.1:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"local","messages":[{"role":"user","content":"1+1は?"}]}' \
| python3 -m json.tool
速度が出ないときの調整
次の順に試す。
-cmoeで起動する(全エキスパートをシステムメモリへ)nvidia-smiで VRAM に余裕があれば、-cmoeの代わりに-ncmoe Nを使う。N は「CPU 側に残す層数」なので、減らすほど GPU に移る。24層のモデルなら-ncmoe 20から始め、余裕を見て 16, 12 と下げる(-ncmoe 24以上は-cmoeと同じ)- それでも足りなければ
-ctk q8_0 -ctv q8_0で KVキャッシュを半分にする -cの値を下げて、扱う文章の長さを減らす
10. 実測 — MoE と Dense を同じ条件で比べる
第4章で示した「毎回読む量が速度を決める」という原則を、実測で確認した結果である。
測定環境
| 項目 | 値 |
|---|---|
| GPU | NVIDIA GeForce RTX 3070 Ti(VRAM 8 GB) |
| CPU | Intel Core i9-11900K(16スレッド) |
| システムRAM | 94 GB(DDR4) |
| OS | Ubuntu |
| llama.cpp | b10217(Vulkan ビルド) |
| 測定日 | 2026-08-25 |
注意点として、この環境には CUDA 版ではなく Vulkan 版が入っている。 インストーラが CUDA を検出できなかったためである(ドライバ 535 が新しい CUDA ビルドの要件を満たさない)。GPU は正常に使えているが、CUDA 版ならもう少し速い可能性がある。
測定条件
両モデルとも同一の条件で測った。
プロンプト : 「Pythonでフィボナッチ数列を返す関数を書いてください。コードのみ。」
文脈長 : -c 32768
温度 : temperature = 0(毎回同じ答えになる設定)
出力上限 : max_tokens = 250
起動オプションだけがモデルの構造に応じて異なる。
| モデル | オプション | 理由 |
|---|---|---|
| gpt-oss-20b | -cmoe | MoE なのでエキスパートをRAMへ |
| Qwen3.8-27B | なし | Dense には -cmoe が効かない |
結果
| gpt-oss-20b | Qwen3.8-27B | |
|---|---|---|
| 構造 | MoE 20.9B / A3.6B | Dense 27.8B |
| 量子化 | MXFP4(約4.6 bpw) | Q4_K_M(約4.9 bpw) |
| ファイルサイズ | 12.1 GB | 19.0 GB |
| VRAM 使用量 | 3.6 GB | 6.1 GB |
| 生成速度 | 12.53 tok/s | 1.94 tok/s |
| プロンプト処理速度 | 28.23 tok/s | 6.99 tok/s |
| 250トークンの生成時間 | 20 秒 | 129 秒 |
生成速度で 6.5 倍の差がついた。
量子化形式が揃っていないことについて
両者は量子化の形式が異なる。1パラメータあたりのビット数は 4.6 対 4.9 でほぼ同等だが、成り立ちが違う。
| MXFP4(gpt-oss-20b) | Q4_K_M(Qwen3.8-27B) | |
|---|---|---|
| いつ4ビットになったか | 学習時から4ビット | 学習後に丸めた |
| BF16 版の存在 | 無い | 有る |
| 第3章の劣化の議論 | 当てはまらない | 当てはまる |
量子化形式を揃えることは技術的には可能である。第三者が Q4_K_M や IQ4_NL に変換した版を配布しているためである(unsloth に16種、bartowski に29種)。
しかしそうする意味がない。 gpt-oss-20b は元が MXFP4 なので、それを展開して別の4ビット形式に変換しても情報は増えず、変換の誤差が乗るだけである。Q8_0 に変換すればファイルは大きくなるが、中身の情報量は MXFP4 のままである。
したがって gpt-oss-20b については、公式の MXFP4 を使うのが正しい。
ただしこの違いは速度の比較には影響しない。 速度を決めるのは1トークンあたりに読むバイト数であり、両者のビット数はほぼ同じだからである。速度差 6.5 倍は量子化形式ではなく、MoE と Dense の構造の違いから来ている。
一方、出力の品質を比べる用途にはこの2つは使えない。 量子化形式もモデルの素性も違うため、どちらが優れているかを判定する材料にならない。
計算値との照合
第5章の式で予測した値と比べる。
予測 = メモリ帯域 ÷ 1トークンあたりに読む量
gpt-oss-20b (MXFP4, MoE) : 50 GB/s ÷ 2.1 GB ≒ 24 tok/s → 実測 12.5 tok/s
Qwen3.8-27B (Q4_K_M, Dense): 50 GB/s ÷ 19.0 GB ≒ 2.6 tok/s → 実測 1.9 tok/s
いずれも実測は予測の半分から7割程度に収まった。式は速度の上限を与えるもので、実際には計算そのものの時間や層をまたぐ処理が加わるため、これより遅くなる。桁を見積もる道具としては十分に使える。
重要なのは比率である。予測では 24 ÷ 2.6 ≒ 9倍、実測では 12.5 ÷ 1.9 ≒ 6.5倍。「毎回読む量が速度を決める」という仮説は、実測でも成立している。
体感での差
250トークンは日本語でおよそ 150〜250 文字、短い関数1つ分である。
| 250トークン | 2,000トークン(実務的な回答1つ) | |
|---|---|---|
| gpt-oss-20b | 20 秒 | 約 2.7 分 |
| Qwen3.8-27B | 129 秒 | 約 17 分 |
Dense のほうは、投げて他の作業をして戻ってくる使い方になる。対話には向かない。
推論モデルは出力上限を大きく取る
モデルには2種類ある。質問に直接答えるものと、答える前に思考の過程を出力するものである。後者を推論モデルと呼ぶ。Qwen3.8-27B は推論モデルである。
推論モデルでは、生成されるトークンの多くが思考に費やされる。したがって max_tokens(1回の応答で生成する上限)を小さく設定すると、思考の途中で打ち切られ、答えが出力されない。
ここで2つの数値を混同しないこと。
| 意味 | 誰が決めるか | |
|---|---|---|
| コンテキスト長 | 入力と出力を合わせて保持できる上限 | 起動時の -c |
| max_tokens | 1回の応答で生成する上限 | 呼び出し時のパラメータ |
推論モデルには 2,000 以上を目安に指定する。
結論
この環境では MoE を選ぶべきである。
| 判定 | |
|---|---|
| gpt-oss-20b(MoE) | **実用的。**対話に使える速度 |
| Qwen3.8-27B(Dense) | 遅い。同容量のMoEを選ぶほうがよい |
ただし第6章で述べたとおり、これは VRAM 8 GB という条件下での結論である。 VRAM が 24 GB あれば Qwen3.8-27B は VRAM に収まり、理論上は約 53 tok/s で動く。モデルの優劣ではなく、環境との組み合わせの問題である。
11. Claude Code でローカルモデルは使えるか
使えない。 Claude Code は Anthropic の Claude モデル専用である。
よくある誤解として「ANTHROPIC_BASE_URL をローカルサーバに向ければ動く」というものがあるが、公式ドキュメントがこれを明確に否定している。
ANTHROPIC_BASE_URLchanges where requests are sent, not which model answers them.
(ANTHROPIC_BASE_URL は「リクエストの送り先」を変えるだけであり、「どのモデルが答えるか」を変えるものではない)
公式にサポートされている構成は、Anthropic API のほか Amazon Bedrock、Google Cloud Agent Platform、Microsoft Foundry 経由だが、いずれも中身は Claude である。Claude Agent SDK も同様に Claude 専用である。
理由は、Claude Code が Claude 向けに設計された ハーネス だからである。ハーネスとは、モデルを取り囲んでツールの実行・権限管理・文脈管理を担う層を指す。Claude Code のツール定義の形式や内部プロンプトの構造は Claude を前提にしており、他のモデルを差し込む口が存在しない。
ではローカルモデルをどう使うか
公式に可能な方法が2つある。
MCP サーバ経由 — ローカルモデルを MCP(Model Context Protocol)サーバでラップし、Claude Code からツールとして呼ぶ。「Claude Code がローカルモデルになる」のではなく、「Claude Code がローカルモデルを道具として使う」形である。大量のテキスト処理や、外部に送信できないデータの処理に向く。
Bash から直接呼ぶ — llama serve を起動しておき、curl で叩く。非公式だが実験には十分である。
なお、ローカルモデルでコーディングエージェントを動かしたい場合は、Claude Code ではなく OpenAI互換エンドポイントを指定できる別のハーネス を使うのが正しい選択である。
12. モデルを作る側のコスト
ここまでは「配布されたモデルを使う」側の話だった。作る側にいくらかかるのかを知っておくと、オープンウェイトが公開されていることの意味が変わって見える。
実務家による見積もり(2026年8月時点)
日本の機械学習研究者 Odashi 氏が X 上で示した金額である。個人の見積もりであり、公式に検証された数値ではない点に注意すること。
300B-A30B 級のモデルを、Qwen と同等の学習量で作る場合:
| 項目 | 金額 |
|---|---|
| 学習を1回走らせる | 約 50 億円 |
| バッファ・予備実験・その他の手続きを含む実際の総額 | 約 300 億円 |
300B-A30Bくらいの大きさのモデルかつQwenと同じ学習量であれば、手元の基準で学習一発がざっくり50億円なので、バッファ、予備実験、他の手続き用に最低5倍用意するとして300億円とかですかね
出典: https://x.com/odashi_t/status/2087485648592941526 (2026-08-12)
学習の本番は総額の6分の1にすぎない。 残りは失敗した実験、データの準備、人件費などである。1回で成功する前提の計算は現実的でない、ということでもある。
継続するか、追いつけるようにしておくか
同じ議論で、2つの戦略のコスト差も語られている。
| 戦略 | 見積もり |
|---|---|
| 常に最先端の1世代前を自力で出し続ける | 約 100 億円 |
| 普段は作らず、必要になってから半年で追いつく | その約10倍 |
前者は100億円位あれば出来るんじゃないでしょうか(実際LLM-jpがもっと強い縛り条件付きで出来てる)。後者の状況になると恐らく国内に人材も計算資源もない状況なので、基本的な準備だけでその10倍くらいかかりそうです。
作り続けるほうが、必要になってから始めるより安い。 理由は金額ではなく、人材と計算資源が組織の外に流出してしまうためである。
この文書との関係
第6章で挙げたモデルは、いずれも数十億から数百億円をかけて作られたものが、無償で配布されている。
| モデル | 作った組織 |
|---|---|
| gpt-oss-20b | OpenAI |
| GLM-4.7-Flash | Z.AI |
| Qwen3.8 系 | Alibaba |
| gemma-4 系 |
手元の 12 GB のファイルは、その規模の投資の産物である。 ダウンロードして動かすコストは、電気代とディスク容量だけで済む。
同時に、これは作る側に回るのは現実的でないことも意味する。個人や中小組織にとって、選択肢は「配布されたものを使う」か「既存のモデルを自分のデータで追加学習する」かのどちらかになる。
13. モデルの良し悪しをどう判断するか
リーダーボード(順位表)は数多くあるが、鵜呑みにできないものが多い。オープンウェイトについては次の3つが2026年8月時点で生きている。
| サイト | 測定主体 | 備考 |
|---|---|---|
Artificial Analysis /models/open-source | 自前で全モデルを実行 | オープンウェイト専用ページあり |
Epoch AI /topics/open-models | 自前と外部を明示分類 | 全データがCC BY 4.0でダウンロード可 |
| Hugging Face Hub の Eval API | 自己申告の転記 | 構造上オープンウェイトのみ。要クロスチェック |
なお、かつて標準的だった Hugging Face Open LLM Leaderboard は2025年3月に終了しており、データは凍結している。引用してはならない。
順位表を読むときの注意
信頼区間を見る。 上位のモデル同士はスコアが接近しており、誤差の範囲で重なっていることが多い。「1位」に意味があるとは限らない。
pass@1 と明記されているか確認する。 pass@1 は1回で正解した割合、pass@k は k 回のうち1回でも正解した割合である。同じモデルで pass@1 が 42%、pass@16 が 71% ということが普通に起きる。回数を明記しない順位表は信用しない。
最終的には自分のタスクで測る。 Anthropic の評価ガイドは、実際の失敗事例から20〜50件のタスクを集めることを推奨している。
20-50 simple tasks drawn from real failures is a great start
ただし注意点がある。「AとBのどちらが優れているか」を統計的に言い切るには、3ポイントの差を検出するのに約1,000問が必要である(arXiv:2411.00640)。現実的には、20〜50件で「自分の用途で使い物になるかどうか」を判断し、順位は付けないのが正しい姿勢である。
14. まとめ
| 判断 | 根拠 |
|---|---|
| MoE を選ぶ | メモリは総パラメータ分必要だが計算は活性分だけ。GPU メモリが少ない環境で決定的 |
| 密なモデルは避ける | 毎トークンごとに全パラメータを読み出すため、同サイズの MoE の5〜10分の1の速度 |
| Q4 が実用の下限 | 3ビット以下でコード生成が明確に劣化する |
| 日本語の長文は Q5 以上 | 4ビットでは長文タスクが最大59%低下し、非英語入力でさらに悪化する |
| ファイルサイズ ≠ 必要メモリ | KVキャッシュと計算バッファが別途必要 |
| ベンチマークは自分のタスクで | 量子化の劣化は難しいタスクに集中するため、簡単なテストでは検出できない |
最初の一歩
curl -LsSf https://llama.app/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
llama serve -hf ggml-org/gpt-oss-20b-GGUF -cmoe -c 32768 --port 8080 --jinja
出典
すべて実際にページを取得して原文を確認したもの。
| 内容 | 出典 |
|---|---|
| llama.cpp のオプションと仕様 | https://github.com/ggml-org/llama.cpp |
| 難易度による劣化の非対称性 | arXiv:2504.04823(COLM 2025) |
| 低確信サンプルが先に壊れる機序 | arXiv:2405.00632(NAACL 2024 Findings) |
| 長文脈・非英語での劣化 | arXiv:2505.20276(EMNLP 2025) |
| コード生成での量子化影響 | arXiv:2503.07103 |
| 4ビットで指示追従が崩れる | arXiv:2407.09141(NeurIPS 2024) |
| 評価タスクの作り方 | https://www.anthropic.com/engineering/demystifying-evals-for-ai-agents |
| 差の検出に必要なサンプル数 | arXiv:2411.00640 |
| Claude Code のモデル制約 | https://code.claude.com/docs/en/model-config |
| Ollama のコンテキスト長制限 | https://github.com/ollama/ollama/blob/main/docs/context-length.mdx |
作成日: 2026-08-25