Skip to content

TransformersLesson 2 of 10

Tokens, vectors, and similarity

Embeddings, dot products, and position information

A token ID is a lookup address. Its numerical size says nothing about meaning: token 100 is not twice as meaningful as token 50.

Give every token a learned list of numbers: its embedding. The invented vectors below have four entries.

  • cat[0.9, 0.3, -0.2, 0.6]
  • dog[0.8, 0.4, -0.1, 0.5]

A trained model learns its embedding table. These two vectors were chosen for illustration; they are not measurements from a particular trained model.

see this in PyTorch

Each token id is just a number that looks up its own learned vector in a big table, turning a row of ids into a stack of meaning-vectors.

import torch
import torch.nn as nn
vocab_size = 128000 # how many distinct tokens exist (the whole "dictionary")
d_model = 64 # how big each token's vector is (its "meaning" in numbers)
# The learned lookup table: one row per token, each row is a d_model vector.
# embedding.weight has shape (vocab_size, d_model) and is trained like any layer.
embedding = nn.Embedding(vocab_size, d_model)
# Our input is just token ids — integers pointing at rows in the table.
ids = torch.tensor([42, 7, 1001]) # ids: (seq,) here seq = 3
# Look up each id -> grab its row -> stack into one tensor.
vectors = embedding(ids) # vectors: (seq, d_model) = (3, 64)
# So token id 42 became a 64-number vector, id 7 its own vector, etc.
print(ids.shape) # torch.Size([3])
print(vectors.shape) # torch.Size([3, 64])
Go deeper: how does text even become numbers?

The text input is first split into tokens (whole words, or fragments like straw+berry), each a row-number in a fixed dictionary — and that number is what gets looked up.

Click an example — watch text split into tokens, turn into ids, then look up vectors.
Go deeper: how do the numbers learn their meaning?

The table usually starts from random values. Training changes those values along with the other parameters to improve prediction. Related uses can lead to related vectors, but a useful semantic arrangement is learned rather than assigned by a human. The animation below is a schematic illustration, not a live training run.

Press Play — random arrows organize. Toggle the word2vec analogy (king − man + woman ≈ queen).

A vector can be drawn as an arrow from the origin. Angle and length describe relationships between vectors, but neither is a complete definition of a token’s meaning. Cosine similarity compares directions; the dot product also depends on both lengths.

An input embedding is the same whenever that token ID is looked up. After attention and feed-forward updates, its contextual representation depends on the surrounding sequence.

An output score can be a dot product between a contextual vector h and a token’s output vector w. For h=(2,1)h=(2,1) and w=(3,1)w=(3,-1),

hw=2(3)+1(1)=5.h\cdot w=2(3)+1(-1)=5.

The result is one score, not a probability. An output vector need not be the same vector used for the input embedding. Weight tying is the choice to share those parameters.

Drag the angle. See where dot product and cosine disagree.
see this in PyTorch

A matrix multiply (@) takes a grid of numbers shaped (n, d) and a grid shaped (d, k) and produces a new (n, k) grid, where the inner sizes must match and each output is a row dotted with a column.

import torch
# A tensor is just a grid of numbers (like a spreadsheet of values the model learns from).
A = torch.randn(2, 3) # A: (n, d) = (2 rows, 3 cols) -> 2 tokens, each a 3-number vector
B = torch.randn(3, 4) # B: (d, k) = (3, 4) -> turns each 3-vector into a 4-vector
# The shape rule for @ : (n, d) @ (d, k) -> (n, k)
# The inner d's MUST match (3 == 3); they "cancel", leaving the outer (n, k).
C = A @ B # same as torch.matmul(A, B)
print(C.shape) # torch.Size([2, 4]) -> 2 tokens, now described by 4 numbers each
# Each output number is a row of A "dotted" with a column of B:
# C[0, 0] = A[0, 0]*B[0, 0] + A[0, 1]*B[1, 0] + A[0, 2]*B[2, 0] (multiply pairs, then add)
print(torch.allclose(C[0, 0], (A[0] * B[:, 0]).sum())) # True

Swapping tokens swaps their rows, so the input matrices already differ. But unrestricted self-attention without position information treats a row permutation consistently; it has no explicit representation of token positions. Additive position embeddings give each position its own vector and add it to the token vector.

Flip the order. Words move, positions don't — so the matrix changes.

Next: how words borrow meaning from their neighbours.

Sources · 6
  1. Jurafsky, Daniel, and James H. Martin. Speech and Language Processing (3rd ed. draft, 2026), Chapter 8: “Transformers.”
  2. Mikolov, Tomas, Kai Chen, Greg Corrado, and Jeffrey Dean. “Efficient Estimation of Word Representations in Vector Space.” 2013. arXiv:1301.3781.
  3. Mikolov, Tomas, Wen-tau Yih, and Geoffrey Zweig. “Linguistic Regularities in Continuous Space Word Representations.” NAACL-HLT, 2013.
  4. Sennrich, Rico, Barry Haddow, and Alexandra Birch. “Neural Machine Translation of Rare Words with Subword Units.” ACL, 2016. arXiv:1508.07909.
  5. Vaswani, Ashish, et al. “Attention Is All You Need.” NeurIPS, 2017. arXiv:1706.03762.
  6. Su, Jianlin, et al. “RoFormer: Enhanced Transformer with Rotary Position Embedding.” 2021. arXiv:2104.09864.

Full bibliography →

Definition

Read the full glossary entry →