∇
Chapter 28 · Section 28.3 · 90 min

Non-contrastive methods and collapse

A non-contrastive method learns image features by asking two views of the same photograph to agree, and it asks nothing else. It uses no negatives, the other images that a contrastive method pushes away. That makes it cheaper and simpler, but it opens a trap. A network that outputs the same vector for every photograph makes every pair of views agree perfectly. Its loss is the best possible, and it has learned nothing. This failure is called collapse. This section explains how methods without negatives avoid collapse, and how you can tell when a training run has fallen into it.

Here is the setting, recalled from §28.2. Take one unlabeled photo and make two views of it. Each view is a random crop of the photo with a random color distortion. An encoder network turns each view into a vector. A contrastive loss pulls the two vectors of one photo together. It also pushes them away from the vectors of every other photo in the batch. Those other photos are the negatives, and they are what stops the encoder from mapping everything to one point. They are also expensive. SimCLR used batches of 4,096 images spread over 128 TPU cores, and MoCo kept a queue of 65,536 stored vectors.

Delete the negatives and only the pull is left. A loss that only pulls is minimized by a constant output. The book has shown this twice. In §1.10, a linear encoder trained only to match two views shrank to the zero map. In §7.2, a retrieval encoder trained only to pull pairs together retrieved no better than a blind guess.

And yet methods with no negatives work, and some beat SimCLR. The yardstick is the linear-probe accuracy of §28.1. You freeze the trained encoder, fit one linear classifier on its features with the ImageNet labels, and report that classifier's accuracy. With a ResNet-50, SimCLR reached 69.3 percent. BYOL, which has no negatives, reached 74.3 (Grill et al. 2020). SimSiam, simpler still, reached 67.7 percent after 100 epochs with an ordinary batch and plain SGD (Chen and He 2021). Remove one line of SimSiam's code, a stop-gradient defined below, and it scores 0.1 percent, which is chance on 1,000 classes. Nothing in either loss forbids the constant solution. So what keeps these networks away from it?

There are two kinds of answer. Either the loss makes the constant expensive, or training is arranged so that it never gets there. Methods of the first kind add a term to the loss. The term keeps every output dimension spread out, or decorrelates the dimensions, or forces each batch to use many clusters. Methods of the second kind make the two branches of the network different. One branch gets a stop-gradient, the other gets an extra small network, or the target changes slowly.

This section builds both kinds. We first make collapse precise and measurable. Then we take apart BYOL and SimSiam, which are of the second kind. In a linear network small enough to solve by hand, we prove that the stop-gradient is what saves them. Then we derive three methods of the first kind, Barlow Twins, VICReg, and SwAV. We end with dimensional collapse, a quieter failure that strikes even methods with negatives.

The symbols are those of the whole chapter, and here they are in one place.

  • xx is an unlabeled image. tt and t′t' are two random augmentations drawn from the augmentation policy T\mathcal{T} of §28.2, so the two views are x(1)=t(x)x^{(1)} = t(x) and x(2)=t′(x)x^{(2)} = t'(x).
  • The encoder fθf_\theta is a ResNet-50, or a ViT followed by pooling. It produces the representation h=fθ(x)∈Rd\mathbf{h} = f_\theta(x) \in \R^{d}, the vector every evaluation reads. For a ResNet-50, d=2048d = 2048.
  • The projection head gθg_\theta is a small MLP. It maps the representation to the embedding z=gθ(h)∈Rdz\mathbf{z} = g_\theta(\mathbf{h}) \in \R^{d_z}, the vector the loss sees. §28.2 showed why the head is thrown away after training.
  • θ\theta holds the trainable parameters. A batch holds BB images, so 2B2B views.
  • z^=z/∥z∥\hat{\mathbf{z}} = \mathbf{z}/\lVert\mathbf{z}\rVert is the unit vector along z\mathbf{z}.
  • In this section λ\lambda always means weight decay. Other weights get subscripts, such as λBT\lambda_{\text{BT}}.

What collapse looks like, and how to measure it

You cannot read collapse off the loss, because a collapsed network usually has an excellent loss. SimSiam without its stop-gradient quickly reaches −1-1, the lowest value its loss can take. You have to look at the embeddings themselves. There are three ways for them to fail.

Complete collapse is easy to see once you look. Dimensional collapse is the dangerous one. The network still tells inputs apart, but only along a few directions, so the loss and even a quick probe can look fine. Three measurements catch these failures, and we build them one at a time.

Measure one, the spread of each coordinate

Normalize every embedding to unit length. Take the standard deviation of each coordinate over a batch, and average over the coordinates. A completely collapsed network scores 0, because every unit vector is the same. A healthy network, whose unit vectors point evenly in every direction, scores 1/dz1/\sqrt{d_z}, up to the sampling noise of the batch. For dz=2048d_z = 2048 that is 1/2048=0.02211/\sqrt{2048} = 0.0221. SimSiam's authors used this reference value. Their Figure 2 shows two curves, one sitting near 0.0221 with the stop-gradient and one falling to 0 without it.

∂ Proof by symmetry

Flipping the sign of coordinate ii is an orthogonal map, so z^i\hat z_i and −z^i-\hat z_i have the same distribution, and E[z^i]=0\mathbb{E}[\hat z_i] = 0. Swapping coordinates ii and jj is orthogonal too, so E[z^i2]=E[z^j2]\mathbb{E}[\hat z_i^2] = \mathbb{E}[\hat z_j^2] for all i,ji, j. These dzd_z equal second moments add up to E∥z^∥2=1\mathbb{E}\lVert\hat{\mathbf{z}}\rVert^2 = 1, so each is 1/dz1/d_z. The standard deviation is then 1/dz−02=1/dz\sqrt{1/d_z - 0^2} = 1/\sqrt{d_z}. ∎

This test has a blind spot, which the cell below shows. Embeddings confined to an 8-dimensional subspace of R128\R^{128} score almost as well as healthy ones. Their unit vectors still point in many different directions, so every coordinate still varies. To see dimensional collapse you need the spectrum.

Measure two, the spectrum

Stack the embeddings of a batch into the matrix Z\mathbf{Z}, subtract the mean of each column, and compute the singular values (§0.10). Each nonzero singular value stands for one direction along which the embeddings vary, and its size says how much they vary along it. A completely collapsed batch has every singular value equal to zero. A batch confined to rr directions has rr nonzero singular values and the rest at zero. A healthy batch has dzd_z singular values of similar size.

Measure three, the effective rank

A spectrum is a list of dzd_z numbers. When you compare a hundred runs, you want one number per run. The effective rank counts how many directions share the spread. Three tiny cases show what it should do. Singular values (2,2,0)(2, 2, 0) mean two equal directions, so the count should be 2. Singular values (1,1,1,1)(1, 1, 1, 1) should count 4. Singular values (10,0.1,0.1)(10, 0.1, 0.1) should count a little more than 1, because one direction holds almost everything. The exponential of an entropy does exactly this.

∂ Proof of the bounds

Without ϵ\epsilon, the pkp_k form a probability distribution on rr outcomes. The entropy of such a distribution lies between 0, reached only by a point mass, and log⁡r\log r, reached only by the uniform distribution (§0.5). Exponentiating gives 1≤erank⁡≤r1 \le \operatorname{erank} \le r. ∎

In plain words, the effective rank counts the directions that carry the embeddings' spread, each weighted by its share. Check it on the third tiny case. With (10,0.1,0.1)(10, 0.1, 0.1) the shares are (0.980,0.0098,0.0098)(0.980, 0.0098, 0.0098), the entropy is 0.1100.110, and the effective rank is e0.110=1.12e^{0.110} = 1.12.

The effective rank is a cousin of the stable rank of §0.10. The stable rank divides the squared Frobenius norm by the largest squared singular value, so it compares the spectrum with its top value only. The effective rank depends on the shape of the whole spectrum.

Two details change the number in practice. RankMe uses the singular values themselves, not their squares (the eigenvalues of Z⊤Z\mathbf{Z}^\top\mathbf{Z}). And RankMe's formula does not center, so a nonzero mean adds a direction. When you compare runs, use one convention and say which.

Now a small simulation. The cell runs all three measurements on three sets of 1,024 embeddings of width 128. One set is completely collapsed. One is confined to a rank-8 subspace. One is isotropic, meaning spread evenly in every direction.

Python · cell 1

The collapsed set has standard deviation 0, centered singular values that are zero up to rounding, and effective rank 1. The isotropic set sits at the reference, 0.0883 against 1/128=0.08841/\sqrt{128} = 0.0884, with effective rank 125.9 of 128. The rank-8 set is the lesson. Its standard deviation, 0.0857, is within 3 percent of healthy. Its effective rank, 7.94, exposes it at once.

Warm-up

Diagnose collapse

Write collapse_report(Z, eps=1e-7). It takes a batch of embeddings Z of shape (n, d_z) with no zero rows, and it returns a dict with the three measurements above plus one more.

  • "std" is the per-coordinate spread. Normalize each row to unit length, take the standard deviation of each coordinate over the rows (ddof=0), and average over the coordinates.
  • "sv" holds all min(n, d_z) singular values of the column-centered matrix Z - Z.mean(0), in descending order.
  • "erank" is RankMe of the uncentered Z, with pk=σk/∑jσj+ϵp_k = \sigma_k/\sum_j\sigma_j + \epsilon and natural logarithms.
  • "k99" is the smallest kk such that the top kk squared centered singular values hold at least 99 percent of their total. Return 0 if the centered matrix has no spread, meaning that total is at most 10−1210^{-12} times the sum of the squared entries of Z.
Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.

BYOL, a network that predicts a slowly moving copy of itself

BYOL, short for Bootstrap Your Own Latent, trains a network to predict its own output for a different view of the same image. The "own output" comes from a slowly updated copy of the network. The method starts from an experiment that sounds too simple to work. Freeze a randomly initialized network and call it the target. Train a second network to predict the target's embedding of one view from the other view. The constant solution is impossible here, because the target is fixed and does not output a constant.

The trained network reached 18.8 percent linear-probe accuracy on ImageNet, while the random target itself scored 1.4 (Grill et al. 2020, Table 5). Predicting a poor representation produced a better one. Now make the improved network the new target, and repeat. BYOL runs that bootstrap continuously, at every training step.

Three pieces make it work, and each needs a name.

  • The online network is the one trained by gradient descent.
  • The target network has the same architecture but never receives gradients. After every step, its weights move a small fraction of the way toward the online weights. This update is an exponential moving average (EMA), the same one §28.2 built for MoCo's key encoder.
  • The predictor is a small MLP that sits only on the online side, after the projection head. It turns the online embedding into a guess of the target's embedding.

The equality in the loss is the identity ∥a^−b^∥2=2−2a^⊤b^\lVert\hat{\mathbf{a}} - \hat{\mathbf{b}}\rVert^2 = 2 - 2\hat{\mathbf{a}}^\top\hat{\mathbf{b}} for unit vectors. §28.2 derived what the moving average does. It averages the online weights over a window of about 1/(1−m)1/(1-m) steps, and it lags behind them by m/(1−m)m/(1-m) steps on average. At m0=0.996m_0 = 0.996 the target trails by 0.996/0.004=2490.996/0.004 = 249 steps. The cosine schedule gives m=0.998m = 0.998 halfway through and m=1m = 1 at the end. So the target changes ever more slowly as the online network settles.

Notice what is missing. Nothing pushes two different images apart. Why, then, does the online network not drift to a constant, which the target, a moving average of it, would eventually copy?

The BYOL paper gives an argument. It is worth stating carefully, because it is often overstated. Suppose the predictor is always the best possible one for the current online and target networks. Then an online network that carries any information about the image predicts the target at least as well as a collapsed one. So collapsing gains nothing. The derivation below makes this exact.

The argument is about equilibria under two assumptions, an optimal predictor and a fixed target. It is not a proof that training reaches a good place, and the BYOL authors say so. Collapsed equilibria still exist. The authors report only that training never converged to one.

∂ BYOL's argument from an optimal predictor

For squared error, the best predictor of the target embedding z′\mathbf{z}' from the online embedding z\mathbf{z} is the conditional mean, q⋆(z)=E[z′∣z]q^\star(\mathbf{z}) = \mathbb{E}[\mathbf{z}' \mid \mathbf{z}] (§0.4). The loss it achieves is E∑iVar⁡(zi′∣z)\mathbb{E}\sum_i\operatorname{Var}(z'_i \mid \mathbf{z}). By the law of total variance, Var⁡(zi′)=E[Var⁡(zi′∣z)]+Var⁡(E[zi′∣z])\operatorname{Var}(z'_i) = \mathbb{E}[\operatorname{Var}(z'_i \mid \mathbf{z})] + \operatorname{Var}(\mathbb{E}[z'_i \mid \mathbf{z}]), so

E[Var⁡(zi′∣z)]≤Var⁡(zi′).\mathbb{E}[\operatorname{Var}(z'_i \mid \mathbf{z})] \le \operatorname{Var}(z'_i).

The right side is what a constant online output achieves, since conditioning on a constant tells you nothing. More generally, replacing z\mathbf{z} by any function of it can only discard information, so it never lowers E[Var⁡(zi′∣⋅)]\mathbb{E}[\operatorname{Var}(z'_i \mid \cdot)]. With an optimal predictor, the online network gains nothing by collapsing. ∎

The last line is the clue that the rest of this section develops. A slow target and a fast predictor are two ways of doing one job, which is keeping the predictor ahead of the network it predicts. In an interview, the expected answer to "what does BYOL need?" is the predictor and the asymmetry between the branches. The moving average is a stabilizer on top.

SimSiam, the stop-gradient alone

If the predictor matters more than the moving average, how much of BYOL can you delete? Chen and He (2021) deleted the target network entirely. Both branches use the same network with the same weights, an arrangement called a Siamese network. The only asymmetry left is a stop-gradient. A stop-gradient treats a value as a constant during backpropagation. The forward pass uses the value, but no gradient flows back through it. In PyTorch it is .detach().

In terms of architecture, SimSiam is BYOL with m=0m = 0, the setting that gave BYOL 0.3 percent. So why does one recipe fail and the other work? BYOL's own appendix gives part of the answer. With no target network and a predictor learning rate raised tenfold, BYOL reached 66.6 percent. The two recipes also differ in weight decay, 10−610^{-6} with LARS in BYOL's ablation and 10−410^{-4} with SGD in SimSiam. Weight decay and the predictor's speed are exactly the quantities the linear theory below singles out. The balance is fragile, and in practice you tune those two first.

The predictor is essential, and SimSiam's paper has an exact argument for why.

Proof. The first term sends gradient only through z(1)\mathbf{z}^{(1)}, namely 12 ∂D(z(1),z(2))/∂z(1)\tfrac12\,\partial D(\mathbf{z}^{(1)}, \mathbf{z}^{(2)})/\partial\mathbf{z}^{(1)}. The second sends gradient only through z(2)\mathbf{z}^{(2)}, namely 12 ∂D(z(2),z(1))/∂z(2)\tfrac12\,\partial D(\mathbf{z}^{(2)}, \mathbf{z}^{(1)})/\partial\mathbf{z}^{(2)}. Because DD is symmetric in its two arguments, ∂D(z(2),z(1))/∂z(2)=∂D(z(1),z(2))/∂z(2)\partial D(\mathbf{z}^{(2)}, \mathbf{z}^{(1)})/\partial\mathbf{z}^{(2)} = \partial D(\mathbf{z}^{(1)}, \mathbf{z}^{(2)})/\partial\mathbf{z}^{(2)}. So the two pieces add up to exactly half the full gradient of D(z(1),z(2))D(\mathbf{z}^{(1)}, \mathbf{z}^{(2)}), which flows through both arguments. ∎

In plain words, without a predictor the stop-gradient changes only the step size. The network then minimizes DD directly, and the constant solution wins. The PyTorch block near the end checks this identity with autograd.

A hypothesis is not a mechanism. To see a mechanism, we need a model small enough to solve.

A linear Siamese network you can solve

Tian, Chen and Ganguli (2021) found such a model. Strip the network down to one number per part, and the training dynamics can be solved by hand. The solution shows exactly what the stop-gradient, the predictor, and the weight decay each do.

Here is the model. The data are x∼N(0,1)x \sim \mathcal{N}(0, 1). Each view adds independent augmentation noise of variance σ2\sigma^2, so x(1)=x+σϵ1x^{(1)} = x + \sigma\epsilon_1 and x(2)=x+σϵ2x^{(2)} = x + \sigma\epsilon_2, with ϵ1,ϵ2∼N(0,1)\epsilon_1, \epsilon_2 \sim \mathcal{N}(0,1). The online network is one weight ww. The predictor is one weight pp (a number, not a probability). The target is the online weight itself, as in SimSiam. The loss is the squared error between the predicted online output and the target output,

L(w,p)=12 E[(p w x(1)−w x(2))2].\mathcal{L}(w, p) = \tfrac12\,\mathbb{E}\big[(p\,w\,x^{(1)} - w\,x^{(2)})^2\big].

Two expectations do all the work. The first is E[(x(1))2]=E[x2]+2σE[xϵ1]+σ2E[ϵ12]=1+σ2\mathbb{E}[(x^{(1)})^2] = \mathbb{E}[x^2] + 2\sigma\mathbb{E}[x\epsilon_1] + \sigma^2\mathbb{E}[\epsilon_1^2] = 1 + \sigma^2, since xx and ϵ1\epsilon_1 are independent with mean 0. The second is E[x(1)x(2)]=E[x2]=1\mathbb{E}[x^{(1)}x^{(2)}] = \mathbb{E}[x^2] = 1, since every other term contains an independent zero-mean factor. Expanding the square gives L=12w2(p2(1+σ2)−2p+(1+σ2))\mathcal{L} = \tfrac12 w^2\big(p^2(1+\sigma^2) - 2p + (1 + \sigma^2)\big).

With the stop-gradient, the target w x(2)w\,x^{(2)} is held constant while we differentiate. So only the online copy of ww receives gradient,

∂L∂w∣sg=E[(pwx(1)−wx(2)) p x(1)]=−wp(1−(1+σ2)p),∂L∂p=−w2(1−(1+σ2)p).\frac{\partial\mathcal{L}}{\partial w}\Big|_{\text{sg}} = \mathbb{E}\big[(p w x^{(1)} - w x^{(2)})\,p\,x^{(1)}\big] = -wp\big(1 - (1+\sigma^2)p\big), \qquad \frac{\partial\mathcal{L}}{\partial p} = -w^2\big(1 - (1+\sigma^2)p\big).

Without the stop-gradient, ww receives gradient through both branches, and

∂L∂w∣no sg=w E[(px(1)−x(2))2]=w(p2(1+σ2)−2p+1+σ2).\frac{\partial\mathcal{L}}{\partial w}\Big|_{\text{no sg}} = w\,\mathbb{E}\big[(p x^{(1)} - x^{(2)})^2\big] = w\big(p^2(1+\sigma^2) - 2p + 1 + \sigma^2\big).

The same point gets two opposite verdicts. With the stop-gradient the online weight grows. Without it the weight shrinks. To see where each run ends, follow the gradients over time.

Gradient flow is the small-learning-rate limit of gradient descent (§0.6). It is written w˙=−∂L/∂w\dot w = -\partial\mathcal{L}/\partial w, where the dot is the derivative in training time. Three additions bring the model closer to practice.

  • The predictor gets a learning rate αp\alpha_p times that of the online weight.
  • Both weights get weight decay λ\lambda.
  • The target becomes κw\kappa w instead of ww. The value κ=1\kappa = 1 is SimSiam. A κ\kappa below 1 models a moving-average target, which lags behind a growing online weight. Tian et al. call this ratio τ\tau, a letter this book keeps for temperatures.

Finally, write s=w2s = w^2 for the squared online weight. It measures how much signal the online output carries, which is what a probe can use. Collapse is s=0s = 0.

∂ Proof of the three items

The flow equations are the gradients above with κ\kappa in place of the target weight 1, since E[x(1)⋅κx(2)]=κ\mathbb{E}[x^{(1)}\cdot\kappa x^{(2)}] = \kappa. For s˙\dot s, use s˙=2ww˙\dot s = 2w\dot w and w˙=wp(κ−(1+σ2)p)−λw\dot w = wp(\kappa - (1+\sigma^2)p) - \lambda w.

For item 1, ddt(s−p2/αp)=s˙−2pp˙/αp\frac{d}{dt}(s - p^2/\alpha_p) = \dot s - 2p\dot p/\alpha_p. The data terms are 2ps(κ−(1+σ2)p)2ps(\kappa - (1+\sigma^2)p) and −2p⋅s(κ−(1+σ2)p)-2p\cdot s(\kappa - (1+\sigma^2)p), which cancel. The decay terms are −2λs+2λp2/αp=−2λ(s−p2/αp)-2\lambda s + 2\lambda p^2/\alpha_p = -2\lambda(s - p^2/\alpha_p). With λ=0\lambda = 0 the derivative is 0. Since s≥c>0s \ge c > 0, the factor κ−(1+σ2)p\kappa - (1+\sigma^2)p must vanish at a fixed point, which gives p⋆p^\star. And p˙\dot p has the sign of κ−(1+σ2)p\kappa - (1+\sigma^2)p, so pp moves toward p⋆p^\star without overshooting.

For item 2, solve the linear equation c˙=−2λc\dot c = -2\lambda c. On the parabola, substitute s=p2/αps = p^2/\alpha_p into p˙\dot p to get p˙=p (p(κ−(1+σ2)p)−λ)\dot p = p\,\big(p(\kappa - (1+\sigma^2)p) - \lambda\big). Its nonzero roots solve the stated quadratic, and they are real exactly when its discriminant κ2−4λ(1+σ2)\kappa^2 - 4\lambda(1+\sigma^2) is nonnegative. The bracket p(κ−(1+σ2)p)−λp(\kappa - (1+\sigma^2)p) - \lambda is negative for p<p−p < p_-, positive between the roots, and negative above p+p_+. So for p>0p > 0 the flow pushes pp away from p−p_- and toward p+p_+ or 0, which gives the stability claims. Above the threshold, use p(κ−(1+σ2)p)≤κ2/(4(1+σ2))p(\kappa - (1+\sigma^2)p) \le \kappa^2/\big(4(1+\sigma^2)\big), the maximum of a downward parabola. Then s˙=2s(p(κ−(1+σ2)p)−λ)≤−2s(λ−κ2/(4(1+σ2)))\dot s = 2s\big(p(\kappa - (1+\sigma^2)p) - \lambda\big) \le -2s\big(\lambda - \kappa^2/(4(1+\sigma^2))\big), a negative multiple of ss, so ss decays exponentially from every start.

For item 3, the bracket is a quadratic in pp with positive leading coefficient 1+σ21+\sigma^2. Its minimum is at p=1/(1+σ2)p = 1/(1+\sigma^2), where it equals (1+σ2)−1/(1+σ2)=σ2(2+σ2)/(1+σ2)(1+\sigma^2) - 1/(1+\sigma^2) = \sigma^2(2+\sigma^2)/(1+\sigma^2), positive for σ2>0\sigma^2 > 0. So ddtw2≤−2 σ2(2+σ2)1+σ2w2\frac{d}{dt}w^2 \le -2\,\frac{\sigma^2(2+\sigma^2)}{1+\sigma^2}w^2. A quantity whose rate of decrease is at least kk times itself decays at least as fast as e−kte^{-kt} (Grönwall's inequality), which gives the bound. ∎

In plain words, the loss on its own rewards shrinking. The stop-gradient changes the dynamics so that they preserve a quantity, and that quantity is a wall between the run and the collapsed axis s=0s = 0. At a non-collapsed fixed point, the predictor has learned how much an augmentation shrinks the shared signal. Its value p⋆=κ/(1+σ2)p^\star = \kappa/(1+\sigma^2) is the regression coefficient of one view on the other. Without the stop-gradient, the noise makes the two views disagree by an amount proportional to ww, and the cheapest fix is w=0w = 0. For σ2=0.25\sigma^2 = 0.25 the weight decays at an exponential rate of at least 0.25⋅2.25/1.25=0.450.25\cdot 2.25/1.25 = 0.45.

Now each of the three hyperparameters has a meaning, and each is a setting you will tune in a real run.

  • A faster predictor (larger αp\alpha_p) flattens the parabola, so more starting points lie above it. BYOL and SimSiam both found fast predictors helpful. But conservation gives s(∞)=s(0)+(p(∞)2−p(0)2)/αps(\infty) = s(0) + (p(\infty)^2 - p(0)^2)/\alpha_p. So a very fast predictor does all the learning while ss barely grows. That fits a finding of Tian et al. on STL-10, a benchmark of 96-pixel images in 10 classes. Plugging in the optimal linear predictor at every step gave about 40 percent, against 74 to 75 for a predictor trained by gradient descent.
  • Weight decay makes the run forget its starting point and ties ss to pp. Then the size of the online weight reflects the augmentation strength. Too much decay collapses everything.
  • A lagging target (κ\kappa below 1) sets a modest goal κ/(1+σ2)\kappa/(1+\sigma^2) early and raises it as κ\kappa approaches 1. Tian et al. describe this as an automatic curriculum for the predictor.

The cell draws the flow for σ2=0.25\sigma^2 = 0.25 in three regimes. The gray arrows show the direction of the flow at each point, the dashed curve is the parabola s=p2s = p^2 (with αp=1\alpha_p = 1), and the green line marks p⋆=0.8p^\star = 0.8. The red path is one run from (p,s)=(0.2,1)(p, s) = (0.2, 1).

Python · cell 2

The left run keeps s−p2s - p^2 at its starting value, 1−0.04=0.961 - 0.04 = 0.96, up to the error of the Euler steps. It ends at p=0.800p = 0.800, exactly 1/(1+σ2)1/(1+\sigma^2), with s=1.60s = 1.60. The middle run, with weight decay 0.05, is pulled down onto the parabola. It ends at p=0.747p = 0.747 and s=0.560s = 0.560. That is essentially the larger root p+=(1+0.75)/2.5=0.746p_+ = (1 + \sqrt{0.75})/2.5 = 0.746, with s=p+2=0.557s = p_+^2 = 0.557. The right run, without the stop-gradient, slides to s=0s = 0 while pp wanders. That is collapse.

Why does the stop-gradient keep a Siamese network from collapsing?
The one-weight model above, with predictor p and view noise σ² = 0.25. Drag on the plot to set the start.
Loading interactive figure…
Core

SimSiam in one dimension, with and without the stop-gradient

Simulate the scalar model with κ=1\kappa = 1, the one the theorem above solves. Implement simulate_siamese(w0, p0, sigma2, alpha_p=1.0, wd=0.0, stop_grad=True, dt=0.01, steps=2000). Integrate the gradient flow with explicit Euler steps of size dt. Update ww and pp together, both computed from their current values,

w˙=−∂L/∂w−λw,p˙=−αp ∂L/∂p−λp,\dot w = -\partial\mathcal{L}/\partial w - \lambda w, \qquad \dot p = -\alpha_p\,\partial\mathcal{L}/\partial p - \lambda p,

with λ\lambda = wd. When stop_grad is true, ∂L/∂w\partial\mathcal{L}/\partial w treats the target w x(2)w\,x^{(2)} as a constant. Otherwise it differentiates through the target too. Return two arrays w and p of length steps + 1, with the starting values at index 0.

Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.

Sixteen directions at once, and which ones survive

Real data are not the same in every direction. Some directions carry a lot of variation from image to image, and some carry little. The theorem has a sharper form that says which directions a non-contrastive method keeps. Repeat the scalar algebra for one input direction jj along which the data have variance νj\nu_j instead of 1. Keep the augmentation noise at σ2\sigma^2 in every direction. Then E[(x(1))2]=νj+σ2\mathbb{E}[(x^{(1)})^2] = \nu_j + \sigma^2 and E[x(1)x(2)]=νj\mathbb{E}[x^{(1)}x^{(2)}] = \nu_j. With the stop-gradient and κ=1\kappa = 1 the flow is

p˙j=αpsj(νj−(νj+σ2)pj)−λpj,s˙j=2pjsj(νj−(νj+σ2)pj)−2λsj.\dot p_j = \alpha_p s_j\big(\nu_j - (\nu_j + \sigma^2)p_j\big) - \lambda p_j, \qquad \dot s_j = 2p_js_j\big(\nu_j - (\nu_j + \sigma^2)p_j\big) - 2\lambda s_j .

The proof of item 2 of the theorem goes through word for word, with κ\kappa replaced by νj\nu_j and 1+σ21 + \sigma^2 by νj+σ2\nu_j + \sigma^2.

In plain words, with weight decay a non-contrastive network keeps exactly the directions whose signal is strong compared with the augmentation noise. It lets the rest collapse. A tiny example makes the threshold concrete. With σ2=0.5\sigma^2 = 0.5 and λ=0.01\lambda = 0.01, the bar is 4λ=0.044\lambda = 0.04. A direction with νj=1\nu_j = 1 scores 1/1.5=0.671/1.5 = 0.67 and survives easily. A direction with νj=0.1\nu_j = 0.1 scores 0.01/0.6=0.0170.01/0.6 = 0.017 and dies.

This puts a number on an idea that runs through the whole chapter, from the augmentation graph of §28.1 onward. What the augmentations destroy, the representation learns to ignore. In practice, stronger augmentation or more weight decay means fewer surviving directions.

The cell checks the theorem in a small simulation with real matrices. It trains a 16 by 16 linear online network and a 16 by 16 linear predictor, three ways. The data have variances νj=2⋅0.7j\nu_j = 2\cdot0.7^j, the augmentation noise is σ2=0.5\sigma^2 = 0.5, and the weight decay is 0.01. The cell uses the exact expected gradients, the large-batch limit, which keeps the run deterministic and fast. The threshold 4λ=0.044\lambda = 0.04 predicts that the first 8 directions survive. Along a surviving direction, the embedding's scale should be sjνj=pj+νj\sqrt{s_j\nu_j} = p_{j+}\sqrt{\nu_j} when αp=1\alpha_p = 1.

Python · cell 3

The prediction holds to within 0.002 for the first seven directions. The theory gives 1.124, 0.863, 0.645, 0.467, 0.324, 0.214, and 0.131. Training gives 1.125, 0.863, 0.646, 0.466, 0.326, 0.216, and 0.130. The network started from a random matrix that was not aligned with the data, and it was never told which directions exist. The eighth direction sits right at the threshold, 0.1652/0.665=0.0410.165^2/0.665 = 0.041 against 0.04, and is still settling. The ninth and beyond are dying, as predicted. The moving-average target lands in the same place. Without the stop-gradient, the whole network shrinks to a scale of 10−7110^{-71}. What little shape is left comes from the slowest-dying directions, so its effective rank of 1.77 describes almost nothing.

Setting the predictor directly

The theory says what a trained linear predictor converges to. So why train it at all? Tian et al. proposed to compute it directly, a method they call DirectPred. Here is the idea in plain words. Measure how the predictor's inputs are spread, find their main directions, and build a predictor that keeps those directions and scales each one by the square root of its strength.

In symbols, let f\mathbf{f} be the online network's output, which is the predictor's input. Its correlation matrix is F=E[ff⊤]\mathbf{F} = \mathbb{E}[\mathbf{f}\mathbf{f}^\top], uncentered. The matrix theory in the box above says the predictor's eigenvectors align with those of F\mathbf{F}. On the parabola, each eigenvalue sjs_j of F\mathbf{F} is tied to the predictor's eigenvalue by sj=pj2/αps_j = p_j^2/\alpha_p, so pj∝sjp_j \propto \sqrt{s_j}. DirectPred estimates F\mathbf{F} with a moving average over batches, F^←ρF^+(1−ρ) Ebatch[ff⊤]\hat{\mathbf{F}} \leftarrow \rho\hat{\mathbf{F}} + (1-\rho)\,\mathbb{E}_{\text{batch}}[\mathbf{f}\mathbf{f}^\top], where ρ\rho sets how slowly the average moves. It decomposes F^=U^diag⁡(sj)U^⊤\hat{\mathbf{F}} = \hat{\mathbf{U}}\operatorname{diag}(s_j)\hat{\mathbf{U}}^\top and sets

Wp=U^diag⁡(sj+ϵmax⁡jsj)U^⊤.\mathbf{W}_p = \hat{\mathbf{U}}\operatorname{diag}\big(\sqrt{s_j} + \epsilon\max_j s_j\big)\hat{\mathbf{U}}^\top .

The small ϵ\epsilon lifts weak directions so that they can still grow. The test was on STL-10 with a ResNet-18 trained for 100 epochs with a moving-average target. DirectPred reached 76.77 percent, against 74.51 for a linear predictor trained by gradient descent. The ϵ\epsilon term added about another point, 77.86 at its best setting. That is small-scale evidence, but it is evidence that the linear theory captured something real. An interviewer who asks "what does the predictor learn?" will be pleased by this answer, a map aligned with the main directions of its inputs.

Research

DirectPred on a linear Siamese network

Train a linear BYOL with a moving-average target, and set its predictor by DirectPred at every step. Work in the expected-gradient (large-batch) setting of the cell above. Implement train_linear_byol(W0, nu, sigma2, predictor="directpred", steps=600, lr=0.1, m=0.99, rho=0.3, eps=0.0) and return the final online weights W. Use S=diag⁡(ν)\mathbf{S} = \operatorname{diag}(\nu) and A=S+σ2I\mathbf{A} = \mathbf{S} + \sigma^2\mathbf{I}. Start with W = Wa = W0 and F^=WAW⊤\hat{\mathbf{F}} = \mathbf{W}\mathbf{A}\mathbf{W}^\top. Then take steps steps, each doing three things in this order.

  1. Set the predictor. If predictor == "directpred", update F^←ρF^+(1−ρ)WAW⊤\hat{\mathbf{F}} \leftarrow \rho\hat{\mathbf{F}} + (1-\rho)\mathbf{W}\mathbf{A}\mathbf{W}^\top, take its eigendecomposition with np.linalg.eigh, clip negative eigenvalues to 0, and set Wp\mathbf{W}_p by the formula above. If predictor == "none", set Wp=I\mathbf{W}_p = \mathbf{I}.
  2. Take a gradient step of size lr on 12E∥WpWx(1)−Wax(2)∥2\tfrac12\mathbb{E}\lVert\mathbf{W}_p\mathbf{W}x^{(1)} - \mathbf{W}_a x^{(2)}\rVert^2 with respect to W\mathbf{W} only, holding the target Wa\mathbf{W}_a fixed, with no weight decay.
  3. Update the target, Wa←mWa+(1−m)W\mathbf{W}_a \leftarrow m\mathbf{W}_a + (1-m)\mathbf{W}.

The tests compare your weights with a reference. Then they check that DirectPred keeps many directions alive while the network without a predictor keeps shrinking.

Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.

Is BatchNorm a hidden source of negatives?

BatchNorm (§0.7) normalizes each feature with the mean and variance of the whole batch. So the gradient of one image's loss flows into every other image in the batch. A widely read 2020 analysis of BYOL suggested that this coupling acts as a hidden contrastive term. In small experiments, a ResNet-18 on STL-10 trained with SGD, it reported that BYOL did no better than chance without BatchNorm in its projector and predictor.

Richemond et al. (2020) tested the idea at full scale. They replaced BatchNorm everywhere with two layers that use no batch statistics at all. Group normalization normalizes groups of channels within one image, and weight standardization normalizes each filter's weights. BYOL trained this way reached 73.9 percent, against 74.3 with BatchNorm. Removing BatchNorm with nothing in its place gave 0.1 percent. Three changes together brought that back to 65.7, with still no batch statistics. They were a better weight initialization, keeping BatchNorm's learned scale and shift as plain parameters, and a longer warmup. So batch statistics are not what prevents collapse, although they help optimization. The linear theory above has no BatchNorm either, which supports the same conclusion. This is a favorite interview question, and the answer is the experiment, not the hypothesis.

Barlow Twins, make the cross-correlation the identity

The asymmetric methods avoid collapse through their training dynamics, and it took a theorem to see why. Barlow Twins takes the other road. It writes a loss whose minimum is not a collapsed network in the first place (Zbontar et al. 2021). The name honors the neuroscientist Horace Barlow, who argued that the brain recodes its sensory input so that no two units of the code carry the same information. That is redundancy reduction. Barlow Twins adds a second demand, that each unit ignore the augmentation.

In plain words, the loss asks two things of every output unit ii. Unit ii for the first view should be perfectly correlated with unit ii for the second view, so the unit ignores the augmentation. And unit ii for one view should be uncorrelated with every other unit jj for the other view, so no two units duplicate each other. One matrix holds all those correlations at once, and the loss pushes it toward the identity.

Each CijC_{ij} is the correlation over the batch between dimension ii of the first view and dimension jj of the second. It lies in [−1,1][-1, 1] when ϵ=0\epsilon = 0, by the Cauchy-Schwarz inequality (an inner product is at most the product of the two lengths). A positive ϵ\epsilon only shrinks it. Here is a tiny batch worked through by hand.

The general statement says exactly where the loss is zero, and what collapse costs.

∂ Proof

The loss is a sum of squares with positive weights, so it is nonnegative and vanishes exactly when every square does, Cii=1C_{ii} = 1 and Cij=0C_{ij} = 0. With ϵ=0\epsilon = 0, each standardized column has ∥z~i∥2=B\lVert\tilde{\mathbf{z}}_i\rVert^2 = B. So Cii=z~i(1)⊤z~i(2)/B=1C_{ii} = \tilde{\mathbf{z}}^{(1)\top}_i\tilde{\mathbf{z}}^{(2)}_i/B = 1 is equality in Cauchy-Schwarz between two vectors of the same length, which forces z~i(2)=z~i(1)\tilde{\mathbf{z}}^{(2)}_i = \tilde{\mathbf{z}}^{(1)}_i. Substituting into Cij=0C_{ij} = 0 gives z~i(1)⊤z~j(1)=0\tilde{\mathbf{z}}^{(1)\top}_i\tilde{\mathbf{z}}^{(1)}_j = 0 for i≠ji \ne j, and together with the diagonal this is Z~(1)⊤Z~(1)/B=I\tilde{\mathbf{Z}}^{(1)\top}\tilde{\mathbf{Z}}^{(1)}/B = \mathbf{I}. The converse is the same computation backwards. For a constant network, zbi−zˉi=0z_{bi} - \bar z_i = 0, so z~bi=0/ϵ=0\tilde z_{bi} = 0/\sqrt{\epsilon} = 0, CBT=0\mathbf{C}_{\text{BT}} = \mathbf{0}, and the loss is ∑i12=dz\sum_i 1^2 = d_z. ∎

In plain words, the invariance term says every output unit must report the same thing for both views. The redundancy term says no two units may report the same thing. Collapse breaks the first rule in every unit, so it costs dzd_z instead of 0. The standardization does the work that negatives did in §28.2, because a unit with no spread cannot correlate with anything.

There is a catch that the formula hides. Centering removes one dimension, so the centered batch has rank at most B−1B - 1, and so does CBT\mathbf{C}_{\text{BT}}. It cannot equal the dz×dzd_z\times d_z identity unless dz≤B−1d_z \le B - 1. With the paper's dz=8,192d_z = 8{,}192 and B=2,048B = 2{,}048, the minimum 0 is out of reach. The loss is always a compromise between its two terms. Even so, Barlow Twins kept improving across every projector width its authors tried, while SimCLR and BYOL saturate early. In an interview, this rank argument is the expected answer to "can Barlow Twins reach zero loss?".

To train with this loss you need its gradient, which passes through the batch standardization.

∂ The gradient of the Barlow Twins loss

Write A=Z~(1)\mathbf{A} = \tilde{\mathbf{Z}}^{(1)} and GC=∂LBT/∂CBT\mathbf{G}_C = \partial\mathcal{L}_{\text{BT}}/\partial\mathbf{C}_{\text{BT}}, which has diagonal entries −2(1−Cii)-2(1 - C_{ii}) and off-diagonal entries 2λBTCij2\lambda_{\text{BT}}C_{ij}. Since C=A⊤Z~(2)/B\mathbf{C} = \mathbf{A}^\top\tilde{\mathbf{Z}}^{(2)}/B is linear in A\mathbf{A}, a small change dA\mathrm{d}\mathbf{A} changes the loss by

dL=tr⁡(GC⊤ dC)=1Btr⁡(GC⊤ dA⊤Z~(2))=1Btr⁡(dA⊤ Z~(2)GC⊤),\mathrm{d}\mathcal{L} = \operatorname{tr}\big(\mathbf{G}_C^\top\,\mathrm{d}\mathbf{C}\big) = \tfrac1B\operatorname{tr}\big(\mathbf{G}_C^\top\,\mathrm{d}\mathbf{A}^\top\tilde{\mathbf{Z}}^{(2)}\big) = \tfrac1B\operatorname{tr}\big(\mathrm{d}\mathbf{A}^\top\,\tilde{\mathbf{Z}}^{(2)}\mathbf{G}_C^\top\big),

using the cyclic property of the trace. So ∂L/∂A=1BZ~(2)GC⊤∈RB×dz\partial\mathcal{L}/\partial\mathbf{A} = \frac1B\tilde{\mathbf{Z}}^{(2)}\mathbf{G}_C^\top \in \R^{B\times d_z}, the same shape as A\mathbf{A} (§0.2).

Next comes the standardization. It is BatchNorm without the learned scale and shift, whose backward pass §0.7 derived. For one column with upstream gradient g=∂L/∂ai\mathbf{g} = \partial\mathcal{L}/\partial\mathbf{a}_i and standardized values ai\mathbf{a}_i,

∂L∂zi(1)=1vi+ϵ(g−gˉ 1−ai g ai‾),\frac{\partial\mathcal{L}}{\partial\mathbf{z}^{(1)}_i} = \frac{1}{\sqrt{v_i + \epsilon}}\Big(\mathbf{g} - \bar g\,\mathbf{1} - \mathbf{a}_i\,\overline{g\,a_i}\Big),

where gˉ\bar g is the batch mean of g\mathbf{g} and g ai‾\overline{g\,a_i} the batch mean of the elementwise product. The two subtracted terms remove the parts of g\mathbf{g} that a shift or a rescaling of the column would absorb, so every column of the result sums to zero. Here gˉ\bar g is in fact 0, because g\mathbf{g} is a combination of the centered columns of Z~(2)\tilde{\mathbf{Z}}^{(2)}, but the general formula costs nothing. The second view's gradient is the same with the roles swapped, ∂L/∂Z~(2)=1BZ~(1)GC\partial\mathcal{L}/\partial\tilde{\mathbf{Z}}^{(2)} = \frac1B\tilde{\mathbf{Z}}^{(1)}\mathbf{G}_C.

Interview

Barlow Twins, no loops

Implement barlow_twins(Z1, Z2, lam=5e-3, eps=1e-5) for two batches of embeddings of shape (B, d_z). Standardize each dimension of each view over the batch (axis 0), with that view's own mean and population variance and ϵ\epsilon inside the square root. Form CBT\mathbf{C}_{\text{BT}} by dividing by BB. Return (loss, C, dZ1), where dZ1 is the gradient of the loss with respect to Z1. Use no Python loops over the batch or the dimensions.

Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.

VICReg, three terms with three jobs

Barlow Twins ties invariance and decorrelation together in one cross-correlation matrix. It also hides the scale of the embeddings behind a standardization. VICReg separates the jobs into three terms, each computed on its own branch where possible (Bardes, Ponce and LeCun 2022). In plain words, it asks for three things. The two views of an image should be close. Every dimension should keep a minimum spread over the batch. And no two dimensions should be correlated. The name lists the terms, variance, invariance, and covariance.

The variance term is the hinge of §1.10. There it charged one minus each dimension's standard deviation whenever that standard deviation fell below 1, and it stopped a linear encoder from shrinking to zero. Here it gains a small ϵ\epsilon and an average over the dzd_z dimensions.

Each term has one job. Invariance pulls the views together. Variance forbids complete collapse. Covariance forbids dimensional collapse by decorrelating the dimensions. The variance term cannot do that alone, since every dimension could carry the same signal with unit spread.

Why hinge the standard deviation and not the variance? The paper remarks that a hinge on the variance has a vanishing gradient near collapse. Computing the gradient makes the remark exact.

∂ Proof

Write u=zj−zˉj1\mathbf{u} = \mathbf{z}^j - \bar z_j\mathbf{1}. The variance is σj2=u⊤u/(B−1)\sigma_j^2 = \mathbf{u}^\top\mathbf{u}/(B-1), and ∂zˉj/∂zbj=1/B\partial\bar z_j/\partial z_{bj} = 1/B. So ∂σj2/∂zbj=2B−1(ub−1B∑cuc)=2ubB−1\partial\sigma_j^2/\partial z_{bj} = \frac{2}{B-1}\big(u_b - \frac1B\sum_c u_c\big) = \frac{2u_b}{B-1}, because the centered entries sum to zero. The chain rule through the square root multiplies by 1/(2σj2+ϵ)1/(2\sqrt{\sigma_j^2 + \epsilon}), which gives the first formula. Its norm is ∥u∥/((B−1)σj2+ϵ)\lVert\mathbf{u}\rVert/((B-1)\sqrt{\sigma_j^2+\epsilon}) with ∥u∥=B−1 σj\lVert\mathbf{u}\rVert = \sqrt{B-1}\,\sigma_j, which simplifies to the stated value. The norm of 2u/(B−1)2\mathbf{u}/(B-1) is 2σj/B−12\sigma_j/\sqrt{B-1}.

For the covariance term, c=1dz∑i≠jCij2c = \frac1{d_z}\sum_{i\ne j}C_{ij}^2 gives ∂c/∂C=2dzO\partial c/\partial\mathbf{C} = \frac{2}{d_z}\mathbf{O} with O=offdiag⁡(C)\mathbf{O} = \operatorname{offdiag}(\mathbf{C}), which is symmetric. With C=Z~⊤Z~/(B−1)\mathbf{C} = \tilde{\mathbf{Z}}^\top\tilde{\mathbf{Z}}/(B-1),

dc=2dz(B−1)tr⁡(O(dZ~⊤Z~+Z~⊤dZ~))=4dz(B−1)tr⁡(dZ~⊤Z~O),\mathrm{d}c = \tfrac{2}{d_z(B-1)}\operatorname{tr}\big(\mathbf{O}(\mathrm{d}\tilde{\mathbf{Z}}^\top\tilde{\mathbf{Z}} + \tilde{\mathbf{Z}}^\top\mathrm{d}\tilde{\mathbf{Z}})\big) = \tfrac{4}{d_z(B-1)}\operatorname{tr}\big(\mathrm{d}\tilde{\mathbf{Z}}^\top\tilde{\mathbf{Z}}\mathbf{O}\big),

so ∂c/∂Z~=4dz(B−1)Z~O\partial c/\partial\tilde{\mathbf{Z}} = \frac{4}{d_z(B-1)}\tilde{\mathbf{Z}}\mathbf{O}. Centering multiplies by I−1B11⊤\mathbf{I} - \frac1B\mathbf{1}\mathbf{1}^\top on the left, and 1⊤Z~=0\mathbf{1}^\top\tilde{\mathbf{Z}} = \mathbf{0}, so it changes nothing. ∎

In plain words, the standard-deviation hinge pushes a shrinking dimension apart with a nearly constant force, about 1/B−11/\sqrt{B-1}. A variance hinge pushes with a force proportional to σj\sigma_j. So the closer a dimension gets to collapse, the less a variance hinge resists, which is exactly backward.

Put numbers on it with B=257B = 257, so B−1=16\sqrt{B-1} = 16. A dimension that has shrunk to σj=0.1\sigma_j = 0.1 gets a push of 0.995/16=0.0620.995/16 = 0.062 from the standard-deviation hinge. A variance hinge would give it 0.2/16=0.01250.2/16 = 0.0125, five times less, and the gap widens as σj\sigma_j falls. The standard-deviation hinge keeps most of its force down to σj≈ϵ=0.01\sigma_j \approx \sqrt{\epsilon} = 0.01, where it is still 1/21/\sqrt2 of its full size.

The ϵ\epsilon is there because the derivative of σj2\sqrt{\sigma_j^2} is undefined at σj=0\sigma_j = 0. With it, the force falls off linearly once σj\sigma_j drops well below ϵ\sqrt{\epsilon}. Even there it is 1/(2ϵ)=501/(2\sqrt{\epsilon}) = 50 times the variance hinge's force. An interviewer asking "why the square root?" wants this argument.

Compared with Barlow Twins, VICReg makes three different choices, and it shares one limit.

Barlow TwinsVICReg
Scale of the embeddingsremoved by standardization, so rescaling a dimension changes nothingvisible to the loss, so the variance term must hold it up
What is decorrelatedthe two branches against each other, through one cross-correlationeach branch on its own, so the branches need not share weights, architectures, or even input modalities
Invariancea correlation of 1 per dimensiona plain squared distance
Reachable minimum when dzd_z exceeds B−1B - 1nono

The last row holds for VICReg for a rank reason. A dz×dzd_z\times d_z covariance with every diagonal entry at least 1 and zeros off the diagonal is full rank. The covariance of BB samples has rank at most B−1B - 1. So with dz=8,192d_z = 8{,}192 and B=2,048B = 2{,}048, the variance and covariance terms cannot both be zero.

The second row is VICReg's practical advantage. Because each branch is regularized on its own, the paper pairs images with text and evaluates retrieval on MS-COCO, a dataset of photos with captions. Whitening methods take the hard version of the same idea. W-MSE (Ermolov et al. 2021) whitens each batch of embeddings exactly, with the matrices of §0.10, so that their covariance is the identity. Only then does it apply a mean-squared-error loss between the views, so collapse is impossible by construction.

The cell computes the Barlow Twins and VICReg terms on a healthy batch of 512 pairs in R16\R^{16} and on four damaged versions. It shows which term answers which kind of damage.

Python · cell 4

Read the table one row at a time. Four dead dimensions cost Barlow Twins almost exactly 4 in its invariance term, because each dead dimension has Cii=0C_{ii} = 0. They cost VICReg through its variance term, 12.9. Eight copies of one dimension light up the redundancy and covariance terms. Noisy views raise both invariance terms. Shrinking the whole batch tenfold changes nothing for Barlow Twins, whose standardization removes scale. VICReg's variance term jumps to 44.9, because it alone watches the scale.

The widget below lets you damage a batch yourself and watch each term respond. Predict before you slide. Choose Barlow Twins and correlated dims, and push the correlation between dimensions to 0.9. Which term grows, and roughly by how much, given that there are dz(dz−1)d_z(d_z - 1) off-diagonal entries weighted by 0.005? Then choose VICReg and spread, set the spread per dimension to 0.1, and predict the variance term before you look.

What do Barlow Twins and VICReg each penalize in a batch of embeddings?
256 pairs of 16-dimensional embeddings. Damage the batch one way and see which loss term answers.
Loading interactive figure…

Each kind of damage shows up in the term built to catch it, the division of labor the cell above printed. The paper's coefficient study, which drops terms from the loss at ImageNet scale, tells the same story.

Interview

VICReg loss and its gradient

Implement vicreg(Z1, Z2, lam_inv=25.0, lam_var=25.0, lam_cov=1.0, eps=1e-4) for two batches of shape (B, d_z), exactly as the definition box writes it. Five details matter. Use the unbiased variance and covariance. Hinge Var⁡+ϵ\sqrt{\operatorname{Var} + \epsilon}, not the variance. Keep the 1/dz1/d_z factors. Average the invariance over the batch. Regularize each branch separately. Return (loss, dZ1, dZ2), the loss and its gradients with respect to both inputs. Use no loops.

Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.

Clustering, and codes that must be balanced

A third family prevents collapse by counting. Give the network a set of clusters, assign every image to one of them, and train the network to predict an image's assignment from another view of it. Collapse would put every image in one cluster. So add a rule that the clusters must be used equally, and the constant solution can no longer score well.

SwAV, short for swapping assignments between views (Caron et al. 2020), does the balancing inside each batch. So the method runs online, one batch at a time, with no pass over the whole dataset.

SwAV's clusters are prototypes, learned unit vectors in the embedding space, one per cluster. An image's code is a soft assignment, a probability distribution over the prototypes. The codes of a batch are chosen to agree with the embeddings as much as possible, under one rule. Every prototype must receive an equal share of the batch, a rule called equipartition. Then each view is trained to predict the other view's code.

Choosing the codes is an optimal transport problem. Think of each image as holding an equal share of mass, 1/B1/B, that it must ship to the prototypes. Shipping mass from image bb to prototype kk earns the score SbkS_{bk}, the cosine similarity between them, per unit of mass. The plan must earn as much as possible, and every prototype must receive the same total, 1/Kp1/K_p. Here is a tiny case. With 4 images and 2 prototypes, each prototype must receive half the mass, two images' worth, even if all 4 images prefer the first prototype.

The entropy term εH\varepsilon H keeps the codes soft, and ε\varepsilon sets how soft. The constrained problem has a closed-form solution up to two scaling vectors, and the algorithm that finds them takes a few lines.

∂ Deriving the form of the transport plan

The objective is strictly concave in Γ\boldsymbol\Gamma (a linear term plus ε\varepsilon times the strictly concave entropy), and the constraint set is convex and compact, so the maximizer exists and is unique. Attach a multiplier αb\alpha_b to each image's constraint and βk\beta_k to each prototype's,

J=∑bkΓbkSbk−ε∑bkΓbklog⁡Γbk+∑bαb(1B−∑kΓbk)+∑kβk(1Kp−∑bΓbk).\mathcal{J} = \sum_{bk}\Gamma_{bk}S_{bk} - \varepsilon\sum_{bk}\Gamma_{bk}\log\Gamma_{bk} + \sum_b\alpha_b\Big(\tfrac1B - \sum_k\Gamma_{bk}\Big) + \sum_k\beta_k\Big(\tfrac1{K_p} - \sum_b\Gamma_{bk}\Big).

Setting ∂J/∂Γbk=Sbk−ε(log⁡Γbk+1)−αb−βk=0\partial\mathcal{J}/\partial\Gamma_{bk} = S_{bk} - \varepsilon(\log\Gamma_{bk} + 1) - \alpha_b - \beta_k = 0 gives

log⁡Γbk=Sbkε−1−αbε−βkε,Γbk=e−1/2−αb/ε⏟ub eSbk/ε e−1/2−βk/ε⏟vk.\log\Gamma_{bk} = \frac{S_{bk}}{\varepsilon} - 1 - \frac{\alpha_b}{\varepsilon} - \frac{\beta_k}{\varepsilon}, \qquad \Gamma_{bk} = \underbrace{e^{-1/2 - \alpha_b/\varepsilon}}_{u_b}\ e^{S_{bk}/\varepsilon}\ \underbrace{e^{-1/2 - \beta_k/\varepsilon}}_{v_k}.

Every entry is positive, so the constraint Γ≥0\boldsymbol\Gamma \ge 0 is inactive, and the stationary point is the maximizer. The column constraint reads vk∑bubKbk=1/Kpv_k\sum_b u_bK_{bk} = 1/K_p, so for fixed u\mathbf{u} the right v\mathbf{v} is vk=(1/Kp)/(K⊤u)kv_k = (1/K_p)/(\mathbf{K}^\top\mathbf{u})_k. The row constraint gives ub=(1/B)/(Kv)bu_b = (1/B)/(\mathbf{K}\mathbf{v})_b. Sinkhorn-Knopp alternates these two updates. That is the same as alternately dividing each column of the current matrix by its sum and multiplying by 1/Kp1/K_p, then each row by its sum and multiplying by 1/B1/B. One global constant multiplying K\mathbf{K} cancels in every rescaling, which is why subtracting the largest score before exponentiating is safe.

The same entropic balanced assignment appears in §13.3, which derives it for routing tokens to experts, with tokens in place of images and experts in place of prototypes. There its job is to keep every expert busy. Here its job is to make the constant solution expensive, and the next result says exactly how expensive.

Proof. Swapping two images leaves the problem unchanged, so by uniqueness the solution has identical rows. The column constraint then forces every entry to be 1/(BKp)1/(BK_p), so every code is uniform. The loss of each image is a cross-entropy against the uniform distribution, which is at least that distribution's entropy, log⁡Kp\log K_p (§0.5). ∎

For SwAV's 3,000 prototypes, a collapsed encoder pays at least log⁡3000=8.01\log 3000 = 8.01 per image. An encoder whose predictions match confident, balanced codes can bring the loss down toward the codes' own entropy, which is near 0 when ε\varepsilon is small. Equipartition turns the constant solution into a bad one.

The same reasoning explains SwAV's three warnings, and each is a setting you must get right in practice.

  • A large ε\varepsilon weights the entropy so heavily that the codes are nearly uniform whatever the embeddings. Then the target carries no information, and the authors observed that training collapses.
  • A small ε\varepsilon gives sharp codes, but exp⁡(S/ε)\exp(\mathbf{S}/\varepsilon) becomes extreme, and three iterations may not finish balancing them. The cell below shows this.
  • A small batch breaks the balance. The batch must be large compared with KpK_p, or there is no meaningful balanced assignment. With batch 256 and 3,000 prototypes, SwAV keeps a queue of the last 3,840 embeddings and computes codes over it. That is a far shorter queue than MoCo's 65,536.

The cell balances 6 images over 3 prototypes, a small example you can follow entry by entry.

Python · cell 5

Four of the six images prefer prototype 1, so assigning each image to its best prototype gives totals (4,1,1)(4, 1, 1). At ε=0.05\varepsilon = 0.05, three iterations barely move them, to (3.92,1,1.08)(3.92, 1, 1.08). The scores differ by up to 0.9, and e0.9/0.05=e18e^{0.9/0.05} = e^{18} dwarfs everything else. Fifty iterations reach the equipartition (2,2,2)(2, 2, 2), and they split image 4 evenly between the first two prototypes. At ε=0.5\varepsilon = 0.5, three iterations already balance the batch, but image 4's code is soft, (0.45,0.29,0.25)(0.45, 0.29, 0.25). A small ε\varepsilon buys sharp targets at the cost of slow balancing. With thousands of images per batch, SwAV's authors found three iterations enough in practice. The collapsed batch gets uniform codes and a loss of exactly log⁡3\log 3.

Interview

Sinkhorn-Knopp for balanced codes

Implement sinkhorn(scores, eps=0.05, n_iters=3) for scores of shape (B, K_p), following SwAV's released order exactly.

  1. Form Q=exp⁡(scores/ε)⊤\mathbf{Q} = \exp(\text{scores}/\varepsilon)^\top of shape (K_p, B), subtracting the single largest entry of scores / eps before exponentiating, and divide Q\mathbf{Q} by its total.
  2. Repeat n_iters times. Rescale every row (prototype) to sum to 1/Kp1/K_p, then every column (image) to sum to 1/B1/B.
  3. Rescale every column to sum to 1, and return the transpose, codes of shape (B, K_p) whose rows sum to 1.

Use one global constant for the shift in step 1. A per-image shift would change the result after a finite number of iterations. The released code skips the shift, which changes nothing mathematically but can overflow.

Tests, hints, verified solutions, and AI help, with Pro at $7.99 a month.

Dimensional collapse, even with negatives

Negatives prevent complete collapse. They do not prevent dimensional collapse. Jing, Vincent, LeCun and Tian (2022) trained a standard SimCLR for 100 epochs on ImageNet with 128-dimensional embeddings. A sizable part of the embedding covariance spectrum had fallen to essentially zero. They proved two mechanisms that cause it, each for linear networks.

Strong augmentation. Take a one-layer linear encoder z=Wx\mathbf{z} = \mathbf{W}x trained with InfoNCE, the contrastive loss of §7.2. Its gradient flow is W˙=WX\dot{\mathbf{W}} = \mathbf{W}\mathbf{X} for a symmetric matrix X\mathbf{X}. That matrix is a weighted covariance of the data minus a weighted covariance of the augmentation noise. Along a direction where the augmentation varies more than the data, X\mathbf{X} has a negative eigenvalue. Treating X\mathbf{X} as fixed, as their Theorem 1 does, the weight along that direction then shrinks to zero. In plain words, pushing negatives apart along such a direction does not pay, because pulling the positive pair together along it costs more.

Implicit regularization. Now take two linear layers, z=W2W1x\mathbf{z} = \mathbf{W}_2\mathbf{W}_1x. During training, the singular vectors of adjacent layers align. Each aligned pair of singular values then grows at a rate proportional to its own size. So small directions stay small, and the product drifts toward low rank, even without strong augmentation (their Theorems 2 and 3).

The cell tests the first mechanism in a small simulation. It trains a linear encoder on 16-dimensional data of unit variance with InfoNCE over a batch of 64. The similarity is −∥zi−zj′∥2/2-\lVert\mathbf{z}_i - \mathbf{z}'_j\rVert^2/2, as in their analysis. It runs once with mild augmentation and once with augmentation of variance 8 on dimensions 8 to 15.

Python · cell 6

With mild augmentation, all 16 singular values of W\mathbf{W} stay alive. The noisy half sits at 0.33 to 0.68, against 1.3 to 1.9 for the clean half. With strong augmentation, the noisy half falls to between 0.001 and 0.09, while the clean half grows past 1.6. That is a gap of at least 18 times, and up to three orders of magnitude. The encoder still has negatives, and it has still discarded half of its dimensions.

Here the discarded directions are pure nuisance, which is the point of augmentation. In a real image the line between nuisance and content is not so clean. Jing et al. argue that the lost dimensions are capacity a downstream task could have used, and the projector results below support them.

This also explains the projection head. A trainable projector between the representation and the loss can absorb the collapse, so that the representation h\mathbf{h} keeps more dimensions than the embedding z\mathbf{z}. Jing et al. confirmed it at 100 epochs with a ResNet-50.

  • SimCLR with a two-layer nonlinear projector reached 66.5 percent.
  • With a linear projector it reached 61.1, and with no projector 51.5. Without a projector, the representation's own spectrum collapsed.
  • Their DirectCLR applies InfoNCE directly to a fixed sub-vector of the representation, its first d0d_0 coordinates, with no trainable projector. It reached 62.7, beating the linear projector.

Garrido et al. (2023) later turned the same observation into a tool. The effective rank of the embeddings tracks downstream accuracy well enough to select hyperparameters without labels, which §28.6 takes up. An interviewer who asks why we throw the projection head away expects this answer, as well as the one from §28.2.

In PyTorch

Here are four of the losses in production form, BYOL, SimSiam, Barlow Twins, and VICReg. The stop-gradient is .detach(), and the moving-average update runs under torch.no_grad(). The block also checks two exact results against autograd. One is SimSiam's identity, that without a predictor the stop-gradient loss has half the gradient of the plain loss. The other is the VICReg covariance gradient from the theorem.

🔥 In PyTorchfor a machine with PyTorch

All the joint-embedding methods side by side

Every method in this chapter so far is a joint-embedding method. It embeds two views with encoders and compares the embeddings. The table puts the methods of §28.2 and this section together, at real scale.

Each family pays a different cost for avoiding collapse. Contrastive methods pay for many negatives. The redundancy-reduction methods, Barlow Twins and VICReg, pay in memory, not compute.

The asymmetric methods, BYOL and SimSiam, pay in sensitivity to hyperparameters instead. Their success depends on the target momentum, the predictor's learning rate, and the weight decay. Those are exactly the three quantities the linear theory singles out.

Where it breaks. The mechanisms are understood for linear networks. For deep networks, the linear theorems predict the ablations, but nobody has proved that BYOL or SimSiam avoid collapse. Both also have failure modes the theory does not cover. A frozen predictor fails to converge, and BatchNorm on the predictor's output makes the loss oscillate. Barlow Twins and VICReg cannot reach their minimum when dzd_z exceeds the batch, so the balance of their terms depends on BB. Clustering methods need a batch or a queue that is large compared with the number of prototypes. And every method here compares whole-image embeddings. None of them is trained to keep the spatial detail that segmentation needs. That gap is what §28.4 and §28.5 address.

The same tools reach beyond whole images. A stop-gradient and a moving-average target keep joint-embedding predictive architectures from collapsing, models that predict the embeddings of hidden image regions from the visible ones. LeCun's 2022 proposal for such architectures, A Path Towards Autonomous Machine Intelligence, suggested variance and covariance terms like VICReg's for the same purpose.

Read more

Watch next

🎬 BYOL: Bootstrap Your Own Latent: A New Approach to Self-Supervised Learning (Paper Explained) · Yannic KilcherA careful walk through BYOL's online and target networks, the predictor, the moving average, and the ablations that show what prevents collapse.
🎬 10P – Non-contrastive joint embedding methods (JEMs) for self-supervised learning (SSL) · Alfredo Canziani (冷在)NYU Deep Learning practicum that puts the non-contrastive families (asymmetric, redundancy reduction, clustering) side by side, the same map this section draws.
🎬 Jure Žbontar | Barlow Twins: Self-Supervised Learning via Redundancy Reduction · KUIS AIThe first author explains the cross-correlation loss, why it avoids collapse without asymmetry, and why it gets better with wider projectors.