Charan | AI Journey › 01 · Vectors › How Embeddings Are Learned
⚡ 3D Simulator
AI Journey · Vectors & Embeddings

How Embeddings Are Learned

Understand the mechanism that turns random vectors into meaningful geometry. The distributional hypothesis, gradient descent on the embedding table, and why tokens used in similar contexts end up nearby in vector space.

🔴 MUST 15 Study Phases Vectors Prerequisite: Embeddings → Why Text Becomes Numbers
🧙‍♂️ The Wise Scholar's Metaphor The Distributional Hypothesis
⏮️ 00 · Math & Foundations Hub →

Learning Embeddings: Pulling Nearby Concepts Together

The scholar begins life with random static in their memory drawers. But as they read trillions of sentences across the library, the Distributional Hypothesis ("You shall know a word by the company it keeps" — J.R. Firth) guides them. Every time "cat" and "dog" occur surrounded by "pet", "fur", and "vets", backpropagation applies tiny gravitational tugs pulling their drawer vector knobs closer together in vector space.

01

IntroductionFrom random noise to meaningful structure

When a model is initialised, every token in the vocabulary gets assigned a random vector — just noise. A randomly initialised vector for cat might be [0.03, -0.11, 0.07, ...], while dog gets [-0.08, 0.14, -0.02, ...]. These two vectors are not especially close. They have no meaning yet.

By the end of training on a large corpus, the same vectors become neighbours in a high-dimensional space. No one hand-crafted these numbers. The model adjusted them, one gradient step at a time, to reduce prediction error. The geometry is a byproduct of the training objective.

At initialisation

Vectors are random. cat and dog are as similar as cat and car. The embedding table is just uninitialised parameters.

After training

Vectors reflect usage patterns. cat and dog cluster together. Paris relates to France the way Berlin relates to Germany.

Key idea: No one programs the meaning into embeddings. The model adjusts them during training to reduce prediction error. Similar contexts produce similar vectors as an emergent property.
Random init→ Training corpus→ Gradient updates→ Learned geometry
02

WhyWhy does the model need to learn the embedding table?

Because the right geometry depends on the task, the language, and the domain. There is no universal "correct" vector for bank — the right representation depends on whether the corpus is financial news, river ecology papers, or general English conversation. A pre-fixed table could not capture these specific patterns.

Learning the embedding table means the model discovers the geometry that best serves the training objective. Changing the task or data changes what gets learned.

Task-shaped

Fine-tune on code → code-specific geometry. function clusters near return and class, not near "mathematical function" or "social function".

Language-shaped

Multilingual corpus → cross-lingual alignment. The vector for cat in English may be close to chat in French after multilingual pretraining.

Domain-shaped

Medical text → clinical relationships. aspirin clusters near drug names and dosage terms rather than near "aspiration" or "spiral".

Data-shaped

Biased data → biased geometry. If certain words appear together due to societal bias in the corpus, the embeddings will reflect that bias.

Practical consequence: A model pretrained on general English may underperform on medical or legal text because its embedding geometry was shaped by general usage, not domain-specific patterns. Domain-adaptive pretraining or fine-tuning corrects this.
03

IntuitionThe Distributional Hypothesis

"A word is known by the company it keeps" — J.R. Firth, 1957. This is the distributional hypothesis, and it is the conceptual foundation of learned embeddings.

If cat and dog appear repeatedly in similar sentence contexts — "The [word] sat on the mat", "The [word] slept on the sofa", "She gave the [word] some food" — then during training, the gradients for both tokens will be nudged in similar directions. Over many steps, their vectors converge.

Contexts containing "cat":
  "The cat sat on the mat."
  "The cat slept on the sofa."
  "She gave the cat some food."

Contexts containing "dog":
  "The dog sat on the mat."
  "The dog slept on the sofa."
  "She gave the dog some food."

→ Similar contexts → similar gradient direction → similar vectors
Key idea: The model does not know what "cat" or "dog" means. It only knows which vectors minimise prediction error across the training data. Because both words appear in similar contexts, they receive similar gradient corrections, and their vectors end up nearby. Meaning is geometry; geometry is co-occurrence.
Contrast: "cat" and "car" appear in very different contexts. car co-occurs with drive, engine, road. cat co-occurs with fur, meow, pet. Their gradient updates push them apart, not together.
04

TheoryThe embedding table as a learnable parameter matrix

The embedding table is a matrix $E \in \mathbb{R}^{V \times d}$ where $V$ is vocabulary size and $d$ is embedding dimensionality. Each row $E[t]$ is the vector for token $t$. This matrix is a learnable parameter — it is updated by gradient descent exactly like the weights of any other layer.

Forward
Look up token $t$ in batch → retrieve $E[t]$ → pass through model → compute loss $\mathcal{L}$
Backward
Compute gradient $\nabla_{E[t]} \mathcal{L}$ — how much does changing $E[t]$ reduce the loss?
Update
$$E[t] \leftarrow E[t] - \eta \cdot \nabla_{E[t]} \mathcal{L}$$
Note
$\eta$ is the learning rate. The gradient $\nabla_{E} \mathcal{L}$ is sparse — only rows for tokens that appeared in the current batch are non-zero. Only those rows are updated in that step.

Token ID vs vector: which is which?

Think of the embedding table as a database table. To keep it small, each vector below has just 4 numbers:

Token ID (token)Dim 1Dim 2Dim 3Dim 4
0 (the)0.21−0.140.720.08
1 (cat)0.80−0.300.400.15
2 (dog)0.75−0.250.450.12

Illustrative values only. Real embedding values are learned during model training.

Token ID 1  → identifies the row for "cat"
Row 1       = [ 0.80, −0.30, 0.40, 0.15 ]   ← the vector for "cat"

A token ID does not contain vector numbers. ID 1 is not the vector [0.80, −0.30, 0.40, 0.15]; it simply tells the model which vector to retrieve.

Where do the vector numbers come from?

  1. Initially, the values are typically set by a numerical initialization scheme.
  2. During training, the model adjusts them through optimization and backpropagation (the update rule above).
  3. Over time, the values become useful for the model's language-processing task.

In a real LLM each vector may contain hundreds or thousands of numbers. Token ID = which row? Vector = the learned numbers stored in that row. What “4 numbers” means is explained in Vector Dimensions.

Why sparse? The embedding lookup is a matrix row selection — the gradient flows only through the rows that were actually selected. If token 372 did not appear in the batch, its row receives no gradient and is not updated.
05

How It WorksThe training loop step-by-step

Each training iteration follows the same loop. The embedding table is updated as a side-effect of training the model on its objective (next-token prediction, masked language modelling, or another task).

  1. Sample a batch of text from the corpus.
  2. Tokenize → convert to token IDs.
  3. Look up embedding rows for those IDs: $x_i = E[t_i]$ for each token $t_i$ in the batch.
  4. Pass embeddings through the model layers (attention, feed-forward, etc.).
  5. Compute the training loss $\mathcal{L}$ (e.g. cross-entropy against the target tokens).
  6. Backpropagate: compute $\nabla_{E[t_i]} \mathcal{L}$ for each token $t_i$ seen in the batch.
  7. Optimizer updates those embedding rows: $E[t_i] \leftarrow E[t_i] - \eta \cdot \nabla_{E[t_i]} \mathcal{L}$.
  8. Repeat for millions of batches.
Sample batch→ Tokenize → IDs→ Lookup E[t_i]→ Forward pass→ Loss→ dL/dE[t_i]→ Update rows↺
Key idea: The embedding table is not trained in isolation. It is updated alongside all other model parameters. The geometry that emerges reflects whatever structure in the training data helps reduce the model's loss.
06

MathematicsSparse gradient updates in detail

Consider a batch containing tokens $\{t_1, t_2, \ldots, t_B\}$ (with possible repetitions). The full gradient matrix $\nabla_E \mathcal{L}$ has the same shape as $E$ — but most rows are exactly zero.

Full gradient
$$\nabla_E \mathcal{L} \in \mathbb{R}^{V \times d} \quad \text{but} \quad [\nabla_E \mathcal{L}]_i = \mathbf{0} \text{ if } i \notin \{t_1,\ldots,t_B\}$$
Per-token update
For each unique token $t$ seen in the batch: $\quad E[t] \leftarrow E[t] - \eta \cdot \sum_{j: t_j = t} \frac{\partial \mathcal{L}}{\partial E[t_j]}$
Consequence
Frequent tokens receive many gradient updates per epoch. Rare tokens receive few updates — their rows are poorly optimised. This is a known limitation of dense embedding tables.

Frequent token: "the"

Appears in nearly every sentence. Updated hundreds of thousands of times. Its vector is well-optimised to capture the distributional statistics of a common article.

Rare token: "osmium"

Appears infrequently. Updated rarely. Its vector may not converge well — the model has seen too few examples to shape its geometry reliably.

07

Worked ExampleTwo-token toy training scenario

Consider a minimal vocabulary of two tokens: cat (ID 0) and dog (ID 1). The embedding table starts as:

Initial E: E[0] (cat) = [ 0.10, -0.20] ← random E[1] (dog) = [ 0.30, 0.10] ← random Cosine similarity(cat, dog) ≈ 0.21 (not very similar)

Training repeatedly sees the sentences "the cat sat on the mat" and "the dog sat on the mat". For the target word sat, both cat and dog are the preceding context. The gradient updates for both rows point in directions that better predict sat from the context.

After 10,000 steps: E[0] (cat) = [ 0.72, 0.45] ← shaped by context E[1] (dog) = [ 0.68, 0.49] ← shaped by same contexts Cosine similarity(cat, dog) ≈ 0.97 (very similar)
Note: This is a simplified illustration. Real models use much higher dimensions, more diverse contexts, and tasks like masked language modelling or next-token prediction. But the principle — same contexts push vectors together — holds in full-scale training.
08

VisualizeTraining loop as a flowchart

Each loop through the training data performs one gradient update. Over millions of iterations, the embedding table is gradually shaped by the training signal.

flowchart LR A([Random\nEmbedding Table]) --> B[Sample Batch] B --> C[Tokenize → IDs] C --> D[Lookup E[t_i]] D --> E[Forward Pass] E --> F[Compute Loss] F --> G[Backprop] G --> H[Sparse Gradient\ndL/dE[t_i]] H --> I[Update Rows] I -->|next batch| B I --> J([Learned\nGeometry])

Each loop iteration slightly adjusts the vectors for tokens seen in that batch. After millions of iterations the geometry reflects distributional patterns in the corpus.

Early training

Vectors are nearly random. Similar words are not meaningfully closer than dissimilar ones. The model predicts poorly.

Late training

Vectors have drifted to positions that minimise loss. Semantic and syntactic clusters have emerged. Analogical relationships hold.

09

CodeManual gradient descent on a toy embedding table

The code below implements one step of embedding learning from scratch — no PyTorch, just NumPy arithmetic. It shows the gradient computation, sparse update, and how two tokens in similar contexts converge.

Python
import numpy as np

# ── Toy setup ─────────────────────────────────────────────────────────────
# Vocabulary: {cat: 0, dog: 1, sat: 2}
# Task: given context token, predict target token (simplified skip-gram)
VOCAB_SIZE = 3    # cat, dog, sat
EMBED_DIM   = 2   # 2D for easy visualisation
LR          = 0.1

# Initialise embedding table randomly
rng = np.random.default_rng(42)
E = rng.uniform(-0.5, 0.5, (VOCAB_SIZE, EMBED_DIM))

# ── Simplified forward pass ────────────────────────────────────────────────
# Predict target from context via dot product + softmax
def forward(E, context_id, target_id):
    """Return loss and probability of target given context."""
    context_vec = E[context_id]            # shape: (d,)
    logits = E @ context_vec               # shape: (V,)  — dot with all rows
    logits -= logits.max()                 # numerical stability
    probs = np.exp(logits) / np.exp(logits).sum()
    loss = -np.log(probs[target_id] + 1e-9)
    return loss, probs

# ── Training loop ──────────────────────────────────────────────────────────
# Training data: (context, target) pairs
# "cat sat" → (cat→sat) and "dog sat" → (dog→sat)
data = [(0, 2), (1, 2)] * 500    # 1000 pairs, same pattern for both

for step, (ctx, tgt) in enumerate(data):
    loss, probs = forward(E, ctx, tgt)

    # ── Gradient computation ──────────────────────────────────────────────
    # d_loss / d_logits = probs - one_hot(target)
    d_logits = probs.copy()
    d_logits[tgt] -= 1.0                  # gradient of cross-entropy + softmax

    # d_loss / d_E[context] = E.T @ d_logits  (from E @ context_vec = logits)
    d_E_ctx = E.T @ d_logits              # shape: (d,)

    # ── Sparse update: only context row changes ───────────────────────────
    E[ctx] -= LR * d_E_ctx

    if step % 200 == 0:
        sim = np.dot(E[0], E[1]) / (np.linalg.norm(E[0]) * np.linalg.norm(E[1]))
        print(f"step {step:4d}  loss={loss:.3f}  cos(cat,dog)={sim:.3f}")

print("\nFinal cosine similarity between cat and dog:", end=" ")
sim = np.dot(E[0], E[1]) / (np.linalg.norm(E[0]) * np.linalg.norm(E[1]))
print(f"{sim:.4f}  (should be close to 1.0 — same contexts)")

What this shows

  • Gradient flows only through the context row (sparse update)
  • cat and dog converge because they share the same training signal
  • No explicit meaning is encoded — only prediction error

What PyTorch adds

  • Autograd — no manual gradient formulas
  • Batching and efficient sparse optimisers (SparseAdam)
  • nn.Embedding — same concept, GPU-accelerated
10

Hands-OnInspect embeddings before and after fine-tuning

🔬 Experiment: Embedding geometry inspection

Use HuggingFace to inspect how embeddings cluster before and after fine-tuning, and verify that cosine similarity tracks semantic proximity.

$pip install transformers torch scikit-learn matplotlib
>from transformers import AutoTokenizer, AutoModel
>import torch, torch.nn.functional as F
>model = AutoModel.from_pretrained("bert-base-uncased")
>E = model.embeddings.word_embeddings.weight.data # (30522, 768)
># Cosine similarity between "cat" and "dog" vs "cat" and "car"
>tok = AutoTokenizer.from_pretrained("bert-base-uncased")
>ids = tok.convert_tokens_to_ids(["cat","dog","car","run"])
>vecs = F.normalize(E[ids], dim=-1)
>print((vecs[0] @ vecs[1]).item()) # cat·dog
>print((vecs[0] @ vecs[2]).item()) # cat·car
Interesting finding: Antonyms are often surprisingly close in embedding space — because they appear in similar contexts ("the weather was hot / cold", "he ran fast / slow"). Context similarity ≠ semantic similarity in all senses.
11

CompareHow different training setups shape the embedding table

The geometry of learned embeddings depends heavily on the training objective, data, and whether the table is frozen or fine-tuned downstream.

Training mode Example Objective When to freeze vs fine-tune
Explicit context window word2vec skip-gram / CBOW Predict context words from target (or vice versa) using a small window Often frozen downstream — task-agnostic features
Implicit (full model) BERT masked language model Embeddings updated as part of full model training via MLM / NSP Fine-tune all layers including embedding for domain adaptation
Fine-tuning BERT fine-tuned on IMDB Start from pretrained geometry, adapt embedding rows to task-specific signal Fine-tune when domain differs significantly from pretraining corpus
Frozen embeddings GPT-2 with frozen embedding layer Keep pretrained embedding rows fixed; train only upper layers Freeze when data is small — avoids overfitting embedding rows
Rule of thumb: If fine-tuning data is large and domain-specific, unfreeze the embedding table. If fine-tuning data is small, keep it frozen to preserve the pretrained geometry.
12

ApplyWhere learned embeddings appear in real systems

🧠 Live Lab: Word2Vec / Skip-Gram Learning & Gradient Drift Simulator
Watch Vectors Pull Closer with Positive Context & Push Apart with Negative Sampling
Green arrows = Gradient pull (Positive Co-occurrence). Red dashes = Gradient push (Negative sample).
Training Progress
Epoch: 0
Loss: 1.386
cos(cat, dog): -0.120
Active Pairs:
• Positive: (cat, dog), (cat, pet)
• Negative: (cat, quantum), (dog, matrix)
Target: cos(cat, dog) $\to +1.0$
🔍 Behind-the-Scenes: Skip-Gram with Negative Sampling Loss

Mikolov et al.'s SGNS objective function:

$\mathcal{L}_{\text{SGNS}} = \log \sigma(\vec{v}_w \cdot \vec{v}_c) + \sum_{i=1}^k \mathbb{E}_{w_i \sim P_n} [\log \sigma(-\vec{v}_w \cdot \vec{v}_{w_i})]$
  1. Positive Pair Pull: Maximizes sigmoid probability $\sigma(\vec{v}_w \cdot \vec{v}_c) \to 1$ for real co-occurring words.
  2. Negative Sample Push: Minimizes probability $\sigma(\vec{v}_w \cdot \vec{v}_{w_i}) \to 0$ for $k$ randomly selected noise words.
  3. Result: Self-organizing semantic clusters without labeled supervision!

LLMs (GPT, LLaMA, Mistral)

The embedding table is updated during pretraining as part of the full model. During fine-tuning, it may be frozen or updated depending on the task and dataset size.

Semantic search models

Models like Sentence-BERT are trained specifically to push similar sentence embeddings together (contrastive loss). The embedding geometry directly serves retrieval quality.

Domain adaptation

Continued pretraining on medical, legal, or code corpora reshapes the embedding geometry so domain terms cluster appropriately — improving downstream task accuracy.

Word analogies (classic)

The famous word2vec analogies (king − man + woman ≈ queen) emerge from distributional training. No analogy objective was used — the geometry self-organises from co-occurrence.

Raw text corpus→ Training objective→ Gradient updates→ Embedding geometry→ Downstream task
13

LimitationsWhat learning cannot fix

Training shapes the geometry, but it also encodes the flaws of the training data and process. Understanding these limitations is essential for responsible use.

  • Bias amplification: Embeddings trained on biased corpora reflect those biases. Occupational stereotypes, racial associations, and gender biases found in text are baked into the vectors.
  • Infrequent tokens: Rare tokens receive far fewer gradient updates. Their rows may not converge — their geometry can be nearly random relative to frequent tokens.
  • Catastrophic forgetting: Fine-tuning on a new domain can shift embedding rows away from their pretrained geometry, degrading performance on the original domain.
  • Non-interpretable dimensions: There is no clean correspondence between individual dimensions and human-readable concepts. The geometry emerges from the training signal, not from human design.
  • Static embeddings are context-free: A single trained row for "bank" cannot capture both "river bank" and "financial bank" — the same vector is used regardless of context.
Warning: "The embedding knows the meaning of the word" is wrong. The embedding row knows what helps predict the training signal. That is often useful, but it is not the same as semantic understanding.

Common misconception

"A word's embedding is its true meaning, learned once and correct forever."

Better model

"A word's embedding is a statistical fingerprint of its usage in a specific corpus under a specific training objective. Different corpora and tasks produce different embeddings for the same word."

14

Feynman ChallengeCan you explain it simply?

Feynman Mastery Check

Imagine explaining learned embeddings to a curious friend using the "detective without a dictionary" metaphor:

  • The model is a detective who cannot look up word meanings in a dictionary — it only has the text.
  • It notices: "cat" and "dog" keep showing up in the same kinds of sentences. Must be related.
  • It adjusts its mental model of each word (its vector) to make future predictions less wrong.
  • After millions of cases, the detective has a highly calibrated intuition — not because it was told meanings, but because it observed patterns.
  • The "meaning" is the pattern of co-occurrence, captured as a direction in high-dimensional space.
10-second explanation: Embeddings are learned by gradient descent — during training, token vectors are adjusted to minimise prediction error. Tokens appearing in similar contexts receive similar gradient corrections, so they drift towards each other. The geometry that emerges reflects distributional patterns in the corpus.

Common misconceptions to tackle:

  • "Embeddings are programmed with word meanings" — No: they start random and are adjusted by gradient descent to reduce prediction error. Meaning is never explicitly encoded.
  • "Training makes all similar words neighbours" — No: "similarity" in embedding space means distributional similarity (similar contexts), not conceptual or semantic similarity in every sense. Antonyms can be neighbours.
  • "A token's embedding is stable across all models" — No: the same word has different embeddings in BERT vs GPT-2 vs LLaMA because the training objectives, data, and architectures differ.
  • "You can look at an embedding vector and read its meaning" — No: individual dimensions are not interpretable. The meaning lives in the geometric relationships between vectors.
  • "Random init means training always produces the same geometry" — No: training is stochastic. Different random seeds, batch orderings, and hyperparameters produce different final geometries, though they may encode similar information.
15

Build + SummaryCement your understanding

🔨 Mini-Projects

1 · Embedding inspector

Load bert-base-uncased. Compute cosine similarity for 10 word pairs: (king, queen), (cat, dog), (happy, sad), (Paris, France), (run, walk). Plot the similarities as a bar chart. Explain why antonyms may cluster.

2 · Fine-tuning effect

Fine-tune a tiny BERT on a domain corpus (e.g. IMDB movie reviews). Compare cosine similarities for domain-specific terms (actor, director, sequel) before and after fine-tuning. Measure whether domain terms cluster more tightly post-fine-tuning.

3 · Gradient tracer

Implement the 3-token toy training loop from Phase 09. Log which embedding rows are updated per batch. Run 500 steps and observe: (a) sparse update pattern, (b) convergence of cat/dog cosine similarity, (c) effect of learning rate on convergence speed.

Summary

Random init

All embedding rows start as uninformative random vectors. No meaning is hand-coded.

Gradient updates

Backprop computes $\nabla_{E[t]} \mathcal{L}$ for tokens seen in each batch. The optimizer adjusts those rows. All other rows are unchanged that step.

Distributional hypothesis

Similar contexts → similar gradient corrections → similar vectors. The geometry emerges from co-occurrence patterns, not explicit semantic labelling.

Task-shaped geometry

Different tasks and corpora produce different embedding geometries. Fine-tuning shifts the geometry toward the new domain or task objective.

Next: Static embeddings assign one fixed vector per token regardless of context. The next topic — Static vs Contextual Embeddings — explains why "bank" needs different vectors depending on whether it means a river bank or a financial institution, and how attention solves this.
🐙
Go Deeper · Code it yourself
ai-engineering-from-scratch
Open-source, 523-lesson curriculum. The lesson below builds Word2Vec (skip-gram + negative sampling) from scratch in NumPy — exactly the mechanism that shapes the embedding geometry you just studied.
This page 0:00
This session 0:00
Total (all pages) 0:00
Today 0:00
▶ Running
📊 View all study stats →
0:00 studying