Course contents 08 / 33

08 / 33 · Variational Autoencoders

VAE variants: β-VAE and VQ-VAE

Three ways to change a VAE: a weight on the KL term that sets how much the code may carry (β-VAE), a discrete code whose prior is learned afterwards (VQ-VAE and VQ-VAE-2), and, as optional depth, a flow decoder with an exact likelihood (VAPNEV).

On this page 11

The VAE ended with two complaints. Its samples are blurry, and its fixed Gaussian prior is only roughly matched by the codes the encoder actually produces, so prior samples can land where the decoder was never trained. This note follows three answers. The first keeps the model and changes the objective: a weight β\beta on the KL term decides how much information the code may carry. The second keeps the autoencoder and changes the code: a grid of discrete symbols from a learned codebook, with the prior fitted afterwards by a model strong enough to match them. The third keeps the Gaussian code and changes the decoder’s likelihood: an exact likelihood computed by a normalizing flow instead of a squared error summed over pixels.

Notation. As in the VAE note: an image xx, a code zz, an encoder qφ(z∣x)q_\varphi(z \mid x), a decoder pθ(x∣z)p_\theta(x \mid z), a prior p(z)p(z). sg[⋅]\mathrm{sg}[\cdot] is the stop-gradient operator: it returns its argument in the forward pass and has zero derivative in the backward pass. A codebook is a set of KK vectors e1,…,eK∈Rde_1, \dots, e_K \in \mathbb R^d.

Three ways to change a VAE#

The ELBO of one image has two terms:

L(x)=Eqφ(z∣x)[log⁡pθ(x∣z)]⏟reconstruction−DKL(qφ(z∣x) ∥ p(z))⏟KL to the prior.\mathcal L(x) = \underbrace{\mathbb E_{q_\varphi(z \mid x)}\big[\log p_\theta(x \mid z)\big]}_{\text{reconstruction}} - \underbrace{D_{\mathrm{KL}}\big(q_\varphi(z \mid x)\,\|\,p(z)\big)}_{\text{KL to the prior}} .

The first term wants the code to say as much about xx as possible; the second charges for every bit it says. Changing their balance is the β-VAE. Changing what a code is, a continuous Gaussian or one symbol out of KK, is the VQ-VAE. The two are independent: one moves along a trade-off, the other changes where the difficulty of generation lives. A third change, an optional extension at the end of the note, keeps both terms and replaces the form of the reconstruction term itself, pθ(x∣z)p_\theta(x \mid z).

β-VAE: a weight on the KL term#

The β-VAE (Higgins et al., 2017) maximizes

Lβ(x)=Eqφ(z∣x)[log⁡pθ(x∣z)]−β DKL(qφ(z∣x) ∥ p(z)).\mathcal L_\beta(x) = \mathbb E_{q_\varphi(z \mid x)}\big[\log p_\theta(x \mid z)\big] - \beta\, D_{\mathrm{KL}}\big(q_\varphi(z \mid x)\,\|\,p(z)\big) .

β=1\beta = 1 is the plain VAE. For β>1\beta > 1 the objective is still a lower bound on log⁡pθ(x)\log p_\theta(x), because it subtracts more of a non-negative quantity than the ELBO does; for β<1\beta < 1 it can exceed log⁡pθ(x)\log p_\theta(x) and is no longer a bound. In both cases β\beta changes which model training prefers, not only the scale of the loss.

Rate and distortion#

Averaged over the data, the two terms have names from information theory (Alemi et al., 2018). The rate is the average KL,

R=Ex DKL(qφ(z∣x) ∥ p(z)),R = \mathbb E_{x}\, D_{\mathrm{KL}}\big(q_\varphi(z \mid x)\,\|\,p(z)\big),

measured in nats. It bounds from above the mutual information between images and their codes under the encoder: the identity behind this, rate equals mutual information plus the KL from the aggregate posterior to the prior, is derived in the VAE note. The distortion D=−ExEqφ(z∣x)log⁡pθ(x∣z)D = -\mathbb E_x \mathbb E_{q_\varphi(z \mid x)} \log p_\theta(x \mid z) is the average reconstruction loss. The negative ELBO is D+RD + R, and the β-VAE minimizes D+βRD + \beta R: the Lagrangian of “reconstruct as well as possible with at most a given rate”. Every β\beta picks one point of the trade-off; β=1\beta = 1 is the point that best bounds the likelihood.

Worked example: one latent dimension#

To see the trade-off with numbers, take one latent dimension, a standard normal prior p(z)=N(0,1)p(z) = \mathcal N(0, 1) and a fixed linear decoder p(x∣z)=N(wz,σ2)p(x \mid z) = \mathcal N(w z, \sigma^2) with w=1w = 1 and σ2=0.1\sigma^2 = 0.1. The data come from this very model, so x∼N(0,w2+σ2)=N(0,1.1)x \sim \mathcal N(0, w^2 + \sigma^2) = \mathcal N(0, 1.1). Holding the decoder fixed isolates what β\beta does to the encoder. Let the encoder be q(z∣x)=N(m,v)q(z \mid x) = \mathcal N(m, v). For one xx the β-objective is, up to constants,

J(m,v)=−(x−wm)2+w2v2σ2−β2(v+m2−1−ln⁡v),J(m, v) = -\frac{(x - w m)^2 + w^2 v}{2\sigma^2} - \frac{\beta}{2}\big(v + m^2 - 1 - \ln v\big),

using Eq(x−wz)2=(x−wm)2+w2v\mathbb E_q (x - w z)^2 = (x - wm)^2 + w^2 v and the closed-form KL to a standard normal from the VAE note. Setting the derivatives to zero,

∂J∂v=−w22σ2−β2+β2v=0,∂J∂m=w(x−wm)σ2−βm=0,\frac{\partial J}{\partial v} = -\frac{w^2}{2\sigma^2} - \frac{\beta}{2} + \frac{\beta}{2v} = 0, \qquad \frac{\partial J}{\partial m} = \frac{w(x - wm)}{\sigma^2} - \beta m = 0,

gives the optimal encoder

m=ww2+βσ2 x,v=βσ2w2+βσ2.m = \frac{w}{w^2 + \beta\sigma^2}\, x, \qquad v = \frac{\beta\sigma^2}{w^2 + \beta\sigma^2} .

At β=1\beta = 1 these are the mean and variance of the exact posterior p(z∣x)p(z \mid x), so the ELBO is tight. Averaging over x∼N(0,1.1)x \sim \mathcal N(0, 1.1) gives the rate and the squared-error distortion E(x−wz)2\mathbb E(x - wz)^2:

β\betam/xm / xvvrate RR, natsdistortion E(x−wz)2\mathbb E(x - wz)^2
0.250.9760.0241.890.025
10.9090.0911.200.100
40.7140.2860.550.376
160.3850.6150.131.032

Raising β\beta shrinks the code toward the prior: the mean is pulled to 0 and the variance grows toward 1, so the code says less about xx and the reconstruction gets worse. At β=16\beta = 16 the distortion, 1.03, is close to the variance of the data, 1.1: the code carries almost nothing. Lowering β\beta does the opposite and buys sharper reconstructions with a higher rate.

A high rate does not by itself mean a code far from the prior. The rate splits into the mutual information I(X;Z)I(X; Z) between images and codes plus the KL from the aggregate posterior q(z)=Ex q(z∣x)q(z) = \mathbb E_x\, q(z \mid x) to the prior. Here q(z)=N(0,(m/x)2⋅1.1+v)q(z) = \mathcal N\big(0, (m/x)^2 \cdot 1.1 + v\big): at β=0.25\beta = 0.25 its variance is 1.071, and the mismatch DKL(q(z) ∥ p(z))D_{\mathrm{KL}}\big(q(z)\,\|\,p(z)\big) is 0.001 of the 1.89 nats, so almost all of the rate is information about xx. Prior samples are poor when the aggregate posterior leaves the prior, or when the decoder is wrong where the prior puts mass. In this toy the decoder is fixed and equal to the true model, so β\beta changes only the encoder and samples decoded from the prior stay exact. In a jointly trained VAE a small β\beta also weakens the penalty on the mismatch, and that is how it can make prior samples worse.

Figure

β moves a VAE along the rate–distortion curve

Rate–distortion curve of a β-VAEA decreasing curve: as β grows, the rate falls and the distortion rises. β = 0.25: R = 1.89, D = 0.03; β = 1: R = 1.20, D = 0.10; β = 4: R = 0.55, D = 0.38; β = 16: R = 0.13, D = 1.03.00.40.81.200.511.522.5rate R, natsdistortion E(x − wz)²β = 0.25R 1.89, D 0.03β = 1, plain VAER 1.20, D 0.10β = 4R 0.55, D 0.38β = 16R 0.13, D 1.03Rate–distortion curve of a β-VAEA decreasing curve: as β grows, the rate falls and the distortion rises. β = 0.25: R = 1.89, D = 0.03; β = 1: R = 1.20, D = 0.10; β = 4: R = 0.55, D = 0.38; β = 16: R = 0.13, D = 1.03.00.40.81.200.511.522.5rate R, natsdistortion E(x − wz)²β = 0.25β = 1β = 4β = 16
One latent dimension, a fixed decoder x | z ~ N(z, 0.1) and data x ~ N(0, 1.1). For each β the encoder is chosen optimally by the formulas in the text; the curve shows all such points for β from 0.025 to 100. The rate R is the average KL from the posterior to the prior in nats, the distortion the average squared reconstruction error. β = 1 (the plain VAE) recovers the exact posterior and a distortion of exactly 0.1, the decoder noise. At β = 4 the rate drops below half and the error grows almost fourfold.

What β buys and what it does not#

Higgins et al. (2017) report that β>1\beta > 1 makes individual latent coordinates track individual factors of variation (position, scale, rotation of a sprite), which they call disentanglement. A disentangled representation is one in which a single latent unit is sensitive to changes in a single generative factor while being relatively invariant to changes in the others (Section 1). Both halves matter: the unit must follow its factor, and it must change little when another factor changes. On CelebA faces with β=250\beta = 250, single units turn the head, change the expression toward a smile or change the hair style while the rest of the face stays; in a plain VAE (β=1\beta = 1) the unit that turns the head also changes the expression, glasses and gender (Figure 1). Such a code would let us edit one feature at a time, reuse the factors for new tasks, reason about unseen combinations of known factors and notice inputs that fit no known combination (Section 1).

The mechanism is the pressure to spend little rate: a factorized prior is cheapest to match with a posterior whose coordinates are independent. β<1\beta < 1 weakens that pressure: it buys sharper reconstructions, and the objective favours a disentangled code even less. The effect of β>1\beta > 1 is not guaranteed either. Locatello et al. (2019) prove that without supervision or inductive biases disentanglement cannot be identified from data, and in a study of more than 12,000 trained models find that random seeds and hyperparameters matter more than the choice among disentangling objectives. Burgess et al. (2018) replace the fixed weight by a target rate CC that grows during training, Eqlog⁡pθ(x∣z)−γ ∣DKL−C∣\mathbb E_q \log p_\theta(x \mid z) - \gamma\,\lvert D_{\mathrm{KL}} - C \rvert, so that the code is allowed one more nat at a time. The useful reading of β-VAE is the one above: a dial on the rate, not a switch for interpretability.

VQ-VAE: a discrete latent code#

The VQ-VAE (van den Oord, Vinyals and Kavukcuoglu, 2017) gives up the continuous code. The encoder still outputs a map of vectors, ze(x)∈Rh×w×dz_e(x) \in \mathbb R^{h \times w \times d}, but each vector is replaced by the nearest entry of a learned codebook before it reaches the decoder:

k∗(i)=arg⁡min⁡k∥ze(x)i−ek∥2,zq(x)i=ek∗(i).k^*(i) = \arg\min_k \big\lVert z_e(x)_i - e_k \big\rVert^2, \qquad z_q(x)_i = e_{k^*(i)} .

The code of an image is the grid of indices k∗(i)k^*(i): for the 32×3232 \times 32 images below, 64 integers between 1 and 512 at the bottom level. In ELBO terms, the posterior q(z=k∣x)q(z = k \mid x) is one-hot at k∗k^*, and with a uniform prior over the KK codes its KL is log⁡K\log K per position, a constant. The KL term drops out of training, and the VQ-VAE trains as a plain autoencoder with a quantized bottleneck.

Figure

Vector quantization: the nearest codebook vector

Codebook cells in the planeA square split into three cells by the lines x = 1, y = 1 and y = x. Each cell holds its codebook vector and a few encoder outputs. The output (1.4, 0.3) is joined by a dashed line to its nearest vector e₂ = (2, 0).e₁e₃encoder output zezq = e₂each encoder output is replacedby the nearest codebook vector:the plane splits into Voronoi cells‖ze − e₂‖² = 0.45, the smallest‖ze − e₁‖² = 2.05‖ze − e₃‖² = 4.85Codebook cells in the planeA square split into three cells by the lines x = 1, y = 1 and y = x. Each cell holds its codebook vector and a few encoder outputs. The output (1.4, 0.3) is joined by a dashed line to its nearest vector e₂ = (2, 0).e₁e₃encoder output zezq = e₂each encoder output is replacedby the nearest codebook vector:the plane splits into Voronoi cells‖ze − e₂‖² = 0.45, the smallest‖ze − e₁‖² = 2.05‖ze − e₃‖² = 4.85
A codebook of three vectors e₁ = (0, 0), e₂ = (2, 0), e₃ = (0, 2) splits the plane into three cells bounded by the perpendicular bisectors between the vectors. Dots are encoder outputs, coloured by their cell. The output (1.4, 0.3) of the worked example is closest to e₂, so the decoder receives e₂. The commitment term pulls that output toward e₂, and the codebook update moves e₂ toward the mean of the outputs that fall in its cell.

Training through the argmin#

The argmin has no useful gradient: a small change of zez_e either keeps the same eke_k or jumps to another. The VQ-VAE uses the straight-through estimator (Bengio, Léonard and Courville, 2013): in the forward pass the decoder receives zqz_q, in the backward pass the gradient with respect to zqz_q is copied to zez_e unchanged. In code it is one line, z_q = z_e + (z_q - z_e).detach(): the value is zqz_q, the derivative is that of zez_e. The copy is a surrogate, not the derivative of quantization. Inside a cell the quantizer is constant, so its true Jacobian is zero; on a cell boundary it jumps. The straight-through estimator replaces that Jacobian by the identity, and this stays a substitution even when zez_e sits exactly on ek∗e_{k^*}, where the true derivative is still zero. Closeness only makes the heuristic plausible: the decoder’s gradient, evaluated at ek∗e_{k^*}, is then a reasonable guess for the direction in which to move zez_e. The loss has three terms:

L=−log⁡pθ(x∣zq(x))+∥sg[ze(x)]−e∥2+βc∥ze(x)−sg[e]∥2,\mathcal L = -\log p_\theta\big(x \mid z_q(x)\big) + \big\lVert \mathrm{sg}[z_e(x)] - e \big\rVert^2 + \beta_c \big\lVert z_e(x) - \mathrm{sg}[e] \big\rVert^2 ,

summed over positions, with e=ek∗e = e_{k^*}. The reconstruction term trains the decoder and, through the straight-through copy, the encoder. The codebook term moves ee toward the encoder output; it does not touch the encoder. The commitment term moves the encoder output toward ee; it does not touch the codebook. Without it nothing stops the encoder outputs from drifting away from the codebook faster than the codebook can follow. The paper uses βc=0.25\beta_c = 0.25 and reports that results are robust to it.

Worked example: one quantization step#

Take d=2d = 2, K=3K = 3, the codebook e1=(0,0)e_1 = (0, 0), e2=(2,0)e_2 = (2, 0), e3=(0,2)e_3 = (0, 2) and one encoder output ze=(1.4,0.3)z_e = (1.4, 0.3), the red point of the figure. The squared distances are

∥ze−e1∥2=1.96+0.09=2.05,∥ze−e2∥2=0.36+0.09=0.45,∥ze−e3∥2=1.96+2.89=4.85.\lVert z_e - e_1\rVert^2 = 1.96 + 0.09 = 2.05, \quad \lVert z_e - e_2\rVert^2 = 0.36 + 0.09 = 0.45, \quad \lVert z_e - e_3\rVert^2 = 1.96 + 2.89 = 4.85 .

The nearest vector is e2e_2, so the decoder receives zq=(2,0)z_q = (2, 0) and the code is the index 2. The codebook term is 0.450.45 and the commitment term is 0.25⋅0.45=0.11250.25 \cdot 0.45 = 0.1125: the same distance, with gradients sent in opposite directions. If the decoder’s loss has gradient gg with respect to zqz_q, the encoder receives exactly gg at zez_e, plus the commitment gradient 2βc(ze−e2)=0.5⋅(−0.6,0.3)=(−0.3,0.15)2\beta_c(z_e - e_2) = 0.5 \cdot (-0.6, 0.3) = (-0.3, 0.15), which points from e2e_2 toward zez_e, so a descent step moves zez_e toward e2e_2.

The codebook as online k-means#

The codebook term moves each eke_k toward the encoder outputs assigned to it, which is the update of k-means. The appendix of the VQ-VAE paper replaces it by exponential moving averages. For each code keep a count NkN_k and a sum mkm_k, update them with the nkn_k outputs assigned to code kk in the batch,

Nk←γNk+(1−γ) nk,mk←γ mk+(1−γ)∑i: k∗(i)=kze(x)i,ek=mkNk,N_k \leftarrow \gamma N_k + (1 - \gamma)\, n_k, \qquad m_k \leftarrow \gamma\, m_k + (1 - \gamma) \sum_{i:\, k^*(i) = k} z_e(x)_i, \qquad e_k = \frac{m_k}{N_k},

with γ=0.99\gamma = 0.99, and drop the codebook term from the loss. Each eke_k is then a running mean of its cell, exactly the k-means centroid computed online. With N2=10N_2 = 10, m2=(20,0)m_2 = (20, 0) (so e2=(2,0)e_2 = (2, 0)) and a batch of two outputs (1.4,0.3)(1.4, 0.3) and (1.8,−0.1)(1.8, -0.1) assigned to it, the update gives N2=9.92N_2 = 9.92, m2=(19.832,0.002)m_2 = (19.832, 0.002) and e2=(1.9992,0.0002)e_2 = (1.9992, 0.0002): a small step toward the batch mean (1.6,0.1)(1.6, 0.1), as a moving average with γ=0.99\gamma = 0.99 should take.

The weak point of this scheme is the one k-means has: a code that no output selects receives no update and stays where it was initialized, a dead code. With many dead codes the effective codebook is small. Practical fixes restart unused codes at recent encoder outputs, as in Jukebox (Dhariwal et al., 2020), or look codes up in a low-dimensional, normalized space, as in ViT-VQGAN (Yu et al., 2022). Implementations often add a small constant to the counts (Laplace smoothing) to avoid dividing by zero for unused codes; this does not revive them.

Where the prior went#

Because the KL term is constant, training leaves the prior uniform, and sampling the codes independently and uniformly would give an image of random patches. The VQ-VAE therefore fits the prior after the autoencoder: encode the training set into grids of indices and train an autoregressive model on them, a PixelCNN in the paper, which predicts each index from the ones before it. Generation samples a grid from this prior and decodes it. The two-stage structure is the point of the method. The autoencoder handles the pixels, and the prior only has to model a grid that is tens of times smaller and made of symbols, where autoregressive models are strong; how they work is the subject of the autoregressive models note.

VQ-VAE-2: two levels of codes#

A single grid has to carry both the global layout and the fine texture. VQ-VAE-2 (Razavi, van den Oord and Vinyals, 2019) uses two: a coarse top grid for the layout and a finer bottom grid for detail that is quantized after seeing the top. For ImageNet at 256×256256 \times 256 the grids are 32×3232 \times 32 and 64×6464 \times 64 with 512 codes each; FFHQ at 1024×10241024 \times 1024 uses three levels. The prior is hierarchical too: an autoregressive model over the top codes, with causal self-attention interleaved with its gated convolutions, and a conditional one over the bottom codes given the top, without attention to keep the larger grid affordable. The paper also filters samples with a pretrained ImageNet classifier, a rejection step that trades diversity for quality.

Figure

A small VQ-VAE-2: two code maps

Training and generation in a two-level VQ-VAETraining: a 32×32 image goes through the bottom encoder to an 8×8 map, the top encoder compresses it to 4×4, the top map is quantized, decoded back to 8×8, combined with the bottom features and quantized as the bottom map; the decoder reconstructs the image from the upsampled top codes and the bottom codes. Generation: a PixelCNN samples 16 top codes, a conditional PixelCNN 64 bottom codes, and the decoder turns them into an image.image32×32×3bottom encoder÷4 → 8×8top encoder÷2 → 4×4quantize top4×4 codes of 512top decoder4×4 → 8×8quantize bottom8×8 codes of 512decodertop ↑ + bottomreconstruction32×32×3PixelCNN (top)16 codes, one by oneconditional PixelCNN64 bottom codesdecodera new imagetraininggenerationTraining and generation in a two-level VQ-VAETraining: a 32×32 image goes through the bottom encoder to an 8×8 map, the top encoder compresses it to 4×4, the top map is quantized, decoded back to 8×8, combined with the bottom features and quantized as the bottom map; the decoder reconstructs the image from the upsampled top codes and the bottom codes. Generation: a PixelCNN samples 16 top codes, a conditional PixelCNN 64 bottom codes, and the decoder turns them into an image.image32×32×3bottom encoder÷4 → 8×8top encoder÷2 → 4×4quantize top4×4 codes of 512top decoder4×4 → 8×8quantize bottom8×8 codes of 512decodertop ↑ + bottomreconstruction32×32×3PixelCNN (top)16 codes, one by oneconditional PixelCNN64 bottom codesdecodera new imagetraininggeneration
Top: the training path for 32×32 CIFAR-10 images. The bottom encoder shrinks the image fourfold, the top encoder twofold more. The 4×4 top map is quantized first; its decoded version, together with the bottom encoder features, determines the 8×8 bottom map. The decoder receives the upsampled top codes and the bottom codes. Bottom: generation. A PixelCNN samples the top codes one by one, a conditional PixelCNN that sees them samples the bottom codes, and the decoder turns the pair of maps into an image. Both maps are indices into codebooks of 512 vectors of dimension 64.

How many bits#

The figure shows a small version for 32×3232 \times 32 CIFAR-10 images: a 4×44 \times 4 top grid and an 8×88 \times 8 bottom grid, 512 codes each. An image is 32⋅32⋅3=307232 \cdot 32 \cdot 3 = 3072 bytes, or 24,576 bits. Its code is 16+64=8016 + 64 = 80 indices of log⁡2512=9\log_2 512 = 9 bits, or 720 bits, about 34 times fewer. Sampling cost scales the same way: an autoregressive model over raw subpixels needs 3072 sequential steps per image, the two priors need 16+64=8016 + 64 = 80. At the paper’s 256×256256 \times 256 scale the gap is 196,608196{,}608 subpixels against 322+642=512032^2 + 64^2 = 5120 codes.

VAPNEV: a flow likelihood instead of pixel-wise reconstruction#

Optional depth: a flow decoder with an exact likelihood, and its conditional version. The rest of the note does not depend on it.

The changes above leave the decoder’s likelihood alone. With a factorized Gaussian decoder, −log⁡pθ(x∣z)-\log p_\theta(x \mid z) is a squared error summed over pixels, and the best decoder output for a code is the average of all images that fit it: the blur of the VAE. VAPNEV (Agrawal and Dukkipati, 2016), an anagram of VAE-NVP, keeps the Gaussian code and the ELBO and replaces this term by an exact likelihood computed with a real NVP flow (Dinh, Sohl-Dickstein and Bengio, 2017) that is conditioned on the code. Flows are treated in full in the normalizing flows note later in the course; this section needs only the change-of-variables formula and the coupling layer, both restated here.

Notation. y∈RDy \in \mathbb R^D is an intermediate variable of the same size as the image. For every code zz, fz:y↦xf_z: y \mapsto x is an invertible map, a flow written in the course’s latent-to-data direction, with inverse fz−1:x↦yf_z^{-1}: x \mapsto y. Agrawal and Dukkipati write the map in the data-to-latent direction.

The decoder likelihood as a change of variables#

The decoder network does not output an image. It outputs the mean and the variances of a Gaussian over yy, and the flow turns yy into the image:

y∣z∼N(μθ(z),σθ2(z)),x=fz(y).y \mid z \sim \mathcal N\big(\mu_\theta(z), \sigma_\theta^2(z)\big), \qquad x = f_z(y).

By the change-of-variables formula, the likelihood of an image is exact (Section 3.1, Eqs. 10–11):

log⁡pθ(x∣z)=log⁡N(fz−1(x); μθ(z),σθ2(z))+log⁡∣det⁡∂fz−1(x)∂x∣.\begin{aligned} \log p_\theta(x \mid z) ={}& \log\mathcal N\big(f_z^{-1}(x);\, \mu_\theta(z), \sigma_\theta^2(z)\big) \\ &+ \log\left|\det\frac{\partial f_z^{-1}(x)}{\partial x}\right| . \end{aligned}

The ELBO keeps its form, with this term in place of the squared error:

L(x)=Eqφ(z∣x)[log⁡N(fz−1(x); μθ(z),σθ2(z))+log⁡∣det⁡∂fz−1(x)∂x∣]−DKL(qφ(z∣x) ∥ p(z)).\begin{aligned} \mathcal L(x) ={}& \mathbb E_{q_\varphi(z \mid x)}\Big[\log\mathcal N\big(f_z^{-1}(x);\, \mu_\theta(z), \sigma_\theta^2(z)\big) \\ &\qquad + \log\left|\det\frac{\partial f_z^{-1}(x)}{\partial x}\right|\Big] \\ &- D_{\mathrm{KL}}\big(q_\varphi(z \mid x)\,\|\,p(z)\big). \end{aligned}

The Gaussian now lives in the space of yy, not of pixels. The flow mixes pixels, so the model can represent dependencies between pixels for a given code, which a factorized Gaussian decoder cannot: it treats them as independent noise around one mean image. With fzf_z the identity, the model is the ordinary VAE with a Gaussian decoder of learned variances. The formula also holds when the flow ignores zz; the code then acts only through μθ\mu_\theta and σθ\sigma_\theta (Section 3.1).

Conditional coupling layers#

The inverse map fz−1f_z^{-1} is a stack of conditional coupling layers (Section 3.2). As in an affine coupling layer, the input of a layer is split into two parts xax_a and xbx_b; the first passes unchanged, and the second is scaled and shifted by functions of the first. Here those functions also see the code (Eqs. 12–13):

ya=xa,yb=xb⊙exp⁡(sz(xa))+tz(xa).y_a = x_a, \qquad y_b = x_b \odot \exp\big(s_z(x_a)\big) + t_z(x_a).

For a fixed zz the Jacobian is still triangular, with log⁡∣det⁡∣=∑isz(xa)i\log\lvert\det\rvert = \sum_i s_z(x_a)_i, and the inverse is xb=(yb−tz(ya))⊙exp⁡(−sz(ya))x_b = \big(y_b - t_z(y_a)\big) \odot \exp\big(-s_z(y_a)\big) (Eqs. 14–15). Inverting needs the code, and the code is always known: from the encoder during training and from the prior during generation.

The scale combines a network s1s_1 of the unchanged part (two residual blocks in the paper) with a small transposed-convolution network s2s_2 that turns the low-dimensional code into a map of the same shape (Eq. 16):

sz(xa)=κ⊙s1(xa)⊙s2(z)+β1⊙s1(xa)+β2⊙s2(z)+b.\begin{aligned} s_z(x_a) ={}& \kappa \odot s_1(x_a) \odot s_2(z) + \beta_1 \odot s_1(x_a) \\ &+ \beta_2 \odot s_2(z) + b . \end{aligned}

The vectors κ\kappa, β1\beta_1, β2\beta_2 and bb are learned per channel and broadcast over positions, and the shift tzt_z is built the same way from its own pair of networks. The product term lets the code switch features of xax_a on and off, and the direct term gives every layer a shortcut to the code. The authors credit these shortcuts with strong conditioning and with good results from a flow with fewer layers.

Worked example: one exact likelihood evaluation#

A toy case with D=2D = 2 and a scalar code z=0.5z = 0.5. One conditional coupling layer uses sz(xa)=xazs_z(x_a) = x_a z and tz(xa)=xa−zt_z(x_a) = x_a - z, and the decoder outputs μθ(z)=(z,2z)=(0.5,1.0)\mu_\theta(z) = (z, 2z) = (0.5, 1.0) and σθ=(1,0.5)\sigma_\theta = (1, 0.5). Take the image x=(0.4,1.0)x = (0.4, 1.0).

  1. Map to yy. ya=0.4y_a = 0.4. The layer computes s=0.4⋅0.5=0.2s = 0.4 \cdot 0.5 = 0.2 and t=0.4−0.5=−0.1t = 0.4 - 0.5 = -0.1, so yb=1.0⋅e0.2−0.1=1.1214y_b = 1.0 \cdot e^{0.2} - 0.1 = 1.1214.
  2. Gaussian term. log⁡N(0.4; 0.5,12)+log⁡N(1.1214; 1.0,0.52)=−0.9239−0.2553=−1.1792\log\mathcal N(0.4;\, 0.5, 1^2) + \log\mathcal N(1.1214;\, 1.0, 0.5^2) = -0.9239 - 0.2553 = -1.1792.
  3. Log-determinant. s=0.2s = 0.2: the layer stretches the xbx_b direction by e0.2e^{0.2}, so the density of xx is e0.2e^{0.2} times the density of yy.
  4. Total. log⁡pθ(x∣z)=−1.1792+0.2=−0.9792\log p_\theta(x \mid z) = -1.1792 + 0.2 = -0.9792 nats.

Going back, xb=(1.1214+0.1) e−0.2=1.0x_b = (1.1214 + 0.1)\, e^{-0.2} = 1.0: the layer is inverted exactly once zz is known.

Training, sampling and results#

  • Training. The model maximizes the ELBO with Adam. The authors observed the KL term going to zero early in training, the posterior collapse of a decoder strong enough to model the images without the code, and countered it with the KL annealing of Bowman et al. (2016), Section 3.1: a weight on the KL term that starts at zero and grows to one during training (Section 3.3).
  • Continuous data. A flow needs continuous inputs. The 8-bit images are dequantized with uniform noise (see the discrete-data callout), scaled to [0,1][0, 1] and mapped by x′=logit⁡(α+(1−α) x)x' = \operatorname{logit}\big(\alpha + (1 - \alpha)\,x\big) with α=0.05\alpha = 0.05, and the bound is corrected by the log-Jacobian of this preprocessing so that it refers to the images themselves (Section 4.1). How flows are applied to images is covered in flow architectures.
  • Sampling. Draw z∼N(0,I)z \sim \mathcal N(0, I), then y∼N(μθ(z),σθ2(z))y \sim \mathcal N(\mu_\theta(z), \sigma_\theta^2(z)), and return x=fz(y)x = f_z(y) (Section 3.4). A VAE’s decoder is a distribution too, but its samples for one code differ only by independent pixel noise, so usually only its mean is shown. Here the noise in yy passes through the flow, which mixes pixels, so one code gives different images; y=μθ(z)y = \mu_\theta(z) gives one image per code. Reconstruction does the same with zz from the encoder (Section 3.5).
  • Architecture (Section 4.2). An 8-layer convolutional encoder and an 8-layer transposed-convolution decoder, a 256-dimensional code, and a multi-scale real NVP with 2 scales. Each scale has 3 conditional coupling layers with checkerboard masks and 3 with channel-wise masks, with 64 filters in the residual blocks of the first scale and 128 in the second.

Test results in bits per dimension (Tables 1–2; lower is better, and << marks an upper bound from an ELBO):

ModelCIFAR-10CelebA
PixelRNN3.00—
VAE with inverse autoregressive flow<3.28< 3.28—
Real NVP3.493.02
Convolutional DRAW<3.59< 3.59—
VAPNEV<3.55< 3.55<2.8< 2.8

On CIFAR-10 a VAE with one stochastic layer and this likelihood is roughly level with real NVP, which uses 8 residual blocks per coupling layer against 2, and its bound is slightly below that of convolutional DRAW, a VAE with several stochastic layers and recurrence. It stays behind autoregressive models and behind a VAE with a flow posterior. On CelebA it beats real NVP with 2 scales instead of 4 (Section 4.4). The reconstructions keep high-level content such as pose, background colour, hair colour and expression (Figures 3–4). The bits per dimension are those of the autoregressive models note.

Conditional VAPNEV#

Agrawal and Dukkipati suggest conditional density modelling as an extension but do not implement it (Section 5). The construction is that of the conditional VAE. For an image xx with a condition cc, for CelebA its 40 binary attributes, condition the encoder, qφ(z∣x,c)q_\varphi(z \mid x, c), the decoder’s Gaussian, N(μθ(z,c),σθ2(z,c))\mathcal N\big(\mu_\theta(z, c), \sigma_\theta^2(z, c)\big), and the coupling layers, whose code branch s2s_2 (and its shift counterpart) receives zz and cc together. Write the resulting flow fz,cf_{z,c} and keep the prior p(z)=N(0,I)p(z) = \mathcal N(0, I). The bound becomes

log⁡pθ(x∣c)≥Eqφ(z∣x,c)[log⁡N(fz,c−1(x); μθ(z,c),σθ2(z,c))+log⁡∣det⁡∂fz,c−1(x)∂x∣]−DKL(qφ(z∣x,c) ∥ p(z)).\begin{aligned} \log p_\theta(x \mid c) \ge{}& \mathbb E_{q_\varphi(z \mid x, c)}\Big[\log\mathcal N\big(f_{z,c}^{-1}(x);\, \mu_\theta(z, c), \sigma_\theta^2(z, c)\big) \\ &\qquad + \log\left|\det\frac{\partial f_{z,c}^{-1}(x)}{\partial x}\right|\Big] \\ &- D_{\mathrm{KL}}\big(q_\varphi(z \mid x, c)\,\|\,p(z)\big). \end{aligned}

Sampling fixes the attributes, draws zz from the prior, draws yy from the decoder’s Gaussian N(μθ(z,c),σθ2(z,c))\mathcal N\big(\mu_\theta(z, c), \sigma_\theta^2(z, c)\big) and returns x=fz,c(y)x = f_{z,c}(y). Changing one attribute while keeping zz asks for the same face with that attribute changed, to the extent that the code has not absorbed the attribute itself.

What changed#

VAEβ-VAEVQ-VAE / VQ-VAE-2VAPNEV
Codecontinuous, Gaussiancontinuous, Gaussiangrid of indices into a codebookcontinuous, Gaussian
ObjectiveELBOreconstruction − β · KLreconstruction + codebook + commitmentELBO with an exact flow likelihood
Role of the priorfixed N(0,I)\mathcal N(0, I), enforced by the KLthe same, with weight β\betauniform during training; learned afterwards by an autoregressive modelfixed N(0,I)\mathcal N(0, I), enforced by the KL
Gradient through the codereparameterizationreparameterizationstraight-through copyreparameterization
Samplingdecode z∼N(0,I)z \sim \mathcal N(0, I)the samesample codes autoregressively, then decodedecode zz to a Gaussian over yy, sample yy, apply the flow
Typical troubleblur, prior holesthe rate–distortion trade-off itselfdead codes, slow sequential priorKL collapse without annealing, a costly full-resolution decoder

Limitations#

  • β moves along a trade-off; it does not escape it. Lower distortion costs rate. Rate is mostly information about the image, not necessarily a mismatch with the prior; poor prior samples come from the aggregate posterior leaving the prior, which a small β\beta penalizes less. Disentanglement is a possible side effect, not a property of the objective.
  • The straight-through gradient is a surrogate. It uses an identity Jacobian where the quantizer’s true derivative is zero, so it is never the exact gradient; the commitment term keeps zez_e near its codebook vector, which makes the substitution reasonable, not exact.
  • Codebook collapse. Without restarts or a normalized lookup, a large share of the codes can go unused.
  • Two-stage training. The prior is fitted to codes of a frozen autoencoder; errors of the first stage, such as a code grid that is hard to predict, cannot be fixed by the second.
  • A flow decoder is strong and expensive. VAPNEV’s decoder can model the images without the code, so the KL term collapses unless it is annealed, and its flow works at full image resolution, which costs far more than a transposed-convolution decoder.
  • Sequential sampling. The autoregressive prior samples one index at a time. Smaller than pixels, the grid is still sequential; later work replaces the prior by transformers over the same codes or by diffusion in a continuous latent space (latent diffusion).

Summary#

  • β-VAE scales the KL term by β\beta and moves the model along the rate–distortion curve: β>1\beta > 1 gives a lower rate and worse reconstructions, β<1\beta < 1 the opposite. β=1\beta = 1 recovers the standard ELBO, β>1\beta > 1 maximizes a looser lower bound, and for β<1\beta < 1 the objective need not bound the likelihood.
  • VQ-VAE replaces the Gaussian code by the nearest codebook vector. The KL becomes a constant, the argmin is crossed by the straight-through estimator, and the loss adds codebook and commitment terms, or an EMA update that makes the codebook an online k-means.
  • The prior is learned after the autoencoder by an autoregressive model over the code grid. VQ-VAE-2 uses two grids, a coarse one for layout and a fine one for detail, and a prior for each.
  • VAPNEV keeps the Gaussian code and the ELBO and replaces the pixel-wise reconstruction by the exact likelihood of a real NVP flow whose base Gaussian and coupling layers depend on the code. It needs KL annealing to keep the code in use. Its conditional version adds a label to the encoder, the decoder and the coupling layers.

Notebook#

The VQ-VAE part follows the VQ-VAE-2 notebook of the HSE-LAMBDA Deep Generative Models repository (cell numbers count every cell from 1). The notebook has no saved outputs, so it documents the procedure rather than results.

  • Cell 6: Quantize computes squared distances to all 512 codebook vectors at once with the expansion ∥a−e∥2=∥a∥2−2a⊤e+∥e∥2\lVert a - e\rVert^2 = \lVert a\rVert^2 - 2a^\top e + \lVert e\rVert^2, a single matrix product, picks the nearest, updates the codebook with the EMA above (decay 0.99), returns the commitment distance diff = mean((quantize.detach() - input)²) and applies the straight-through estimator input + (quantize - input).detach(). The codebook is a buffer drawn from a standard normal, not a parameter, so Adam never touches it; it moves only through the EMA, and only in training mode. The counts are smoothed as Nk←Nk+ϵn+Kϵ nN_k \leftarrow \frac{N_k + \epsilon}{n + K\epsilon}\, n with n=∑kNkn = \sum_k N_k and ϵ=10−5\epsilon = 10^{-5}, which keeps their total and makes every count positive. One issue: the counts start at 00 while the sums mkm_k start at the random codebook. After the first update, a code that the first batch did not select is therefore divided by a smoothed count of about ϵ\epsilon, and its norm grows about 10510^5 times. It shrinks back only as 0.99t0.99^t, which takes about ln⁡105/−ln⁡0.99≈1150\ln 10^5 / {-\ln 0.99} \approx 1150 steps. In our own toy run of this update with standard-normal encoder outputs (not a notebook output), only 2 to 3 of the 512 codes were selected between steps 2 and 1000. Starting the counts at 11, so that the first quotient mk/Nkm_k / N_k is the random codebook itself, avoids the jump.
  • Cells 7–10: architecture. ResBlock is ReLU, a 3×33 \times 3 convolution from 128 to 32 channels, ReLU and a 1×11 \times 1 convolution back to 128, added to its input. The bottom encoder applies two 4×44 \times 4 stride-2 convolutions and a 3×33 \times 3 convolution, the top encoder one 4×44 \times 4 stride-2 convolution and a 3×33 \times 3 convolution, each followed by residual blocks; the decoders mirror this with a 3×33 \times 3 convolution, residual blocks and 4×44 \times 4 stride-2 transposed convolutions. The settings are channel=128, n_res_block=2, n_res_channel=32, and codebooks of 512 vectors of dimension 64. The bottom encoder downsamples by 4 (to 8×88 \times 8 for CIFAR-10), the top encoder by 2 more (to 4×44 \times 4), and 1×11 \times 1 convolutions project the features to the 64-dimensional code vectors before quantization. The top code reaches the bottom level along two separate paths: dec_t, a small decoder, brings it back to 8×88 \times 8 to be concatenated with the bottom features and quantized as the bottom code, while upsample_t, a single transposed convolution, enlarges it for the final decoder, which receives it together with the bottom code.
  • Cell 12: training minimizes the mean squared reconstruction error plus 0.25⋅0.25 \cdot diff, the commitment term; there is no codebook term because the EMA replaces it. Every sample_interval steps (200 in cell 20) it saves a grid of the batch above its reconstructions, computed in evaluation mode.
  • Cells 13 and 22: infer_vqvae reconstructs two batches of 64 CIFAR-10 test images in evaluation mode and saves the 128 reconstructions to a file.
  • Cells 14–20: CIFAR-10 at 32×3232 \times 32 normalized to [−1,1][-1, 1] (the comment in cell 15 still says 64×6464 \times 64), batch size 32, Adam at 3⋅10−43 \cdot 10^{-4}, five epochs.
  • Cells 25–27: the priors. Masked convolutions of types A and B, and two PixelCNN priors with seven 7×77 \times 7 masked layers of 64 channels and plain ReLUs between them, no gating. The input is an embedding of the code indices, Embedding(512, 64), and a 1×11 \times 1 convolution gives 512 logits per position. The unconditional prior models the top codes. The conditional one models the bottom codes: it embeds the nearest-neighbour upsampled top codes with Embedding(512, 16), concatenates them with the embedding of the bottom codes and mixes the two with a 1×11 \times 1 convolution. Two issues. This plain stack has the blind spot and lacks the gated layers and the attention of the paper’s priors. And because the condition is mixed into the same channels before the first type-A masked layer, the mask also hides the condition at the position being predicted. Each bottom index sees the top codes only through earlier positions, so the top-left index of every 2×22 \times 2 block, whose top code appears at no earlier position, is predicted without it. We checked this by differentiating a re-implementation of the network: the logits at a position have zero gradient with respect to the condition at that position. The condition should enter without a mask, added in every layer as in the conditional Gated PixelCNN.
  • Cells 29–32: datasets that encode every image on the fly into its code grids, and cross-entropy training of the two priors with Adam at learning rate 10−310^{-3}, batch size 32 and 10 epochs each. Encoding should run with the VQ-VAE in evaluation mode, which cell 22 leaves it in; in training mode the quantizer would keep updating its codebook while the codes are being extracted.
  • Cells 34–35: sampling: 16 sequential steps for the top grid, 64 for the bottom grid given the upsampled top, and decoding. Each step reruns the PixelCNN on the whole grid.
  • Implementation note. utils.save_image(..., range=(-1, 1)) in cells 12, 22 and 35 uses the argument name that torchvision renamed to value_range; with current versions these calls need the new name.

The β-VAE has no trained example in the course notebooks: the VAE notebook defines the β-weighted loss in cell 24 but trains only with β=1\beta = 1.

VAPNEV has no implementation in the course repository. The exercise notebook 03_hw_vapnev.ipynb of the same repository states the tasks on CelebA and leaves the code cells empty. Its only saved outputs are the device (mps), the shape of one image, 3×64×643 \times 64 \times 64, and a grid of 25 random faces.

  • Cells 3–9: data. CelebA through the course’s dataset class, with Resize(64) and CenterCrop(64), which keep the aspect ratio, and pixels mapped from [0,1][0, 1] to [−1,1][-1, 1] by 2x−12x - 1.
  • Cells 10–11: a normalizing flow on these faces, evaluated with FID and the negative log-likelihood. Any layers are allowed, coupling, autoregressive or linear, either convolutional or on the flattened image; the layers are described in flow architectures. A likelihood quoted for images must account for the dequantization and for the Jacobian of the preprocessing, as Agrawal and Dukkipati do for their logit transform.
  • Cells 12–13: a VAE on the same faces, evaluated with FID, as in the VAE notebook.
  • Cells 14–15: VAPNEV, following the paper, and a conditional VAPNEV. The notebook leaves the details of the condition to the task description; the natural choice is the 40 CelebA attributes, which the course’s dataset class returns with every image and the wrapper of cell 6 discards.
  • Cells 16–17: an analysis of the latent spaces: which model interpolates better, encoding a face from outside CelebA and finding the nearest codes of training images, and the most interesting sample.

Next#

The VAE family trains its generator through a likelihood bound, with or without a discrete code, and pays for the bound with blur, with a separate prior or with a costly flow decoder. The next note takes the opposite route: a generator trained without any likelihood, judged only by a second network that tries to tell its samples from real data.

References#