Train your own embedding model
Setup & orientation·4 min

What you're building

0 / 1

An embedding model is a function text → vector, trained so that similar text gets similar vectors under cosine. Everyone calls model.encode() and treats it as magic. It isn't: it's a mean-pool over learned token vectors, a tiny MLP, and a contrastive loss you'll hand-derive by the end of this course. Over six chapters you'll train a real text-embedding model from a random init on your CPU — then prove it works by beating a bag-of-words baseline on retrieval recall@5.

The whole course in one picture

text → unit vector
"reset my password"  ──tokenize──▶  [id, id, id]
      │  lookup rows of E  [vocab × 32]
      ▼
 [[..32..],[..32..],[..32..]]  ──mean-pool──▶  [..32..]
      │  MLP:  Linear 32→64  →  tanh  →  Linear 64→32
      ▼
   project  ──▶  L2-normalize  ──▶  sentence vector ∈ ℝ³², ‖v‖ = 1

You'll train this with InfoNCE / in-batch negatives: pull a sentence and its paraphrase together, push everything else in the batch apart. This is the exact objective sentence-transformers calls MultipleNegativesRankingLoss and SimCSE uses as its contrastive loss. Then you'll measure the result the way real embedding models are measured — recall@5 over a frozen retrieval set.

The big idea

Training an embedding model is just gradient descent making cosine large for pairs that mean the same thing, and small for everything else. That single sentence is the entire course.

Tiny but real

The model here is small on purpose — d = 32, a 256-bucket token table, a 64-wide hidden layer — so the whole thing trains and grades in seconds, single-threaded, on a CPU. The shape is identical to production embedding models; only the scale is smaller. Everything is seeded, so your numbers will match the reference exactly.