Attention and Language Models

This article starts from the problem a language model is trying to solve, then derives the attention mechanisms used to solve it. We will connect next-token prediction to logits, probabilities, cross-entropy, causal masking, and the components of a modern GPT-style language model. The goal is not to memorize an architecture diagram, but to understand why each computation is present.

本文从 language model 要解决的问题出发,再推导为解决这个问题所需的 attention mechanism。我们会把 next-token prediction 与 logits、概率、cross-entropy、causal mask,以及现代 GPT-style language model 的各个组件连接起来。重点不是背诵一张架构图,而是理解每一步计算为什么存在。

1. Language Modeling

1.1 Next-Token Prediction

A language model assigns probabilities to token sequences. After a tokenizer maps text to $x_1,x_2,\ldots,x_T$, the chain rule writes the probability of the complete sequence as

\[q_\theta(x_1,\ldots,x_T)=\prod_{t=1}^{T}q_\theta(x_t\mid x_{<t}),\]

where $x_{<t}=(x_1,\ldots,x_{t-1})$ is the context available before token $t$, and $\theta$ denotes all trainable parameters. The large sequence problem has therefore become one repeated prediction problem: given a prefix, produce a probability distribution over the next token.

At position $t$, the network produces a vector $z_t\in\mathbb R^{\lvert\mathcal V\rvert}$ with one number for each token in vocabulary $\mathcal V$. These raw scores are logits. They are not probabilities and need not sum to one. Softmax converts them into the next-token distribution:

\[q_\theta(v\mid x_{<t})=\frac{e^{z_{t,v}}}{\sum_{u\in\mathcal V}e^{z_{t,u}}}.\]

During training, the correct next token is known at every position. The model is penalized by $-\log q_\theta(x_t\mid x_{<t})$ and these terms are averaged across tokens. This is next-token cross-entropy; Use of Information Theory in Learning Theory explains why it is both a prediction loss and an expected coding length.

What must the network do before it can produce useful logits? It must turn each token into a representation that contains the relevant information from its prefix. A token embedding by itself only identifies that token; the embedding for “bank” does not say whether the surrounding sentence concerns money or a river. Attention is the mechanism that makes a token representation depend on its context.

Language model 为 token sequence 分配概率。Tokenizer 把文本映射成 $x_1,x_2,\ldots,x_T$ 后,概率的 chain rule 把完整序列的概率写成

\[q_\theta(x_1,\ldots,x_T)=\prod_{t=1}^{T}q_\theta(x_t\mid x_{<t}),\]

其中 $x_{<t}=(x_1,\ldots,x_{t-1})$ 是预测第 $t$ 个 token 前已经可见的 context,$\theta$ 表示所有可训练参数。于是,庞大的序列建模问题变成一个反复出现的预测问题:给定 prefix,输出下一个 token 的概率分布。

在位置 $t$,network 输出向量 $z_t\in\mathbb R^{\lvert\mathcal V\rvert}$,词表 $\mathcal V$ 中的每个 token 对应一个数。这些 raw scores 就是 logits;它们不是概率,也不必加和为 1。Softmax 把它们变成 next-token distribution:

\[q_\theta(v\mid x_{<t})=\frac{e^{z_{t,v}}}{\sum_{u\in\mathcal V}e^{z_{t,u}}}.\]

训练时,每个位置的正确 next token 都已知。模型在该位置受到 $-\log q_\theta(x_t\mid x_{<t})$ 的惩罚,再对所有 token 取平均。这就是 next-token cross-entropy;Use of Information Theory in Learning Theory 解释了为什么它既是 prediction loss,也是 expected coding length。

Network 在产生有用的 logits 之前必须先做什么?它必须把每个 token 变成包含相关 prefix 信息的表示。Token embedding 本身只标识这个 token;“bank”的 embedding 并不能说明上下文在谈银行还是河岸。Attention 正是让 token representation 随 context 改变的机制。

1.2 Autoregressive Training and Generation

At inference time, GPT cannot produce an unknown continuation all at once. Starting from a prompt $x_1,\ldots,x_m$, it computes $q_\theta(x_{m+1}\mid x_{\le m})$, selects or samples one token, appends that token to the context, and repeats. The distribution at the next step depends on the token just chosen, so that step cannot be computed beforehand. Generation is therefore sequential, and it stops when an end token is selected or another stopping rule is reached.

Figure 14: Autoregressive generation. The language model appends one selected token to its context before predicting the next.

During training, however, the complete text $[x_1,\ldots,x_T]$ is already available. The model receives $[x_1,\ldots,x_{T-1}]$ and is supervised against the one-position-shifted targets $[x_2,\ldots,x_T]$. This is often described as teacher forcing: every training position receives the actual preceding tokens from the data rather than tokens sampled from the model. An early prediction error therefore cannot corrupt the context used to train later positions.

Because every training token is known before the forward pass, all positions can enter causal self-attention in one matrix. The mask in Section 2.4 preserves the rule that position $t$ may only use positions up to $t$. The model assigns a probability to the correct next token at every position, and these probabilities are trained with next-token cross-entropy; Use of Information Theory in Learning Theory derives exactly what that loss measures.

The distinction is worth making explicit. During generation, if the model has produced “Welcome to,” the next prediction must condition on the entire available prefix, not only on “to.” During training, the shifted sequence and causal mask expose exactly the corresponding prefix at every position. Training is parallel because those prefixes come from known data; generation is sequential because each new prefix contains a token that has not yet been chosen.

推理时,GPT 不能一次性产生未知的 continuation。从 prompt $x_1,\ldots,x_m$ 出发,它先计算 $q_\theta(x_{m+1}\mid x_{\le m})$,选择或采样一个 token,把该 token 接到 context 后再重复。下一步的分布依赖刚刚选出的 token,因此无法提前计算。生成必然是串行的,直到模型选出 end token 或满足其他停止条件。

图 14:自回归生成。Language model 每选出一个 token,都要先把它接入 context,再预测下一个 token。

但训练时,完整文本 $[x_1,\ldots,x_T]$ 已经可见。模型接收 $[x_1,\ldots,x_{T-1}]$,监督目标则是右移一位的 $[x_2,\ldots,x_T]$。这通常称为 teacher forcing:每个训练位置读到的都是数据中真实的 preceding tokens,而不是从模型中采样的 token。因此,某个较早位置的预测错误不会污染后续位置的训练 context。

因为所有训练 token 在 forward pass 开始前都已知,全部位置可以作为一个矩阵同时进入 causal self-attention。第 2.4 节的 mask 保证位置 $t$ 只能使用不晚于 $t$ 的位置。模型在每个位置为正确的 next token 分配概率,并用 next-token cross-entropy 训练;Use of Information Theory in Learning Theory 详细推导了这个 loss 究竟衡量什么。

这个区别值得明确写出。生成时,若模型已经产生 “Welcome to”,下一次预测必须以整个 prefix 为条件,而不能只看 “to”。训练时,shifted sequence 与 causal mask 会在每个位置暴露完全对应的 prefix。训练可以并行,是因为这些 prefix 来自已经知道的数据;生成必须串行,是因为每个新 prefix 都包含一个尚未选出的 token。

2. Self-Attention

The language-modeling problem above tells us what context is available, but not how to use it. Self-attention gives each token a query, compares that query with the keys of visible tokens, and uses the resulting scores to mix their values. We will begin with one attention head, write it in matrix form, and understand what its weights mean. Sections 2.4 and 2.5 then add causal masking and multiple heads for an autoregressive language model.

上面的 language-modeling problem 告诉了我们哪些 context 可以使用,却没有说明怎样使用。Self-attention 为每个 token 产生 query,将它与所有可见 token 的 key 比较,再用所得分数混合相应的 value。我们先从一个 attention head 开始,把计算写成矩阵形式,并理解其权重的意义;第 2.4 与 2.5 节再加入自回归 language model 所需的 causal mask 与 multiple heads。

2.1 Single-Layer Attention

The diagram below illustrates single-layer self-attention. Assuming an input sequence $x_{1,2,3}$, an embedding layer generates corresponding embeddings $a_{1,2,3}$ for each token. We then define three matrices, $Q, K, V$, as model parameters. For token embedding $a_1$, we multiply it with matrices $Q$ and $K$ to obtain vectors $q_1$ and $k_1$, respectively. Multiplying these two vectors results in an initial attention score, $at_{11}$ (often denoted as $\alpha$). It’s crucial to understand that $at_{11}$ is a scalar value, not a vector. Applying softmax to all attention scores produces normalized values, denoted as $st_{11}$. Simultaneously, $a_1$ is multiplied with matrix $V$ to yield a value vector $v_1$. Multiplying the normalized qk token with the v token gives us a qkv token, $wt_{11}$. By multiplying $q_1$ with the k vectors derived from the second and third tokens in the input sequence, we obtain $wt_{12}$ and $wt_{13}$. Summing these three tokens yields $b_1$. Repeating this process for $q_2$ and $q_3$ yields $b_2$ and $b_3$, respectively. This constitutes the core algorithm behind self-attention.

Figure 3: Single-layer self-attention. All three tokens enter simultaneously — no sequential dependency. The output \(b_1\) is a weighted sum of all value vectors.

Here are some noteworthy points about the diagram:

  1. The only parameters in a self-attention layer are the three matrices: ${W}^Q,{W}^K,{W}^V$.
  2. The output token corresponding to each input token is essentially a weighted sum of key-value pairs from all tokens (including itself) and its own query.
  3. $q, k, v$ are essentially semantic representations of the corresponding token $x$ in the latent space. Token $x$ enters the latent space as $q, k, v$ through ${W}^Q$, $W^K, W^V$.
  4. The output token does not depend on the hidden state of any previous time step.

The fourth point may raise a question: if every position is computed from the same input matrix, how does the model know token order? Order is supplied explicitly by a position representation, which is developed in Section 3.1.

下图展示了单层自注意力。假设输入序列为 $x_{1,2,3}$,嵌入层为每个 token 生成对应的嵌入 $a_{1,2,3}$。然后我们定义三个矩阵 $Q, K, V$ 作为模型参数。对于 token 嵌入 $a_1$,我们将其分别与矩阵 $Q$ 和 $K$ 相乘,得到向量 $q_1$ 和 $k_1$。将这两个向量相乘得到初始注意力分数 $at_{11}$(通常记为 $\alpha$)。关键要理解的是:$at_{11}$ 是一个标量值,不是向量。 对所有注意力分数应用 softmax 得到归一化值,记为 $st_{11}$。同时,$a_1$ 与矩阵 $V$ 相乘得到 value 向量 $v_1$。将归一化的 qk 值与 v 值相乘得到 qkv 值 $wt_{11}$。将 $q_1$ 与输入序列中第二和第三个 token 的 k 向量相乘,得到 $wt_{12}$ 和 $wt_{13}$。将这三个值相加得到 $b_1$。对 $q_2$ 和 $q_3$ 重复此过程分别得到 $b_2$ 和 $b_3$。这就是自注意力背后的核心算法。

图 3:单层自注意力。所有三个 token 同时进入——没有顺序依赖。输出 \(b_1\) 是所有 value 向量的加权和。

关于该图有几个值得注意的要点:

  1. 自注意力层中唯一的参数是三个矩阵:${W}^Q,{W}^K,{W}^V$。
  2. 每个输入 token 对应的输出 token 本质上是来自所有 token(包括自身)的键值对与其自身查询的加权和。
  3. $q, k, v$ 本质上是对应 token $x$ 在潜在空间中的语义表示。Token $x$ 通过 ${W}^Q$, $W^K, W^V$ 以 $q, k, v$ 的形式进入潜在空间。
  4. 输出 token 不依赖于任何先前时间步的隐藏状态。

第四点可能引出一个问题:如果所有位置都从同一个输入矩阵计算,模型如何知道 token 顺序?顺序信息由 position representation 显式提供,第 3.1 节会详细解释。

2.2 Matrix Form

Based on the fourth point, this algorithm can be parallelized using matrices. By concatenating the three vectors $e_{1,2,3}$ into a matrix, we get the following diagram. Since our input sequence has 3 tokens, the Inputs matrix on the left has $n = 3$. This input matrix is multiplied by three parameter matrices to obtain $Q, K, V$. Multiplying $Q$ by $K^T$ produces the attention score matrix. In the diagram, self-attention seems to be applied to each of the three tokens ($x_1, x_2, x_3$) separately. However, their embedding vectors can actually be concatenated for parallel processing. Similarly, concatenating $at_{11, 12, 13}$ forms a row of the attention score matrix (think about why it’s a row, not a column?). Applying row-wise softmax to this attention score matrix yields the normalized attention score matrix $A$, where each row sums to 1. The shape of matrix $A$ is $n\times n$. We will delve deeper into the mathematical significance of matrix $A$ later. Finally, multiplying matrix $A$ with $V$ produces the final matrix $Z$, with a shape of $n\times d_v$. This signifies that we have $n$ tokens, with each token now possessing a value of length $d_v$.

Figure 4: Matrix form of self-attention. Hover over each stage to follow the shapes from \(X\) to \(Z\).

Now, let’s examine the official formula for self-attention:

\[AT(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_k}})V\]

Here, $Q, K, V$ represent the hidden state matrices resulting from multiplying the input matrix $X$ with three parameter matrices, respectively. $d_k$ represents the number of columns in the matrix $W_k$.

Why divide by $\sqrt{d_k}$? One unscaled score is a dot product,

\[s_{ij}=q_i^\top k_j=\sum_{m=1}^{d_k}q_{im}k_{jm}.\]

For intuition, suppose the components are independent, have mean zero and variance one. Each product $q_{im}k_{jm}$ then has mean zero and variance one, so the sum has

\[\mathbb E[s_{ij}]=0,\qquad \operatorname{Var}(s_{ij})=d_k.\]

Its typical magnitude therefore grows like $\sqrt{d_k}$. Large score differences push softmax toward nearly one-hot outputs, where most probabilities—and their gradients—are tiny. Scaling gives

\[\operatorname{Var}\!\left(\frac{s_{ij}}{\sqrt{d_k}}\right)=\frac{1}{d_k}\operatorname{Var}(s_{ij})=1,\]

keeping the scale entering softmax roughly stable as the key dimension changes. The independence assumption is only a motivating approximation, but it explains the normalization.

To isolate the scaling effect, the small figure below uses a deliberately simple toy setting. One query compares exactly two independent candidate keys. The query and key coordinates are assumed independent, with zero mean and unit variance, just as in the variance argument above; neither key has a systematic score advantage. The head width is fixed at 64. Under these assumptions, a representative one-standard-deviation positive score gap is about 11.3 before scaling and about 1.41 after scaling; these are the red and blue marker positions.

With two candidates, softmax depends only on the signed score gap—the first key’s score minus the second key’s score. As that gap ranges from negative to positive, the first key’s weight follows exactly a sigmoid curve, not an arbitrary fitted curve. A negative gap gives the first key little weight, zero gap gives the keys equal weight, and a positive gap gives the first key most of the weight. The left panel of the figure draws this complete sigmoid. The right panel draws the local slope of that same sigmoid: how much the attention weight responds to a tiny change in the gap. It is one softmax sensitivity factor through which gradients pass, not the complete loss gradient. The unscaled red marker lies in a flat tail; the scaled blue marker remains in a region with visible slope. Only the gap matters—a large common offset changes neither marker.

Left: the complete sigmoid obtained from two-key softmax. Right: the slope of that same sigmoid.

基于第四点,该算法可以使用矩阵进行并行化。将三个向量 $e_{1,2,3}$ 拼接成一个矩阵,就得到下图。由于输入序列有 3 个 token,左侧的 Inputs 矩阵有 $n = 3$。将该输入矩阵与三个参数矩阵相乘得到 $Q, K, V$。将 $Q$ 与 $K^T$ 相乘即可得到注意力分数矩阵。在图中,自注意力似乎分别应用于三个 token($x_1, x_2, x_3$)。但实际上它们的嵌入向量可以拼接起来并行处理。同样,拼接 $at_{11, 12, 13}$ 构成注意力分数矩阵的一行(想想为什么是一行而不是一列?)。对该注意力分数矩阵按行做 softmax 得到归一化注意力分数矩阵 $A$,其中每行之和为 1。矩阵 $A$ 的形状是 $n\times n$。我们稍后将深入探讨矩阵 $A$ 的数学意义。最后,将矩阵 $A$ 与 $V$ 相乘得到最终矩阵 $Z$,形状为 $n\times d_v$。这意味着我们有 $n$ 个 token,每个 token 现在拥有长度为 $d_v$ 的 value。

图 4:自注意力的矩阵形式。将鼠标移到各阶段上,可沿 shape 从 \(X\) 追踪到 \(Z\)。

现在让我们来看自注意力的正式公式:

\[AT(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_k}})V\]

其中,$Q, K, V$ 分别是输入矩阵 $X$ 与三个参数矩阵相乘后得到的隐藏状态矩阵。$d_k$ 表示矩阵 $W_k$ 的列数。

为什么要除以 $\sqrt{d_k}$?一个未经 scaling 的 score 是 dot product:

\[s_{ij}=q_i^\top k_j=\sum_{m=1}^{d_k}q_{im}k_{jm}.\]

为了建立直觉,假设各 coordinate 相互独立,均值为 0、方差为 1。每个乘积 $q_{im}k_{jm}$ 的均值就是 0、方差为 1,因此求和后有

\[\mathbb E[s_{ij}]=0,\qquad \operatorname{Var}(s_{ij})=d_k.\]

所以其典型大小会随 $\sqrt{d_k}$ 增长。过大的 score 差异会使 softmax 接近 one-hot,大多数 probability 及其 gradient 都变得很小。Scaling 后则有

\[\operatorname{Var}\!\left(\frac{s_{ij}}{\sqrt{d_k}}\right)=\frac{1}{d_k}\operatorname{Var}(s_{ij})=1,\]

从而在 key dimension 改变时,让进入 softmax 的尺度大致稳定。独立性假设只是用于解释动机的近似,但它清楚说明了 normalization 的来源。

为了单独观察 scaling 的作用,下面的小图采用一个刻意简化的 toy setting:一个 query 只比较两个相互独立的 candidate keys。与上面的 variance argument 一致,假设 query 与 keys 的各 coordinates 相互独立、均值为零、方差为一,并且两个 keys 都没有系统性的 score advantage。Head width 固定为 64。在这些假设下,一个具有代表性的、相差一个 standard deviation 的正向 score gap,在 scaling 前约为 11.3,scaling 后约为 1.41;图中的红色与蓝色 marker 就放在这两个位置。

只有两个 candidates 时,softmax 只依赖 signed score gap,也就是第一个 key 的 score 减去第二个 key 的 score。当这个 gap 从负数变到正数时,第一个 key 获得的 weight 严格形成一条 sigmoid curve,并不是随意拟合的 curve:gap 为负时第一个 key 获得很小的 weight,gap 为零时两个 keys 平分 weight,gap 为正时第一个 key 获得大部分 weight。图的左侧画出这条完整 sigmoid;右侧画出同一条 sigmoid 的局部斜率,也就是 gap 发生微小变化时 attention weight 能改变多少。它是 gradient 会经过的一个 softmax sensitivity factor,并不是完整的 loss gradient。Unscaled 红色 marker 落在平坦尾部,scaled 蓝色 marker 仍位于有明显斜率的区域。只有 gap 重要,共同 offset 很大并不会移动 marker。

左图:two-key softmax 得到的完整 sigmoid;右图:同一条 sigmoid 的斜率。

2.3 Essence of Self-Attention

Let’s delve into the essence of the official self-attention formula. Firstly, it’s essential to acknowledge that the three matrices $Q,K,V$ are essentially linear transformations of the input matrix $X$, representing $X$ semantically in the latent space. In other words, it’s possible to train the model without the matrices ${W}^Q,{W}^K,{W}^V$, but the complexity would be insufficient, impacting the model’s performance. For clarity, we’ll use $X$ as a toy substitute for all three matrices, while retaining the scale factor. Each entry of $XX^{\mathsf T}$ sums $d_k$ coordinate products. If those products are roughly independent with unit variance, the dot product has variance $d_k$ and a typical magnitude proportional to $\sqrt{d_k}$. Dividing by $\sqrt{d_k}$ keeps the score scale approximately constant as the vector width grows, preventing softmax from becoming artificially sharp merely because more coordinates were added. The toy formula is therefore:

\[AT(X)=softmax\!\left(\frac{XX^{\mathsf T}}{\sqrt{d_k}}\right)X.\]

Consider the sentence “Welcome to Starbucks.” If the embedding layer employs simple 2-hot encoding (e.g., “Welcome” is encoded as 1010), we can represent the input matrix $X$ as shown on the left side of the diagram below. Multiplying this matrix with its transpose yields a matrix that’s essentially an attention matrix, as depicted on the right side of the diagram.

Figure 5: Computing \(XX^T\) with 2-hot encodings. The resulting matrix captures pairwise token similarity.

What does this attention matrix represent? Examining the first row, we see that this row essentially calculates the similarity between the token “Welcome” and all other tokens in the sentence. The essence of similarity between word vectors is attention. If token A and token B frequently co-occur, their similarity tends to be high. For instance, in the diagram, “Welcome” exhibits high similarity with itself and “Starbucks,” indicating that these two tokens should receive higher attention when inferring the token “Welcome.”

Normalizing this result using softmax gives us the normalized attention matrix shown on the right side of the diagram below. After normalization, this attention matrix becomes a coefficient matrix, ready to be multiplied with the original matrix.

Figure 6: Row-wise softmax normalizes the attention matrix so each row sums to 1.

The final step involves right-multiplying the normalized attention matrix $\alpha$ with the input matrix $X$, resulting in the matrix $\hat X$, as illustrated below. What does this step essentially achieve? The highlighted first row of the left matrix will be multiplied and summed with each column of the input matrix $X$ to compute each value in the first row of the output matrix. Since the first row of the $\alpha$ matrix represents the attention values of the token “Welcome” towards all tokens, the first row of the output matrix $\hat X$ becomes the attention-weighted embedding of the token “Welcome.”

Figure 7: The final multiplication \(\hat{X} = \alpha X\). Each row of \(\hat{X}\) is the attention-weighted embedding of the corresponding token.

In summary, given an input matrix $\mathsf{X}$, self-attention outputs a matrix $\hat X$, which is the attention-weighted semantic representation matrix of the input matrix.

让我们深入探讨自注意力正式公式的本质。首先,必须认识到三个矩阵 $Q,K,V$ 本质上是输入矩阵 $X$ 的线性变换,在潜在空间中语义化地表示 $X$。换句话说,不使用矩阵 ${W}^Q,{W}^K,{W}^V$ 也可以训练模型,但复杂度不足会影响模型性能。为了建立一个 toy view,下面暂时用同一个 $X$ 代替三个矩阵,但保留 scale factor。$XX^{\mathsf T}$ 的每个 entry 都是 $d_k$ 个 coordinate products 的和;若这些乘积近似独立且 variance 为 1,dot product 的 variance 就是 $d_k$,典型大小会随 $\sqrt{d_k}$ 增长。除以 $\sqrt{d_k}$ 后,score scale 不会仅仅因为 vector width 增大而变大,从而避免 softmax 无端变得过于尖锐。因此 toy formula 是:

\[AT(X)=softmax\!\left(\frac{XX^{\mathsf T}}{\sqrt{d_k}}\right)X.\]

考虑句子 “Welcome to Starbucks.”。如果嵌入层采用简单的 2-hot 编码(例如,”Welcome” 编码为 1010),我们可以将输入矩阵 $X$ 表示为下图左侧所示。将该矩阵与其转置相乘得到一个本质上是注意力矩阵的矩阵,如下图右侧所示。

图 5:使用 2-hot 编码计算 \(XX^T\)。结果矩阵捕获了 token 之间的成对相似度。

这个注意力矩阵代表什么?查看第一行,我们可以看到这一行本质上计算了 token “Welcome” 与句子中所有其他 token 的相似度。词向量之间相似度的本质就是注意力。如果 token A 和 token B 经常共同出现,它们的相似度往往很高。例如,在图中,”Welcome” 与自身和 “Starbucks” 展现出高相似度,表明在推断 token “Welcome” 时这两个 token 应获得更高的注意力。

对该结果使用 softmax 归一化得到下图右侧所示的归一化注意力矩阵。归一化后,该注意力矩阵变成系数矩阵,可以与原始矩阵相乘。

图 6:按行 softmax 将注意力矩阵归一化,使每行之和为 1。

最后一步是将归一化注意力矩阵 $\alpha$ 右乘输入矩阵 $X$,得到矩阵 $\hat X$,如下图所示。这一步本质上实现了什么?左侧矩阵高亮显示的第一行将与输入矩阵 $X$ 的每一列相乘并求和,计算输出矩阵第一行的每个值。由于 $\alpha$ 矩阵的第一行表示 token “Welcome” 对所有 token 的注意力值,因此输出矩阵 $\hat X$ 的第一行成为 token “Welcome” 的注意力加权嵌入。

图 7:最终乘法 \(\hat{X} = \alpha X\)。\(\hat{X}\) 的每一行是对应 token 的注意力加权嵌入。

总之,给定输入矩阵 $\mathsf{X}$,自注意力输出矩阵 $\hat X$,即输入矩阵的注意力加权语义表示矩阵。

2.4 Query, Key, Value, and Causal Masking

While the matrices $W^Q, W^K, W^V$ aren’t strictly necessary, and we know that attention weighting can be achieved using $X$ alone, the performance would be suboptimal. It’s natural to wonder how the QKV concept came about and its underlying rationale.

Why choose the names QKV? Q stands for Query, K for Key, and V for Value. The database analogy is useful if applied carefully: a query is compared with searchable keys, while each key is paired with the value that will be returned if that key receives weight. There is one key and one value per token position, so K and V contain the same number of rows. Unlike an ordinary database lookup, the result is usually not one value; it is a weighted mixture of several values.

The following interactive snippet makes the tensor contractions in a minimal implementation explicit. Select either einsum expression to inspect which axes are retained and which axis is summed out.

Interactive snippet: reading the two einsum expressions in scaled dot-product attention.

虽然矩阵 $W^Q, W^K, W^V$ 并非严格必要,我们知道仅使用 $X$ 就能实现注意力加权,但性能会不够理想。很自然地会好奇 QKV 概念的来源及其背后的原理。

为什么选择 QKV 这个名称?Q 代表 Query,K 代表 Key,V 代表 Value。Database analogy 只有在谨慎使用时才准确:query 与可搜索的 keys 比较,每个 key 则和一个 value 配对;只要这个 key 获得 weight,对应 value 就会进入结果。每个 token position 都有一个 key 和一个 value,因此 K 与 V 的 row 数相同。与普通 database lookup 不同,结果通常不是某一个 value,而是多个 values 的 weighted mixture。

下面的 interactive snippet 把 minimal implementation 中的 tensor contractions 完整展开。选择任意一个 einsum expression,即可检查哪些 axes 被保留、哪个 axis 被求和消去。

交互式 snippet:逐项读取 scaled dot-product attention 中的两个 einsum expressions。

Shifting the targets is not sufficient by itself. Without a mask, the representation at an early position could attend to later tokens in the same training sequence. It would then use the answer it is supposed to predict—a direct form of data leakage. Causal self-attention enforces the language-modeling factorization by allowing row $i$ to use only columns $j\le i$.

For query $q_t$, this means that only $k_1,\ldots,k_t$ may receive weight and only their paired values $v_1,\ldots,v_t$ may enter the output:

\[o_t=\sum_{s\le t}\alpha_{t,s}v_s, \qquad \alpha_{t,s}=0\ \text{for }s>t.\]

In Figure 8, select $q_1$, $q_2$, or $q_3$. Query $q_1$ can use only $(k_1,v_1)$; $q_2$ can use the first two pairs; $q_3$ can use all three. The dashed future paths contribute nothing. Training can compute all three query rows in parallel, but parallel computation does not imply future access.

Figure 8: Causal QKV retrieval. Query q_t mixes only values whose paired keys occur at positions s ≤ t.

Switch the figure to Matrix view to follow the complete computation and the shape of every matrix:

\[\boxed{ S=\frac{QK^{\mathsf T}}{\sqrt{d_k}} \quad\longrightarrow\quad \widetilde S=S+M \quad\longrightarrow\quad A=\operatorname{softmax}_{\mathrm{row}}(\widetilde S) \quad\longrightarrow\quad O=AV.}\]

The additive mask makes the causal rule concrete:

\[M_{t,s}=\begin{cases} 0,&s\le t,\\ -\infty,&s>t. \end{cases}\]

Thus the allowed region is lower triangular, while the upper-triangular future scores are replaced by $-\infty$ before softmax. Figure 16 isolates this pattern.

Figure 16: Causal mask. The upper triangle is set to \(-\infty\) before softmax, preventing each position from attending to future tokens.

The dense multiplication may temporarily compute $S_{1,3}=q_1^{\mathsf T}k_3/\sqrt{d_k}$. Computing that number is not yet the same as transmitting information from $v_3$. The mask changes it to $-\infty$, row-wise softmax produces $A_{1,3}=0$, and the multiplication $AV$ therefore assigns $v_3$ coefficient zero in $o_1$. The order matters: if ordinary softmax ran before masking, the future score would enter the denominator, and simply zeroing its weight afterward would leave the allowed weights incorrectly normalized.

The database analogy now receives its final qualification: each output row represents a token after integrating information only from its available prefix, not from the complete sequence. Later rows have a larger searchable prefix than earlier rows. Backpropagation learns Q and K projections that produce useful routing weights and a V projection that produces useful content.

只右移 target 仍然不够。若没有 mask,较早位置的表示可以关注同一训练序列中更晚的 token,从而直接利用本应预测的答案,造成 data leakage。Causal self-attention 通过只允许第 $i$ 行使用满足 $j\le i$ 的列,严格实现 language-modeling factorization。

对于 query $q_t$,这意味着只有 $k_1,\ldots,k_t$ 可以获得 weight,也只有与它们配对的 $v_1,\ldots,v_t$ 能够进入输出:

\[o_t=\sum_{s\le t}\alpha_{t,s}v_s, \qquad \alpha_{t,s}=0\ \text{ when }s>t.\]

在图 8 中依次选择 $q_1$、$q_2$ 或 $q_3$:$q_1$ 只能使用 $(k_1,v_1)$;$q_2$ 可以使用前两对;$q_3$ 才能使用全部三对。虚线表示的 future paths 对结果没有贡献。Training 可以并行计算三条 query rows,但 parallel computation 并不意味着能够访问 future。

图 8:Causal QKV 检索。Query q_t 只混合与位置 s ≤ t 的 keys 配对的 values。

将图切换到矩阵视角,可以追踪完整 computation 以及每个 matrix 的 shape:

\[\boxed{ S=\frac{QK^{\mathsf T}}{\sqrt{d_k}} \quad\longrightarrow\quad \widetilde S=S+M \quad\longrightarrow\quad A=\operatorname{softmax}_{\mathrm{row}}(\widetilde S) \quad\longrightarrow\quad O=AV.}\]

Additive mask 把 causal rule 写成:

\[M_{t,s}=\begin{cases} 0,&s\le t,\\ -\infty,&s>t. \end{cases}\]

所以 allowed region 是 lower triangular,upper-triangular future scores 则在 softmax 前被替换成 $-\infty$。图 16 单独展示了这个 pattern。

图 16:因果掩码。上三角在 softmax 之前设为 \(-\infty\),防止每个位置关注未来 token。

Dense multiplication 可能暂时算出 $S_{1,3}=q_1^{\mathsf T}k_3/\sqrt{d_k}$。但算出这个 number,还不等于已把 $v_3$ 的信息传给 $q_1$。Mask 先把它改成 $-\infty$,row-wise softmax 随后产生 $A_{1,3}=0$,所以在乘法 $AV$ 中,$v_3$ 在 $o_1$ 里的 coefficient 为零。Operation order 非常重要:如果先执行普通 softmax,future score 就会进入 denominator;之后仅把它的 weight 清零,会使 allowed weights 的 normalization 出错。

现在可以为 database analogy 加上最后的限定:每条 output row 只表示 token 整合其可用 prefix信息后的 representation,而不是整合 complete sequence。越靠后的 row 拥有越大的 searchable prefix。Backpropagation 会学习产生有效 routing weights 的 Q、K projections,以及产生有效内容的 V projection。

2.5 Multi-Head Attention

A single head produces one similarity matrix and therefore one way of routing context at each layer. GPT-style language models use multiple heads so the same token can form several attention patterns in parallel—for example, one pattern may retrieve a nearby syntactic cue while another retrieves a distant name. Multi-head attention is the same operation derived above, applied to several learned subspaces.

Interactive implementation of a multi-head attention layer.

The diagram below illustrates the structure of multi-head attention. Formally, multi-head attention is defined as:

\[\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h) W^O, \quad \text{head}_i = \text{Attention}(Q W_i^Q, K W_i^K, V W_i^V)\]

where \(W_i^Q \in \mathbb{R}^{d_{\text{model}} \times d_k}\), \(W_i^K \in \mathbb{R}^{d_{\text{model}} \times d_k}\), \(W_i^V \in \mathbb{R}^{d_{\text{model}} \times d_v}\), and \(W^O \in \mathbb{R}^{hd_v \times d_{\text{model}}}\). This mechanism divides the three matrices $W^Q,W^K,W^V $ into multiple smaller matrices. For instance, in a two-head attention setup, $W_Q$ is split into two smaller matrices, $W^{q_1}$ and $W^{q_2}$. Consequently, the $q$ matrix generated from $a_1$ can also be divided into two smaller matrices, $q_{11}$ and $q_{12}$, which we call attention heads. After obtaining multiple heads, the corresponding qkv heads perform single-layer attention separately, resulting in multiple outputs. For example, two heads would yield $b_{11}$ and $b_{12}$ as outputs. These outputs from different heads are then aggregated into a single output vector, $b_1$. Notice a detail in the diagram: $q_{21}$ is not used when calculating $b_1$. Think about why. Since $b_1$ represents the latent space representation of the query $a_1$, it cannot involve the query $a_2$. Refer back to the Query, Key, Value section if this isn’t clear. Once all heads have completed their calculations, an affine matrix $W_o$ is applied to aggregate information from all heads. The shapes of the matrices are indicated in the diagram. Assuming the maximum sentence length is 256 tokens and the embedding size is 1024, the shape of $a_1$ would be (256, 1024). The shapes of other matrices are also shown in the diagram.

Figure 17: Multi-head attention. The Q, K, V matrices are split into multiple heads, each performing attention independently before concatenation.

Is the sole purpose of adding heads merely to increase the number of parameters? If so, we could simply enlarge the hidden size of $W^Q, W^K, W^V$. Why achieve this by adding heads?

Usually it does not increase the QKV parameter count. If the model width is $d$ and each of $h$ heads has width $d_h=d/h$, then all query projections together still map $d$ dimensions to $h d_h=d$ dimensions. The point is structural: every head has its own softmax distribution. Enlarging one head gives a wider value vector but still only one attention pattern; using $h$ heads produces $h$ independently normalized patterns and lets $W^O$ combine their retrieved information.

During the training of the multi-head attention mechanism, due to differences in parameter initialization, we have $q_{11} \neq q_{12}$. Similarly, we have $st_{111} \neq st_{121}$ and $b_{11} \neq b_{12}$. However, since $b_{11}$ and $b_{12}$ are concatenated, the gradient flow during backpropagation is symmetrical for these two paths. Different initialization methods lead to heads learning different feature selection capabilities.

Analyses of trained language models often find heads that emphasize syntax, local context, delimiters, or rare identifying tokens. This specialization is not hard-coded and is not guaranteed: some heads become redundant. It is an optimization outcome made possible by separate projection matrices and separate softmax maps. The gradients that create these roles are computed by backpropagation; Backpropagation develops that mechanism from the chain rule.

Let’s ponder another question: what are the significant drawbacks of using multi-layer attention (stacking multiple single-layer attention layers) instead of multi-head attention? There are substantial parallelization limitations. Multi-head attention can be easily parallelized because different heads receive the same input and perform the same computations. In contrast, due to the stacked structure of multi-layer attention, upper layers must wait for computations in lower layers to complete before proceeding, hindering parallelization. The time complexity increases linearly with the number of layers. Therefore, from a parallelization standpoint, multi-head attention is often preferred.

More heads are not automatically better. At fixed model width, increasing $h$ makes every head narrower, so head count trades per-head expressivity against the number of distinct attention maps. What makes the computation efficient is that all heads act on the same input and can be evaluated in parallel before concatenation.

单个 head 只产生一个 similarity matrix,因此每层只有一种 routing context 的方式。GPT-style language model 使用多个 head,让同一个 token 可以并行形成多种 attention pattern:例如一个 pattern 检索邻近的语法线索,另一个检索远处出现的名称。Multi-head attention 就是把前面推导的同一种运算应用到多个 learned subspace。

Multi-head attention layer 的交互式实现。

下图展示了多头注意力的结构。形式上,多头注意力定义为:

\[\text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \ldots, \text{head}_h) W^O, \quad \text{head}_i = \text{Attention}(Q W_i^Q, K W_i^K, V W_i^V)\]

其中 \(W_i^Q \in \mathbb{R}^{d_{\text{model}} \times d_k}\),\(W_i^K \in \mathbb{R}^{d_{\text{model}} \times d_k}\),\(W_i^V \in \mathbb{R}^{d_{\text{model}} \times d_v}\),\(W^O \in \mathbb{R}^{hd_v \times d_{\text{model}}}\)。这个机制将三个矩阵 $W^Q,W^K,W^V$ 分成多个更小的矩阵。例如,在双头注意力设置中,$W_Q$ 被分成两个较小的矩阵 $W^{q_1}$ 和 $W^{q_2}$。因此,从 $a_1$ 生成的 $q$ 矩阵也可以分成两个较小的矩阵 $q_{11}$ 和 $q_{12}$,我们称之为注意力头。 获得多个头后,对应的 qkv 头分别执行单层注意力,产生多个输出。例如,两个头会产生 $b_{11}$ 和 $b_{12}$ 作为输出。来自不同头的输出然后聚合成单个输出向量 $b_1$。注意图中一个细节:计算 $b_1$ 时没有使用 $q_{21}$。想想为什么。由于 $b_1$ 代表查询 $a_1$ 的潜在空间表示,它不能涉及查询 $a_2$。如果不清楚,请回顾 Query, Key, Value 部分。所有头完成计算后,应用仿射矩阵 $W_o$ 来聚合所有头的信息。矩阵的形状在图中标出。假设最大句子长度为 256 个 token,嵌入大小为 1024,则 $a_1$ 的形状为 (256, 1024)。其他矩阵的形状也在图中标出。

图 17:多头注意力。Q、K、V 矩阵被分成多个头,每个头独立执行注意力,然后拼接。

增加头的唯一目的仅仅是增加参数数量吗?如果是这样,我们可以简单地增大 $W^Q, W^K, W^V$ 的隐藏大小。为什么要通过添加头来实现?

通常它不会增加 QKV 的参数量。若 model width 为 $d$,$h$ 个 head 各自宽 $d_h=d/h$,那么所有 query projection 合起来仍然是从 $d$ 维映射到 $h d_h=d$ 维。关键在结构:每个 head 都有独立的 softmax distribution。把一个 head 加宽,只会得到更宽的 value vector,却仍只有一种 attention pattern;使用 $h$ 个 head 会产生 $h$ 个独立归一化的 pattern,再由 $W^O$ 混合取回的信息。

在多头注意力机制的训练过程中,由于参数初始化的差异,我们有 $q_{11} \neq q_{12}$。同样,$st_{111} \neq st_{121}$ 且 $b_{11} \neq b_{12}$。然而,由于 $b_{11}$ 和 $b_{12}$ 是拼接的,反向传播过程中这两条路径的梯度流是对称的。不同的初始化方法导致头学习到不同的特征选择能力。

对训练后 language model 的分析经常发现,有些 head 强调语法、局部 context、delimiter 或罕见的标识性 token。这种分工没有被硬编码,也不保证发生;有些 head 会变得冗余。独立 projection matrix 与独立 softmax map 提供了形成不同角色的可能,实际角色则是 optimization 的结果。产生这些角色的 gradient 由 backpropagation 计算;Backpropagation 从 chain rule 开始推导了这个机制。

让我们再思考一个问题:使用多层注意力(堆叠多个单层注意力层)而非多头注意力有什么显著缺点?存在大量的并行化限制。 多头注意力可以轻松并行化,因为不同的头接收相同的输入并执行相同的计算。相比之下,由于多层注意力的堆叠结构,上层必须等待下层计算完成才能继续,阻碍了并行化。时间复杂度随层数线性增加。 因此,从并行化的角度来看,多头注意力通常更受青睐。

更多 head 并不自动更好。在 model width 固定时,增加 $h$ 会让每个 head 变窄,所以 head count 是“每个 head 的表达能力”与“独立 attention map 的数量”之间的权衡。它之所以计算高效,是因为所有 head 接收同一个 input,可以并行计算后再拼接。

3. Embeddings

Attention operates on vectors, but a tokenizer initially gives the model only discrete token IDs. The embedding stage must therefore answer two separate questions: what token is this? and where does it occur? Token embeddings represent identity and learned lexical features; position embeddings represent order. Their sum forms the initial residual-stream vector consumed by the first block.

Attention 处理的是 vector,但 tokenizer 最初交给模型的只是离散 token ID。因此 embedding stage 必须分别回答两个问题:这是什么 token?以及它出现在哪里?Token embedding 表示 token identity 与学到的 lexical feature,position embedding 表示顺序;两者相加后形成第一个 block 所读取的初始 residual-stream vector。

3.1 Position Embeddings

Self-attention by itself is permutation equivariant: if we reorder the rows of $X$, the output rows are reordered in exactly the same way. The operation can compare token contents, but nothing in $QK^T$ says that one row came before another. A language model, however, must distinguish “dog bites man” from “man bites dog” and must know which tokens belong to the prefix of the current prediction.

We therefore give the model a vector $p_t$ that identifies or relates to position $t$. The simplest integration is additive: if token embedding $e(x_t)$ and position representation $p_t$ both have width $d$, the layer receives

\[h_t^{(0)}=e(x_t)+p_t.\]

The vector $p_t$ can be learned directly as a parameter for every allowed position, generated deterministically, or applied to queries and keys as a relative-position operation. The following deterministic construction is useful because its behavior can be inspected exactly.

A classic construction is sinusoidal positional encoding. For a token at position $t$, embedding dimension $d$, and dimension-pair index $i$, even and odd coordinates use sine and cosine at the same frequency:

Equivalently, $\omega_i=10000^{-2i/d}$, so the pair is $[\sin(t\omega_i),\cos(t\omega_i)]$. Here $t$ identifies the token position, while $i$ identifies a pair of embedding coordinates; they are different indices. Notice that the resulting $p_t$ has the same length $d$ as the token embedding. It can therefore be added directly to that semantic embedding. Extending $t$ across the sequence produces a matrix. For example, given “I am a Robot” with 4 tokens and $d=4$, we obtain the following $4\times4$ matrix. Each row is one $p_t$.

Figure 9: Sinusoidal positional encoding matrix for "I am a Robot" (4 tokens, \(d = 4\)). Hover over a cell to inspect its frequency and value.

The first row corresponds to $t=0$. Every sine coordinate is then $\sin(0)=0$ and every cosine coordinate is $\cos(0)=1$. For $d=4$, the two frequencies are $\omega_0=1$ and $\omega_1=0.01$, so the next row is $[\sin(1),\cos(1),\sin(0.01),\cos(0.01)]$. Repeating this calculation produces the matrix.

How do we interpret this method? It leverages the periodicity of the cosine function. In fact, as long as we can find multiple functions with different periods but similar characteristics (e.g., the waveform of cosine functions is the same), they can theoretically be used for positional encoding. For instance, we can employ binary positional encoding instead of sinusoidal encoding. As shown in the diagram below, assuming a sequence with 16 tokens and an embedding size of 4, we can obtain the positional embedding for each token using binary encoding:

Figure 10: Binary positional encoding for 16 tokens. Hover over a bit to inspect its switching rate and period.

Clearly, the least significant bit changes very rapidly (period of 2), while the most significant bit changes the slowest (period of 16). Each coordinate thus operates at a different scale, and together the bits uniquely identify a position. Binary encoding illustrates the multi-scale idea; sinusoidal encoding gives a smooth version. GPT-style language models may instead learn an absolute position embedding or encode relative displacement by rotating queries and keys. The latter construction is developed in RoPE and M-RoPE.

Self-attention 本身是 permutation equivariant:若重新排列 $X$ 的行,输出也只会以完全相同的方式重新排列。它可以比较 token content,但 $QK^T$ 中没有任何信息说明哪一行先出现。Language model 却必须区分 “dog bites man” 与 “man bites dog”,也必须知道哪些 token 属于当前预测的 prefix。

因此,我们给模型一个标识位置 $t$ 或描述其相对关系的向量 $p_t$。最简单的整合方式是相加:若 token embedding $e(x_t)$ 与 position representation $p_t$ 都是 $d$ 维,则 layer 接收

\[h_t^{(0)}=e(x_t)+p_t.\]

$p_t$ 可以是每个允许位置独立学习的 parameter,也可以由确定性公式产生,还可以作为 relative-position operation 直接作用于 query 与 key。下面先看一种可以精确观察其行为的确定性构造。

一种经典构造是正弦位置编码。对于位置为 $t$ 的 token、嵌入维度 $d$ 和维度对索引 $i$,偶数与奇数坐标使用频率相同的正弦和余弦:

等价地,令 $\omega_i=10000^{-2i/d}$,这一对坐标就是 $[\sin(t\omega_i),\cos(t\omega_i)]$。这里 $t$ 表示 token 的位置,$i$ 表示一对嵌入坐标;它们是两个不同的索引。所得 $p_t$ 的长度与 token embedding 同为 $d$,因此可以直接与语义 embedding 相加。让 $t$ 遍历整个序列便得到一个矩阵。例如,输入 “I am a Robot” 有 4 个 token,且 $d=4$,就得到下面的 $4\times4$ 矩阵;每一行都是一个 $p_t$。

图 9:"I am a Robot" 的正弦位置编码矩阵(4 个 token,\(d = 4\))。将鼠标移到单元格上可查看其频率和数值。

第一行对应 $t=0$。此时所有 sine coordinate 都是 $\sin(0)=0$,所有 cosine coordinate 都是 $\cos(0)=1$。当 $d=4$ 时,两组频率为 $\omega_0=1$ 与 $\omega_1=0.01$,所以下一行是 $[\sin(1),\cos(1),\sin(0.01),\cos(0.01)]$。对每个位置重复计算即可得到整个矩阵。

如何理解这种方法?它利用了余弦函数的周期性。实际上,只要能找到多个具有不同周期但特征相似的函数(例如余弦函数的波形相同),理论上都可以用于位置编码。例如,我们可以使用二进制位置编码代替正弦编码。如下图所示,假设序列有 16 个 token,嵌入大小为 4,我们可以使用二进制编码得到每个 token 的位置嵌入:

图 10:16 个 token 的二进制位置编码。将鼠标移到 bit 上可查看其翻转速度与周期。

显然,最低有效位变化非常快(周期为 2),而最高有效位变化最慢(周期为 16)。每个坐标因而工作在不同尺度上,合在一起可以唯一标识位置。二进制编码直观展示了这种多尺度思想,正弦编码则给出平滑版本。GPT-style language model 也可以直接学习 absolute position embedding,或通过旋转 query 和 key 来编码相对位移;后一种构造见 RoPE and M-RoPE。

3.2 Token Embeddings

Let the vocabulary contain $\lvert\mathcal V\rvert$ tokens and let the model width be $d$. A learned embedding table

\[E\in\mathbb R^{\lvert\mathcal V\rvert\times d}\]

stores one $d$-dimensional row for every token ID. If the tokenizer emits ID $x_t$, the lookup $e(x_t)=E[x_t]$ selects that row. This is equivalent to multiplying a one-hot vector by $E$, but a lookup avoids constructing a mostly zero vector.

The table is learned with the rest of the model. Tokens that play similar roles may acquire useful geometric relationships, but the lookup alone is context-free: the same token ID always starts from the same row. Attention later turns this base vector into a context-dependent representation. This distinction is why the word “bank” can begin with one token embedding yet end with a different hidden representation in a financial sentence than in a sentence about a river.

Many language models also reuse the same table at the output. With weight tying, a final hidden state $h_t\in\mathbb R^d$ produces vocabulary logits such as

\[z_t=Eh_t+b.\]

The input side selects a row from $E$; the output side compares $h_t$ with every row at once. Sharing these weights reduces parameters and connects the space used to read tokens with the space used to predict them.

设词表含有 $\lvert\mathcal V\rvert$ 个 token,model width 为 $d$。一个可学习的 embedding table

\[E\in\mathbb R^{\lvert\mathcal V\rvert\times d}\]

为每个 token ID 保存一行 $d$ 维 vector。Tokenizer 在位置 $t$ 输出 ID $x_t$ 时,lookup $e(x_t)=E[x_t]$ 直接取出对应行。这等价于用 one-hot vector 乘以 $E$,但 lookup 不必真的构造一个几乎全为零的长向量。

这张表与模型其余参数一起学习。作用相似的 token 可能形成有用的几何关系,但 lookup 本身不读取 context:同一个 token ID 总是从同一行出发。之后 attention 才把这个基础 vector 变成依赖上下文的表示。因此,“bank” 可以从同一个 token embedding 出发,却在金融语句与河岸语句中得到不同的 hidden representation。

许多 language model 还会在 output 端复用同一张表。采用 weight tying 时,最终 hidden state $h_t\in\mathbb R^d$ 可以产生

\[z_t=Eh_t+b\]

这样的 vocabulary logits。Input 端从 $E$ 中选择一行;output 端则让 $h_t$ 同时与每一行比较。共享 weight 既减少 parameter,也把“读入 token”与“预测 token”所用的空间联系起来。

4. Feed-Forward Network

Attention moves information between token positions by mixing value vectors. The feed-forward network performs a different job: it transforms the features within each position. The same two-layer MLP is applied independently to every row $x_t$ of the sequence matrix:

\[\operatorname{FFN}(x_t)=W_2\,\phi(W_1x_t+b_1)+b_2.\]

The first projection expands the model width $d$ to a larger hidden width $d_{\mathrm{ff}}$; the activation $\phi$ adds nonlinearity; the second projection returns to width $d$ so the result can re-enter the residual stream. Without this nonlinear feature transformation, attention would mainly route and average existing features rather than construct richer ones. The choice of $\phi$ is itself an architecture decision. A common choice is GELU, explained with the corresponding implementation in Section 5.3; many modern language models instead use a gated variant.

The parameter count explains why this visually simple component matters. Ignoring biases, the attention projections $W^Q,W^K,W^V,W^O$ contain about $4d^2$ parameters. A plain FFN contains $2d\,d_{\mathrm{ff}}$. With the common choice $d_{\mathrm{ff}}=4d$, that is $8d^2$: roughly twice the parameters of attention in the same block. These weights also have to be stored and trained; LLM Optimization Basics: Memory follows their contribution to training memory.

Attention 通过混合 value vector,在 token position 之间传递信息。Feed-forward network 做的是另一件事:它变换每个位置内部的 feature。同一个两层 MLP 独立作用于 sequence matrix 的每一行 $x_t$:

\[\operatorname{FFN}(x_t)=W_2\,\phi(W_1x_t+b_1)+b_2.\]

第一层 projection 把 model width 从 $d$ 扩张到更大的 hidden width $d_{\mathrm{ff}}$;activation $\phi$ 引入 nonlinearity;第二层再映射回 $d$,使结果能重新进入 residual stream。如果没有这个 nonlinear feature transformation,attention 主要是在 routing 与 averaging 已有 feature,难以构造更丰富的新 feature。$\phi$ 的选择本身也是一种 architecture decision。常见选择是 GELU,第 5.3 节会解释其含义并给出对应实现;许多现代 language model 则采用 gated variant。

Parameter count 说明了这个看似简单的组件为什么重要。忽略 bias,attention projection $W^Q,W^K,W^V,W^O$ 约有 $4d^2$ 个参数;普通 FFN 则有 $2d\,d_{\mathrm{ff}}$ 个。取常见设置 $d_{\mathrm{ff}}=4d$ 时,后者为 $8d^2$,约是同一 block 中 attention 参数量的两倍。这些 weight 同样需要存储和训练;LLM Optimization Basics: Memory 继续分析了它们对训练显存的贡献。

5. Architecture Designs

Attention and the FFN specify the two main transformations, but they do not by themselves make a deep language model trainable or turn its final vector into a probability distribution. Residual connections preserve an information path, LayerNorm controls feature scale, GELU supplies a nonlinear gate inside the FFN, and softmax normalizes scores where the model must choose among alternatives.

The following minimal model places every component on one depth-ordered path. Inside the expanded block, gray arrows are learned transformations and orange arrows are the two residual identity paths. Click any node to inspect what enters and leaves it.

Figure 21: A minimal pre-norm language model from prefix to next token. Each block contains two normalization modules and two residual additions.

Attention 与 FFN 给出了两种主要 transformation,却还不足以让深层 language model 易于训练,也不能自动把最终 vector 变成 probability distribution。Residual connection 保留信息通路,LayerNorm 控制 feature scale,GELU 在 FFN 内提供 nonlinear gate,softmax 则在模型必须从多个选项中分配权重时归一化 score。

下面的 minimal model 把所有组件放到同一条 depth-ordered path 上。展开的 block 内,灰色箭头表示 learned transformation,橙色箭头表示两条 residual identity paths。点击任一 node 可以查看其输入、输出与职责。

图 21:从 prefix 到 next token 的 minimal pre-norm language model。每个 block 含有两个 normalization modules 和两次 residual additions。

5.1 Residual Connections

Residual connections follow the same one-per-sublayer pattern as the normalization modules, but they are not normalization. The attention sublayer has one skip path from $x^{(\ell)}$ to its addition; the FFN sublayer has a second skip path from $a^{(\ell)}$ to its addition. The two patterns are structurally identical, but they carry different states and surround different learned functions:

\[a^{(\ell)}=x^{(\ell)}+\Delta_{\mathrm{attn}}^{(\ell)}, \qquad x^{(\ell+1)}=a^{(\ell)}+\Delta_{\mathrm{ffn}}^{(\ell)}.\]

GPT-style language models stack many attention and FFN sublayers. If every sublayer replaced its input entirely, information and gradients would have to survive a long chain of transformations. A residual connection instead asks each sublayer to learn a change to a persistent residual stream. In the common pre-norm arrangement,

\[y=x+f(\operatorname{LayerNorm}(x)),\]

where $f$ is either causal self-attention or an FFN.

Figure 22: A pre-norm residual sublayer. Hover over each component to follow the learned path and the identity path.

The addition creates a direct identity path. Locally, its Jacobian contains an identity term,

\[\frac{\partial y}{\partial x}=I+\frac{\partial f(\operatorname{LayerNorm}(x))}{\partial x}.\]

Consequently, both activations and gradients have a route through the block that does not depend entirely on the learned transformation $f$. This does not guarantee perfect optimization, but it makes deep stacks far easier to train. Backpropagation explains how the Jacobians compose; Basics of Optimizers explains how the resulting gradients update parameters.

Residual connection 与 normalization module 一样,都是“每个 sublayer 各有一个”,但 residual 并不是 normalization。Attention sublayer 有一条从 $x^{(\ell)}$ 绕到 addition 的 skip path;FFN sublayer 则有第二条从 $a^{(\ell)}$ 绕到 addition 的 skip path。两者结构相同,但携带的 state 不同,包围的 learned function 也不同:

\[a^{(\ell)}=x^{(\ell)}+\Delta_{\mathrm{attn}}^{(\ell)}, \qquad x^{(\ell+1)}=a^{(\ell)}+\Delta_{\mathrm{ffn}}^{(\ell)}.\]

GPT-style language model 会堆叠许多 attention 与 FFN sublayer。若每个 sublayer 都彻底替换输入,信息与 gradient 就必须穿过一条很长的 transformation chain。Residual connection 改为让每个 sublayer 学习对一条持续存在的 residual stream 所作的改变量。常见 pre-norm 排列为

\[y=x+f(\operatorname{LayerNorm}(x)),\]

其中 $f$ 可以是 causal self-attention 或 FFN。

图 22:Pre-norm residual sublayer。将鼠标移到各组件上,可分别追踪 learned path 与 identity path。

这个加法提供了一条直接的 identity path。从局部来看,其 Jacobian 包含 identity term:

\[\frac{\partial y}{\partial x}=I+\frac{\partial f(\operatorname{LayerNorm}(x))}{\partial x}.\]

因此,activation 与 gradient 都能沿一条不完全依赖 learned transformation $f$ 的路径穿过 block。这不保证 optimization 一定完美,却使深层堆叠容易训练得多。Backpropagation 解释 Jacobian 如何复合;Basics of Optimizers 则解释所得 gradient 如何更新 parameter。

5.2 LayerNorm

Where does LayerNorm appear? A language-model block usually contains two learned sublayers—attention and an FFN—and each has its own residual addition. In the common pre-norm arrangement, normalization appears immediately before each learned sublayer:

\[\begin{aligned} a^{(\ell)} &=x^{(\ell)} +\operatorname{Attention}_{\ell} \!\left(\operatorname{LN}^{\mathrm{attn}}_{\ell}(x^{(\ell)})\right),\\ x^{(\ell+1)} &=a^{(\ell)} +\operatorname{FFN}_{\ell} \!\left(\operatorname{LN}^{\mathrm{ffn}}_{\ell}(a^{(\ell)})\right). \end{aligned}\]

Read the first line from the inside outward: normalize $x^{(\ell)}$, pass the normalized vector through attention, then add the result back to the original, unnormalized $x^{(\ell)}$. The sum is $a^{(\ell)}$. The second line repeats the same pattern for the FFN. Thus there are normally two separate normalization modules per block, with distinct learned $\gamma$ parameters (and $\beta$ when the chosen norm includes a bias). There are also two residual additions—not one residual connection wrapped around the entire attention-plus-FFN block.

The identity branch never passes through LayerNorm:

\[\underbrace{x}_{\text{identity path}} \; + \; \underbrace{f(\operatorname{LN}(x))}_{\text{normalized learned path}}.\]

This is what “pre-norm” means: LayerNorm is before attention or the FFN on the learned branch, while the residual addition happens after that sublayer. After the last block, many language models apply one additional final normalization before the vocabulary projection:

\[h_{\mathrm{final}}=\operatorname{LN}_{f}(x^{(L)}),\qquad z=W_{\mathrm{vocab}}h_{\mathrm{final}}+b.\]

The exact placement is an architecture choice. An older post-norm arrangement instead uses $\operatorname{LN}(x+f(x))$: first run the sublayer, add the residual, and then normalize the sum. Some architectures add more norms or replace LayerNorm with RMSNorm. Unless stated otherwise, the equations in this article use the pre-norm pattern above.

Why is normalization needed in the first place? Temporarily abstract either attention or the FFN as one learned function $f_\ell$. The residual stream is repeatedly modified as sublayers are stacked:

\[x^{(\ell+1)}=x^{(\ell)}+f_\ell(x^{(\ell)}).\]

Nothing in this addition guarantees that the typical magnitude or common offset of the coordinates stays fixed. Consider a deliberately simple two-dimensional example. Let the initial residual vector for one token be

\[x^{(0)}=(1,-1),\]

and suppose a learned branch happens to amplify its input according to $f_0(x)=2x$. The first residual update gives

\[x^{(1)}=x^{(0)}+f_0(x^{(0)})=(1,-1)+(2,-2)=(3,-3).\]

The direction has not changed, but the magnitude is three times larger. If the next branch temporarily has the same gain, then

\[x^{(2)}=(3,-3)+(6,-6)=(9,-9).\]

This toy example is intentionally exaggerated; it does not claim that every real layer computes $2x$. It demonstrates the missing constraint: residual addition alone contains no rule saying that $x^{(\ell+1)}$ must have the same scale as $x^{(\ell)}$. Learned matrices can amplify or shrink a vector, and many such updates accumulate through depth.

Why would the next layer care? Ignoring biases, $q=W^Qx$ and $k=W^Kx$ are linear in the hidden vector. Scaling the hidden vectors by 3 therefore scales both $q$ and $k$ by 3, so their dot product $q^\top k$ becomes 9 times larger. Suppose two attention scores before softmax are $(1,0)$. Their weights are approximately

\[\operatorname{softmax}(1,0)\approx(0.731,0.269).\]

If larger hidden vectors make the corresponding score difference nine times larger, the scores become $(9,0)$ and

\[\operatorname{softmax}(9,0)\approx(0.9999,0.0001).\]

The attention decision has changed from a soft mixture to an almost one-hot choice even though the score ordering is identical. A common offset can drift as well: adding an update $(10,10)$ to $(1,-1)$ produces $(11,9)$, whose mean is 10 instead of 0. A later linear projection generally reacts to both changes unless its weights happen to cancel them.

LayerNorm removes these two nuisances before the learned branch sees them. Ignoring $\epsilon$, all three vectors

\[(1,-1),\qquad (3,-3),\qquad (11,9)\]

normalize to $(1,-1)$: the second differs only in scale, while the third differs only by a common offset. The next sublayer can therefore respond to the relative pattern of coordinates without first having to compensate for whichever magnitude and offset earlier layers happened to produce. The general formula below performs exactly this operation in $d$ dimensions.

What are $d$ and a “coordinate”? A token must be represented by numbers before a neural network can process it. If the model width—also called $d_{\text{model}}$ or the hidden size—is $d$, then one token is represented by a vector containing exactly $d$ numbers:

\[x_t=(x_{t,1},x_{t,2},\ldots,x_{t,d})\in\mathbb R^d.\]

Each scalar $x_{t,i}$ is one coordinate, meaning the $i$-th component or slot of that vector. A coordinate is not another token. It is one axis in the model’s learned representation space, and it usually does not have a simple human-assigned meaning by itself. At the input, $d$ is the token-embedding dimension. The attention and FFN outputs are projected back to the same width, so inside later blocks $d$ is also the dimension of each token’s hidden-state or residual-stream vector.

For example, consider $T=3$ tokens and model width $d=4$:

\[X= \begin{bmatrix} 0.2 & -0.1 & 0.7 & 0.4\\ -0.3 & 0.8 & 0.5 & -0.2\\ 0.9 & 0.1 & -0.4 & 0.6 \end{bmatrix} \in\mathbb R^{3\times4}.\]

The three rows correspond to three token positions. The four entries in one row are that token’s four coordinates. Thus $x_{2,3}=0.5$ means “coordinate 3 of token 2,” not “token 3.”

Which values are normalized together? LayerNorm treats every row independently. For token 2 above, it uses only $(-0.3,0.8,0.5,-0.2)$ and computes

\[\mu_2=\frac{-0.3+0.8+0.5-0.2}{4}=0.2, \qquad \sigma_2^2=\frac{(-0.5)^2+(0.6)^2+(0.3)^2+(-0.4)^2}{4}=0.215.\]

It does not mix these numbers with the other two rows. More generally, for the vector $x_t=(x_{t,1},\ldots,x_{t,d})$ at position $t$, it computes

\[\mu_t=\frac{1}{d}\sum_{i=1}^{d}x_{t,i}, \qquad \sigma_t^2=\frac{1}{d}\sum_{i=1}^{d}(x_{t,i}-\mu_t)^2.\]

It therefore does not average over the $T$ tokens, over other sequences, or over the batch. Every token supplies its own mean and variance by averaging the $d$ coordinates within its own row.

The wording is easy to misread: LayerNorm does normalize every token, but it normalizes each token separately. To normalize one $d$-dimensional token vector, it needs a summary of that vector’s location and scale, so it computes the mean and variance of the $d$ coordinates. Averaging coordinates does not assert that they have identical semantics. It treats the entire hidden vector as one geometric object; $\gamma_i$ and $\beta_i$ still remain different for every coordinate.

What if we averaged along the token axis instead? For each coordinate $i$, we would compute something like

\[\mu_i^{\mathrm{tokens}}=\frac{1}{T}\sum_{t=1}^{T}x_{t,i}.\]

This is a valid but different operation: coordinate $i$ of token 2 would now depend on coordinate $i$ of every other token. Changing the sentence, its length, or its padding would change token 2’s normalized representation. More seriously, using all $T$ positions in a causal language model would allow an early token’s normalization statistics to depend on future tokens. Restricting the statistics to the prefix avoids leakage, but then the normalization of an already processed token changes whenever the prefix grows, which conflicts with caching its hidden state during generation. LayerNorm avoids all of this: a token’s normalized vector depends only on that token’s current $d$ coordinates.

Figure 23: For a (B\times T\times d) tensor, LayerNorm's fixed-((b,t)) group is a line along (d); the illustrated sequence-style BatchNorm group fixes (i) and forms a plane across (B\times T). Drag to rotate, scroll to zoom, or use the preset views.

Why is LayerNorm a line here, while BatchNorm is a plane? A line or plane is not an intrinsic property of either method. It simply counts how many tensor indices are allowed to vary inside one normalization group:

  • LayerNorm fixes the batch index $b$ and token index $t$. Only the coordinate index $i=1,\ldots,d$ varies, so its $d$ values lie along one axis: a line.
  • The sequence-style BatchNorm shown in the figure fixes coordinate $i$. Both $b=1,\ldots,B$ and $t=1,\ldots,T$ vary, so its $BT$ values span two axes: a plane.

This also explains why the geometry can change with the tensor layout. For an ordinary matrix $A\in\mathbb R^{B\times d}$, BatchNorm fixes $i$ and varies only $b$, so its group is a line, not a plane. A sequence implementation that normalizes each position separately across the batch would likewise fix $(t,i)$ and vary only $b$. The formulas—which indices are fixed and which are reduced—are the definition; the drawing is only their geometry in this particular three-axis tensor.

The normalized coordinates are then

\[\hat x_{t,i}=\frac{x_{t,i}-\mu_t}{\sqrt{\sigma_t^2+\epsilon}}, \qquad y_{t,i}=\gamma_i\hat x_{t,i}+\beta_i.\]

These equations describe three steps. Subtracting $\mu_t$ centers the coordinates, so their mean becomes zero. Dividing by the standard deviation makes their variance approximately one; it is only approximate because the small constant $\epsilon$ prevents division by zero when the coordinates are almost identical. Finally, $\gamma,\beta\in\mathbb R^d$ apply a learned scale and offset to each feature coordinate. The symbol $\odot$ in the compact vector formula denotes coordinate-wise multiplication.

A small example makes the operation concrete. For $x=(1,2,3)$, the mean is $2$ and the variance is $2/3$. Ignoring $\epsilon$,

\[\hat x =\frac{(1,2,3)-2}{\sqrt{2/3}} \approx(-1.225,0,1.225).\]

Now replace the input by $x’=100x+50=(150,250,350)$. Its mean and standard deviation change by the same shift and positive scale, so normalization produces the same $\hat x$. LayerNorm preserves the relative pattern “first coordinate below the token mean, second at the mean, third above it” while discarding that token’s overall offset and magnitude. It does not claim that the three coordinates mean the same thing, nor does it standardize one feature over the dataset.

Why introduce $\gamma$ and $\beta$ after deliberately removing scale and offset? Normalization removes a different, input-dependent mean and variance for every token. In contrast, $\gamma_i$ and $\beta_i$ are learned parameters for feature $i$, shared across tokens. They let the model decide that one feature should generally be amplified, suppressed, or shifted without forcing the next sublayer to absorb uncontrolled example-by-example scale. They cannot reconstruct the discarded mean and norm of each input token. In a pre-norm block, that information is not lost from the model as a whole because the unnormalized $x$ remains available on the residual identity path.

This distinction is visible in the pre-norm computation:

\[u^{(\ell)}=\operatorname{LayerNorm}(x^{(\ell)}), \qquad x^{(\ell+1)}=x^{(\ell)}+f_\ell(u^{(\ell)}).\]

LayerNorm controls the input seen by $f_\ell$; it does not force the residual stream after the addition to have mean zero and variance one. The identity branch carries $x^{(\ell)}$ forward unchanged, while the learned branch operates on $u^{(\ell)}$ at a controlled scale. In backpropagation, this also leaves a direct identity contribution to the gradient, as Section 5.1 showed. LayerNorm therefore improves the conditioning of each learned branch, while the residual connection preserves a clean route through the stack. It moderates scale sensitivity; it does not by itself guarantee that activations or gradients can never grow.

What, then, is BatchNorm? For an ordinary activation matrix $A\in\mathbb R^{B\times d}$ containing $B$ examples, BatchNorm fixes a coordinate $i$ and estimates that coordinate’s mean and variance across the batch:

\[\mu_i^{\mathrm{BN}}=\frac{1}{B}\sum_{b=1}^{B}A_{b,i}, \qquad (\sigma_i^2)^{\mathrm{BN}}=\frac{1}{B}\sum_{b=1}^{B}(A_{b,i}-\mu_i^{\mathrm{BN}})^2.\]

LayerNorm fixes an example and reduces across its coordinates; BatchNorm fixes a coordinate and reduces across examples. For sequence activations $X\in\mathbb R^{B\times T\times d}$, a common BatchNorm-style arrangement also pools token positions, giving $BT$ values for each fixed coordinate $i$:

\[\mu_i^{\mathrm{BN}}=\frac{1}{BT}\sum_{b=1}^{B}\sum_{t=1}^{T}X_{b,t,i}.\]

The exact extra axes depend on the layer and tensor layout; the defining distinction is that BatchNorm estimates per-coordinate statistics from a collection of examples, whereas LayerNorm obtains per-token statistics from one vector.

A small matrix makes the distinction concrete. Ignore $\epsilon$, $\gamma$, and $\beta$, and let three examples have two coordinates:

\[A=\begin{bmatrix}1&10\\3&20\\5&30\end{bmatrix}.\]

BatchNorm works down each column. The column means are $(3,20)$; after division by the corresponding standard deviations, its output is approximately

\[\operatorname{BN}(A)= \begin{bmatrix}-1.225&-1.225\\0&0\\1.225&1.225\end{bmatrix}.\]

Each number now says where this example sits relative to the other examples for the same coordinate. LayerNorm instead works across each row. Both entries in every row are equally far below and above that row’s mean, so

\[\operatorname{LN}(A)= \begin{bmatrix}-1&1\\-1&1\\-1&1\end{bmatrix}.\]

Each number now describes the relative pattern of coordinates within this example. BatchNorm compares examples coordinate by coordinate; LayerNorm compares coordinates inside one example.

During training, BatchNorm uses the current mini-batch statistics, so the output for one example can change when its batch companions change. A small batch gives a noisy estimate; changing batch size, distributing a batch across devices, or filling sequences with different amounts of padding can change the statistics. During inference, BatchNorm therefore usually substitutes running averages accumulated during training. This creates a second rule whose running estimates must represent the test data well. In a convolutional tensor $(N,C,H,W)$, BatchNorm usually fixes channel $C$ and pools over $(N,H,W)$; the many spatial samples often make those estimates stable, which is one reason BatchNorm remains highly useful in convolutional networks.

LayerNorm uses the current token’s coordinates in both training and inference, so its rule is unchanged and still works with a batch of one. In a causal language model, pooling across token positions would also require careful masking: padding should not enter the statistics, and future positions must not influence earlier ones. This batch independence, together with the absence of padding and future-token coupling, is why LayerNorm—or the closely related RMSNorm—is usually preferred in causal language models.

LayerNorm 究竟在什么时候出现? 一个 language-model block 通常包含 attention 与 FFN 两个 learned sublayers,并且二者各自拥有一次 residual addition。在常见的 pre-norm 排列中,normalization 紧贴在每个 learned sublayer 之前:

\[\begin{aligned} a^{(\ell)} &=x^{(\ell)} +\operatorname{Attention}_{\ell} \!\left(\operatorname{LN}^{\mathrm{attn}}_{\ell}(x^{(\ell)})\right),\\ x^{(\ell+1)} &=a^{(\ell)} +\operatorname{FFN}_{\ell} \!\left(\operatorname{LN}^{\mathrm{ffn}}_{\ell}(a^{(\ell)})\right). \end{aligned}\]

由内向外读取第一行:先 normalization $x^{(\ell)}$,再把 normalized vector 送入 attention,最后把所得结果加回未经 normalization 的原始 $x^{(\ell)}$,得到 $a^{(\ell)}$。第二行对 FFN 重复同一结构。因此,每个 block 通常有两个彼此独立的 normalization modules,各自拥有不同的 learned $\gamma$ parameters;如果所用 normalization 包含 bias,也各有自己的 $\beta$。同时,这里有两次 residual addition,并不是在完整的 “attention + FFN” block 外面只包一条 residual connection。

Identity branch 完全不会经过 LayerNorm:

\[\underbrace{x}_{\text{identity path}} \; + \; \underbrace{f(\operatorname{LN}(x))}_{\text{normalized learned path}}.\]

这就是 “pre-norm” 的含义:LayerNorm 位于 attention 或 FFN learned branch 的前面,residual addition 则发生在该 sublayer 之后。通过最后一个 block 后,许多 language models 还会在 vocabulary projection 前使用一次额外的 final normalization:

\[h_{\mathrm{final}}=\operatorname{LN}_{f}(x^{(L)}),\qquad z=W_{\mathrm{vocab}}h_{\mathrm{final}}+b.\]

具体位置是一种 architecture choice。较早的 post-norm 排列采用 $\operatorname{LN}(x+f(x))$:先执行 sublayer,再做 residual addition,最后 normalization 整个和。还有些 architecture 会加入更多 norms,或者用 RMSNorm 替代 LayerNorm。除非特别说明,本文的公式都采用上面的 pre-norm pattern。

为什么一开始就需要 normalization?暂时把 attention 或 FFN 中任意一个 learned sublayer 抽象成函数 $f_\ell$。Residual stream 会随着 sublayers 堆叠而反复被修改:

\[x^{(\ell+1)}=x^{(\ell)}+f_\ell(x^{(\ell)}).\]

这个加法本身并不保证各 coordinate 的典型大小或共同 offset 保持不变。先看一个刻意简化的二维例子。假设某个 token 的初始 residual vector 是

\[x^{(0)}=(1,-1),\]

而某条 learned branch 此时恰好把输入放大两倍,即 $f_0(x)=2x$。第一次 residual update 得到

\[x^{(1)}=x^{(0)}+f_0(x^{(0)})=(1,-1)+(2,-2)=(3,-3).\]

Vector 的方向没有改变,magnitude 却变成原来的 3 倍。若下一条 branch 暂时也有相同的 gain,则

\[x^{(2)}=(3,-3)+(6,-6)=(9,-9).\]

这个 toy example 是故意夸大的;它并不是说真实 network 的每个 layer 都在计算 $2x$。它展示的是 residual addition 所缺少的约束:其中没有任何规则要求 $x^{(\ell+1)}$ 与 $x^{(\ell)}$ 尺度相同。Learned matrix 可能放大或缩小 vector,许多这样的 update 会沿 depth 累积。

为什么下一层会在意?暂时忽略 bias,$q=W^Qx$ 与 $k=W^Kx$ 都是 hidden vector 的 linear function。把 hidden vectors 放大 3 倍,会让 $q$ 与 $k$ 各自放大 3 倍,因此 dot product $q^\top k$ 会放大 9 倍。假设 softmax 之前的两个 attention scores 为 $(1,0)$,对应 weights 约为

\[\operatorname{softmax}(1,0)\approx(0.731,0.269).\]

若 hidden vector 变大,使 score difference 放大 9 倍,scores 就变成 $(9,0)$,此时

\[\operatorname{softmax}(9,0)\approx(0.9999,0.0001).\]

Score 的大小关系完全没变,attention decision 却从较平滑的 mixture 变成几乎 one-hot 的选择。共同 offset 也可能漂移:给 $(1,-1)$ 加上 update $(10,10)$ 会得到 $(11,9)$,其 mean 从 0 变成 10。除非后续 linear projection 的 weights 恰好把这些变化抵消,否则它通常会对 scale 和 offset 都作出反应。

LayerNorm 会在 learned branch 读取输入之前去掉这两种干扰。暂时忽略 $\epsilon$,下面三个 vectors

\[(1,-1),\qquad (3,-3),\qquad (11,9)\]

经过 normalization 后都会变成 $(1,-1)$:第二个只改变了 scale,第三个只加入了共同 offset。于是下一条 sublayer 可以直接响应 coordinates 之间的相对 pattern,而不必先补偿前面 layers 偶然产生的 magnitude 与 offset。下面的一般公式就是把同一操作扩展到 $d$ 个 dimensions。

$d$ 和 coordinate 分别是什么? Token 必须先表示成数值,才能交给 neural network 处理。若 model width——也常写作 $d_{\text{model}}$ 或 hidden size——为 $d$,那么一个 token 就由恰好包含 $d$ 个数的 vector 表示:

\[x_t=(x_{t,1},x_{t,2},\ldots,x_{t,d})\in\mathbb R^d.\]

每个标量 $x_{t,i}$ 都是一个 coordinate,即这个 vector 的第 $i$ 个分量或位置。Coordinate 不是另一个 token;它是模型学到的 representation space 中的一条坐标轴,单独来看通常没有人为指定的简单语义。在 input 端,$d$ 就是 token embedding 的 dimension。Attention 与 FFN 的输出都会投影回同一个宽度,因此进入后续 block 后,$d$ 也仍是每个 token 的 hidden-state 或 residual-stream vector 的 dimension。

例如,假设共有 $T=3$ 个 tokens,model width 为 $d=4$:

\[X= \begin{bmatrix} 0.2 & -0.1 & 0.7 & 0.4\\ -0.3 & 0.8 & 0.5 & -0.2\\ 0.9 & 0.1 & -0.4 & 0.6 \end{bmatrix} \in\mathbb R^{3\times4}.\]

三个行对应三个 token positions;一行中的四个数则是该 token 的四个 coordinates。因此,$x_{2,3}=0.5$ 表示“第 2 个 token 的第 3 个 coordinate”,而不是“第 3 个 token”。

究竟把哪些数放在一起 normalization? LayerNorm 独立处理每一行。对于上面的第 2 个 token,它只使用 $(-0.3,0.8,0.5,-0.2)$,并计算

\[\mu_2=\frac{-0.3+0.8+0.5-0.2}{4}=0.2, \qquad \sigma_2^2=\frac{(-0.5)^2+(0.6)^2+(0.3)^2+(-0.4)^2}{4}=0.215.\]

它不会把这些数与另外两行混在一起。一般地,对于位置 $t$ 的 vector $x_t=(x_{t,1},\ldots,x_{t,d})$,它计算

\[\mu_t=\frac{1}{d}\sum_{i=1}^{d}x_{t,i}, \qquad \sigma_t^2=\frac{1}{d}\sum_{i=1}^{d}(x_{t,i}-\mu_t)^2.\]

所以,它不会在 $T$ 个 token 之间取平均,也不会使用其他 sequence 或 batch 中的 example。每个 token 都只对自己这一行的 $d$ 个 coordinates 取平均,从而产生自己的 mean 与 variance。

这里的措辞很容易产生误解:LayerNorm 的确会 normalize 每一个 token,但每个 token 都被单独处理。为了 normalization 一个 $d$ 维 token vector,它需要概括这个 vector 的位置与尺度,因此对其中 $d$ 个 coordinates 计算 mean 与 variance。对 coordinates 求平均,并不是说它们拥有相同语义;这里是把整个 hidden vector 当成一个几何对象,而 $\gamma_i$ 与 $\beta_i$ 对每个 coordinate 仍然各不相同。

如果改为沿 token axis 求平均会怎样?对于每个 coordinate $i$,我们会计算类似

\[\mu_i^{\mathrm{tokens}}=\frac{1}{T}\sum_{t=1}^{T}x_{t,i}.\]

这在数学上可以定义,却是另一种 operation:第 2 个 token 的 coordinate $i$ 会依赖其他所有 token 的 coordinate $i$。改变 sentence content、sequence length 或 padding,都会改变第 2 个 token normalization 后的 representation。更严重的是,在 causal language model 中使用全部 $T$ 个位置,会让较早 token 的 normalization statistics 依赖 future tokens。若只使用 prefix 可以避免 leakage,但每当 prefix 增长,已经处理过的 token 又会得到不同的 normalization result,与 generation 时缓存其 hidden state 相冲突。LayerNorm 避免了这些问题:一个 token normalization 后的 vector 只依赖它自己当前的 $d$ 个 coordinates。

图 23:对于 (B\times T\times d) tensor,LayerNorm 固定 ((b,t)) 后的 group 是沿 (d) 的一条线;图中的 sequence-style BatchNorm 固定 (i) 后,在 (B\times T) 上形成一个面。可拖拽旋转、滚轮缩放,或切换预设视角。

为什么这里 LayerNorm 是线,而 BatchNorm 是面? 线或面并不是两种方法与生俱来的形状;它只表示一个 normalization group 中有几个 tensor indices 在变化:

  • LayerNorm 固定 batch index $b$ 与 token index $t$,只有 coordinate index $i=1,\ldots,d$ 变化。因此这 $d$ 个 values 沿一个 axis 排开,是一条线。
  • 图中的 sequence-style BatchNorm 固定 coordinate $i$,让 $b=1,\ldots,B$ 与 $t=1,\ldots,T$ 同时变化。因此这 $BT$ 个 values 跨越两个 axes,是一个面。

这也说明,形状会随 tensor layout 改变。对于普通 matrix $A\in\mathbb R^{B\times d}$,BatchNorm 固定 $i$ 后只让 $b$ 变化,所以它的 group 也是一条线,不是面。若一种 sequence implementation 在每个 token position 上分别跨 batch 做 normalization,它会固定 $(t,i)$、只让 $b$ 变化,同样得到线。真正的定义是公式中“哪些 indices 固定、哪些 indices 被 reduce”;图形只是它们在当前三轴 tensor 中的几何外观。

随后逐 coordinate 计算

\[\hat x_{t,i}=\frac{x_{t,i}-\mu_t}{\sqrt{\sigma_t^2+\epsilon}}, \qquad y_{t,i}=\gamma_i\hat x_{t,i}+\beta_i.\]

这组公式可以拆成三步。减去 $\mu_t$ 会把 coordinates 居中,使其平均值变为 0;除以 standard deviation 会让 variance 约为 1——之所以说“约为”,是因为 $\epsilon$ 会在 coordinates 几乎相同时防止除以 0。最后,$\gamma,\beta\in\mathbb R^d$ 分别为每个 feature coordinate 加上可学习的 scale 与 offset。紧凑 vector 公式中的 $\odot$ 表示 coordinate-wise multiplication。

看一个小例子。若 $x=(1,2,3)$,其 mean 为 $2$,variance 为 $2/3$。暂时忽略 $\epsilon$,则

\[\hat x =\frac{(1,2,3)-2}{\sqrt{2/3}} \approx(-1.225,0,1.225).\]

现在把输入换成 $x’=100x+50=(150,250,350)$。它的 mean 与 standard deviation 会经历相应的平移和正比例缩放,因此 normalization 后仍得到同一个 $\hat x$。LayerNorm 保留的是“第一个 coordinate 低于该 token 的平均值、第二个等于平均值、第三个高于平均值”这一相对 pattern,同时去掉该 token 整体的 offset 与 magnitude。它并不是说三个 coordinate 具有相同语义,也不是在整个 dataset 上分别标准化每个 feature。

既然刚刚移除了 scale 与 offset,为什么还要加入 $\gamma$ 和 $\beta$?Normalization 为每个 token 移除的是随输入而变化的 mean 与 variance;而 $\gamma_i$ 与 $\beta_i$ 是 feature $i$ 的 learned parameters,在所有 token 之间共享。它们让模型可以稳定地放大、压低或平移某个 feature,而不必让下一层吸收每个 example 都不同的失控尺度。它们不能重建某个输入 token 被丢弃的 mean 与 norm。在 pre-norm block 中,这些信息也没有从整个模型中消失,因为未经 normalization 的 $x$ 仍沿 residual identity path 保留下来。

把 pre-norm 的计算展开,这一点会更清楚:

\[u^{(\ell)}=\operatorname{LayerNorm}(x^{(\ell)}), \qquad x^{(\ell+1)}=x^{(\ell)}+f_\ell(u^{(\ell)}).\]

LayerNorm 控制的是 $f_\ell$ 所看到的输入;它并不强迫 addition 之后的 residual stream 仍然具有 mean 0、variance 1。Identity branch 原样传递 $x^{(\ell)}$,learned branch 则在尺度受控的 $u^{(\ell)}$ 上运算。反向传播时,这也会留下第 5.1 节所讲的 direct identity gradient contribution。因此,LayerNorm 改善每条 learned branch 的 numerical conditioning,residual connection 则保留穿过整个 stack 的直接路径。它能缓和模型对尺度的敏感性,却不能单独保证 activation 或 gradient 永远不会增长。

那么 BatchNorm 是什么? 对于包含 $B$ 个 examples 的普通 activation matrix $A\in\mathbb R^{B\times d}$,BatchNorm 固定 coordinate $i$,在整个 batch 上估计该 coordinate 的 mean 与 variance:

\[\mu_i^{\mathrm{BN}}=\frac{1}{B}\sum_{b=1}^{B}A_{b,i}, \qquad (\sigma_i^2)^{\mathrm{BN}}=\frac{1}{B}\sum_{b=1}^{B}(A_{b,i}-\mu_i^{\mathrm{BN}})^2.\]

LayerNorm 固定一个 example,在其 coordinates 上 reduce;BatchNorm 则固定一个 coordinate,在多个 examples 上 reduce。对于 sequence activations $X\in\mathbb R^{B\times T\times d}$,一种常见的 BatchNorm-style arrangement 还会同时汇集 token positions,于是每个固定 coordinate $i$ 有 $BT$ 个 values:

\[\mu_i^{\mathrm{BN}}=\frac{1}{BT}\sum_{b=1}^{B}\sum_{t=1}^{T}X_{b,t,i}.\]

具体还会 reduce 哪些 axis 取决于 layer 与 tensor layout;最关键的区别是,BatchNorm 从一组 examples 中估计每个 coordinate 的 statistics,而 LayerNorm 从单个 vector 中得到每个 token 自己的 statistics。

一个小 matrix 可以把区别说清楚。先忽略 $\epsilon$、$\gamma$ 与 $\beta$,假设三个 examples 各有两个 coordinates:

\[A=\begin{bmatrix}1&10\\3&20\\5&30\end{bmatrix}.\]

BatchNorm 沿每一列向下计算。两列的 mean 是 $(3,20)$;再分别除以各列的 standard deviation,得到近似

\[\operatorname{BN}(A)= \begin{bmatrix}-1.225&-1.225\\0&0\\1.225&1.225\end{bmatrix}.\]

每个数现在表达:这个 example 在同一个 coordinate上,相对于其他 examples 位于什么位置。LayerNorm 则沿每一行横向计算。每一行的两个数到本行 mean 的距离都大小相等、方向相反,因此

\[\operatorname{LN}(A)= \begin{bmatrix}-1&1\\-1&1\\-1&1\end{bmatrix}.\]

每个数现在表达的是:在这个 example 内部,各 coordinates 形成了怎样的相对 pattern。BatchNorm 逐 coordinate 比较不同 examples;LayerNorm 则在一个 example 内比较不同 coordinates。

Training 时,BatchNorm 使用当前 mini-batch 的 statistics,所以只要更换同 batch 中的其他 examples,一个 example 的输出就可能改变。小 batch 会产生较嘈杂的估计;改变 batch size、把一个 batch 分散到多台 devices,或让 sequences 含有不同数量的 padding,也都可能改变 statistics。因此 inference 时通常改用 training 期间累积的 running averages。这意味着它有第二套规则,而且 running estimates 必须能代表 test data。在 convolutional tensor $(N,C,H,W)$ 中,BatchNorm 通常固定 channel $C$、汇集 $(N,H,W)$;大量 spatial samples 往往让估计更稳定,这也是它在 convolutional networks 中仍然很有用的原因之一。

LayerNorm 在 training 与 inference 时都只使用当前 token 自己的 coordinates,因此规则完全相同,即使 batch size 为 1 也能工作。在 causal language model 中,若跨 token positions 汇集,还必须正确处理 masking:padding 不应参与 statistics,future positions 也不能影响 earlier positions。正是这种 batch independence,以及不会与 padding 或 future token 耦合的性质,使 LayerNorm——或与之接近的 RMSNorm——通常更适合 causal language model。

5.3 GELU

If the FFN contained only two linear projections, their composition would still be a single linear map. It could change coordinates but could not build genuinely nonlinear features. The activation $\phi$ between them prevents that collapse.

GELU, or the Gaussian Error Linear Unit, is a common choice:

\[\operatorname{GELU}(x)=x\,\Phi(x),\]

where $\Phi(x)$ is the standard normal cumulative distribution function. Rather than using a hard threshold, GELU smoothly scales a value according to its magnitude: large positive values pass almost unchanged, large negative values are strongly suppressed, and values near zero are partially retained. Applied coordinate by coordinate, it lets the expanded FFN decide which intermediate features should influence the projection back to model width.

To implement this definition, use the identity

\[\Phi(x)=\frac12\left(1+\operatorname{erf}\!\left(\frac{x}{\sqrt2}\right)\right),\]

where the error function is

\[\operatorname{erf}(u)=\frac{2}{\sqrt\pi}\int_0^u e^{-t^2}\,dt.\]

Substitution gives the exact elementwise formula used by the implementation:

\[\boxed{\operatorname{GELU}(x) =\frac{x}{2}\left(1+\operatorname{erf}\!\left(\frac{x}{\sqrt2}\right)\right)}.\]

In tensor code, torch.erf, multiplication, and addition all operate independently on every coordinate; no loop over coordinates is required. The interactive implementation below follows the exact formula and then uses it between the two FFN projections.

Interactive snippet: exact GELU inside an FFN, with the tanh approximation available in the second tab.

Many implementations also offer the inexpensive tanh approximation

\[\operatorname{GELU}(x)\approx \frac{x}{2}\left[1+\tanh\!\left( \sqrt{\frac{2}{\pi}}\left(x+0.044715x^3\right) \right)\right].\]

Its implementation is available in the second tab of the snippet above.

PyTorch’s F.gelu(x, approximate="none") corresponds to the exact form, while F.gelu(x, approximate="tanh") selects the approximation. Autodifferentiation differentiates either sequence of tensor operations automatically; GELU does not require a custom backward pass.

如果 FFN 只包含两次 linear projection,它们复合后仍然只是一次 linear map:它可以改变坐标,却无法构造真正的 nonlinear feature。夹在两层之间的 activation $\phi$ 防止了这种退化。

GELU,即 Gaussian Error Linear Unit,是一种常见选择:

\[\operatorname{GELU}(x)=x\,\Phi(x),\]

其中 $\Phi(x)$ 是 standard normal cumulative distribution function。GELU 不采用硬阈值,而是根据输入大小进行平滑缩放:较大的正值几乎原样通过,较大的负值被强烈抑制,接近零的值则部分保留。它逐 coordinate 作用,让扩张后的 FFN 决定哪些中间 feature 应该影响映射回 model width 的结果。

为了实现这个 definition,可以使用 identity

\[\Phi(x)=\frac12\left(1+\operatorname{erf}\!\left(\frac{x}{\sqrt2}\right)\right),\]

其中 error function 定义为

\[\operatorname{erf}(u)=\frac{2}{\sqrt\pi}\int_0^u e^{-t^2}\,dt.\]

代入后就得到 implementation 实际计算的 exact elementwise formula:

\[\boxed{\operatorname{GELU}(x) =\frac{x}{2}\left(1+\operatorname{erf}\!\left(\frac{x}{\sqrt2}\right)\right)}.\]

在 tensor code 中,torch.erf、multiplication 与 addition 都会独立作用于每个 coordinate,不需要手写逐 coordinate loop。下面的交互式 implementation 会先严格实现 exact formula,再把它放入 FFN 的两次 projections 之间。

交互式 snippet:FFN 中的 exact GELU;第二个 tab 提供 tanh approximation。

许多 implementation 还会提供计算成本更低的 tanh approximation:

\[\operatorname{GELU}(x)\approx \frac{x}{2}\left[1+\tanh\!\left( \sqrt{\frac{2}{\pi}}\left(x+0.044715x^3\right) \right)\right].\]

对应 implementation 位于上方 snippet 的第二个 tab。

PyTorch 中,F.gelu(x, approximate="none") 对应 exact form,F.gelu(x, approximate="tanh") 则选择 approximation。Autodifferentiation 会自动对这两串 tensor operations 求 derivative,因此 GELU 不需要手写 backward pass。

5.4 Softmax

The network’s last linear layer produces one real-valued score for every possible choice. At a language-model position these scores form

\[z=(z_1,\ldots,z_{\lvert\mathcal V\rvert})\in\mathbb R^{\lvert\mathcal V\rvert}.\]

They are logits. A logit may be negative, and the logits need not sum to one, so they cannot yet be probabilities. We need a conversion with three properties: every output should be positive, the outputs should sum to one, and a larger score should yield a larger probability. Softmax supplies that conversion. For $m$ possible choices,

\[\operatorname{softmax}(z)_i=\frac{e^{z_i}}{\sum_{j=1}^{m}e^{z_j}}.\]

Exponentiation makes every numerator positive; division by their sum makes the outputs add to one. But the more revealing identity is the ratio between two outputs:

\[\boxed{\frac{q_i}{q_k}=e^{z_i-z_k}}.\]

Softmax therefore interprets logit differences as log probability ratios, or log-odds. If $z_i-z_k=\log 2$, choice $i$ receives twice the probability of choice $k$. If the two logits are equal, their probabilities are equal. For example,

\[z=(2,1,0) \quad\Longrightarrow\quad \operatorname{softmax}(z)\approx(0.665,0.245,0.090).\]

The first choice is not assigned probability $2$; it is assigned $e^2$ units of positive mass, which are then normalized against the mass assigned to every other choice.

Is a logit a log-probability? Not by itself. Taking the logarithm of the softmax output gives

\[\boxed{\log q_i=z_i-\operatorname{logsumexp}(z)}, \qquad \operatorname{logsumexp}(z)=\log\sum_j e^{z_j}.\]

Thus $z_i$ is an unnormalized log-probability. The second term is the shared normalizing constant that turns all logits into actual log-probabilities. This also explains the shift invariance

\[\operatorname{softmax}(z+c\mathbf 1)=\operatorname{softmax}(z).\]

Adding the same constant to every logit changes no difference $z_i-z_k$, so it changes no probability. There are infinitely many logit vectors for the same distribution; softmax cares about relative evidence, not the absolute zero of the score scale.

Does softmax appear only at the final logits? No. In the architecture developed here it has two core jobs, and an optional architecture may use it for additional routing. The same formula is reused whenever scores must compete inside a specified set, but the meaning of that set changes.

1. Attention softmax: turning comparisons into a read operation. “Choosing where to read” is only shorthand. Softmax does not inspect the text and retrieve a token by itself. A complete attention head first constructs comparisons between token representations; softmax performs one precise step in the middle: it converts those comparison scores into mixing weights.

Start with just one example and one head. Suppose a layer receives token representations

\[x_1,x_2,\ldots,x_T,\qquad x_t\in\mathbb R^d.\]

We focus on position $t$. Its current vector $x_t$ contains what the network has represented at that position so far, but updating it may require information stored at earlier positions. The head creates three learned views of the vectors:

\[q_t=W_Qx_t, \qquad k_s=W_Kx_s, \qquad v_s=W_Vx_s.\]

Here $q_t\in\mathbb R^{d_k}$ is the query of the position being updated. Each $k_s\in\mathbb R^{d_k}$ is a key used to decide whether position $s$ is relevant to that query. Each $v_s\in\mathbb R^{d_v}$ is the value, the information position $s$ will contribute if it receives weight. “Query,” “key,” and “value” are learned vector roles—not literal words or manually assigned meanings.

The query is compared with every candidate key by a scaled dot product:

\[r_{t,s}=\frac{q_t^{\mathsf T}k_s}{\sqrt{d_k}}.\]

A larger $r_{t,s}$ means that, according to this head’s learned geometry, key $s$ matches query $t$ more strongly. But these $r_{t,s}$ values are still arbitrary real scores: they may be negative, do not sum to one, and cannot yet serve as weights for a controlled average. The factor $1/\sqrt{d_k}$ keeps typical dot-product magnitudes from growing with key dimension; it does not perform the normalization over positions.

Next define which positions the query is allowed to use. In a causal language model, position $t$ may use its prefix but not the future:

\[\mathcal A_t=\{s: s\le t\text{ and }s\text{ is not padding}\}.\]

Attention softmax holds the query $t$ fixed and normalizes only across candidates $s\in\mathcal A_t$:

\[\boxed{\alpha_{t,s} =\frac{e^{r_{t,s}}}{\sum_{u\in\mathcal A_t}e^{r_{t,u}}}}, \qquad s\in\mathcal A_t.\]

All allowed weights are nonnegative and satisfy $\sum_{s\in\mathcal A_t}\alpha_{t,s}=1$. The head can now perform the actual read:

\[\boxed{o_t=\sum_{s\in\mathcal A_t}\alpha_{t,s}v_s}.\]

This last equation is what “reading from the context” means. The head usually does not select one position. It builds a weighted mixture of several value vectors, and that mixture becomes the head’s proposed update for position $t$. The scores decide the relative weights; the values supply the content being mixed.

For example, suppose the query is at position 3 in a four-token sequence and its raw scores are

\[r_{3,:}=(1.2,\ 0.3,\ -0.4,\ 2.0).\]

Position 4 has the largest raw score, but it is in the future and is therefore unavailable. After masking, shifting by the largest allowed score, exponentiating, and normalizing, we obtain

\[\begin{aligned} \text{masked scores}&=(1.2,\ 0.3,\ -0.4,\ -\infty),\\ \text{shifted scores}&=(0,\ -0.9,\ -1.6,\ -\infty),\\ \alpha_{3,:}&\approx(0.621,\ 0.253,\ 0.126,\ 0). \end{aligned}\]

The read result is therefore

\[o_3\approx0.621v_1+0.253v_2+0.126v_3.\]

Nothing from $v_4$ enters the result. Also notice that $0.621$ is not the probability that token 1 is “correct,” nor the probability that token 1 will be generated next. It is an internal routing weight: for this query, in this head, at this layer, it states how much of value vector $v_1$ enters the mixture.

Softmax makes all allowed positions compete. For two allowed positions,

\[\frac{\alpha_{t,s}}{\alpha_{t,u}}=e^{r_{t,s}-r_{t,u}}.\]

Increasing one score does not merely increase its own weight; because the denominator is shared, it takes mass away from the other positions. This competition keeps total weight equal to one even when prefix length changes. Without such normalization, raw scores could be negative, the total scale of $o_t$ would vary with score magnitude and number of candidates, and “similarity” would not directly define a controlled mixture. The value vectors may still have different magnitudes, so attention does not force $o_t$ itself to have unit length.

Masked softmax is an equivalent implementation of the restricted set $\mathcal A_t$. Define

\[M_{t,s}=\begin{cases} 0,&s\in\mathcal A_t,\\ -\infty,&s\notin\mathcal A_t. \end{cases}\]

Then

\[\alpha_{t,s} =\frac{e^{r_{t,s}+M_{t,s}}} {\sum_u e^{r_{t,u}+M_{t,u}}}.\]

Because $e^{-\infty}=0$, a forbidden position gets zero weight and contributes nothing to the denominator. In other words, masking changes the support—the set that may receive weight—before softmax distributes one unit of mass over it.

Is masked softmax a triangular matrix? Masked softmax itself is an operation, so it has no single fixed shape. Its output inherits the shape and sparsity pattern of the mask. In full causal self-attention with $Q=K=T$, the mask is lower triangular:

\[M=\begin{bmatrix} 0&-\infty&-\infty\\ 0&0&-\infty\\ 0&0&0 \end{bmatrix},\]

and row-wise masked softmax produces a lower-triangular attention-weight matrix

\[A=\begin{bmatrix} 1&0&0\\ \alpha_{2,1}&\alpha_{2,2}&0\\ \alpha_{3,1}&\alpha_{3,2}&\alpha_{3,3} \end{bmatrix}, \qquad \sum_s\alpha_{t,s}=1.\]

Thus it is accurate to call this output lower triangular, but not to say every masked softmax is triangular. Masked softmax is a general operation; the mask supplied by the caller determines its pattern. A key padding mask $[B,K]$ is shared across queries and removes whole key columns, so by itself it does not impose $s\le t$. For example, a Transformer encoder normally uses bidirectional self-attention: every non-padding token may read both earlier and later tokens, and its padding mask is therefore not triangular. During cached one-token generation, the score slice may have shape $1\times K$ rather than being square. Sliding-window or other structural masks produce banded or different patterns. The general rule is simply that the output is zero wherever the mask forbids an entry.

Only after this single-query picture is clear do the full tensor indices help. With $B$ examples, $H$ heads, and $T$ positions, all scores have shape

\[S\in\mathbb R^{B\times H\times T\times T}, \qquad S_{b,h,t,s}=\frac{q_{b,h,t}^{\mathsf T}k_{b,h,s}}{\sqrt{d_k}}.\]

For every fixed triple $(b,h,t)$, the slice $S_{b,h,t,:}$ is exactly the one-query score vector just studied. Softmax runs along its final key index $s$—axis=-1—and does not mix different examples, heads, or query positions. Consequently, each example contains $H\times T$ separate attention distributions per layer. Different heads can learn different comparisons and produce different value mixtures. The $H$ head outputs at position $t$ are then concatenated and passed through the output projection $W_O$; only that combined vector becomes the attention sublayer’s update to the residual stream. Efficient kernels may avoid storing the full $T\times T$ score matrix, but mathematically they still compute these same masked row-wise normalizations.

Softmax is the standard way to obtain this smooth, competitive read, although an architecture can define a different attention normalization. Its role should now be precise: query–key projections construct the scores, the mask determines which keys are legal, softmax turns the legal scores into relative weights, and the weighted sum reads the values.

2. Vocabulary softmax: choosing what token may come next. After the final hidden state $h_{b,t}\in\mathbb R^d$, the language-model head produces

\[z_{b,t,v}=h_{b,t}^{\mathsf T}w_v+b_v, \qquad z\in\mathbb R^{B\times T\times\lvert\mathcal V\rvert}.\]

For fixed $(b,t)$, softmax is now taken over vocabulary index $v$:

\[q_\theta(v\mid x_{<t}) =\frac{e^{z_{b,t,v}}}{\sum_{u\in\mathcal V}e^{z_{b,t,u}}}.\]

This time the normalized numbers really are the model’s categorical probabilities for the next token. Attention softmax competes over source positions; vocabulary softmax competes over token identities. Their denominators are unrelated even though their formulas look identical.

Stable softmax: why subtract the largest logit? The formula is mathematically simple but a literal floating-point implementation can fail. For example, $e^{1000}$ overflows, while $e^{-1000}$ may round to zero. If every numerator underflows, even the denominator becomes zero. Shift invariance gives a numerically stable but mathematically identical implementation:

\[c=\max_jz_j, \qquad q_i=\frac{e^{z_i-c}}{\sum_j e^{z_j-c}}.\]

Now the largest exponent is $e^0=1$ and every other exponent lies in $(0,1]$. For instance, $(1000,999)$ is replaced by $(0,-1)$ and produces the same probabilities, approximately $(0.731,0.269)$, without ever computing $e^{1000}$. Stable softmax is not a new distribution or approximation: in exact arithmetic it is precisely ordinary softmax written in a safer form.

Stable and masked softmax are often combined. First add the mask, then find the maximum among the remaining allowed scores, subtract it, exponentiate, and normalize:

\[a_i=z_i+M_i, \qquad c=\max_{j:M_j=0}a_j, \qquad q_i=\frac{e^{a_i-c}}{\sum_j e^{a_j-c}}.\]

Which one calls which? The mathematical relationship is most cleanly written as

\[\boxed{\operatorname{masked\_softmax}(z,M) =\operatorname{stable\_softmax}(z+M)}.\]

In other words, masking specifies which entries are allowed, and the stable algorithm then computes softmax over those entries safely. The implementation below is interactive.

Figure 24: Interactive masked-softmax implementation. Select a variable or equation to inspect its tensor shape and current numerical value.

For training, implementations usually compute stable log_softmax directly rather than first forming probabilities and then taking their logarithms:

\[\log q_i=(z_i-c)-\log\sum_j e^{z_j-c}.\]

If the correct class is $k$, the next-token cross-entropy is

\[\boxed{L=-\log q_k=-z_k+\operatorname{logsumexp}(z)}.\]

The first term rewards the correct token’s logit; the second compares it with all vocabulary logits. Raising $z_k$ helps only insofar as it raises the correct token relative to its competitors.

What signal does this send backward? Differentiating the loss with respect to every output logit gives the unusually simple result

\[\boxed{\frac{\partial L}{\partial z_i}=q_i-\mathbf 1[i=k]}.\]

For the correct token, the derivative is $q_k-1\le 0$, so gradient descent increases its logit. For every incorrect token, the derivative is $q_i\ge0$, so gradient descent decreases its logit; an incorrect token that currently receives more probability is pushed down more strongly. When the prediction is already correct and confident, $q_k\approx1$ and all these gradients are small. When it is confidently wrong, the correct logit receives a derivative near $-1$ and the wrongly favored token a derivative near $+1$. For a soft target distribution $p$, the same calculation becomes $\partial L/\partial z_i=q_i-p_i$: training moves the predicted distribution toward the target distribution.

Notice that the logit gradients sum to zero. This is another expression of shift invariance: training can change relative logits, but a common shift of every logit has no effect on the loss.

What does temperature change? Dividing logits by a positive temperature $\tau$ changes how strongly their differences matter:

\[q_i(\tau)=\frac{e^{z_i/\tau}}{\sum_j e^{z_j/\tau}}.\]

When $\tau<1$, differences are magnified and the distribution becomes sharper; as $\tau\to0^+$ it approaches a one-hot choice at the largest logit. When $\tau>1$, differences shrink and the distribution becomes flatter; as $\tau\to\infty$ it approaches the uniform distribution. Language models are normally trained with the model’s defined scale, while generation-time temperature modifies the sampling distribution without changing the stored model parameters. Temperature does not change which token has the largest logit—it changes how much probability the alternatives retain.

For two choices, softmax depends on only one difference:

\[q_1=\frac{e^{z_1}}{e^{z_0}+e^{z_1}}=\sigma(z_1-z_0).\]

This is why binary classification may use either two logits with softmax or one logit with sigmoid: the one-logit convention fixes one reference score and learns their difference. A large vocabulary keeps one logit per token because there are many competing outcomes rather than one binary complement.

Finally, softmax does not guarantee that a model is correct or calibrated. It guarantees only that finite scores become a valid categorical distribution; every finite-logit choice receives strictly positive probability. The learned network and cross-entropy objective must determine whether those probabilities match the data.

Network 最后一层 linear map 会为每个可能选项输出一个 real-valued score。在 language-model 的某个位置,这些 scores 组成

\[z=(z_1,\ldots,z_{\lvert\mathcal V\rvert})\in\mathbb R^{\lvert\mathcal V\rvert}.\]

它们叫作 logits。Logit 可以为负,所有 logits 也不必加和为 1,因此还不能直接作为 probabilities。我们需要一种 conversion:每个输出必须为正、全部输出必须加和为 1,而且 score 越大,probability 也应越大。Softmax 正好完成这个转换。对于 $m$ 个可能选项,

\[\operatorname{softmax}(z)_i=\frac{e^{z_i}}{\sum_{j=1}^{m}e^{z_j}}.\]

Exponentiation 让每个 numerator 都为正;再除以总和,就让所有输出加和为 1。不过,更能说明其含义的是两个输出的 ratio:

\[\boxed{\frac{q_i}{q_k}=e^{z_i-z_k}}.\]

因此,softmax 把 logit differences 解释成 log probability ratios,也就是 log-odds。若 $z_i-z_k=\log 2$,选项 $i$ 的 probability 就是选项 $k$ 的两倍;若两个 logits 相等,它们的 probabilities 也相等。例如,

\[z=(2,1,0) \quad\Longrightarrow\quad \operatorname{softmax}(z)\approx(0.665,0.245,0.090).\]

第一个选项并不是得到 probability $2$;它先获得 $e^2$ 份正的 mass,再与其他所有选项获得的 mass 一起 normalization。

Logit 是 log-probability 吗? 单独看并不是。对 softmax output 取 logarithm,得到

\[\boxed{\log q_i=z_i-\operatorname{logsumexp}(z)}, \qquad \operatorname{logsumexp}(z)=\log\sum_j e^{z_j}.\]

所以 $z_i$ 是一个 unnormalized log-probability。第二项是所有 logits 共享的 normalization constant;减掉它以后才是真正的 log-probability。这也解释了 shift invariance:

\[\operatorname{softmax}(z+c\mathbf 1)=\operatorname{softmax}(z).\]

给所有 logits 加上同一个 constant,不会改变任何 difference $z_i-z_k$,所以 probabilities 完全不变。同一个 distribution 对应无穷多个 logit vectors;softmax 在意的是相对 evidence,而不是 score 的 absolute zero。

Softmax 只在最后把 logits 变成 probabilities 时出现吗? 不是。在本文构造的 architecture 中,它有两个核心任务;某些可选 architecture 还会用它进行额外 routing。只要一组 scores 需要在某个指定集合内竞争,就可以复用同一个公式,但这个集合的含义会改变。

1. Attention softmax:把 comparisons 变成一次读取。 “决定去哪里读取”只是一种简称。Softmax 本身不会阅读文本,也不会独自找出某个 token。一个完整 attention head 会先在 token representations 之间建立 comparisons;softmax 只负责中间一个非常明确的步骤:把这些 comparison scores 转换成 mixing weights。

先只考虑一个 example 和一个 head。假设某一 layer 收到 token representations

\[x_1,x_2,\ldots,x_T,\qquad x_t\in\mathbb R^d.\]

现在只观察 position $t$。它当前的 vector $x_t$ 包含 network 到目前为止在这个位置表示的信息,但要继续更新它,可能需要使用 earlier positions 中的信息。这个 head 会从 vectors 构造三种 learned views:

\[q_t=W_Qx_t, \qquad k_s=W_Kx_s, \qquad v_s=W_Vx_s.\]

其中,$q_t\in\mathbb R^{d_k}$ 是待更新位置的 query;每个 $k_s\in\mathbb R^{d_k}$ 是一个 key,用于判断 position $s$ 与这个 query 是否相关;每个 $v_s\in\mathbb R^{d_v}$ 是一个 value,表示 position $s$ 在获得 weight 后实际贡献的信息。“Query”“key”“value”只是 learned vector roles,并非 literal words,也不是人为规定的语义。

Query 与每个候选 key 通过 scaled dot product 比较:

\[r_{t,s}=\frac{q_t^{\mathsf T}k_s}{\sqrt{d_k}}.\]

较大的 $r_{t,s}$ 表示:按照这个 head 学出的 geometry,key $s$ 与 query $t$ 更匹配。但是这些 $r_{t,s}$ 仍只是任意 real scores:它们可能为负、不加和为 1,也还不能直接作为一个尺度受控的 average weights。因子 $1/\sqrt{d_k}$ 用于阻止 dot-product 的典型大小随 key dimension 增长;它并没有完成 positions 之间的 normalization。

接下来需要规定 query 可以使用哪些 positions。在 causal language model 中,position $t$ 可以使用 prefix,却不能使用 future:

\[\mathcal A_t=\{s: s\le t\text{ 并且 }s\text{ 不是 padding}\}.\]

Attention softmax 固定 query $t$,只在 candidates $s\in\mathcal A_t$ 之间 normalization:

\[\boxed{\alpha_{t,s} =\frac{e^{r_{t,s}}}{\sum_{u\in\mathcal A_t}e^{r_{t,u}}}}, \qquad s\in\mathcal A_t.\]

所有 allowed weights 都非负,并满足 $\sum_{s\in\mathcal A_t}\alpha_{t,s}=1$。现在这个 head 才能真正执行读取:

\[\boxed{o_t=\sum_{s\in\mathcal A_t}\alpha_{t,s}v_s}.\]

最后这个 equation 才是“从 context 中读取”的确切含义。Head 通常不会只选中一个 position,而是把多个 value vectors 按权重混合;所得 mixture 会成为这个 head 对 position $t$ 提出的 update。Scores 决定 relative weights,values 则提供被混合的内容。

例如,假设 query 位于四-token sequence 的 position 3,raw scores 为

\[r_{3,:}=(1.2,\ 0.3,\ -0.4,\ 2.0).\]

Position 4 的 raw score 最大,但它位于 future,不能使用。依次进行 masking、减去 allowed scores 中的 maximum、exponentiation 与 normalization 后,得到

\[\begin{aligned} \text{masked scores}&=(1.2,\ 0.3,\ -0.4,\ -\infty),\\ \text{shifted scores}&=(0,\ -0.9,\ -1.6,\ -\infty),\\ \alpha_{3,:}&\approx(0.621,\ 0.253,\ 0.126,\ 0). \end{aligned}\]

因此 read result 是

\[o_3\approx0.621v_1+0.253v_2+0.126v_3.\]

$v_4$ 完全没有进入结果。还要注意,$0.621$ 不是“token 1 正确的 probability”,也不是 token 1 接下来被生成的 probability。它是一个 internal routing weight:对于这个 layer 中这个 head 的这个 query,它规定 value vector $v_1$ 有多少进入 mixture。

Softmax 会让所有 allowed positions 互相竞争。对于两个 allowed positions,

\[\frac{\alpha_{t,s}}{\alpha_{t,u}}=e^{r_{t,s}-r_{t,u}}.\]

提高一个 score 不仅提高它自己的 weight;由于 denominator 被共享,它还会从其他 positions 手中拿走 mass。这种 competition 让 prefix length 改变时 total weight 仍等于 1。若不做这种 normalization,raw scores 可能为负,$o_t$ 的总尺度会随 score magnitude 与 candidate 数量改变,“similarity”也不能直接定义一个受控 mixture。Value vectors 自身仍可具有不同 magnitudes,所以 attention 并不会强迫 $o_t$ 的 length 等于 1。

Masked softmax 是 restricted set $\mathcal A_t$ 的等价 implementation。定义

\[M_{t,s}=\begin{cases} 0,&s\in\mathcal A_t,\\ -\infty,&s\notin\mathcal A_t. \end{cases}\]

于是

\[\alpha_{t,s} =\frac{e^{r_{t,s}+M_{t,s}}} {\sum_u e^{r_{t,u}+M_{t,u}}}.\]

因为 $e^{-\infty}=0$,forbidden position 的 weight 为零,也不会贡献 denominator。换句话说,masking 会先改变 support——也就是允许获得 weight 的集合——然后 softmax 才在这个集合上分配一单位 mass。

Masked softmax 是一个三角矩阵吗? Masked softmax 本身是一种 operation,因此不存在唯一固定的 matrix shape;它的 output 会继承 mask 的 shape 与 sparsity pattern。在 $Q=K=T$ 的 full causal self-attention 中,mask 是 lower triangular:

\[M=\begin{bmatrix} 0&-\infty&-\infty\\ 0&0&-\infty\\ 0&0&0 \end{bmatrix},\]

沿 row 执行 masked softmax 后,attention-weight matrix 也是 lower triangular:

\[A=\begin{bmatrix} 1&0&0\\ \alpha_{2,1}&\alpha_{2,2}&0\\ \alpha_{3,1}&\alpha_{3,2}&\alpha_{3,3} \end{bmatrix}, \qquad \sum_s\alpha_{t,s}=1.\]

因此,可以说这里的 output是下三角矩阵,却不能说所有 masked softmax 都是三角矩阵。Masked softmax 是 general operation,具体 pattern 由 caller 提供的 mask 决定。Key padding mask $[B,K]$ 会在所有 queries 之间共享,并移除完整的 key columns;它本身并没有施加 $s\le t$。例如,Transformer encoder 通常采用 bidirectional self-attention:每个 non-padding token 都能读取 earlier 与 later tokens,因此它的 padding mask 不是三角矩阵。使用 cache 进行 one-token generation 时,score slice 可能是 $1\times K$,根本不是 square matrix。Sliding-window 或其他 structural masks 还会产生 banded 或不同 pattern。一般规则只有一个:凡是 mask 禁止的位置,output 都为零。

理解单个 query 后,完整 tensor indices 才真正有帮助。对于 $B$ 个 examples、$H$ 个 heads 与 $T$ 个 positions,全部 scores 的 shape 为

\[S\in\mathbb R^{B\times H\times T\times T}, \qquad S_{b,h,t,s}=\frac{q_{b,h,t}^{\mathsf T}k_{b,h,s}}{\sqrt{d_k}}.\]

对于每个固定 triple $(b,h,t)$,slice $S_{b,h,t,:}$ 就是刚才分析的 one-query score vector。Softmax 沿其最后一个 key index $s$——也就是 axis=-1——运行,不会混合不同 examples、heads 或 query positions。因此,每个 example 在每一 layer 都有 $H\times T$ 个独立 attention distributions。不同 heads 可以学出不同 comparisons,并形成不同 value mixtures。Position $t$ 上的 $H$ 个 head outputs 随后被 concatenate,再经过 output projection $W_O$;只有这个 combined vector 才成为 attention sublayer 写入 residual stream 的 update。高效 kernel 可能不会存储完整 $T\times T$ score matrix,但在数学上仍然计算这些相同的 masked row-wise normalizations。

Softmax 是获得这种 smooth、competitive read 的标准方法,但 architecture 也可以定义其他 attention normalization。它的角色现在可以精确总结为:query–key projections 构造 scores,mask 决定哪些 keys 合法,softmax 把合法 scores 转换成 relative weights,weighted sum 再读取 values。

2. Vocabulary softmax:决定下一个 token 可以是什么。 得到 final hidden state $h_{b,t}\in\mathbb R^d$ 后,language-model head 产生

\[z_{b,t,v}=h_{b,t}^{\mathsf T}w_v+b_v, \qquad z\in\mathbb R^{B\times T\times\lvert\mathcal V\rvert}.\]

固定 $(b,t)$ 后,这次 softmax 沿 vocabulary index $v$ 计算:

\[q_\theta(v\mid x_{<t}) =\frac{e^{z_{b,t,v}}}{\sum_{u\in\mathcal V}e^{z_{b,t,u}}}.\]

这一次 normalized numbers 才真正是模型对 next token 给出的 categorical probabilities。Attention softmax 在 source positions 之间竞争;vocabulary softmax 在 token identities 之间竞争。虽然公式相同,二者的 denominators 毫无关联。

Stable softmax:为什么要减去最大的 logit? 公式在数学上很简单,直接照写成 floating-point operation 却可能失败。例如,$e^{1000}$ 会 overflow,而 $e^{-1000}$ 可能被 round 成零;如果每个 numerator 都 underflow,连 denominator 都会变成零。Shift invariance 给出了数值稳定、但在数学上完全等价的写法:

\[c=\max_jz_j, \qquad q_i=\frac{e^{z_i-c}}{\sum_j e^{z_j-c}}.\]

此时最大的 exponent 是 $e^0=1$,其余 exponent 都位于 $(0,1]$。例如,$(1000,999)$ 会先变成 $(0,-1)$,得到的 probabilities 仍约为 $(0.731,0.269)$,但完全不需要计算 $e^{1000}$。Stable softmax 不是新的 distribution,也不是 approximation;在 exact arithmetic 中,它就是普通 softmax 的安全改写。

Stable softmax 与 masked softmax 经常组合使用。正确顺序是:先加入 mask,再在仍被允许的 scores 中求 maximum,然后减去 maximum、exponentiate 并 normalization:

\[a_i=z_i+M_i, \qquad c=\max_{j:M_j=0}a_j, \qquad q_i=\frac{e^{a_i-c}}{\sum_j e^{a_j-c}}.\]

那么究竟是谁调用谁?数学关系最清楚的写法是

\[\boxed{\operatorname{masked\_softmax}(z,M) =\operatorname{stable\_softmax}(z+M)}.\]

也就是说,masking 先规定哪些 entries 可以参与,stable algorithm 再安全地计算这些 entries 上的 softmax。下面的 implementation 可以交互检查。

图 24:交互式 masked-softmax implementation。选择任意变量或等式,即可查看 tensor shape 与当前数值。

Training 时,implementation 通常会直接计算 stable log_softmax,而不是先形成 probabilities 再取 logarithm:

\[\log q_i=(z_i-c)-\log\sum_j e^{z_j-c}.\]

若正确类别是 $k$,next-token cross-entropy 为

\[\boxed{L=-\log q_k=-z_k+\operatorname{logsumexp}(z)}.\]

第一项奖励正确 token 的 logit;第二项把它与词表中的所有 logits 比较。提高 $z_k$ 只有在它相对于 competitors 提高时才有帮助。

这个 loss 会向后传递什么 signal? 对每个 output logit 求 derivative,会得到一个非常简洁的结果:

\[\boxed{\frac{\partial L}{\partial z_i}=q_i-\mathbf 1[i=k]}.\]

对于正确 token,derivative 是 $q_k-1\le0$,所以 gradient descent 会提高其 logit。对于每个错误 token,derivative 是 $q_i\ge0$,所以 gradient descent 会降低其 logit;当前 probability 越高的错误 token,会受到越强的向下修正。若预测已经正确且非常 confident,$q_k\approx1$,所有这些 gradients 都很小。若模型非常自信却预测错误,正确 logit 的 derivative 接近 $-1$,错误地占据高 probability 的 token 则得到接近 $+1$ 的 derivative。对于 soft target distribution $p$,同一个计算变成 $\partial L/\partial z_i=q_i-p_i$:training 会把 predicted distribution 推向 target distribution。

还可以注意到,所有 logit gradients 的总和为零。这是 shift invariance 的另一种表现:training 可以修改 logits 之间的相对关系,但同时平移所有 logits 不会改变 loss。

Temperature 改变了什么? 用一个正 temperature $\tau$ 除 logits,可以控制 differences 的作用强度:

\[q_i(\tau)=\frac{e^{z_i/\tau}}{\sum_j e^{z_j/\tau}}.\]

当 $\tau<1$ 时,differences 被放大,distribution 更尖锐;当 $\tau\to0^+$ 时,它趋近于最大 logit 对应的 one-hot choice。当 $\tau>1$ 时,differences 被缩小,distribution 更平坦;当 $\tau\to\infty$ 时,它趋近 uniform distribution。Language model 通常按模型定义的 scale 训练;generation-time temperature 只修改 sampling distribution,并不修改已经存储的 model parameters。Temperature 不会改变哪个 token 拥有最大的 logit,只会改变其他选项还能保留多少 probability。

对于两个选项,softmax 实际上只依赖一个 difference:

\[q_1=\frac{e^{z_1}}{e^{z_0}+e^{z_1}}=\sigma(z_1-z_0).\]

因此 binary classification 既可以输出两个 logits 并使用 softmax,也可以输出一个 logit 并使用 sigmoid:one-logit convention 相当于固定一个 reference score,只学习二者的 difference。大词表需要为每个 token 保留一个 logit,因为面对的是许多互相竞争的 outcomes,而不是一个 binary complement。

最后,softmax 并不保证模型正确或 calibrated。它只保证有限 scores 会形成一个合法 categorical distribution;只要 logit 有限,每个选项都会得到严格为正的 probability。真正决定这些 probabilities 是否匹配数据的,是 learned network 与 cross-entropy objective。

5.5 A Complete Forward Pass

We can now assemble the components without hiding the order in which they run. The function below keeps the signature of the running example, but reuses multi_head_attention from Section 2.5 instead of expanding its Q/K/V projections and scaled-attention kernel again.

Before reading the implementation, identify its task from the output path. It accepts token IDs with shape $[B,T]$, pools the $T$ final token representations into one vector, and returns logits with shape $[B,C]$. It is therefore a sequence classifier built from a language-model-style block, not an autoregressive next-token model. This distinction will matter at the final two steps.

Interactive snippet: the complete corrected forward pass. Select a line or stage to inspect its shape, operation, and role.

The computation has five boundaries worth checking.

First, token lookup and position lookup produce tensors of the same shape, $[B,T,d]$, so they can be added coordinate by coordinate. Their sum is the initial residual stream. The assertion $d\bmod H=0$ records a requirement of the multi-head helper: its $d$ coordinates must be divisible into $H$ equal groups.

Second, the two learned sublayers use the same Pre-LN pattern but do not share states or normalization parameters:

\[\begin{aligned} x_1&=x_0+\operatorname{MHA}(\operatorname{LN}_1(x_0)),\\ x_2&=x_1+\operatorname{FFN}(\operatorname{LN}_2(x_1)). \end{aligned}\]

The variables named residual save the unnormalized identity path. attn_input and ff_input belong only to the learned branches. Consequently, x = residual + attended is not interchangeable with x = x + layer_norm(attended, ...): the latter normalizes the branch output and implements neither the Pre-LN equation above nor the Post-LN equation $\operatorname{LN}(x+f(x))$. After the Pre-LN stack, a separate final LayerNorm controls the representation seen by the prediction head; its parameters ln_f_g and ln_f_b must be created during parameter initialization.

Third, the attention helper returns attended with the same $[B,T,d]$ shape as its input. Internally it performs the projections, head split, scaled dot-product attention, concatenation, and output projection already developed in Section 2.5. That matching output width is what makes the residual addition legal. The FFN likewise expands $d\to d_{\mathrm{ff}}$ and returns to $d$ before its residual addition.

Fourth, the mask participates in two different operations. Inside attention, it prevents padding positions from being used as keys. During pooling, mask[..., None] changes $[B,T]$ into $[B,T,1]`, allowing one validity bit to broadcast over all $d$ coordinates of a token. Once padded vectors are removed from the numerator, they must also be removed from the denominator:

\[\operatorname{pooled}_b =\frac{\sum_{t=1}^{T}m_{b,t}x_{b,t}} {\max\!\left(\sum_{t=1}^{T}m_{b,t},1\right)}.\]

Dividing by x.shape[1] would instead divide by the padded length $T$. A three-token sequence padded to length five would be represented as $(x_1+x_2+x_3)/5$ rather than the intended $(x_1+x_2+x_3)/3$, so appending meaningless padding would shrink the representation. The maximum only protects against division by zero; ordinary inputs should normally contain at least one real token.

Finally, head_w maps each pooled $d$-dimensional vector to $C$ class logits. These are raw scores, not probabilities, and a cross-entropy implementation can consume them directly. Setting return_attention=True additionally exposes weights with shape $[B,H,T,T]` for inspection without changing the logits.

To turn the trunk into an autoregressive language model, two changes are required together. First, do not pool: apply a vocabulary projection to every final token vector, producing

\[z=xW_{\mathrm{vocab}}+b,\qquad z\in\mathbb R^{B\times T\times|\mathcal V|}.\]

Second, a padding mask alone is insufficient; attention must also enforce the causal condition that query position $t$ cannot read key position $s>t$. Removing pooling changes the output from one prediction per sequence to one next-token prediction per position, while causal masking prevents those predictions from using their own future targets.

现在可以把前文的 components 组合起来,并明确展示它们实际运行的顺序。下面的函数保留此前 example 的 signature,但直接复用第 2.5 节的 multi_head_attention,不再重复展开其中的 Q/K/V projections 与 scaled-attention kernel。

阅读 implementation 前,先从 output path 判断它在解决什么任务。输入 token IDs 的 shape 是 $[B,T]$;函数把 $T$ 个 final token representations 汇集成一个 vector,最后返回 shape 为 $[B,C]$ 的 logits。因此,它是一个由 language-model-style block 构成的 sequence classifier,而不是 autoregressive next-token model。这个区别会在最后两步变得关键。

交互式 snippet:修正后的完整 forward pass。选择任意代码行或 stage,可以检查其 shape、operation 与作用。

阅读这段 computation 时,有五个 boundary 值得逐一检查。

第一,token lookup 与 position lookup 产生相同的 $[B,T,d]$ shape,因此可以逐 coordinate 相加。它们的和构成初始 residual stream。Assertion $d\bmod H=0$ 记录了 multi-head helper 的必要条件:$d$ 个 coordinates 必须能平均分成 $H$ 组。

第二,两个 learned sublayers 都使用相同的 Pre-LN pattern,但它们不共享 state,也不共享 normalization parameters:

\[\begin{aligned} x_1&=x_0+\operatorname{MHA}(\operatorname{LN}_1(x_0)),\\ x_2&=x_1+\operatorname{FFN}(\operatorname{LN}_2(x_1)). \end{aligned}\]

名为 residual 的 variable 保存未经 normalization 的 identity path;attn_input 与 ff_input 只属于 learned branches。因此,x = residual + attended 不能替换成 x = x + layer_norm(attended, ...):后者 normalization 的是 branch output,既不等于上面的 Pre-LN equation,也不等于 Post-LN equation $\operatorname{LN}(x+f(x))$。Pre-LN stack 结束后,独立的 final LayerNorm 会控制 prediction head 所读取的 representation;其 parameters ln_f_g 与 ln_f_b 需要在 parameter initialization 时创建。

第三,attention helper 返回的 attended 与 input 具有相同的 $[B,T,d]$ shape。它内部已经执行第 2.5 节介绍的 projections、head split、scaled dot-product attention、concatenation 与 output projection。正是相同的 output width,使 residual addition 合法。FFN 同样先把宽度从 $d$ 扩张到 $d_{\mathrm{ff}}$,再回到 $d$ 后进行 residual addition。

第四,同一个 mask 参与两种不同 operation。在 attention 内部,它阻止 padding positions 被当作 keys 使用。在 pooling 阶段,mask[..., None] 把 $[B,T]$ 变成 $[B,T,1]$,让一个 validity bit broadcast 到该 token 的全部 $d$ 个 coordinates。既然 padded vectors 已从 numerator 中移除,就也必须从 denominator 中移除:

\[\operatorname{pooled}_b =\frac{\sum_{t=1}^{T}m_{b,t}x_{b,t}} {\max\!\left(\sum_{t=1}^{T}m_{b,t},1\right)}.\]

若除以 x.shape[1],分母就会是包含 padding 的长度 $T$。一个包含三个真实 tokens、padding 到长度五的 sequence 会被表示成 $(x_1+x_2+x_3)/5$,而不是预期的 $(x_1+x_2+x_3)/3$;也就是说,仅仅追加没有意义的 padding 就会缩小 representation。这里的 maximum 只用于防止除零;正常 input 通常应至少包含一个真实 token。

最后,head_w 把每个 pooled $d$-dimensional vector 映射为 $C$ 个 class logits。它们是 raw scores,并不是 probabilities;cross-entropy implementation 可以直接读取 logits。设置 return_attention=True 时,函数还会返回 shape 为 $[B,H,T,T]$ 的 weights 供检查,但不会改变 logits。

若要把这个 trunk 改成 autoregressive language model,必须同时做两处修改。第一,不再 pooling,而是对每个 final token vector 执行 vocabulary projection:

\[z=xW_{\mathrm{vocab}}+b,\qquad z\in\mathbb R^{B\times T\times|\mathcal V|}.\]

第二,仅有 padding mask 并不足够;attention 还必须强制 causal condition,使 query position $t$ 无法读取 key position $s>t$。去掉 pooling 会让 output 从“每个 sequence 一个 prediction”变为“每个 position 一个 next-token prediction”;causal masking 则防止这些 predictions 读取自己的 future targets。