PLaMo 3アーキテクチャ徹底解析
対象はPLaMo 3 NICT 2604 31B Base(2604版)で、参照先はHugging Faceのpfnet/plamo-3-nict-2604-31b-baseのrevision e26c257e2175b05db69f01b52f4edf6fa4118f53です。公開実装はTransformers 5系を前提とするmodeling_plamo.pyで、vLLM用のsitecustomize.pyも同梱されています。
比較に使うPLaMo 3 NICT 31B Base[5]は、最大系列長4096の4K版です。revisionは9c1fa626です。トークナイザの定義ファイルとコードは、2604版とバイト単位で同一です。
Gemma 4の比較対象はgoogle/gemma-4-31Bの事前学習版で、revisionは5bbc2fb1c1b2c611d06e3d9f23c170ba21659d89です。実装はTransformers 5.12.1のmodeling_gemma4.py[7]を参照しています。実行環境と測定条件は§10に示します。
- [5] Preferred Networks, Inc., "PLaMo 3 NICT 31B Base (model card, config.json, modeling_plamo.py; revision 9c1fa626)," Hugging Face, 2026.
- [7] Hugging Face, "modeling_gemma4.py (Transformers v5.12.1)," GitHub, 2026.
- 各計算で使うベクトルの次元数を、設定ファイルと重みの形状に合わせること(§2.1)。
- 正規化で各成分に掛ける係数を、保存された重みから正しく求めること(§3.2)。
- 過去の計算結果を保存・再利用する処理と、位置情報を反映する処理の順序を、公開実装に合わせること(§4.4)。
1. 局所Attentionと大域Attentionによる長文処理
2. 設定と保存された重みから分かるモデル構成
2.1. 主要な設定値
config.json[1]の主要な値を次の表に示します。
| 設定項目 | 値 | 記号・役割 |
|---|---|---|
vocab_size | 107520 | 語彙数\(V\)。埋め込みの行数と一致 |
hidden_size | 5120 | 残差ストリーム(層間で受け渡すベクトル)の次元数\(D\)。隠れ次元とも呼ぶ |
num_hidden_layers | 64 | デコーダブロック数\(L\) |
intermediate_size | 25600 | MLPの中間次元\(F\)(\(5D\))。gate/upそれぞれの射影出力の次元数(§7) |
num_attention_heads | 64 | Queryヘッド数\(H_q\) |
num_key_value_heads | 8 | Key/Valueヘッド数\(H_{kv}\) |
head_dim | 128 | 1ヘッドの次元数\(d\)。Q/K/Vで共通 |
rms_norm_eps | \(10^{-6}\) | RMSNormで二乗平均に加える\(\epsilon\) |
window_size | 2048 | 局所Attentionの窓幅\(W\) |
sliding_window_pattern | 8 | 8層ごとに大域Attention |
rope_local_theta | 10000 | 局所層のRoPEの基底 |
rope_theta | 1000000 | 大域層のRoPEの基底 |
initial_context_length | 4096 | YaRNの元の文脈長\(L_0\)(§6.3) |
rope_scaling_factor | 256 | 大域層のYaRNの係数\(s\)(§6.3) |
max_position_embeddings | 262144 | 設定に記録された最大系列長 |
scale_embedding | false | 埋め込みを\(\sqrt{D}\)倍しない(§2.4) |
linear_type | fp8 | 公開実装では参照されない(重みはBF16) |
nn.Linearを使います。公開実装のLinearType列挙型にはnormal、fp8、mxfp8が定義されていますが、モデルの構築や順伝播の分岐には使われていません。linear_typeの値は8B Baseではnormal、31Bモデルの4K版・2604版ではfp8ですが、この設定値は公開重みの保存形式や射影の計算を変えません。
head_dimに従って128を使います。Queryの総次元数が隠れ次元を上回る点は、Gemma 4も同じです(§8)。
2.2. 公開重みのキー名とパラメータ数
model.layers.layers.{i}.で始まります。iは0始まりの層番号です。重みを変換する際は、layersが2回続く点に注意してください。ブロック内では、mixer属性がAttention、mlp属性がトークンごとの特徴変換(MLP)に対応します。これらの属性名は全64層で共通です。
Plamo3ForCausalLMは、model属性にPlamo3Modelを持ちます。埋め込みのキー名はmodel.embed_tokens.weight、最終RMSNormはmodel.norm.weightです。ブロック列はPlamo3Model.layersのPlamo3Decoderが管理し、そのlayers属性にModuleListを持ちます。この2段の階層が、キー名のlayers.layersに対応します。
model.layers.layers.{i}.をキー名から省いています。PyTorchの線形層の重みは、行が出力、列が入力に対応する\([\text{out}, \text{in}]\)の形状です。RMSNormが保存するのは、実効ゲインとオフセットの差分です(§3.2)。
| キー名 | 形状 |
|---|---|
mixer.qkv_proj.weight | \(10240 \times 5120\) |
mixer.o_proj.weight | \(5120 \times 8192\) |
mixer.q_norm.weight、mixer.k_norm.weight | 各128 |
mlp.gate_up_proj.weight | \(51200 \times 5120\) |
mlp.down_proj.weight | \(5120 \times 25600\) |
pre_mixer_norm.weight、post_mixer_norm.weight、pre_mlp_norm.weight、post_mlp_norm.weight | 各5120 |
lm_head.weightは保存していません。Gemma 4も入出力の行列を共有します(§8)。
1ブロックの内訳は、QKV射影が52,428,800、出力射影が41,943,040、gate/up射影が262,144,000、down射影が131,072,000、RMSNormが\(4 \times 5120 + 2 \times 128 = 20{,}736\)パラメータです。合計は487,608,576で、モデル全体では\(550{,}502{,}400 + 64 \times 487{,}608{,}576 + 5{,}120 = 31{,}757{,}456{,}384\)になります。
設定ファイルにtie_word_embeddingsの指定はなく、公開実装では既定値のTrueが使われます。保存されている全テンソルの要素数も同じ値で、テンソル数は\(64 \times 10 + 2 = 642\)です。RoPEの周波数は学習パラメータに含まれず、実行時にバッファとして作られます。公開実装は出力ヘッドの行数を語彙数以上の16の倍数に揃えますが、107,520は16で割り切れるため、追加行はありません。
2.3. モデルサイズごとの構成・演算回数・読み込み量
| 項目 | 610M[4] | 2B[2] | 8B[3] | 31B[1] |
|---|---|---|---|---|
| 総パラメータ数 | \(8.90 \times 10^{8}\) | \(2.60 \times 10^{9}\) | \(8.09 \times 10^{9}\) | \(3.18 \times 10^{10}\) |
| 入力埋め込みの パラメータ数 | \(1.65 \times 10^{8}\) | \(2.75 \times 10^{8}\) | \(4.40 \times 10^{8}\) | \(5.51 \times 10^{8}\) |
| 隠れ次元\(D\) | 1536 | 2560 | 4096 | 5120 |
| 層数\(L\) | 16 | 24 | 32 | 64 |
| MLPの中間次元\(F\) | 6144 | 10240 | 16384 | 25600 |
| Queryヘッド数\(H_q\) | 16 | 24 | 32 | 64 |
| Key/Valueヘッド数\(H_{kv}\) | 1 | 4 | 4 | 8 |
| 入力埋め込みと 出力ヘッド | 共有なし | 共有 | 共有 | 共有 |
| decodeの概算演算回数 (GFLOP/トークン) | 1.75 | 5.89 | 17.39 | 68.34 |
| うち内積・重み付き和の割合 | 17.24% | 11.54% | 6.95% | 7.07% |
| 重みの読み込み量 (GiB/ステップ) | 1.35 | 4.85 | 15.07 | 59.15 |
| KVキャッシュの読み込み量 (MiB/トークン) | 18 | 108 | 144 | 576 |
| K/Vの追加保存に 必要な容量(KiB/トークン) | 局所層: 7 大域層: 1 合計: 8 | 局所層: 42 大域層: 6 合計: 48 | 局所層: 56 大域層: 8 合計: 64 | 局所層: 224 大域層: 32 合計: 256 |
語彙数を\(V\)、隠れ次元を\(D\)、層数を\(L\)、MLPの中間次元を\(F\)、Query・KVヘッド数を\(H_q,H_{kv}\)、ヘッド次元を\(d\)とします。出力ヘッドを含む線形射影の行列要素数\(P_{\mathrm{lin}}\)は、次の式で求められます。各ブロックのQKV・出力射影が\(2Dd(H_q+H_{kv})\)、gate/up/down射影が\(3DF\)、出力ヘッドが\(VD\)要素です。
\[ P_{\mathrm{lin}} = L\left[2Dd(H_q+H_{kv}) + 3DF\right] + VD \]大域層数を\(N_g=L/8\)、局所層数を\(N_l=7L/8\)、系列長を\(N\)、窓幅を\(W\)とし、全層の参照トークン数の合計を\(A=N_gN+N_l\min(N,W)\)と置きます。合計演算回数\(C\)は次の式で概算しています。第1項が線形射影、第2項がAttentionの内積と重み付き和です。表では\(B=1\)、\(N=4096\)、\(W=2048\)、\(d=128\)を代入し、第2項を\(C\)で割って内積・重み付き和の割合を求めています。
\[ C \approx 2BP_{\mathrm{lin}} + 4BH_qdA \]BF16は1要素2バイトなので、行列重みの読み込み量は\(2P_{\mathrm{lin}}\)バイト、KとVの読み込み量は計\(4BH_{kv}dA\)バイトです。GQAでは、同じKVヘッドを参照するQueryヘッド間でKとVを使い回すと仮定しています。系列間でのKVキャッシュの共有は仮定していません。1 MiBは\(2^{20}\)バイト、1 GiBは\(2^{30}\)バイトです。
新しい1トークンのKとVは、1層あたり計\(4H_{kv}d\)バイトです。窓外のK/Vを破棄しない場合、1トークンあたりの追加保存量は局所層全体で\(4N_lH_{kv}d\)バイト、大域層全体で\(4N_gH_{kv}d\)バイト、全層では\(4LH_{kv}d\)バイトになります。1 KiBは\(2^{10}\)バイトです。31Bでは局所56層で224 KiB、大域8層で32 KiB、合計256 KiBです。
演算回数と読み込み量の概算では、正規化・softmax・RoPE・活性化関数・残差加算などの演算、入力埋め込みの検索、正規化の重みや中間データの読み込みを省いています。追加保存量はK/Vの要素数から求めた容量であり、KVキャッシュの再配置などに伴う書き込みは数えていません。新しいKとVも含めて参照範囲を数えており、それらがメモリへの保存前に使われる場合との差も無視しています。実際のメモリ転送量は、重みやK/Vがハードウェアのキャッシュに残るかどうかや、カーネルによる重み・K/Vの再読み込み、中間データの保存方法によって変わります。
31Bモデルの4K版は、2604版と層数や次元数が同じです。計算に関わる設定では、大域層にYaRNを適用しないことと、最大系列長が4096であることの2点だけが異なります。重みは一致せず、同名の射影行列と埋め込みを比較したコサイン類似度は、ほぼ0でした。
2つのチェックポイントの同名テンソルをそれぞれ1次元に並べ、コサイン類似度を求めました。埋め込みと全64層のqkv_proj、o_proj、gate_up_proj、down_projでは、すべて−0.001〜0.001でした。ただし、ニューロンの並べ替えや、入出力の関係を保った重みの変換(再パラメータ化)でも、重みの類似度は変わるため、この測定から学習履歴を特定することはできません。
オフセットを足す前のRMSNormの重みについて、各層で求めたコサイン類似度の中央値はpost_mixer_normが0.74、post_mlp_normが0.90、q_normとk_normが約0.79でした。最終RMSNormの類似度は0.95、入力側のRMSNormでは0.04〜0.08です。出力側のゲインの層ごとの傾向も似ています(§9.2)。BF16の値がビット単位で一致する要素の割合は、どのテンソルでも0.1〜0.8%でした。
2.4. 入力からlogitsまでの計算
forward)で求めたlogitsをそのまま返します。softmaxによる確率への変換や、次のトークンの選択は、生成処理側で行います。
3. ブロックの構造とオフセット付きRMSNorm
3.1. 残差を含むブロックの式
pre_mixer_norm、mixer、post_mixer_normです。その出力を残差に加えた\(A\)を、MLP側のpre_mlp_norm、mlp、post_mlp_normへ順に渡します。残差に加えるテンソルの形状は、どちらも\([B, T, 5120]\)です。Gemma 4も、両処理の前後に計4つのRMSNormを置きます(§8)。
3.2. 重みとオフセットの和による実効ゲイン
| 適用箇所 | 実装名 | オフセット\(c\) | 正規化する次元数\(n\) |
|---|---|---|---|
| Attention入力 | pre_mixer_norm | 1 | 5120 |
| Attention出力 | post_mixer_norm | \(1/5 = 0.2\) | 5120 |
| MLP入力 | pre_mlp_norm | 1 | 5120 |
| MLP出力 | post_mlp_norm | \(5^{-1.5} \approx 0.0894\) | 5120 |
| Query | mixer.q_norm | 1 | ヘッドごとの128 |
| Key | mixer.k_norm | 1 | ヘッドごとの128 |
| 最終出力 | model.norm | 1 | 5120 |
公開実装のコメントには、すべてのオフセットを1にすると性能が低下したとあります。ただし、評価条件や低下量、0.2と\(5^{-1.5}\)を選んだ理由は記されていません。Plamo3RMSNormのdocstringは、weight decay(重み減衰)を適用したときのパラメータ更新がtorch.nn.RMSNormと異なる点を挙げています。また、推論用に置き換える場合は、オフセットを重みへ足す必要があると注記しています。
weight decayは、学習する重みを0へ近づける更新です。\(w\)をその対象に含め、AdamWのように勾配による更新と分離して減衰させる場合を考えます。学習率を\(\eta\)、減衰係数を\(\lambda\)とすると、減衰だけによる更新は\(w' = (1 - \eta\lambda)w\)です。このとき、実効ゲインは\(\gamma' = (1 - \eta\lambda)\gamma + \eta\lambda c\)となり、\(c\)へ近づきます。一方、オフセットを足し込んだ\(\gamma\)に同じ減衰を掛けると、0へ近づきます。オフセットを重みに足しておけば推論時の出力は保てますが、その重みに同じweight decayを適用して学習を続けると、実効ゲインの変化は元のモデルと異なります。この導出はRMSNormにもweight decayを適用する場合の性質で、実際の学習設定を示すものではありません。
sitecustomize.pyは、どちらも重みの読み込み時にオフセットを足します。
_plamo3_rms_normは、二乗平均と、各成分を分母で割る処理を32ビット浮動小数点(FP32)で計算します。分母で割った値を入力のデータ型へ戻してから、(offset + weight)を掛けます。Gemma 4の実装は、ゲインの乗算までFP32で計算してから入力のデータ型へ戻す順序です。オフセットを重みへ足し込むときも、加算に使うデータ型と丸めの段階によって値は変わりえます。BF16でビット単位の一致を求める場合は、数式に加え、オフセットの加算、型変換、乗算の順序まで合わせる必要があります。
4. Attentionの計算手順とテンソルの形状
4.1. QKV射影の分割位置
pre_mixer_normの出力を\(U \in \mathbb{R}^{B \times T \times 5120}\)とすると、\([Q_{\text{flat}}, K_{\text{flat}}, V_{\text{flat}}] = U W_{\text{qkv}}^\mathsf{T}\)で一度に射影できます。出力の次元数は、\(64 \times 128 + 8 \times 128 + 8 \times 128 = 10240\)です。
qkv_proj.weightの行をこの境界で分けます。ヘッドごとにQ/K/Vを交互に取り出すと、本来Q・K・Vに使うべき重みを取り違えます。
4.2. GQAによるKey/Valueの共有
scaled_dot_product_attentionにenable_gqa=Trueを渡して、K/Vヘッドを共有するAttentionの計算をPyTorch側に任せています。両者は数学的には同じで、§10の参照実装は明示的に繰り返す方法です。キャッシュに保存する段階では、64ヘッド分へ複製する必要はありません。
4.3. ヘッドごとのQ/K正規化
q_normとk_normでヘッドごとのRMSNormを適用します。どちらもオフセット1、\(\epsilon = 10^{-6}\)で、トークン・ヘッドごとに128次元のベクトルを正規化します。ゲインの形状は\([128]\)で、Q用は64個のQueryヘッド、K用は8個のKVヘッドに共通です。Vには正規化を適用しません。
- [21] Alex Henry, Prudhvi Raj Dachapally, Shubham Shantaram Pawar, Yuxuan Chen, "Query-Key Normalization for Transformers," Findings of EMNLP, 2020. (L2正規化と学習可能なスカラーを使うQuery-Key Normalization)
4.4. KVキャッシュとRoPEの適用順序
DynamicCacheです。正規化済み・RoPE適用前のKと、正規化していないVを保存し、Qは保存しません。RoPEを適用する対象は、キャッシュから返されたK全体と今回のQです。したがって大域層では、過去のKも順伝播のたびに回転し直します。
局所層では、TransformersのDynamicSlidingWindowLayerがキャッシュ更新後に末尾の最大\(W - 1 = 2047\)トークンを残します。次のdecodeでは新しい1個を加えた2048個にKの位置\(0, \dots, 2047\)を割り当て、Qの位置を2047とします。固定周波数のRoPEでは、QとKの位置を同じ量だけ平行移動しても内積は変わりません。この実装のYaRNも固定周波数と共通の振幅補正を使うため、同じ性質を保ちます。ただし、有限精度の丸め誤差まで一致するとは限りません。
引数のposition_idsはAttentionへ渡されず、内部で作った連番が使われます。不等間隔の位置を指定する場合や、複数の系列を連結した入力で位置をリセットする場合は、引数の位置情報をAttentionへ渡すように実装を変更する必要があります。
4.5. GQAの式と出力射影
o_proj.weight(\(5120 \times 8192\))を掛けて隠れ次元へ戻します。
5. 局所/大域Attentionの配置とKVキャッシュ
5.1. 局所7層・大域1層の配置
swa_maskはtriu(diagonal=-(window_size - 1))で帯状のマスクを作ります。参照先との距離は\(W - 1\)以下なので、自分を含めて最大\(W = 2048\)個です。局所層のキャッシュは\(W - 1\)個を残し、次のdecodeで新しい1個が加わるため、prefillとdecodeの参照範囲は一致します。
4K版に同梱された旧実装はtriu(diagonal=-window_size)を使い、自分を含めて最大\(W + 1 = 2049\)個を参照します。独自のキャッシュクラスが残すのも末尾\(W\)個です。「窓幅2048」に含めるトークン数は、実装の版によって1個異なります。
2604版にも、マスクを省略できる条件のassertが\(S \le W + 1\)のまま残っています。そのため、学習モードでマスクを省略し、キャッシュなしで\(T = W + 1\)を入力すると、本来は窓外となる1トークンも参照対象に入ります。ランダム重みの小型モデル(\(W = 4\))では、この条件で学習モードと評価モードのlogitsに最大0.15の差が出ました(§10)。
5.2. KVキャッシュ容量の計算
| 系列長\(N\) | PLaMo 3 31B | Gemma 4 31B | PLaMo 3 31Bを全層大域にした場合 |
|---|---|---|---|
| 4,096 | 576 MiB | 1,120 MiB | 1 GiB |
| 32,768 | 1,472 MiB | 3,360 MiB | 8 GiB |
| 131,072 | 4,544 MiB | 11,040 MiB | 32 GiB |
| 262,144 | 8,640 MiB | 21,280 MiB | 64 GiB |
Gemma 4の大域10層は4ヘッド×512次元のKとVを持ち、1層・1トークンあたり8 KiBです。局所50層は16ヘッド×256次元で、1層・1トークンあたり16 KiBになります。局所層の合計容量は、約800 MiBで頭打ちです。
attention_k_eq_vは射影の共有を指定します。共有する射影出力を\(Z\)、ゲイン\(\gamma\)のRMSNormを\(N_\gamma\)とすると、大域層では\(K = \operatorname{RoPE}(N_{\gamma_k}(Z))\)、\(V = N_1(Z)\)です。上の表は、KとVを別々に保持するTransformersの実装に対応します。共通の射影出力だけを保存し、KとVを再計算する実装では、保存するテンソルに合わせて容量を計算し直す必要があります。
1要素1バイトと仮定すると、1Kトークンで128 MiB、128Kトークンで約2.2 GiBとなり、丸めを考慮すると、公開されている比較表[8]の値と一致します。本記事で示すKVキャッシュ容量には、パラメータ本体・マスク・活性値・logitsに必要なメモリ、メモリ割り当ての断片化による余分な使用量、prefill中の一時領域を含めていません。
- [8] Shuji Suzuki, "大規模言語モデルの次期バージョン PLaMo 3 シリーズにおける8B, 31Bの小規模モデルによる事前学習の検証," Preferred Networks Tech Blog, 2025.
5.3. 計算量と実装上のメモリ使用量
公開実装はprefillで\(T \times S\)の因果マスクと局所マスクを配列として構築し、scaled_dot_product_attentionに渡します。マスクで参照先を制限するだけでは、窓外のQ/Kの内積計算まで省略されるとは限りません。設定上の最大系列長\(T = S = 262144\)でFP32のマスクを1枚作ると、\(T \times S\)要素に各4バイトを使うため、256 GiBが必要です。これは形状とデータ型から計算した値で、実行時の測定値ではありません。
4K版の旧実装にあったflash_attnを呼ぶ分岐は、2604版では削除されています。vLLMの実装は、窓幅を指定できるAttentionバックエンドを使います。
6. RoPEの回転ペアと大域層のYaRN
6.1. split-halfの回転ペア
6.2. 局所層と大域層の基底の違い
6.3. 大域層のYaRN
rope_scaling_factorに設定された\(s = 256\)です。最大系列長262,144は元の文脈長4096の64倍ですが、この64を係数に使うと公開実装とは異なる周波数になります。
YaRNは、Q・Kに共通の係数\(0.1 \ln s + 1\)を掛け、周波数を変えたときのAttentionの重みの分布を補正します。論文ではこの係数を温度\(t\)による\(\sqrt{1/t}\)として導入していますが、公開実装はcos/sinのテーブルへ係数を掛けるため、本記事では振幅補正と呼びます。通常のAttentionの係数\(1/\sqrt{128}\)も含めると、振幅補正のない回転後の内積に掛かる係数は\(2.4165 / \sqrt{128} \approx 0.2136\)です。
\(L_0 \times 256 = 1{,}048{,}576\)は、設定上の最大系列長262,144と異なります。YaRNの係数\(s\)だけから、対応できる文脈長や、その長さでの精度を求めることはできません。YaRNの数理はYaRNの解説記事で扱っています。
BF16で公開実装と照合する場合は、三角関数の丸めにも注意が必要です。公開実装は角度とcos/sinをFP32で計算し、cos/sinを入力のデータ型へ戻してから振幅補正の係数を掛けます。§10の参照実装はFP32を対象としており、このBF16への型変換は省いています。
Plamo3Config.rope_parametersは、config.jsonの値から局所層・大域層それぞれのRoPE設定を生成して返すプロパティです。Transformers 5.12.1では、旧名のrope_scalingからも同じ値を取得できます[22]。JSONにrope_scalingがないことだけでは、YaRNが無効とは判断できません。
参照したvLLM本体[15]は、層の種類ごとのrope_parametersを読みます。一方、同梱のsitecustomize.pyは旧名のrope_scalingを読む別実装です。層の種類ごとの設定との互換性や、vLLMでの実行結果は確認していません。
- [22] Hugging Face, "configuration_utils.py (Transformers v5.12.1)," GitHub, 2026.
- [15] vLLM Project, "vllm/model_executor/models/plamo3.py (commit d881812)," GitHub, 2026.
6.4. Gemma 4のp-RoPE
Transformersのproportional形式[23]は、角周波数を計算するとき、指数の分母に元のヘッド次元512を使います。そのうえで、低周波側の角周波数を0にします。回転ペアは\((j, j + 256)\)で、角周波数は次の値です。
回転の対象となるのは、成分番号0〜63と256〜319の計128成分です。先頭128成分に通常の128次元RoPEを適用する方法とは、回転ペアも周波数も異なる点に注意が必要です。周波数0の回転ペアではcosが1、sinが0となり、元の値がそのまま残ります。
Barberoらは、Gemma 7Bの解析で低周波側の回転ペアがトークン同士の内容の照合に使われていると解釈し、その回転を取り除く方法を提案しています[19]。
- [23] Hugging Face, "modeling_rope_utils.py (Transformers v5.12.1)," GitHub, 2026.
- [19] Federico Barbero, Alex Vitvitskyi, Christos Perivolaropoulos, Razvan Pascanu, Petar Veličković, "Round and Round We Go! What makes Rotary Positional Encodings useful?," ICLR, 2025.
7. SwiGLUによるMLPと射影行列の分割
pre_mlp_normで正規化した入力を\(U \in \mathbb{R}^{B \times T \times 5120}\)とすると、計算は次の式で表せます。
gate_up_proj.weightの先頭25600行がgate、後半25600行がupに対応します。この境界で行列を分けて使っても、射影出力は数学的に同じです。gate側の出力\(G\)だけに\(\operatorname{SiLU}(g) = g\,\sigma(g)\)を適用し、up側の出力\(U_{\text{up}}\)と要素ごとに掛けます。\(\sigma(g) = 1/(1 + e^{-g})\)はシグモイド関数です。
8. Gemma 4 31Bとの共通点と相違点
| 役割 | PLaMo 3 | Gemma 4 |
|---|---|---|
| 1ブロック | Plamo3DecoderLayer | Gemma4TextDecoderLayer |
| Attention入力のRMSNorm | pre_mixer_norm | input_layernorm |
| Attention | mixer(qkv_projを分割) | self_attn(q_proj、k_proj。局所層はv_projも使用) |
| Attention出力のRMSNorm | post_mixer_norm | post_attention_layernorm |
| MLP入力のRMSNorm | pre_mlp_norm | pre_feedforward_layernorm |
| MLP | mlp.gate_up_projを分割、down_proj | mlp.gate_proj、up_proj、down_proj |
| MLP出力のRMSNorm | post_mlp_norm | post_feedforward_layernorm |
| 層ごとのスカラー | なし | layer_scalar(ブロック出力に乗算) |
| 最終RMSNorm | model.norm | model.norm |
| 項目 | PLaMo 3 31B | Gemma 4 31B |
|---|---|---|
| ブロック数 / 隠れ次元\(D\) | 64 / 5120 | 60 / 5376 |
| MLPの中間次元\(F\) / 活性化関数 | 25600(\(5D\))/ SiLU | 21504(\(4D\))/ tanh近似GELU |
| Queryヘッド数 / KVヘッド数 | 64 / 8 | 局所32 / 16、大域32 / 4 |
| ヘッド次元 | 128(全層) | 局所256、大域512 |
| Queryの総次元数 | 8192(\(> D\)) | 局所8192、大域16384(\(> D\)) |
| 大域層のValue | Kとは別に射影 | Kと射影出力を共有し、V用に正規化(attention_k_eq_v) |
| 語彙数 | 107,520 | 262,144 |
| 局所:大域の周期 | 7:1(大域8層、最後は大域) | 5:1(大域10層、最後は大域) |
| 局所窓 | 2048(自分を含む。4K版の旧実装は2049) | 1024(自分を含む) |
| 設定上の最大系列長 | 262,144(4K版は4096) | 262,144 |
| RoPEの基底(局所 / 大域) | \(10^4\) / \(10^6\) | \(10^4\) / \(10^6\) |
| 大域層のRoPEの拡張 | YaRN(係数256、振幅補正あり。4K版はなし) | p-RoPE(\(p = 0.25\)、256対中64対だけ回転) |
| Q/K正規化 | RMSNorm、ゲイン128次元、オフセット1 | RMSNorm、ゲインは局所256次元・大域512次元 |
| Vの正規化 | なし | ゲインなしのRMSNorm |
| Q/Kの内積に掛ける固定係数 | \(1/\sqrt{128}\) | 1(公開重みのゲインによる係数は§9.4) |
| RMSNormのゲインの求め方 | \(c + w\)(出力側の\(c\)は0.2と\(5^{-1.5}\)) | \(w\)そのもの(初期値1) |
| 入力埋め込みの\(\sqrt{D}\)倍 | なし(scale_embedding = false) | あり |
| 埋め込みと出力ヘッドの共有 | あり | あり |
| 出力logitsのsoftcap | なし | \(30 \tanh(\cdot / 30)\) |
| キャッシュに保存するK | 正規化後・RoPE前 | 正規化後・RoPE後 |
layer_scalarをブロック出力全体に掛けます。公開重みの値はすべて0より大きく1未満で、ブロック出力全体を縮小する倍率になっています。
Gemma4TextDecoderLayerは、残差加算を終えたブロック出力にlayer_scalarを掛けてから、次のブロックへ渡します。Transformersでは、1要素のバッファとして登録されており、学習パラメータには含まれません[7]。初期値は1ですが、公開重みには層ごとに異なる値が保存されています(§9.4)。
入力を正の定数倍する前後で二乗平均が\(\epsilon\)を十分に上回る場合、RMSNormの出力はほぼ変わりません。そのため、スカラーでブロック出力を縮めても、次のAttentionに渡す正規化済み入力はほぼ同じです。一方、残差経路の値は縮むので、新たに加えるAttention出力・MLP出力と、残差との大きさの比が変わります。加算後のベクトルの方向も変わりうるため、中間層のスカラーを変えたことによる値の違いは、最終RMSNormを通した出力にも残ることがあります。
- [7] Hugging Face, "modeling_gemma4.py (Transformers v5.12.1)," GitHub, 2026.
9. 学習済み重みの統計的な特徴
9.1. 比較対象と統計量
PLaMo 3 31Bの2604版は全642テンソル(31,757,456,384要素)、Gemma 4 31Bはテキスト部分の全832テンソル(30,697,345,340要素)が対象です。Gemma 4の要素数には、学習パラメータに加えて60個のlayer_scalarも含みます。
BF16は16ビットで値を表すため、ビット列は65,536通りです。重みをsafetensorsのバイト列から直接読み、テンソルごとに各ビット列の出現回数を数え、対応する数値を使って64ビット浮動小数点(FP64)で統計量を計算しています。標本抽出はしていません。
標準偏差は母標準偏差(ddof = 0)です。RMSは\(\sqrt{\operatorname{mean}(w^2)}\)で、平均を引かずに計算します。超過尖度は、平均から大きく離れた値の影響を強く受ける指標です。正規分布で0となる定義を使います。分位点は経験分布関数の逆関数で求め、BF16で表現できる値の間は補間しません。標本抽出による誤差はありませんが、FP64の計算には丸め誤差があります。
PLaMoのQKV射影は§4.1の境界でQ/K/Vに、gate/up射影は§7の境界でgateとupに分け、部分ごとに統計量を計算しました。これらは元のテンソルの一部なので、総パラメータ数には重複して足しません。実効ゲインは、重みとオフセットの和をFP64で計算した値です。BF16で加算したときの丸めは含みません。
両モデルの重みにNaNとInfはなく、PLaMoの重みにはちょうど0の値もありませんでした。
9.2. 出力側の正規化ゲインと残差の大きさ
post_mixer_normは、層0が0.116、層1が0.098で、初期値に相当するオフセット0.2を下回ります。層53で初めて0.2を超え、最終層は0.269です。
post_mlp_normでは、層7の平均ゲイン0.021が最小です。層23で初めてオフセットの約0.089を上回り、最終層は0.358です。一方、入力側の平均ゲインは、pre_mixer_normが0.977〜1.035、pre_mlp_normが0.905〜1.204の範囲にあります。出力側では入力側より層間の差が大きく、特に浅い層でオフセットを下回っています。
入力文は「これからの人工知能技術は、計算資源の制約の中でどこまで」です。PLaMoのトークナイザでは、文頭を表すBOSトークンを含めて12トークンになります。Gemmaでは同じ入力文が17トークンになり、図9で比べるのは各モデルの末尾トークンです。RMSは入力に依存するため、この1文の値を他の入力にも当てはめることはできません。
PLaMoでは、BOSトークンの残差のRMSが終盤の層で6.3に達し、他のトークンの6倍以上になっていました。ここで測ったのは活性値の大きさです。特定のトークンに参照の重みが集中するattention sinkを確認するには、Attentionの重みの分布も調べる必要があります。
層7(最初の大域層)でRMSが一時的に大きくなる傾向は、BOS以外のトークンにも共通です。4K版でも、層7で0.17まで増えました。残差と出力側のゲインがともに大きくなる理由を特定するには、複数の入力や学習過程の調査が必要です。
layer_scalarの乗算もこの推移に関わります。出力側のRMSNormの配置は共通でも、残差ストリームの大きさは両モデルで異なる推移を示しました。
9.3. Q/Kゲインの成分ごとの違い
q_normとk_normの実効ゲイン\(1 + w\)は、高周波側の回転ペアに属する一部の成分で小さくなっていました。成分番号を\(i\)とすると、対応する回転ペア番号は\(j = i \bmod 64\)です。\(|\gamma| < 0.05\)の成分はすべて層31以降にあり、\(j \le 16\)の回転ペアに属します。
回転ペアごとに平均したゲインは、高周波側の\(j = 0\)付近では約0.6、低周波側の\(j \ge 48\)では約1.4で、その間もほぼ単調に増えます。低周波側ではほぼ一様ですが、高周波側では層や成分による差が大きくなっています。
QでもKでも、同じ回転ペア\((j, j + 64)\)の2成分がともに閾値未満になる例は、64層×64対のいずれにもありませんでした。片側が小さいとき、もう一方のゲインは多くの場合1を超えています。RoPEは2成分の値を混ぜて回転させるため、片側のゲインが小さいだけで、その回転ペアがAttentionスコアに位置差を反映しなくなったとは言えません。
高周波側の回転ペアでゲインが成分間で大きく異なる傾向は、4K版と610M Fin Instructにも見られました。この傾向が長文処理や日本語の性能にどう影響するかは、重みの測定だけでは分かりません。
Qの該当282成分を回転ペア番号ごとに数えると、\(j = 0\)から13までは順に18、25、17、26、23、20、30、21、18、22、16、19、16、9成分でした。\(j = 14\)と16に1成分ずつあり、それ以外は0成分です。Kは\(j \le 13\)に245成分、\(j = 16\)に1成分あります。
ゲインの最小値はQ・Kともに0.0039で、負の値はありませんでした。最大値はQが2.55、Kが2.26です。
4K版で同じ閾値に該当するのは、Qが273成分、Kが166成分で、いずれも\(j \le 16\)にあります。16層の610M Fin Instructでは、Qの153成分が\(j \le 14\)、Kの101成分が\(j \le 18\)に分布します。両モデルとも、同じ回転ペアの2成分がそろって閾値未満になる例はありませんでした。
ゲインの成分ごとの差が参照先への重みをどう変えるかは、チェックポイントだけでは分かりません。実際の入力に対するQ/Kの活性値を調べ、ゲインを変更したときのAttentionスコアや、遠いトークンに割り当てる重みを比較する必要があります。
9.4. Gemma 4のゲインと射影行列の大きさ
layer_scalarの各層の値は、最初の2層が0.097と0.070、最後の層が0.040と小さく、中間の層は0.46〜0.99の範囲にあります。最初の2層のスカラーの積は約1/150です。残差経路を通る入力埋め込みの項には、この倍率が掛かります。各層では係数を掛ける前にAttention出力とMLP出力が加わるため、ブロック出力全体が1/150になるわけではありません。図9では、層1の出力のRMSは埋め込みの約半分です。
| 層番号 | layer_scalarの値 |
|---|---|
| 0〜9 | 0.097、0.070、0.992、0.969、0.984、0.879、0.914、0.852、0.859、0.867 |
| 10〜19 | 0.914、0.812、0.719、0.973、0.977、0.840、0.977、0.844、0.969、0.906 |
| 20〜29 | 0.902、0.957、0.910、0.695、0.836、0.793、0.664、0.641、0.457、0.562 |
| 30〜39 | 0.695、0.758、0.766、0.785、0.758、0.668、0.789、0.809、0.797、0.684 |
| 40〜49 | 0.590、0.645、0.766、0.809、0.848、0.871、0.895、0.879、0.875、0.832 |
| 50〜59 | 0.867、0.871、0.703、0.828、0.906、0.871、0.844、0.809、0.727、0.040 |
全60層の積は約\(1.5 \times 10^{-9}\)ですが、各層でAttention出力とMLP出力が加わるため、この積だけで最終出力の大きさや方向は説明できません。中間層のスカラーは、残差と新たに加える出力の比率を変えます(§8)。
最終層で0.040を掛けた出力は、別の出力を加えることなく最終RMSNormへ渡されます。今回の入力文の末尾トークンでは、最終RMSNorm前のRMSは約0.7でした。二乗平均に対する\(\epsilon = 10^{-6}\)の比は約\(2 \times 10^{-6}\)と十分小さいため、出力を縮小した倍率は最終RMSNormでほぼ相殺されます。
layer_scalar
最初の局所2層と最後の大域層だけが0.1未満で、ブロック出力を0.1倍未満に縮めます。大域層をオレンジ色で示しています。
| RMSNormの実装名 | 平均ゲインの範囲(層間) | 全層・全成分の最小 / 最大 |
|---|---|---|
input_layernorm | 4.9〜47.6 | −54 / 1248 |
post_attention_layernorm | 0.018〜1.68 | 0.00003 / 20 |
pre_feedforward_layernorm | 2.2〜218 | −100 / 860 |
post_feedforward_layernorm | 0.032〜1.9 | 0.0002 / 50 |
norm(最終) | 11.4 | −2.6 / 510 |
q_projとk_projの標準偏差の相対差は\(10^{-4}\)未満で、gate_projとup_projも同様です。埋め込みの標準偏差は0.01364で、\(\sqrt{5376}\)倍すると約0.9998になります。
RMSNormの直後に線形層がある場合は、ゲインと行列の重みの間で倍率を移しても、数学的には同じ出力を得られます。線形層の行列を\(W\)、ゲインを掛ける前の正規化済み入力を\(\hat{x}\)とすると、列ベクトルの記法では\(W\operatorname{diag}(\gamma)\hat{x}\)と書けます。\(W\)の列を0でない係数で割り、対応する\(\gamma\)の成分に同じ係数を掛けても、射影後の値は変わりません。同じRMSNormから複数の射影へ分岐する場合は、すべての射影を同じ対応で変換します。Gemma 4の標準偏差が揃うことは、このような再パラメータ化と整合します。ただし、出力射影を含むすべての行列に、この変換が使われたとは断定できません。
PLaMo 3では、Q/K射影の後にQ/KのRMSNorm、出力射影とdown射影の後に出力側のRMSNormがあります。これらの行列全体を正の定数倍すると、射影出力も同じ倍率で変わります。定数倍の前後で二乗平均が\(\epsilon\)を十分に上回るなら、RMSNormで割る分母もほぼ同じ倍率で変わり、正規化後の値はほぼ元と同じです。ただし、層7のMLP出力のように二乗平均が\(\epsilon\)より小さい場合は例外です(§9.5)。重みの絶対的な大きさだけでは、初期化方式や残差に加える出力の大きさを求めにくい点は、両モデルに共通します。
PLaMo 3のo_projでは、層ごとの超過尖度の中央値は115、最大は層16の3506です。平均からの距離が標準偏差の5倍を超える要素は0.040%あります。正規分布なら約0.00006%です。down_projも層6では超過尖度4270ですが、層8以降のgate/upは0.1〜0.6です。
Gemma 4の射影行列の超過尖度は、種類ごとに層間の中央値を取ると約0.34〜3.01に収まります。ただし、個別にはv_projの9.38のような例もあり、埋め込みの超過尖度は111です。超過尖度だけで分布全体の形を説明したり、性能の優劣を判断したりすることはできません。
9.5. 浅い層のMLPの重みと正規化後の出力
o_projの標準偏差は、層0〜7で0.004〜0.005でした。
| 層 | gate / up / downの重みの標準偏差 | o_projの重みの標準偏差 | SiLU入力のRMS | MLP出力のRMS(正規化前) | MLP出力のRMS(正規化後) | Attention出力のRMS(正規化前) | Attention出力のRMS(正規化後) |
|---|---|---|---|---|---|---|---|
| 0 | 0.0037 / 0.0037 / 0.0041 | 0.0048 | 0.255 | 0.5847 | 0.022 | 2.3 | 0.135 |
| 1 | 0.0046 / 0.0045 / 0.0048 | 0.0039 | 0.777 | 6.444 | 0.048 | 17.3 | 0.134 |
| 2 | 0.0010 / 0.0010 / 0.0011 | 0.0042 | 0.521 | 33.11 | 0.043 | 60.4 | 0.102 |
| 3 | 0.0006 / 0.0006 / 0.0006 | 0.0039 | 0.770 | 108.6 | 0.042 | 47.8 | 0.103 |
| 4 | 0.0006 / 0.0006 / 0.0006 | 0.0045 | 0.352 | 11.89 | 0.037 | 23.3 | 0.125 |
| 5 | 0.0036 / 0.0035 / 0.0036 | 0.0046 | 0.145 | 0.645 | 0.067 | 8.76 | 0.125 |
| 6 | 0.0006 / 0.0006 / 0.0006 | 0.0051 | 0.060 | 0.6542 | 0.072 | 4.82 | 0.200 |
| 7 | 0.0031 / 0.0031 / 0.0034 | 0.0045 | 0.013 | 0.00021 | 0.047 | 2.47 | 0.448 |
| 8 | 0.0057 / 0.0057 / 0.0057 | 0.0059 | 0.037 | 0.0054 | 0.378 | 0.253 | 0.376 |
10. 参照実装と公開実装の照合
wにはFP32へ変換した重みの辞書、idsには形状\([1, T]\)のトークンID列を渡します。
import math
import torch
import torch.nn.functional as F
EPS, DH = 1e-6, 128
OFF = dict(
pre_mixer=1.0, post_mixer=1 / 5,
pre_mlp=1.0, post_mlp=5 ** -1.5,
q=1.0, k=1.0, final=1.0,
)
def rms_norm(x, weight, offset): # (c + w) ⊙ x / sqrt(mean(x^2) + ε)
y = x.float() * torch.rsqrt(x.float().pow(2).mean(-1, keepdim=True) + EPS)
return (offset + weight) * y.to(x.dtype)
def rope(x, theta, yarn): # split-half形式で回転。大域層にはYaRNを適用
T = x.shape[-2]
freq = theta ** (torch.arange(0, DH, 2).float() / DH)
inv, conc = 1.0 / freq, 1.0
if yarn: # L0 = 4096, s = 256, β_fast = 32, β_slow = 1
low = 64 * math.log(4096 / (32 * 2 * math.pi)) / math.log(theta)
high = 64 * math.log(4096 / (1 * 2 * math.pi)) / math.log(theta)
mask = 1 - ((torch.arange(64).float() - low) / (high - low)).clamp(0, 1)
inv = (1.0 / (256 * freq)) * (1 - mask) + (1.0 / freq) * mask
conc = 0.1 * math.log(256) + 1.0 # 振幅補正。cosとsinの両方に掛ける
ang = torch.arange(T).float()[:, None] * inv[None]
cos, sin = (
torch.cat([ang, ang], -1).cos() * conc,
torch.cat([ang, ang], -1).sin() * conc,
)
x1, x2 = x[..., :DH // 2], x[..., DH // 2:]
return x * cos + torch.cat([-x2, x1], -1) * sin
def block(x, w, i):
p = f"model.layers.layers.{i}."
is_global = (i + 1) % 8 == 0
T = x.shape[1]
u = rms_norm(x, w[p + "pre_mixer_norm.weight"], OFF["pre_mixer"])
q, k, v = torch.split(
u @ w[p + "mixer.qkv_proj.weight"].T,
[64 * 128, 8 * 128, 8 * 128], -1,
)
q = q.view(1, T, 64, 128).transpose(1, 2) # [B, 64, T, 128]
k = k.view(1, T, 8, 128).transpose(1, 2) # [B, 8, T, 128]
v = v.view(1, T, 8, 128).transpose(1, 2)
q = rms_norm(q, w[p + "mixer.q_norm.weight"], OFF["q"])
k = rms_norm(k, w[p + "mixer.k_norm.weight"], OFF["k"])
theta = 1000000 if is_global else 10000
q, k = rope(q, theta, is_global), rope(k, theta, is_global)
# GQA:連続する8個のQueryヘッドが同じ1組のK/Vヘッドを参照
k = k.repeat_interleave(8, 1)
v = v.repeat_interleave(8, 1)
s = (q @ k.transpose(-1, -2)) / math.sqrt(128)
i_, j_ = torch.arange(T)[:, None], torch.arange(T)[None, :]
allowed = j_ <= i_
if not is_global:
allowed &= (i_ - j_) <= 2047 # 局所層:自分自身と直前の2047トークン
s = s.masked_fill(~allowed, float("-inf"))
a = (torch.softmax(s, -1) @ v).transpose(1, 2).reshape(1, T, 64 * 128)
x = x + rms_norm(
a @ w[p + "mixer.o_proj.weight"].T,
w[p + "post_mixer_norm.weight"], OFF["post_mixer"],
)
u = rms_norm(x, w[p + "pre_mlp_norm.weight"], OFF["pre_mlp"])
g, up = (u @ w[p + "mlp.gate_up_proj.weight"].T).chunk(2, -1)
m = (F.silu(g) * up) @ w[p + "mlp.down_proj.weight"].T
return x + rms_norm(m, w[p + "post_mlp_norm.weight"], OFF["post_mlp"])
def forward(ids, w):
x = w["model.embed_tokens.weight"][ids] # 埋め込みを√D倍しない
for i in range(64):
x = block(x, w, i)
x = rms_norm(x, w["model.norm.weight"], OFF["final"])
return x @ w["model.embed_tokens.weight"].T # 出力ヘッドは埋め込みと共有
| 検証 | 条件 | 最大絶対誤差 |
|---|---|---|
| 公開重み・全64層:参照実装と公開実装 | 2604版、FP32、\(T = 12\)、キャッシュなし | \(9.5 \times 10^{-6}\)(平均絶対誤差\(1.2 \times 10^{-6}\)) |
| 公開実装:BF16とFP32 | 2604版、\(T = 12\)、キャッシュなし | 0.165(平均絶対誤差0.019)。最大スコアのトークンは一致 |
| 公開重み:一括処理と1トークンずつのdecode | 2604版、FP32、系列長12 | \(1.0 \times 10^{-5}\) |
| 小型モデル:一括処理と1トークンずつのdecode | 8層、\(D = 48\)、ヘッド次元16、\(W = 4\)、系列長12、FP32 | \(2.7 \times 10^{-7}\)(4K版の旧実装では\(3.3 \times 10^{-7}\)) |
| 小型モデル:一括処理と3・6・3トークンに分けたprefill | 同上 | \(2.1 \times 10^{-7}\)(旧実装では\(2.8 \times 10^{-7}\)) |
| 小型モデル:学習モードでのマスク省略と評価モード | 上記の小型モデルで\(T = 4, 5, 6\) | \(T = 5\)のみ0.15(旧実装では0) |
公開重みの照合には、PyTorch 2.12.1(CPU)とTransformers 5.12.1を使いました。モデルカードはPyTorch 2.9.0以下を指定していますが、この検証では2.12.1で実行しています。両実装ともFP32で重みを読み込むため、重みだけでそれぞれ約127 GBが必要です。CPUは96スレッドで実行しました。小型モデルは、公開実装のクラスにランダム重みを与えたものです。4K版の旧実装の検証にはTransformers 4.57.1を使っています。
- 保存されたキー名
model.layers.layers.{i}.からの重みの対応付けと、1つにまとめた射影行列の分割位置(§2.2・§4.1・§7) - 設定ファイルのヘッド次元128と、RMSNormの適用箇所ごとのオフセット(§2.1・§3.2)
- Q/K正規化とRoPEの適用順序、split-halfの回転ペア、大域層のYaRNと振幅補正(§6.1・§6.3)
- キャッシュに保存するKがRoPE適用前の値であることと、Q/Kへの位置番号の割り当て(§4.4)
- 0始まりの層番号に対応する局所/大域層の配置と、窓幅に含めるトークン数(§5.1)
- 入力埋め込みと出力ヘッドの重みの共有(§2.2)
- BF16での型変換、オフセット加算、乗算の順序(§3.2・§6.3)
11. まとめ
参考文献
- [1] Preferred Networks, Inc., "PLaMo 3 NICT 2604 31B Base (model card, config.json, modeling_plamo.py; revision e26c257e)," Hugging Face, 2026. (本記事の主対象。版を固定した設定ファイル、公開実装、重み)
- [2] Preferred Networks, Inc., "PLaMo 3 NICT 2B Base (model card and config.json)," Hugging Face, 2026. (モデルサイズの比較)
- [3] Preferred Networks, Inc., "PLaMo 3 NICT 8B Base (model card and config.json)," Hugging Face, 2026. (モデルサイズの比較)
- [4] Preferred Networks, Inc., "PLaMo 3 610M Fin Instruct (model card and config.json)," Hugging Face, 2026. (金融向け派生モデルの構成とパラメータ数)
- [5] Preferred Networks, Inc., "PLaMo 3 NICT 31B Base (model card, config.json, modeling_plamo.py; revision 9c1fa626)," Hugging Face, 2026. (層数や次元数が同じ4K版。比較用の重みと、窓の数え方が異なる旧実装)
- [6] Google DeepMind, "Gemma 4 31B (model card and config.json)," Hugging Face, 2026. (比較対象。設定ファイルと重み)
- [7] Hugging Face, "modeling_gemma4.py (Transformers v5.12.1)," GitHub, 2026. (Gemma 4の正規化・RoPE・KVキャッシュの公開実装)
- [8] Shuji Suzuki, "大規模言語モデルの次期バージョン PLaMo 3 シリーズにおける8B, 31Bの小規模モデルによる事前学習の検証," Preferred Networks Tech Blog, 2025. (PLaMo 3のアーキテクチャ変更の背景、KVキャッシュの比較表)
- [9] Iz Beltagy, Matthew E. Peters, Arman Cohan, "Longformer: The Long-Document Transformer," arXiv:2004.05150, 2020. (Sliding Window Attentionを含むLongformer)
- [10] Preferred Networks, Kaizaburo Chubachi, others, "PLaMo 2 Technical Report," arXiv:2509.04897, 2025. (前世代PLaMo 2の技術報告)
- [11] Liliang Ren, Yang Liu, Yadong Lu, Yelong Shen, Chen Liang, Weizhu Chen, "Samba: Simple Hybrid State Space Models for Efficient Unlimited Context Language Modeling," ICLR, 2025. (PLaMo 2が採用していたMambaとSWAの混合構成)
- [12] Gemma Team, "Gemma 3 Technical Report," arXiv:2503.19786, 2025. (局所/大域Attentionの併用とQ/K正規化を持つGemma 3)
- [13] Gemma Team, "Gemma 4 Technical Report," arXiv:2607.02770, 2026. (Gemma 4の5:1の層比率、大域層でのKの再利用、p-RoPE)
- [14] Biao Zhang, Rico Sennrich, "Root Mean Square Layer Normalization," NeurIPS, 2019. (RMSNormの原典)
- [15] vLLM Project, "vllm/model_executor/models/plamo3.py (commit d881812)," GitHub, 2026. (RMSNormのオフセットを重みへ足し込む推論実装)
- [16] Joshua Ainslie, James Lee-Thorp, Michiel de Jong, Yury Zemlyanskiy, Federico Lebrón, Sumit Sanghai, "GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints," EMNLP, 2023. (Grouped-Query Attention)
- [17] Jianlin Su, Murtadha Ahmed, Yu Lu, Shengfeng Pan, Wen Bo, Yunfeng Liu, "RoFormer: Enhanced Transformer with Rotary Position Embedding," Neurocomputing 568, 2024. (RoPEの原典)
- [18] Bowen Peng, Jeffrey Quesnelle, Honglu Fan, Enrico Shippole, "YaRN: Efficient Context Window Extension of Large Language Models," ICLR, 2024. (YaRN)
- [19] Federico Barbero, Alex Vitvitskyi, Christos Perivolaropoulos, Razvan Pascanu, Petar Veličković, "Round and Round We Go! What makes Rotary Positional Encodings useful?," ICLR, 2025. (p-RoPE。低周波側の回転ペアから回転を取り除く提案)
- [20] Noam Shazeer, "GLU Variants Improve Transformer," arXiv:2002.05202, 2020. (SwiGLUを含むGLU系MLP)