Cursor Research、NVL72 向け MoE メガカーネル「Mixture-of-Kittens」公開
本文の状態
日本語全文を表示中
詳細モードで約39分の本文を読めます。
同じ出来事の情報源
この情報源を基点に整理
Cursor Research
Cursor Research は、NVL72 環境における MoE 層のボトルネック解消を目指し、通信と計算を融合させたオープンソースのトレーニング・メガカーネル「Mixture-of-Kittens」を発表した。
AI深層分析を開く2026年8月5日 00:21
AI深層分析
キーポイント
MoK の本質的な設計変更
Cursor Research は既存手法が計算部分のみを最適化していた点を踏まえ、通信と計算の両方を単一の完全な決定論的カーネルに融合させることでボトルネックを解消した。
NVL72 環境への最適化
GB300 NVL72 のアーキテクチャ特性(マルチノード・ラック内の高速なオーバーラップ、Grace CPU の相対的な低速さ)を考慮し、CPU-GPU 同期を最小化する設計を採用した。
実証された性能向上
複数の NVL72 ラックにわたる本番トレーニング環境での評価により、エンドツーエンドのトークン処理速度が 1.41 倍向上したことが確認されている。
オープンソース化と技術的基盤
MXFP8 や NVFP4 の独自カーネル開発などの先行研究を踏まえ、GitHub でコードが公開され、コミュニティからのフィードバックや貢献を呼びかけている。
MoKのアーキテクチャと対象モデル
MoKはDeepSeek-V3スタイルのMoE層を対象としており、GLMやQwenなどのオープンウェイトモデルに広く採用されている。この層は1つの共有エキスパートと多数のルーティング済みエキスパートを組み合わせて構成される。
重要な引用
MoK addresses that bottleneck by fusing all MoE communication and computation into a single, fully deterministic kernel.
In our production training stack across several NVL72 racks, MoK increased end-to-end tokens per second by 1.41x.
For each token entering the MoE layer, a router projection selects the top-k routed experts and assigns a router weight to each one.
But because the communication can take as long as the computation itself, running the two sequentially is inefficient.
編集コメントを表示
編集コメント
Cursor Research が NVL72 という最新ハードウェアの特性を深く理解し、MoE トレーニングの実践的なボトルネックを解消する手法を公開した点は注目すべき成果である。技術的な詳細が明記されているため、大規模モデルの学習基盤構築を検討しているエンジニアにとって有益な情報源となるだろう。
Source Article
元記事を日本語で読む
本文に関係しない購読案内、埋め込み通知、サイト内プロモーションは除いています。
本日、Cursor は NVL72 向けに開発した生産環境対応の MoE(Mixture of Experts)トレーニング用メガカーネル「Mixture-of-Kittens (MoK)」をオープンソース化しました。
エージェント型コーディングモデルである Composer のトレーニングと推論規模を拡大する過程で、MoE レイヤーが常に最大のボトルネックとなってきました。ワークロードやトレーニング設定にもよりますが、エンドツーエンドのトレーニング時間の半分超を MoE が占有することさえあります。
MoK はこのボトルネックを解消するため、MoE の通信と計算処理をすべて単一の完全な決定性カーネルに統合しました。現在、MoK は数万基の GPU を用いた Composer トレーニングを支えています。
GitHub で MoK を試し、コードを検索できます。皆様からのフィードバックやコントリビュートをお待ちしています。
MoK は、MoE レイヤーの高速化に向けたこれまでの試行錯誤の上に成り立っています。過去 1 年間、私たちは独自に MXFP8 や NVFP4 のトレーニングカーネルを開発し、MoE 推論のための「warp decode」アプローチを確立しました。
しかし、それらの技術は計算部分の最適化に留まり、GPU 間の通信は別途処理されることを前提としていました。実際の生産環境では、通信がボトルネックとなっていました。そこで私たちは、通信機能をカーネル内部に直接組み込む形で、MoE レイヤーをゼロから再設計しました。
さらに、GB300 NVL72 への移行により、解決すべき課題が 2 つの重要な点で変化しました。まず、NVL72 は単一の NVLink ドメイン内に収まるマルチノードラックであり、72 枚の GPU にわたって計算と通信を高速かつ微細に重ね合わせることを可能にします。
次に、統合された Grace CPU(GB300 の「G」)は、GPU に比べて相対的に低速です。その結果、GPU ストリームが CPU 側の処理に容易に追いつき、CPU が作業している間は GPU が完全にアイドル状態になることが判明しました。そのため、CPU での処理量と CPU-GPU 間の同期を徹底的に最小化する必要があります。
これらの課題に対する私たちの解決策が「Mixture-of-Kittens(MoK)」です。これは NVL72 向けに第一原理から構築された、極めて最適化された MoE 学習用メガカーネルです。MoK はすべての MoE 通信と計算を単一のカーネルに融合し、完全に決定論的でありながら、公開されている実装と比較して最良の性能を発揮します。
複数の NVL72 ラックで構成する本番環境のトレーニングスタックにおいて、MoK の導入によりエンドツーエンドのトークン処理速度が 1.41 倍向上しました。
この投稿の後半では、MoK の核となるアイデアについて解説します。具体的には、適切な通信方向の選定方法や、計算と通信の重ね合わせ構造、リングトークンバッファによる CPU-GPU 同期の排除などです。さらに、メガカーネルの設計思想、決定論性の確保、MXFP8 サポート、その他の実装詳細についても触れます。
MoE における計算と通信の重ね合わせ
MoK は、GLM、Qwen、Kimi(K2.7 まで)、および DeepSeek-V3 (DSV3) 自体など、オープンウェイトモデルの多くで広く採用されている DeepSeek-V3 (DSV3) スタイルの MoE レイヤーを対象としています。これらのレイヤーは、1 つの共有エクスパートと数百に及ぶルーティングされたエクスパートを組み合わせる構造を持っています。
MoE レイヤーに入力される各トークンに対して、ルーター投影がトップ k のルーティングエクスパートを選択し、それぞれにルーター重みを割り当てます。選択された各エクスパートは、アップ投影とゲート投影、SwiGLU 活性化関数、そしてダウン投影からなる標準的なフィードフォワードネットワーク計算を実行します。レイヤー全体では、ルーター重みを用いて共有エクスパートとルーティングエクスパートの出力を結合します。
ここでは以下の記号を使用します:
- d = モデル次元
- f = エクスパート中間次元
- S = ルーティングされたトップ k エクスペートの集合
- x = 入力トークン
- w_r = ルーター重み
- W_e, b_e = エクスパート重み
MoE レイヤーの計算式は以下の通りです:
y = w_s * f(x) + Σ_{i∈S} w_i * f_i(x)ここで、
- w_s は共有エクスパートの重み
- f は共有エクスパートの計算関数
- w_i と f_i はそれぞれ i 番目のルーティングエクスペートの重みと計算関数を表します。
エクスパート並列化(EP)では、ルーティングされたエクスパートを分割し、その重みを多数の GPU またはランクに分散します。すべてのエクスパート重みを集合的に保持するランクの総数を「EP degree」と呼びます。例えば、256 のルーティングエクスパートと EP degree が 64 の場合、各ランクは 4 つのルーティングエクスパートと 1 つの共有エクスパートを保持することになります。その結果、ルーター投影に基づき、トークンは MoE レイヤーの前と後に GPU をまたいで転送される必要があります。
分散型 MoE の最もシンプルな実装では、各トークンをその割り当てられた専門家が担当するランクへ送信(dispatch all-to-all)し、FFN を実行した後に結果を元のランクへ返還(combine all-to-all)、最後に専門家ごとの出力の加重和を取ります。しかし、通信時間が計算時間と同等に長くなる場合があり、これらを逐次実行するのは非効率的です。
標準的な解決策は、パイプライン処理を通じて dispatch/combine1 の通信を各専門家の FFN 計算と重ね合わせることです。具体的には、トークンの断片を転送しながらその断片に対して FFN を計算し、同時に次の断片の転送も並行して行うというサイクルを繰り返します。MoK はこのスキームの一つの変種であり、既存のベースラインよりも高速化を実現する、ターゲットに特化した革新的な技術群を採用しています。

適切な通信方向の選択
GPU 間でトークンを送信する際、トークン所有元の GPU が積極的に遠隔先の GPU にデータを格納するプッシュ型(push-based)と、必要なトークンを遠隔元の GPU から読み込むプル型(pull-based)のどちらかを選択できます。既存のアプローチでは、GPU 間でのトークンの散乱や集約にプッシュ型の通信を依存しているケースが少なくありません(例:DeepEP)。
一般的には、プッシュ方式の方がプロトコル通信が少なくて済み、GPU 間のリンクをより効率的に飽和させられるため、デフォルトの選択肢とされることが多い。しかし私たちの観察では、それぞれの仕組みには独自のトレードオフがあり、パフォーマンス最大化のためには各通信オペレーターに対して適切な方策を選ぶことが重要だ。その理由は主に三つある。
スケジューリング
トークンを可能な限り高速に分散・結合するためには、以下の条件が満たされる必要がある。
- ラック内の 72 台の GPU を相互接続するすべての NVLink レーンを常に飽和状態に保たなければならない。一部の (送信元→宛先) レーンのみを使ってトークンが移動しているような時間的空白は許されない。そのため、どの瞬間においても各送信元ランクからの送出が、すべての宛先ランクに対して均等に分散されるようにトークンを選定する必要がある。
- 各ランクに送られるトークンは、そのランク内のローカルエキスパートの順序で到着しなければならない。到着順がバラバラだと、テンソルコアによる行列乗算を開始する前に、グループ化された GEMM がフルサイズのトークンタイルを待つ時間が長くなってしまう。
- ローカルでのコピーはゼロに抑える必要がある。エキスパート用のトークンは連続したメモリ領域に直接着地し、ローカルで順序を入れ替えることなく、グループ化された GEMM を即座に開始できるようにする。
上記三つの条件を満たすためのオーバーヘッドを最小限に抑えなければならない。時間を多く割くべきは実際にトークンを送ることであり、スケジューリングや送信対象のトークンを探すことに費やす時間は極めて少なくすべきだ。
プッシュベースのディスパッチでは、{src_index, dst_rank, dst_index} の列を持つスケジューリングテーブルを作成する必要があります。ここで src_index はローカルの着信アクティベーションバッファ内のインデックスを指し、dst_index はトークンが到着する先ランのメモリ上の場所を示します。このテーブルの行インデックスは、NVLINK を介してトークンが送信される順序を決定します。
このテーブルの各行が dst_rank をラウンドロビン方式で巡回し、すべての接続されたレーンが常に稼働状態となるようにします。
特定の dst_rank を対象とする行では、dst_index の値はすべてのソース GPU にわたって均等に交互に配置されなければなりません。また、その宛先ランク上でも、ローカルエキスパートの順序に従って増加している必要があります。このテーブルを構築するには複数のソート処理が必要となり、各ランクのスケジューリングでは他のすべてのランクの状況も考慮する必要があります。なぜなら、2 つ以上のソースランクが同じ dst_index に書き込むことはできないからです。
| スケジュール ID | 送信元 ID | 宛先ランク | 宛先 ID |
|---|---|---|---|
| 0 | 17 | 0 | 0 |
| 1 | 0 | 1 | 0 |
| 2 | 29 | 2 | 0 |
| 3 | 3 | 3 | 0 |
| … | … | … | … |
プッシュベースのスケジューリングでは、ネットワーク全体を飽和させるために、連続するエントリ間で宛先ランクをインターリーブする必要があります。
| スケジュール ID | 送信元ランク | 送信元 ID |
|---|---|---|
| 0 | 0 | 0 |
| 1 | 1 | 5 |
| 2 | 2 | 13 |
| 3 | 3 | 7 |
| … | … | … |
プルベースのスケジューリングでは、ネットワーク全体を飽和させるために連続するエントリはソースランクを交互に配置する必要があります。
プルベースのディスパッチを採用すると、スケジュールテーブルは {src_rank, src_index} の 2 カラムに簡素化され、テーブルの行インデックスがローカル宛先バッファ内のトークンインデックスと直接対応します。
理論上、テーブルの行数と宛先バッファの行数は一致するはずです(これには大量のメモリ割り当てが必要になります。詳細は後述します)。ここではソート処理は不要です。ルーターの投影結果を順に走査し、現在のランクに配置すべきトークンが見つかったら、そのソースランクとインデックスをスケジュールに書き込みます。
アルゴリズムは以下の通りです:
入力: ルーティングテンソル R(R[i, j] はソースランク i のトークン j における経路 r に割り当てられた専門家のグローバルインデックス)、ローカルランク rank、ランクあたりの専門家数 E
出力: ローカル専門家ごとのトークン数 counts_local、ローカル専門家およびソースランクごとのトークン数 counts_global、領域オフセット offsets、スケジュールテーブル schedule
counts_local = zeros(num_local_experts)
counts_global = zeros(num_local_experts, num_ranks)
offsets = zeros(num_local_experts + 1)
schedule = zeros(total_tokens, 2)
for i from 0 to num_ranks - 1 do
for j from 0 to tokens_per_rank[i] - 1 do
for r from 0 to num_routes - 1 do
if R[i, j, r] < num_local_experts then
expert_id = R[i, j, r]
counts_global[expert_id, i] += 1
schedule[counts_global[expert_id, i], :] = [i, j]
end if
end for
end for
end for
for e from 0 to num_local_experts - 1 do
offsets[e + 1] = offsets[e] + counts_global[e, :].sum()
end for実際の運用では、このアルゴリズムを実装したスケジューリングカーネルは MoE の実行時間の 3% 未満しか占めず、CPU と GPU の通信を一切行わずにデバイス側だけで完結します。
プッシュベースの結合(combine)を選択し、{src_rank, src_index} を {dst_rank, dst_index} として読み取ることで、このスケジューリングをそのまま再利用することも可能です。実際には、フォワードとバックワードのすべての 4 つの通信操作に対して一度だけスケジュールを構築すればよく、以下の組み合わせを選べば十分です。
- プルベースのフォワードディスパッチ
- プッシュベースのフォワード結合
- プルベースのバックワード逆結合
- プッシュベースのバックワード逆ディスパッチ
最悪の場合でもこのスケジュールは数メガバイト程度なので、メモリ圧力をかけることなく再利用のために保持できます。さらに大きな利点は、後述する通り、GPU 間やマルチレーン間の信号伝送が完全に不要になる点です。
NVLink バンド幅の活用率
あらゆるネットワークシステムと同様に、NVLink を介して転送されるすべてのユーザデータ(ペイロード)には、ソースと宛先、確認応答など、使用するネットワークプロトコルに依存する追加のプロトコルメタデータが付加されて送信されます。NVLink 通信プロトコルの詳細は非公開ですが、リンク上で送られるデータを観察し、慎重に推論することは可能です。
その結果わかったのは、プッシュベースの NVLink 通信では転送される総バイト数(プロトコルメタデータとペイロードの合計)が少なく、かつほぼすべてのデータが一方向に流れるため、すべてのレーンがフル稼働している状態で高いバンド幅利用率を達成できるということです。
一方、プルベースの転送では総データ量は多くなりますが、プロトコルのメタデータはリンクの双方向に分散されます。プラー側がまず片方向へメタデータを送信し、その後、もう片方向から追加のメタデータとペイロードを受信します。
これを検証するには、シンプルなクロス GPU 転送カーネルを作成し、NCU でプロファイリングすればよいです。例えば、NVLINK を介して 256x256 の BF16 タイル(131,072 バイト)を 1 つ送信するマイクロベンチマークでは、以下の結果が得られました:
| 合計 | 合計 RX | 合計 TX | プロトコル RX | プロトコル TX | ペイロード RX | ペイロード TX | |
|---|---|---|---|---|---|---|---|
| プッシュ | 159.6 KB | 2.9 KB (1.84%) | 155.6 KB (99.16%) | 2.7 KB | 24.6 KB | 0 KB | 131.1 KB |
| プル | 172.0 KB | 147.5 KB (85.71%) | 24.6 KB (14.29%) | 16.4 KB | 24.6 KB | 131.1 KB | 0 KB |
上記の表において、RX は受信方向を、TX は送信方向を表します。プッシュ方式では総データ量が約 12.4 KB 少なくなるため、理論上は NVLink の飽和率全体が向上する可能性があります。しかし、NVLink は各方向に独立したレーンを持っています。GB300 上の第 5 世代 NVLink で仕様書に記載された帯域幅(1.8 TB/s)を達成するには、双方向の通信が完全に成立している必要があります。MoE のディスパッチやコンバインドのようなワークロードでは、転送されるデータは数キロバイト程度で不均衡になりがちです。その結果、リンク上で実行待ちの状態(バブル)が生じてしまいます。
実験結果によると、エキスパートの不均衡が発生する状態でトークンをディスパッチする際、プルベースの通信方式はプッシュベースに比べて NVLink の帯域利用率を最大 29% 向上させます。このため、プル方式の方がより優れた選択肢となります。
シグナリング
シグナリングは不可欠です。GPU はディスパッチやコンバインドの通信が完了したことを知らなければなりません。受信したトークンに対する処理を開始できるのは、完了信号を受信した後だけです。このシグナリングによるオーバーヘッドを最小限に抑えることが重要であり、適切な通信方向を選択することは大きな影響を持ちます。
プッシュベースのディスパッチまたはプルベースのコンバインドの場合、完了信号は GPU 間を行き来する必要があります。エキスパートグループ化された GEMM を開始する前に、あるランクは最大 71 のピアからの信号を待機し、メモリフェンスを発行してラック全体にわたってメモリをフラッシュしなければなりません。さらに、シグナリングが転送されている間にデータはすでに宛先に存在しています。
プルベースのディスパッチとプッシュベースのコンバインを採用することで、GPU 間のシグナリングは不要になります。各ランクがデータロードを発行し、到着を待ってから即座に使用を開始できるため、マルチノード同期も必要ありません。また、シグナリングを行うのは単一のエンティティのみであるため、専門家の並列度が高まってもオーバーヘッドが増大することはありません。
私たちはこのシグナリングのオーバーヘッドが非常に大きいことを発見しました。マルチノードマイクロベンチマークでは、プッシュベースのディスパッチによるシグナリングはプルベースのものよりも約 5.8 倍の遅延(103 µs 対 18 µs)を発生させ、メガカーネル内ではこのコストがすぐに蓄積します。
これらの結果に基づき、MoK ではプルベースのフォワードディスパッチ、プッシュベースのフォワードコンバイン、プルベースのバックワードリバースコンバイン、そしてプッシュベースのバックワードリバースディスパッチを採用しています。

計算と通信のオーバーラップを適切に構造化する
計算・通信の粒度
計算と通信の粒度とは、計算タスクと通信タスクが完了を互いにシグナリングする際の粒度のことです。ここには興味深いトレードオフが存在します。
通信の粒度を極端に細かくすると、テンスコアが行列乗算積算命令を実行するために必要なトークン数(Blackwell では 256 など)だけを転送し、転送と演算を連続的に重ね合わせることになります。このアプローチの好例として Comet が挙げられます。
一方、通信を極端に粗くすると、数千から数万のトークンを一度に転送し、バッチ全体が揃うまで待ってからテンスコア演算を開始します。DeepEP はこの手法の好例です。
私たちが観察したのは、どちらかの極端なアプローチが最適解ではないということです。最適な点は中間にあり、ワークロードによって異なります。
通信が細かすぎると、テンスコアは十分に飽和しません。Nvidia のテンスコアは高度にパイプライン化され、帯域幅を最適化したアクセラレータです。演算のたびに数回の MMA 命令ごとに待機状態になるのではなく、絶えずデータを送り続けることが重要です。
通信が粗すぎると、最初のトークン群が届くまで、あるいは最終的な出力を結合するまでテンスコアが長時間待たされることになります。

私たちが各ラウンドで送信するトークンの集合をミニバッチと呼びます。MoK では、このミニバッチサイズを調整可能なパラメータとして扱っており、ワークロードを実行する前にさまざまな構成を簡単に試すことができます。
最適なミニバッチサイズを選ぶための大まかなヒューリスティックは、各オペレーター(例えば、エキスパートグループ化された GEMM など)に必要となる「ウェーブ」の数を考慮することです。
ここでいうウェーブとは、GPU 上のすべての SM(ストリーミングマルチプロセッサ)で並行実行が行われる1ラウンドのことです。もし作業量が少なすぎると(例えば、エキスパートグループ化された GEMM に受け渡されるトークン数が少なすぎる場合)、一部の SM がアイドル状態になる「部分的なウェーブ」が発生します。あるいは逆に、「テール効果」と呼ばれる現象が起き、最後のウェーブで利用可能な SM の一部しか使われないこともあります。
私たちは、FFN(フィードフォワードネットワーク)内の各エキスパートグループ化 GEMM オペレーターに対して、少なくとも2つの完全なウェーブが生じるようなミニバッチサイズを選ぶのが有効だと考えています。このアプローチが機能する理由は主に2つあります。(1) 完全なウェーブを1回行うだけで、テンソルコアは十分に飽和状態になります。(2) 2つのウェーブを設定することで、2番目のウェーブの MMA(乗算加算演算)が、1番目のウェーブのエピローグや従属オペレーター(例えば SwiGLU アクティベーション関数や次のグループ化 GEMM など)と重なり合い、テール効果の影響を分散させることができます。
具体的には Blackwell GPU において、GEMM でテンソルコアを完全に活用する場合、減算次元を とすると、1-SM または 2-SM の MMA(乗算加算演算)のいずれの場合でも、各 SM は 出力タイルを担当することになります。
したがって、以下のパラメータが与えられたとします:
- :転送あたりのトークン数(つまりミニバッチサイズ)
- :隠れ次元
- :エキスパート中間次元
- :SM の数
各 GEMM(行列積演算)が少なくとも 2 つのウェーブを埋める十分なタスク数を生成し、かつ通信粒度は最大限のオーバーラップを実現するために可能な限り小さくなるようにする必要があります。up プロジェクションと gate プロジェクションは互いに依存関係がないため並列実行可能ですが、この場合の要件は以下の通りです。
一方、down プロジェクションは他の演算器と並列実行できないため、別の条件が適用されます。
これらを組み合わせると、求める要件は次のようになります。
例えば、Composer 2.5 のベースモデルである Kimi 2.5 を考えてみましょう。ここで N = 1024、K = 8192 とします。Blackwell GPU では T = 64 なので、計算結果は以下のようになります。
Kimi 2.5 の形状で MoK(Mixture-of-Kittens)を順方向実行したマイクロベンチマークでは、以下のような結果が得られ、これは概ねヒューリスティックと一致しています。
| ms | |
|---|---|
| 512 | 5.981 |
| 1024 | 4.669 |
| 1536 | 3.981 |
| 2048 | 3.666 |
| 2560 | 3.425 |
| 3072 | 3.447 |
| 3584 | 3.524 |
| 4096 | 3.473 |
重なり部分のスケジューリング
通信粒度が決まったら、次に重要なのは、GPU 上でディスパッチ(分散)、コンバイン(集約)、FFN(フィードフォワードネットワーク)といった異なるタスクをどのようにスケジュールして効率的に並行処理を実現するかです。これには「SM 間オーバーラップ」手法を採用しています。具体的には、一部の SM を専門家の FFN 計算用(計算用 SM)に割り当て、残りの SM をディスパッチやコンバインの通信処理用(通信用 SM)に割り当てます。両グループはローカルカウンターを介してシグナルを送り合い、タイミングを調整します。
この手法が可能なのは、Tensor Memory Accelerator (TMA) の読み書き機能を活用することで、NVLINK バンド幅をほぼ最大限に活用しつつ、必要な SM 数の 3 分の 1 未満で済むからです。
ベース戦略として「SM 間オーバーラップ」を採用しています。MoE(Mixture of Experts)の順伝播フェーズでは、通信用 SM がプル型のディスパッチ全対全処理を開始し、トークンのミニバッチがすべて到着して計算準備が整うたびに、計算用 SM にシグナルを送ります。これを受け取った計算用 SM は、そのトークンに対して MLP-SwiGLU を原子演算で実行します。下方向投影までの処理が完了すると、計算用 SM は通信用 SM へ「トークンをコンバインの準備ができている」と通知します。
通信用 SM は、すべてのディスパッチタスクを完了するまで、いかなるコンバイン全対全タスクも実行しません。そのため、通信用 SM がディスパッチを終える頃には、計算用 SM からの完了シグナルが多数届いています。その後、通信用 SM はプッシュ型のコンバイン処理に移行し、その間、計算用 SM は最後に到着したトークンの FFN 処理を完了させます。
さらに、計算用 SM が最初のディスパッチ完了を待っている間に、共有専門家の FFN 処理も組み込むことが可能です。

逆伝播も同様ですが、フォワードリプレイの影響でやや複雑になります(詳細は次節で解説)。通信用SM(Streaming Multiprocessors)が逆結合処理を実行し、計算用SMに対してFFNの逆伝播を開始するよう信号を送ります。ただし、重み勾配(wgrads)の計算は除外されます。具体的には、3つの専門家グループ化されたGEMM演算と、それに対応する3つの活性化関数勾配(dgrads)、そしてSwiGLU活性化関数の逆伝播が行われます。FFNの処理が完了し、トークンが逆分散(reverse-dispatch)の準備ができたら、計算用SMは通信用SMに完了を通知します。
すべてのミニバッチにおける活性化勾配(dgrads)の計算が完了した後、残りの3つの重み勾配(wgrads)を実行します。wgrads の実行を遅らせるのには2 つの理由があります。(1) 逆分散はこれらに依存しないため、最後の逆分散処理と wgrads を並列実行できること。(2) トークン軸が wgrads の縮小次元であるため、トークン軸全体を一括して集約することで数値的不安定性を最小限に抑えられるからです。フォワードパスと同様に、共有専門家の全体的な逆伝播を最初のラウンドの逆結合処理と重ねて実行します。

リングトークンバッファによるCPUとGPUの同期を完全排除
最後に残る課題は、MoE(Mixture-of-Experts)の動的な性質への対応です。どのラベルにどれだけのトークンが到達するかを事前に知ることはできません。
これに対処する既存の方法には主に 2 つあります。1 つ目はトークンドロップで、固定されたバッファサイズを超えたトークンは単に無視され、エキスパート FFN(Feed-Forward Network)に入力されることはありません。2 つ目は CPU と GPU の同期です。ルーターの結果から各ランクごとのトークン数を計算し、それを CPU に送信して CPU が正確なサイズのバッファを割り当てます。
両者には明らかな欠点があります。トレーニングの品質のために意図的にトークンを捨てることは避けたいですし、CPU-GPU の同期は GPU ストリームが CPU スレッドよりも先に進めなくなる原因となります。
特に GB300 NVL72 では、統合された Grace CPU が非常に遅いため、この同期のコストは甚大です。実際のトレースでは、Intel CPU を搭載した DGX マシンでは問題にならなかった同じトレーニングスタックでも、GPU カーネルがログ出力やリモートサーバーへの学習メトリクス転送といった CPU 作業によってボトルネックに陥っている様子が頻繁に確認されています。こうした状況から、CPU と GPU の同期を可能な限り最小限に抑える必要があります。
MoK ではこれを「マクロバッチ」と呼ぶリングトークンバッファで解決します。通信用 SM(Streaming Multiprocessor)がトークンを転送先へ書き込むために、大きくてほとんど使われないバッファを割り当てるのではなく、数百メガバイトの固定サイズを持つリングバッファを作成し、ミニバッチ単位でこれを循環使用します。
マクロバッチ処理を効率的に実装するには、計算と通信の適切な重なり合わせが不可欠です。バッファの空きスロット待ちやデータの到着遅れによって、いずれかが停止してはいけません。理想的な状態は、リングバッファの境界をまたいで重なりを持たせることです。具体的には、バッファの末尾部分で計算を行いながら、その始点部へのデータ転送(ディスパッチ)を並行して実行します。
肝心なのは、パフォーマンスが許す限り各スロットを早期に解放し、できるだけ早く再利用できるようにすることです。順伝播(フォワードパス)では、ディスパッチでスロットを埋め、コンバインでそれらを空にして、次のディスパッチのために確保します。
しかし、すべてのディスパッチを実行した後にすべてのコンバインを実行するスケジュール(前節の手法)を採用すると、次のマクロバッチは最後のコンバインが完了するまで開始できず、計算と通信の重なり合わせも最初のディスパッチが完了するまで再開されません。
これを回避するため、フォワードパスではディスパッチとコンバインを交互に実行します。前回のマクロバッチのミニバッチに対するコンバイン処理を、同じリングバッファ領域を使用する次のマクロバッチの対応するミニバッチに対するディスパッチ処理と組み合わせて実行します。これにより、バッファは空になった瞬間にすぐに再充填されます。なお、最初のマクロバッチのディスパッチと最後のマクロバッチのコンバインには互いに対応する処理が存在しないため、これらは交互実行されません。

後方伝播時の前方再計算を最小化するための逆方向リング構造
後方伝播(バックワードパス)は、やや複雑になります。なぜなら、この際のメガカーネルは前方活性化の再計算(リプレイ)に対応する必要があるからです。
マクロバッチバッファはリング構造を採用しています。そのため、複数のマクロバッチが存在する場合、前方伝播中に一部の保存された活性化値が上書きされ、後方伝播時に再計算が必要になります。ただし、再計算が必要な範囲は SwiGLU 活性化までで十分です。後方伝播では、下層投影(down projection)の出力勾配と入力活性化のみが必要であり、その前方伝播での出力自体は不要だからです。
ここで重要な最適化が「逆方向リング」の実装です。マクロバッチを昇順に処理すると、最後のマクロバッチでリングバッファが部分的な状態になり、後方伝播時に再計算すべき活性化値が増加してしまいます。そこで MoK では、前方伝播の段階でマクロバッチを降順(逆方向)に処理します。これにより、保存されたリングバッファは常に完全に満たされているか、あるいは必要なすべてのトークンを含む状態が維持され、後方伝播時の前方再計算量を最小限に抑えることができます。
その他の機能と実装の詳細
メガカーネル
MoK は、megakernel 技術を用いて構築しました。この手法では、カーネル起動の境界で命令を分断するのではなく、SM(ストリーミングマルチプロセッサ)レベルで命令が重なるように設計されています。
通常、megakernel は前方計算または後方計算のステップ全体を融合させるのに適していますが、MoK においても以下の 2 つの理由からこの手法が有効であると判明しました。1 つ目は、megakernel の融合なしにミニバッチ処理やマクロバッチ処理を実装すると複数のカーネル起動が必要となり、起動オーバーヘッドが増大することです。2 つ目は、SM 間の重なり処理において、グリーンコンテキストを持つ複数のストリームでは意図した通りに SM を正確に分割できないことが多く、ソフトウェアによるパーティショニングであれば割り当ての保証を厳密に行えるからです。
Determinism(決定性)
内部でのアブレーション実験やオンポリシー RL のポストトレーニングにおいて、MoK は完全に決定性を持つように設計しました。浮動小数点演算の順序が固定されているため、ハードウェアのスケジューリングや命令発行順に関わらず、同じ入力に対してはビット単位で同一の結果が出力されます。
Cluster Launch Control (CLC) for RDMA overlap
MoK メガカーネルは、RDMA のオーバーラップを可能にするため、CLC(Cluster Launch Controller)を通じてタスクスケジューリングを行います。CLC は Blackwell アーキテクチャで導入されたハードウェアネイティブのワーク・スティーリング機能であり、永続的なグリッドカーネルを実装する新たな手法です。
CLC ベースのカーネルは、現在のカーネルが完全に完了するのを待たずに、優先度の高いストリーム上の他のカーネルに対して自然に譲渡(yield)できます。これは非常に重要です。なぜなら、トレーニング中、私たちはしばしばラック内の通信と計算を、独自の SM(Streaming Multiprocessor)を必要とする FSDP all-gather などのラック間 InfiniBand/RoCE 通信とオーバーラップさせる必要があるからです。
もし CLC がなければ、ラック間の通信はメガカーネルの後に直列化されてしまい、著しいパフォーマンス低下を招きます。
MXFP8 サポート
MoK は BF16 と MXFP8 の両方の精度モードをサポートしています。私たちは数値的な問題を引き起こさず、かつ高速なため、MXFP8 モードでトレーニングを行います。ただし、MXFP8 モードでは、トレーニングの安定性を保つために共有エクスパートは BF16 で保持されます。
MXFP8 の追加コストとして、テンソルをテンサーコアに投入する前に量子化(quantization)を行う必要があります。このオーバーヘッドを最小限に抑えるため、私たちは以下の 2 つのアプローチを採用しました。
(1) 重みの事前量子化用の最適化された MXFP8 量子化カーネルを提供します。
(2) アクティベーションの量子化を、dispatch all-to-all、エクスパートグループ化された GEMM(General Matrix Multiply)、および SwiGLU に融合させます。
Router weight gradient computation
MoK の逆伝播では、SonicMoE 方式の計算を用いてルーター重みの勾配も算出します。下向き投影(down-projection)の出力全体を保存するのではなく、SwiGLU の活性化値と下向き投影の逆伝播勾配との内積からこれを計算しています。この処理は SwiGLU の逆伝播に統合されており、追加的なメモリアクセスを防いでいます。
計算/通信 SM のチューニング
計算用 SM と通信用 SM の最適な比率はワークロードによって異なります。ローカルのトークン数やモデルの形状、ハードウェアの演算能力とネットワーク帯域幅が、ディスパッチやコンバインタスクに要する時間をエキスパート FFN タスクと比較してどう変化させるかを決めます。同じワークロード内でも、順伝播と逆伝播では最適な比率が異なります。MoK ではこれに対応するため、順伝播用と逆伝播用の通信 SM 数をそれぞれ設定可能なパラメータを公開しています。
速度向上
MoK の評価には、2 つ種類のベンチマークを用いました。1 つ目は MoE レイヤー単体のベンチマークで、関連するすべてのコードを公開しています。2 つ目は、複数の NVL72 ラックにわたる社内生産用トレーニングスタックでのエンドツーエンドベンチマークです。
MoE レイヤー ベンチマーク
MoK では、グローバルトークンスケジューリング、トークンのディスパッチ(all-to-all)、エキスパート FFN、トークンのコンバイン(all-to-all)、そして最終的な加重和という各処理を個別にベンチマークしました。順伝播と逆伝播は別々に評価し、BF16 モードと MXFP8 モードの両方でテストを行いました。すべての試験は 1 つの NVL72 ラック内で行い、ルーティング前に EP degree を 64、GPU あたり 2,048 トークンとして設定しました。
比較対象として選定したベースラインは、(1) MoE の順伝播と逆伝播の両方をサポートし、(2) NVL72 上で動作するものに限りました。
- NCCL + PyTorch
- DeepEP + PyTorch
- DeepEP + TransformerEngine
- HybridEP + Megatron(Nvidia が NVL72 で推奨するオプションで、DeepEP + Megatron よりも優れています)
広く使われているオープンウェイトモデルの形状についてテストを行いました。
- Kimi K2.7 Code 形状 (: 384, : 7168, : 2048, top-k: 8)
- GLM-5.2 形状 (: 256, : 6144, : 2048, top-k: 8)
- Qwen3.5-397B-A17B 形状 (: 512, : 4096, : 1024, top-k: 10)
- DeepSeek-V4-Pro 形状 (: 384, : 7168, : 3072, top-k: 6)
以下のグラフは、すべてのベースラインにおける 4 つの形状の結果を示しています。
全体として、最速のベースラインと比較すると、MoK は MXFP8 の順伝播で最大 2.37 倍、MXFP8 の逆伝播で 1.78 倍、BF16 の順伝播で 1.92 倍、BF16 の逆伝播で 1.58 倍高速であることが確認できました。
エンドツーエンドベンチマーク
公開されている実装との比較に加え、社内生産環境のトレーニングスタックにおける速度向上も報告します。従来、当社のトレーニングスタックは、DeepEP ベースの実装にカスタム MXFP8 MoE 計算カーネルを組み合わせてエキスパート並列化を実現していました。ここでは、MoE レイヤーの実装選択(DeepEP と MoK)を変えてエンドツーエンドのトークン/秒を比較しました。ベンチマークは、GB300 NVL72 ラックにまたがる 512 GPU で実施されました。
| DeepEP ベースの | MoK | |
|---|---|---|
| GPU 当たり 1 秒あたりのトークン数 | 760.9 | 1,070.2 (1.41x) |
全体として、MoK は以前の DeepEP ベースの運用環境と比較してトークンあたりの処理速度を約 41%向上させました。これにより、GB300 NVL72 インフラストラクチャ上でモデルのトレーニングをより効率的に行えるようになりました。
エージェント時代のメガカーネル
Mixture-of-Kittens(MoK)は本日、完全にオープンソース化されました。今後も継続的なメンテナンスを行い、コミュニティからのフィードバックや貢献を歓迎します。この取り組みを通じて AI 研究への参入障壁を下げ、より多くの研究者やラボが効率的にモデルをトレーニングできる環境を整えることを目指しています。また、MoK は高い柔軟性も重視しています。エージェントの支援を受けながら、既存のプラットフォーム以外でも素早く適応できるよう、修正しやすい設計に注力しました。
参考までに、高性能なカーネルを生成可能な AI モデルが登場したことで、カーネル最適化の領域はさらに興味深いものとなっています。従来は人手で記述されていた単一演算子のカーネルも、現在はほぼすべて AI が担当するようになりました。適切な設計指針(例えば、ワープの専門化方法や使用する PTX 命令など)さえあれば、エージェントはワンショットで最先端のカーネルを生成できるようになっています。
しかし、さらに興味深いのは、これによって得られる新たな能力です。昨年はメガカーネルを書くために、このような簡略化された抽象化レイヤーを作成する必要がありました。今年私たちはフレームワークを必要としませんでした。代わりに、追加の抽象化レイヤーを取り除き、エージェントの支援を受けながら、複雑さを自ら解決してゼロから取り組んだのです。
エージェントは単純なタスク(例えば単一演算子カーネルなど)を自動化し、より困難なタスク(例えば分散 MoE メガカーネルの作成など)も、非常に少人数のチームで、以前よりもはるかに迅速に完了させることができました。
とはいえ、数十万もの GPU にわたって実行される高リスクの ML ワークロードの最適化には、まだ多くの課題が残っています。もしこの記事や同様の取り組みに興味を持っていただけた場合は、ぜひご連絡ください。hiring@cursor.com までお問い合わせください。
引用
本成果を利用する際は、以下のように引用してください:
Stuart H. Sul, Nash Brown, Henry Wildermuth, William Lin, and Federico Cassano. "Mixture-of-Kittens: MoE Megakernel for NVL72s." Cursor Research, Aug 2026. https://github.com/cursor/mixture-of-kittens
または BibTeX 形式:
@misc{sul2026mok,
title={Mixture-of-Kittens: {MoE} Megakernel for {NVL72s}},
author={Stuart H. Sul and Nash Brown and Henry Wildermuth and William Lin and Federico Cassano},
organization={Cursor Research},
year={2026},
publisher = {GitHub},
howpublished = {\url{https://github.com/cursor/mixture-of-kittens}},
}*本稿の読了と有益なフィードバックを提供してくれた Chris Ré、Sasha Rush、Less Wright、Chen Lu、Nathan Wang に心より感謝いたします。*
- この記事では、dispatch は「すべてのノード間通信(all-to-all communication)」を指し、combine も同様に「すべてのノード間通信」を指します。なお、「combine」に含まれることが一般的な加重集約は、ここでは「加重和(weighted sum)」として別途言及されます。↩
原文を表示
Today, we're open-sourcing Mixture-of-Kittens (MoK), our production MoE training megakernel for NVL72s.
As we have scaled the training and inference of Composer, our agentic coding model, the mixture-of-experts layer has consistently remained the major bottleneck. Depending on the workload and training configuration, it can consume more than half of end-to-end training time.
MoK addresses that bottleneck by fusing all MoE communication and computation into a single, fully deterministic kernel. It now powers Composer training across tens of thousands of GPUs.
You can try MoK and explore the code on GitHub. We look forward to your feedback and contributions.
MoK grew out of several earlier attempts to speed up the MoE layer. Over the past year, we wrote our own MXFP8 and NVFP4 training kernels and developed the "warp decode" approach for MoE inference.
But those techniques optimized only the compute portion of the layer and assumed inter-GPU communication would be handled separately. In our production workloads, communication had become the limiting factor. That led us to redesign the full MoE layer from first principles, with communication built directly into the kernel.
In addition, our move to GB300 NVL72s changed the problem in two important ways. First, an NVL72 is a multi-node rack within a single NVLink domain, enabling fast, fine-grained overlap of computation and communication across all 72 GPUs.
Second, the integrated Grace CPUs (the "G" in GB300) tend to be slow relative to the GPUs. We found that GPU streams easily caught up to CPU-side work, causing the GPU to be completely idle during that time. So we have to aggressively minimize CPU work and CPU-GPU synchronization.
Our solution to this set of challenges is Mixture-of-Kittens (MoK), a highly optimized MoE training megakernel built from first principles for NVL72s. MoK fuses all MoE communication and computation into a single kernel, is fully deterministic, and achieves state-of-the-art performance against publicly available implementations.
In our production training stack across several NVL72 racks, MoK increased end-to-end tokens per second by 1.41x.
The rest of this post explains the key ideas behind MoK, including how we chose the right communication direction, structured the overlap between computation and communication, and eliminated CPU-GPU synchronization with ring token buffers. We also cover the megakernel design, determinism, MXFP8 support, and several other implementation details.
Overlapping computation and communication in MoE
MoK targets DeepSeek-V3 (DSV3)-style MoE layers, which are widely used across open-weight models including GLM, Qwen, Kimi (up to K2.7), and DSV itself. These layers combine one shared expert with many routed experts, often hundreds.
For each token entering the MoE layer, a router projection selects the top-k routed experts and assigns a router weight to each one. Each selected expert then runs the standard feed-forward network computation, consisting of up and gate projections, a SwiGLU activation, and a down projection. The layer combines the outputs of the shared and routed experts using the router weights.
We use the following notation:
- = model dimension
- = expert intermediate dimension
- = set of routed top-k experts
- Input token
- Router weights
- Expert weights , ,
And the MoE layer computes:
where
With expert parallelism (EP), we shard the routed experts and spread their weights across many GPUs, or ranks, and we call the number of ranks that collectively hold all expert weights the EP degree. For example, with 256 routed experts and an EP degree of 64, each rank holds 4 routed experts, plus the shared expert. As a result, tokens must be transferred across GPUs before and after the MoE layer, according to the router projection.
The most straightforward implementation of distributed MoE sends each token to the ranks holding its assigned experts (dispatch all-to-all), runs the FFN, returns the results to each token's original rank (combine all-to-all), and takes a weighted sum of the expert outputs. But because the communication can take as long as the computation itself, running the two sequentially is inefficient.
The standard remedy is to overlap dispatch/combine1 communication with per-expert FFN through pipelining: transfer one chunk of tokens, compute FFN on it while overlapping transfer of the next chunk, and repeat. MoK is one variant of this scheme, with a set of novel, target-specific techniques that make it faster than existing baselines.

Choosing the right communication direction
When sending tokens across GPUs, one can choose a push-based mechanism, where the GPU that owns the tokens actively stores them into the remote destination GPUs, or a pull-based mechanism, where the GPU that needs the tokens loads them from the remote source GPUs. Existing approaches often rely on push-based communication for scattering and gathering tokens across GPUs (e.g., DeepEP).
The common notion is that pushing saturates inter-GPU links better, since it involves less protocol communication, and thus it becomes the default choice. Our observation, however, is that each mechanism has its own tradeoffs, and choosing the right one for each communication operator matters for maximizing performance, for the following three reasons.
Scheduling
To dispatch and combine tokens as fast as possible, the following conditions must hold:
- All NVLink lanes interconnecting the 72 GPUs in the rack must stay saturated. We cannot afford stretches of time where tokens travel over only a subset of (source → destination) lanes, so tokens must be selected such that each source rank's sends are spread evenly across all destination ranks at any given moment.
- Tokens sent to a rank should arrive ordered by that rank's local experts. If arrivals are unordered, the expert-grouped GEMMs wait longer for a full tile of tokens before the tensor core matrix multiplications can begin.
- There should be zero local copies. Tokens for an expert should land directly in contiguous memory, so the grouped GEMMs can start without reordering anything locally.
- The overhead of satisfying the above three conditions must stay minimal. We want to spend most of the time actually sending tokens, and very little time scheduling or searching for tokens to send.
With push-based dispatch, we need to produce a schedule table with columns {src_index, dst_rank, dst_index}, where src_index is the index into the local incoming activation buffer and dst_index is the location in the destination rank's memory where the token must land. The row index of this table will decide the order in which tokens are sent over NVLink. We want the rows of this table to cycle through dst_rank round-robin, so that every connected lane stays busy.
Among the rows targeting a given dst_rank, the dst_index values must be interleaved evenly across all source GPUs, and they must also follow increasing local expert order on that destination rank. Building this table involves multiple sorts, and each rank's schedule must account for every other rank's, since no two source ranks can write to the same dst_index.
| Schedule Idx | Src Idx | Dst Rank | Dst Idx |
|---|---|---|---|
| 0 | 17 | 0 | 0 |
| 1 | 0 | 1 | 0 |
| 2 | 29 | 2 | 0 |
| 3 | 3 | 3 | 0 |
| … | … | … | … |
Push-based schedule: consecutive entries must interleave destination rank for full network saturation.
| Schedule Idx | Src Rank | Src Idx |
|---|---|---|
| 0 | 0 | 0 |
| 1 | 1 | 5 |
| 2 | 2 | 13 |
| 3 | 3 | 7 |
| … | … | … |
Pull-based schedule: consecutive entries must interleave source rank for full network saturation.
With pull-based dispatch, the schedule table simplifies to two columns, {src_rank, src_index}, and the row index of the table directly corresponds to the token index in the local destination buffer.
In theory, the number of rows in the table and in the destination buffer would match (which would require large memory allocation; more on this in a later section). No sorting is needed here. We walk over the router projection results, and whenever we find a token that should land on the current rank, we write its source rank and index into our schedule. The algorithm looks as follows:
Inputs: routing tensor , where is the global index of the expert assigned to the -th route of token on source rank ; local rank ; experts per rank
Outputs: token counts per local expert , token counts per local expert and source rank , region offsets , schedule table
,
for to , to , to do
if then
;
end if
end for
for to do
end for
for to , to , to do
if then
;
end if
end for
In practice, our schedule kernel implementing this algorithm takes less than 3% of the total MoE runtime, and runs fully on the device-side without any CPU-GPU communication.
We can also reuse this schedule as-is for combine by choosing push-based combine, simply reading {src_rank, src_index} as {dst_rank, dst_index}. In fact, we can build the schedule once and reuse it for all four communication operations across forward and backward, by choosing:
- Pull-based forward dispatch
- Push-based forward combine
- Pull-based backward reverse-combine
- Push-based backward reverse-dispatch
The schedule is only a few megabytes in the worst case, so we can keep it around for reuse without any memory pressure. An additional benefit is that this completely eliminates inter-GPU, multi-lane signaling, as explained later below.
NVLink bandwidth utilization
As with any networking system, all user data (payload) being transferred over NVLink is sent with additional protocol metadata containing information about the source and destination, acknowledgements, etc., that depends on the networking protocol. While the details of the NVLink communication protocol are undisclosed, we can observe the data being sent on the link and reason about it carefully.
What we find is that push-based NVLink communication moves fewer total bytes (i.e., protocol metadata plus payload) and sends almost everything in one direction, so it achieves higher bandwidth utilization when all lanes are fully busy.
On the other hand, pull-based transfers move more bytes in total, but the protocol metadata is more split between both directions of the link. The puller first sends metadata one way, then receives more metadata plus the payload the other way.
We can verify this by writing a simple cross-GPU transfer kernel, and profiling it with NCU. For instance, in our microbenchmark sending one 256x256 BF16 tile (131,072B) over NVLink, we observe the following:
| Total | Total RX | Total TX | Protocol RX | Protocol TX | Payload RX | Payload TX | |
|---|---|---|---|---|---|---|---|
| Push | 159.6 KB | 2.9 KB (1.84%) | 155.6 KB (99.16%) | 2.7 KB | 24.6 KB | 0 KB | 131.1 KB |
| Pull | 172.0 KB | 147.5 KB (85.71%) | 24.6 KB (14.29%) | 16.4 KB | 24.6 KB | 131.1 KB | 0 KB |
In the above table, RX refers to the receiving direction, while TX refers to the sending direction. We can see that push involves roughly 12.4 KB less bytes in total, ideally leading to better NVLink saturation overall. However, NVLink has separate lanes for each direction. To reach the bandwidth advertised in the NVLink spec (1.8 TB/s for fifth-generation NVLink on GB300), traffic must fully flow both ways. And, for a workload like MoE dispatch/combine, each transfer tends to be only a few kilobytes and imbalanced, leaving execution bubbles on the link.
Empirically, pull-based communication delivers up to 29% higher NVLink bandwidth utilization than push-based communication when dispatching tokens under expert imbalance, making it the better choice.
Signalling
Signalling is necessary because the GPUs must know when dispatch/combine communication has completed. The GPUs can only begin operating on the received tokens after they receive a completion signal. It is important to minimize this signalling overhead, and choosing the right communication direction has a meaningful impact.
With push-based dispatch or pull-based combine, completion signals must cross between GPUs. Before an expert-grouped GEMM can begin, a rank must wait for signals from as many as 71 peers and flush memory across the rack by issuing a memory fence. In addition, the data is already sitting at the destination during the signal's transit time.
With pull-based dispatch and push-based combine, cross-GPU signalling disappears. Each rank issues a load, waits for the data to arrive, and can begin using it immediately. No multi-node synchronization is required. Also, only a single entity performs signalling, so the overhead does not grow with the degree of expert parallelism.
We found this signalling overhead to be quite large. In our multi-node microbenchmarks, push-based dispatch signalling incurs roughly 5.8x higher latency than pull-based dispatch signalling, at 103 µs versus 18 µs, and the cost accumulates quickly within a megakernel.
Based on these results, MoK uses pull-based forward dispatch, push-based forward combine, pull-based backward reverse-combine, and push-based backward reverse-dispatch.

Properly structuring the computation-communication overlap
Computation-communication granularity
Computation-communication granularity is the granularity at which computation and communication tasks signal each other of completion. It comes with an interesting trade-off.
At one extreme, communication can be very fine-grained. We send only enough tokens for the tensor cores to launch a full matrix-multiply-accumulate instruction, 256 on Blackwell, for instance, and continuously overlap each transfer with the matrix multiplications. Comet is a good example of this approach.
At the other extreme, communication can be coarse-grained. We send thousands or tens of thousands of tokens at once and wait for the full batch to arrive before beginning the tensor core operations. DeepEP is a good example here.
Our observation is that neither extreme is the right choice. The optimal point sits somewhere in the middle and depends on the workload.
If the communication is too fine-grained, the tensor cores never fully saturate. Nvidia tensor cores are heavily pipelined, bandwidth-optimized accelerators, and we want to keep feeding them rather than hitting a barrier wait every few MMA instructions.
If the communication is too coarse-grained, the tensor cores wait too long for the first round of tokens to arrive and for the final round of outputs to be combined.

We call the set of tokens we send each round a minibatch. MoK makes the minibatch size a tunable parameter so that it's easy to sweep possible configurations before running a workload.
A rough heuristic for choosing the optimal minibatch size is to consider how many waves each operator (e.g., expert-grouped GEMM) requires.
A wave is one round of concurrent execution across all SMs on the GPU. If a work is too small (e.g., an expert-grouped GEMM receives too few tokens), we get a partial wave, in which some SMs sit idle. Alternatively, we may see a tail effect, where the final wave occupies only a fraction of the SMs.
We find it useful to choose a minibatch size that gives each expert grouped-GEMM operator in the FFN at least two full waves. This works for two reasons: (1) a single full wave is enough to fully saturate the tensor cores; and (2) with two waves, the second wave's MMAs overlap with the first wave's epilogue and dependent operators (e.g., the SwiGLU activation or the next grouped GEMM), amortizing the tail effect.
Specifically, on Blackwell GPUs, fully utilizing the tensor cores for an GEMM, where is the reduction dimension, means each SM works on a output tile, regardless of 1-SM or 2-SM MMA.
So given:
- : number of tokens per transfer (i.e., the minibatch size)
- : hidden dimension
- : expert intermediate dimension
- : number of SMs
We want each GEMM to produce enough tasks to fill at least two waves, while keeping the communication granularity as small as possible for maximum overlap. For the up and gate projections, which run simultaneously since neither depends on the other, this means:
For the down projection, which cannot run in parallel with other operators:
Combining the two, the requirement we are looking for is:
For example, take Kimi 2.5, the base model for Composer 2.5, where and . On Blackwell GPUs, , so we get:
On our microbenchmark running MoK forward for Kimi 2.5 shapes, we observe the following, roughly matching the heuristics:
| ms | |
|---|---|
| 512 | 5.981 |
| 1024 | 4.669 |
| 1536 | 3.981 |
| 2048 | 3.666 |
| 2560 | 3.425 |
| 3072 | 3.447 |
| 3584 | 3.524 |
| 4096 | 3.473 |
Scheduling the overlaps
Once the communication granularity is decided, the next question is how to schedule the different tasks (dispatch, combine, FFN) on GPUs so that the overlap happens efficiently. To do this, we employ the inter-SM overlapping technique, in which we assign some SMs to the expert FFNs (comp SMs) and some to dispatch/combine (comms SMs), and have the two groups signal each other through a local counter. This is possible because with Tensor Memory Accelerator (TMA) loads and stores, we can fully saturate NVLink bandwidth with less than a third of the SMs.
We use inter-SM overlapping as our base strategy. In the MoE forward pass, the comms SMs begin the pull-based dispatch all-to-all and signal the comp SMs each time a full minibatch of tokens has arrived and is ready for computation. The comp SMs then run MLP-SwiGLU atomically on those tokens, and once everything through the down projection is complete, they signal the comms SMs that the tokens are ready for combine.
Comms SMs go through all of dispatch tasks before doing any combine all-to-all tasks, so many completion signals arrive from the comp SMs by the time comms SMs are done with dispatch. Comms SMs will then move on to the push-based combine while the comp SMs finish the FFNs for the last-arriving tokens. Additionally, we can fit in shared expert FFN while the comp SMs wait for the first dispatch to complete.

The backward pass is similar, though it gets a bit more complex with forward replay (more on this in the next section). The comms SMs perform the reverse-combine and signal the comp SMs to run the FFN backward, excluding the wgrads (i.e., 3 expert-grouped GEMMs for 3 dgrads and the SwiGLU activation backward), and the comp SMs signal the comms SMs once the FFNs are complete and the tokens are ready for the reverse-dispatch.
We perform the three remaining wgrads after the dgrads for all minibatches are complete. We delay the wgrads for two reasons: (1) reverse-dispatch does not depend on them, so wgrads can overlap with the last reverse-dispatches; and (2) since the token axis is the reduction dimension for wgrads, accumulating over the full token axis at once minimizes numerical instability. As in the forward pass, we overlap the full shared expert backward with the first round of reverse-combine.

Fully eliminating CPU-GPU synchronization with ring token buffers
The last missing piece is handling MoE dynamism; we do not know in advance how many tokens will arrive at a destination rank.
There are two existing ways to handle this. The first is token dropping, where any tokens beyond a fixed buffer size are simply ignored and never enter the expert FFNs. The second is CPU-GPU synchronization, where the per-rank token counts computed from the router results are sent to the CPU, and the CPU uses them to allocate exact-sized buffers.
Both have obvious downsides. We do not want to drop tokens for the sake of training quality, and CPU-GPU synchronization prevents the GPU stream from running ahead of the CPU thread.
CPU-GPU synchronization is especially costly on GB300 NVL72s because the integrated Grace CPUs are very slow. Our traces often show GPU kernels bottlenecked by CPU work such as logging or pushing training metrics to a remote server, even though the same training stack caused no such problems on DGX machines with Intel CPUs. Given this, we want to minimize CPU-GPU synchronization as much as possible.
In MoK, we resolve this with a ring token buffer, which we call macrobatch. Instead of allocating a large, mostly unused destination buffer for the comms SMs to transfer tokens into, we create a fixed-size ring buffer of a few hundred megabytes and cycle through it at minibatch granularity.
Implementing macrobatching efficiently requires careful overlap of computation and communication. Neither should stall because a buffer slot is still in use or because its data has not yet arrived. Ideally, we overlap across the ring boundary, computing on the tail end of the buffer while dispatching into its start.
The key idea is to drain each slot as early as performance allows so that it can be reused as early as possible. In the forward pass, dispatch fills slots and combine drains them, freeing them for the next dispatch.
However, if we run all dispatches followed by all combines (as in the previous section's schedule), the next macrobatch cannot begin until every combine has finished, and computation and communication only start overlapping again after its first dispatch completes.
To avoid this, we perform dispatch-combine interleaving for the forward pass. The combine for a minibatch of the previous macrobatch is interleaved with the dispatch for the corresponding minibatch of the next macrobatch, which uses the same region of the ring buffer. This way, the buffer is refilled as soon as it is emptied. Note that the first macrobatch's dispatches and the last macrobatch's combines are not interleaved, as they do not have their counterparts.

Reversed ring to minimize forward replay during backward
The backward pass is slightly more complex because the backward megakernel must support forward activation replay. The macrobatch buffer is a ring, so if there are multiple macrobatches, some saved activations are overwritten during the forward pass and must be recomputed. The replay only needs to run up to the SwiGLU activation, since backward only needs the down projection's input activation and output gradient, not its forward output.
One key optimization here is the reversed ring. If we consume tokens in ascending macrobatch order, the last macrobatch leaves the ring buffer partially filled, and the backward pass ends up with more activations to replay. MoK therefore walks through the tokens in reverse macrobatch order during the forward pass, so that the saved ring buffer is always either completely full or contains all of the tokens, minimizing forward replay during the backward pass.
Other features and implementation details
Megakernel
We built MoK using the megakernel technique, where instructions overlap at the SM task level instead of being separated by kernel launch boundaries. Megakernels are usually suited for fusing an entire forward or backward step, but we found the technique useful for MoK for two reasons: (1) implementing minibatching and macrobatching without megakernel fusion would require multiple kernel launches, increasing the launch boundary overhead; and (2) for inter-SM overlapping, we found multiple streams with green contexts unreliable at partitioning SMs exactly as intended, while software partitioning gives exact allocation guarantees.
Determinism
For internal ablations and on-policy RL post-training, we designed MoK to be fully deterministic. The order of floating point operations is fixed, so the same input produces bitwise-identical output regardless of hardware scheduling and instruction issue order.
Cluster Launch Control (CLC) for RDMA overlap
The MoK megakernel schedules its tasks through CLC to allow RDMA overlap. CLC is a hardware-native work-stealing feature introduced in Blackwell as a new way of implementing persistent grid kernels. A CLC-based kernel can naturally yield to kernels on a higher-priority stream without having to wait for the current kernel to fully complete. This matters because, during training, we often need to overlap intra-rack communication and computation with inter-rack InfiniBand/RoCE communication, such as FSDP all-gather, which require SMs of their own. Without CLC, the inter-rack communication would serialize behind the megakernel, causing significant performance degradation.
MXFP8 support
MoK supports both BF16 and MXFP8 precision modes. We train in MXFP8 mode, since it is faster and causes no numerical issues. In MXFP8 mode, the shared expert stays in BF16, as we found this to affect the training stability.
One added cost of MXFP8 is that tensors must be quantized before they are fed into the tensor cores. To minimize this overhead, we (1) provide an optimized MXFP8 quantization kernel for pre-quantizing the weights; and (2) fuse activation quantization into the dispatch all-to-all, the expert-grouped GEMMs, and the SwiGLU.
Router weight gradient computation
The MoK backward pass also computes the router weight gradients, using a SonicMoE-style calculation. Instead of saving the full down-projection output, it computes them from the inner product of the SwiGLU activation and the down-projection dgrad. This computation is fused into the SwiGLU backward to avoid additional memory traffic.
Computation/Communication SM tuning
The optimal ratio of comp to comms SMs depends on the workload. The local token count, the model shapes, and the hardware compute and network bandwidth all change how long the dispatch/combine tasks take relative to the expert FFN tasks. Even within the same workload, the optimal ratio differs between the forward and backward passes. MoK therefore exposes tunable parameters that set the number of comms SMs separately for forward and backward.
Speedups
We evaluated MoK with two types of benchmarks: individual MoE layer benchmarks, for which we release all benchmark code, and end-to-end benchmarks on our internal production training stack across multiple NVL72 racks.
MoE layer benchmarks
We benchmark single MoE layer execution: global token scheduling, token dispatch all-to-all, expert FFNs, token combine all-to-all, and the final weighted sum. We benchmarked the forward and backward passes separately, in both BF16 and MXFP8 modes. All tests ran within a single NVL72 rack, with EP degree 64 and 2,048 tokens/GPU before routing.
We chose baselines that (1) support both the MoE forward and backward passes; and (2) run on NVL72s:
- NCCL + PyTorch
- DeepEP + PyTorch
- DeepEP + TransformerEngine
- HybridEP + Megatron, which is Nvidia's recommended option on NVL72s over DeepEP + Megatron
We tested the shapes of widely used open-weight models:
- Kimi K2.7 Code shape (: 384, : 7168, : 2048, top-k: 8)
- GLM-5.2 shape (: 256, : 6144, : 2048, top-k: 8)
- Qwen3.5-397B-A17B shape (: 512, : 4096, : 1024, top-k: 10)
- DeepSeek-V4-Pro shape (: 384, : 7168, : 3072, top-k: 6)
The graphs below show results for all four shapes across all baselines:
Overall, we observe that MoK is up to 2.37x faster for the MXFP8 forward, 1.78x for the MXFP8 backward, 1.92x for the BF16 forward, and 1.58x for the BF16 backward, compared to the fastest baseline.
End-to-end benchmarks
In addition to the benchmarks against publicly available implementations, we report speedups on our internal production training stack. Previously, our training stack relied on a DeepEP-based implementation with custom MXFP8 MoE computation kernels for expert-parallelism. We compare the end-to-end tokens per second metric by varying the MoE layer implementation choice (DeepEP vs MoK). The benchmarks were conducted on 512 GPUs across several GB300 NVL72 racks.
| DeepEP-based | MoK | |
|---|---|---|
| Tokens / second / GPU | 760.9 | 1,070.2 (1.41x) |
Overall, MoK delivered an approximately 41% tokens-per-second speedup over our previous DeepEP-based production setup, allowing us to train our models more efficiently across our GB300 NVL72 infrastructure.
Megakernels for the agent era
Mixture-of-Kittens is fully open-sourced as of today. We plan to keep maintaining it and welcome community feedback and contributions. Our hope is that this lowers the barrier to AI research, allowing more researchers and labs to train models efficiently. MoK also aims to be flexible. We put a lot of effort into making it easy to modify, so that with the help of agents, you can quickly adapt it to platforms beyond the ones we run on.
As a side note, with the arrival of AI models capable of writing performant kernels, the kernel optimization space has become a lot more interesting. Single-operator kernels that used to be written by hand are now almost entirely handled by AI. Given the right design directions (e.g., how to specialize warps, which PTX instructions to use), agents can one-shot state-of-the-art kernels.
Even more interesting, however, is the new capabilities this gives us. Last year, writing a megakernel required creating a layer of simplified abstractions like this one. This year, we did not need a framework. Instead, we removed the additional layer of abstraction and, with the help of agents, worked through the complexity ourselves from scratch.
Agents automated the simpler tasks (e.g., single-operator kernels) and helped us get through the harder ones (e.g., writing a distributed MoE megakernel) much faster and with a very small team.
That said, there is plenty of work ahead of us in optimizing high-stakes ML workloads that run across hundreds of thousands of GPUs. If you find this post and this type of work interesting, we would love to hear from you. Reach out to us at hiring@cursor.com.
Citation
If you use this work, please cite:
Stuart H. Sul, Nash Brown, Henry Wildermuth, William Lin, and Federico Cassano. "Mixture-of-Kittens: MoE Megakernel for NVL72s." Cursor Research, Aug 2026. https://github.com/cursor/mixture-of-kittens
Or in BibTeX:
@misc{sul2026mok,
title={Mixture-of-Kittens: {MoE} Megakernel for {NVL72s}},
author={Stuart H. Sul and Nash Brown and Henry Wildermuth and William Lin and Federico Cassano},
organization={Cursor Research},
year={2026},
publisher = {GitHub},
howpublished = {\url{https://github.com/cursor/mixture-of-kittens}},
}*Special thanks to Chris Ré, Sasha Rush, Less Wright, Chen Lu, and Nathan Wang for reading this post and offering valuable feedback.*
- In this post, dispatch refers to the dispatch all-to-all communication and combine refers to the combine all-to-all communication. The weighted reduction usually included in "combine" is referred to separately as the weighted sum. ↩
News to Guide
ニュースの次に確認する
発表内容を、現在の料金や仕様と照らし合わせられる関連ガイドです。
今日のまとめ
AIデイリーブリーフで今日の重要ニュースをまとめ読み