開発
59GBの国産32B MoE「LLM-jp-4」を16GBのM2 Macで動かす——1バイトも増やさず2ビット崩壊を解消した「Project Pyrite」
2026/10/29
1. 16GB Mac における「32B MoE」というスイートスポット
ローカルLLMを Mac(Apple Silicon 16GB 統合メモリ)で動かす際、これまでは「8B〜9B の 4ビット量子化(約5.5〜6.5GB)が快適、13B〜14B が上限」というのが定石だった。
しかし、MoE(Mixture-of-Experts) アーキテクチャはこの前提を覆すポテンシャルを持っている。国立情報学研究所(NII)を中心とする LLM-jp が公開した llm-jp/llm-jp-4-32b-a3b-base は、総パラメータ数こそ 31.8B(約320億) だが、各トークンで実際に計算される活性パラメータは 128個のエキスパートのうち上位8個(約3.0B相当) に過ぎない。
Apple Silicon の推論速度は「1トークンあたりにメモリから GPU へ読み出す重みのバイト数」で決まる。もし 32B MoE を 16GB メモリに収めることができれば、「知識の引き出しは 32B クラスでありながら、推論速度は 3B クラス並みに速い」 という理想的なローカルLLM環境が手に入る。
問題はサイズだ。元の BF16 モデルは 59.06 GiB あり、4ビット量子化でも約 16.5 GiB となって 16GB Mac ではスワップが発生して使い物にならない。16GB Mac の安全上限(context_len=4096 時にピーク 11.25 GiB 以下)に収めるには、2ビット領域(約 9.81 GiB) まで圧縮する必要がある。
2. 単純な2ビット量子化で起きる「反復ループ崩壊」
ところが、mlx-lm でエキスパート層を一括して 2-bit (group_size=64) に量子化すると、サイズは 9.8105 GiB(10,533,950,464 bytes) に収まるものの、日本語生成で深刻な品質劣化が起きる。
たとえば、ことわざ「急がば回れ」の由来を尋ねると、標準2ビットモデルは以下のように同じ文を無限に繰り返すループ崩壊を起こしてしまう:
【標準 2-bit Baseline の出力】 …室町時代の連歌師・宗長が詠んだ和歌に由来する。宗長が京都から駿河へ帰る際、琵琶湖を渡る船に乗るか、遠回りをして陸路を行くか迷った末に詠んだ歌である。宗長が京都から駿河へ帰る際、琵琶湖を渡る船に乗るか…(※4回連続ループ)
そこで私たちが立ち上げた 「Project Pyrite」 では、ひとつの厳格なルールを課した。
「標準 2-bit モデルと 1バイトの狂いもない完全同一サイズ(10,533,950,464 bytes)のまま、どこまで元の BF16 モデルの知能を取り戻せるか?」 である。
3. 鍵は「後半層の down_proj」と「ルータの8ビット保護」
16GB の M2 Pro 上で 59GB の BF16 教師モデルを1層ずつストリーミング実行し、全 32層 × 3射影 × 128エキスパート = 12,288個の行列 について、実際の日本語トークンが通過した際の量子化誤差を計測した。すると、極めて明確な偏りが浮かび上がった。
- SwiGLU の外れ値を直撃で受ける後半層
down_projの感度爆発 MoE の各エキスパートはgate_proj、up_proj、down_projの3つの射影で構成される。gate_projとup_projの出力は SwiGLU 活性化関数で掛け合わされるため、ここでスパースな巨大外れ値(Activation Outlier)が発生する。その外れ値を直接入力として受け取り、残差ストリームへ書き戻す 後半層(第21〜31層)のdown_projは、他の層の 3〜8倍 も量子化誤差に敏感だったのである。 - わずか
9.8 MiBで守れる MoE ルータ(mlp.gate) 128個のエキスパートのうちどれを選ぶかを決めるルータ行列は、全32層合わせても全体の 0.1%未満 しかない。ここを8-bit(合計0.0098 GiB) で保護するだけで、エキスパート本体が2ビット化されていても BF16 原モデルとの Top-8 エキスパート選択一致率が平均98.25%(最低層でも96.73%)維持される ことが判明した。
4. 「1バイトも増やさない」等価交換レシピと結果
MLX のアフィン量子化では、グループサイズを 64(実効 2.50 bit)から 128(実効 2.25 bit)に広げると、スケール・バイアスのメタデータ容量が浮く。
そこで、比較的感度の低い gate_proj と up_proj を group_size=128 に変更して 629,145,600 bytes(0.5859 GiB) の予算を捻出し、その同じ 629,145,600 bytes を使って高感度な down_proj 等を 3-bit (group_size=64) へ昇格させた。
| モデル構成 | 総テンソル容量 | 日本語 Held-out KL ($\downarrow$) | 日本語 Held-out PPL ($\downarrow$) | Top-1 一致率 ($\uparrow$) |
|---|---|---|---|---|
| BF16 原モデル(教師) | 59.06 GiB | 0.0000 | 7.45 | 100.0% |
標準 2-bit Baseline (2bit_g64) | 9.8105 GiB (10,533,950,464 B) | 0.3583 | 10.84 | 72.2% |
Pyrite 6a(層・射影混合 / mlx-lm 標準互換) | 9.8105 GiB (10,533,950,464 B) | 0.3190 (-10.98%) | 10.35 | 73.2% |
| Pyrite 6b(Expert単位ティアリング) | 9.8105 GiB (10,533,950,464 B) | 0.2791 (-22.11%) | 9.90 | 75.2% |
結果として、1バイトも同じサイズのまま KL ダイバージェンスは最大 -22.11% 減少し、先ほどの「急がば回れ」のプロンプトでも反復ループが完全に消え、宗長の和歌(「もののふの矢橋の船は速けれど急がば回れ瀬田の長橋」)と琵琶湖・比叡山おろしの背景まで正確に解説できるようになった。
さらに 16GB M2 Pro 上で Metal の Wired Limit を 11.0 GiB に設定して全重みをオンメモリ常駐させると、34〜49 tokens/sec という軽快な速度で 32B MoE の推論が可能となった。作成したモデルは masahiroid/llm-jp-4-32b-a3b-base-Pyrite-2bit-MLX として Hugging Face で公開している。