744Bのフロンティア級モデルを、GPUなしで、しかもRAMが25GBしかないノートPCで動かす。しかもちゃんと正しい答えを返す。そんな話をHacker NewsのShow HNで見かけて、最初は誇張だろうと思った。実際にリポジトリを読むと、誇張ではなかった。ただし正直な但し書きが付く。速度はおよそ0.1トークン/秒。夜通し回してようやく1本の返答、という世界だ。
作者いわく「大事なのは、そこへ到達するまでの道のりだった」。このcolibriという小さなエンジンが面白いのは、速さではなく、大きなモデルを動かすときに本当に必要なメモリは何なのか、という前提を組み替えている点にある。
なぜ744Bは普通400GBのメモリを要求するのか
まず素朴な壁の話から。LLMを推論するには、モデルの重みをどこか高速にアクセスできる場所、つまりGPUのVRAMか、せめてCPUのRAMに載せておく必要がある。パラメータ数がそのまま容量になる。GLM-5.2は744Bパラメータのモデルなので、4bit量子化(int4、重みを4bitに丸めてサイズを1/4に縮める手法)でもおよそ372〜475GBを占める。これはUnslothの実行ガイドが示す実測値で、要するに複数のGPUか大容量サーバがないと載らない。
ところがGLM-5.2は「MoE(Mixture of Experts、専門家混合)」というアーキテクチャを採る。ネットワークの各層に256個の小さなサブネットワーク(エキスパート)を並べておき、入力トークンごとにルーターがそのうち数個だけを選んで通す。744Bという巨大な看板の裏で、1トークンを処理するのに実際に火が入るのは約40Bぶんだけだ。残りの大半は、そのトークンに関しては眠っている。
この「ほとんどのパラメータは、いま計算しているトークンにとっては冷たい」という性質が、colibriの出発点になる。
常駐させるのは働きづめの部分だけ
colibriの発想は、モデルを二つに割ることだ。
一つは、どのトークンでも必ず通る部分。アテンション、共有エキスパート、埋め込みなど約17Bぶんで、これはint4で約9.9GB。ここは常にRAMに置く。もう一つが、75個のMoE層に散らばる合計21,504個の routed エキスパート。int4で1個あたり約19MB、全部で約370GBある。これは常駐させず、ディスク(NVMe SSD)に置いておき、ルーターがそのトークンで選んだものだけを、必要になった瞬間に読み込む。
OSのデマンドページングを、モデルの重みに対して自前でやっていると考えると腑に落ちる。よく使うエキスパートは層ごとのLRUキャッシュに残し、.coli_usageというファイルに使用頻度を記録して、次回以降は熱いエキスパートを優先的にメモリへ固定する。使うほど賢くキャッシュが育つ設計だ。
数字で並べると、同じモデルでも要求スペックがまるで変わる。
| 通常のint4実行 | colibri | |
|---|---|---|
| 常駐メモリ | 約372〜475GB | 約9.9GB(RAM) |
| 重みの置き場所 | 全部メモリ | ディスク約370GB+一部RAM |
| 想定ハード | 複数GPU/大容量サーバ | 25GBのPC+NVMe SSD |
| ピークRSS | — | 約20GB(自動で上限管理) |
つまりcolibriは、VRAMの壁をディスク容量の壁に付け替えた。SSDの370GBは、GPUの370GBよりずっと安い。
ボトルネックはディスクの読み出し速度に移る
代償はもちろん速度だ。1トークンごとに、選ばれたエキスパート約11GBぶんをディスクから読む。冷えた状態ではこの読み出しがそのまま律速になり、1GB/s級のドライブでは0.05〜0.1トークン/秒に落ち着く。作者の開発機(WSL2、25GB RAM)の実測がまさにこのあたりだ。
速度はハードで大きく変わる。コミュニティの計測では、Intel Core Ultra 7 270K(24スレッド、24GB)で0.11トークン/秒、Apple M5 Max(128GB、内蔵SSD)では1.06トークン/秒まで伸びている。作者の見立てでは、PCIe5のNVMeやRAID0で帯域を8〜12GB/s確保し、熱いエキスパートがRAMに載る状況なら2〜4トークン/秒は狙えるという。ここは実測ではなく予測だと明記されている点は正直だ。
速度を稼ぐ工夫も入っている。GLM-5.2が持つMLA(Multi-head Latent Attention)によってKVキャッシュは通常比57分の1に小さく、さらにMTP(Multi-Token Prediction)による投機的デコードで1回の前向き計算あたり2.2〜2.8トークンを進める。この投機のドラフト用ヘッドだけはint8で持つ必要があり、int4に落とすとドラフトの採択率が0〜4%まで崩れる、という細かい知見も書かれていて、量子化を一律に効かせてはいけないことがよく分かる。
手元で試すには
エンジンは実行時ゼロ依存の純粋なC。中核はc/glm.cのおよそ1,300行に、safetensorsリーダーとBPEトークナイザのヘッダが付くだけだ。BLASもPythonもGPUも実行時には要らない。動かす手順はリポジトリのとおり短い。
cd c
./setup.sh # gcc/OpenMPを確認し、ビルドと自己テスト
./coli convert --model /nvme/glm52_i4 # FP8→int4変換(初回のみPythonが必要)
COLI_MODEL=/nvme/glm52_i4 ./coli chat
変換ステップは、公式のFP8チェックポイント(合計756GB)を5GBのシャード単位で順に落としては量子化し、済んだシャードを消して進む方式なので、756GBを一度に置く必要はない(中断からの再開も可能)。実行にはLinuxかWSL2、AVX2対応CPU、そしてNVMe SSDが要る。--topp 0.7を付けるとルーターの選ぶエキスパートを絞り、ディスク読み出しを3〜4割減らせる。
これは何の合図なのか
実務でこれをそのまま使う場面は、正直まだ思いつかない。0.1トークン/秒はチャットには遅すぎるし、作者自身がint4での正答率(フル精度との品質差)はまだ測れていないと認めている。ベンチ用のハーネスは用意したものの、1GB/sのディスクでは1回の前向き計算に丸一日かかるため後回し、という状態だ。安いSSDを読み出しで酷使し続ける発熱・摩耗のリスクも、ノートPCの半田付けストレージでは無視できない。
それでもこのプロジェクトが示す方向は無視しにくい。MoEの「使うのは一部だけ」という性質と、ストレージ階層(RAMとSSDの速度差)を突き合わせれば、モデルサイズと必要メモリを切り離せる。フロンティア級の重みを、GPUの潤沢なVRAMではなく、常駐部分だけをRAMに、残りを速いストレージから流し込む形で扱う。この分割の考え方自体は、推論の民主化を語るうえで筋がいい。速いNVMeとRAMが潤沢な環境なら数トークン/秒という予測が本当なら、「個人が自宅のマシンでフロンティア級のオープンモデルを動かす」ラインは、GPUの値段ではなくSSDの帯域で引き直されることになる。1,300行のCが、その仮説を最小構成で叩きつけてきた、というのが自分の受け取り方だ。