マルチモーダル視覚言語モデル(VLM)はAIに視覚をもたらしますが、推論エンジンの最適化はまだ追いついていません。Modalチームは顧客向けにQwen2.5-VL-3Bモデルのベンチマークを実施中、SGLangのスループットがGPUの限界を大きく下回っていることに気づきました。その原因を探るため、スケジューラのプロファイリングを行いました。
SGLangのスケジューラは、GPUへのジョブ発行を制御する単一スレッドのループです。py-spyを用いて30秒間のマルチモーダルトラフィックをサンプリングすると、process_input_requests関数がスケジューラCPU時間の約13%を消費していました。さらに深掘りすると、その大半はhash_feature関数内のreconstruct_on_target_device、そしてtorch.UntypedStorage._new_shared_cudaの呼び出しに費やされていました。
問題は、トークナイザープロセスからスケジューラへのテンソル共有方式にありました。SGLangではCUDA IPCを用いてプロセス間でGPUメモリを共有しますが、従来の実装ではスケジューラがイテレーションごとに各テンソルに対して_new_shared_cudaを呼び出し、同じハンドルを何度も開き直していました。このホスト側の簿記処理が無駄なオーバーヘッドを生んでいたのです。
解決策は驚くほどシンプルで、Pythonの辞書を使ったプールハンドルキャッシュです。CUDAメモリプールはプロセス生存中に再割り当てされないため、キャッシュの無効化は不要です。書き込み時のみロックが必要で、読み取りはロックフリー。実装後、再度py-spyで確認すると、_new_shared_cudaのホットスポットは消失し、入力処理のサンプル数は半分以下になりました。
エンドツーエンドのベンチマーク結果は顕著でした。H100上でQwen2.5-VL-3Bを実行したところ、スループットは16.2%向上(22.2 req/s→25.7 req/s)、TTFT平均は13.2%低下、TPOT平均は17.2%低下。テールレイテンシも改善し、E2EレイテンシのP99は14.9%減少しました。デコードレイテンシも17%改善しましたが、これはスケジューラが単一スレッドであるため、入力処理時間の短縮がバッチ処理の迅速化につながったからです。
本最適化はSGLang v0.5.10にマージされており、CUDA IPC転送を使用するあらゆるマルチモーダルモデルで効果を発揮します。