兆パラメータモデルの再起動、8.8分から32秒に短縮

8月21日、Ant GroupのLing基盤チームはAlibaba、SGLangチームとともに、LMSYSのブログでWeight Cache Daemonというコンポーネントを公開した。GPUメモリに常駐するプロセスが、量子化・分割済みの重みを保持し続け、新たに起動する推論エンジンがCUDA IPC経由でゼロコピーでマッピングできるというものだ。チームが示した数値によると、Ling-2.6-1T FP8の重み読み込みは約495秒から0.63秒に、起動全体は8.8分から0.528分に短縮された。

8分半のうち8分がディスク読み込みだった

チームは起動プロセス全体を分解して計測した。Ling-2.6-1T FP8をH20-3e×8基で動かし、重みは3.5TのNVMe SSDに置いた場合、起動からリクエストを受け付けられるまでに約527秒かかった。このうち重み読み込みが495秒、割合にして93.9%を占める。tokenizer初期化が13秒、torchの分散初期化が5秒、CUDA graphのキャプチャが7.7秒、残りを全部足しても6秒未満だった。

各GPUはディスクから約120GBのsafetensorsを読み込み、デシリアライズし、テンソル並列に沿って分割したうえでFP8量子化と重みの並べ替えを行う。分割数は合計161にのぼる。この一連の処理は再起動のたびに最初からやり直す必要があるが、出力自体は決定的だ。同じモデル、同じ設定であれば、最終的にGPUメモリに乗るテンソルは毎回同一であり、多くの場合、直前のプロセスが終了した時点でまだそこに残っている。

本番環境にとって、この数分間はP99のテール遅延が再起動のたびに跳ね上がり、処理中のリクエストがすべて失敗するか無限に待たされることを意味する。ローリングアップグレードや障害復旧もこの周期に縛られてしまう。

重みをGPUメモリに残しておく

各GPUではTP rankごとに1つのdaemonプロセスが動く。daemonは一度だけフルパイプラインでディスクから読み込み、model.state_dict()に含まれるすべてのパラメータとバッファをCUDA IPCハンドルとしてエクスポートし、Unixソケット経由で接続してきたエンジンプロセスに渡す。エンジン側はまずmeta device上でモデル構造だけを組み立て、メモリは一切確保しない。そのうえで各パラメータのdataポインタをマッピングされたテンソルに向ける。2つのプロセスは同一の物理GPUメモリを共有し、コピーは一度も発生しない。FP8量子化の過程で生成されるweight_scaleなどの後処理パラメータもあわせてキャッシュされ、量子化のやり直しを省く。

安全対策として2段階のチェックが入っている。ひとつは設定のフィンガープリントで、モデルパス、TP/PP/DPの分割、量子化方式と設定のハッシュ、dtypeが一致している必要があり、さらにGPUの計算能力とtorchのバージョンも環境情報として記録される。アーキテクチャやtorchバージョンが異なると後処理の分岐が変わり、重みはマッピングできても値が壊れてしまう場合がある。環境情報をフィンガープリントに含めることで、こうした見えにくい不整合を明示的な不一致として検出し、ディスクからの読み込みにフォールバックさせる。

もうひとつは量子化方式のホワイトリストだ。現時点で検証済みなのは非量子化とblock-wise FP8のみで、per-tensor FP8、Marlin、AWQ/GPTQは即座にエラーになる。理由は、IPCが生のテンソルデータしかエクスポートしないのに対し、これらの方式は効果の一部をPython側のメタデータに持たせたり、重みの並べ替えや転置を行ったりするためだ。マッピングをそのまま行うと値が誤ったものになる。チームは誤った結果を静かに返すのではなく、明確にエラーを出す設計を選んだ。

daemonがクラッシュしても稼働中のエンジンには影響しない。CUDAの参照カウントが生きている限りメモリは保持され、両方のプロセスが終了して初めて解放される。daemonが再起動すると、再度ディスクから読み込みハンドルを再エクスポートし、新しいエンジンが再び接続できるようになる。

ついでにホットスタンバイのコストも解決した

このコンポーネントには3つのモードがある。daemon(エンジン自身がdaemonを起動、初回起動は従来通り遅い)、client(稼働中のdaemonに接続し、秒未満で再起動できる)、off(デフォルト。ディスクから読み込み、Ling-2.6-1Tでは405〜411秒かかる)。

起動の高速化以上に実務的なのは、いくつかのデプロイ形態が可能になる点だ。同じGPU上で複数のエンジンインスタンスが同じ重みをマッピングすれば、ディスク読み込みも量子化も一度で済む。優先度の高いオンラインサービスと優先度の低いオフラインバッチ処理が同じGPUを共有し、後者がプリエンプトされても秒未満で再起動できる。主系・待機系の切り替えでは、待機系エンジンが同じ重みをゼロコピーでマッピングしてウォームな状態を保ち、主系がダウンしてから1秒以内に引き継ぐ。

最後の点は明確なコスト項目になる。ざっと計算すると、Ling-2.6-1Tのインスタンス1つは8基のH20-3eを占有する。従来型のホットスタンバイでは、その隣にさらに8基を常時アイドル状態で待機させる必要があった。重み共有型のスタンバイに切り替えれば、この常時アイドルのGPU群がまるごと不要になる。ローリングアップグレードも同様で、8.8分に1回のペースだとすると、インスタンスごとに1回のアップグレードで約1.2GPU時間のアイドルを消費する計算になり、インスタンス数が百を超えるクラスタでは1回のアップグレードで3桁のGPU時間が積み上がる。

まだ終わっていない

Weight Cache DaemonはFast Engine Recovery Frameworkの第一段階にすぎない。ロードマップにはコールドスタート10秒以内、ホットスタンバイ切り替え1秒以内という目標が掲げられている。次はCUDA graphのシリアライズ、kernelキャッシュ、分散初期化の最適化に取り組む計画だ。上記の分解結果からすると、これらを合計すると約26秒で、重み読み込み以外に残る最大の部分にあたる。

Qwen3-235B FP8クラスの数値も併せて公開された。重みは約235GBで、ディスクからの読み込みは306〜327秒、IPCマッピングは1秒未満で、約500倍の高速化にあたる。Ling-2.6-1Tクラスでは約780倍に達する。

ブログでは発表されたばかりの2.8TパラメータのKimi K3にも触れている。パラメータ数が増えるほどディスク読み込み時間はほぼ線形に伸びる一方、IPCマッピングはほぼ一定のままで、この差は開く一方だ。すでに兆パラメータ級のモデルを運用しているチームにとって、再起動のコストは「数分待つ」ものから「ほとんど待たない」ものへと変わりつつある。この変化が影響するのは可用性の数字だけでなく、設定を頻繁に変える勇気や、同じGPUに2つのサービスを詰め込む勇気にも及ぶ。

参考資料:LMSYS Org技術ブログ、CocoLoop、SGLangプロジェクトのドキュメント。起動時間の内訳、重み読み込みとIPCマッピングの比較数値は、いずれもチームが公開した単一ノードのベンチマーク表に基づく。