Q = X W_Q, \quad K = X W_K, \quad V = X W_V what is the dimension for each?
The equations represent the projection of the input XXX into query (QQQ), key (KKK), and value (VVV) spaces using the weight matrices WQW_QWQ, WKW_KWK, and WVW_VWV. To understand the dimensions of QQQ, KKK, and VVV, we need to analyze the dimensions of the components:
-
XXX: The input matrix of shape (N,dmodel)(N, d_{\text{model}})(N,dmodel), where:
- NNN is the batch size (number of input sequences or tokens).
- dmodeld_{\text{model}}dmodel is the dimensionality of the model (the embedding size of the input).
-
WQW_QWQ, WKW_KWK, WVW_VWV: Weight matrices of shape (dmodel,dk)(d_{\text{model}}, d_k)(dmodel,dk), (dmodel,dk)(d_{\text{model}}, d_k)(dmodel,dk), and (dmodel,dv)(d_{\text{model}}, d_v)(dmodel,dv), respectively. These matrices project XXX into lower-dimensional spaces for queries, keys, and values:
- dkd_kdk: The dimensionality of the query and key projections (typically a hyperparameter).
- dvd_vdv: The dimensionality of the value projections (can differ from dkd_kdk).
- Q=XWQQ = X W_QQ=XWQ: (N,dmodel)×(dmodel,dk)=(N,dk)(N, d_{\text{model}}) \times (d_{\text{model}}, d_k) = (N, d_k)(N,dmodel)×(dmodel,dk)=(N,dk).
- K=XWKK = X W_KK=XWK: (N,dmodel)×(dmodel,dk)=(N,dk)(N, d_{\text{model}}) \times (d_{\text{model}}, d_k) = (N, d_k)(N,dmodel)×(dmodel,dk)=(N,dk).
- V=XWVV = X W_VV=XWV: (N,dmodel)×(dmodel,dv)=(N,dv)(N, d_{\text{model}}) \times (d_{\text{model}}, d_v) = (N, d_v)(N,dmodel)×(dmodel,dv)=(N,dv).
- QQQ has shape (N,dk)(N, d_k)(N,dk).
- KKK has shape (N,dk)(N, d_k)(N,dk).
- VVV has shape (N,dv)(N, d_v)(N,dv).
These shapes are crucial for computing the attention mechanism, where the dot product attention computes scores between QQQ and KTK^TKT, followed by weighting VVV.
In GPT, there is no cross-attention layer because there is no encoder. The cross-attention layer is specifically used to attend to encoder outputs, which are not present in models like GPT that rely solely on the decoder for autoregressive generation. Therefore, GPT consists of masked self-attention and feed-forward layers only.
Autoregressive generation refers to a process in which a model generates a sequence (such as text) one element (or token) at a time, where each token is predicted based on the previously generated tokens. The term autoregressive means that each step in the generation process depends on the outputs of the previous steps.
-
Initial Input (Prompt):
- You provide an initial prompt, which could be a few words or sentences. This prompt serves as the context for the generation process.
-
Token Prediction:
- GPT takes the prompt as input and predicts the most likely next token (e.g., word or subword). The model does this using a combination of its learned weights and the context provided by the input.
- The model leverages masked self-attention, meaning it can only attend to previous tokens, not future ones, ensuring that it predicts the next token based solely on what has been generated so far.
-
Iteration:
- After predicting the next token, the model appends it to the input sequence and uses this extended sequence to predict the next token.
- This process continues iteratively, with the model predicting one token at a time, based on all previous tokens.
-
Stopping Condition:
- The generation process continues until a stopping condition is met, such as reaching a certain length or generating a special "end-of-sequence" token.
Let’s walk through an example step-by-step, using the following initial prompt:
Prompt: "The sun was setting over the mountains, and"
- Input: "The sun was setting over the mountains, and"
- GPT looks at the prompt and predicts the most likely next token.
- Prediction: "the" (since "the" is a common word after "and").
- The model now adds the predicted token "the" to the input and uses the updated sequence to predict the next token.
- Updated Input: "The sun was setting over the mountains, and the"
- Input: "The sun was setting over the mountains, and the"
- GPT predicts the next token, which could be a noun or adjective that commonly follows "the".
- Prediction: "sky"
- The predicted token "sky" is appended to the input.
- Updated Input: "The sun was setting over the mountains, and the sky"
- Input: "The sun was setting over the mountains, and the sky"
- GPT predicts the next token based on the extended sequence.
- Prediction: "turned" (a verb that fits well with the context of "sky").
- The process repeats: the predicted token "turned" is added to the sequence, and GPT continues predicting the next token.
- Updated Input: "The sun was setting over the mountains, and the sky turned"
The model would continue in this fashion, generating more tokens one at a time, producing a coherent and contextually relevant sequence based on the prompt and the prior tokens.
你提到的情况在日常生活中非常常见——我们在说话时,可能会意识到自己犯了错误,然后及时进行更正。这种自我纠正的行为是人类交流的一个重要特征。然而,GPT等模型在生成文本时,并不会像人类一样主动回过头去更改已经生成的部分。一旦生成了某个词或短语,GPT就会继续基于这些已经生成的内容生成下一个词,而不会像人类一样在中途发现错误并做出修改。
-
自回归生成机制:
- GPT使用的是自回归(autoregressive)生成,这意味着它生成每个词时,都是基于之前生成的词。这个过程是单向的,生成的内容一旦生成,就被固定下来,后续的生成会基于这个固定的上下文继续向前推进。
- 由于模型并没有反向修改的能力,它无法像人类一样实时发现错误并进行更正。
-
因果自注意力机制:
- GPT中的注意力机制是因果(causal)自注意力,这意味着模型只能“看到”之前生成的内容,而不能“看到”未来或尚未生成的内容。
- 这使得模型在生成过程中是顺序性的,无法回头修改已经生成的词或句子。
-
人类语言的自我纠正:在人类对话中,当我们意识到我们说错了时,会主动纠正自己。例如:
- 你可能说:“我昨天去超市买了……哦,不对,我是去了书店。”
- 这种行为源于人类具有即时反馈和反思的能力,我们可以识别到错误,并通过语言表达即时修正。
-
GPT的固定生成过程:相比之下,GPT是基于已经生成的部分进行下一步预测的。它不会像人类那样“意识到”自己说错了,也不会主动回过头去修正。它的生成是顺序性的、不可修改的。例如:
- GPT生成了:“猫坐在椅子上”,接下来它只能继续基于这个句子生成,无法返回去把“椅子”改成“桌子”。
Consider the following sentence as an input sequence:
Input Sentence: "The cat sits on the mat."
The encoder will process this sentence through several steps:
The input sentence is first tokenized, meaning each word is broken down into individual tokens (or subword tokens). For simplicity, we assume the tokenizer breaks the sentence into word-level tokens:
Tokens: ["The", "cat", "sits", "on", "the", "mat", "."]
Before processing the tokens, each token is converted into a vector using an embedding layer. This embedding layer maps each word or token to a fixed-size vector (typically 512 or 768 dimensions) that represents the word in a continuous, high-dimensional space.
For example, the word "cat" might be converted to a vector like this (simplified for illustration):
"The" -> [0.2, 0.1, 0.7, ...] # (vector representation)
"cat" -> [0.6, 0.4, 0.3, ...]
"sits" -> [0.5, 0.9, 0.2, ...]
"on" -> [0.3, 0.7, 0.1, ...]
"the" -> [0.2, 0.1, 0.7, ...]
"mat" -> [0.4, 0.6, 0.8, ...]
"." -> [0.1, 0.3, 0.4, ...]
This vectorized representation of the words (called word embeddings) is used as input to the encoder. These embeddings contain semantic information about each word but are not yet contextualized with respect to the rest of the sentence.
Since Transformers do not have built-in sequence awareness (they don't have a mechanism like RNNs to process tokens sequentially), positional encoding is added to the word embeddings to introduce information about the order of the words in the sentence.
Positional encoding adds a unique vector to each token's embedding based on its position in the sequence (e.g., the 1st word gets a different positional vector than the 2nd word). This allows the model to understand the relative positions of words.
Once the embeddings (with positional encodings) are passed into the encoder, the self-attention mechanism begins its work. This mechanism allows each word to "look at" all the other words in the sentence and assign different levels of attention (importance) to them.
For example, while encoding the word "cat", the self-attention layer may decide that "sits" and "mat" are more important than "The" and "." for understanding the context of "cat". So the self-attention mechanism will combine information from these words to create a contextualized representation for "cat".
- Attention Weights for "cat":
- "The" -> 0.1 (low importance)
- "cat" -> 0.3
- "sits" -> 0.4 (high importance)
- "on" -> 0.1
- "the" -> 0.05
- "mat" -> 0.35 (high importance)
- "." -> 0.1
The self-attention mechanism is applied to each word in the sentence, creating a new representation for every word that takes into account its relationship with the other words.
After self-attention, the new, contextualized word representations are passed through a feed-forward neural network (FFN). This network refines the word representations further and applies non-linear transformations to help the model capture more complex patterns.
The same FFN is applied independently to each word's representation.
At the end of this process, each word in the input sentence has a contextualized representation. These representations encode not only the meaning of the individual words but also the relationships between the words in the sentence.
For example, the new representation for "cat" now contains information about "sits" and "mat", because these words are relevant to understanding "cat" in this context.
The output of the encoder looks like this (simplified vector representations):
"The" -> [0.25, 0.1, 0.7, ...] # Contextualized vector for "The"
"cat" -> [0.65, 0.45, 0.35, ...] # Contextualized vector for "cat"
"sits" -> [0.55, 0.9, 0.25, ...] # Contextualized vector for "sits"
"on" -> [0.35, 0.75, 0.15, ...] # Contextualized vector for "on"
"the" -> [0.25, 0.1, 0.7, ...] # Contextualized vector for "the"
"mat" -> [0.45, 0.65, 0.85, ...] # Contextualized vector for "mat"
"." -> [0.15, 0.35, 0.45, ...] # Contextualized vector for "."
The self-attention mechanism by itself is powerful because it allows the model to capture relationships between tokens, but it's still limited in its ability to capture complex, non-linear interactions. That's where the feed-forward neural network (FFN) comes in:
-
Non-Linearity:
- The FFN introduces non-linearity into the model. Self-attention is a linear operation, meaning it combines the input in a simple, additive way. While this is useful for learning relationships between tokens, non-linear transformations (applied by FFNs) allow the model to capture more complex patterns and interactions in the data.
- Without non-linearity, the model would only be able to model linear relationships, which limits its expressiveness.
-
Token-Specific Transformation:
- After the self-attention mechanism generates the new contextualized representation of each token, the FFN is applied independently to each token to further refine the representation.
- The FFN adds complexity and depth to the model by allowing each token's representation to undergo a non-linear transformation, helping the model capture more abstract patterns and concepts that are crucial for tasks like translation, summarization, and text generation.
-
Layered Refinement:
- The Transformer is built with multiple layers, and each layer refines the representations produced by the previous one. The self-attention mechanism is responsible for making the tokens aware of each other, while the FFN adds complexity and expressiveness to those contextualized representations.
- Each layer of the encoder or decoder consists of self-attention followed by an FFN. Together, they work in tandem to incrementally improve the token representations across layers.
Let’s walk through a simple example to illustrate how the self-attention mechanism works and how it computes attention scores and uses them to output a weighted sum of the representations of other words in the sequence.
Let’s take a simple sentence:
"The cat sat on the mat."
Each word in the sentence will be represented as a vector (embedding), and the self-attention mechanism will compute how much attention each word should pay to every other word.
-
Input Representation:
- Assume that each word in the sentence is first converted into an embedding vector.
- For simplicity, let's represent these word embeddings as vectors of just 3 dimensions (in reality, they are much larger, e.g., 512 or 768 dimensions).
"The" -> [1.0, 0.0, 0.0]
"cat" -> [0.0, 1.0, 0.0]
"sat" -> [0.0, 0.0, 1.0]
"on" -> [0.5, 0.5, 0.0]
"the" -> [0.5, 0.0, 0.5]
"mat" -> [0.0, 0.5, 0.5]
-
These vectors represent the initial word embeddings.
-
Query, Key, and Value Vectors:
- For each word, we generate query (Q), key (K), and value (V) vectors by multiplying the embedding by learned weight matrices
$W_Q$ ,$W_K$ , and$W_V$ . - For simplicity, let’s assume we’ve already computed the query, key, and value vectors for the word "cat":
- For each word, we generate query (Q), key (K), and value (V) vectors by multiplying the embedding by learned weight matrices
Query for "cat" -> [1.0, 0.0, 1.0]
Key for "cat" -> [1.0, 0.5, 0.0]
Value for "cat" -> [0.0, 1.0, 0.5]
- This process is done for every word in the sentence, generating different Q, K, and V vectors for each word.
-
Computing Attention Scores:
- The attention score between two words is computed as the dot product of the query vector of the current word (in this case, "cat") with the key vector of every other word (including itself).
The dot product measures the similarity between two vectors—higher scores mean greater similarity or relevance.
Let's compute the attention scores for "cat" with every other word in the sentence:
Attention score (cat, The) = Q(cat) · K(The) = [1.0, 0.0, 1.0] · [1.0, 0.0, 0.0] = 1.0
Attention score (cat, cat) = Q(cat) · K(cat) = [1.0, 0.0, 1.0] · [1.0, 0.5, 0.0] = 1.0
Attention score (cat, sat) = Q(cat) · K(sat) = [1.0, 0.0, 1.0] · [0.0, 0.0, 1.0] = 1.0
Attention score (cat, on) = Q(cat) · K(on) = [1.0, 0.0, 1.0] · [0.5, 0.5, 0.0] = 0.5
Attention score (cat, the) = Q(cat) · K(the) = [1.0, 0.0, 1.0] · [0.5, 0.0, 0.5] = 1.0
Attention score (cat, mat) = Q(cat) · K(mat) = [1.0, 0.0, 1.0] · [0.0, 0.5, 0.5] = 0.5
- These attention scores measure how much "cat" should attend to (or focus on) each of the other words, including itself.
- Normalizing the Attention Scores (Softmax):
- The attention scores are then normalized using a softmax function, which converts them into probabilities that sum to 1. The softmax highlights the most relevant words, while reducing the influence of less relevant words.
The softmax for "cat" looks like this:
Softmax(attention scores for "cat"):
[1.0, 1.0, 1.0, 0.5, 1.0, 0.5] -> [0.217, 0.217, 0.217, 0.132, 0.217, 0.132]
- After softmax, the attention scores become weights, indicating how much attention "cat" should pay to each word. These values now sum to 1.
- Weighted Sum of Value Vectors(Element-Wise Calculation):
The attention weights are applied to each dimension of the value vectors separately.
For each dimension of the vectors, the weighted sum is calculated like this:
-
For the 1st dimension (the first number in each value vector)::
-
The final step is to compute the weighted sum of the value vectors of the other words, using the softmaxed attention scores as weights.
-
For "cat," we now use the normalized attention weights to combine the value vectors from the words "The," "cat," "sat," "on," "the," and "mat."
Let's compute the weighted sum of the value vectors for "cat":
-
The attention weights are applied to each dimension of the value vectors separately.
For each dimension of the vectors, the weighted sum is calculated like this:
- For the 1st dimension (the first number in each value vector):
Weighted sum for 1st dimension =
0.217 * 1.0 (V(The)[0]) + 0.217 * 0.0 (V(cat)[0]) + 0.217 * 0.0 (V(sat)[0]) +
0.132 * 0.5 (V(on)[0]) + 0.217 * 0.5 (V(the)[0]) + 0.132 * 0.0 (V(mat)[0])
= 0.217 + 0 + 0 + 0.066 + 0.108 + 0
= 0.391
Weighted sum for 2nd dimension =
0.217 * 0.0 (V(The)[1]) + 0.217 * 1.0 (V(cat)[1]) + 0.217 * 0.0 (V(sat)[1]) +
0.132 * 0.5 (V(on)[1]) + 0.217 * 0.0 (V(the)[1]) + 0.132 * 0.5 (V(mat)[1])
= 0 + 0.217 + 0 + 0.066 + 0 + 0.066
= 0.349
For the 3rd dimension (the third number in each value vector):
Weighted sum for 3rd dimension =
0.217 * 0.0 (V(The)[2]) + 0.217 * 0.5 (V(cat)[2]) + 0.217 * 1.0 (V(sat)[2]) +
0.132 * 0.0 (V(on)[2]) + 0.217 * 0.5 (V(the)[2]) + 0.132 * 0.5 (V(mat)[2])
= 0 + 0.108 + 0.217 + 0 + 0.108 + 0.066
= 0.499
or can be simply to
Weighted sum = 0.217 * V(The) + 0.217 * V(cat) + 0.217 * V(sat) + 0.132 * V(on) + 0.217 * V(the) + 0.132 * V(mat)
V(The) = [1.0, 0.0, 0.0]
V(cat) = [0.0, 1.0, 0.5]
V(sat) = [0.0, 0.0, 1.0]
V(on) = [0.5, 0.5, 0.0]
V(the) = [0.5, 0.0, 0.5]
V(mat) = [0.0, 0.5, 0.5]
Weighted sum =
0.217 * [1.0, 0.0, 0.0] + 0.217 * [0.0, 1.0, 0.5] + 0.217 * [0.0, 0.0, 1.0] +
0.132 * [0.5, 0.5, 0.0] + 0.217 * [0.5, 0.0, 0.5] + 0.132 * [0.0, 0.5, 0.5]
Weighted sum =
[0.217, 0.0, 0.0] + [0.0, 0.217, 0.108] + [0.0, 0.0, 0.217] +
[0.066, 0.066, 0.0] + [0.108, 0.0, 0.108] + [0.0, 0.066, 0.066]
Final result for "cat" = [0.391, 0.349, 0.499]
This vector [0.391, 0.349, 0.499]
is the new representation for "cat" after self-attention. It contains information from the word "cat" itself and the other words in the sentence, weighted by their relevance.
- The final result is a vector because each word's representation is multi-dimensional (3 dimensions in our simplified example, but in reality, it could be 512 or 768 dimensions).
- The self-attention mechanism computes a weighted combination of the value vectors, which are also vectors, so the result is a vector that has the same number of dimensions as the value vectors.
-
Parallel Processing:
- In the Transformer, each word (or token) is processed in parallel. This means that the words are not processed one at a time (like in RNNs or LSTMs). Instead, all the words in the sentence are passed into the model at once, and computations for each word can happen simultaneously.
-
Parallelism: The self-attention mechanism is computed in parallel because all words (or tokens) are processed simultaneously. This is a major advantage of the Transformer, as it allows for much faster processing compared to sequential models.
-
Dependency: While each word is processed in parallel, the self-attention mechanism ensures that the final output for each word depends on the other words in the sentence. This is what gives the model its ability to capture context and relationships between words.
-
Self-Attention Mechanism:
- The self-attention mechanism does create dependencies between words. Each word "attends" to every other word in the sentence, which means that the model looks at the relationships between words while processing the sentence.
- However, this attention calculation is done for all words in parallel, thanks to the structure of matrix operations. So, while words attend to each other, these calculations are done simultaneously for all words.
-
Independence and Dependencies in Self-Attention:
-
Independence in Processing: In terms of processing, the Transformer handles all words in parallel—each word is processed simultaneously through the model, as opposed to being processed one by one. This is a key efficiency gain in the Transformer, especially when compared to sequential models like RNNs or LSTMs.
-
Dependencies in Context: Even though each word is processed independently in terms of computation (i.e., matrix operations for each word are performed in parallel), the self-attention mechanism still captures the relationships between words. This happens because each word's representation is updated based on how it attends to all other words in the sentence.
-
How This Happens: Self-attention computes a weighted sum of the representations of all other words for each word. So, each word’s final representation depends on its relationship with all the other words, even though the computations are done in parallel.
-
In the Transformer model, multiple encoder layers are stacked on top of each other. Each encoder takes the output of the previous encoder as input and refines the representation of the input sentence. The bottom-most encoder starts with the word embeddings, while higher encoders use the outputs of the encoders below them.
Each encoder consists of two main sub-layers:
- Self-Attention Layer.
- Feed-Forward Neural Network (FFN).
the output of one layer’s FFN becomes the input to the self-attention mechanism of the next layer.
-
Query (Q):
- The query vector represents the current word (or token) that is being processed. The model uses this vector to determine how much attention the current word should pay to the other words in the sequence.
- Essentially, it acts like a question: How relevant is this word to the other words in the sequence?
-
Key (K):
- The key vector represents each word in the sequence and is used to compare with the query vector. Each word has its own key vector, and the model compares the query with all the keys to decide how much attention to give to each word.
- The key acts like an index: How closely does this word match the query?
-
Value (V):
- The value vector represents the actual information that will be used to update the word's representation. Once the model has determined how much attention to give to each word (using the query and key), it uses the value vectors to generate the final output.
- The value acts like the content: What information do we want to use from this word?
In self-attention, the attention score between two tokens iii and jjj is calculated as:
-
$Q_i \cdot K_j^T$ is the dot product of the query vector for token$i$ and the key vector for token$j$ . - The dimensionality of both
$Q$ and$K$ is$d_k$ , and the result of their dot product is a scalar that represents the similarity between the query and key vectors. - The score is divided by
$\sqrt{d_k}$ to prevent large values when$d_k$ is large, which could lead to extremely high softmax outputs and thus poor gradient flow during training.
The reason we divide by
When you compute the dot product of two vectors, the expected magnitude of the result depends on the dimensionality of the vectors. If the dimensionality dkd_kdk is large, the dot product will tend to be larger, even if the individual components of the vectors are relatively small.
- Suppose QiQ_iQi and KjK_jKj are random vectors, and each component of these vectors is on average around 1.
- If QiQ_iQi and KjK_jKj have a dimensionality of dkd_kdk, the dot product is the sum of dkd_kdk terms. Each of these terms is the product of corresponding components from QiQ_iQi and KjK_jKj. If each product is around 1, the sum will roughly be dkd_kdk.
For example:
- If dk=64d_k = 64dk=64, the dot product might sum to something like 64.
- If dk=1024d_k = 1024dk=1024, the dot product might sum to something like 1024.
This means that as dkd_kdk increases, the dot product grows proportionally to dkd_kdk. To normalize the magnitude of this dot product so that it doesn't grow too large as dkd_kdk increases, we need to scale it. But dividing by dkd_kdk itself would overcompensate, making the values too small.
The dot product scales linearly with dkd_kdk, but the magnitude (or norm) of a vector scales with the square root of the number of dimensions. This is a statistical property of high-dimensional spaces: when you sum random variables (the components of the vectors in this case), their total magnitude grows with the square root of the number of components, not linearly.
Thus, dividing by dk\sqrt{d_k}dk appropriately adjusts the scale of the dot product without making it too small or too large.
While the mean of the dot product (the expected value) might be close to zero because of the symmetry between positive and negative values, the magnitude of the dot product is more influenced by the variance of the individual components, and variance grows with dkd_kdk.
Here's why:
Let’s assume that the elements of QiQ_iQi and KjK_jKj are random variables drawn from a distribution with a mean of 0 and a variance of 1. The dot product Qi⋅KjTQ_i \cdot K_j^TQi⋅KjT is the sum of dkd_kdk products between corresponding elements of QiQ_iQi and KjK_jKj.
Each product Qi[k]⋅Kj[k]Q_i[k] \cdot K_j[k]Qi[k]⋅Kj[k] is a random variable with an expected value of 0 (since the mean is 0) but with some variance.
When we sum up dkd_kdk independent random variables, even if the mean of each random variable is 0, the variance of the sum increases as we add more terms.
Here’s why:
- The variance of the sum of dkd_kdk independent random variables (with a variance of 1) is equal to dk×variance of each termd_k \times \text{variance of each term}dk×variance of each term.
- If each product has a variance of 1, then the variance of the dot product grows as dkd_kdk. The dot product will have variance proportional to dkd_kdk.
In mathematical terms:
Variance of the dot product=dk×variance of each product\text{Variance of the dot product} = d_k \times \text{variance of each product}Variance of the dot product=dk×variance of each product
Thus, even though the mean of the dot product is 0, the variance grows with dkd_kdk. Variance measures how much the individual values can deviate from the mean. So, as dkd_kdk increases, the spread of possible values (both positive and negative) becomes larger.
The magnitude of the dot product is the absolute value of the sum of these products. The expected magnitude is not simply 0 because:
- The positive and negative components do not cancel each other perfectly every time.
- Even though the mean is close to zero, the fluctuations around the mean become larger as dkd_kdk increases due to the increasing variance.
- Therefore, the dot product might be small sometimes, but as dkd_kdk increases, there is a higher chance that the dot product will be large in magnitude (whether positive or negative).
Think of it like rolling a large number of dice. If you roll one die, the expected sum is around the midpoint of the die's range (3.5). If you roll two dice, the expected sum is still 7 (2 × 3.5), but the spread of possible outcomes (the variance) increases: you could roll a 2 (two 1s) or a 12 (two 6s), with many values in between.
As you roll more dice, the expected sum per die remains the same, but the spread of the possible total sum increases, and the extremes (very low or very high sums) become more likely.
Similarly, in the dot product, as dkd_kdk increases, the expected value remains near zero, but the magnitude of the result (positive or negative) is more likely to deviate from zero due to the larger spread.
This is why we scale the dot product by dk\sqrt{d_k}dk:
- As dkd_kdk increases, the variance (and thus the magnitude) of the dot product grows.
- Dividing by dk\sqrt{d_k}dk ensures that the dot product remains in a reasonable range, preventing large dot product values from dominating the softmax and attention calculations.
In the Transformer architecture, the matrices WQW_QWQ, WKW_KWK, and WVW_VWV are learned weight matrices used to project the input embeddings into the query (QQQ), key (KKK), and value (VVV) vectors. These matrices are trained during the model's training process, and their values are updated through backpropagation, like any other neural network parameters.
Here's how they work in the Transformer:
Let’s assume:
- You have an input sequence of tokens X=[x1,x2,...,xn]X = [x_1, x_2, ..., x_n]X=[x1,x2,...,xn], where X∈Rn×dmodelX \in \mathbb{R}^{n \times d_{\text{model}}}X∈Rn×dmodel (with nnn being the number of tokens, and dmodeld_{\text{model}}dmodel being the dimensionality of each token's embedding).
- Each token xix_ixi is represented as an embedding of size dmodeld_{\text{model}}dmodel.
To compute the queries, keys, and values, the model uses learned weight matrices WQW_QWQ, WKW_KWK, and WVW_VWV to linearly transform the input embeddings.
For each token in the input sequence, the queries, keys, and values are computed as follows:
-
Query (QQQ) is computed using the weight matrix WQW_QWQ:
Q=XWQQ = XW_QQ=XWQ
where WQ∈Rdmodel×dkW_Q \in \mathbb{R}^{d_{\text{model}} \times d_k}WQ∈Rdmodel×dk is a learned matrix, and Q∈Rn×dkQ \in \mathbb{R}^{n \times d_k}Q∈Rn×dk.
-
Key (KKK) is computed using the weight matrix WKW_KWK:
K=XWKK = XW_KK=XWK
where WK∈Rdmodel×dkW_K \in \mathbb{R}^{d_{\text{model}} \times d_k}WK∈Rdmodel×dk, and K∈Rn×dkK \in \mathbb{R}^{n \times d_k}K∈Rn×dk.
-
Value (VVV) is computed using the weight matrix WVW_VWV:
V=XWVV = XW_VV=XWV
where WV∈Rdmodel×dvW_V \in \mathbb{R}^{d_{\text{model}} \times d_v}WV∈Rdmodel×dv, and V∈Rn×dvV \in \mathbb{R}^{n \times d_v}V∈Rn×dv.
- X∈Rn×dmodelX \in \mathbb{R}^{n \times d_{\text{model}}}X∈Rn×dmodel: The input token embeddings (sequence of tokens, each of size dmodeld_{\text{model}}dmodel).
- WQ∈Rdmodel×dkW_Q \in \mathbb{R}^{d_{\text{model}} \times d_k}WQ∈Rdmodel×dk: The learned weight matrix that projects the input embeddings to queries of size dkd_kdk.
- WK∈Rdmodel×dkW_K \in \mathbb{R}^{d_{\text{model}} \times d_k}WK∈Rdmodel×dk: The learned weight matrix that projects the input embeddings to keys of size dkd_kdk.
- WV∈Rdmodel×dvW_V \in \mathbb{R}^{d_{\text{model}} \times d_v}WV∈Rdmodel×dv: The learned weight matrix that projects the input embeddings to values of size dvd_vdv.
These weight matrices WQW_QWQ, WKW_KWK, and WVW_VWV are learned during the model’s training process.
In multi-head attention, these transformations are done independently for each attention head. If there are hhh heads, then each head has its own set of WQ(i)W_Q^{(i)}WQ(i), WK(i)W_K^{(i)}WK(i), and WV(i)W_V^{(i)}WV(i) weight matrices for each head iii, and the size of each head is dhead=dmodel/hd_{\text{head}} = d_{\text{model}} / hdhead=dmodel/h.
Thus, for each head:
Q(i)=XWQ(i),K(i)=XWK(i),V(i)=XWV(i)Q^{(i)} = XW_Q^{(i)}, \quad K^{(i)} = XW_K^{(i)}, \quad V^{(i)} = XW_V^{(i)}Q(i)=XWQ(i),K(i)=XWK(i),V(i)=XWV(i)
Each attention head computes its own set of queries, keys, and values, and the outputs are concatenated at the end.
These weight matrices WQW_QWQ, WKW_KWK, and WVW_VWV are learned through training. During training:
- The model computes attention scores using the queries and keys.
- The attention scores are used to compute the weighted sum of the values.
- The result of this weighted sum flows through the rest of the model, and eventually, the loss function measures how well the model is doing on a specific task (e.g., language translation or text generation).
- The loss is backpropagated through the model, including the weight matrices WQW_QWQ, WKW_KWK, and WVW_VWV, which get updated using gradient descent or a similar optimization algorithm.
- Initialization: Initially, WQW_QWQ, WKW_KWK, and WVW_VWV are usually initialized randomly or with a small Gaussian distribution.
- Training: As the model sees more data during training, the weight matrices WQW_QWQ, WKW_KWK, and WVW_VWV are adjusted by backpropagation to minimize the loss function. Over time, these weight matrices learn how to project the input embeddings into queries, keys, and values that produce effective attention scores and outputs.
- WQW_QWQ, WKW_KWK, and WVW_VWV are learned weight matrices in the Transformer model.
- They project the input embeddings XXX into queries (QQQ), keys (KKK), and values (VVV).
- These weight matrices are updated during training via backpropagation and are used to compute the attention scores and apply the self-attention mechanism.
The output of each attention head in multi-head attention is computed for every token in the input sequence, not just one token. However, when we refer to an "output vector of size dvd_vdv" for each head, we're talking about the size of the attention output for each token within the sequence.
Let me explain how this works for all tokens, not just one, and why we describe the output size for one token at a time:
When the attention mechanism is applied in the Transformer, it works token by token for the entire sequence. Suppose you have an input sequence of length nnn (i.e., nnn tokens). The Transformer processes the entire sequence at once in parallel, meaning it computes the attention for all tokens simultaneously.
-
For each token tit_iti in the sequence, the model generates:
- A query vector QiQ_iQi,
- A key vector KiK_iKi,
- A value vector ViV_iVi, where all of these vectors are of size dkd_kdk, dkd_kdk, and dvd_vdv, respectively.
-
Attention scores are calculated for each token by comparing its query vector QiQ_iQi with the key vectors KjK_jKj of every other token tjt_jtj in the sequence. This generates attention weights, which are then applied to the value vectors VjV_jVj to produce the final attention output for token tit_iti.
After applying the attention mechanism:
- For each token tit_iti, each head produces an output vector of size dvd_vdv.
- If there are hhh attention heads, each head will independently compute a different output for the token.
The reason we say each head produces an output of size dvd_vdv is because, for every token in the input sequence, the final result of applying attention is a vector of size dvd_vdv for that token.
- If the sequence length is nnn (i.e., nnn tokens), and each head produces an output of size dvd_vdv for each token, the output of a single attention head will have a shape of: Head Output∈Rn×dv\text{Head Output} \in \mathbb{R}^{n \times d_v}Head Output∈Rn×dv This means each token in the sequence has a corresponding output vector of size dvd_vdv from this attention head.
-
If there are hhh attention heads, the model computes independent attention outputs for each token from each head. After each head has produced its output (of size dvd_vdv for each token), these outputs are concatenated along the last dimension.
-
So, after concatenating the outputs of hhh attention heads, the final concatenated output for the sequence has the shape:
Concatenated Output∈Rn×(h×dv)\text{Concatenated Output} \in \mathbb{R}^{n \times (h \times d_v)}Concatenated Output∈Rn×(h×dv)
This means each token in the sequence will have an output vector of size h×dvh \times d_vh×dv, where the information from all attention heads is combined.
Let’s assume:
- Sequence length n=5n = 5n=5 (i.e., 5 tokens),
- h=8h = 8h=8 attention heads,
- dv=64d_v = 64dv=64 (the dimensionality of the output from each head for each token).
Each attention head will produce an output of size 646464 for each token in the sequence. After applying attention, the output for each head will have the shape:
Single Head Output∈R5×64\text{Single Head Output} \in \mathbb{R}^{5 \times 64}Single Head Output∈R5×64
for the 5 tokens.
Once we concatenate the outputs of 8 heads, the final output for the entire sequence will have the shape:
Concatenated Output∈R5×(8×64)=R5×512\text{Concatenated Output} \in \mathbb{R}^{5 \times (8 \times 64)} = \mathbb{R}^{5 \times 512}Concatenated Output∈R5×(8×64)=R5×512
This means each token now has an output vector of size 512, which is the result of concatenating the outputs from all 8 heads.
When we refer to each head producing an output of size dvd_vdv, we’re focusing on the output for each token. Since the attention mechanism processes the entire sequence at once, each token gets its own output vector of size dvd_vdv from each head. These per-token outputs are what get concatenated and processed further by the Transformer.
The output of each attention head in multi-head attention is computed for every token in the input sequence, not just one token. However, when we refer to an "output vector of size dvd_vdv" for each head, we're talking about the size of the attention output for each token within the sequence.
Let me explain how this works for all tokens, not just one, and why we describe the output size for one token at a time:
When the attention mechanism is applied in the Transformer, it works token by token for the entire sequence. Suppose you have an input sequence of length nnn (i.e., nnn tokens). The Transformer processes the entire sequence at once in parallel, meaning it computes the attention for all tokens simultaneously.
-
For each token tit_iti in the sequence, the model generates:
- A query vector QiQ_iQi,
- A key vector KiK_iKi,
- A value vector ViV_iVi, where all of these vectors are of size dkd_kdk, dkd_kdk, and dvd_vdv, respectively.
-
Attention scores are calculated for each token by comparing its query vector QiQ_iQi with the key vectors KjK_jKj of every other token tjt_jtj in the sequence. This generates attention weights, which are then applied to the value vectors VjV_jVj to produce the final attention output for token tit_iti.
After applying the attention mechanism:
- For each token tit_iti, each head produces an output vector of size dvd_vdv.
- If there are hhh attention heads, each head will independently compute a different output for the token.
The reason we say each head produces an output of size dvd_vdv is because, for every token in the input sequence, the final result of applying attention is a vector of size dvd_vdv for that token.
- If the sequence length is nnn (i.e., nnn tokens), and each head produces an output of size dvd_vdv for each token, the output of a single attention head will have a shape of: Head Output∈Rn×dv\text{Head Output} \in \mathbb{R}^{n \times d_v}Head Output∈Rn×dv This means each token in the sequence has a corresponding output vector of size dvd_vdv from this attention head.
-
If there are hhh attention heads, the model computes independent attention outputs for each token from each head. After each head has produced its output (of size dvd_vdv for each token), these outputs are concatenated along the last dimension.
-
So, after concatenating the outputs of hhh attention heads, the final concatenated output for the sequence has the shape:
Concatenated Output∈Rn×(h×dv)\text{Concatenated Output} \in \mathbb{R}^{n \times (h \times d_v)}Concatenated Output∈Rn×(h×dv)
This means each token in the sequence will have an output vector of size h×dvh \times d_vh×dv, where the information from all attention heads is combined.
Let’s assume:
- Sequence length n=5n = 5n=5 (i.e., 5 tokens),
- h=8h = 8h=8 attention heads,
- dv=64d_v = 64dv=64 (the dimensionality of the output from each head for each token).
Each attention head will produce an output of size 646464 for each token in the sequence. After applying attention, the output for each head will have the shape:
Single Head Output∈R5×64\text{Single Head Output} \in \mathbb{R}^{5 \times 64}Single Head Output∈R5×64
for the 5 tokens.
Once we concatenate the outputs of 8 heads, the final output for the entire sequence will have the shape:
Concatenated Output∈R5×(8×64)=R5×512\text{Concatenated Output} \in \mathbb{R}^{5 \times (8 \times 64)} = \mathbb{R}^{5 \times 512}Concatenated Output∈R5×(8×64)=R5×512
This means each token now has an output vector of size 512, which is the result of concatenating the outputs from all 8 heads.
When we refer to each head producing an output of size dvd_vdv, we’re focusing on the output for each token. Since the attention mechanism processes the entire sequence at once, each token gets its own output vector of size dvd_vdv from each head. These per-token outputs are what get concatenated and processed further by the Transformer.
To give a concrete example of how self-attention works, let's walk through the process of transforming tokens into query, key, and value vectors, including their shapes.
Imagine we have a simple input sequence of three tokens:
Input Sequence: "The cat sat"
Each token in this sequence is represented by an embedding vector. Let's assume each token is represented by a vector of size 4 (this is the embedding dimension, though in practice, embedding dimensions are often much larger, like 512 or 1024).
So, the input for the self-attention layer can be represented as a matrix with shape:
- Input Shape:
(3, 4)
— 3 tokens, each with a 4-dimensional embedding.
[
[0.1, 0.2, 0.3, 0.4], # "The" -> Token 1 embedding
[0.5, 0.6, 0.7, 0.8], # "cat" -> Token 2 embedding
[0.9, 1.0, 1.1, 1.2] # "sat" -> Token 3 embedding
]
For each token, we will create three vectors: Query, Key, and Value. These are computed by multiplying the original token embeddings by three learned matrices: W_q
, W_k
, and W_v
(for query, key, and value, respectively).
Assume the output dimension of these transformations is also 4. So, W_q
, W_k
, and W_v
are matrices of shape (4, 4)
.
- Query (Q) = Input Embedding *
W_q
- Key (K) = Input Embedding *
W_k
- Value (V) = Input Embedding *
W_v
Each token embedding (which is of shape (4,)
) gets multiplied by the learned weight matrices to produce new vectors.
For simplicity, let’s assume:
W_q = W_k = W_v = [
[0.1, 0.2, 0.3, 0.4],
[0.5, 0.6, 0.7, 0.8],
[0.9, 1.0, 1.1, 1.2],
[1.3, 1.4, 1.5, 1.6]
]
So for each token, after multiplying the input embedding by W_q
, W_k
, and W_v
, you get:
[
[0.3, 0.7, 1.1, 1.5], # Query for "The"
[0.7, 1.5, 2.3, 3.1], # Query for "cat"
[1.1, 2.3, 3.5, 4.7] # Query for "sat"
]
[
[0.3, 0.7, 1.1, 1.5], # Key for "The"
[0.7, 1.5, 2.3, 3.1], # Key for "cat"
[1.1, 2.3, 3.5, 4.7] # Key for "sat"
]
[
[0.3, 0.7, 1.1, 1.5], # Value for "The"
[0.7, 1.5, 2.3, 3.1], # Value for "cat"
[1.1, 2.3, 3.5, 4.7] # Value for "sat"
]
Now, we compute attention scores by taking the dot product of each token's query with every token's key (including itself). This step helps determine how much each token should pay attention to others.
For simplicity, let's compute attention for the first token, "The":
- Query for "The" =
[0.3, 0.7, 1.1, 1.5]
- Keys for all tokens:
- "The" =
[0.3, 0.7, 1.1, 1.5]
- "cat" =
[0.7, 1.5, 2.3, 3.1]
- "sat" =
[1.1, 2.3, 3.5, 4.7]
- "The" =
- Score between "The" and "The" =
(0.3*0.3) + (0.7*0.7) + (1.1*1.1) + (1.5*1.5) = 3.74
- Score between "The" and "cat" =
(0.3*0.7) + (0.7*1.5) + (1.1*2.3) + (1.5*3.1) = 8.74
- Score between "The" and "sat" =
(0.3*1.1) + (0.7*2.3) + (1.1*3.5) + (1.5*4.7) = 13.74
The raw scores are normalized using softmax, which converts them into probabilities (attention weights) that sum to 1.
For example, the softmax of the scores [3.74, 8.74, 13.74]
might be:
- Weights:
[0.02, 0.28, 0.70]
These attention weights are then used to compute a weighted sum of the Value vectors for each token.
For the first token ("The"), the weighted sum would be:
- Weighted sum =
0.02 * Value(The) + 0.28 * Value(cat) + 0.70 * Value(sat)
= 0.02 * [0.3, 0.7, 1.1, 1.5] + 0.28 * [0.7, 1.5, 2.3, 3.1] + 0.70 * [1.1, 2.3, 3.5, 4.7]
= [1.0, 2.0, 3.0, 4.0] # This is the output for token "The"
This new vector [1.0, 2.0, 3.0, 4.0]
becomes the transformed representation of "The" after self-attention, incorporating information from "cat" and "sat".
- Input Shape:
(3, 4)
— 3 tokens, each with a 4-dimensional embedding. - Query, Key, Value Shapes: Each
(3, 4)
— 3 tokens, each with a 4-dimensional query, key, and value vector. - Attention Weights Shape:
(3, 3)
— Attention weights for each token attending to all 3 tokens. - Output Shape:
(3, 4)
— The output is still 3 tokens, each with a 4-dimensional vector, but now transformed by self-attention.
This process allows each token to gather contextual information from other tokens in the sequence, capturing long-range dependencies in the data.
In a Transformer model, as words pass through each encoder layer (such as encoder 3, encoder 4, and so on), the self-attention mechanism in each layer progressively refines the understanding of the word based on the relationships it has with other words in the sentence.
Let’s break down what happens in encoder 3 and encoder 4 when processing the word "it":
By the time the word "it" reaches encoder 3, it has already passed through the first two layers of encoding. At this stage:
- The self-attention mechanism in encoder 3 is processing the word "it" by looking at its relationship with other words in the sentence. It might still be considering multiple candidates, such as "the street" and "the animal."
- The attention scores are computed between "it" and every other word in the sentence, but at this level, the model is still refining its understanding.
- For instance, encoder 3 might begin giving higher attention scores to "the animal" based on the context of the sentence, but it's not fully certain yet.
- However, the encoding of "it" now carries a bit more context from its relationship with "the animal."
So, at encoder 3, the model may have a partial association between "it" and "the animal," but it may still consider other words like "the street" as possible referents.
By the time the word "it" reaches encoder 4, the model has further refined the associations built in previous layers. At this stage:
- The self-attention mechanism in encoder 4 is getting closer to resolving the ambiguity. It looks at the relationships established in previous layers and strengthens the association between "it" and "the animal."
- The model now understands more clearly, based on the sentence structure and the context of the surrounding words, that "it" refers to "the animal" and not "the street."
- The attention scores between "it" and "the animal" are likely much higher now, compared to the earlier layers. The encoding of "it" is becoming more heavily influenced by "the animal" rather than "the street."
At encoder 4, the model has a stronger confidence that "it" refers to "the animal" and has mostly incorporated this relationship into the encoding.
By the time the word "it" reaches encoder 5, the model has almost fully resolved the ambiguity. The self-attention mechanism now gives the strongest attention to "the animal" and has baked this relationship into the encoding of "it."
At this point, the representation of "it" contains information that indicates "it" refers to "the animal" based on the attention mechanism in the earlier encoders, allowing the model to make accurate predictions or translations.
- Encoder 3: Starts refining the association between "it" and possible referents like "the animal" and "the street," but the model is not fully confident yet.
- Encoder 4: Further strengthens the relationship between "it" and "the animal," with much clearer context that "it" likely refers to "the animal."
- Encoder 5: Fully incorporates the meaning of "the animal" into the encoding of "it," allowing the model to clearly understand that "it" refers to "the animal."
The deeper the layer in the Transformer, the more refined and contextually aware the word representations become, allowing the model to handle complex language dependencies more effectively.
the dimensionality of the positional encoding is the same as the dimensionality of the word embedding vector.
Imagine we have an input vector X representing some word embedding, and this vector goes through a sub-layer (like self-attention or a feed-forward neural network). The key idea of a residual connection is that instead of just passing the output of the sub-layer forward, we add the input back to the output.
-
Input (X): Let's say the input vector to the sub-layer is:
X=[1.5,2.0,−0.5]X = [1.5, 2.0, -0.5]X=[1.5,2.0,−0.5]
-
Sub-layer Output: The sub-layer (such as self-attention or a feed-forward neural network) processes X and produces some new output Y. For simplicity, let's say the output is:
Y=[0.8,1.2,−0.1]Y = [0.8, 1.2, -0.1]Y=[0.8,1.2,−0.1]
-
Next Step: Normally, the model would pass Y to the next layer for further processing. But without any residual connection, we could lose important information from X as we move deeper into the network.
-
Input (X): The same input vector as before:
X=[1.5,2.0,−0.5]X = [1.5, 2.0, -0.5]X=[1.5,2.0,−0.5]
-
Sub-layer Output (Y): The sub-layer processes X and produces an output Y:
Y=[0.8,1.2,−0.1]Y = [0.8, 1.2, -0.1]Y=[0.8,1.2,−0.1]
-
Add Residual Connection: Instead of just passing Y forward, we add the original input X to the output Y:
Residual Output=X+Y=[1.5,2.0,−0.5]+[0.8,1.2,−0.1]\text{Residual Output} = X + Y = [1.5, 2.0, -0.5] + [0.8, 1.2, -0.1]Residual Output=X+Y=[1.5,2.0,−0.5]+[0.8,1.2,−0.1]
This gives us:
Residual Output=[2.3,3.2,−0.6]\text{Residual Output} = [2.3, 3.2, -0.6]Residual Output=[2.3,3.2,−0.6]
-
Next Step: Now, we pass this new residual output ([2.3, 3.2, -0.6]) to the next layer.
- Preventing Information Loss: By adding the input X back to the output, we ensure that the information from X is not lost as we move deeper into the network.
- Better Gradient Flow: In deep networks, gradients can sometimes vanish or explode, making it hard to train the model. Adding the residual connection makes it easier for the model to backpropagate gradients and learn more effectively.
Think of a residual connection like taking notes in a lecture. Let's say you're trying to summarize everything you learned at the end of each lecture (this is like the output of each layer in the model). However, instead of just relying on your summary, you also keep the original notes (the input). This way, even if your summary is not perfect, you still have all the details from the lecture.
In this case:
- X is like your original notes.
- Y is like your summary.
- The residual connection ensures you have both the summary (Y) and the original notes (X) available for the next step, giving you the full picture and preventing any important information from being lost.
In every encoder and decoder layer of a Transformer:
- Self-attention is computed, but instead of relying solely on the output of the self-attention mechanism, the original input (embeddings or vectors from the previous layer) is added back.
- The same happens for the feed-forward network sub-layer. The output of the FFNN is combined with its original input before passing to the next layer.
By doing this, the Transformer ensures that as the model gets deeper, it retains important information from earlier layers and improves learning.
This is how residual connections (or skip connections) work to ensure smooth information flow and better gradient management.
🌟🌟🌟
Let’s break down the role of Add & Normalize with a clear example.
In a Transformer model, after each sub-layer (like self-attention or feed-forward neural network), two things happen:
- Add (Residual Connection): The original input to the sub-layer is added back to the output of that sub-layer.
- Layer Normalization: The result is normalized, ensuring stable training.
We will look at this process in two parts: Self-Attention and Feed-Forward Network (FFN), using a simple example.
-
Original Input (X1): This could be the output from a previous layer (or an embedding). Let’s assume it’s a vector:
X1=[1.0,2.0,−1.0]X1 = [1.0, 2.0, -1.0]X1=[1.0,2.0,−1.0]
-
Output from Self-Attention (Y1): After the self-attention mechanism processes the input, it produces an output. Let’s say the output of self-attention is:
Y1=[0.5,1.5,−0.5]Y1 = [0.5, 1.5, -0.5]Y1=[0.5,1.5,−0.5]
- We take the original input X1 and add it to the output of the self-attention mechanism Y1: Residual Output=X1+Y1=[1.0,2.0,−1.0]+[0.5,1.5,−0.5]\text{Residual Output} = X1 + Y1 = [1.0, 2.0, -1.0] + [0.5, 1.5, -0.5]Residual Output=X1+Y1=[1.0,2.0,−1.0]+[0.5,1.5,−0.5] Residual Output=[1.5,3.5,−1.5]\text{Residual Output} = [1.5, 3.5, -1.5]Residual Output=[1.5,3.5,−1.5]
- Now, we apply layer normalization to the residual output. This means that we normalize the values so that the resulting vector has a mean of 0 and a variance of 1.
-
Mean: First, calculate the mean of the residual output vector.
Mean=1.5+3.5+(−1.5)3=3.53≈1.17\text{Mean} = \frac{1.5 + 3.5 + (-1.5)}{3} = \frac{3.5}{3} \approx 1.17Mean=31.5+3.5+(−1.5)=33.5≈1.17
-
Variance: Next, calculate the variance. The variance is the average of the squared differences from the mean.
Variance=(1.5−1.17)2+(3.5−1.17)2+(−1.5−1.17)23\text{Variance} = \frac{(1.5 - 1.17)^2 + (3.5 - 1.17)^2 + (-1.5 - 1.17)^2}{3}Variance=3(1.5−1.17)2+(3.5−1.17)2+(−1.5−1.17)2 ≈(0.33)2+(2.33)2+(−2.67)23\approx \frac{(0.33)^2 + (2.33)^2 + (-2.67)^2}{3}≈3(0.33)2+(2.33)2+(−2.67)2 ≈0.11+5.43+7.133≈4.89\approx \frac{0.11 + 5.43 + 7.13}{3} \approx 4.89≈30.11+5.43+7.13≈4.89
-
Normalize: Finally, normalize each value by subtracting the mean and dividing by the standard deviation (which is the square root of the variance):
Standard Deviation=4.89≈2.21\text{Standard Deviation} = \sqrt{4.89} \approx 2.21Standard Deviation=4.89≈2.21
So the normalized values are:
Normalized Output=1.5−1.172.21,3.5−1.172.21,−1.5−1.172.21\text{Normalized Output} = \frac{1.5 - 1.17}{2.21}, \frac{3.5 - 1.17}{2.21}, \frac{-1.5 - 1.17}{2.21}Normalized Output=2.211.5−1.17,2.213.5−1.17,2.21−1.5−1.17 Normalized Output=[0.15,1.06,−1.19]\text{Normalized Output} = [0.15, 1.06, -1.19]Normalized Output=[0.15,1.06,−1.19]
The layer normalized output is:
[0.15,1.06,−1.19][0.15, 1.06, -1.19][0.15,1.06,−1.19]
This is now the input to the next sub-layer (the feed-forward neural network).
Now the feed-forward neural network (FFN) works similarly, but on its own:
-
Original Input (X2): The input to the feed-forward network (which is the output from the previous self-attention sub-layer).
X2=[0.15,1.06,−1.19]X2 = [0.15, 1.06, -1.19]X2=[0.15,1.06,−1.19]
-
Output from FFN (Y2): After the FFN processes the input, it produces an output. Let’s say the output of the FFN is:
Y2=[0.25,0.80,−1.0]Y2 = [0.25, 0.80, -1.0]Y2=[0.25,0.80,−1.0]
- We take the original input X2 and add it to the output of the FFN Y2: Residual Output=X2+Y2=[0.15,1.06,−1.19]+[0.25,0.80,−1.0]\text{Residual Output} = X2 + Y2 = [0.15, 1.06, -1.19] + [0.25, 0.80, -1.0]Residual Output=X2+Y2=[0.15,1.06,−1.19]+[0.25,0.80,−1.0] Residual Output=[0.40,1.86,−2.19]\text{Residual Output} = [0.40, 1.86, -2.19]Residual Output=[0.40,1.86,−2.19]
- Apply layer normalization to the residual output:
- Mean: Mean=0.40+1.86+(−2.19)3=0.073≈0.023\text{Mean} = \frac{0.40 + 1.86 + (-2.19)}{3} = \frac{0.07}{3} \approx 0.023Mean=30.40+1.86+(−2.19)=30.07≈0.023
- Variance: Variance=(0.40−0.023)2+(1.86−0.023)2+(−2.19−0.023)23\text{Variance} = \frac{(0.40 - 0.023)^2 + (1.86 - 0.023)^2 + (-2.19 - 0.023)^2}{3} Variance=3(0.40−0.023)2+(1.86−0.023)2+(−2.19−0.023)2 ≈2.15\approx 2.15≈2.15
- Standard Deviation: 2.15≈1.47\sqrt{2.15} \approx 1.472.15≈1.47
- Normalized Output: Normalized Output=0.40−0.0231.47,1.86−0.0231.47,−2.19−0.0231.47\text{Normalized Output} = \frac{0.40 - 0.023}{1.47}, \frac{1.86 - 0.023}{1.47}, \frac{-2.19 - 0.023}{1.47}Normalized Output=1.470.40−0.023,1.471.86−0.023,1.47−2.19−0.023 ≈[0.26,1.25,−1.50]\approx [0.26, 1.25, -1.50]≈[0.26,1.25,−1.50]
The layer normalized output is:
[0.26,1.25,−1.50][0.26, 1.25, -1.50][0.26,1.25,−1.50]
This is the output passed to the next encoder layer.
- Residual Connection (Add): The original input to the sub-layer is added back to the output of that sub-layer.
- Layer Normalization (Normalize): The result of the residual connection is normalized, ensuring stable training by keeping the mean close to 0 and the variance close to 1.
This Add & Normalize process happens after both the self-attention sub-layer and the feed-forward neural network (FFN) sub-layer, ensuring that information flows smoothly through the network and that training is more stable due to improved gradient flow.
🌟🌟🌟 prenorm and postnorm
Pre-Norm and Post-Norm refer to two different ways of applying layer normalization in Transformer models, specifically in relation to the residual connections. Let's explain both approaches and their differences.
In the original Transformer model (as described in the paper "Attention is All You Need"), Post-Norm is used. This means that layer normalization is applied after the residual connection.
Here is the typical order of operations:
- Sub-layer (e.g., Self-Attention or Feed-Forward Network) processes the input and produces an output.
- The output from the sub-layer is added to the original input (this is the residual connection).
- The result of the residual connection is passed through a layer normalization step.
- Input (X):
[1.0, 2.0, -1.0]
- Sub-layer Output (Y):
[0.5, 1.5, -0.5]
- Residual Connection: Add X and Y: Residual Output=X+Y=[1.0,2.0,−1.0]+[0.5,1.5,−0.5]=[1.5,3.5,−1.5]\text{Residual Output} = X + Y = [1.0, 2.0, -1.0] + [0.5, 1.5, -0.5] = [1.5, 3.5, -1.5]Residual Output=X+Y=[1.0,2.0,−1.0]+[0.5,1.5,−0.5]=[1.5,3.5,−1.5]
- Layer Normalization: Normalize the residual output: Normalized Output=LayerNorm([1.5,3.5,−1.5])\text{Normalized Output} = \text{LayerNorm}([1.5, 3.5, -1.5])Normalized Output=LayerNorm([1.5,3.5,−1.5])
- The result after normalization is passed to the next layer.
In Post-Norm, the residual addition happens before the normalization.
- Preservation of Gradient Flow: The residual connection helps with gradient flow, preventing vanishing gradients, while the layer normalization stabilizes the training.
However, some research suggests that Post-Norm Transformers can suffer from instability when training deep models with many layers.
We'll start with the same input X as before and go through each step, applying layer normalization first before proceeding to the sub-layer and residual connection.
We have the original input vector:
X=[1.0,2.0,−1.0]X = [1.0, 2.0, -1.0]X=[1.0,2.0,−1.0]
Next, we apply layer normalization to the input vector X. Layer normalization adjusts the input so that it has a mean of 0 and a variance of 1.
Mean=1.0+2.0+(−1.0)3=2.03≈0.67\text{Mean} = \frac{1.0 + 2.0 + (-1.0)}{3} = \frac{2.0}{3} \approx 0.67Mean=31.0+2.0+(−1.0)=32.0≈0.67
Variance is calculated by finding the average squared difference from the mean.
Variance=(1.0−0.67)2+(2.0−0.67)2+(−1.0−0.67)23\text{Variance} = \frac{(1.0 - 0.67)^2 + (2.0 - 0.67)^2 + (-1.0 - 0.67)^2}{3}Variance=3(1.0−0.67)2+(2.0−0.67)2+(−1.0−0.67)2 =(0.33)2+(1.33)2+(−1.67)23= \frac{(0.33)^2 + (1.33)^2 + (-1.67)^2}{3}=3(0.33)2+(1.33)2+(−1.67)2 =0.11+1.77+2.793=4.673≈1.56= \frac{0.11 + 1.77 + 2.79}{3} = \frac{4.67}{3} \approx 1.56=30.11+1.77+2.79=34.67≈1.56
Standard Deviation=1.56≈1.25\text{Standard Deviation} = \sqrt{1.56} \approx 1.25Standard Deviation=1.56≈1.25
Now we normalize each element in X using the formula:
Normalized Input=Input−MeanStandard Deviation\text{Normalized Input} = \frac{\text{Input} - \text{Mean}}{\text{Standard Deviation}}Normalized Input=Standard DeviationInput−Mean
For each element:
- First element: 1.0−0.671.25≈0.27\frac{1.0 - 0.67}{1.25} \approx 0.271.251.0−0.67≈0.27
- Second element: 2.0−0.671.25≈1.07\frac{2.0 - 0.67}{1.25} \approx 1.071.252.0−0.67≈1.07
- Third element: −1.0−0.671.25≈−1.33\frac{-1.0 - 0.67}{1.25} \approx -1.331.25−1.0−0.67≈−1.33
So, the normalized input is:
Normalized Input=[0.27,1.07,−1.33]\text{Normalized Input} = [0.27, 1.07, -1.33]Normalized Input=[0.27,1.07,−1.33]
Now, we pass the normalized input through a sub-layer, such as a self-attention mechanism or a feed-forward network. For simplicity, let’s assume this sub-layer outputs the following vector Y:
Y=[0.5,1.0,−0.8]Y = [0.5, 1.0, -0.8]Y=[0.5,1.0,−0.8]
This is the output after the normalized input has been processed by the sub-layer.
In the residual connection step, we add the original input (X) back to the output of the sub-layer (Y). Remember, the original input is:
X=[1.0,2.0,−1.0]X = [1.0, 2.0, -1.0]X=[1.0,2.0,−1.0]
Now, we add X to Y:
Residual Output=X+Y=[1.0,2.0,−1.0]+[0.5,1.0,−0.8]\text{Residual Output} = X + Y = [1.0, 2.0, -1.0] + [0.5, 1.0, -0.8]Residual Output=X+Y=[1.0,2.0,−1.0]+[0.5,1.0,−0.8] Residual Output=[1.5,3.0,−1.8]\text{Residual Output} = [1.5, 3.0, -1.8]Residual Output=[1.5,3.0,−1.8]
The final output, after adding the residual connection, is:
Residual Output=[1.5,3.0,−1.8]\text{Residual Output} = [1.5, 3.0, -1.8]Residual Output=[1.5,3.0,−1.8]
This result is then passed to the next layer in the network.
In Pre-Norm, the layer normalization happens before the residual connection.
- Improved Stability for deeper models: Pre-Norm Transformers tend to be more stable when training deeper models. By applying layer normalization first, the inputs to the sub-layer are already well-behaved (normalized), which helps with training stability.
- Better Gradient Flow: Since the normalization happens earlier, it can help avoid exploding or vanishing gradients in very deep models.
Feature | Pre-Norm | Post-Norm |
---|---|---|
Normalization Location | Before the sub-layer (e.g., self-attention or FFN) | After the sub-layer (e.g., self-attention or FFN) |
Residual Connection | After the sub-layer | Before normalization, after residual connection |
Training Stability | More stable for deeper models (e.g., 24+ layers) | Can suffer from instability in very deep models |
Gradient Flow | Helps gradients flow through the network earlier, improving stability for deep networks | Gradient flow can become challenging as the network deepens |
- Pre-Norm normalizes the input before passing it through the sub-layer, which can lead to more stable training, especially in deeper models.
- Post-Norm normalizes the input after the sub-layer, which was the design used in the original Transformer model but may be less stable in very deep networks.
- Many recent Transformer architectures have adopted Pre-Norm due to its improved training stability in deeper models.
Pre-Norm provides more stable training, especially in deeper models, for a few key reasons:
- In very deep networks, gradients can either vanish (become too small) or explode (become too large) as they are backpropagated through many layers.
- In Pre-Norm, because layer normalization is applied before the sub-layer, it helps regulate the input to the sub-layer. This results in more controlled and well-behaved activations during both forward and backward passes.
- The normalized input has a mean of 0 and a standard deviation of 1, which ensures that the gradients do not become too large or too small as they flow through the layers. This is particularly useful in very deep models (e.g., 24+ layers) because it prevents gradient vanishing/explosion, making optimization more effective.
- When layer normalization is applied before the sub-layer, it ensures that the input to each sub-layer (e.g., self-attention or feed-forward network) is standardized. This means that each sub-layer receives a well-conditioned input that is consistent in scale and distribution.
- As a result, the sub-layers are more likely to learn effectively and converge faster. This avoids the problem of sub-layers receiving inputs that may be poorly scaled or distributed, which can slow down learning or make training unstable.
- Pre-Norm helps stabilize the training process as the number of layers increases. In Post-Norm, the normalization happens after the sub-layer, which means that the sub-layer operates on potentially unnormalized inputs (inputs that might have a large or varying distribution).
- In very deep networks, this can lead to instability, as the unnormalized outputs of deeper sub-layers may become harder to learn from. By normalizing before each sub-layer in Pre-Norm, the network ensures that each sub-layer works with stable inputs, making training more predictable and reducing the likelihood of divergence in deep models.
- In Pre-Norm, the original input to the sub-layer is added back after the sub-layer processing, which preserves important information as the network deepens.
- Because layer normalization is applied earlier in the process, the residual connection doesn’t distort or destabilize the input. This maintains a consistent flow of information, helping the model remain stable even as it goes through many layers.
- In Post-Norm, the sub-layer processes the raw input first, without normalization. If the sub-layer produces outputs with large variations, this can make the learning process less stable.
- Since normalization happens after the residual connection, it might not correct the instability introduced by the sub-layer, which can lead to problems like gradient explosion or vanishing, especially when the model has many layers (e.g., 24 or more).
- Pre-Norm ensures that the input to each sub-layer is well-behaved by normalizing it first, leading to smoother forward and backward propagation.
- It helps preserve gradients in deep models, improving learning and convergence, while avoiding the instability that can arise from using unnormalized inputs in deeper layers.
🌟🌟🌟 Let's explore why Layer Normalization (LayerNorm) is used instead of Batch Normalization (BatchNorm) in Transformers, along with an example to explain the difference and why the normalized input has a mean of 0 and a standard deviation of 1.
- BatchNorm normalizes across the batch dimension. This means that it computes the mean and variance for each feature by looking at all samples in a batch.
- It was originally designed for convolutional neural networks (CNNs), where the model processes images in mini-batches. Each feature map of the CNN is normalized using the statistics computed across the mini-batch.
- BatchNorm works well in cases where data is processed in batches (like in CNNs) because it can leverage the statistics of the entire batch.
-
Sequence Processing: Transformers work with sequential data (e.g., sentences in natural language processing or time series data), where each sequence is processed independently. For such data, normalizing across the batch doesn’t make sense because:
- Each sequence can have different lengths, and the relationships within a sequence are more important than comparing across different sequences.
-
Small Batch Sizes: In tasks like natural language processing, batch sizes are often small or vary due to different sequence lengths, making it hard for BatchNorm to compute meaningful statistics.
-
Batch Dependency: BatchNorm introduces a dependency on the batch statistics (mean and variance), which can make it unsuitable when the model needs to generalize well across different batches (especially when the batch size is small).
- LayerNorm normalizes the input across the feature dimension within each individual sample, not across the entire batch.
- This means that instead of normalizing each feature using the statistics of the entire batch, LayerNorm computes the mean and variance for each feature within a single sample (i.e., across all the features of a specific token or time step in a sequence).
-
Sequence Independence: LayerNorm is independent of the batch size and works well when each sequence needs to be processed individually.
- This is ideal for tasks like language modeling, where each token in a sequence is treated independently and normalized with respect to itself, not the entire batch.
-
Handles Variable-Length Sequences: Since LayerNorm normalizes across features within a single input, it works well for variable-length sequences and ensures consistent normalization across different sequence lengths.
-
No Batch Dependency: LayerNorm does not rely on batch statistics, which makes it more stable and effective for models like Transformers, where the input could vary in size or batch structure.
Layer normalization ensures that the output for each token has a mean of 0 and a standard deviation of 1. This is done to stabilize and regulate the network, ensuring that activations remain in a consistent range throughout training.
Here’s a step-by-step breakdown of how it works:
Consider a token embedding with 3 features:
X=[1.5,2.0,−0.5]X = [1.5, 2.0, -0.5]X=[1.5,2.0,−0.5]
Step 1: Compute the Mean: The mean is the average of all the features within the token vector:
Mean=1.5+2.0+(−0.5)3=3.03=1.0\text{Mean} = \frac{1.5 + 2.0 + (-0.5)}{3} = \frac{3.0}{3} = 1.0Mean=31.5+2.0+(−0.5)=33.0=1.0
Step 2: Compute the Variance: The variance measures how far the features are from the mean:
Variance=(1.5−1.0)2+(2.0−1.0)2+(−0.5−1.0)23\text{Variance} = \frac{(1.5 - 1.0)^2 + (2.0 - 1.0)^2 + (-0.5 - 1.0)^2}{3}Variance=3(1.5−1.0)2+(2.0−1.0)2+(−0.5−1.0)2 =(0.5)2+(1.0)2+(−1.5)23=0.25+1.0+2.253=3.53≈1.17= \frac{(0.5)^2 + (1.0)^2 + (-1.5)^2}{3} = \frac{0.25 + 1.0 + 2.25}{3} = \frac{3.5}{3} \approx 1.17=3(0.5)2+(1.0)2+(−1.5)2=30.25+1.0+2.25=33.5≈1.17
Step 3: Compute the Standard Deviation: The standard deviation is the square root of the variance:
Standard Deviation=1.17≈1.08\text{Standard Deviation} = \sqrt{1.17} \approx 1.08Standard Deviation=1.17≈1.08
Step 4: Normalize Each Feature: Finally, for each feature, subtract the mean and divide by the standard deviation:
Normalized Featurei=Featurei−MeanStandard Deviation\text{Normalized Feature}_i = \frac{\text{Feature}_i - \text{Mean}}{\text{Standard Deviation}}Normalized Featurei=Standard DeviationFeaturei−Mean
For each element:
- 1.5−1.01.08≈0.46\frac{1.5 - 1.0}{1.08} \approx 0.461.081.5−1.0≈0.46
- 2.0−1.01.08≈0.93\frac{2.0 - 1.0}{1.08} \approx 0.931.082.0−1.0≈0.93
- −0.5−1.01.08≈−1.39\frac{-0.5 - 1.0}{1.08} \approx -1.391.08−0.5−1.0≈−1.39
So, the normalized vector becomes:
Normalized Input=[0.46,0.93,−1.39]\text{Normalized Input} = [0.46, 0.93, -1.39]Normalized Input=[0.46,0.93,−1.39]
Now, this normalized vector has a mean of 0 and a standard deviation of 1:
- New Mean: 0.46+0.93+(−1.39)3=0\frac{0.46 + 0.93 + (-1.39)}{3} = 030.46+0.93+(−1.39)=0
- New Variance: (0.46−0)2+(0.93−0)2+(−1.39−0)23=1\frac{(0.46 - 0)^2 + (0.93 - 0)^2 + (-1.39 - 0)^2}{3} = 13(0.46−0)2+(0.93−0)2+(−1.39−0)2=1
🌟🌟🌟
In Post-Norm, the sequence of operations is as follows:
- The input is processed by a sub-layer (e.g., self-attention or feed-forward network).
- The residual connection adds the original input to the sub-layer's output.
- Layer normalization is applied after the residual connection.
In Pre-Norm, the sequence of operations is as follows:
- Layer normalization is applied to the input first.
- The normalized input is then processed by a sub-layer (e.g., self-attention or feed-forward network).
- The residual connection adds the original input to the sub-layer's output.
🌟🌟🌟
Suppose we have 3 tokens, and each token has 3 features:
Token | Feature 1 | Feature 2 | Feature 3 |
---|---|---|---|
Token 1 | 1.0 | 2.0 | -1.0 |
Token 2 | 3.0 | 1.0 | 0.5 |
Token 3 | 2.0 | -1.0 | 1.5 |
In LayerNorm, the mean and variance are computed for each token's features, instead of across the entire batch.
- Mean: [ \text{Mean}_1 = \frac{1.0 + 2.0 + (-1.0)}{3} = \frac{2.0}{3} \approx 0.67 ]
- Variance: [ \text{Variance}_1 = \frac{(1.0 - 0.67)^2 + (2.0 - 0.67)^2 + (-1.0 - 0.67)^2}{3} ] [ = \frac{(0.33)^2 + (1.33)^2 + (-1.67)^2}{3} = \frac{0.11 + 1.77 + 2.79}{3} \approx 1.56 ]
- Mean: [ \text{Mean}_2 = \frac{3.0 + 1.0 + 0.5}{3} = \frac{4.5}{3} = 1.5 ]
- Variance: [ \text{Variance}_2 = \frac{(3.0 - 1.5)^2 + (1.0 - 1.5)^2 + (0.5 - 1.5)^2}{3} ] [ = \frac{(1.5)^2 + (-0.5)^2 + (-1.0)^2}{3} = \frac{2.25 + 0.25 + 1.0}{3} = \frac{3.5}{3} \approx 1.17 ]
- Mean: [ \text{Mean}_3 = \frac{2.0 + (-1.0) + 1.5}{3} = \frac{2.5}{3} \approx 0.83 ]
- Variance: [ \text{Variance}_3 = \frac{(2.0 - 0.83)^2 + (-1.0 - 0.83)^2 + (1.5 - 0.83)^2}{3} ] [ = \frac{(1.17)^2 + (-1.83)^2 + (0.67)^2}{3} = \frac{1.37 + 3.35 + 0.45}{3} \approx 1.72 ]
In LayerNorm, normalization is done across the features of each individual token, rather than across the batch.
[ \text{Standard Deviation}_1 = \sqrt{1.56} \approx 1.25 ]
- Feature 1: [ \frac{1.0 - 0.67}{1.25} \approx 0.27 ]
- Feature 2: [ \frac{2.0 - 0.67}{1.25} \approx 1.07 ]
- Feature 3: [ \frac{-1.0 - 0.67}{1.25} \approx -1.33 ]
[ \text{Normalized Token 1} = [0.27, 1.07, -1.33] ]
[ \text{Standard Deviation}_2 = \sqrt{1.17} \approx 1.08 ]
- Feature 1: [ \frac{3.0 - 1.5}{1.08} \approx 1.39 ]
- Feature 2: [ \frac{1.0 - 1.5}{1.08} \approx -0.46 ]
- Feature 3: [ \frac{0.5 - 1.5}{1.08} \approx -0.93 ]
[ \text{Normalized Token 2} = [1.39, -0.46, -0.93] ]
[ \text{Standard Deviation}_3 = \sqrt{1.72} \approx 1.31 ]
- Feature 1: [ \frac{2.0 - 0.83}{1.31} \approx 0.89 ]
- Feature 2: [ \frac{-1.0 - 0.83}{1.31} \approx -1.39 ]
- Feature 3: [ \frac{1.5 - 0.83}{1.31} \approx 0.51 ]
[ \text{Normalized Token 3} = [0.89, -1.39, 0.51] ]
After normalization, LayerNorm can apply a learned scaling factor (γ) and a bias (β) to each normalized feature to allow the model to learn the optimal feature representation.
- Token 1: ([0.27, 1.07, -1.33])
- Token 2: ([1.39, -0.46, -0.93])
- Token 3: ([0.89, -1.39, 0.51])
Suppose we have a batch of 3 sequences (tokens) with 3 features each:
Token | Feature 1 | Feature 2 | Feature 3 |
---|---|---|---|
Token 1 | 1.0 | 2.0 | -1.0 |
Token 2 | 3.0 | 1.0 | 0.5 |
Token 3 | 2.0 | -1.0 | 1.5 |
-
Mean for each feature across the batch:
-
Feature 1: [ \text{Mean}_1 = \frac{1.0 + 3.0 + 2.0}{3} = \frac{6.0}{3} = 2.0 ]
-
Feature 2: [ \text{Mean}_2 = \frac{2.0 + 1.0 + (-1.0)}{3} = \frac{2.0}{3} \approx 0.67 ]
-
Feature 3: [ \text{Mean}_3 = \frac{-1.0 + 0.5 + 1.5}{3} = \frac{1.0}{3} \approx 0.33 ]
-
-
Variance for each feature across the batch:
-
Feature 1: [ \text{Variance}_1 = \frac{(1.0 - 2.0)^2 + (3.0 - 2.0)^2 + (2.0 - 2.0)^2}{3} = \frac{1.0 + 1.0 + 0.0}{3} = \frac{2.0}{3} \approx 0.67 ]
-
Feature 2: [ \text{Variance}_2 = \frac{(2.0 - 0.67)^2 + (1.0 - 0.67)^2 + (-1.0 - 0.67)^2}{3} \approx 1.56 ]
-
Feature 3: [ \text{Variance}_3 = \frac{(-1.0 - 0.33)^2 + (0.5 - 0.33)^2 + (1.5 - 0.33)^2}{3} \approx 1.11 ]
-
Next, each token's feature is normalized by subtracting the mean and dividing by the standard deviation (square root of the variance):
- Feature 1: [ \frac{1.0 - 2.0}{\sqrt{0.67}} \approx -1.22 ]
- Feature 2: [ \frac{2.0 - 0.67}{\sqrt{1.56}} \approx 1.06 ]
- Feature 3: [ \frac{-1.0 - 0.33}{\sqrt{1.11}} \approx -1.26 ]
- Feature 1: [ \frac{3.0 - 2.0}{\sqrt{0.67}} \approx 1.22 ]
- Feature 2: [ \frac{1.0 - 0.67}{\sqrt{1.56}} \approx 0.27 ]
- Feature 3: [ \frac{0.5 - 0.33}{\sqrt{1.11}} \approx 0.16 ]
- Feature 1: [ \frac{2.0 - 2.0}{\sqrt{0.67}} = 0.0 ]
- Feature 2: [ \frac{-1.0 - 0.67}{\sqrt{1.56}} \approx -1.33 ]
- Feature 3: [ \frac{1.5 - 0.33}{\sqrt{1.11}} \approx 1.10 ]
After normalization, BatchNorm may apply a learned scaling factor (γ) and a bias (β) to allow the model to learn the optimal representation for each feature.
- BatchNorm normalizes across the batch (computing statistics across all tokens in the batch for each feature).
- LayerNorm normalizes within each token's features (computing statistics across the features of each token independently), making it better suited for Transformers and sequence models where token-level independence is crucial.
By normalizing across the features of each token independently, LayerNorm ensures that each token's representation is processed consistently, without being influenced by other tokens in the batch, which is essential for models like Transformers that process sequences.