How does a computer know that "How do I reset my password?" and "I forgot my login" mean the same thing? Sentence embeddings turn text into points in space, and contrastive training teaches them where to go.
Intro
Same Meaning, Different Words
Search for, how do I reset my password, and a keyword engine hunts for those exact words. But the help article is titled, I forgot my login. Zero shared words, identical meaning. Today we fix that by teaching a model to turn text into points in space, where similar meanings land close together.
- Keyword search misses paraphrases
- Embeddings map meaning to points
Today's Roadmap
This is lesson eleven. Last time we made prompts measurable with structured output and systematic evaluation. Now we begin the retrieval half of the course. By the end you will understand how sentence embeddings are built, derive the contrastive loss that trains them, compute it by hand, and implement it in PyTorch.
- Pooling and contrastive loss
- Hand-computed example
- PyTorch implementation
From Tokens to Sentences
Token Vectors Are Not Enough
Recall from the ML course's embeddings lesson that every token gets a vector, a learned row in a lookup table. The word bank gets one starting vector. But a search system does not compare tokens, it compares whole questions, paragraphs and documents. We need one single vector for an entire piece of text.
- Tokens each get a vector
- Search needs one vector per text
Meaning as Location
The geometric intuition is simple. Imagine a map where every text is a pin. Texts about cooking cluster in one region, texts about tax law in another. A question and its answer should sit very near each other, while unrelated texts sit far apart. Search then becomes finding the nearest pins to your query pin.
- Similar texts sit near each other
- Search becomes nearest-neighbour lookup
Why Context Matters
Why not just average raw word vectors? That works a little, but it ignores context. The dog bit the man and the man bit the dog contain the same words, and the average is identical. A transformer encoder fixes this, because attention lets each token vector absorb its context before we combine them.
- Averaging raw words loses order
- Encoders add context via attention
Pooling
Pooling: Grid to Vector
An encoder like BERT outputs one contextual vector per token. If your text has twelve tokens and the hidden size is seven hundred sixty eight, you get a twelve by seven hundred sixty eight grid. Pooling is the step that collapses that grid into a single vector of length seven hundred sixty eight.
- Encoder gives one vector per token
- Pooling yields one vector per text
Mean Pooling
Mean pooling is the most common choice. Add up the token vectors and divide by the number of real tokens. Take a toy example with three tokens whose first coordinates are two, four and six. The mean is twelve over three, which is four. Padding tokens must be excluded using the attention mask, or short texts get dragged toward zero.
- Average token vectors
- Mask out padding tokens
CLS Pooling
The alternative is CLS pooling. BERT-style models prepend a special classification token, and during training that token learns to summarize the whole input. You simply take its output vector and ignore the rest. Which one is right depends on how the model was trained, so always follow the model card, never guess.
- Special token summarizes input
- Follow the model card
Raw Encoders Fall Short
But here is the catch. A raw pretrained encoder, even with perfect pooling, gives mediocre sentence vectors. It was trained to fill in masked words, not to place similar sentences near each other. Distances between its vectors are not tuned for meaning. We need a training objective that shapes the geometry directly.
- Masked LM does not target similarity
- Geometry must be trained
Contrastive Intuition
Pull Together, Push Apart
Contrastive learning gives that objective. The idea is a party game. Show the model a positive pair, two texts that should match, like a question and its answer. Pull them together. Show it negatives, texts that do not match, and push them apart. Repeat that millions of times and the space organizes itself around meaning.
- Positives get pulled close
- Negatives get pushed away
In-Batch Negatives
Where do the negatives come from? The trick is in-batch negatives. Take a batch of three pairs. For the first question, its own answer is the positive, and the answers belonging to the other two questions act as free negatives. No extra labeling needed, and a bigger batch means more negatives for the same cost.
- Other pairs' documents are negatives
- Bigger batch, more negatives
The InfoNCE Loss
Defining the Symbols
Now the math. Let q be a query embedding, d plus its true positive document, and d one through d B all documents in the batch, including d plus. Let s of q and d be a similarity score, usually cosine similarity, a number between minus one and one. Tau, the temperature, is a small positive constant that we will explain shortly.
- q: query, d plus: true document
- s: similarity, tau: temperature
The InfoNCE Formula
The loss is minus log of a fraction. The numerator is e to the power of s of q and d plus, divided by tau. The denominator is the sum over every document j in the batch of e to the power of s of q and d j, divided by tau. Written fully, L equals minus log of exp of s over tau for the positive, over the sum of exp of s over tau across all j.
- Minus log of a fraction
- Numerator: positive, denominator: all
It Is Just Cross-Entropy
Here is the key insight. That fraction is a softmax. It is the probability the model assigns to picking the correct document out of the batch. So InfoNCE is just cross-entropy, which you know from the ML course, applied to a classification problem where the classes are the documents and the correct class is the matching one.
- Fraction equals softmax probability
- Classes are the batch documents
How the Loss Behaves
Look at how the loss behaves. If the positive gets probability close to one, minus log is near zero, so the loss is tiny. If the positive gets probability one tenth, the loss is about two point three. Minimizing the loss raises the positive's score and lowers every negative's score at the same time.
- p near 1 gives loss near 0
- p of 0.1 gives loss 2.3
Worked Example
The 3x3 Similarity Matrix
Let us compute it. Three pairs in a batch, so the similarity matrix is three by three. Rows are queries, columns are documents. Row one is zero point eight, zero point three, zero point one. Row two is zero point two, zero point seven, zero point four. Row three is zero, zero point three, zero point six. The diagonal holds the true pairs.
- Rows: queries, columns: documents
- Diagonal: true pairs
Row One, Step by Step
Pick temperature tau equals zero point five. Dividing by tau just doubles every score. Row one becomes one point six, zero point six, zero point two. Exponentiate: about four point nine five, one point eight two, and one point two two. They sum to about eight. The positive probability is four point nine five over eight, roughly zero point six two.
- Divide by tau: 1.6, 0.6, 0.2
- Softmax gives p of 0.62
Rows One and Two
The loss for row one is minus the natural log of zero point six two, which is about zero point four eight. Row two scores become zero point four, one point four, zero point eight. Exponentials are one point four nine, four point zero six, two point two three, summing to seven point seven seven. Probability zero point five two, loss about zero point six five.
- Row one loss: about 0.48
- Row two loss: about 0.65
Row Three and the Average
Row three scores become zero, zero point six, one point two. Exponentials are one, one point eight two, three point three two, summing to six point one four. The positive probability is about zero point five four, so the loss is about zero point six two. Average the three losses: zero point four eight, plus zero point six five, plus zero point six two, divided by three, is about zero point five eight.
- Row three loss: about 0.62
- Batch loss: about 0.58
The Role of Temperature
Now watch what temperature does. Lower tau to zero point one and the scores are multiplied by ten. Row one becomes eight, three, one. Now the positive takes over ninety nine percent of the probability, and the loss collapses to about zero point zero zero eight. Small tau sharpens the softmax and makes the loss focus on the hardest mistakes.
- Small tau sharpens the softmax
- Large tau flattens it
Training Data and Negatives
Where Pairs Come From
Contrastive training lives or dies on its pairs. Common sources include search logs, where a query is paired with the result users clicked. Natural language inference data, where entailment sentences form positives. And titles paired with abstracts or body text, which exist at web scale. Question and answer forums give another huge pool of pairs.
- Search logs, NLI, titles and abstracts
- Q and A pairs at web scale
Hard Negatives
Random in-batch negatives are easy: a cooking question versus a tax answer. After a while the model separates those trivially and learns little. Hard negatives are documents that look relevant but are wrong, like a password-reset article for a different product. They are often mined with a keyword search or an earlier model, and they teach fine distinctions.
- Easy negatives teach little
- Hard negatives sharpen boundaries
The False Negative Trap
Hard negatives carry a danger: false negatives. If your mining picks a document that is actually relevant but unlabeled, you are training the model to push away a correct answer. Teams usually filter mined candidates, for example skipping those ranked too high, and they keep a mix of easy and hard so the signal stays clean.
- Unlabeled positives hurt training
- Filter and mix negatives
Why Batch Size Matters
Batch size matters too. With in-batch negatives, a batch of thirty two gives each query thirty one negatives, while a batch of several thousand gives far more and a much harder classification problem. That is why large embedding runs favor big batches, often using tricks to fit them across many accelerators in memory.
- Negatives per query: batch minus one
- Bigger batches cost more memory
Practical Embedding Features
Query and Document Prefixes
Queries and documents are not the same kind of text. A query is short and vague, a document is long and detailed. Many modern models are asymmetric and expect prefixes, such as query colon before a question and passage colon before a document. The prefix tells the encoder which role the text plays, and skipping it quietly hurts retrieval quality.
- Short query, long document
- Use the prefixes the model expects
Matryoshka Embeddings
Another idea is Matryoshka embeddings, named after the nesting dolls. The model is trained so the first sixty four numbers already form a decent embedding, the first two hundred fifty six a better one, and the full vector the best. You can truncate the vector to save storage and speed, trading a little accuracy for a lot of size.
- Prefixes of the vector still work
- Truncate to trade accuracy for size
Multilingual and Domain Limits
Know the limits too. Multilingual models map many languages into a shared space, so a French question can find an English answer, but quality is usually uneven across languages. And domain shift is real: a model trained on web text may blur the difference between terms that are distinct in medicine, law or your own product codes. Always test on your own data.
- Quality varies by language
- Test on your own domain data
Python in Practice
Encoding with sentence-transformers
Time for code. With the sentence-transformers library, you load a model by name, call encode on a list of strings, and get back a matrix with one row per text. Then you compare vectors with cosine similarity. Pick any embedding model your provider or the open source hub offers, and read its card for prefixes and max length.
- encode returns one row per text
- Check prefixes and max length
Mean Pooling by Hand
If you prefer plain Hugging Face, load the tokenizer and model, run the batch, then do mean pooling yourself. Multiply the hidden states by the attention mask, sum along the token axis, and divide by the mask sum. Then normalize to unit length. Those few lines are exactly what the high level library does for you.
- Mask, sum, divide by count
- Normalize to unit length
InfoNCE in PyTorch
Now the loss. Given query embeddings and document embeddings, both normalized, compute the similarity matrix with a matrix multiply, divide by tau, and call cross-entropy with labels zero, one, two, up to the batch size minus one. The correct document for query i sits in column i. That is the whole InfoNCE loss in four lines.
- Matrix multiply gives all scores
- Labels are 0 through B minus 1
The Symmetric Loss
Many implementations also add the symmetric loss: compute cross-entropy over rows, then over columns, and average. That trains documents to find their queries as well. Also remember that gradients flow into both sides, so the encoder gets updated from every pair in the batch, positives and negatives alike.
- Rows: query to document
- Columns: document to query
Common Mistakes and Recap
Mistake: Mixed Models
Mistake one: mixing embedding models. Each model has its own private coordinate system, so vectors from two models are not comparable, even when both have the same dimension. If you index documents with one model, you must embed queries with exactly that model and version. Upgrading the model means re-embedding everything.
- Each model has its own space
- Same model for index and query
Mistake: Max Token Length
Mistake two: ignoring max token length. Many encoders accept only a limited number of tokens, such as five hundred twelve, and silently truncate the rest. A long document whose key facts come late gets embedded from only its opening. Check the limit, count tokens, and split long text into chunks, which is exactly where our RAG lessons are heading.
- Encoders truncate silently
- Count tokens and chunk text
More Common Traps
A few more traps. Forgetting the padding mask in mean pooling. Using a temperature copied from another setup without tuning it. Skipping prefixes. And treating a similarity score as a probability: a score of zero point eight means different things in different models. Compare scores within one model, and evaluate with real queries.
- Mask padding, tune tau
- Scores are model-specific
Recap
Let us recap. Pooling collapses token vectors into one text vector. Contrastive training pulls matching pairs together and pushes others apart. InfoNCE is cross-entropy over in-batch negatives, with temperature controlling sharpness. Good data and hard negatives drive quality. Prefixes, Matryoshka truncation and model consistency matter in practice.
- Pooling, contrastive loss, InfoNCE
- Data, prefixes, model consistency
Next: Similarity Metrics
We keep saying nearest, but nearest by what measure? Next lesson compares cosine similarity and dot product, shows when they agree and when they do not, and builds exact nearest neighbour search.
- Cosine versus dot product
- Exact nearest neighbour search