Key ideas
- An autoencoder has an encoder that maps an input to a code (latent vector) and a decoder that maps it back, . Training makes close to (e.g. MSE), so each input is its own target and no labels are needed: autoencoders learn from unlabeled data, in a setting called unsupervised or self-supervised1. The reconstruction is lossy, an approximation of the input.
- Reconstruction alone can be useless: with a code at least as large as the input and no other constraint, the network can simply learn the identity2. The standard ways out are an undercomplete bottleneck (), a sparse code (more units than inputs, but only a few active per input) and denoising1,2.
- A denoising autoencoder corrupts each input with a random process (Gaussian noise, masking), encodes and scores the output against the clean ; a fresh corruption is drawn every time an example is presented2.
- Linear autoencoder ≈ PCA. With no nonlinearity and squared error, code units span the same subspace as the top principal components, but the learned weight vectors need not be orthonormal or ordered like the principal axes1,2. The smallest achievable error is the variance along the discarded principal directions.
- Convolutional autoencoders shrink the image with strided convolutions or pooling and grow it back with transposed convolutions (
nn.ConvTranspose2d). A transposed convolution can be seen as the gradient of a convolution with respect to its input; it restores the shape, not the values, and is not an inverse5. When the kernel size is not divisible by the stride, outputs overlap unevenly and show checkerboard artifacts; nearest-neighbour resizing followed by an ordinary convolution avoids them6. - A plain autoencoder is not a generator: nothing forces its codes to follow , so most random Gaussian codes land where the decoder was never trained.
- A variational autoencoder (VAE) lets the encoder output a distribution and trains it together with the decoder by maximising the ELBO: a reconstruction term minus a KL term that pulls toward the prior 3. Because the codes then fill the prior, decoding generates new data. The loss has two parts, reconstruction and KL; there is no adversarial term.
- Reparameterization trick: draw and set . The randomness moves into , so is a differentiable function of the encoder parameters and backpropagation reaches the encoder; the naive Monte Carlo gradient estimator would have very high variance3. A new is drawn at every step.
- β-VAE multiplies the KL term by . is the ordinary VAE; usually gives more disentangled latent factors but worse reconstructions, because less information passes through the latent bottleneck4.
Formulas
The ELBO and its gap to the log-likelihood3:
KL between a diagonal Gaussian and , in closed form because both are Gaussian3:
With logvar this is -0.5 * sum(1 + logvar - mu**2 - logvar.exp()), and = exp(0.5 * logvar).
- Gaussian decoder with unit variance: , so maximising it is minimising squared error, and pixels are independent given .
- β-VAE: 4.
nn.Linear(n_in, n_out)has parameters, e.g. has .- Transposed convolution (dilation 1): 5; ordinary convolution: .
Worked example
An encoder outputs and for one image. KL to the prior, per dimension:
- dimension 1: , paid only for the shifted mean;
- dimension 2: , paid only for the narrowed variance.
Total nats. A dimension with and costs nothing but also carries no information about ; when every dimension ends up like that, the code is useless (posterior collapse).
In code
import torch
from torch import nn
enc = nn.Sequential(nn.Conv2d(3, 8, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(8, 4, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2))
dec = nn.Sequential(nn.ConvTranspose2d(4, 8, 2, stride=2), nn.ReLU(), # kernel = stride:
nn.ConvTranspose2d(8, 3, 2, stride=2), nn.Sigmoid()) # no uneven overlap
x = torch.rand(16, 3, 32, 32)
code = enc(x)
print(code.shape, code[0].numel()) # torch.Size([16, 4, 8, 8]) 256
print(dec(code).shape) # torch.Size([16, 3, 32, 32])
mu, logvar = torch.tensor([0.6, 0.0]), torch.log(torch.tensor([1.0, 0.5]))
z = mu + torch.exp(0.5 * logvar) * torch.randn(2) # reparameterization
kl = -0.5 * torch.sum(1 + logvar - mu**2 - logvar.exp())
print(round(kl.item(), 4)) # 0.2766
Common pitfalls
- Using the noisy image as both input and target teaches the network to copy the noise; a denoising autoencoder needs noisy inputs and clean targets2.
- More code units, or a cross-entropy instead of a squared-error loss, do not stop the identity solution; a bottleneck, a sparsity penalty or input corruption does2.
ConvTranspose2dis not the inverse ofConv2d: its weights are learned separately and it only maps back to the larger shape5.- A linear autoencoder finds the PCA subspace, not the ordered, orthogonal principal axes; its best output is the projection onto that subspace, so it matches PCA's reconstruction error and cannot beat it1.
- Decoding random codes with a plain autoencoder does not give realistic samples; the VAE's KL term is what ties the codes to the prior.
- The reparameterization trick exists for the encoder's gradient (), not the decoder's, and it is not what makes the KL term closed-form; that comes from both distributions being Gaussian3.
logvarstores : the standard deviation isexp(0.5 * logvar), and plugging where the formula wants gives a wrong KL.- Raising β trades reconstruction quality for disentanglement; it does not improve both4.
References
- Wikipedia: Autoencoder — Lead section; Mathematical principles › Interpretation (undercomplete vs overcomplete); Variations › Sparse autoencoder (SAE), Denoising autoencoder (DAE); History; Applications › Dimensionality reduction › Principal component analysis; Applications › Anomaly detection
- Vincent et al. (2010), Stacked Denoising Autoencoders, JMLR 11 — Sec. 2.3 Merely Retaining Information is Not Enough; Sec. 3.1 The Denoising Autoencoder Algorithm
- Kingma & Welling (2014), Auto-Encoding Variational Bayes, arXiv:1312.6114 — Sec. 2.2 The variational bound; Sec. 2.4 The reparameterization trick; Sec. 3 Example: Variational Auto-Encoder; Appendix B
- Burgess et al. (2018), Understanding disentangling in β-VAE, arXiv:1804.03599 — Sec. 3 β-VAE
- PyTorch documentation: torch.nn.ConvTranspose2d — Class description; Shape
- Odena, Dumoulin & Olah (2016), Deconvolution and Checkerboard Artifacts, Distill — Deconvolution & Overlap; Better Upsampling