02 — Foundations

Token Embeddings#

Learned RepresentationsMathematical 1 min read
◆ The PatternMapping discrete token IDs to continuous vector space

Each token ID indexes into a learned embedding table of shape (vocab_size, d_model). The result is a dense vector that captures semantic meaning. Similar tokens end up near each other in this space — "king" and "queen" are close, "cat" and "automobile" are far.

E = Embedding(token_id) ∈ ℝ^d_model
Simple lookup: row token_id from the embedding matrix. No computation, just indexing.
Scaled: E' = E · √d_model
Some architectures scale embeddings so their magnitude matches positional encodings.

Typical dimensions: GPT-2 uses d=768 (small) to d=1600 (XL). LLaMA-70B uses d=8192. The embedding table is often tied with the output projection (weight tying), reducing parameter count.

For GPT-3 (a 50,257-token vocabulary, d_model = 12,288) the embedding table is about 0.6B parameters — under 0.4% of its 175B. In small models the share is far larger: about 31% in GPT-2 small.
Interactive — 2D embedding projection

Python — embedding layer#

Pattern bridge: Mapping tokens to dense vectors where distance = meaning. Cosine similarity measures the result.
Worked example

In GPT-2 small the embedding table — 50,257 tokens × 768 dimensions — is 31% of all 124M parameters. In Llama 2 70B one 32,000 × 8,192 table is 0.4%. Tying the input and output tables, as GPT-2 does, saves 38.6M parameters. In small models the vocabulary is a large share of the budget; in large ones it hardly registers.

Where it misleads
  • Embedding geometry reflects co-occurrence in training text, including its biases.
  • Rare tokens get few updates and poor vectors; “glitch tokens” that almost never appeared in training can produce strange behaviour.
  • Comparing input embeddings across models is meaningless; each model has its own space.
In code
def embedding_share(vocab, d, total):
    return vocab * d / total

gpt2_small = embedding_share(50_257, 768, 124_439_808)       # GPT-2 small, tied input/output
llama2_70b = embedding_share(32_000, 8_192, 68_976_648_192)   # Llama 2 70B, one of its two tables
tied_saving = 50_257 * 768                                     # parameters saved by weight tying
Python, in your browser — edit the code and run it again

Assumes import numpy as np. Configurations named after real models use their published shapes; other numbers are made up or simulated, as the comments say.

The same idea with a library
import torch
import torch.nn as nn

vocab_size, d_model = 32000, 4096
embed = nn.Embedding(vocab_size, d_model)

# Forward: token IDs → dense vectors
token_ids = torch.tensor([101, 2054, 2003])  # 3 tokens
vectors = embed(token_ids)  # shape: (3, 4096)

# Cosine similarity between tokens
from torch.nn.functional import cosine_similarity
sim = cosine_similarity(vectors[0], vectors[1], dim=0)
print(f"Similarity: {sim:.3f}")
Sources
  • O. Press & L. Wolf, “Using the Output Embedding to Improve Language Models”, EACL, 2017
  • A. Radford, J. Wu, R. Child, D. Luan, D. Amodei & I. Sutskever, “Language Models Are Unsupervised Multitask Learners”, OpenAI, 2019
  • H. Touvron et al., “Llama 2: Open Foundation and Fine-Tuned Chat Models”, arXiv:2307.09288, 2023

Last reviewed October 2026 · How this site checks its content · Report a mistake

Linked from 1
← Previous
Tokenization
Open in the full reader, with the topic sidebar