The Complete Beginner's Path

Understand Contrastive
Learning & CLIP

How neural networks learn what "similar" means, and how CLIP taught machines to see through the lens of language.

Prerequisites: Neural network basics + Embedding intuition. That's it.
10
Chapters
9+
Interactives
0
Assumed Knowledge

Chapter 0: What Is Representation?

Raw data — pixels, audio samples, characters — is not directly useful for reasoning. A 224×224 image is 150,528 numbers, but those numbers don't tell you "this is a dog" or "this looks like a Van Gogh painting." A representation is a transformation that turns raw data into useful numbers.

A good representation puts similar things close together and different things far apart in an embedding space. A photo of a golden retriever and a labrador should have nearby embeddings. A golden retriever and a car should be far apart.

The key question: How do you learn a good embedding function without manually labeling millions of examples? Contrastive learning answers this: you learn by comparing pairs.
Embedding Space

Points are data samples. Colors are categories. A good representation clusters similar items together. Click "Shuffle" to see a bad (random) embedding; click "Organize" to see a learned one.

Check: What makes a good representation?

Chapter 1: Contrastive Learning

Contrastive learning is the art of learning embeddings by comparing pairs. For each sample (the anchor), you need a positive (something similar) and negatives (things that are different). The loss pulls anchor and positive together and pushes anchor and negatives apart.

The beauty: you don't need class labels. The "positive" can be a different augmentation of the same image: flip it, crop it, change the color. Any two views of the same image are a positive pair. Everything else in the batch is a negative.

Anchor
Original image
↓ augment
Positive
Augmented version (same content)
↓ contrast with
Negatives
All other images in the batch
Pull and Push

The anchor is pulled toward the positive and pushed away from negatives. Click "Step" to see the forces applied. Watch embeddings organize over steps.

Step: 0
Self-supervised: In SimCLR, two sampled augmentations of one image construct a positive pair without a human class label. Scale still depends on compute, data curation, and choosing transformations that preserve the information of interest.
Check: In contrastive learning, what is a "positive pair"?

Chapter 2: SimCLR — Simple Framework

SimCLR (Simple Contrastive Learning of Representations) showed how effective contrastive learning can be with a clean, minimal design. Take a batch of N images. Augment each twice to get 2N views. For each image, its two augmented views form the positive pair. The other 2(N-1) views are negatives.

The architecture: a ResNet encoder maps each view to an embedding, then a small projection head (MLP) maps it to the space where the contrastive loss is applied. After training, the projection head is thrown away — the encoder's output is the useful representation.

Image x
Original image from batch
↓ two random augmentations
xi, xj
Two augmented views
↓ encoder f (ResNet)
hi, hj
Representations (keep these)
↓ projection head g (MLP)
zi, zj
Projected embeddings (contrastive loss here)
Why use h downstream? SimCLR's ablations found that h transferred better than z. Its probes also found that h retained substantially more information about applied transformations than z, while the contrastive loss was applied to z.
AugmentationWhat it doesWhy it helps
Random crop + resizeDifferent spatial viewsForces spatial invariance
Color jitterAdjust brightness, contrast, saturationPrevents color-based shortcuts
Horizontal flipMirror the imageOrientation invariance
Gaussian blurSmooth the imagePrevents texture-based shortcuts
One reported SimCLR setup: A ResNet-50 produces h with dimension 2048. A two-layer MLP maps it to z with dimension 128. The contrastive loss is computed on z, while downstream linear evaluation uses h.
Check: In SimCLR, for a batch of N images, how many positive pairs does each image have?

Chapter 3: InfoNCE Loss

The workhorse of contrastive learning: an InfoNCE-style loss (SimCLR calls its normalized, temperature-scaled variant NT-Xent). For paired banks indexed so that ki matches qi, the loss is the negative log probability assigned to that paired key among all candidates in the denominator. It's essentially a softmax over similarity scores.

Li = −log ( exp(sim(qi,ki)/τ) / ∑m=1B exp(sim(qi,km)/τ) )

In the SimCLR variant, both views live in one 2N-view bank: exclude the anchor itself, include its paired view once, and treat the other 2N−2 views as competitors. The lab below uses separate query and key banks, so the anchor is not itself a candidate.

The temperature τ controls softmax sharpness. Low τ concentrates probability and gradient weight on the highest-scoring candidates; high τ spreads weight more evenly, approaching a uniform distribution only as τ approaches infinity. The similarity function is cosine similarity: sim(a,b) = a·b / (||a|| ||b||).

Realization — temperature in numbers: Say two text embeddings have cosine similarities of 0.30 and 0.29 with an image. At τ=0.01, the softmax probabilities become ~0.73 vs ~0.27. At τ=1.0, they become ~0.502 vs ~0.498. When the positive is already the 0.30 candidate, lowering τ lowers its cross-entropy; if a negative has the higher score, lowering τ raises the penalty. CLIP learns an inverse temperature scale exp(logit_scale) = 1 / tau, initialized to 1/0.07.
Paired Image–Text B×B Similarity Matrix

Two paired banks—B image embeddings and B text embeddings—create a B×B matrix. The diagonal marks paired positives; training aims to score them above the off-diagonal alternatives. Adjust temperature to see the row-softmax effect.

Batch size B6
Temperature τ0.10
Temperature changes confidence: CLIP initializes its learned scale to the equivalent of τ=0.07. A lower τ makes score differences count more; τ=1.0 is smoother but is not exactly uniform unless the logits are equal. The loss may rise or fall as τ changes, depending on whether the positive is already the highest-scoring candidate.
Check: What does a lower temperature τ do to the row-softmax weights?
🔨DerivationWhat InfoNCE actually bounds▶✓ ATTEMPTED

Under CPC's candidate-sampling assumptions, one positive comes from the joint distribution and the other N−1 candidates are independent draws from the marginal. Define LN as the expected negative log probability assigned to the positive. CPC establishes I(X;Y) ≥ log N − LN.

Your task: Rearrange the inequality and explain what increasing N changes. Use natural logs; divide by log 2 only when reporting bits.

log N − LN is a lower-bound estimate of mutual information. It is not an equality and log N is not the information capacity of the learned representation.

CPC gives I(X;Y) ≥ log N − LN. Lowering the loss raises this bound; increasing N raises its ceiling and can tighten it. The result does not prove that a model with batch size N can represent only log N nats, nor that CLIP's batch size is theoretically required.

🔨DerivationTemperature changes scale and weighting▶✓ ATTEMPTED

Let ak = sim(zi,zk)/τ and p = softmax(a). Derive the anchor gradient and identify both places where τ acts.

∇z_iL = (1/τ)[∑kpk∇sim(zi,zk) − ∇sim(zi,zpos)]. A smaller τ changes the explicit prefactor and also changes every pk, concentrating relative weight on high-similarity candidates. It does not guarantee that every gradient coordinate grows.

🔨DerivationWhat normalization removes▶✓ ATTEMPTED

Assume a row already ranks the positive above every negative. What happens if every raw dot-product logit is multiplied by a growing positive scale?

The softmax can become more confident without changing the ordering. L2-normalizing each projected feature removes per-example norm from the score, turning the dot product into cosine similarity. CLIP then uses one learned global logit scale. If the positive is not already ranked above a negative, scale alone cannot repair that error.

🔗 Pattern Recognition
Scaled dot-product weights, different uses
InfoNCE (this lesson)
softmax(zi · zjT / τ) — one image scores all text candidates; the paired index is the target.
Self-Attention (Transformer)
softmax(Q · KT / √d) — one query forms weights used to combine value vectors. → Transformer lesson

Both form softmax weights from scaled dot products. In the contrastive loss, a known paired index supplies a classification target. In attention, the weights combine value vectors into a contextual representation. The algebraic weight pattern is similar, but the weights serve different operations.

Why are these scales not interchangeable? Attention divides by √d to compensate for dimension-dependent dot-product variance; contrastive τ calibrates the sharpness of similarity logits. Both rescale logits before softmax, but they solve different problems.

Checkpoint — Before you move on
Why does a naive positive-only alignment loss admit a collapsed constant representation, and what does SimCLR add?
✓ Gate cleared
Model Answer

For a naive alignment loss such as one minus cosine similarity, a constant vector gives every positive pair perfect agreement. SimCLR adds in-batch negatives, so mapping different samples to the same point is penalized. Negatives are one anti-collapse mechanism; DINO uses centering, sharpening, and a momentum teacher instead.

Chapter 4: CLIP — Connecting Vision and Language

CLIP (Contrastive Language-Image Pre-training) applies contrastive learning across modalities: images and text. Instead of two augmented views of the same image, the positive pair is an image and its caption. Train on 400 million image-text pairs from the internet.

Two separate encoders: a vision encoder (ViT or ResNet) maps images to embeddings, and a text encoder (Transformer) maps captions to embeddings. The contrastive loss pulls matching (image, caption) pairs together and pushes non-matching pairs apart.

Image Encoder
ViT / ResNet → image embedding
 
Shared Embedding Space
cos(image, text) = similarity
 
Text Encoder
Transformer → text embedding

Let's trace the exact data flow. The image path: a batch of images [batch, 3, 224, 224] enters ViT-L/14. The image is split into 14×14-pixel patches — a 16×16 grid at 224×224 — each flattened and projected to 1024 dims, giving 256 patch tokens plus one class token — 257 tokens total. After 24 transformer layers, the class token (a single 1024-dim vector) is extracted and passed through a linear projection head that maps it to 768 dimensions. The result is L2-normalized: [batch, 768].

The text path: a caption is tokenized with BPE (byte-pair encoding, 49,152-token vocabulary), padded/truncated to 77 tokens. A 12-layer transformer processes these tokens. The embedding at the [EOS] token position (analogous to the class token) is extracted and projected to 768 dimensions. Also L2-normalized: [batch, 768].

One concrete configuration: In ViT-L/14 at 224 pixels, the vision Transformer width is 1024, the text Transformer width is 768, and both pooled features are mapped into a shared 768-dimensional multimodal space. The base/ViT-B text width of 512 belongs to a different configuration.
CLIP Embedding Space

Images (squares) and text (circles) in a shared space. Matching pairs are connected. CLIP learns to align them.

The breakthrough: CLIP learns a shared space where "a photo of a dog" and an actual photo of a dog are neighbors. This means you can classify images using text descriptions alone — no task-specific training required.
Check: What are CLIP's positive pairs?

Chapter 5: Training CLIP

CLIP's training is elegant. Take a batch of N (image, text) pairs. Compute all N×N cosine similarities. The diagonal contains matching pairs. Apply cross-entropy loss to make each row and column peak at the diagonal. That's it.

In code, this is shockingly simple. You have image_embeds of shape [N, 768] and text_embeds of shape [N, 768], both L2-normalized. The similarity matrix is one matrix multiply:

logits = image_embeds @ text_embedsT × exp(logit_scale)

This gives an [N, N] matrix. The diagonal entries are the N positive pairs (imagei matched with texti). The off-diagonal entries are the N²−N negative pairs. For a concrete example with N=4: you get 4 positive pairs and 12 negatives. The loss is symmetric cross-entropy — cross-entropy on the rows (which text matches each image?) AND on the columns (which image matches each text?), averaged.

L = ½(CErows(logits, labels) + CEcols(logits, labels))    where labels = [0, 1, 2, ..., N−1]

The authors constructed WIT from 400 million image-text pairs collected from publicly available internet sources. Their largest Vision Transformer trained for 12 days on 256 V100 GPUs with a batch size of 32,768. The batch supplies many in-batch alternatives, but the paper does not establish that this batch size is theoretically required.

The N×N Training Matrix

Each cell is the cosine similarity between image i and text j. The loss tries to make the diagonal bright (high similarity) and everything else dark (low similarity).

Step: 0
HyperparameterValueWhy
Batch size32,768Many in-batch candidates in the reported setup
Temperature τ0.07-equivalent initialization; learned thereafterControls the row/column softmax sharpness
Image encoderViT-L/14Large Vision Transformer for best quality
Text encoder12-layer TransformerStandard text encoding
Embedding dim512 or 768Shared dimension for image-text space
What the large batch supplies: With batch size 32,768, each image has 32,767 non-matching captions in its row, and symmetrically for each caption column. This is the reported CLIP setup; the paper does not establish that this exact batch size is required.
Check: In CLIP training, what does each row of the N×N matrix represent?
💻 Build It Implement CLIP's Symmetric Contrastive Loss ▶ ✓ ATTEMPTED
You have a batch of image embeddings and text embeddings, both L2-normalized. Implement the full CLIP loss: compute the similarity matrix, apply the learned inverse-temperature scale, compute cross-entropy in both directions (image-to-text and text-to-image), and average.
signature def clip_loss(image_embeds, text_embeds, logit_scale): """ Args: image_embeds: (N, D) tensor, L2-normalized text_embeds: (N, D) tensor, L2-normalized logit_scale: scalar (learnable parameter) Returns: loss: scalar, symmetric contrastive loss """
Test case
N=4, D=8. With random normalized embeddings and logit_scale=log(1/0.07)≈2.66, there is no fixed loss value for one random draw. Verify the result against an independent symmetric cross-entropy computation. Uniform logits, specifically, give log(4).
logits = image_embeds @ text_embeds.T * exp(logit_scale). Here exp(logit_scale) is the positive inverse temperature, 1/τ; multiplying by it is equivalent to dividing cosine similarities by τ.
python
import torch
import torch.nn.functional as F

def clip_loss(image_embeds, text_embeds, logit_scale):
    # Inverse temperature scale (learned, initialized to 1/0.07 ≈ 14.3)
    scale = torch.exp(logit_scale)

    # Similarity matrix: (N, N)
    logits = image_embeds @ text_embeds.T * scale

    # Labels: diagonal is the correct match
    N = logits.shape[0]
    labels = torch.arange(N, device=logits.device)

    # Symmetric cross-entropy
    loss_i2t = F.cross_entropy(logits, labels)       # rows
    loss_t2i = F.cross_entropy(logits.T, labels)     # cols

    return (loss_i2t + loss_t2i) / 2
Bonus: Exponentiating the learned logit-scale parameter keeps the scale positive. The CLIP paper describes clipping that scale at 100; the released repository's model forward does not include that clamp, so implementations should state which behavior they follow.
💥Reasoning LabWhich conclusion follows?▶✓ ATTEMPTED

Changing temperature, normalization, or the candidate set changes the optimization problem. Predict the qualitative score changes, run a controlled experiment, and limit the conclusion to the measured result.

If every candidate score is equal, what does loss = log(N) establish?
🏗Design ChallengeSharding CLIP similarities▶✓ ATTEMPTED
CLIP uses a global batch of 32,768 pairs. How can the pairwise loss be computed without materializing a complete 32K by 32K matrix on every GPU?

The authors sharded the similarity calculation. Each GPU computed only the subset of pairwise similarities required for its local batch. The paper does not report every GPU storing the complete matrix, nor the 48 MB/96 MB accounting previously shown here.

Chapter 6: Zero-Shot Transfer

CLIP's superpower: zero-shot classification. To classify an image, create text prompts for each class: "a photo of a cat", "a photo of a dog", "a photo of a car." Embed all prompts. Embed the image. Pick the text with highest cosine similarity. No training on the target task.

This works because CLIP's shared embedding space aligns concepts across modalities. "A photo of a dog" is near actual dog photos, even if CLIP never saw this specific classification task during training.

For the ViT-L/14 configuration, zero-shot ImageNet classification starts with all 1,000 ImageNet class names. Create a text template for each: "a photo of a {class}". Run them through the text encoder to get 1,000 embeddings of shape [1000, 768]; these can be computed once and reused across the image set. Encode an image to [1, 768], take its dot product with all 1,000 normalized text embeddings, and choose the argmax. No ImageNet-specific fitting is performed in this zero-shot evaluation.

How well does it work? The ViT-L/14@336 model reports 76.2% zero-shot top-1 accuracy on ImageNet, matching the original ResNet-50 while using none of ImageNet's 1.28 million crowd-labeled examples for task-specific training. The authors separately audited possible web-training-data overlap. Their 80-prompt ensemble improved 3.5 points over a single-prompt baseline; three example prompts are only an illustration of averaging.
Image
Encode with CLIP vision encoder
↓ cosine similarity
Text Prompts
"a photo of a {class}" for each class
↓ argmax
Prediction
Class with highest similarity
Zero-Shot Classification

An image is compared against text prompts for 5 classes. The bar chart shows similarity scores. The highest score wins. Click to generate a new random scenario.

Prompt engineering matters: "a photo of a dog" works better than just "dog" because CLIP was trained on natural captions. On ImageNet, "a photo of a {class}" improved accuracy by 1.3 points over bare class names. The paper's 80-prompt ensemble then improved another 3.5 points over its single-prompt baseline. The reported 76.2% headline already comes from the paper's evaluated zero-shot setup; it should not be increased to 79.7% by adding the gain again.
Check: Why does zero-shot classification work with CLIP?
What does the CLIP paper directly establish about counting?
The paper compares zero-shot performance across several task types.

Chapter 7: SigLIP — Pairwise Sigmoid Loss

SigLIP replaces CLIP's globally normalized softmax objective with independent sigmoid losses for image-text pairs.

L = −∑i,j log σ(zij · yij)

This removes global normalization across a row or column. The paper reports better results at smaller batches and tests batches up to one million examples, but gains diminish quickly and 32K is sufficient in its reported study. Its million-example implementation still exchanges features through chunked collective permutes.

What does SigLIP remove?

Chapter 8: DINO & Self-Supervised Vision

DINO trains a student to match the output distribution of a momentum teacher across augmented crops. Centering and teacher-output sharpening counter different collapse modes.

The paper finds that the last-layer class-token attention maps contain information about semantic regions and object boundaries, despite not being optimized as segmentation masks. It evaluates this structure with thresholded attention masks and video instance-segmentation transfer. These results do not alone establish generic robotics or depth claims.

What spatial result does the DINO paper directly demonstrate?

Chapter 9: Reusing Representations

Later systems reuse pretrained encoders in specific, documented ways. Original LLaVA freezes a CLIP ViT-L/14 visual encoder, takes its grid features, and trains a linear projection into the language model's word-embedding space. At 224 pixels, ViT-L/14 has a 16 by 16 grid: 256 patch features, each at the vision width of 1024 before projection.

Stable Diffusion v1 uses a frozen CLIP ViT-L/14 text encoder. Its non-pooled text representation conditions the denoising U-Net through cross-attention.

GPT-4V's public system card says the model accepts image inputs, but its vision-encoder architecture is not disclosed.

The supported pattern: pretrained representations can be reused across many downstream tasks; each named lineage still needs a source for the exact encoder and connection mechanism.