LIVE · BENGALURU EST. 2024
EXP #015 At At Q-04 · Transformers from Scratch · step 3 ⚠ Learning

How Does It Even Know Word Order?

Shuffle the words in a sentence and self-attention returns the exact same answer — a dot product doesn't care about order. So a bare transformer literally cannot tell "dog bites man" from "man bites dog". This experiment injects position back in: why the naive fixes fail, why the answer is sinusoids, and the one property (shift-by-k = a fixed rotation) that makes relative position learnable — plus the 2000-token cliff that sinks a model trained to 512.

2026-07-15 12 MIN READ COMPLETE
01

HYPOTHESIS

H₀
H₀ Attention understands word order — feed it a sentence and it knows which word came first.
02

METHOD

We’ve built the whole attention sub-layer — scaled dot-product, multi-head, masking, cross-attention. It works. And yet it has a hole so basic it’s almost funny. Consider two sentences:

“dog bites man”  vs  “man bites dog”

Same words, opposite meaning — the difference is entirely word order. So here’s the hypothesis I want to test: attention understands word order; feed it a sentence and it knows which word came first. We’ll prove it wrong on the very first interactive, then spend the rest of the experiment fixing it. Verdict, as usual, up front: FAR FROM IT.

03

PROOF: ATTENTION IS ORDER-BLIND

interactive

Recall the mechanism: a word’s output is softmax(q·k / √d_k) weighted over the values. Every piece of that — the dot product, the softmax, the weighted sum — depends only on which words are present, never on where they sit. Permute the inputs and you permute the outputs, nothing more:

Attention(πX)=πAttention(X)\text{Attention}(\pi X) = \pi\,\text{Attention}(X)

That’s the definition of permutation invariance (plain: reshuffling the inputs only reshuffles the outputs — no new information). Watch it directly. Below, the query word “bites” attends to the other words in two different orders:

positional encoding:
query = "bites" · how much does it attend to each word, in two different word orders?
① dog bites man
dog0.395
bites (query)0.360
man0.245
② man bites dog
dog0.395
bites (query)0.360
man0.245
output vectors differ by 0.0000 IDENTICAL 💀 — with no positions, "bites" can't tell who it bit. Attention sees a bag of words, not a sentence.

↑ With positional encoding OFF, the output for “bites” is bit-for-bit identical across both orderings — it genuinely cannot tell who bit whom. Flip it ON and the two orderings finally diverge.

SPECIMEN · a bag of words, not a sentence 100×

Without positions, a transformer sees your sentence the way a shopping list sees its items: a set, not a sequence. “dog bites man” and “man bites dog” hash to the same bag. Every ounce of syntax — subject, object, who-did-what-to-whom — lives in the ordering, and attention throws it away. The fix isn’t to change attention; it’s to stamp each word with where it stands before attention ever runs.

04

THE NAIVE FIXES — AND WHY THEY BREAK

So we add a position signal to each word’s embedding. The obvious first tries both fail, and failing them tells us exactly what we need.

Attempt 1 — the raw index. Add the number pos (0, 1, 2, …) to the embedding. But the index is unbounded: by position 5000 you’re adding a value of 5000 to vectors whose entries are around ±1. The position doesn’t inform the word, it obliterates it. We need something bounded.

Attempt 2 — normalise by length, pos / length. Now it’s bounded to [0, 1]. But it’s inconsistent: the 3rd word is 3/5 = 0.60 in a five-word sentence and 3/50 = 0.06 in a fifty-word one. The same absolute position produces a different number depending on how long the sentence happens to be, so “third word” is never a stable signal. We need something bounded and consistent across lengths — the same position always encoded the same way.

05

THE ANSWER — SINUSOIDS

interactive

Here’s the trick. Encode each position not as one number but as a whole vector of sines and cosines at geometrically-spaced frequencies:

PE(pos,2i)=sin ⁣(pos100002i/d),PE(pos,2i+1)=cos ⁣(pos100002i/d)PE_{(pos,\,2i)} = \sin\!\left(\frac{pos}{10000^{\,2i/d}}\right), \qquad PE_{(pos,\,2i+1)} = \cos\!\left(\frac{pos}{10000^{\,2i/d}}\right)

Every value is a sine or cosine, so it’s bounded to [−1, 1]. Low dimensions use long wavelengths (they crawl across positions); high dimensions use short ones (they race). Together they form a smooth binary counter — a unique fingerprint per position that means the same thing regardless of sentence length.

every position (row) gets a unique code across dimensions (columns) · drag to inspect one
dim →0468121620
dim 0 · slow wave
dim 8 · fast wave
position = 6
position 6's fingerprint is one value per dimension — bounded to [−1, 1], and unique: no two rows are alike. Low dims turn slowly across positions, high dims fast — a smooth binary counter.

↑ Drag the position slider. Each row is one position’s code across all dimensions; the two waves show a slow dimension and a fast one. No two rows are alike, and every value stays in [−1, 1].

06

THE REAL REASON — SHIFT-BY-k IS A ROTATION

interactive

Uniqueness and boundedness we could get a hundred ways. The property that makes sinusoids special — the one worth understanding — is what happens when you move a fixed distance. Recall the angle-addition identity:

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

Read that carefully: the encoding at pos + k is a fixed linear combination of the encoding at pos. For a sin/cos dimension pair it’s exactly a rotation by the angle k·freq:

[sin(pos+k)cos(pos+k)]=[cosksinksinkcosk]depends only on k[sin(pos)cos(pos)]\begin{bmatrix}\sin(pos+k)\\[2pt]\cos(pos+k)\end{bmatrix} = \underbrace{\begin{bmatrix}\cos k & \sin k\\[2pt]-\sin k & \cos k\end{bmatrix}}_{\text{depends only on }k}\begin{bmatrix}\sin(pos)\\[2pt]\cos(pos)\end{bmatrix}

The rotation matrix depends only on k, not on pos. So “the word k positions back” is the same linear transform everywhere in the sentence — the model learns it once and it works at every location. That is why positions are sinusoids and not random unique vectors: relative position becomes linear, and linear is exactly what a neural network is good at.

PE(pos)   PE(pos+k) · each dim-pair is a point on a circle at angle pos·freq
slow pair · Δ = 1.05 rad
fast pair · Δ = 2.70 rad
pos = 2
shift k = 3
drag pos — both dots swing around the circle, but the angle between them stays locked at k·freq. A shift by k is the same rotation everywhere, so the model learns "k tokens back" as a single linear transform — the whole reason positions are sinusoids and not random vectors.

↑ Drag pos: both dots swing around, but the angle between them — the shift of k — stays locked. A fixed rotation, independent of position.

07

THE 2000-TOKEN CLIFF

Mock question. “You trained on sequences up to 512 tokens and it’s great. In production a user pastes a 2000-token document and quality falls off a cliff. Why?” This is length extrapolation, and it splits the schemes apart.

Many implementations skip sinusoids and use a learned positional table — one trainable vector per position, up to the max training length. It’s just an embedding lookup. Trained to 512, that table has no row for position 2000: the model has literally never seen, and cannot produce, a code for that spot. Sinusoids at least keep emitting values past 512 — but the model still never trained on those combinations, so attention drifts out of distribution. Either way, position is where long-context models quietly break.

the lookup table that runs out

This is exactly why modern LLMs moved to RoPE (rotary embeddings) and ALiBi: instead of adding an absolute code, they bake relative distance directly into the attention scores — leaning on the very rotation property we just derived — and extrapolate to lengths far beyond training. The sinusoid was the right idea; RoPE is the idea taken to its conclusion.

  • Learned absolute positions have a hard cap at the training length — position 2000 simply doesn’t exist for a 512-trained model.
  • Sinusoids extrapolate numerically but not reliably; RoPE/ALiBi encode relative distance and hold up far better — the direct payoff of shift-by-k being linear.
08

THE MAP IS COMPLETE

interactive

With position injected, every attention block on the blueprint is now something we’ve derived by hand. Here’s Attention Is All You Need, Figure 1, with the whole attention path lit — including, finally, the positional-encoding inputs at the bottom:

Attention Is All You Need — the whole machine · click any lit block to jump to the experiment that builds it
ENCODER ×N
Add & Norm
Feed Forward
Add & Norm
Multi-Head AttentionEXP-013/14
⊕ Positional EncodingEXP-015
Input Embedding
Inputs
Output Probabilities
Softmax
Linear
DECODER ×N
Add & Norm
Feed Forward
Add & Norm
Multi-Head AttentionEXP-014
Add & Norm
Masked Multi-Head AttentionEXP-014
⊕ Positional EncodingEXP-015
Output Embedding
Outputs (shifted right)
↑ encoder K, V flow → into the decoder's cross-attention
built in this quest coming next (EXP-015) foundational
The full attention path is built: positional encoding (bottom), encoder & decoder self-attention, the causal mask, and cross-attention. What's left in grey is the scaffolding around attention — embeddings, Add & Norm, and the feed-forward network.

↑ Every coral block is one we invented from its problem. What remains grey — embeddings, Add & Norm, feed-forward — is the plumbing that holds the attention together.

09

CONCLUSION

⚠ FAR FROM IT
Attention doesn’t understand word order — it’s blind to it.

A dot product is symmetric, so self-attention is permutation-invariant: to it, “dog bites man” and “man bites dog” are the same bag of words. Order has to be injected from outside, before attention runs. Raw indices explode; length-normalised positions aren’t consistent; the fix is a vector of sinusoids at geometric frequencies — bounded, unique, length-independent.

But the reason it’s sinusoids specifically is the deep part: because sin(pos+k) is a fixed linear combination of the encoding at pos, a shift by k is the same rotation everywhere, so relative position is a single linear map the model learns once. That property is also what its successors, RoPE and ALiBi, push further to survive the 2000-token cliff. Attention is powerful because it’s order-free — and usable only once you hand the order back.

10

WHAT NEXT

That’s the attention sub-layer, end to end: scaled dot-product (EXP-013), multi-head + masking + cross-attention (EXP-014), and now position (EXP-015). What turns it into a full transformer block is the un-glamorous scaffolding wrapped around it — residual connections, LayerNorm, and the position-wise feed-forward network — and then the architecture forks into BERT (encoder-only) and GPT (decoder-only). The hard, beautiful idea, though, you now own outright.

🎚️THE JUDGMENT CALLdecide it
What do you need from positions? Pick the scheme.
📌 verdict: Order isn't learned — inject it; long context / relative offsets → RoPE or ALiBi, not learned tables.