A Deep Dive into the PLaMo 3 Architecture

Published on October 26, 2026

A Deep Dive into the PLaMo 3 Architecture

PLaMo 3 31B's 64 layers repeat a cycle of seven local attention layers and one global attention layer. A local layer attends to the current token and up to 2047 preceding tokens; every eighth layer can attend to the full history. This keeps most attention operations close to the current token while preserving regular access to distant tokens. Lower compute and storage costs follow when the backend computes within the window and discards old local keys and values.
PLaMo 3 is a family of large language models developed jointly by Preferred Networks (PFN) and Japan's National Institute of Information and Communications Technology (NICT)[8]. I asked Codex to analyze the public implementation and trained weights of PLaMo 3 NICT 2604 31B Base[1]. The architecture description, weight statistics, and numerical checks in this article are based on that analysis.

The analysis uses PLaMo 3 NICT 2604 31B Base (the 2604 release), pinned to revision e26c257e2175b05db69f01b52f4edf6fa4118f53 of pfnet/plamo-3-nict-2604-31b-base on Hugging Face. Its public implementation, modeling_plamo.py, targets Transformers 5. The repository also ships sitecustomize.py for vLLM.

PLaMo 3 NICT 31B Base[5], used for comparison, is the 4K release with a maximum sequence length of 4096; its revision is 9c1fa626. Its tokenizer definition files and code are byte-for-byte identical to those of the 2604 release.

The Gemma 4 comparison target is the pretrained google/gemma-4-31B at revision 5bbc2fb1c1b2c611d06e3d9f23c170ba21659d89. For its implementation I refer to modeling_gemma4.py in Transformers 5.12.1[7]. The execution environment and measurement conditions are given in §7.

  1. [5] Preferred Networks, Inc., "PLaMo 3 NICT 31B Base (model card, config.json, modeling_plamo.py; revision 9c1fa626)," Hugging Face, 2026.
  2. [7] Hugging Face, "modeling_gemma4.py (Transformers v5.12.1)," GitHub, 2026.
The 2604 release was trained by distillation from a 120B model's outputs and has a configured context limit of 262,144 tokens. The earlier PLaMo 3 NICT 31B Base, referred to here as the 4K release, has the same layer count and dimensions but a 4096-token limit. Its positional encoding and trained weights differ, so the two releases need to be distinguished when interpreting the code or checkpoint.
The first part follows the forward pass from token IDs to logits, the scores for candidate next tokens, and gives the formulas and constants needed to reproduce it. Three details matter when implementing the model: head dimensions are configured independently of the hidden dimension, normalization gains include offsets added to the stored weights, and keys enter the cache before positional rotation. A short-input check in 32-bit floating point (FP32) reproduced the public model's logits to within \(10^{-5}\) (§7).
Gemma 4 31B[6] provides a comparison with the same broad local/global design. Its different head sizes, normalization, and positional encoding expose choices that affect computation and cache storage. The later weight analysis examines a related issue: how normalization can turn projection outputs of very different magnitudes into similarly sized additions to the residual stream. The focus throughout is the model computation; tokenizer internals are outside the scope.

1. Long-context processing with local and global attention

As a decoder-only Transformer, PLaMo 3 predicts the next token from the sequence so far. Attention gathers information by matching a token's query against other tokens' keys, then combining their value vectors with the resulting weights. Sliding window attention (SWA)[9] restricts the accessible keys and values to a recent window; global attention can use all positions up to the current one.
PFN attributes the move to this design to difficulties improving long-sequence performance and limited inference-engine and application support for PLaMo 2[8]. That earlier model[10] combined Mamba with SWA in a Samba-style architecture[11]; PLaMo 3 combines global attention with SWA, as Gemma 3 does[12].
Inference starts with prefill, which processes the input sequence, followed by decode steps that generate one token at a time. A KV cache stores earlier tokens' keys and values. Each decode step reuses them and computes new K/V vectors only for the current token.
In a global layer, prefill attention work grows quadratically with sequence length, and the cache grows linearly. A local layer needs only roughly linear prefill attention work if its kernel computes within a fixed window. During decode, its attended range stops growing at 2048 tokens, and its stored cache can remain bounded by discarding older entries. These savings concern different resources: skipping out-of-window computation saves operations, while discarding out-of-window keys and values saves storage. Section 8 quantifies both and examines the public implementation's memory requirements.
A local window limits direct access, but its token vectors may already contain information gathered from older tokens in earlier layers. Global layers provide direct access to the full history, while local layers can carry older information forward indirectly.
PLaMo 3's 64-layer stack therefore contains 56 local layers and 8 global layers. Gemma 4 31B uses 50 local and 10 global layers in a 5:1 cycle[13]. Layer counts are only part of the cache calculation: each model also chooses how many key/value vectors to store, their dimensions, and the local window width (§8.1).
Comparison of the overall structure of PLaMo 3 and Gemma 4, traced from token IDs down to logits. The hidden dimension D and layer count L are variables. PLaMo 3 repeats an 8-layer cycle of 7 local and 1 global layers with a window of 2048; Gemma 4 repeats a 6-layer cycle of 5 local and 1 global layers with a window of 1024. The vocabularies are 107520 and 262144. Both share the input embedding with the output head, but only Gemma 4 scales the embedding by √D and applies a softcap to the logits.
Figure 1: Overall structure of PLaMo 3 and Gemma 4 Read each model from token IDs at the top to logits at the bottom. Blue blocks use local attention and orange blocks use global attention; each cycle repeats through the stack. \(B\) is the batch size, \(T\) the number of tokens processed in the current call, \(D\) the hidden dimension, and \(L\) the layer count.

2. Model configuration and stored weights

2.1. Key configuration values

Tensor shapes distinguish the tokens processed now from those available to attention. Let \(B\) be the batch size and \(T\) the number of tokens per sequence in the current call. Queries cover those \(T\) tokens; keys and values cover \(S\) tokens, including cached tokens returned by the update. With an empty cache, prefill has \(S = T\); token-by-token decode has \(T = 1\). Once a local cache starts discarding old entries, its \(S\) during decode differs from that of a global layer.
Each block combines attention with a multilayer perceptron (MLP), which transforms each token independently. Attention divides its computation among heads, each of which computes its own weights and weighted sum. The configuration[1] specifies the dimension of each head separately from the hidden dimension of the vectors passed between blocks.
SettingValueSymbol and role
vocab_size107520Vocabulary size \(V\); equals the number of embedding rows
hidden_size5120Dimension \(D\) of the residual stream, the vector passed between layers; also called the hidden dimension
num_hidden_layers64Number of decoder blocks \(L\)
intermediate_size25600MLP intermediate dimension \(F\) (\(5D\)); output size of each of the gate and up projections (§6)
num_attention_heads64Number of query heads \(H_q\)
num_key_value_heads8Number of key/value heads \(H_{kv}\)
head_dim128Dimension \(d\) of one head; shared by Q, K, and V
rms_norm_eps\(10^{-6}\)\(\epsilon\) added to the mean square in RMSNorm
window_size2048Local attention window size \(W\)
sliding_window_pattern8Global attention every 8 layers
rope_local_theta10000RoPE base for local layers
rope_theta1000000RoPE base for global layers
initial_context_length4096Original context length \(L_0\) for YaRN (§5.3)
rope_scaling_factor256YaRN factor \(s\) for global layers (§5.3)
max_position_embeddings262144Maximum sequence length recorded in the config
scale_embeddingfalseEmbeddings are not scaled by \(\sqrt{D}\) (§2.3)
linear_typefp8Not referenced by the public implementation; weights use 16-bit floating point (BF16)
All 642 stored tensors use BF16, a 16-bit floating-point format, and the projections use ordinary nn.Linear. The code defines a LinearType enum with normal, fp8, and mxfp8, but neither model construction nor the forward pass branches on it. Although linear_type is normal for 8B Base and fp8 for both 31B releases, those values do not select a different storage format or projection computation in the public implementation.
The total query dimension \(H_q d = 8192\) exceeds the hidden dimension \(D = 5120\). A reimplementation that derives the head dimension as \(D / H_q\) would get 80, which does not match the stored weight shapes. Use 128, as head_dim specifies.

2.2. Weight names, shapes, and parameter counts

Each block's checkpoint keys begin with model.layers.layers.{i}., where i is the zero-based layer index. The repeated layers reflects two levels of the module hierarchy. Within a block, mixer identifies attention and mlp identifies the MLP.
The top-level class Plamo3ForCausalLM holds a Plamo3Model in its model attribute. The embedding key is model.embed_tokens.weight and the final RMSNorm is model.norm.weight. The sequence of blocks is managed by a Plamo3Decoder at Plamo3Model.layers, which in turn holds a ModuleList in its own layers attribute. These two levels produce the layers.layers in the key names.
Each block stores ten tensors: four projection matrices, two Q/K normalization vectors, and four normalization vectors around attention and the MLP. The projections have no biases.
The table omits the common prefix model.layers.layers.{i}. from the key names. PyTorch linear-layer weights have shape \([\text{out}, \text{in}]\), with rows for outputs and columns for inputs. RMSNorm stores the difference between the effective gain and the offset (§3.2).
Key nameShape
mixer.qkv_proj.weight\(10240 \times 5120\)
mixer.o_proj.weight\(5120 \times 8192\)
mixer.q_norm.weight, mixer.k_norm.weight128 each
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.weight5120 each
The embedding matrix serves both as the lookup table for input token IDs and as the output head that scores candidate next tokens. This sharing means there is no separate lm_head.weight in the checkpoint.
The total parameter count, covering the embedding, the 64 blocks, and the final RMSNorm, is about 31.76 billion.

Per block, the QKV projection has 52,428,800 parameters, the output projection 41,943,040, the gate/up projection 262,144,000, the down projection 131,072,000, and RMSNorm \(4 \times 5120 + 2 \times 128 = 20{,}736\). The block total is 487,608,576, and the whole model has \(550{,}502{,}400 + 64 \times 487{,}608{,}576 + 5{,}120 = 31{,}757{,}456{,}384\).

The config file does not set tie_word_embeddings, so the public implementation uses the default True. The element count of all stored tensors is the same number, and there are \(64 \times 10 + 2 = 642\) tensors. RoPE frequencies are not learned parameters; they are created as buffers at run time. The public implementation pads the output head's row count up to a multiple of 16 at or above the vocabulary size, but 107,520 is already divisible by 16, so no rows are added.

2.3. From input to logits

The model first looks up the vector for each token ID in the embedding matrix and then updates it through the 64 blocks in sequence. With input IDs \(I \in \{0, \dots, V-1\}^{B \times T}\) and embedding matrix \(E \in \mathbb{R}^{V \times D}\), the computation is
\[ \begin{eqnarray} X_0 &=& E[I], \\ X_{\ell+1} &=& \operatorname{Block}_\ell(X_\ell) \quad (\ell = 0, \dots, 63) \end{eqnarray} \]
After the last block, \(X_{64}\) passes through an RMSNorm with offset 1 (§3.2). Multiplication by the transpose of the input embedding matrix gives \(\operatorname{logits} = \operatorname{RMSNorm}(X_{64})\, E^\mathsf{T}\), with shape \([B, T, V]\): one score per vocabulary token at each input position.
PLaMo 3 uses the embedding vectors without multiplying by \(\sqrt{D}\) and returns logits without applying a softcap to bound their range. Conversion to probabilities and selection of the next token belong to the generation code.

3. Block structure and RMSNorm with offsets

3.1. Block equations with residual connections

Each block adds two contributions to the residual stream: an attention output, followed by an MLP output. Both sublayers have RMSNorm on their inputs and outputs, so each residual addition uses a normalized contribution.
Let \(N_{\mathrm{pre\_attn}}\) and \(N_{\mathrm{post\_attn}}\) denote the normalizations before and after attention, and define the MLP normalizations similarly. A block maps input \(X\) to output \(Y\) in two stages:
\[ \begin{eqnarray} A &=& X + N_{\mathrm{post\_attn}}\bigl(\operatorname{Attention}(N_{\mathrm{pre\_attn}}(X))\bigr), \\ Y &=& A + N_{\mathrm{post\_mlp}}\bigl(\operatorname{MLP}(N_{\mathrm{pre\_mlp}}(A))\bigr) \end{eqnarray} \]
The attention path is pre_mixer_norm → mixer → post_mixer_norm. Adding its output to \(X\) gives \(A\), which feeds pre_mlp_norm → mlp → post_mlp_norm. Each contribution has shape \([B, T, 5120]\), matching the residual.
Comparison of the decoder blocks of PLaMo 3 and Gemma 4. Attention and the MLP are processed top to bottom, each wrapped in RMSNorm before and after, and the normalized output is added to the residual. PLaMo 3 obtains its gain by adding an offset to the stored weight; Gemma 4 uses the stored weight directly. PLaMo 3's head dimension is 128, while Gemma 4 uses separate variables for local and global layers. The MLP activation is SiLU in PLaMo 3 and tanh-approximated GELU in Gemma 4. Only Gemma 4 multiplies a per-layer scalar after the final residual addition.
Figure 2: Decoder block and residual path comparison Both models normalize each sublayer's input and its contribution to the residual. PLaMo 3 forms the normalization gain by adding an offset to the stored weight \(w\); Gemma 4 uses \(w\) directly and scales the whole block output by \(s_\ell\). \(F\) is the MLP intermediate dimension; \(H_q\) and \(H_{kv}\) are the query and KV head counts. Gemma 4's head dimension and KV head count differ between local and global layers.

3.2. Effective gains and normalization offsets

RMSNorm[14] divides a vector by a denominator based on its root mean square (RMS), reducing the influence of its overall magnitude. A learned gain then scales each component. PLaMo 3 computes this normalization for an \(n\)-dimensional vector \(x\) as
\[ \boxed{\;N^{(c)}_w(x) = (c + w) \odot \frac{x}{\sqrt{\frac{1}{n}\sum_{r=1}^{n} x_r^2 + \epsilon}}\;} \]
Here, \(\odot\) denotes elementwise multiplication and \(\epsilon = 10^{-6}\) keeps the denominator nonzero. RMSNorm does not subtract the input mean. The checkpoint stores \(w\), while the code supplies a fixed offset \(c\), so the effective gain is \(\gamma = c + w\). The offset depends on where normalization is applied.
SiteImplementation nameOffset \(c\)Normalized dimension \(n\)
Attention inputpre_mixer_norm15120
Attention outputpost_mixer_norm\(1/5 = 0.2\)5120
MLP inputpre_mlp_norm15120
MLP outputpost_mlp_norm\(5^{-1.5} \approx 0.0894\)5120
Querymixer.q_norm1128 per head
Keymixer.k_norm1128 per head
Final outputmodel.norm15120
The weight \(w\) is initialized to 0, so the initial effective gain equals \(c\): 0.2 at the attention output and about 0.089 at the MLP output. Training learns the difference \(w\) between the effective gain and this fixed offset.

The distinction affects weight decay, as the Plamo3RMSNorm docstring notes. A code comment also reports that setting every offset to 1 degraded performance, without giving the evaluation conditions, the size of the drop, or the reason for choosing 0.2 and \(5^{-1.5}\).

Weight decay pulls learned weights toward 0. If it is applied to \(w\) separately from the gradient update, as in AdamW, the offset changes the point toward which the gain decays. With learning rate \(\eta\) and decay coefficient \(\lambda\), the decay step gives \(w' = (1 - \eta\lambda)w\). The effective gain then becomes \(\gamma' = (1 - \eta\lambda)\gamma + \eta\lambda c\), moving toward \(c\). Applying the same decay directly to \(\gamma\) would move it toward 0. Folding the offset into the stored weight therefore preserves the inference formula but changes the effect of weight decay if training resumes.

To substitute a standard RMSNorm kernel, pass \(\gamma\), the weight with the offset added, as the gain. Both vLLM's PLaMo 3 implementation[15] and the sitecustomize.py for vLLM shipped with the model add the offset when loading the weights. In BF16, the order of addition and dtype conversions also affects rounding.
The public implementation's _plamo3_rms_norm computes the mean square and division in 32-bit floating point (FP32), casts the normalized vector back to the input dtype, then multiplies by (offset + weight). Gemma 4 keeps the normalized vector in FP32 through the gain multiplication and casts afterward. Folding the offset into the weight introduces another rounding choice: the dtype used for the addition. To match the public implementation bit for bit in BF16, a replacement must preserve these dtypes and the order of addition, conversion, and multiplication.

4. Attention computation and tensor shapes

4.1. Split points of the QKV projection

The attention path starts with a linear projection of the normalized input into queries (Q), keys (K), and values (V). The public implementation stacks the three projection matrices into one, so a single multiplication produces all three outputs.
For the normalized input \(U \in \mathbb{R}^{B \times T \times 5120}\) from pre_mixer_norm, the combined projection is \([Q_{\text{flat}}, K_{\text{flat}}, V_{\text{flat}}] = U W_{\text{qkv}}^\mathsf{T}\). Its output dimension is \(64 \times 128 + 8 \times 128 + 8 \times 128 = 10240\).
Split the last axis into Q, K, and V, in that order, over the half-open ranges \([0{:}8192]\), \([8192{:}9216]\), and \([9216{:}10240]\). To use separate projection matrices, split the rows of qkv_proj.weight at the same boundaries. The checkpoint groups rows by projection, not by head.
Each split tensor is reshaped to \([B, T, H, d]\), where \(H\) is that projection's head count, and the head and token axes are swapped. After the transpose, Q has shape \([B, 64, T, 128]\) and K and V have \([B, 8, T, 128]\).

4.2. Shared keys and values in GQA

Grouped-query attention[16] (GQA) lets multiple query heads share keys and values. In PLaMo 3 31B, each group of 8 consecutive query heads uses one of the 8 K/V heads. Each query head computes its own attention weights, but the cache needs only 8 heads' K/V vectors rather than 64, reducing their storage eightfold.
Repeating each K/V head 8 times to expand it to \([B, 64, S, 128]\) turns this into ordinary multi-head attention. The public implementation passes enable_gqa=True to PyTorch's scaled_dot_product_attention and lets PyTorch handle the shared K/V heads. The two are mathematically identical; the reference implementation in §7 repeats the heads explicitly. The cache does not need the 64-head copy.

4.3. Per-head Q/K normalization

Before computing attention scores, PLaMo 3 applies RMSNorm to each Q and K head through q_norm and k_norm. Each operation normalizes 128 components with offset 1 and \(\epsilon = 10^{-6}\). The Q gain vector is shared by all 64 query heads and the K gain vector by all 8 KV heads. V passes through without normalization.
Query-Key Normalization by Henry et al.[21] scales Q and K to unit length by their L2 norm and multiplies the dot product by a learnable scalar. PLaMo 3 uses an RMSNorm with per-component gains and the usual attention scale \(1/\sqrt{128}\). Both normalize Q and K, but they differ in the normalizing denominator and in the number and position of the learned coefficients.
  1. [21] Alex Henry, Prudhvi Raj Dachapally, Shubham Shantaram Pawar, Yuxuan Chen, "Query-Key Normalization for Transformers," Findings of EMNLP, 2020. (Query-Key Normalization with L2 normalization and a learnable scalar)

4.4. Order of the KV cache update and RoPE

The public implementation uses Transformers' DynamicCache to store normalized K before positional rotation, together with unnormalized V. Q is computed from the current input and is not cached.
After updating the cache, the implementation applies RoPE, which introduces position information by rotating pairs of components (§5). Each call rotates the current Q and every K returned by the cache. Global layers therefore rotate past keys again from their stored, unrotated values.
An inference engine must agree with the code that fills its cache about whether keys have already been rotated. Gemma 4, for example, caches keys after RoPE. Mixing the two conventions would either rotate keys twice or skip the rotation.
Attention generates consecutive positions internally: \(0, \dots, S-1\) for K and the trailing positions \(S - T, \dots, S - 1\) for Q. After a local layer drops old tokens, it renumbers the remaining tokens. This shifts Q and K positions by the same amount, preserving their relative distances. The post-RoPE dot products and attention scores are therefore unchanged apart from rounding error.

In local layers, Transformers' DynamicSlidingWindowLayer keeps at most the last \(W - 1 = 2047\) tokens after the cache update. The next decode step adds one new token, assigns K positions \(0, \dots, 2047\) to the 2048 tokens, and gives Q position 2047. With fixed-frequency RoPE, shifting the Q and K positions by the same amount leaves the dot product unchanged. This implementation's YaRN uses fixed frequencies and a common amplitude correction, so it keeps the same property, although finite-precision rounding need not match exactly.

The position_ids argument is not passed to attention; the internally generated sequence is used instead. To specify non-uniform positions, or to reset positions in an input that concatenates several sequences, the implementation must be changed to pass the position argument through to attention.

4.5. GQA equations and the output projection

After rotation, Q/K dot products are scaled, masked, and passed through softmax over the key positions. The mask sets disallowed scores to \(-\infty\), giving them zero weight; §4.6 defines the allowed positions.
Let \(Q', K'\) be Q and K after normalization and rotation, and \(M\) the additive mask. Zero-based query head \(h\) uses KV head \(g(h) = \lfloor h / 8 \rfloor\). With \(b\) indexing the sequence in the batch, \(t,s\) the query and key token positions, and \(r\) the component within a head, the attention weights \(A\) and each head's output \(O\) are
\[ \begin{eqnarray} A_{b,h,t,s} &=& \operatorname{softmax}_s\left(\frac{\sum_{r=0}^{127} Q'_{b,h,t,r}\, K'_{b,g(h),s,r}}{\sqrt{128}} + M_{b,t,s}\right), \\ O_{b,h,t,r} &=& \sum_s A_{b,h,t,s}\, V_{b,g(h),s,r} \end{eqnarray} \]
The dot-product scale is fixed at \(1/\sqrt{128}\). There is no additional learned score multiplier, score softcap, or attention dropout. An optimized kernel can evaluate these equations without storing the full score matrix.
To combine the heads, transpose \([B, 64, T, 128]\) to \([B, T, 64, 128]\) and concatenate the last two axes into \([B, T, 8192]\). Multiplication by the transpose of o_proj.weight, whose shape is \(5120 \times 8192\), returns to the hidden dimension. The block then applies post_mixer_norm before adding this result to the residual.
Top-to-bottom comparison of the attention internals of PLaMo 3 and Gemma 4. Q, K, and V are produced from the normalized input and processed in separate lanes. PLaMo 3 normalizes Q and K, updates the K/V cache, and then applies RoPE to Q and to all keys in the cache. Gemma 4 also normalizes V without a gain, applies RoPE to the current Q and K, and then stores K and V in the cache. Gemma 4's global layers share the projection output between K and V. Both models concatenate the GQA output and return to hidden dimension D with the output projection. Dimensions and head counts are variables; window sizes and other constants are shown as values.
Figure 3: Attention computation with caching in PLaMo 3 and Gemma 4 PLaMo 3 caches K before RoPE and rotates all returned keys on every call; Gemma 4 rotates only the current keys before adding them to the cache. Gemma 4 also normalizes V without a gain. Shapes place the head axis before the token axis: \(d\) is the head dimension and \(S\) the number of K/V tokens returned by the cache.

4.6. Layer indices and attention masks

With zero-based layer index \(\ell\), the global layers are those with \((\ell + 1) \bmod 8 = 0\): layers 7, 15, 23, 31, 39, 47, 55, and 63, which include the last layer. The remaining 56 layers are local.
For a query at position \(i\), a global layer allows keys at positions \(j \le i\), excluding future tokens. A local layer also requires \(i - j < W\). In the 2604 release, a full window therefore contains the current token and the 2047 preceding tokens, 2048 in total. The older implementation shipped with the 4K release allows 2049 tokens despite having the same window setting.

swa_mask builds a band mask with triu(diagonal=-(window_size - 1)). The distance to an attended token is at most \(W - 1\), so at most \(W = 2048\) tokens including the current one are attended. The local-layer cache keeps \(W - 1\) tokens, and the next decode step adds one, so prefill and decode attend to the same range.

The older implementation shipped with the 4K release uses triu(diagonal=-window_size) and attends to at most \(W + 1 = 2049\) tokens including the current one; its own cache class keeps the last \(W\) tokens. The number of tokens covered by "window size 2048" thus differs by one between implementation versions.

The 2604 release still has an assert that permits skipping the mask when \(S \le W + 1\). In training mode with the mask skipped and no cache, an input of \(T = W + 1\) tokens therefore attends to one token that should be outside the window. On a small random-weight model (\(W = 4\)), this produced a difference of up to 0.15 in the logits between training and evaluation mode (§7).

Example attention masks for 8 tokens. Rows are queries and columns are keys. The global layer on the left has a lower-triangular pattern where each token attends to itself and all earlier tokens. The local layer on the right, with window size 4, has a band pattern where each token attends only to itself and at most the 3 preceding tokens.
Figure 4: Global and local attention masks (\(W = 4\)) This eight-token example uses a four-token window. Blue cells can be attended; gray cells are masked with \(-\infty\). The local layer's range forms a band covering the current token and the \(W - 1\) before it. The actual window size \(W\) is 2048.

5. Positional encoding with RoPE and YaRN

5.1. Split-half rotation pairs

RoPE (Rotary Position Embedding)[17] introduces relative-position information into Q/K dot products. It groups the components of each Q and K head into rotation pairs, then rotates each two-component vector by an angle proportional to the token's position. In the resulting dot product, the positional contribution depends on the difference between the query and key positions.
PLaMo 3 uses the split-half layout (the GPT-NeoX layout): the 128 components of a head are divided into a first half and a second half of 64, and component \(j\) is paired with component \(j + 64\).
Let \(p\) be the token position and \(j = 0, \dots, 63\) the rotation pair index. With \(a_j\) and \(b_j\) the two components of a pair, the rotated components \(a'_j\) and \(b'_j\) are
\[ \begin{bmatrix} a'_j \\ b'_j \end{bmatrix} = \begin{bmatrix} \cos(p\omega_j) & -\sin(p\omega_j) \\ \sin(p\omega_j) & \cos(p\omega_j) \end{bmatrix} \begin{bmatrix} a_j \\ b_j \end{bmatrix}, \qquad \omega_j = \theta^{-2j/128} \]
The angular frequency \(\omega_j\) is the rotation angle per one-token advance. Pair \(j = 0\) has the highest frequency, with a wavelength of \(2\pi\) tokens; frequency decreases toward \(j = 63\). The base \(\theta\) controls the spacing of these frequencies.
Changing the component order within a Q/K head requires the same permutation of the projection matrix rows and RMSNorm gains. This conversion is needed when porting the weights to an implementation that pairs adjacent components, known as the GPT-J layout.
Q/K normalization must also precede RoPE. Scaling components by different gains and then rotating generally produces a different vector from rotating first and scaling afterward. This ordering matters even in local layers. In global layers, a subsequent RMSNorm would also largely cancel YaRN's amplitude correction (§5.3).

5.2. Different bases for local and global layers

Local layers use RoPE base \(\theta = 10^4\); global layers use \(\theta = 10^6\). The larger base lengthens the wavelength for every pair with \(j > 0\), so a greater token separation is needed to accumulate the same rotation angle. Gemma 3 and Gemma 4 use these same local and global bases[12, 6].

5.3. YaRN in the global layers

The 2604 release applies YaRN[18] in global layers to adjust RoPE for longer contexts. YaRN changes both the frequencies and the scale of attention scores. High-frequency pairs keep their original frequencies, low-frequency pairs have theirs divided by a factor \(s\), and intermediate pairs blend the original and reduced frequencies. Local layers use ordinary RoPE; the 4K release[5] uses no YaRN in either layer type.
The YaRN factor is \(s = 256\), as set by rope_scaling_factor. It is a separate setting from the context limit: the configured maximum of 262,144 tokens is 64 times the original 4096-token context. Substituting that ratio for \(s\) would give the wrong frequencies.
The public implementation varies the interpolation coefficient linearly with the rotation pair index.
The transition uses fractional boundaries without rounding them to integers. From the original context length \(L_0 = 4096\), \(\beta_{\text{fast}} = 32\), \(\beta_{\text{slow}} = 1\), and base \(\theta = 10^6\), the boundaries of the interpolation range are \[ \begin{eqnarray} j_{\text{low}} &=& 64 \frac{\ln\bigl(L_0 / (2\pi\beta_{\text{fast}})\bigr)}{\ln\theta} \approx 13.96, \\ j_{\text{high}} &=& 64 \frac{\ln\bigl(L_0 / (2\pi\beta_{\text{slow}})\bigr)}{\ln\theta} \approx 30.02 \end{eqnarray} \] Then \(\alpha_j = \operatorname{clip}\bigl((j - j_{\text{low}}) / (j_{\text{high}} - j_{\text{low}}),\, 0,\, 1\bigr)\), and the interpolated angular frequency is \(\tilde\omega_j = \omega_j [(1 - \alpha_j) + \alpha_j / 256]\), where \(\operatorname{clip}\) restricts a value to the range 0 to 1. Rounding the boundaries to integers would change the interpolated frequencies.
YaRN also multiplies both \(\cos\) and \(\sin\) by an amplitude correction of \(1 + 0.1 \ln 256 \approx 1.5545\). Scaling both Q and K by this factor multiplies their dot product by about 2.42 relative to the same rotations without the correction. Q/K normalization precedes RoPE, so it does not remove this scaling from the attention scores.

Multiplying both Q and K by \(1 + 0.1\ln256\) scales their dot product by \((1 + 0.1\ln256)^2 \approx 2.4165\). Including the usual attention scale gives a multiplier of \(2.4165 / \sqrt{128} \approx 0.2136\) on the rotated dot product before amplitude correction. The YaRN paper introduces the Q/K multiplier as \(\sqrt{1/t}\) for a temperature \(t\); the public implementation applies it through the cos/sin tables.

For a derivation of the frequency and amplitude adjustments, see the YaRN article.

YaRN frequency multiplier against rotation pair index j, with a logarithmic vertical axis. The multiplier is 1 for j up to about 13.96, interpolates down to 1/256 between about 13.96 and 30.02, and stays at 1/256 beyond.
Figure 5: YaRN frequency multiplier in the global layers The multiplier is calculated from the 2604 settings: \(s = 256\), \(L_0 = 4096\), and \(\theta = 10^6\). Dashed lines mark the transition boundaries. The vertical axis is logarithmic, but interpolation is linear in the multiplier itself.
When porting the model, also preserve the order of rounding in BF16 and read the RoPE settings for each layer type.
The public implementation computes angles and cos/sin in FP32, casts cos/sin to the input dtype, and then multiplies by the amplitude correction. A BF16 implementation must preserve that order to match its rounding. The reference implementation in §7 targets FP32 and omits the BF16 cast.

Plamo3Config.rope_parameters is a property that generates the RoPE settings for local and global layers from the values in config.json. In Transformers 5.12.1, the same values are also available under the old name rope_scaling[22]. The absence of rope_scaling in the JSON does not by itself mean that YaRN is disabled.

The cited vLLM implementation[15] reads rope_parameters for each layer type. The bundled sitecustomize.py implements this separately and reads the older rope_scaling name. Its compatibility with settings that differ by layer type, and the outputs produced under vLLM, were not checked.

  1. [22] Hugging Face, "configuration_utils.py (Transformers v5.12.1)," GitHub, 2026.
  2. [15] vLLM Project, "vllm/model_executor/models/plamo3.py (commit d881812)," GitHub, 2026.

6. SwiGLU MLP and projection layout

After the attention residual addition, the MLP transforms each token independently using the same weights at every position. Two projections expand its normalized vector from 5120 to 25600 components: the gate projection controls how much of each up-projection component passes through.
The gate activation is SiLU, making the MLP a SwiGLU[20]. For input \(U \in \mathbb{R}^{B \times T \times 5120}\), already normalized by pre_mlp_norm, the computation is
\[ \begin{eqnarray} [G, U_{\text{up}}] &=& U W_{\mathrm{gate\_up}}^\mathsf{T}, \\ \operatorname{MLP}(U) &=& \bigl[\operatorname{SiLU}(G) \odot U_{\text{up}}\bigr] W_{\text{down}}^\mathsf{T} \end{eqnarray} \]
The packed gate_up_proj.weight stores gate weights in its first 25600 rows and up weights in the remaining 25600. Both outputs have shape \([B, T, 25600]\). Only the gate passes through \(\operatorname{SiLU}(g) = g\,\sigma(g)\), where \(\sigma(g) = 1/(1 + e^{-g})\). The elementwise product then passes through the down projection, returning to \([B, T, 5120]\) for output normalization and residual addition.
SiLU can produce negative gate values, so the gate can reverse the sign of an up component as well as change its magnitude. The linear layers have no biases, and the MLP uses no dropout.

7. Numerical validation of the reference implementation

The formulas above were used to implement an independent forward pass and compare its outputs with the public model code. On one short Japanese input, using the 2604 weights in FP32, the maximum absolute logit difference was \(9.5 \times 10^{-6}\).

7.1. Reference forward pass

The reference code computes the FP32 forward pass directly from checkpoint tensors. Its test input is also used for the activation measurements in §10.
The exact input is “これからの人工知能技術は、計算資源の制約の中でどこまで,” a fragment meaning roughly “How far can future AI technology go with limited computing resources?” It produces 12 tokens including the beginning-of-sequence (BOS) token in PLaMo and 17 tokens in Gemma. The activation comparisons use each model's own tokenization of this text.

The reference implementation reads weights directly from safetensors and runs on CPU in FP32 with batch size 1, without padding or a cache. It takes w, a dictionary of weights converted to FP32, and ids, a token ID tensor of shape \([1, T]\). It repeats K/V heads explicitly to express GQA and constructs the attention scores directly.

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 rotation; YaRN on global layers
    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      # amplitude correction, applied to both cos and 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: each group of 8 consecutive query heads uses one K/V head
    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        # local layer: the current token and the 2047 before it
    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]          # no √D scaling of the embedding
    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     # output head tied to the embedding

7.2. Agreement and test coverage

After all 64 layers, the two FP32 implementations agree on the highest-scoring token at every position. Running the public implementation in BF16 changes its logits by up to 0.165 relative to FP32. On this input, that precision difference is about four orders of magnitude larger than the difference between the two FP32 implementations.
Additional cache checks found close agreement with single-pass outputs. The public-weight test covered the same short input; a separate small model with random weights tested decode and chunked prefill across the local-window boundary. Inputs longer than 2048 tokens with the public 31B weights, including the configured 262,144-token limit, were not tested.

Errors below are absolute differences between logits. On the public-weight test input, the largest absolute logit was 18.2. The small-model tests use random weights in the public implementation's classes; they are separate from the tests with the released 31B weights.

CheckConditionsMaximum absolute error
Public weights, all 64 layers: reference vs. public implementation2604 release, FP32, \(T = 12\), no cache\(9.5 \times 10^{-6}\) (mean absolute error \(1.2 \times 10^{-6}\))
Public implementation: BF16 vs. FP322604 release, \(T = 12\), no cache0.165 (mean absolute error 0.019); highest-scoring tokens agree
Public weights: single pass vs. token-by-token decode2604 release, FP32, sequence length 12\(1.0 \times 10^{-5}\)
Small model: single pass vs. token-by-token decode8 layers, \(D = 48\), head dimension 16, \(W = 4\), sequence length 12, FP32\(2.7 \times 10^{-7}\) (\(3.3 \times 10^{-7}\) with the 4K release's older implementation)
Small model: single pass vs. prefill in chunks of 3, 6, and 3 tokensSame as above\(2.1 \times 10^{-7}\) (\(2.8 \times 10^{-7}\) with the older implementation)
Small model: training mode without mask vs. evaluation modeThe small model above with \(T = 4, 5, 6\)0.15 at \(T = 5\) only (0 with the older implementation)

The checks against the public weights used PyTorch 2.12.1 (CPU) and Transformers 5.12.1. The model card specifies PyTorch 2.9.0 or earlier, but these checks ran on 2.12.1. Both implementations load the weights in FP32, so each needs about 127 GB for the weights alone. The CPU runs used 96 threads. The small model is the public implementation's class with random weights. The checks of the 4K release's older implementation used Transformers 4.57.1.

7.3. Checks when porting the model

The following details connect the forward-pass specification to the checkpoint and runtime:
  • Map the model.layers.layers.{i}. weight keys correctly and split merged projections at the specified row boundaries (§2.2, §4.1, §6).
  • Use head dimension 128 and the correct RMSNorm offset at each site (§2.1, §3.2).
  • Apply Q/K normalization before split-half RoPE, including YaRN frequencies and amplitude correction in global layers (§5.1, §5.3).
  • Match the cache representation and Q/K positions: the public implementation stores K before RoPE (§4.4).
  • Place local and global layers by their zero-based indices and match the window's token count (§4.6).
  • Share the input embedding matrix with the output head (§2.2).
  • Match the order of dtype conversions, offset addition, and multiplication in BF16 (§3.2, §5.3).
Begin with a short input, batch size 1, FP32, and no cache, comparing outputs block by block. Then add caching, inputs that cross the window boundary, padding, BF16, and optimized kernels one at a time. Comparing after each change makes it easier to locate the source of a mismatch.

8. KV cache storage and computation costs

8.1. KV cache size estimates

The cache estimate assumes that global layers retain the entire history and local layers discard entries outside their windows. Its size is the number of retained tokens multiplied by the bytes per token's keys and values, summed over layers.
Let \(N\) be the sequence length including the current token and \(W\) the window size including the current token. \(H_{kv}\) is the KV head count, \(d\) the head dimension, and \(b\) the bytes per element. With \(N_g\) global and \(N_l\) local layers, the storage for K/V tensors at batch size 1 is approximately
\[ C_{\text{KV}} \approx 2\, b\, H_{kv}\, d \left[ N_g N + N_l \min(N, W) \right] \]
The leading 2 accounts for K and V. BF16 uses \(b = 2\) bytes per element, giving PLaMo 3 31B a cache cost of 4 KiB per layer per token. The 8 global layers add 32 KiB for each additional token, while the 56 local layers plateau at about 448 MiB. Here, KiB, MiB, and GiB mean \(2^{10}\), \(2^{20}\), and \(2^{30}\) bytes, and 1K means 1024 tokens.
At 256K tokens, the estimated total is about 8.4 GiB, compared with 64 GiB if all layers were global. The reduction grows with sequence length because only the global-layer share continues to grow.
The table gives values for batch size 1 in BF16. Relative to an all-global PLaMo 3, the cache is about 5.6 times smaller at 32K tokens and 7.6 times smaller at 256K. The window size counts tokens including the current one: 2048 for PLaMo 3 and 1024 for Gemma 4. An actual local cache keeps at most one token fewer than the window size after an update; this one-token difference is ignored in the estimate.
Sequence length \(N\)PLaMo 3 31BGemma 4 31BPLaMo 3 31B with all layers global
4,096576 MiB1,120 MiB1 GiB
32,7681,472 MiB3,360 MiB8 GiB
131,0724,544 MiB11,040 MiB32 GiB
262,1448,640 MiB21,280 MiB64 GiB

Gemma 4's 10 global layers have K and V of 4 heads × 512 dimensions, 8 KiB per layer per token. Its 50 local layers have 16 heads × 256 dimensions, 16 KiB per layer per token, and their total plateaus at about 800 MiB.

attention_k_eq_v specifies the shared projection. With \(Z\) as its output and \(N_\gamma\) denoting RMSNorm with gain \(\gamma\), global layers compute \(K = \operatorname{RoPE}(N_{\gamma_k}(Z))\) and \(V = N_1(Z)\). The table follows Transformers, which stores these processed K and V tensors separately. An implementation that caches only \(Z\) and recomputes K and V would require a different storage estimate.

For PLaMo 3, assuming 1 byte per element gives 128 MiB at 1K tokens and about 2.2 GiB at 128K tokens, matching PFN's published comparison table[8] after rounding. Parameters, masks, activations, logits, allocator overhead, and temporary prefill buffers require additional memory.

  1. [8] Shuji Suzuki, "大規模言語モデルの次期バージョン PLaMo 3 シリーズにおける8B, 31Bの小規模モデルによる事前学習の検証," Preferred Networks Tech Blog, 2025.
Gemma 4 31B shares the K and V projection in its global layers, but normalization and rotation produce different tensors that Transformers stores separately[7]. Its 4 KV heads of dimension 512 take 8 KiB per global layer per token, twice PLaMo 3's 4 KiB. With 10 global layers, each additional token adds 80 KiB. Once the local-layer share becomes negligible, Gemma's cache is therefore about 2.5 times PLaMo 3's.
Log-log plot of KV cache size against sequence length from 1K to 256K. In BF16 with batch size 1, PLaMo 3 takes 256 MiB at 1K and 8.4 GiB at 256K; Gemma 4 takes 880 MiB at 1K and 20.8 GiB at 256K. PLaMo 3 with all 64 layers global would take 64 GiB at 256K.
Figure 6: Computed KV cache size (BF16, batch size 1) The estimates retain all global K/V entries and discard local entries beyond windows of 2048 tokens for PLaMo 3 and 1024 for Gemma 4. K and V are stored separately. Both axes are logarithmic, and 1K is 1024 tokens. Other runtime memory is excluded.

8.2. Compute cost and memory use in the implementation

For prefill without a cache, fix the head counts and dimensions. Computing attention only within the window takes \(O(TW)\) work per local layer, compared with \(O(T^2)\) per global layer. This reduces the dot products and weighted sums. Total runtime also includes the projections and MLPs, which still run at every token, and depends on how the backend executes these operations.
The public implementation also allocates a mask over all \(T \times S\) query-key pairs, including disallowed positions. At the configured maximum length, a single FP32 mask would require 256 GiB. An attention backend can avoid this allocation by accepting the window directly and computing within it. This implementation choice matters even when the kernel avoids storing the score matrix itself.

During prefill, the public implementation builds the \(T \times S\) causal and local masks as arrays and passes them to scaled_dot_product_attention. Restricting attention through a mask does not guarantee that the Q/K dot products outside the window are skipped. At the configured maximum sequence length \(T = S = 262144\), a single FP32 mask takes 4 bytes for each of its \(T \times S\) elements, or 256 GiB. This storage requirement follows from the mask shape and dtype.

The branch that called flash_attn in the 4K release's older implementation has been removed in the 2604 release. The vLLM implementation uses an attention backend that accepts a window size.

8.3. Decode cost across model sizes

Smaller PLaMo 3 models also use a head dimension of 128, a configured window of 2048, one global layer in eight, and a vocabulary of 107,520. The comparison below uses 610M Fin Instruct, NICT 2B and 8B Base, and NICT 2604 31B Base. The 4K and 2604 31B releases have the same dimensions, so the estimates use one column for both.
The 4K release has a 4096-token context limit and no YaRN. Its older implementation also uses a 2049-token local window (§4.6); this estimate ignores that one-token difference and uses 2048 for both releases. Their layer counts and projection dimensions are identical.
Parameter totals include the input embedding and output head, counting them once when tied. The 610M Fin Instruct variant stores separate matrices, bringing its total to about 890 million parameters despite its name. The other models tie them.
The table gives decode estimates at a sequence length of 4096 in BF16. It counts linear projections, attention dot products, and weighted sums; 1 GFLOP is \(10^9\) floating-point operations. Read volumes assume one read of each projection weight per batch step and of each sequence's K/V.

The sequence length of 4096 includes the current token. Global layers attend to all 4096 tokens and local layers to 2048. Linear projections include the output head, and a multiply-add counts as 2 FLOPs. Each projection matrix is assumed to be read once per batch step.

Let \(V\) be the vocabulary size, \(D\) the hidden dimension, \(L\) the layer count, \(F\) the MLP intermediate dimension, \(H_q,H_{kv}\) the query and KV head counts, and \(d\) the head dimension. The number of matrix elements in the linear projections including the output head, \(P_{\mathrm{lin}}\), is given below: each block's QKV and output projections have \(2Dd(H_q+H_{kv})\) elements, the gate/up/down projections have \(3DF\), and the output head has \(VD\).

\[ P_{\mathrm{lin}} = L\left[2Dd(H_q+H_{kv}) + 3DF\right] + VD \]

Let \(N_g=L/8\) be the number of global layers, \(N_l=7L/8\) the number of local layers, \(N\) the sequence length, and \(W\) the window size, and let \(A=N_gN+N_l\min(N,W)\) be the total number of attended tokens over all layers. The total operation count \(C\) is estimated as below, with the first term for the linear projections and the second for the attention dot products and weighted sums. The table substitutes \(B=1\), \(N=4096\), \(W=2048\), and \(d=128\), and divides the second term by \(C\) to get the share of dot products and weighted sums.

\[ C \approx 2BP_{\mathrm{lin}} + 4BH_qdA \]

BF16 uses 2 bytes per element, so the weight reads are \(2P_{\mathrm{lin}}\) bytes and the K and V reads total \(4BH_{kv}dA\) bytes. K and V are reused across the query heads that share a KV head under GQA, but not across sequences.

For 31B, these reads total \(59.15 + 0.5625B\) GiB per batch step, or \(59.15/B + 0.5625\) GiB per generated token. For a batch of \(B\) sequences, multiply the table's per-token operation count and KV reads by \(B\).

The estimates leave out normalization, softmax, RoPE, activation functions, residual additions, and similar operations, as well as the embedding lookup and the reads of normalization weights and intermediate data. The attended range includes the new K and V, and the difference when they are used before being written to memory is ignored. Actual memory traffic depends on whether weights and K/V stay in hardware caches, on kernels rereading weights or K/V, and on how intermediate data is stored.

Operations and KV reads are per generated token; weight reads are per batch step. A larger batch spreads weight reads across more generated tokens, while each sequence still needs its own KV reads.
Item610M[4]2B[2]8B[3]31B[1]
Total parameters\(8.90 \times 10^{8}\)\(2.60 \times 10^{9}\)\(8.09 \times 10^{9}\)\(3.18 \times 10^{10}\)
Input embedding parameters\(1.65 \times 10^{8}\)\(2.75 \times 10^{8}\)\(4.40 \times 10^{8}\)\(5.51 \times 10^{8}\)
Hidden dimension \(D\)1536256040965120
Layers \(L\)16243264
MLP intermediate dimension \(F\)6144102401638425600
Query heads \(H_q\)16243264
Key/value heads \(H_{kv}\)1448
Input embedding and
output head
SeparateTiedTiedTied
Estimated decode operations
(GFLOP/token)
1.755.8917.3968.34
Share from dot products
and weighted sums
17.24%11.54%6.95%7.07%
Weight reads
(GiB/step)
1.354.8515.0759.15
KV cache reads
(MiB/token)
18108144576
At this sequence length, 31B needs an estimated 68.34 GFLOPs per generated token, of which about 7% comes from attention dot products and weighted sums. A shorter local window reduces that part. The rest comes from linear projections in attention, the MLP, and the output head, whose operation counts are unchanged by the window.

9. Similarities and differences from Gemma 4 31B

Gemma 4 31B shares PLaMo 3's main ingredients: local/global attention, GQA, Q/K RMSNorm, normalization before and after each sublayer, and a tied embedding and output head. The comparison covers Gemma's 60-layer text decoder with hidden dimension 5376 and about 30.7 billion parameters; its roughly 0.58-billion-parameter image encoder is outside the scope.
The main differences lie in the head dimensions, normalization gains, residual scaling, and treatment of position. For readers comparing the code, the corresponding sublayers use different names in the two implementations.
RolePLaMo 3Gemma 4
One blockPlamo3DecoderLayerGemma4TextDecoderLayer
Attention input RMSNormpre_mixer_norminput_layernorm
Attentionmixer (qkv_proj split)self_attn (q_proj, k_proj; local layers also use v_proj)
Attention output RMSNormpost_mixer_normpost_attention_layernorm
MLP input RMSNormpre_mlp_normpre_feedforward_layernorm
MLPmlp.gate_up_proj split, down_projmlp.gate_proj, up_proj, down_proj
MLP output RMSNormpost_mlp_normpost_feedforward_layernorm
Per-layer scalarNonelayer_scalar (multiplies the block output)
Final RMSNormmodel.normmodel.norm

9.1. Configuration and normalization

ItemPLaMo 3 31BGemma 4 31B
Blocks / hidden dimension \(D\)64 / 512060 / 5376
MLP intermediate dimension \(F\) / activation25600 (\(5D\)) / SiLU21504 (\(4D\)) / tanh-approximated GELU
Query heads / KV heads64 / 8Local 32 / 16, global 32 / 4
Head dimension128 (all layers)Local 256, global 512
Total query dimension8192 (\(> D\))Local 8192, global 16384 (\(> D\))
Value in global layersProjected separately from KShares the projection output with K, normalized for V (attention_k_eq_v)
Vocabulary size107,520262,144
Local:global cycle7:1 (8 global layers, last layer global)5:1 (10 global layers, last layer global)
Local window2048 (including the current token; 2049 in the 4K release's older implementation)1024 (including the current token)
Configured maximum sequence length262,144 (4096 for the 4K release)262,144
RoPE base (local / global)\(10^4\) / \(10^6\)\(10^4\) / \(10^6\)
Global-layer RoPE extensionYaRN (factor 256, with amplitude correction; none in the 4K release)p-RoPE (\(p = 0.25\); 64 of 256 pairs rotated)
Q/K normalizationRMSNorm, 128-dimensional gain, offset 1RMSNorm, gain 256-dimensional local / 512-dimensional global
V normalizationNoneRMSNorm without gain
Fixed scale on the Q/K dot product\(1/\sqrt{128}\)1 (the scale implied by the public gains is in §10.4)
RMSNorm gain\(c + w\) (output-side \(c\) is 0.2 and \(5^{-1.5}\))\(w\) itself (initialized to 1)
Embedding scaled by \(\sqrt{D}\)No (scale_embedding = false)Yes
Tied embedding and output headYesYes
Softcap on output logitsNone\(30 \tanh(\cdot / 30)\)
K stored in the cacheAfter normalization, before RoPEAfter normalization, after RoPE
The shared normalization layout hides a difference in how gains are stored. PLaMo 3 stores \(w = \gamma - c\), whereas Gemma 4 stores \(\gamma\) directly. Weight comparisons must therefore use PLaMo's effective gains after adding the offsets. Gemma also normalizes V without a gain, scales the input embedding by \(\sqrt{D}\), and bounds the final logits with \(30\tanh(\cdot/30)\).
Gemma 4 additionally multiplies the entire block output by a per-layer scalar, layer_scalar. In the public weights, every value is between 0 and 1, so each scalar shrinks the block output.

Gemma4TextDecoderLayer multiplies the block output by layer_scalar after the residual additions and passes the result to the next block. In Transformers it is registered as a one-element buffer rather than a learnable parameter[7]. Its initial value is 1, but the public weights store a different value for each layer (§10.5).

RMSNorm nearly cancels positive input scaling when the mean square remains well above \(\epsilon\) before and after scaling. Shrinking a block's output can therefore leave the normalized input to the next attention sublayer almost unchanged while reducing the residual carried alongside it. This changes the size of subsequent attention and MLP contributions relative to the residual. Because the direction of their sum can change too, the effect of a middle layer's scalar can persist after the final RMSNorm.

  1. [7] Hugging Face, "modeling_gemma4.py (Transformers v5.12.1)," GitHub, 2026.

9.2. Gemma 4's p-RoPE

p-RoPE[19] rotates a fraction \(p\) of the pairs in each head and leaves the rest unchanged. Gemma 4's global layers have head dimension 512 and \(p = 0.25\): 64 high-frequency pairs out of 256 are rotated, while the 192 low-frequency pairs receive no position-dependent rotation.

Transformers' proportional type[23] computes the angular frequencies with the original head dimension 512 in the exponent's denominator and then sets the low-frequency ones to 0. The rotation pairs are \((j, j + 256)\), with angular frequencies

\[ \omega_j = \begin{cases} (10^6)^{-2j/512} & (0 \le j < 64), \\ 0 & (64 \le j < 256). \end{cases} \]

The rotated components have indices 0 to 63 and 256 to 319, giving 128 components in total. Both their pairing and their frequencies differ from applying ordinary 128-dimensional RoPE to the first 128 components. A zero-frequency pair has cosine 1 and sine 0, so its values pass through unchanged.

Based on their analysis of Gemma 7B, Barbero et al. interpret low-frequency pairs as matching token content and propose leaving them unrotated[19].

  1. [23] Hugging Face, "modeling_rope_utils.py (Transformers v5.12.1)," GitHub, 2026.
  2. [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.
For Gemma 4's 192 unrotated pairs, that layer's RoPE adds no position dependence to the corresponding dot-product terms. PLaMo 3 instead retains position-dependent rotation in all 64 pairs: YaRN slows the low-frequency rotations to 1/256 of their original frequency.
Bands showing the rotation pairs within a head. PLaMo 3 has head dimension 128 in all layers and rotates all 64 pairs. Gemma 4's local layers have head dimension 256 and rotate all 128 pairs. Its global layers have head dimension 512 and rotate only the 64 high-frequency pairs out of 256, leaving the 192 low-frequency pairs unrotated.
Figure 7: Rotation pairs within a head (PLaMo 3 and Gemma 4) With head dimension \(d\), a rotation pair consists of components \(j\) and \(j + d/2\). PLaMo 3 rotates all 64 pairs, whereas Gemma 4's global layers leave the low-frequency three quarters unrotated under p-RoPE (§9.2). Darker color means higher frequency.

10. Trained-weight statistics and activation magnitudes

The checkpoint gives the coefficients used in the forward pass; activations show what those coefficients produce for a particular input. Reading them together is especially useful around RMSNorm, where a projection's weight scale can be a poor guide to the magnitude eventually added to the residual.

10.1. Comparison targets and statistics

The weight statistics cover every tensor element in the 2604 checkpoint and Gemma 4's text decoder. Standard deviation measures spread around the mean; RMS, \(\sqrt{\operatorname{mean}(x^2)}\), measures magnitude without subtracting the mean. Normalization statistics use effective gains. The activation measurements use the same Japanese input as the numerical validation (§7).

The analysis covers all 642 tensors (31,757,456,384 elements) of the PLaMo 3 31B 2604 release and all 832 tensors (30,697,345,340 elements) of the Gemma 4 31B text part. The Gemma 4 count includes the 60 layer_scalar values in addition to the learnable parameters.

BF16 represents values in 16 bits, so there are 65,536 possible bit patterns. The analysis reads the safetensors byte stream, counts each bit pattern per tensor, and computes statistics from the corresponding values in 64-bit floating point (FP64). No sampling was used.

Standard deviations use the full population of tensor elements (ddof = 0).

PLaMo's QKV projection was split into Q, K, and V at the boundaries in §4.1, and the gate/up projection into gate and up at the boundary in §6, with statistics computed per part. These are parts of the original tensors and are not double-counted in the total parameter count. The effective gain is the sum of weight and offset computed in FP64, without the rounding that BF16 addition would introduce.

Neither model's weights contain NaN or Inf, and PLaMo's weights contain no exact zeros.

10.2. Output-side normalization gains and residual magnitude

PLaMo 3's output-side RMSNorm gains generally grow with depth. The mean attention-output gain rises from about 0.12 in the first layer to 0.27 in the last. The MLP-output mean rises from its minimum of about 0.02 in layer 7 to 0.36 in the last layer. Early-layer means fall below the initial gains, while input-side means stay near 1. The larger variation occurs just before residual addition.

Each mean averages all 5120 components of an RMSNorm gain. At the attention output, it is 0.116 in layer 0 and 0.269 in layer 63. At the MLP output, it reaches a minimum of 0.021 in layer 7 and ends at 0.358. The initial gains are 0.2 and about 0.089, respectively. Input-side means range from 0.977 to 1.035 before attention and from 0.905 to 1.204 before the MLP.

In the 4K release, the attention-output mean rises from 0.104 in layer 0 to 0.247 in the last layer. Between the two checkpoints, the correlation of per-layer mean gains is 0.93 for the attention output and 0.99 for the MLP output.

The 4K release has different trained weights, yet its output-side gains follow a similar pattern.
Flattening each embedding or projection tensor and comparing it with the same-named tensor in the other checkpoint gives cosine similarities between −0.001 and 0.001. This covers the embedding and all 64 layers' qkv_proj, o_proj, gate_up_proj, and down_proj. These are comparisons of stored coordinates: neuron permutations and reparameterizations can change the statistic, so it does not identify how the checkpoints were trained.
Mean over all components of the normalization gain for layers 0 to 63. The input side stays near 1, while the output side is small in early layers and tends to grow with depth: about 0.10 to 0.27 at the attention output and about 0.02 to 0.36 at the MLP output. Dashed lines mark the offsets 0.2 and about 0.089 that correspond to the initial values.
Figure 8: Mean normalization gains in PLaMo 3 31B (2604 release) Each point averages the effective gain \(\gamma = c + w\) over all 5120 components; the vertical axis is logarithmic. Dashed lines mark the output-side offsets, which equal the initial gains. Orange ticks below the horizontal axis mark global layers.
On the validation input, the last token's residual RMS grows from 0.017 at the embedding to 0.97 after the final block, about 57-fold. The path is uneven: it temporarily reaches 0.85 around layers 5–7, then drops to 0.10 in layer 8.

Figure 9 follows the last token after embedding, after each block, and after the final RMSNorm. The input from §7 gives 12 tokens including the beginning-of-sequence (BOS) token in PLaMo and 17 in Gemma.

The rise near the first global layer also appears at other non-BOS positions. The 4K release reaches 0.17 at layer 7 on this input. In the 2604 release, BOS behaves differently from the other tokens: its residual RMS reaches 6.3 in later layers.

As the residual grows, an added vector of fixed RMS becomes smaller relative to it. Larger output gains could help maintain the relative size of later contributions, though the measured trend does not establish why the gains grew.
On the same input, Gemma 4's residual RMS starts at 1.0 after embedding scaling, exceeds 5 in the middle layers, and falls to 0.7 near the end. Its per-layer scalars act on both the accumulated residual and the new contributions. The two models thus show different trajectories despite placing sublayer RMSNorms in the same locations.
Residual RMS at the last token of the same Japanese sentence. PLaMo 3 grows from about 0.02 right after the embedding to about 1 after the last block, with a temporary 0.85 at layer 7. Gemma 4 starts at 1, exceeds 5 in the middle, and falls to 0.7 near the end. After the final RMSNorm, at the right edge, PLaMo 3 is at 2.8 and Gemma 4 at 5.6.
Figure 9: Residual stream RMS by block (same Japanese sentence, last token) Measured on the last token of the same Japanese input in both models. Points follow the embedding and each block output; the rightmost point follows the final RMSNorm. The curves describe this single input, whose tokenization differs between models (§7.1).

10.3. Early-layer MLP weights and activations

Layers 2, 3, 4, and 6 have unusually small MLP weights: the gate, up, and down projections have standard deviations of 0.0006–0.0011, roughly one fifth to one tenth of the values from layer 8 onward. These small weights do not consistently produce small activations.
Weight standard deviations and activation RMS are shown for layers 0–8. Activations were measured on the input from §7.1, over its 11 tokens other than the beginning-of-sequence (BOS) token. "SiLU input" is the gate projection output before the activation function. The normalized attention and MLP outputs are the contributions added to the residual.
LayerWeight std. of gate / up / downWeight std. of o_projSiLU input RMSMLP output RMS (before norm)MLP output RMS (after norm)Attention output RMS (before norm)Attention output RMS (after norm)
00.0037 / 0.0037 / 0.00410.00480.2550.58470.0222.30.135
10.0046 / 0.0045 / 0.00480.00390.7776.4440.04817.30.134
20.0010 / 0.0010 / 0.00110.00420.52133.110.04360.40.102
30.0006 / 0.0006 / 0.00060.00390.770108.60.04247.80.103
40.0006 / 0.0006 / 0.00060.00450.35211.890.03723.30.125
50.0036 / 0.0035 / 0.00360.00460.1450.6450.0678.760.125
60.0006 / 0.0006 / 0.00060.00510.0600.65420.0724.820.200
70.0031 / 0.0031 / 0.00340.00450.0130.000210.0472.470.448
80.0057 / 0.0057 / 0.00570.00590.0370.00540.3780.2530.376
Across layers 0–8, the normalized attention and MLP contributions have RMS values between 0.02 and 0.5 on this input.
On the measured input, layer 3 has an MLP output RMS of 108.6 before normalization, despite its small weights. Layer 7's corresponding RMS is just 0.00021, over five orders of magnitude lower. After normalization, the two values are 0.042 and 0.047. The output-side RMSNorm brings these very different raw outputs to similar magnitudes before residual addition.
The normalized magnitude depends on the gains, activations, and \(\epsilon\) together. Unequal component gains make the result sensitive to which input components are large. At layer 7, the input to RMSNorm is small enough that omitting \(\epsilon\) would substantially overestimate the normalized output.
Let \(x\) be one token's vector entering RMSNorm and \(\gamma\) the effective gain. Writing the RMSNorm as \(N_\gamma\), the output RMS satisfies \[ \operatorname{RMS}(N_\gamma(x))^2 = \frac{\operatorname{mean}(\gamma^2 \odot x^2)}{\operatorname{mean}(x^2) + \epsilon}. \] The numerator contains the product of gain and activation, so the gain alone does not determine the output RMS. Scaling the input by a positive constant \(a\) gives \[ N_\gamma(a x) = \gamma \odot \frac{x}{\sqrt{\operatorname{mean}(x^2) + \epsilon/a^2}} \] The normalized output is nearly unchanged by scaling the input only when the mean square is much larger than \(\epsilon\) both before and after. Layer 7's raw MLP output RMS, 0.00021, is below \(\sqrt{\epsilon} = 0.001\). At this scale, multiplying the down or up matrix by a positive constant also changes the RMS of the MLP output added to the residual.
The gate also depends on activation magnitude. Near zero, \(\operatorname{SiLU}(g) \approx g/2\). On this input, the gate's RMS is 0.01–0.06 in layers 6–8 but 0.35–0.77 in layers 2–4, despite their small weights.
In the 4K checkpoint, MLP weight standard deviations stay within 0.0045–0.0068 across all layers, without the unusually small early-layer weights. Its layer 7 gate output nevertheless has a small RMS of 0.035 on this input. That activation behavior appears in both checkpoints despite their different weight scales.

10.4. Q/K gains and attention scores

PLaMo 3's Q/K normalization can scale the two components of a RoPE pair very differently. Gains below 0.05 occur only in high-frequency pairs in the later layers. In every such pair, only one component has a gain this small.

Across all layers, there are 8192 gain components for Q and another 8192 for K. Of these, 282 Q gains and 246 K gains have absolute value below 0.05. All belong to high-frequency pairs (\(j \le 16\)) in layer 31 or later, and no pair has both components below the threshold.

Component \(i\) belongs to rotation pair \(j = i \bmod 64\). Averaging the gains by pair gives about 0.6 near the high-frequency end \(j = 0\) and about 1.4 on the low-frequency side \(j \ge 48\), with an almost monotonic increase in between. The high-frequency gains vary considerably across layers and between the two components of a pair.

Heatmap of the effective gain of Q/K normalization. The vertical axis is layer 0 to 63 and the horizontal axis is component 0 to 127, with corresponding components in the first and second halves forming a rotation pair. Small gains concentrate on the high-frequency side, and the orange cells marking absolute values below 0.05 appear only from layer 31 onward. The low-frequency side is dark blue with nearly uniform values.
Figure 10: PLaMo 3 2604 Q/K normalization gains The heatmaps show \(\gamma = 1 + w\) for 64 layers × 128 components. Components \(j\) and \(j + 64\) form a rotation pair; orange marks \(|\gamma| < 0.05\). The Q gain is shared by all 64 query heads and the K gain by all 8 KV heads.

The smallest gain is 0.0039 for both Q and K, with no negative values. The largest is 2.55 for Q and 2.26 for K.

In the 4K release, 273 Q components and 166 K components meet the same threshold, all at \(j \le 16\). In the 16-layer 610M Fin Instruct, 153 Q components lie at \(j \le 14\) and 101 K components at \(j \le 18\). In both models, no rotation pair had both components below the threshold.

A small gain on one component suppresses that component before RoPE mixes it with its partner, whose gain is usually above 1. The pair still rotates, unlike an unrotated p-RoPE pair. Unequal gains also explain why PLaMo's normalization and rotation must remain in the specified order (§5.1).
Gemma 4's Q and K gains are stored as vectors too, but every component within a given vector has the same value. Across layers, Q gains range from 0.95 to 1.05; K gains range from 0.120 to 0.132 in local layers and 0.060 to 0.065 in global layers.
With uniform gains, their product can be factored out of the Q/K dot product as a single inverse-temperature multiplier. Gemma 4 uses this product without an additional \(1/\sqrt{d}\) scale. For fixed, unequal scores, a larger multiplier makes softmax weights more concentrated.
In local layers (\(d = 256\)), the Q/K gain product is about twice the usual scale \(1/\sqrt{256} = 0.0625\); in global layers (\(d = 512\)), it is about 1.4 times \(1/\sqrt{512} \approx 0.044\). This comparison holds the normalized Q and K fixed and changes only the multiplier on their dot product.

10.5. Gemma 4's residual scaling

Gemma 4's per-layer layer_scalar values are smallest in the first two layers and the last layer. Each scalar acts on the sum of the incoming residual and the new attention and MLP contributions. On the measured sentence, the RMS after the first two blocks is about half the embedding RMS (Figure 9), reflecting both the added contributions and the scalars.

The first two scalars are 0.097 and 0.070, and the last is 0.040; middle-layer values range from 0.46 to 0.99. The first two multiply to about 1/150, scaling the input embedding term carried through the residual path by that factor. The block outputs also include attention and MLP contributions added along the way.

The table lists each layer's stored BF16 scalar, rounded to three decimal places. Values within a row follow increasing layer index.

Layerlayer_scalar value
0 to 90.097, 0.070, 0.992, 0.969, 0.984, 0.879, 0.914, 0.852, 0.859, 0.867
10 to 190.914, 0.812, 0.719, 0.973, 0.977, 0.840, 0.977, 0.844, 0.969, 0.906
20 to 290.902, 0.957, 0.910, 0.695, 0.836, 0.793, 0.664, 0.641, 0.457, 0.562
30 to 390.695, 0.758, 0.766, 0.785, 0.758, 0.668, 0.789, 0.809, 0.797, 0.684
40 to 490.590, 0.645, 0.766, 0.809, 0.848, 0.871, 0.895, 0.879, 0.875, 0.832
50 to 590.867, 0.871, 0.703, 0.828, 0.906, 0.871, 0.844, 0.809, 0.727, 0.040

The last layer's output, multiplied by 0.040, goes to the final RMSNorm with nothing further added. For the last token of the input sentence used here, the RMS before the final RMSNorm was about 0.7. The ratio of \(\epsilon = 10^{-6}\) to the mean square is about \(2 \times 10^{-6}\), small enough that the final RMSNorm almost entirely cancels the shrinking factor.

Bar chart of Gemma 4 31B's per-layer scalar. Layer 0 is 0.097, layer 1 is 0.070, and layer 59 is 0.040; the other layers range from about 0.46 to 0.99. Global layers are shown in orange.
Figure 11: Gemma 4 31B's per-layer layer_scalar The horizontal axis is the zero-based layer index; the vertical axis gives the scalar stored in the public checkpoint. Each scalar multiplies the entire block output after both residual additions. Orange bars mark global layers.

10.6. Projection weights and normalization gains

Some of Gemma 4's input-side RMSNorms have mean gains in the tens or hundreds. The next operation multiplies their outputs by a projection matrix, so interpreting these large gains requires looking at the matrix weights too.
The middle column gives the range of the per-layer mean gain across layers. The right column gives the minimum and maximum over all layers and all components. The final RMSNorm is a single instance, so its mean gain is one value.
RMSNorm implementation nameRange of mean gain (across layers)Min / max over all layers and components
input_layernorm4.9 to 47.6−54 / 1248
post_attention_layernorm0.018 to 1.680.00003 / 20
pre_feedforward_layernorm2.2 to 218−100 / 860
post_feedforward_layernorm0.032 to 1.90.0002 / 50
norm (final)11.4−2.6 / 510
In Gemma 4's projection matrices, the weight standard deviation is close to the inverse square root of the input dimension. Multiplying it by \(\sqrt{\mathrm{fan\_in}}\), where \(\mathrm{fan\_in}\) is the input dimension, gives values between about 0.95 and 1.05.
For a projection immediately after RMSNorm, a larger gain can be offset by smaller matrix weights. Dividing the matrix columns by nonzero factors and multiplying the corresponding gains by those factors preserves the projection output. The size of either set of coefficients must therefore be interpreted together with the other.

Let \(W\) be the projection matrix and \(\hat{x}\) the normalized input before the gain. In column-vector notation, the output is \(W\operatorname{diag}(\gamma)\hat{x}\). Dividing a column of \(W\) by a nonzero factor while multiplying the corresponding gain component by that factor leaves the result unchanged. If several projections share the same RMSNorm output, the corresponding columns in all of them must be transformed together. This is a mathematical equivalence, not evidence that Gemma 4 underwent such a conversion.

A following RMSNorm can also cancel an overall matrix scale. PLaMo 3 has this arrangement after the Q/K, attention-output, and MLP down projections. Multiplying one of these matrices by a positive constant scales the projection output by that constant; if its mean square remains well above \(\epsilon\) before and after, the normalization denominator scales by almost the same amount. Layer 7's small MLP output (§10.3) illustrates a case where this condition fails.

PLaMo 3's projection weights follow a different pattern: from layer 8 onward, their standard deviations lie around 0.0048–0.0068 across input dimensions of 5120, 8192, and 25600. The early MLP exceptions are the ones examined in §10.3.
The distributions also differ beyond their standard deviations. In PLaMo 3's attention output projection, 0.040% of weights lie more than 5 standard deviations from the mean, versus about 0.00006% for a normal distribution. The prevalence of distant values varies substantially by projection type.

Excess kurtosis measures the influence of values far from the mean: it is the fourth standardized moment minus 3, giving zero for a normal distribution.

For PLaMo 3's o_proj, median excess kurtosis across layers is 115, reaching 3506 in layer 16. These large values reflect the strong influence of weights far from the mean. The down_proj matrix in layer 6 reaches 4270, whereas gate/up matrices from layer 8 onward stay at 0.1–0.6.

For Gemma 4, median excess kurtosis across layers, calculated separately for each projection type, ranges from about 0.34 to 3.01. Individual matrices can be higher, including a v_proj at 9.38; the embedding has excess kurtosis 111.

11. Conclusion

The short-input FP32 comparison shows that the formulas and constants reproduce the public forward pass closely. Taking that implementation to long contexts adds a different requirement: the backend must compute within local windows and discard old local K/V entries to realize the architecture's savings. Mask allocation and cache retention therefore need to be checked alongside the model configuration.
The weight analysis likewise depends on following the computation. PLaMo's offsets turn stored normalization weights into effective gains; Gemma's gains must be considered together with the adjacent projections. In the early MLPs, outputs separated by more than five orders of magnitude before normalization become similarly sized residual contributions, with \(\epsilon\) affecting the smallest output. Stored coefficients, the operations applied to them, and activations on an input answer different parts of the architectural question.

References

  1. [1] Preferred Networks, Inc., "PLaMo 3 NICT 2604 31B Base (model card, config.json, modeling_plamo.py; revision e26c257e)," Hugging Face, 2026. (Main subject of this article: the pinned config file, public implementation, and weights)
  2. [2] Preferred Networks, Inc., "PLaMo 3 NICT 2B Base (model card and config.json)," Hugging Face, 2026. (Model-size comparison)
  3. [3] Preferred Networks, Inc., "PLaMo 3 NICT 8B Base (model card and config.json)," Hugging Face, 2026. (Model-size comparison)
  4. [4] Preferred Networks, Inc., "PLaMo 3 610M Fin Instruct (model card and config.json)," Hugging Face, 2026. (Configuration and parameter count of the finance-oriented variant)
  5. [5] Preferred Networks, Inc., "PLaMo 3 NICT 31B Base (model card, config.json, modeling_plamo.py; revision 9c1fa626)," Hugging Face, 2026. (The 4K release with the same layer count and dimensions: comparison weights, and the older implementation that counts the window differently)
  6. [6] Google DeepMind, "Gemma 4 31B (model card and config.json)," Hugging Face, 2026. (Comparison target: config file and weights)
  7. [7] Hugging Face, "modeling_gemma4.py (Transformers v5.12.1)," GitHub, 2026. (Public implementation of Gemma 4's normalization, RoPE, and KV cache)
  8. [8] Shuji Suzuki, "大規模言語モデルの次期バージョン PLaMo 3 シリーズにおける8B, 31Bの小規模モデルによる事前学習の検証," Preferred Networks Tech Blog, 2025. (Background of PLaMo 3's architecture change and the KV cache comparison table; in Japanese)
  9. [9] Iz Beltagy, Matthew E. Peters, Arman Cohan, "Longformer: The Long-Document Transformer," arXiv:2004.05150, 2020. (Longformer, including sliding window attention)
  10. [10] Preferred Networks, Kaizaburo Chubachi, others, "PLaMo 2 Technical Report," arXiv:2509.04897, 2025. (Technical report on the previous generation, PLaMo 2)
  11. [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. (The hybrid of Mamba and SWA adopted by PLaMo 2)
  12. [12] Gemma Team, "Gemma 3 Technical Report," arXiv:2503.19786, 2025. (Gemma 3, with local/global attention and Q/K normalization)
  13. [13] Gemma Team, "Gemma 4 Technical Report," arXiv:2607.02770, 2026. (Gemma 4's 5:1 layer ratio, K reuse in global layers, and p-RoPE)
  14. [14] Biao Zhang, Rico Sennrich, "Root Mean Square Layer Normalization," NeurIPS, 2019. (Original RMSNorm paper)
  15. [15] vLLM Project, "vllm/model_executor/models/plamo3.py (commit d881812)," GitHub, 2026. (Inference implementation that folds the RMSNorm offset into the weights)
  16. [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. [17] Jianlin Su, Murtadha Ahmed, Yu Lu, Shengfeng Pan, Wen Bo, Yunfeng Liu, "RoFormer: Enhanced Transformer with Rotary Position Embedding," Neurocomputing 568, 2024. (Original RoPE paper)
  18. [18] Bowen Peng, Jeffrey Quesnelle, Honglu Fan, Enrico Shippole, "YaRN: Efficient Context Window Extension of Large Language Models," ICLR, 2024. (YaRN)
  19. [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: removing rotation from the low-frequency pairs)
  20. [20] Noam Shazeer, "GLU Variants Improve Transformer," arXiv:2002.05202, 2020. (GLU-family MLPs including SwiGLU)

Last Modified: October 27, 2026