If you peel back the layers of a modern Large Language Model—past the billions of parameters, the multi-head mechanisms, and the massive GPU clusters—you arrive at a shockingly simple mathematical operation performed trillions of times a second:
\[\mathbf{u} \cdot \mathbf{v} = u_1 v_1 + u_2 v_2 + \dots + u_n v_n\]That’s it. Just multiplying corresponding numbers together and adding them up.
Yet, this elementary arithmetic trick is the fundamental engine that allows LLMs to understand context, route information, and decide which words in a sentence relate to each other.
How does adding simple products together produce artificial intelligence? Why does it magically measure how “aligned” two concepts are in space? And when an LLM processes a word, why doesn’t that word just pay 100% of its attention to itself?
Let’s break it down step-by-step from first principles.
At its core, a dot product takes two vectors (think of them as arrows pointing in space) and outputs a single number.
Geometrically, the dot product of two vectors $\mathbf{u}$ and $\mathbf{v}$ is defined as:
\[\mathbf{u} \cdot \mathbf{v} = \|\mathbf{u}\| \|\mathbf{v}\| \cos\theta\]Where:
Imagine vector $\mathbf{u}$ is lying flat on the floor, and vector $\mathbf{v}$ is floating at an angle above it.
Now, imagine shining a flashlight straight down from above $\mathbf{v}$ onto $\mathbf{u}$. Vector $\mathbf{v}$ casts a shadow on vector $\mathbf{u}$.
v (arrow floating up)
/|
/ |
/ | Flashlight from above
/ |
/ v
+----------> u (floor vector)
|-------|
Shadow length: ||v|| cos(θ)
Notice that the raw dot product depends on two factors: direction (the angle $\theta$) and magnitude (how long the arrows are).
If an arrow is exceptionally long, its dot product will be huge even if it points in a slightly different direction. In deep learning, we often want to isolate purely where the arrow is pointing, regardless of its length.
We achieve this by normalizing vectors to unit length ($|\mathbf{u}| = 1$ and $|\mathbf{v}| = 1$). When vectors are normalized, lengths drop out of the equation entirely:
\[\text{Normalized Dot Product} = (1) \times (1) \times \cos\theta = \cos\theta\]This is Cosine Similarity. A value of $+1$ means complete alignment, $0$ means complete independence (orthogonality), and $-1$ means exact opposition.
A Quick Clarification: In Part 1, we learned that direction (the angle $\theta$) is precisely what we want to measure. But when you look at PyTorch code, you never see
math.cos(theta)or degree calculations. Why don’t we need trigonometric functions in software to compute geometric angles?
When you write matrix_a.dot(matrix_b) or torch.matmul(A, B) in Python, you don’t calculate any angles explicitly. You don’t call math.acos(), nor do you draw triangles.
Instead, the computer calculates simple component arithmetic:
\[\mathbf{u} \cdot \mathbf{v} = \sum_{i=1}^{n} u_i v_i = u_1 v_1 + u_2 v_2 + \dots + u_n v_n\]Why does multiplying coordinates along perpendicular axes and adding them up automatically compute $|\mathbf{u}| |\mathbf{v}| \cos\theta$?
Think of any 2D vector as a step along the $X$-axis plus a step along the $Y$-axis: \(\mathbf{u} = u_x \hat{i} + u_y \hat{j}\) \(\mathbf{v} = v_x \hat{i} + v_y \hat{j}\)
Where $\hat{i}$ and $\hat{j}$ are unit arrows along perpendicular coordinate axes.
Expanding $(\mathbf{u} \cdot \mathbf{v})$ algebraically:
\(\mathbf{u} \cdot \mathbf{v} = (u_x \hat{i} + u_y \hat{j}) \cdot (v_x \hat{i} + v_y \hat{j})\) \(= u_x v_x (\hat{i} \cdot \hat{i}) + u_x v_y (\hat{i} \cdot \hat{j}) + u_y v_x (\hat{j} \cdot \hat{i}) + u_y v_y (\hat{j} \cdot \hat{j})\)
Because our coordinate axes are perpendicular to each other:
The cross-terms vanish completely, leaving:
\[\mathbf{u} \cdot \mathbf{v} = u_x v_x + u_y v_y\]💡 Key Takeaway: By representing vectors in a system of perpendicular axes, hardware computes geometric angles and shadows automatically using fast, simple component-wise arithmetic.
In Large Language Models, words aren’t just strings of text. They are represented as high-dimensional vectors (e.g., 4,096 dimensions). Each dimension can be thought of as a feature axis representing semantic qualities—like tense, sentiment, subject-verb relations, or context.
When two token vectors have a high dot product, it means their feature numbers match along the same dimensions. They are “pointing” in a similar semantic direction.
Let’s walk through how this works in a Transformer’s Attention mechanism.
Consider the sequence: “Your Journey Starts Here”
Every word in this sentence gets transformed into three distinct roles—think of it like a library search:
Let’s focus on the word “Journey” acting as our Query ($Q_{\text{Journey}}$).
Sequence: [ "Your", "Journey", "Starts", "Here" ]
| | | |
Keys (K): K_Your K_Journey K_Starts K_Here
^
| (Query: Q_Journey)
The word “Journey” is a noun describing a process or path. Its Query vector $Q_{\text{Journey}}$ asks: “Where is the action or verb that tells the reader what this journey is doing?”
To answer this, the Transformer computes the dot product of $Q_{\text{Journey}}$ against the Key vectors of every token in the sentence:
Notice how $K_{\text{Starts}}$ scored the highest dot product ($4.8$) because its key vector pointed strongly in the direction requested by $Q_{\text{Journey}}$.
Next, we scale and apply Softmax to convert these raw dot products into percentage probabilities:
\[\text{Attention Weights} = \text{Softmax}\left( \frac{Q K^T}{\sqrt{d_k}} \right) = [ 5\%, \; 15\%, \; 75\%, \; 5\% ]\]The model pays 75% of its attention to “Starts”!
Using this weighted percentage, it blends the Value vectors ($V$) of all tokens together, creating an enriched contextual embedding for “Journey” that explicitly encodes that the journey is starting.
You might notice a subtle distinction here: In Part 1, we said normalizing vectors to unit length isolates pure direction ($\cos\theta$). Why does standard Transformer attention use matrix multiplication on unnormalized vectors ($Q K^T$) rather than pure unit-normalized cosine similarity?
This is a deliberate design trade-off in deep learning:
Looking at the numbers above, a natural question arises:
“In our example, $Q_{\text{Journey}} \cdot K_{\text{Journey}}$ only got 15% attention, while $Q_{\text{Journey}} \cdot K_{\text{Starts}}$ got 75%. Wouldn’t a vector dotted with itself have an angle of $\theta = 0^\circ$ and $\cos(0^\circ) = 1$? Why doesn’t ‘Journey’ pay almost 100% of its attention to ‘Journey’?”
This is one of the most common misconceptions in deep learning. There are three fundamental reasons why tokens don’t just attend to themselves:
A token $X$ does not perform a dot product with itself ($X \cdot X$).
Instead, input token $X$ is transformed by two distinct learned projection matrices: \(Q = X \cdot W_Q \quad \text{and} \quad K = X \cdot W_K\)
Because $W_Q$ and $W_K$ are completely different matrices learned during training, $Q_{\text{Journey}}$ and $K_{\text{Journey}}$ are entirely different vectors! $Q_{\text{Journey}} \cdot K_{\text{Journey}}$ is a Query dotted with a Key, not a vector dotted with itself. There is no guarantee that $\theta = 0^\circ$.
If $W_Q$ and $W_K$ were trained such that $Q_{\text{word}} \cdot K_{\text{word}}$ was always the highest value, every token in the network would only listen to itself.
The phrase “bank of the river” and “bank for a deposit” would process the word “bank” identically. The model would fail to capture any contextual meaning. The loss function explicitly trains $W_Q$ and $W_K$ to reach out and pull in verbs, adjectives, and subjects from neighboring positions.
Even if $Q_{\text{Journey}} \cdot K_{\text{Journey}}$ produces a positive dot product ($2.5$), Softmax converts scores into a competitive probability distribution summing to $1.0$.
Because Softmax uses exponentiation ($\exp(x)$), a score of $4.8$ vs $2.5$ creates a massive gap: $\exp(4.8) \approx 121.5$ while $\exp(2.5) \approx 12.2$. The stronger match for “Starts” exponentially crushes “Journey’s” self-score.
This leads to the ultimate question: If attention is just dot products between Queries and Keys, how does the model learn what to search for in the first place?
Why can’t we just take raw word embeddings $X$ and compute $X \cdot X^T$? Why do we need projection matrices ($W_Q, W_K, W_V$), and why must they undergo training?
Raw Input Vectors (X)
│
▼ (Multiply by Random Weight Matrices)
Projection Spaces: Q = X·W_Q, K = X·W_K, V = X·W_V
│
▼ (Compute Dot Products & Softmax)
Attention Scores: Softmax(Q·Kᵀ / √d)
│
▼ (Blend Value Payload: Context = Σ Score_j · V_j)
Context Vector Output
│
▼ (Forward Pass Output vs Ground Truth)
Calculate Error (Loss)
│
▼ (Backpropagation Chain Rule)
Derivatives: ∂Loss / ∂W_Q, ∂Loss / ∂W_K, ∂Loss / ∂W_V
│
▼ (Gradient Descent Update)
Updated Weights: W ← W - η (∂Loss / ∂W)
If you compute dot products directly on input embeddings ($X \cdot X^T$), the similarity scores are fixed forever. The word “Journey” would have the exact same dot product with “Starts” regardless of sentence structure or context.
Raw word vectors cannot adapt. They don’t know what question is being asked in a specific sentence, nor do they know which semantic features matter for the task at hand.
To allow the model to learn, we introduce linear transformation matrices ($W_Q, W_K, W_V$). At the start of training (Iteration 0), these matrices are filled with random numbers.
Because they are random, the initial dot products are completely meaningless:
However, these random weights serve a vital purpose: they break symmetry, providing the network with adjustable high-dimensional projection dials to begin exploring feature space.
While $W_Q$ and $W_K$ act as the Matchmaker Engine (matching Queries to Keys to calculate where to look and how much percentage attention to assign), $W_V$ is the Payload Extractor:
\[\text{Value Vector } V = X \cdot W_V\]Once Softmax calculates the attention percentages ($75\%$ to “Starts”, $15\%$ to “Journey”), the model uses these percentages to pull and blend the Value vectors together into a single context vector:
\[\text{Context Vector} = 0.75 \times V_{\text{Starts}} + 0.15 \times V_{\text{Journey}} + 0.05 \times V_{\text{Your}} + 0.05 \times V_{\text{Here}}\]Without $W_V$, the model would pass raw, unfiltered token embeddings $X$ forward. $W_V$ acts as a learned feature filter that distills raw word vectors down to only the payload features relevant for the next layer.
How do random weights transform into precision-crafted search filters and payload extractors? Through Backpropagation and Derivatives.
When the model makes a prediction error, we compute gradients for all three weight matrices:
\[\frac{\partial \text{Loss}}{\partial W_Q}, \quad \frac{\partial \text{Loss}}{\partial W_K}, \quad \frac{\partial \text{Loss}}{\partial W_V}\]What do these derivatives tell us in plain English?
“Tilt $W_Q$ and $W_K$ slightly so that $Q_{\text{Journey}}$ aligns closer to $K_{\text{Starts}}$. That will boost their dot product, assigning $75\%$ attention to ‘Starts’ instead of a random comma!”
“You assigned $75\%$ attention to ‘Starts’, but the Value vector $V_{\text{Starts}}$ delivered too much syntactic clutter. Rotate $W_V$ so that $V_{\text{Starts}}$ extracts sharper action/tense features to pass into the context vector!”
Using Gradient Descent, we update all three weight matrices at every training step:
\[W_Q \leftarrow W_Q - \eta \frac{\partial \text{Loss}}{\partial W_Q}, \quad W_K \leftarrow W_K - \eta \frac{\partial \text{Loss}}{\partial W_K}, \quad W_V \leftarrow W_V - \eta \frac{\partial \text{Loss}}{\partial W_V}\]Over millions of training steps across trillions of tokens:
Without backpropagation pushing weights along the path of steepest derivative descent, dot products would just be blind arithmetic on random vectors. Derivatives are the force that sculpts random dot products into meaningful semantic intelligence.
To bring it all together:
The next time you see an LLM write a coherent essay, remember: under the hood, it’s just billions of small flashlights casting shadows on high-dimensional vectors, guided by derivatives to find where the arrows should align.