Token embeddings and positional encodings
You’re working with sequences of token IDs (integers). A Transformer can’t use raw IDs, so the first job is: turn them into vectors and inject order.
What this is / why it matters
Transformers are permutation-invariant by default: without positions, they see a bag of tokens, not a sequence. Embeddings give each token meaning; positional encodings tell the model where it is.
From token IDs to embeddings
Assume:
- Sequence length:
T - Vocabulary size:
V - Embedding dimension (a.k.a. model dimension):
d_model
You start with token IDs:
- Input IDs shape:
[T]
Example:x = [12, 57, 389, 5](soT = 4)
You have an embedding matrix:
E_tokenshape:[V, d_model]
You look up each token ID in E_token:
- Resulting token embeddings:
X_tokenshape[T, d_model]
Concretely, if d_model = 8 and T = 3, you might get:
X_token =
[
[ 0.1, -0.3, 0.4, 0.0, 0.2, -0.1, 0.6, 0.3 ], // token 1
[-0.2, 0.5, 0.1, 0.7,-0.4, 0.2, 0.0,-0.1 ], // token 2
[ 0.0, 0.1, -0.5, 0.3, 0.4, 0.9,-0.3, 0.2 ], // token 3
]
Why positional encodings are necessary
Self-attention computes similarity between token vectors. If you shuffle tokens, you just reorder the rows in X_token. Attention itself has no built-in sense of “this came first”.
So you add positional encodings:
E_posshape:[T_max, d_model](or more, if you support longer sequences)- For each position
t(0..T-1), you get a vectorE_pos[t]and add it:
- Final input to first layer:
Xshape[T, d_model]
Mechanism:
- Each position has its own vector direction in
d_modelspace. - Adding it shifts the token embedding so “word at position 3” is different from “same word at position 10”.
- Attention weights now implicitly depend on position: similarity compares
(token + position)pairs.
Where this breaks:
- If you didn’t add any positional info, the model couldn’t reliably distinguish “dog bites man” from “man bites dog” based on order.
- If your positional encodings don’t cover long enough sequences, positions beyond that length all look the same (or undefined), so performance collapses there.
A tiny runnable-style example (shapes)
Let:
T = 4V = 50_000d_model = 16
Then:
- Token IDs:
[4] E_token:[50_000, 16]- After embedding lookup:
X_token:[4, 16] - Positional encodings:
E_pos:[4, 16] - Final input to Transformer layer:
X = X_token + E_pos:[4, 16]
This is the common starting point for a GPT-style stack.