+ 作る
図を読み込んでいます…
1 / 22

Muse Spark Open を段階的に分解する

発行
かえで
版
第2版
改訂
分量
22コマ・6,317字

Metaのオープンウェイトモデル「Muse Spark Open」(816B・1トークンで使うのは42B)の中身を、入口から62層、Attention、KVキャッシュ、MoE、4ビット化、8枚のGPUへの分割、そして処理時間の内訳まで、図が動く形で一段ずつ開いていきます。

Muse Spark Open を段階的に分解する

Muse Spark Open は、Metaがオープンウェイトで公開した大規模言語モデルです。パラメータ(重み)の総数は8,160億(816B)ですが、1つのトークンを処理するときに実際に使うのはそのうち約420億(42B)だけ、という少し変わった作りをしています。

このアニメモでは、このモデルを入口から出口まで、ブロックごとに開いていきます。もとになっているのは、Joaquín Campo さんのブログ「Memory-Bound」の解説記事で、数値は記事の記述(2026年10月27日時点)に基づいています。詳しい数式や触れる図は元の記事もあわせてどうぞ。

  • Muse Spark Open を段階的に分解する
  • 816Bパラメータの巨大モデルの中を、入口から順にたどる
  • Muse Spark Open
  • 入力
  • 次のトークン
  • 816B(1トークンで使うのは42B)
  • もとの記事:Memory-Bound「Understanding Muse Spark Open」(2026年10月27日)

① 入口:何でも「トークンの列」になる

Muse Spark Open は、文章だけでなく画像・動画・音声も受け取れます。入口は3つあり、文章はトークナイザで、画像や動画は画像用のエンコーダで、音声は音声用のエンコーダで、それぞれ処理されます。

どの入口から入っても、出てくるものは同じ形です。1つのトークンが8,192個の数を並べたベクトルになり、それが入力の長さぶん並んだ「トークンの列」になります。この列は最大で100万トークンまで扱えます。黒い箱が右に移動したように、ここから先はこの列だけがモデルの中を流れていきます。

  • ① 入口:何でも「トークンの列」になる
  • 書類
  • テキスト
  • トークナイザ
  • 写真
  • 画像・動画
  • 画像エンコーダ
  • モデル
  • 62層
  • 会話
  • 音声
  • 音声エンコーダ
  • トークンの列 [T, 8192]
  • 1トークン=8,192個の数のベクトル 最大100万トークンまで

② 62枚の層をくぐり、次のトークンを出す

黒い箱を開けると、中には層が62枚重なっています。トークンの列はこの62枚を順番に通り抜けます。62枚はすべて同じ形をしていて、違うのは中の重みだけです。

最後の層を出たあと、出力層が約20万語の語彙それぞれに点数をつけ、次に来るトークンを1つ選びます。選ばれたトークンは入力の最後に付け足され、もう一度モデルに入ります。文章を生成するときは、この輪を1トークンずつ回しています。

  • ② 62枚の層を順番にくぐり、次のトークンを出す
  • 層:Attention + MoE
  • トークンの列
  • 出力層 約20万語から1つ選ぶ
  • × 62層(全部同じ形、重みだけ別々)
  • 選んだトークンを、次の入力としてもう一度

③ 1枚の層の中:Attention と MoE

62枚のうちの1枚を拡大しました。中には大きく2つの部品があります。前半の Attention は、各トークンがそれより前のトークンを見て、必要な情報を集める部分です。後半の MoE(Mixture of Experts) は、トークンを1つずつ、専門家と呼ばれる小さなネットワークで加工する部分です。

2つの部品は、オレンジの線で描いた残差ストリームを直接書き換えるのではなく、そこに結果を混ぜ込みます。まずストリームのコピーを正規化(数の大きさをそろえる処理)してから部品に通し、出てきた結果も正規化して、ゲート(G)で混ぜます。

普通のモデルは単純に足し算しますが、Muse は「元のストリームをどれだけ残すか(α)」と「新しい結果をどれだけ足すか(β)」を、8,192個の数それぞれについて学習しています。こうすると、62層を通ってもストリームの値が膨らみすぎません。

  • ③ 1枚の層の中:Attention と MoE が交代で書き込む
  • 1枚の層(62枚とも同じ形)
  • 正規化
  • Attention 前のトークンを見る
  • 正規化
  • MoE 専門家8人が処理
  • 残差ストリーム s(8,192個の数)
  • G
  • G
  • G=ゲート: s ← α・s + β・正規化(出力) αとβは学習で決まる

④ 46層は「直近だけ」、16層は「全部」を見る

62枚の層は形は同じですが、Attention がどこまでさかのぼって見るかが違います。46枚は直近2,048トークンだけを見るスライディング層、残りの16枚はそれまでの全部を見るフル層です。

並び方は「スライディング・フル・スライディング・スライディング」の4枚1組のくり返しです。図の紫のマスがフル層で、4枚に1枚の割合で入っているのが分かります。すべての層が全文脈を見る必要はなく、遠くを見る役を一部の層に任せることで、計算とメモリを節約しています。下の2本のバーが、それぞれが見る範囲のイメージです。

  • 62層を順に並べたマス
  • フル層16層の位置
  • ④ 62層のうち46層は「直近だけ」、16層は「全部」を見る
  • 1
  • 62
  • スライディング層:直近2,048トークンだけ見る(46層)
  • フル層:それまでの全部を見る(16層)
  • 並びは「スライディング・フル・スライディング・スライディング」のくり返し
  • フル層が見る範囲
  • スライディング層
  • 今

⑤ Attention:質問(Q)と、見出し・中身(K・V)

Attention では、各トークンが3種類のベクトルを作ります。探したいものを表す Q(クエリ)、自分が何者かを示す見出しの K(キー)、渡す中身の V(バリュー) です。あるトークンは自分の Q を過去のトークンたちの K と照らし合わせ、よく合ったトークンの V を多めに受け取ります。

Muse の Q は128個のヘッド(並列に動く小さな Attention)に分かれています。図では8ヘッドずつを箱1つにまとめて、青い箱16個で描いています。ふつうの作りなら K と V も128ヘッドずつ必要です。そして過去のトークンの K と V は、毎回計算し直さなくていいようにKVキャッシュとして保存しておきます。トークンが増えるほどこのキャッシュは大きくなり、長い文脈ではメモリの一番の悩みになります。

  • ⑤ Attention:質問(Q)と、見出し・中身(K・V)
  • Qで「探したいもの」を出し、過去のトークンのKと照らして、合ったもののVを受け取る
  • Q:128ヘッド(箱1つ=8ヘッド)
  • K・V:ふつうならQと同じ128ヘッド。過去の全トークン分を保存する
  • 過去のトークンのK・Vは「KVキャッシュ」として保存。これが大きなメモリを食う

⑤ GQA:8つの質問ヘッドで、K・Vを共有する

そこで Muse は、K と V のヘッドを16個だけにしています。Q の8ヘッドが、1組の K・V を一緒に使う形です。これを GQA(Grouped-Query Attention) と呼びます。下の段の K・V の箱が、一気に8分の1の細さに縮んだのがその様子です。

KVキャッシュの大きさは K・V のヘッド数で決まるので、これだけでキャッシュは8分の1になります。さらに Muse はキャッシュの数を1つ1バイト(FP8)で保存して、もう半分にしています。Q のほうは128ヘッドのままなので、問いかける力は落としていません。

  • ⑤ GQA:8つの質問ヘッドで、1組のK・Vを共有する
  • Qで「探したいもの」を出し、過去のトークンのKと照らして、合ったもののVを受け取る
  • Q:128ヘッドのまま(箱1つ=8ヘッド)
  • K・V:16ヘッドだけ。Qの8ヘッドで1つを共有する
  • KVキャッシュは1/8に。さらに1つの数を1バイト(FP8)で保存して、もう半分

⑥ どこまで振り返るか:フル層とスライディング層

図は、どのトークンがどのトークンを見てよいかを表したものです。上から下へ並ぶ行が「見る側」、左から右へ並ぶ列が「見られる側」で、色の付いた部分が見てよい組み合わせです。どの層でも、自分より後のトークンは見られません。

フル層は、自分より前のトークンを全部見ます。スライディング層は、直近の決まった数だけを見ます(図では3つですが、実際は2,048トークン)。さらに、トークンの位置を表す情報(RoPE)はスライディング層にだけ加えられ、フル層は位置を持たずに中身だけで探します。こうすると、学習したときより長い文章にも強くなると考えられています。

Attention の最後には出力ゲートもあり、ヘッドごとに「このトークンには何も足さない」と、出力を0近くまで絞れるようになっています。

  • ⑥ どこまで振り返るか:フル層とスライディング層
  • フル層
  • スライディング層
  • フル層で見てよい範囲(自分より前全部)
  • スライディング層で見てよい範囲(直近だけ)
  • 自分より前のトークンを 全部見る(最大100万)
  • 直近の数個だけ見る (実際は直近2,048トークン)
  • 位置の情報(RoPE)を足すのはスライディング層だけ。フル層は中身だけで探す

⑦ 100万トークン分のKVキャッシュ

ここで、KVキャッシュがどれくらいの大きさになるかを計算してみます。もし何も工夫せず、128ヘッドぶんの K と V を1つ2バイトで62層ぶん持つと、1トークンあたり約2MBになります。100万トークンなら約2TB。H200(1枚141GB)を8枚つないでも、合計1,128GBなので入りません。

赤いバーがその大きさで、縦線がGPU1枚と8枚ぶんのメモリです。ここから、これまでに見てきた工夫を、下のリストの順に当てはめていきます。

  • ⑦ 100万トークン分のKVキャッシュ:そのままだと約2TB
  • H200 1枚 141GB
  • 8枚合計 1,128GB
  • そのまま持つと:1トークン約2MB × 100万 = 約2TB
  • ○ GQA:K・Vを128ヘッド→16ヘッドに(÷8)
  • ○ FP8:1つの数を2バイト→1バイトに(÷2)
  • ○ 46層は直近2,048トークンだけ保存(約÷4)
  • ○ 8枚のGPUでヘッドを分担(÷8)
  • GPU 8枚分のメモリを合わせても入らない

⑦ GQAとFP8で、16分の1に

まず GQA で K・V のヘッドを16に減らすと8分の1、さらに FP8 で1つの数を1バイトにすると半分になります。合わせて16分の1、約125GBです。赤いバーが一気に縮みました。

それでもGPU1枚のメモリはほぼ埋まってしまいますし、この大きさは会話が長くなるほど増え続けます。

  • ⑦ GQAとFP8で、16分の1に
  • H200 1枚 141GB
  • 8枚合計 1,128GB
  • GQA(÷8)とFP8(÷2)で:約125GB
  • ● GQA:K・Vを128ヘッド→16ヘッドに(÷8)
  • ● FP8:1つの数を2バイト→1バイトに(÷2)
  • ○ 46層は直近2,048トークンだけ保存(約÷4)
  • ○ 8枚のGPUでヘッドを分担(÷8)
  • 1枚には入るがほぼ満杯。しかも会話が長いほど増え続ける

⑦ さらに2段階で、1枚あたり約4GB

次に効くのが、46層あるスライディング層です。これらは直近2,048トークンぶんしか保存しないので、会話が長くなっても増えません。増え続けるのは16枚のフル層だけになり、全体で約35GB、1トークンあたり約33KBまで小さくなります。

最後に、8枚のGPUで K・V のヘッドを2つずつ分担するので、1枚が持つのはその8分の1、約4GBです。最初の約2TBから見ると、全体で約60分の1になりました。これで、100万トークンの文脈を現実的に扱えるようになっています。

  • ⑦ さらに2段階で、1枚あたり約4GBに
  • H200 1枚 141GB
  • 8枚合計 1,128GB
  • 全体で約35GB → 8枚で分けて、1枚あたり約4GB
  • ● GQA:K・Vを128ヘッド→16ヘッドに(÷8)
  • ● FP8:1つの数を2バイト→1バイトに(÷2)
  • ● 46層は直近2,048トークンだけ保存(約÷4)
  • ● 8枚のGPUでヘッドを分担(÷8)
  • 1トークン約2MB→約33KB。H200(141GB)のうちKVキャッシュは約4GBで済む

⑧ MoE:256人から8人を選ぶ

層の後半の MoE を見てみます。1枚の層には256人の「専門家(エキスパート)」がいて、それぞれが小さなニューラルネットワークです。トークンが来ると、まずルーターが256人全員に点数をつけ、上位8人だけにそのトークンを担当させます。右の16×16のマスが256人で、紫のマスがあるトークンのために選ばれた8人です。

ルーターの中身は、トークンのベクトルに1つの行列を掛けるだけの単純な計算です。ただ、選び間違えたときの影響が大きいので、ここだけは精度の高いFP32で計算しています。また Muse には、他のモデルによくある「全員が必ず通る共有の専門家」がいません。トークンが受け取るものは、すべて自分で選んだ8人から来ます。

  • 256人の専門家を16×16に並べた図
  • ⑧ MoE:256人の専門家から、トークンごとに8人を選ぶ
  • ルーター 256人それぞれに 点数をつける
  • 上位8人を選ぶ
  • 全員共通の専門家は いない
  • トークン h 8,192
  • 行列の掛け算1回 (ここだけFP32)
  • 256人の専門家(1層あたり) 紫=このトークンに選ばれた8人
  • 8人の選び方は約4×10¹⁴通り。トークンごとに細かく組み合わせを変えられる

⑨ 選ばれた8人は、半分の幅で働く

選ばれた8人の専門家が、マスの中から抜け出して一列に並びました。この8人は、トークンをそのままの幅(8,192)では受け取りません。まず8人共通の行列でトークンを4,096の幅に縮め、その小さな空間で8人がそれぞれ処理します。

各専門家の中身は、gate・up・down という3つの4,096×4,096の行列です。gate が「この特徴を通すかどうか」を決め、up が「どれだけ・どちら向きに」を決め、down が結果を元の形に戻します。8人の出力はそれぞれ正規化されたあと、ルーターがつけた点数で重みをつけて足し合わされ(Σ)、最後にもう一度共通の行列で8,192の幅に広げられます。幅を半分にしたことで、専門家1人あたりの重みは半分で済んでいます。

  • ⑨ 選ばれた8人は、半分の幅(4,096)で働く
  • 専門家 ×0.21
  • 専門家 ×0.18
  • 専門家 ×0.15
  • 専門家 ×0.12
  • Σ
  • 専門家 ×0.11
  • x 4,096
  • 専門家 ×0.09
  • h 8,192
  • 縮める 8,192→4,096
  • 専門家 ×0.08
  • 広げる 4,096→8,192
  • f 8,192
  • 専門家 ×0.06
  • 各専門家は gate・up・down の3つの行列(4,096×4,096)。出力を正規化してから、 ルーターの点数で重みをつけて足し合わせる。縮める・広げる行列は8人で共有

⑩ 816Bのうち、約98%が専門家

重みの内訳を見ると、このモデルの性格がよく分かります。専門家1人は約5,000万個の重みを持ち、それが1層に256人、62層ぶんで約7,990億個。全体の816Bのうち、ほとんどが専門家です。Attention や埋め込み、画像エンコーダなどを全部合わせても、右端の細い青い帯(約17B)しかありません。

一方、1つのトークンが1層で使う専門家は8人だけなので、実際に掛け算に使う重みは約42Bで済みます。「大きいのに速い」のはこのためです。ただし、どの専門家が呼ばれるかは前もって分からないので、全員分の重みをメモリに置いておく必要があります。

  • ⑩ 816Bのうち、約98%が専門家の重み
  • Attentionなど全部で 約17B ↓
  • 専門家 799B(256人 × 62層)
  • ← 1トークンが1層で使うのは、このうち8人だけ
  • 合計 816B
  • 1トークンが実際に使う重み:約42B(全体の約5%)
  • だから「大きいのに速い」。ただし、誰が呼ばれてもいいように 全員分の重みをメモリに置いておく必要がある

⑪ 専門家の重みは、そのままでは入らない

紫の帯が、そのままメモリの大きさを表すバーに変わりました。専門家の重み約7,990億個を、1つ16ビット(BF16)で持つと約1.6TBになります。

H200を8枚つないだノード全体のメモリは1,128GB。縦線を大きくはみ出しています。専門家の重みだけで、一番大きなGPUノードにも収まらないのです。

  • ⑪ 専門家の重みは、そのままだとGPU 8枚に入らない
  • GPU 8枚の合計 1,128GB
  • BF16(16ビット):約1.6TB
  • 専門家の重みだけで、1つのノード(H200×8)のメモリをはみ出す

⑪ 4ビット(NVFP4)にして、やっと収まる

そこで Meta は、専門家の重みを NVFP4 という4ビット形式でも公開しています。16個の数ごとに小さな倍率を共有する形式で、1つあたり約4.5ビット。これで専門家の重みは約449GBまで縮み、縦線の内側に収まりました。

ただし H200 には4ビットのまま掛け算する機能がないため、重みを読み込むたびにBF16へ戻してから計算しています。つまり4ビット化で節約できるのは、メモリの量と、メモリから重みを読む時間です。この「読む時間」が、あとで大事になります。

  • ⑪ 4ビット(NVFP4)にして、やっと収まる
  • GPU 8枚の合計 1,128GB
  • NVFP4:約449GB
  • 16個の数ごとに小さな倍率を共有する、約4.5ビットの形式
  • H200は4ビットのまま計算できないので、読み込むたびにBF16に戻して計算する → 節約できるのは「メモリの量」と「読む時間」

⑫ 8枚のGPUで、32人ずつ受け持つ

4ビットにしても約449GBあるので、1枚(141GB)には入りません。そこで各層の256人を8枚のGPUに32人ずつ分けて置きます。先ほどの16×16のマスが戻ってきて、横2行ずつの枠が1枚のGPUになりました。Attention のほうは、K・V のヘッドを2つずつ分担します。

あるトークンの8人は、たいてい複数のGPUに散らばっています。図の例では6枚です。トークンはそれぞれのGPUへ送られ、処理された結果が集められて足し合わされます。1つずつ送っていては遅すぎるので、実際にはたくさんのトークンをまとめて(バッチで)運び、専門家ごとに担当トークンを集めて一度に計算します。

たとえば753トークンのまとまりなら、選ばれる回数は753×8=6,024回で、専門家1人あたり平均約24トークンになります。なお、人気の専門家が1枚のGPUに偏ると、その1枚の仕事が終わるまで他のGPUは待たされてしまいます。

  • 256人の専門家を16×16に並べた図
  • ⑫ 8枚のGPUで、専門家を32人ずつ受け持つ
  • このトークンの8人は、6枚のGPUに 散らばっている → それぞれへ送って、 結果を集めて足し合わせる
  • GPU1
  • GPU2
  • 1つずつ運ぶと遅いので、 トークンは「まとめて」運ぶ(バッチ)
  • GPU3
  • GPU4
  • 753トークン × 8人 = 6,024件 → 専門家1人あたり平均 約24トークン
  • GPU5
  • GPU6
  • 人気の専門家が1枚に偏ると、 その1枚を全員が待つことになる
  • GPU7
  • GPU8

⑬ 専門家を動かす時間:「読む」と「計算」

専門家1人を動かすには、GPUは2つのことをします。メモリから専門家の重みを読むことと、その重みで掛け算をすることです。H200 はこの2つを同時に進められるので、かかる時間は遅いほうで決まります。

重みを読む時間は、専門家1人ぶん(4ビットで約28MB)で約5.9マイクロ秒。担当するトークンが1つでも500個でも、ほとんど変わりません。一方、計算はトークン1つあたり約0.1マイクロ秒で、トークンが増えるほど長くなります。

文章を1つずつ生成しているときは、専門家1人が受け持つトークンは1つだけ。オレンジの計算のバーはほんの少しで、GPUはほとんどの時間を重みの読み込み待ちに使っています。

  • ⑬ 専門家1人を動かす時間:「読む」と「計算」
  • 専門家1人あたり 1トークン(会話1つで生成中)
  • 重みを読む
  • 5.9µs(約28MBの4ビット重み。トークン数に関係なく一定)
  • 計算する
  • 0.1µs
  • 約58トークンで逆転
  • → 計算は一瞬で終わり、ほとんどは重みの読み込み待ち(約98%が待機)
  • GPUは「読む」と「計算」を同時に進めるので、遅いほうの時間がかかる

⑬ 1人あたり約24トークンでも、まだ「読む」が遅い

プロンプトをまとめて読むとき、たとえば753トークンなら、専門家1人あたり約24トークンになります。オレンジの計算のバーは伸びましたが、まだ2.4マイクロ秒。青い「読む」バーの5.9マイクロ秒には届かず、GPUは引き続き重みを待っています。

2本のバーがちょうど同じ長さになるのは、灰色の縦線のところ、専門家1人あたり約58トークンのときです。

  • ⑬ 1人あたり約24トークンでも、まだ「読む」が遅い
  • 専門家1人あたり 約24トークン(753トークンをまとめて読む)
  • 重みを読む
  • 5.9µs(約28MBの4ビット重み。トークン数に関係なく一定)
  • 計算する
  • 2.4µs
  • 約58トークンで逆転
  • → 計算は2.4µsで終わり、残りはまだ重みの読み込み待ち
  • GPUは「読む」と「計算」を同時に進めるので、遅いほうの時間がかかる

⑬ 約94トークンで、立場が逆転する

会話4つぶんを同時に読むと、専門家1人あたり約94トークンになり、オレンジのバーが縦線を越えました。今度は計算のほうが長く、メモリが計算を待つ側です。

この見方をすると、4ビット化の意味がもう1つ見えてきます。もし重みがBF16のままなら、専門家1人を読むだけで約21マイクロ秒かかっていました。4ビットにしたことで、メモリに収まるだけでなく、生成のように「読む」がボトルネックになる場面そのものが速くなっているのです。

  • ⑬ 約94トークンで、立場が逆転する
  • 専門家1人あたり 約94トークン(会話4つを同時に読む)
  • 重みを読む
  • 5.9µs(約28MBの4ビット重み。トークン数に関係なく一定)
  • 計算する
  • 9.4µs
  • 約58トークンで逆転
  • → 今度は計算が長く、メモリのほうが待つ側に
  • 4ビット化は「読む時間」も縮めている(BF16なら読むだけで約21µs)

⑭ 今は、下限の4〜7倍の時間がかかっている

では、現在の実装はこの下限にどれだけ近いのでしょうか。記事が取り上げている高速化チャレンジでは、Meta が使っている推論エンジン SGLang の時間が基準になっています。GPU1枚が受け持つ32人の専門家を1層ぶん動かすのに、753トークンのときは約757マイクロ秒。重みを読むだけの下限は約190マイクロ秒なので、約4倍かかっています。会話4つ同時のときは約2,236マイクロ秒で、計算の下限約310マイクロ秒の約7倍です。

前のページの青いバーとオレンジのバーが、それぞれの「下限」に姿を変えました。灰色の部分が、よりよいカーネル(GPUで動く計算プログラム)を書けば取り戻せるかもしれない時間です。専門家の部分が処理時間の大半を占めることもあって、ここがチャレンジの一番の狙いどころになっています。

  • ⑭ 今のSGLangは、下限の4〜7倍の時間がかかっている
  • 1ターン (753トークン)
  • SGLang 757µs / 下限 約190µs(読む時間)→ 約4倍
  • 会話4つ同時 (3,012トークン)
  • SGLang 2,236µs / 下限 約310µs(計算の時間)→ 約7倍
  • 色の部分=どうしても必要な時間 灰色の部分=より良いカーネルで取り戻せる時間
  • ここが、賞金つき高速化チャレンジの一番の狙いどころ

まとめ

Muse Spark Open は、62枚の同じ形の層が、Attention と MoE で交互に残差ストリームへ書き込んでいく構造でした。Attention は GQA・FP8・スライディング窓の組み合わせで、100万トークンのKVキャッシュを1枚あたり約4GBまで小さくしています。MoE は256人から8人を選ぶことで、816Bの大きさを持ちながら1トークンには42Bしか使いません。その代わり、時間の多くは専門家の重みをメモリから読むことに使われていて、そこに高速化の余地が残っています。

この内容は、Joaquín Campo さんのブログ記事 Understanding Muse Spark Open をもとに、構成と図を作り直してまとめたものです。元の記事には、ここでは省いた数式や、触って動かせる図がたくさんあります。

  • まとめ:Muse Spark Open の中身
  • 62層 ×(Attention+MoE) ゲート付きの残差
  • 46層は直近2,048だけ KVキャッシュは約1/60に
  • Muse Spark Open
  • 816B(使うのは42B)
  • 256人から8人を選ぶMoE 重みは4ビットで約449GB
  • 時間の大半は 専門家の重みの読み込み
  • 出典:Memory-Bound「Understanding Muse Spark Open」(Joaquín Campo, 2026年10月27日)

0 件のコメント

読み込み中…

権利侵害・不適切な内容の連絡: [email protected]