Notation used on this pagesymbols, meanings, shapes
    01

    Vision I needed a label for every image. Who writes millions of labels?

    Labels are expensive; images are free

    In Vision I an encoder learned from two labelled scenes. A label is a fact about an image that a person wrote down, and people are slow. Images, on the other hand, arrive by the billion without anyone writing anything. This part asks what an encoder can learn from an image alone. The answer is the one trick behind MAE, DINO and I-JEPA: hide or transform part of the image and ask the model for what the image already contains. We keep the same 8×8 scene and the frozen encoder from Vision I, so every number in the three methods can be traced on the page.

    142 million images, zero labels.

    ImageNet's labels took about 49,000 crowd workers in 167 countries. DINOv2 learned from ten times as many images that nobody labelled.

    Hide part of scene A and ask the model for it back. The hidden pixels are the label, and the image supplied them itself.

    Three ways to make a target from the image alone: the hidden pixels (MAE), a teacher's answer on another view (DINO), the hidden patch's feature (I-JEPA).
    • The encoder is Vision I's, frozen. Vision I trained it with labels to answer "is there a mug on the right?". Real MAE, DINO and I-JEPA train the whole encoder; here only small parts on top of it learn: a 32-number decoder, a 22-number predictor, a 15-number head and a 3-number probe.
    • One scene, four hidden patches and three or four training images are enough to trace every number and too few to learn a general skill. Section 8 reports a failure as well as a success.
    • The axis names (brightness, contrast, row, col) are true because Vision I fixed the patch projection. Trained encoders do not name their axes.
    • DINO's centre, temperatures and moving average are the real mechanisms at toy settings (temperatures 1 and 0.5, momentum 0.9), and the two collapses they prevent are shown by switching them off.
    • Every number is computed on this page from the parameters that train_vision2.py produced with a fixed seed. The losses are exact for this toy and say nothing about accuracy on real photographs.

    With that said once, the sections can concentrate on the mechanisms.

    Keep one question in mind for each method: where does the target come from, and what could the model learn to predict it? Section 2 starts with the simplest target of all, the hidden pixels.

    02

    Hide most of the picture, keep the rest, and ask a tiny decoder to draw the hole.

    MAE: hide patches, predict the pixels

    A masked autoencoder hides patches, runs the encoder on the visible ones only, and lets a small decoder predict the hidden pixels. The loss compares the prediction with the pixels that were hidden. Our version keeps Vision I's encoder frozen and trains only the decoder: for every hidden slot a placeholder row asks the visible patches a question, reads them through the same keys and values the encoder already computes, and turns four numbers into four pixels. That is 32 trained numbers. The frames below follow the slot of patch 8, the centre of the right mug, and show the decoder after training; the next section trains it.

    The decoder never sees the right mug, and draws a faint one from what the visible patches say.

    The hidden patches are dropped, not blanked: the encoder's attention runs among the 13 rows that remain, with the same $W_Q, W_K, W_V, W_O$ as Vision I.

    rows = patches @ W_patch + pos          # 16 patch rows, plus CLS
    encoded = encoder(rows[visible])        # 13 rows in, 13 rows out

    One line per pixel: the decoder row times a column of $W_{\mathrm{dec}}$, plus the bias.

    z = torch.cat([message, pos[hidden, 2:]], dim=-1)   # what it read, where it is
    pred_pixels = z @ W_dec + b_dec                       # 4 numbers per hidden slot

    The full read for the slot of patch 8, all twelve visible rows. The weight column is the attention row of the placeholder's query against the visible keys; the values are the encoder's, unchanged. The footer is the weighted sum the decoder actually receives.

    Real MAE hides about 75% of the patches and trains a Transformer decoder with several layers together with the encoder. What survives from that design here is the sequence of decisions: drop the hidden rows, add a learned placeholder plus position for each hidden slot, read the visible rows, predict pixels, and score only the hole.

    03

    Thirty-two numbers, one loss, a hundred steps. Then the reason the mug comes back grey.

    Train the decoder: steps 0, 10 and 100

    Training changes the decoder's 32 numbers and nothing else: the encoder stays as Vision I left it. The loss is the mean squared error over the hidden pixels, averaged over three training scenes with the same four patches hidden: A (two mugs), B (one mug) and D (book only). Press the step buttons to move along the curve and to redraw the prediction. Then look at the last frame. Scenes A and B have the same visible patches, so the decoder must give one answer for two different holes. The best single answer under a squared error is between them, and that is the grey mug.

    $$L = \frac{1}{4\,|\mathcal M|}\sum_{j\in\mathcal M}\sum_{c=1}^{4}\big(\hat r_{jc} - r_{jc}\big)^2 \qquad \mathcal M = \{3, 4, 7, 8\}$$

    Pixels are a poor target when the visible part does not decide them.

    The training loss stops near , not at zero, and the split by scene says why: A and B share one prediction, so their errors cannot both vanish. A loss curve alone would not tell you that; the per-scene table and the two-originals picture do.

    04

    The calculator from the loss formula, fed by the trained decoder instead of a guess you type.

    Which pixels enter the loss?

    Every value here follows the formula of section 3. Choose a scene and a training step; the table lists the four hidden patches, the true pixels, the decoder's four numbers and the sum of squared errors per patch. The footer divides the total by the number of hidden pixels, sixteen, and that quotient is the loss the optimizer saw for this scene. The visible pixels never enter: they are copied into the drawing so you can see the whole scene, but the decoder is not asked about them and is not scored on them.

    squared = (pred_pixels[hidden] - pixels[hidden]).square()   # [4 patches, 4 pixels]
    loss = squared.mean()                                        # divide by 16, not 64
    Only the hole is scored. Visible patches are inputs; hidden patches are targets; no pixel is both.

    The denominator is a design choice with a meaning: it makes the loss a per-hidden-pixel error, comparable across masks of different sizes. The real MAE also normalises each patch's pixels before comparing; our pixels are already on one small scale, so we compare them directly.

    05

    Instead of hiding pixels, transform the whole scene twice and ask for the same answer.

    Two views of one scene

    A second family of targets never hides anything. Take one scene, make two views of it, a flip and a darker crop, and ask the model to give the same answer for both. No label is needed: the pair itself says "these belong together". The choice of transformations is the whole content of that request. A flip keeps "two mugs" but swaps left and right; dimming keeps the layout but changes every value. Our encoder is frozen, so the views' features do not move; what moves is a small head on top of them, and the third frame shows its two outputs being pulled together.

    A three-slot head turns the summary row into a distribution; the loss asks the student's (view 1) to match the teacher's (view 2).

    Agreement alone allows an empty answer: one distribution for every scene. DINO's recipe rules it out.

    Notice what the two views share and what the request will therefore preserve. If the downstream question were "which side is the mug on?", a flip would be exactly the wrong view to ask agreement for. Augmentations are a statement about what the representation may ignore.

    06

    A copy of the model answers for the other view. Two small tricks keep the answers from becoming empty.

    DINO: a teacher supplies the target

    DINO has a student and a teacher with the same architecture. The student learns by gradient descent; the teacher is a slow moving average of the student and receives no gradient. The student sees one view and outputs a distribution over some slots; the teacher sees the other view and produces the target distribution, after subtracting a running mean of its own logits (centring) and dividing by a smaller temperature (sharpening). Here the encoder is frozen and the two "networks" are two 4 × 3 heads on the CLS row, trained on scenes A, B, D and E with two views each. The numbers in every table come from that run.

    Both heads read the frozen encoder's CLS row $\vp{e_0'}$. The student's logits are $z_s = \vp{e_0'}W_\theta + b_\theta$; the teacher's are $z_t = \vp{e_0'}W_\phi + b_\phi$ on the other view.

    target = ((z_teacher - center) / tau_t).softmax(-1).detach()  # no gradient
    loss = -(target * (z_student / tau_s).log_softmax(-1)).sum(-1).mean()
    teacher = 0.9 * teacher + 0.1 * student                        # after the step

    Centring stops one slot from winning everywhere; sharpening stops the output from going flat. Without the first the loss falls to 0; without the second it sits at $\log 3 = 1.099$. Neither number means the encoder learned anything.

    The real DINO uses many more slots, a teacher momentum near 1 and temperatures near 0.1 and 0.05, and it trains the whole encoder on many crops per image. The two collapses it guards against are the ones on this page, and the paper shows them the same way: switch a part of the recipe off and watch the teacher's entropy go to zero or to log K (Caron et al. 2021, section 5.3).

    07

    Keep the hole. Change what must be predicted: the hidden patch's representation instead of its pixels.

    I-JEPA: predict a feature, not pixels

    I-JEPA keeps the masked-image setup and replaces the target. A target encoder sees the whole image; its output rows at the hidden positions are the targets. A context encoder sees only the visible patches, and a predictor guesses the target rows from them. The loss is a squared error between representations, and the target encoder follows the context encoder by a moving average. Here both encoders are the frozen Vision I encoder, so the target for patch 8 is simply its output row on the content axes, and the predictor is the placeholder read of section 2 with a 4 × 2 head instead of a 4 × 4 one: 22 trained numbers.

    with torch.no_grad(): target = target_encoder(all_rows)[hidden][:, :2]  # sg[y]
    pred = predictor(context_encoder(rows[visible]), pos[hidden])           # 4-to-2 head
    loss = (pred - target).square().mean()

    What a feature target changes is the currency of the error. A pixel loss charges for every wrong intensity, including texture the context could never determine. A feature loss charges in the encoder's own terms: here two numbers per patch that Vision I gave names to. In the real method those numbers are learned and unnamed, and the target encoder keeps moving as the moving average of the context encoder; here it is frozen, so the target for a patch is fixed for the whole run.

    08

    Freeze the encoder, fit one line with labels, and see what the features already separate.

    What did the encoder learn? A linear probe

    Pretraining gives you an encoder, not a promise. The standard test is a linear probe: freeze the encoder, pool its output rows into one feature per image, and fit a line with labels for a task it was never trained on. Our task is "two mugs or one mug?". The feature is the mean of the sixteen patch rows on brightness and contrast, so the probe is a line in that plane. Twelve views of three scenes give twelve points: A (two mugs) against B and C (one mug), each as the scene itself, flipped, dimmed, and cropped. The crops are held out.

    two mugs (A) one mug (B, C) held-out crops. Dashed: $w\cdot f + b = 0$; shaded: "two mugs".

    The probe found an axis, brightness, that counts bright pixels rather than mugs.

    Read the probe as a measurement, not a verdict. It reports one line, on two named axes, fitted to nine points. The failure on the crops is informative in the same way the moved mug was in Vision I: it names the shortcut. Real probes use thousands of held-out images and features with hundreds of unnamed axes, and they report accuracy without being able to draw the line.

    09

    Same scene, same hidden patch, three different things to predict.

    Three targets, one frozen encoder

    Put the three methods side by side on the one patch we followed. MAE's target is the patch's four pixels, read off the image. DINO's target is a distribution over three slots, produced by a teacher head on another view of the whole scene. I-JEPA's target is the encoder's own row for the patch, two named numbers. All three targets are made from the image without a label, and all three are compared with something the model predicts from what it was shown. The table below also records which parameters received gradients in this toy and which followed the moving average, because that distinction is what keeps the two teacher methods from cheating.

    MAE: the pixels of patch 8

    Four numbers from the file. Ambiguous when the context allows a mug or a table.

    DINO: the teacher's distribution

    I-JEPA: the encoder's row

    The losses are not comparable across rows; they are the numbers each run reached in its own units, from the curves in sections 3, 6 and 7.

    A self-made target must not be free to agree with the prediction. Pixels cannot move; a teacher moves only as a slow copy of the student.

    The comparison is the map for the next part. CLIP keeps the two-branch shape of DINO but replaces the second view with a caption, so the target is no longer made from the image alone: it comes from text written by a person, and the two encoders learn to agree across that gap.

    10

    Say it in words, trace it as operations, write the three losses. Then four questions.

    Summaries and pause-and-think

    Try to explain the part without the page: one sentence, one chain of operations, three losses. The sentence is what you would say in a corridor; the chain is what you would draw on a board; the losses are what you would write in an exam. Then answer the four questions before opening them. Each answer is computed from the toy, so you can check yours against a number. The notation card at the end collects every symbol this part added to Vision I's.

    1 · Intuitive

    Hide part of the image or change its view, run the encoder on what remains, predict what the image already contained, and let the error teach you. A label is never asked for.

    2 · Operational

    3 · Mathematical

    $\mathcal M$ is the hidden set, $\operatorname{sg}[\cdot]$ the stop-gradient, and in DINO the teacher parameters follow $\phi \leftarrow \beta\phi + (1-\beta)\theta$ instead of the gradient.

    New since Vision I: the hidden set $\mathcal M$; the placeholder $u_j = m + p_j$, its question $\vq{q_j}$ and its read $g_j$; the decoder row $z_j$ and the two predictions $\hat r_j$ (pixels) and $\hat y_j$ (feature); the DINO logits $z_s, z_t$, centre $c$, temperatures $\tau_s, \tau_t$ and distributions $p_s, p_t$; the moving average $\phi \leftarrow \beta\phi + (1-\beta)\theta$ and the stop-gradient $\operatorname{sg}[\cdot]$; the pooled feature $f$ of the probe.
    Every target in this part came from the image itself. Vision III takes the target from a caption, so the encoder learns to agree with words.

    Three targets, one encoder, and one probe with labels at the end to say what the features kept. When you read a pretraining paper, find those four things first: what is hidden or transformed, what is predicted, what is compared, and how the result was measured.