4.1.6Transformer Architecture

Positional encodings (sinusoidal)

2,709 words12 min readdifficulty · medium1 backlinks

Transformers process all tokens in parallel, losing the sequential order information that RNNs naturally preserve. Positional encoding injects position information into token embeddings so the model knows "which word came first."

Figure — Positional encodings (sinusoidal)

PE(pos,2i)=sin(pos100002i/dmodel)PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right)

PE(pos,2i+1)=cos(pos100002i/dmodel)PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right)

Even dimensions use sine, odd dimensions use cosine. These are added (not concatenated) to the token embeddings.


Derivation: Why This Formula?

Step 1: Need something that changes with position We want PE(pos)PE(pos) to be unique for each position. A simple counter [1,2,3,...][1, 2, 3, ...] would work but scales unboundedly—position 1000 would dominate the embedding values.

Step 2: Bounded functions—sine and cosine Trig functions oscillate in [1,1][-1, 1], keeping values bounded. For a single frequency ω\omega:

PE(pos)=sin(ωpos)PE(pos) = \sin(\omega \cdot pos)

Why this step? Sine gives us periodicity. Different positions get different values, but the function repeats. One frequency isn't enough because it repeats (period 2π/ω2\pi/\omega), making distant positions look similar.

Step 3: Multiple frequencies for different dimensions Use a different frequency for each embedding dimension. Dimension ii gets frequency:

ωi=1100002i/dmodel\omega_i = \frac{1}{10000^{2i/d_{model}}}

Why decreasing frequencies?

  • Low dimensions (ii small): high frequency \rightarrow changes rapidly with position \rightarrow captures fine-grained local order
  • High dimensions (ii large): low frequency \rightarrow changes slowly \rightarrow captures coarse global position

The factor 1000010000 sets the wavelength range. The longest wavelength is 2π10000628322\pi \cdot 10000 \approx 62832 positions.

Step 4: Alternating sine and cosine Even dimensions use sine, odd use cosine of the same frequency:

PE(pos,2i)=sin(pos100002i/dmodel)PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) PE(pos,2i+1)=cos(pos100002i/dmodel)PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right)

Why both? The pair (sin(ωpos),cos(ωpos))(\sin(\omega pos), \cos(\omega pos)) forms a 2D representation of position on a circle of frequency ω\omega. This allows the model to learn linear transformations to compute relative positions using trig identities:

sin(ω(pos+k))=sin(ωpos)cos(ωk)+cos(ωpos)sin(ωk)\sin(\omega(pos + k)) = \sin(\omega pos)\cos(\omega k) + \cos(\omega pos)\sin(\omega k)

A linear layer can learn weights cos(ωk)\cos(\omega k) and sin(ωk)\sin(\omega k) to shift any position by kk steps.

Relative Position: For any fixed offset kk, PE(pos+k)PE(pos+k) is a linear function of PE(pos)PE(pos):

PE(pos+k)=TkPE(pos)PE(pos+k) = \mathbf{T}_k \cdot PE(pos)

where Tk\mathbf{T}_k is a linear transformation. This makes relative distances learnable.

Bounded Values: All components stay in [1,1][-1, 1].

Extrapolation: Works for positions longer than training sequences (unlike learned positional embeddings capped at max length).


Worked Example 1: Computing PE for a 4-Dimensional Model

Let dmodel=4d_{model} = 4, compute PE(pos=3)PE(pos=3).

Dimensions: i{0,1}i \in \{0, 1\} (since 2i2i and 2i+12i+1 cover indices 0,1,2,3).

Dimension 0 (i=0, even → sine): PE(3,0)=sin(3100000/4)=sin(3)=0.1411PE_{(3,0)} = \sin\left(\frac{3}{10000^{0/4}}\right) = \sin(3) = 0.1411

Dimension 1 (i=0, odd → cosine): PE(3,1)=cos(3100000/4)=cos(3)=0.9900PE_{(3,1)} = \cos\left(\frac{3}{10000^{0/4}}\right) = \cos(3) = -0.9900

Dimension 2 (i=1, even → sine): ω=1100002/4=1100=0.01\omega = \frac{1}{10000^{2/4}} = \frac{1}{100} = 0.01 PE(3,2)=sin(30.01)=sin(0.03)=0.0300PE_{(3,2)} = \sin(3 \cdot 0.01) = \sin(0.03) = 0.0300

Dimension 3 (i=1, odd → cosine): PE(3,3)=cos(30.01)=cos(0.03)=0.9996PE_{(3,3)} = \cos(3 \cdot 0.01) = \cos(0.03) = 0.9996

Why these steps? Lower dimensions (0,1) oscillate rapidly (high ω=1\omega=1), capturing exact position. Higher dimensions (2,3) oscillate slowly (low ω=0.01\omega=0.01), capturing coarse position within sequence.

Final: PE(3)=[0.1411,0.9900,0.0300,0.9996]PE(3) = [0.1411, -0.9900, 0.0300, 0.9996]


Worked Example 2: Demonstrating Relative Position Linearity

Show that PE(pos+1)PE(pos+1) relates linearly to PE(pos)PE(pos) for dimension pair (2i,2i+1)(2i, 2i+1).

For dimension ii, let ωi=1/100002i/dmodel\omega_i = 1/10000^{2i/d_{model}}. We have:

PE(pos,2i)=sin(ωipos),PE(pos,2i+1)=cos(ωipos)PE_{(pos,2i)} = \sin(\omega_i \cdot pos), \quad PE_{(pos,2i+1)} = \cos(\omega_i \cdot pos)

For position pos+1pos+1:

PE(pos+1,2i)=sin(ωi(pos+1))=sin(ωipos+ωi)PE_{(pos+1,2i)} = \sin(\omega_i(pos+1)) = \sin(\omega_i pos + \omega_i)

Using angle addition: =sin(ωipos)cos(ωi)+cos(ωipos)sin(ωi)= \sin(\omega_i pos)\cos(\omega_i) + \cos(\omega_i pos)\sin(\omega_i) =PE(pos,2i)cos(ωi)+PE(pos,2i+1)sin(ωi)= PE_{(pos,2i)} \cdot \cos(\omega_i) + PE_{(pos,2i+1)} \cdot \sin(\omega_i)

Why this step? The trig identity converts the new position into a weighted sum of the old position's encoding. The weights cos(ωi)\cos(\omega_i) and sin(ωi)\sin(\omega_i) depend only on the offset (1 step), not the absolute position.

Similarly for the cosine dimension: PE(pos+1,2i+1)=cos(ωipos)cos(ωi)sin(ωipos)sin(ωi)PE_{(pos+1,2i+1)} = \cos(\omega_i pos)\cos(\omega_i) - \sin(\omega_i pos)\sin(\omega_i) =PE(pos,2i+1)cos(ωi)PE(pos,2i)sin(ωi)= PE_{(pos,2i+1)} \cdot \cos(\omega_i) - PE_{(pos,2i)} \cdot \sin(\omega_i)

In matrix form: [PE(pos+1,2i)PE(pos+1,2i+1)]=[cos(ωi)sin(ωi)sin(ωi)cos(ωi)][PE(pos,2i)PE(pos,2i+1)]\begin{bmatrix} PE_{(pos+1,2i)} \\ PE_{(pos+1,2i+1)} \end{bmatrix} = \begin{bmatrix} \cos(\omega_i) & \sin(\omega_i) \\ -\sin(\omega_i) & \cos(\omega_i) \end{bmatrix} \begin{bmatrix} PE_{(pos,2i)} \\ PE_{(pos,2i+1)} \end{bmatrix}

This is a rotation matrix! A +1 offset rotates the 2D representation by angle ωi\omega_i. The model can learn this transformation to attend to relative positions.


Worked Example 3: Why 10000 as the Base?

The wavelength of dimension ii is:

λi=2π100002i/dmodel\lambda_i = 2\pi \cdot 10000^{2i/d_{model}}

For dmodel=512d_{model}=512:

  • Dimension 0 (i=0i=0): λ0=2π100000=2π6.28\lambda_0 = 2\pi \cdot 10000^0 = 2\pi \approx 6.28 (high frequency)
  • Dimension 255 (i=255i=255): λ255=2π10000510/5122π993062393\lambda_{255} = 2\pi \cdot 10000^{510/512} \approx 2\pi \cdot 9930 \approx 62393 (low frequency)

(Note: 10000510/51210000^{510/512} is slightly less than 1000010000, so the maximal wavelength is just under 2π10000628322\pi \cdot 10000 \approx 62832.)

Why this range?

  • Short wavelengths (6.28\approx 6.28) distinguish adjacent positions (every position looks different)
  • Long wavelengths (62393\approx 62393) encode global position in long documents (sequences up to ~10k tokens)

The geometric progression 100002i/dmodel10000^{2i/d_{model}} ensures smooth coverage across scales—each dimension handles a specific "zoom level" of position.

Why this step? Too small a base (e.g., 100) → longest wavelength only ~628 positions → fails on long sequences. Too large → spectrum stretches too much, wasting resolution. The value 1000010000 balances fine local resolution with long-range coverage.


Step 1: Embed tokens into vectors (from embedding table):

  • "The" → [0.2,0.5,0.8,0.1][0.2, -0.5, 0.8, 0.1]
  • "cat" → [0.3,0.4,0.2,0.6][-0.3, 0.4, 0.2, -0.6]
  • "sat" → [0.7,0.1,0.4,0.3][0.7, 0.1, -0.4, 0.3]

Step 2: Compute positional encodings for positions 0,1,2 (using dmodel=4d_{model}=4):

For pos=0pos=0:

  • PE(0,0)=sin(0)=0PE_{(0,0)} = \sin(0) = 0
  • PE(0,1)=cos(0)=1PE_{(0,1)} = \cos(0) = 1
  • PE(0,2)=sin(0)=0PE_{(0,2)} = \sin(0) = 0
  • PE(0,3)=cos(0)=1PE_{(0,3)} = \cos(0) = 1
  • PE(0)=[0,1,0,1]PE(0) = [0, 1, 0, 1]

For pos=1pos=1:

  • PE(1,0)=sin(1)=0.8415PE_{(1,0)} = \sin(1) = 0.8415
  • PE(1,1)=cos(1)=0.5403PE_{(1,1)} = \cos(1) = 0.5403
  • PE(1,2)=sin(0.01)=0.0100PE_{(1,2)} = \sin(0.01) = 0.0100
  • PE(1,3)=cos(0.01)=0.99995PE_{(1,3)} = \cos(0.01) = 0.99995
  • PE(1)=[0.8415,0.5403,0.0100,0.99995]PE(1) = [0.8415, 0.5403, 0.0100, 0.99995]

For pos=2pos=2:

  • PE(2)=[0.9093,0.4161,0.0200,0.9998]PE(2) = [0.9093, -0.4161, 0.0200, 0.9998]

Step 3: Add positional encodings to embeddings:

  • "The" + PE(0)PE(0) = [0.2,0.5,0.8,1.1][0.2, 0.5, 0.8, 1.1]
  • "cat" + PE(1)PE(1) = [0.5415,0.9403,0.2100,0.39995][0.5415, 0.9403, 0.2100, 0.39995]
  • "sat" + PE(2)PE(2) = [1.6093,0.3161,0.3800,1.2998][1.6093, -0.3161, -0.3800, 1.2998]

These position-aware embeddings feed into the first transformer layer.

Why this step? Addition (not concatenation) preserves dimensionality and lets the model blend semantic content (embeddings) with positional information (encodings).


Why it feels right: Since we compute PE per position, it seems like it's encoding the token itself.

The fix: Positional encoding ONLY encodes where the token is, not what it is. The token embedding encodes meaning ("cat" vs "dog"). They're added together:

Input=Embedding(token)+PE(position)\text{Input} = \text{Embedding}(\text{token}) + PE(\text{position})

Without the embedding, the model has no idea what words mean. Without PE, it has no idea what order they're in.


Why it feels right: Concatenation keeps information distinct: [embedding;PE][embedding; PE] has both components intact.

The fix: Concatenation doubles dimensionality (dmodeld_{model}2dmodel2 \cdot d_{model}), increasing compute cost. Addition works because:

  1. Embeddings and PE live in the same dmodeld_{model} space
  2. Self-attention learns to disentangle them via learned projections WQ,WK,WVW_Q, W_K, W_V
  3. PE values are small (bounded in [-1,1]) compared to embeddings (initialized with larger variance), so they "nudge" rather than overwhelm

Empirically, addition works as well as concatenation with half the parameters.


Why it feels right: The index ii runs from 0 to dmodel1d_{model}-1, same as positions 0 to dmodel1d_{model}-1.

The fix: Each dimension ii encodes a frequency component present at ALL positions. Dimension 0 oscillates quickly at every position (high frequency). Dimension 511 oscillates slowly at every position (low frequency). Think of it like a Fourier transform: low frequencies capture the big picture, high frequencies capture details. Every position uses all dimensions.


Recall Explain to a 12-Year-Old

Imagine you're reading a comic book, but someone cut out all the panels and shuffled them. You'd see Batman punching a villain, then the villain planning the crime, then Batman arriving—totally out of order! You need the panel numbers (1, 2, 3..) to put the story back together.

A Transformer is like a super-smart reader that looks at all panels once. But if we just give it the panels without numbers, it can't tell the story correctly. So we write a secret code on each panel that says "this is panel 3" without actually writing "3".

The code is a pattern of waves—like a fingerprint made of wiggly lines. Panel 1 gets one fingerprint, panel 2 gets another, and so on. Some parts of the fingerprint wiggle fast (to tell nearby panels apart), and some wiggle slow (to tell if you're near the start or end of the comic). We add this fingerprint to each panel, so the Transformer knows the order while still seeing all the pictures at once.


  • Fixed (not learned)
  • Addition to embeddings
  • Sine on even, cosine on odd
  • Ten-thousand base (10000)

Visual: Imagine a spiral notebook where each coil (dimension) has a different tightness—tight coils for fine position, loose coils for coarse position.


Connections

  • Token Embeddings: PE is added to these to create position-aware inputs
  • Self-Attention Mechanism: PE enables attention to distinguish "attend to previous word" from "attend to next word"
  • Multi-Head Attention: Different heads can learn to focus on different relative position offsets
  • Learned Positional Embeddings: Alternative to sinusoidal; learned lookup table (limited to training sequence length)
  • Relative Positional Encodings: Modern alternative (T5, Transformer-XL) that directly encodes relative distances in attention
  • Fourier Transform: Sinusoidal PE decomposes position into frequency components, analogous to frequency analysis
  • Rotary Position Embeddings (RoPE): Modern variant that applies rotation in attention space rather than adding to embeddings

#flashcards/ai-ml

Why can't Transformers use sequence order without positional encoding?
Self-attention is permutation invariant—shuffling tokens doesn't change attention scores. Without PE, "cat sat mat" and "mat sat cat" are identical to the model.
What is the formula for sinusoidal positional encoding at position pospos, dimension 2i2i?
PE(pos,2i)=sin(pos/100002i/dmodel)PE_{(pos,2i)} = \sin(pos / 10000^{2i/d_{model}}). Even dimensions use sine, odd use cosine of the same frequency.
Why do we use multiple frequencies across embedding dimensions?
Low dimensions (high frequency) capture fine-grained local order. High dimensions (low frequency) capture coarse global position. This multi-scale representation covers both nearby and distant relationships.
How does sinusoidal PE enable the model to learn relative positions?
For any offset kk, PE(pos+k)PE(pos+k) is a linear transformation of PE(pos)PE(pos) via trig identities: sin(ω(pos+k))=sin(ωpos)cos(ωk)+cos(ωpos)sin(ωk)\sin(\omega(pos+k)) = \sin(\omega pos)\cos(\omega k) + \cos(\omega pos)\sin(\omega k). The model learns cos(ωk),sin(ωk)\cos(\omega k), \sin(\omega k) weights.
Why pair sine and cosine at the same frequency?
The pair (sin(ωpos),cos(ωpos))(\sin(\omega pos), \cos(\omega pos)) forms a 2D circle representation. This lets the model compute relative positions as rotations, making "3 positions ahead" a learnable linear transformation.
Why 10000 as the base constant?
It sets the wavelength range from 2π2\pi (high freq, local position) to just under 2π10000628322\pi \cdot 10000 \approx 62832 (low freq, global position in long sequences). Covers fine and coarse positioning for typical sequence lengths.
Why add PE to embeddings instead of concatenating?
Addition preserves dimensionality (no extra parameters). PE values are bounded in [-1,1], small enough to "nudge" embeddings without overwhelming them. Attention layers learn to disentangle content from position.
What's the longest sequence sinusoidal PE can handle?
Theoretically infinite (extrapolates beyond training length). The longest wavelength is just under 2π10000628322\pi \cdot 10000 \approx 62832 positions, so patterns repeat after that, but still distinguishable for practical lengths (< 10k tokens).
Sinusoidal PE vs learned positional embeddings—key difference?
Sinusoidal is fixed (not learned), works for any length, encodes relative position linearly. Learned PE is a lookup table (capped at max training length), requires more parameters, but can adapt to data patterns.
If you remove positional encoding, what behavior emerges?
The model treats input as a bag-of-words—"dog bites man" and "man bites dog" become identical. Attention can't distinguish word order, breaking tasks like translation, next-token prediction, or sequence classification.

Concept Map

loses

is

requires

restored by

added to

uses

bounded in

need

low dim

high dim

sin cos pair

enables

Parallel token processing

Sequential order

Self-attention

Permutation invariant

Positional encoding

Token embeddings

Sine and cosine functions

-1 to 1 range

Multiple frequencies

High freq, local order

Low freq, global position

Circle representation

Relative positions via trig

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Hinglish (regional understanding)

Intuition Hinglish mein samjho

Dekho, transformer ka ek interesting problem hai — ye saare tokens ko ek saath, parallel mein process karta hai. RNN jaisa nahi jo ek-ek karke words padhta hai aur order automatically yaad rakhta hai. Toh transformer ke liye "The cat sat" aur "sat cat the" ek jaise dikhte hain, kyunki self-attention permutation invariant hai — matlab tokens ko shuffle kar do, attention scores same rahenge. Lekin real life mein word order matter karta hai na? "Dog bites man" aur "man bites dog" bilkul alag baat hai! Isiliye humein position ki information alag se model mein daalni padti hai, aur yahi kaam karta hai positional encoding.

Ab sawaal ye hai ki position kaise encode karein? Simple counter [1,2,3,...] use kar sakte the, par problem ye hai ki bade positions ki values bahut badi ho jayengi aur embedding ko dominate kar dengi. Isliye smart trick use hoti hai — sine aur cosine functions, jo hamesha -1 se +1 ke beech rehte hain, bounded. Aur ek hi frequency kaafi nahi, kyunki wo repeat ho jaati hai. Isliye har embedding dimension ke liye alag frequency rakhte hain — chhoti dimensions high frequency (fine-grained local order capture karti hain), badi dimensions low frequency (coarse global position). Even dimensions mein sine, odd mein cosine — is sin-cos jodi se position ek circle par 2D point ban jaata hai.

Ye kyun important hai? Sabse badi baat — ye setup model ko relative position samajhne deta hai. Trig identity ki wajah se, PE(pos+k) hamesha PE(pos) ka ek linear transformation hota hai. Matlab model asaani se seekh leta hai ki "position 3 se 5" aur "position 103 se 105" ka distance same feel hota hai. Aur ek aur bonus — kyunki ye formula-based hai, learned nahi, ye training se lambi sequences par bhi kaam karta hai (extrapolation). Toh yaad rakho, positional encoding hi wo cheez hai jo transformer ko word order ka sense deti hai — iske bina model bas ek "bag of words" jaisa behave karega, sentence ka matlab kho dega.

Go deeper — visual, from zero

Test yourself — Transformer Architecture

Connections