Discrete Latent Spaces and Generative Adversarial Networks
Prerequisite Knowledge
This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.
Previously Covered in This Subject
- Variational Autoencoders — covered in Lecture 9
- Entropy and KL Divergence — covered in Lecture 9
- Beta-VAE: Disentangled Representations — covered in Lecture 9
- VQ-VAE: Vector-Quantized Variational Autoencoder — covered in Lecture 9
- PixelCNN and Gated PixelCNN — covered in Lecture 5
- WaveNet: Dilated Causal Convolutions for Audio — covered in Lecture 5
- The Decoder Path and Transpose Convolution — covered in Lecture 3
- Generator Versus Discriminator: A First Look at GANs — covered in Lecture 1
This session closes the discrete-latent branch of variational autoencoders — VQ-VAE and its hierarchical successor VQ-VAE-2 — and then opens a completely new family of generative models: generative adversarial networks (GANs). GANs matter because they break the pattern every earlier method followed: instead of writing down and maximizing a probability distribution, they learn to generate through an implicit contest between two networks. We build the original 2014 formulation piece by piece, read its famous minimax objective term by term, walk its training loop step by step, and finish with the two scores — the Inception Score and the Fréchet Inception Distance — used in practice to judge what such models produce.
Here is the road map for the session:
- Recap and motivation (10.1–10.2). A quick refresher on the standard VAE and beta-VAE, and why categorical data calls for a discrete latent space.
- VQ-VAE (10.3–10.4). The vector-quantized VAE: a codebook of discrete codes, a three-piece loss, the stop-gradient trick that makes it trainable, and how a PixelCNN prior over codes unlocks sampling.
- VQ-VAE-2 (10.5). The hierarchical version that generates noticeably sharper images by separating coarse structure from fine detail.
- GANs (10.6–10.8). Implicit generative modeling: generator versus discriminator, the minimax objective, the training loop, and the non-saturating trick.
- Evaluation (10.9–10.10). How to score generated images with the Inception Score and the Fréchet Inception Distance — and why you should always read them together.
10.1 Recap of Variational Autoencoders and Why Discrete Latent Spaces Matter
Hook: Every generative model we have met so far stores its "ideas" about data as smooth, continuous coordinates. But look around you: most human descriptions of images are categories — indoor or outdoor, day or night, male or female. Should the model's internal representation not match that?
10.1.1 How the Standard VAE Works and Generates
Recall from the previous session how a variational autoencoder (VAE) works. The original formulation assumes the latent space is continuous: each latent coordinate can take any real value, and nearby values decode to similar-looking data.
Given an input, we build an autoencoder with a variational regularizer in place so that the encoder does not output the inputs as-is; it learns the parameters of an underlying distribution over the latent representation. Concretely, the encoder outputs two things per input:
- (mu) — the mean vector, the "center point" of where this image sits in latent space;
- (sigma) — the covariance matrix, which describes how spread out that placement is.
The variational regularizer then forces the distribution the encoder learns to stay very close to a standard Gaussian prior in the latent space: zero mean and unit covariance, with ones on all diagonal entries. During training, the deviation of the learned distributions from this standard normal is minimized by adjusting the parameters of the encoder. In the objective this regularizer appears as the Kullback–Leibler (KL) divergence term between the encoder distribution and the prior:
Here is a training input, is the latent vector, is the encoder's approximate posterior (the Gaussian whose mean and covariance the encoder predicts), and is the decoder's likelihood of the data given a latent code. Minimizing the first term asks the decoder to reconstruct the input faithfully; minimizing the second keeps every encoded distribution close to the standard normal. This is exactly the evidence lower bound (ELBO) machinery covered earlier — here we only need the shape of it, not the full derivation.
Once training is over, generation is simple: sample a latent vector from the standard normal prior, push the sampled values through the decoder, and semantically meaningful new samples come out. That is the basic principle of the standard VAE.
Tiny generation walkthrough. Suppose the latent space is two-dimensional and training has finished. Draw from . Feed it to the decoder; the decoder outputs a face image. Draw again: gives a different face. Nothing about either draw came from a specific training photo — both came from the learned prior. The decoder has learned what "a plausible point of the data manifold" looks like for every neighborhood of latent space.
One assumption deserves attention before we move on: continuity itself.
Scope: The standard VAE assumes latent codes should vary smoothly — nudge slightly and the decoded image changes slightly. This is ideal for interpolating between samples, but it is a poor fit when the underlying factors of variation are genuinely categorical: there is no meaningful "halfway point" between indoor and outdoor, and forcing one into a continuous axis wastes capacity and muddies interpretation. If your data is naturally described by discrete labels, a discrete latent space is the more honest choice — that is the gap VQ-VAE fills.
10.1.2 Categorical Descriptions Call for a Discrete Latent Space
So here is the question that motivates this topic: should we restrict all VAE discussion to continuous latent spaces? In many scenarios you can associate discrete labels with training images — these labels are descriptions of the data. Examples:
- whether an image was taken indoors or outdoors;
- whether it includes mechanical objects or face images;
- for an image of a person: male or female, facing the camera or not.
All of these are categorical pieces of information about the image. Given that data so often carries such discrete descriptions, it makes sense that the latent space itself should be representable using discrete concepts. A picture is then summarized by a short list of tokens — much like how a caption summarizes a scene in words — instead of a long list of decimal numbers.
That idea produces variants of the original VAE known as VQ-VAE and VQ-VAE-2, which is where we pick up. The plan: keep the encoder–decoder skeleton of the VAE, but replace the "sample a Gaussian" middle with "look up the nearest entry in a learned dictionary of codes."
Bridge: Standard VAE = continuous latent space, trained by pulling encoder distributions toward a Gaussian prior. The rest of the discrete-latent branch asks: what happens when we swap those smooth coordinates for a finite set of learned code vectors? First, a one-stop refresher on beta-VAE, the variant built for disentangled editing.
10.2 A Quick Word on Beta-VAE Before Moving On
Hook: Imagine a photo-editing app with separate sliders for "smile", "age", and "skin tone". Turn up "smile" — only the smile changes. Real VAE latent spaces rarely behave this way: one coordinate usually mixes several attributes. Beta-VAE is the fix attempt.
10.2.1 Editing One Factor While Freezing the Rest
Beta-VAE is another variant of the original VAE, already covered adequately earlier, so only the essential idea is repeated here. It targets disentangled feature spaces: when you modify images along one factor, the other factors must stay put.
Suppose you want to edit a facial image — change a neutral expression into a very happy one — without inadvertently changing other attributes like the age of the individual or the skin tone. In an entangled space, moving along any single latent direction tends to rotate several attributes at once, so "make happier" also quietly makes the face older or lighter. Beta-VAE achieves the clean-slider behavior by adding extra weights to the KL divergence term of the VAE objective:
The symbols are the same as in Section 10.1; the only new object is (beta), a constant that scales how strongly each encoded distribution is pushed toward the standard normal. With you recover the plain VAE loss. Raising squeezes the posterior distributions harder toward a sphere of independent, unit-variance axes — and strongly oriented axes are exactly what makes individual coordinates correspond to individual, interpretable factors rather than entangled diagonals.
A useful mental model: think of the ideal latent space as a mixing desk with one slider per attribute. Turning the "expression" slider up should move the image along the happy axis and touch nothing else. Beta-VAE's heavier regularization is a way of demanding that the learned axes line up with those sliders. The analogy breaks where real attributes are correlated in the data itself — if smiling people in your dataset happen to be younger on average, no axis arrangement can fully separate the two.
Pitfall: The extra pressure is not free. Push too high and the reconstruction term gets starved: decoded images turn blurry because the bottleneck spends its capacity obeying the prior instead of preserving detail. Beta-VAE trades some reconstruction sharpness for interpretable structure — pick by watching both terms.
Keep this "edit one factor, freeze the rest" picture in mind; it is the same desire for interpretable structure that drives the discrete-latent work next.
Bridge: Beta-VAE reshapes a continuous latent space so each axis means one thing. Next, VQ-VAE takes the bolder step of throwing away continuity altogether and keeping only a finite dictionary of codes.
10.3 VQ-VAE: Vector-Quantized Variational Autoencoder
Hook: What if we forced every latent code to be chosen from a finite menu? No more smooth coordinates — just a lookup table of learned prototype vectors. Reconstruction becomes "find me the closest menu item," and generation becomes "pick a plausible sequence of menu items." That single change turns a VAE into a VQ-VAE.
10.3.1 From Image to Feature Grid
The starting point of VQ-VAE (the VQ stands for vector quantized) is ordinary convolutional encoding — exactly the kind of encoder you already know from CNNs. During encoding, the original image gets broken into blocks, and each block ends up with a high-dimensional feature value attached to it. Instead of the original RGB image, after the encoder has run, the encoded data lives as a grid of feature vectors.
A concrete example with shapes spelled out: start with a RGB image — that is pixels, each with red, green, and blue channels. Encode it with convolutional layers, exactly as in a CNN setting, until the image is represented on a grid where each of those grid cells carries a 128-dimensional feature vector. Each stride-2 downsampling stage halves the spatial size (), while the channel count grows. So the encoder's output is not a single vector but a spatial array of vectors: cells, each holding a vector .
Picture the result as a shrunken, abstract version of the photo: same rough layout, but instead of raw colors, every position stores a 128-number description of "what content lives around here." Everything that follows operates on this array.
10.3.2 The Codebook and Nearest-Neighbor Quantization
Inside the VQ-VAE encoder sits a codebook: a collection of codebook vectors, each of the same dimension as the encoder features — 128 in our running example. Two things stay fixed throughout training: the number of codebook entries and their dimension. What is learned is their content. At initialization you may attach random feature values to each codebook entry.
Quantization then proceeds per grid cell, and it is simply a nearest-neighbor search:
- Take one cell's feature vector .
- Compare it against everything in the codebook using a distance such as squared Euclidean distance.
- Find whichever codebook entry is closest; record that entry's index.
Repeat for every grid point, so each position in the grid now points at some codebook index. Here is the key move: instead of passing the encoder's raw feature maps onward, you pass the corresponding codebook vectors into the decoder. If cell one matched codebook entry 1, cell two matched entry 53, cell three matched entry 2, and so on, the decoder receives the sequence — actual stored codeword vectors, not encoder outputs. These go through the reverse of what happens inside a CNN and produce a reconstructed image.
Worked example — quantizing one cell. To keep the arithmetic visible, use a toy codebook of vectors in two dimensions: , , . One grid cell produces the encoder output . Compare by squared Euclidean distance:
The smallest distance, 0.02, points to entry 1. This cell records the index 1, and the decoder receives rather than . Sense-check: the winner is the prototype sitting nearest to the encoder output in feature space, exactly as intended — the quantized value replaces the raw feature with its closest "vocabulary word."
The reconstructed image is compared against the original data, and a loss drives adjustments of the encoder and decoder parameters so the reconstruction error goes down. But reconstruction alone is not the whole story — the codebooks themselves also get updated during training, which leads directly to the loss function.
10.3.3 The Three-Piece Loss Function
Training a VQ-VAE minimizes a loss made of three distinct pieces. Reconstructed from the description, with the plain-language reading alongside:
Read the symbols first. is the input image. is the encoder output — the unquantized feature vector coming out of the encoding process for a given cell. is the quantized version of that vector: the codebook entry that was selected as its nearest match. denotes the stop-gradient operator, explained below. Finally, is a constant that sets how strictly you want the encoded values to commit to the codebook values. This is the standard formulation of the method: the stop gradients sit exactly where shown — frozen encoder output inside the codebook term, frozen codeword inside the commitment term.
Piece by piece, in the order described:
- Reconstruction term. The decoder models the likelihood of the data given the quantized codes, so the natural objective is to maximize . Since is a probability between 0 and 1, its logarithm is negative; taking the minus turns it into something to minimize. Minimizing is minimizing the reconstruction error.
- Codebook loss. This measures how far each current codebook vector sits from the encoder outputs assigned to it. "Corresponding" means: if entry was the closest codeword for a particular grid cell, the loss for that cell is the difference vector between the third codebook vector and that cell's feature vector. You want to reduce these distances summed over the entire training dataset. As this term shrinks, the codebook contents migrate toward the values the encoder emits — the goal is to make the codebooks very similar to what comes out of the encoder.
- Commitment loss. The two-way partner of the previous term: while codebooks move toward encoder outputs, the encoder must also commit to codebook values. This term is the level of commitment the encoded values show toward the chosen codebook entries. It pulls toward so both sides meet, and emphasizes that you want the commitment to hold quite strictly.
Notice the elegant symmetry: both auxiliary terms measure the same gap between and . They differ only in which side is frozen — and so in which parameters receive gradient updates. That is precisely what the stop-gradient notation encodes, and Section 10.3.4 unpacks it fully.
Worked example — computing the total loss for one cell. Continue the toy numbers from Section 10.3.2: , chosen entry . Let the decoder report a negative log-likelihood of for this cell's reconstruction, and set (a typical magnitude).
Sense-check: both auxiliary terms evaluate the same displacement of 0.02 between encoder output and codeword — they merely route responsibility for shrinking it to different parameter sets. Summing the three pieces gives the scalar that backpropagation minimizes.
Scope: Three assumptions quietly hold this construction together. First, and the code-vector dimension are fixed hyperparameters — capacity cannot grow during training, so a tiny caps how much detail the model can store, and a huge makes lookups slow and leaves entries unused. Second, the loss treats each grid cell independently; correlations between neighboring cells are handled later by the prior model of Section 10.4, not by this loss. Third, the quantizer itself contributes nothing to the gradient — the loss is built so learning happens on either side of the lookup, never through it. Break these conditions (say, by changing mid-training) and the optimization story collapses.
10.3.4 The Non-Differentiable Step and Stop Gradients
Here is the subtle trap in this loop. Somewhere inside it sits an operation that is not differentiable: the comparison-and-pick. You compare a feature vector against all the , identify the index whose content matches best, and pass that particular codebook content to the decoder. Picking the index that gives the minimum is an argmin operation, and backpropagation cannot flow through it. Nobody asked about this, and it is exactly the right question to ask about this training loop.
Why does argmin kill gradients? Look at the toy example again. Nudge from to : the distances reshuffle slightly, yet the winner stays and the decoder input stays exactly . The output did not change at all, so the local rate of change — the derivative — is zero. Only when a nudge grows large enough to flip the winning index does the output jump, and jumps have no well-defined slope either. The quantized output is a step function of the encoder output: flat almost everywhere, discontinuous at decision boundaries. Gradients are the currency of backpropagation, and step functions pay nothing.
The fix is an engineering act built on the stop gradient operator, written . Its meaning: do not let gradient information flow past this point. Because the decoder inputs are only ever codebook contents — never the raw encoder outputs — you compute the loss gradient with respect to the decoder input, , and simply copy that value onto the encoder path:
That is, treat the quantizer as if it were the identity during the backward pass: copy the partial derivative up to that point and then backpropagate as usual into the encoder weights. This is precisely why the notation writes a stop gradient on . The forward pass uses the true quantized values; only the backward pass pretends the lookup never happened.
Worked example — one backward pass through the quantizer. Continue the running numbers. The decoder received , and suppose backpropagation through the decoder delivers the gradient at its input. The honest chain rule would ask: "how does respond to a change in ?" — and the answer is "not at all, until the winner flips," i.e., a useless zero. Instead the straight-through rule substitutes the identity:
- Copy: .
- Backpropagate into the encoder's convolution weights as though the decoder had consumed directly.
- The encoder shifts a little in the direction that would reduce the loss — say to — moving closer to and lowering the commitment term on the next pass.
Sense-check: the update direction is meaningful (toward the assigned codeword) even though the true derivative through the argmin was zero everywhere along the path taken.
The same trick disciplines the two auxiliary terms:
- In the codebook loss, freezes the encoder side — within this term you update only , moving codebook vectors toward the encoder outputs, and you do not touch here.
- In the commitment loss, freezes the codebook — here you update by changing the encoder's parameters, and you deliberately do not change .
Both things happen together: make the codebooks similar to what the encoder produces, and make the encoder outputs stick close to the codebooks. Each stop gradient protects exactly one player from being tugged by the term aimed at the other.
10.3.5 Updating the Codebook: Dictionary Learning
How, mechanically, does a codebook entry improve? Through dictionary learning: collect all the encoder output vectors for which this particular index was the closest match, and move the codebook vector to their mean:
In words: a codebook vector becomes the average of all the encoded vectors that respond to it. Read the subscript carefully — the average runs over exactly those training cells whose nearest entry is , and nobody else. Entries that win no votes stay put (or drift only via other mechanisms), which hints at a practical worry revisited in the pitfalls below.
Worked example — one codebook update. Suppose entry won the assignment for exactly two grid cells in this batch, whose encoder outputs were and . The dictionary-learning rule sets
The prototype slides to sit in the middle of its cluster of fans. Sense-check: after the move, both and sit closer to than before, so the codebook loss for these cells drops.
That completes the picture of VQ-VAE training. A quick cost note rounds out the procedure: the nearest-neighbor scan costs per grid cell per pass (with and, say, entries in realistic setups), multiplied by 1024 cells per image. Exact scans are fine at lecture scale; production systems reach for approximate nearest-neighbor indexes when grows large. Alternatives worth knowing: k-means-style clustering plays the same role offline, and straight-through estimation is the standard substitute whenever a hard choice sits inside an otherwise differentiable network.
Pitfalls:
- Treating the quantizer as a decoder component. The lookup belongs to the encoder path; see the student question below for why.
- Forgetting a stop gradient. Drop the operators and gradients try to flow through the argmin — training stalls or behaves erratically, and neither side of the codebook bargain learns properly.
- Dead codes. An entry that never wins any assignment never receives a dictionary-learning update and may sit unused forever, wasting codebook capacity. Practical fixes include re-initializing dead entries to actual encoder outputs observed in the batch.
- Mixing up the two auxiliary losses. The codebook loss moves prototypes toward encodings; the commitment loss moves encodings toward prototypes. Swapping them reverses which network learns what.
Exam note: Be able to rebuild the three-piece loss from memory — reconstruction , codebook loss, and -weighted commitment loss — and state which parameter set each stop gradient protects: shields the encoder inside the codebook term; shields the codebook inside the commitment term. Expect a question on why the argmin pick blocks backpropagation and how the straight-through copy answers it.
10.3.6 Student Questions and Answers
Q: Could there be a possibility that two input vectors map to the same encoding? A: Of course — that can happen naturally. The more seemingly complex question is the reverse: what if a particular encoded value is closest to multiple codebook vectors at once? There you effectively toss a coin and decide randomly. But notice what it would mean: several codebook vectors are essentially duplicates, which signals a possible problem with the initialization of the codebook vectors. If it still happens and you have no choice, choose randomly among the tied entries — if the distance from the encoder output to is tiny compared to 's being nearly identical too, just pick index 2 or 3 at random.
A second question probed where each piece of machinery lives.
Q: The selection logic — picking the winning codeword — will that sit at the decoder side? Is it configurable? A: No. It is within the encoder. Everything up to and including the vector quantization step belongs to the encoder: in VQ-VAE, "the encoder" means the CNN blocks plus the vector-quantization layer. Only after that point do the codebook vectors hit the decoder and produce an output.
And the sharpest question of the day — the one nobody asked, so it was raised in class:
Q: Somewhere in this loop there are operations that are not differentiable — what exactly is not differentiable here? A: The comparison and picking of the best codebook entry. Identifying the index whose content is closest — an argmin over the codebook — and routing that specific codeword to the decoder is not a differentiable function through which backpropagation can flow. That is exactly what the stop-gradient engineering described above answers.
10.3.7 Applications Beyond Images
Real-world: VQ-VAE has been applied very successfully not only to images but to one-dimensional signals such as audio. It performs well on ImageNet-scale reconstruction, and it is genuinely useful for speech modeling: converting male speech to a female voice or vice versa, changing speech from one male speaker to another male speaker — various forms of voice style transfer are possible. The reason the discrete codes suit speech so well is that speech itself decomposes into a small inventory of reusable units (phonemes and their acoustic variants), which a codebook represents naturally.
In the speech setting the decoder is typically a WaveNet, the autoregressive (AR) model architecture learned earlier for raw audio: the quantized codes carry the content, and WaveNet renders them into waveform samples. The same recipe transfers to music and other time-series signals — anywhere a finite vocabulary of prototypes is a natural description.
Bridge: Training is settled: encode, quantize against a codebook, decode, and update all three pieces with stop-gradient discipline. But how do you generate brand-new data from the finished model? Sampling is no longer a Gaussian draw — the next topic builds a prior over discrete codes.
10.4 Generating New Samples from a Trained VQ-VAE
Hook: A trained VQ-VAE compresses and reconstructs beautifully. But ask it for something new and you hit a wall: which of the possible index grids should you feed the decoder? The encoder never taught us that. We need to learn what plausible code combinations look like.
10.4.1 Sampling in a VAE versus Sampling in a VQ-VAE
Refresh how sampling worked in the standard VAE: draw a random number and form the latent sample as
where is the learned mean vector, the learned scale, and a noise vector whose dimension equals the dimensionality of the latent space. One clarification on where comes from: in the standard formulation each component of is drawn from a standard normal distribution , not from the interval between zero and one, so the sampled spreads symmetrically around the mean with spread set by ; the product multiplies elementwise. That single closed-form expression is the whole sampler — the prior is known, so one draw suffices.
VQ-VAE cannot work this way. Its latent objects are discrete index grids, and there is no formula that conjures a plausible grid out of thin air. The working assumption during training was that the codes spread roughly uniformly across the codebook: if you use, say, 30 codebook entries, then maybe one-thirtieth of all encoded blocks respond to entry 1, a similar number to entry 2, and so on down to entry . But uniform guessing is exactly wrong for generation: real images favor particular combinations of neighboring codes — edges pair with edges, fur pairs with faces. To produce valid new signals you need a reasonable prior over the discrete codes, one learned from the data.
10.4.2 Learning a Discrete Prior with PixelCNN
After training finishes, every training image has left behind a short sequence of codebook indices. Picture a case with blocks per image: one image might have produced indices 11, 3, 3, 30 — four cells, four indices; another image might have produced 9, 12, 7, 23. Across the whole dataset you accumulate many such discrete sequences — and these are pure discrete data you can model.
So fit a probability distribution over them, exactly the kind of autoregressive distribution learning done with PixelCNN in the AR-model part of the course: learn a PixelCNN-style distribution estimate over the coded inputs — "coded" here means represented purely as codebook indices. The autoregressive trick predicts each index from all the ones before it in raster order, which is precisely the kind of dependency structure (edges near edges, textures repeating) that makes some index grids plausible and most others nonsense. Once that distribution is learned, use PixelCNN to sample new index sequences. Walk each sampled sequence to the codebook, pick up the corresponding entries, and pass them through the decoder: out comes new data.
Worked example — from indices to a generated image. Suppose the toy setup uses blocks and a 32-entry codebook. Training left behind these per-image sequences (four indices each): image A gave , image B gave , and thousands more images gave thousands more sequences. Step by step:
- Fit: train a small PixelCNN on all collected sequences. It learns, say, that after a start-of-grid token, index 11 occurs often, and that a cell following in row-major order is usually 3 again — smooth regions repeat their codeword.
- Sample: draw a fresh sequence from the fitted model, one index at a time: . Every step conditions on the indices already drawn.
- Look up: replace each index by its codeword: .
- Decode: arrange the four vectors back into a spatial grid (full-scale VQ-VAE does this for all 1024 cells of a grid) and run the decoder.
The output is an image that never appeared in training, yet is built entirely from learned vocabulary pieces — a brand-new sample. Sense-check: had we instead rolled a uniform die for every cell independently, neighboring cells would clash (sky next to teeth) and the decoded image would look like noise; the autoregressive prior is what buys coherence.
Real-world note on why one-dimensional signals are even friendlier here: the notion of temporal order makes their autoregressiveness natural. For images you impose an ordering by convention — given a particular block, all blocks on the same row to its left, plus every block in rows above, count as "past" data used to predict the current block. Audio needs no such convention; time provides it. This is also why WaveNet-style decoders and PixelCNN-style priors slot into the audio pipeline without rethinking.
Exam note: Expect at least one assignment-two component dealing with PixelCNN — and remember its second life here as the prior over VQ-VAE codes, not just an image model.
10.5 VQ-VAE-2: Hierarchy for Sharper Generation
Hook: Flat VQ-VAE describes every patch of an image with codes at one scale — like describing a painting only in terms of brushstrokes, with no notion of "this is where the house goes." VQ-VAE-2 adds the missing big picture, and its samples become sharp enough to rival GAN imagery.
10.5.1 Two Encoders, Two Codebooks, Two Decoders
VQ-VAE-2 generates data with noticeably better clarity than flat VQ-VAE — good enough to compete strongly with images produced by generative adversarial networks. Where VQ-VAE beats a standard VAE is exactly where discreteness makes sense; VQ-VAE-2 improves on VQ-VAE. Its idea: don't use one encoder — bring a hierarchical structure into the encode-decode process.
Concretely, suppose the training set is a collection of images. The first encoder — call it the bottom encoder — compresses each image to a representation, each block perhaps carrying 64-dimensional features (illustrative numbers). Those encoded features feed a second encoder — the top encoder — which encodes further, to blocks. Typically the top level uses richer feature maps than the bottom: if the bottom maps are, say, 64- to 80-dimensional, the top might be around 160-dimensional. The intuition behind richer top features: fewer cells must cover more image, so each cell has to describe a larger, more abstract chunk of scene.
Both levels get their own codebook, applying exactly the principles from Section 10.3. At the top level, the training goal is that the top decoder's reconstruction should closely reproduce the encoded values the bottom encoder produced. Then, based on what flows out of the top decoder together with the bottom-level encodings, the lower-level codebook is formed. The key conditioning: the encoded values at the bottom layer are conditioned on the values generated by the top decoder. In other words, fine detail is never chosen in isolation — it is always chosen given the coarse layout above it.
Nothing prevents extending to three or four levels of encoders and decoders — the setup shown used three. But note the trade-off: the hierarchical structure makes training quite difficult, while the clarity of reconstructions and of newly generated data becomes very good, competitive with GAN-based techniques.
The information flow in one pass:
Here and are the two encoder outputs (a grid and a grid respectively), is the top-level reconstruction of the bottom features, and means the top-decoded values are stacked with the bottom encodings as conditioning input. Each arrow's quantize step uses its own level's codebook with nearest-neighbor lookup, exactly as in flat VQ-VAE.
10.5.2 The Painting Analogy
Strip away the encoder-decode nomenclature for a moment and think in everyday terms — this is remarkably close to how humans work. Suppose you want to paint a nice cottage with a river and trees in the background. You probably would not start with the door handle. First you sketch the outline: the entrance to the house, the cottage shape, the areas reserved for greenery, the region where the river will run. Only after the outline exists do you step inside and add lower-level detail — where the door goes, where the windows are — then texture for the river, texture within the green region, texture on the entrance way.
Map that onto the architecture: the top-level encoder and decoder correspond to the outlines — the higher-order concepts — while the bottom level adds the low-level details, and those details are added conditioned on the high-level structure already drawn. Lower-level choices depend on the higher-level lines laid down first. This is analogous to how humans process information in multiple layers of abstraction, and it is the intuition for why VQ-VAE-2 works.
Where does the analogy break? A human painter can revise earlier strokes when details demand it; the feed-forward hierarchy cannot — once the top-level sketch is committed as codes, the lower levels live within it. That rigidity is also the point: it forces a clean division between planning and rendering.
10.5.3 Reconstruction Quality Levels and Sampling with PixelSNAIL
The quality ladder is easy to see in the reconstructions. From an original image, the top-level encoder–decoder combination alone yields an image noticeably less faithful — global shapes present, texture gone. Add the middle encoder — in the setup shown there were three encoders — and much of the graininess resolves: teeth become clear, eyes gain resolution. Use top plus middle plus bottom together and quality improves again. Read the ladder as an ablation study: each extra level contributes exactly the scale of detail it is responsible for, which is strong evidence the hierarchy really has separated coarse from fine.
For generating new data, you need probability distributions over the codebook usage at every level. Flat VQ-VAE used PixelCNN as its distribution estimator; VQ-VAE-2 uses PixelSNAIL, a higher-quality CNN-based distribution model with attention-style receptive fields that capture long-range dependencies between distant patches. The sampling order respects the hierarchy: start with the top-level codebook sequences and build the top prior; then, conditioned on the sampled top codes, learn/sample the bottom-layer codes. Decoding the full stack gives the finished sample.
Pull the family together:
| Variant | Latent space | What it adds |
|---|---|---|
| Standard VAE | continuous | Gaussian prior, ELBO training |
| Beta-VAE | continuous | weighted KL for disentangled axes |
| VQ-VAE | discrete | codebook lookup, autoregressive prior over codes |
| VQ-VAE-2 | discrete, layered | multi-scale codes, coarse-to-fine sampling |
Standard VAE — continuous latent space; beta-VAE — disentangled feature modification; VQ-VAE — discrete latent space; VQ-VAE-2 — a hierarchical structure that keeps the discrete latent space but layers it. The upcoming assignment lets you play with these alongside some GAN aspects.
Scope: The hierarchy buys sharpness at a price. Every extra level multiplies the number of codebooks to learn, priors to fit, and loss terms to balance, so training becomes quite difficult — expect slower convergence and more sensitivity to hyperparameters than flat VQ-VAE. Choose the depth of hierarchy based on how much large-scale structure your data actually has: faces and scenes benefit greatly; textures with little global organization may not justify the cost.
Real-world: VQ-VAE-2's high-fidelity samples on large image datasets showed that discrete latent models could stand next to adversarial approaches on image quality — a result that later fed into architectures combining discrete codes with transformers for even larger-scale generation.
Bridge: The discrete-latent branch ends here: continuous (VAE) to disentangled (beta-VAE) to discrete (VQ-VAE) to hierarchical-discrete (VQ-VAE-2). Next we open a rival family that writes down no probability distribution at all — generative adversarial networks.
10.6 Generative Adversarial Networks: Learning Distributions Without a Likelihood
Hook: Every model so far began the same way: write down (or approximate) a probability distribution, then sample from it. GANs throw that recipe out. No density is ever written down — two networks fight, and realistic data falls out of the fight.
10.6.1 The Likelihood-Based Family So Far
GANs — invented in 2014 by Goodfellow, who was also the first author of the reference book on deep learning used throughout this course, one of the first books to cover the field broadly — differ from everything learned so far in one fundamental way. Every distribution-learning formulation in this course so far rests, to a large extent, on maximization of likelihood:
- Autoregressive (AR) models provided exact calculation of probability distributions — no approximation. Learn the distribution from data, sample it to create new data. Two costs: sampling is sequential (pixel 1, then pixel 2 given pixel 1, and so on), so generation is slow; and there is no concept of a latent space.
- Flow models associate a latent space with the data, giving the latent a deeper meaning than the raw pixels. But that latent space has the same dimension as the data — no compression ability — and the transformation must be bijective: two things cannot map to one during the transformation, because only invertible maps let you compute the exact likelihood by change of variables. Exact likelihood, though.
- VAEs also maximize probability, but only as an approximation: the exact likelihood is intractable because evaluating the KL divergence between the encoder and decoder transformations cannot be done. So we maximize the ELBO — the evidence lower bound — dropping the intractable positive KL term, and instead minimize the KL divergence between the approximate posterior and the standard normal prior while maximizing the data likelihood.
All of these rely on explicit calculation of the probability distribution. Whatever their differences, each one can answer the question "how likely is this point under my model?"
| Family | Likelihood | Latent space | Sampling | Main cost |
|---|---|---|---|---|
| Autoregressive | exact | none | sequential, slow | slow generation |
| Flow | exact | same dim as data | parallel | bijectivity constraint |
| VAE | approximate (ELBO) | lower-dim, continuous | parallel | blurry samples |
| GAN | none | lower-dim, implicit | parallel, fast | unstable training |
10.6.2 The Implicit Alternative and Its Trade-offs
A GAN takes a different route entirely: implicit modeling. It never explicitly calculates the probability distribution. What does that mean? Start from a random vector — usually called , often 100-dimensional — pass it through a module called the generator, and out comes generated data. The generator's parameters are tuned until its outputs look like they came from the training distribution; the distribution itself lives implicitly in those weights, the way a forger's skill lives in their hands rather than in a written recipe.
Flow models share the skeleton (sample , transform): there has the data's own dimension and you apply a learned inverse transformation; in a standard VAE you sample from encoder-learned parameters and decode. The GAN starts from a small-dimensional vector and uses its generation network to create the data, but approaches the distribution implicitly rather than fitting it directly.
Two consequences follow, one pleasant and one awkward. Pleasant: data generation is completely parallel — unlike the AR sampler's sequential crawl, all of an image appears at once, so generation is fast. Awkward: there is no inference capability — no way to compute how likely a generated datum is. The likelihood calculation is absent, which is why evaluation of GANs needs its own treatment later in this session.
Worth fixing in mind, the checklist of things that make any generative model good:
- Sampling — you can draw from it and create new data;
- Likelihood evaluation — it can tell you whether generated data is plausible or not at all likely;
- Trainability — optimization behaves well enough to run;
- Representation — it offers something like a latent space.
GANs score brilliantly on parallel sampling and trainability, give up explicit likelihood scoring, and — depending on variant — provide representations.
Real-world context on momentum: the visible quality of GAN samples climbed dramatically — in 2014 outputs were black-and-white only; by 2015–16 modest-resolution color appeared; from 2021 onward, very high-quality, large, high-resolution images became routine. The topic is enormously broad — dedicated short courses of six to eight weeks exist on GANs alone — and heavily researched, with many variants producing excellent results. The roadmap: basic principles now; evaluation of GANs; a brief look at theory; then a fully convolutional implementation known as DCGAN; subsequent sessions cover the major variants and address training instability.
Bridge: Implicit modeling raises an obvious design question: if no likelihood guides training, what does? The answer is a second network whose entire job is to tell real from fake — the discriminator. Next: the anatomy of the contest.
10.7 Inside a GAN: Generator versus Discriminator
Hook: How do you learn to make convincing fakes without any formula for what "convincing" means? You practice against an expert. Every fake that gets caught teaches you something; every fake that passes proves you improved. A GAN automates exactly this duel between a counterfeiter and an appraiser.
A helpful everyday picture before the architecture: imagine a forger trying to create fake paintings of one master. At first the fakes are clumsy. The forger slips them into a pile of authentic works and hands the whole pile to an art dealer, who marks each piece real or fake and explains the verdicts. The forger returns to the studio and produces better fakes; meanwhile the dealer, seeing ever-better fakes, sharpens their own eye. Locked in this loop, each side forces the other to improve — until the dealer genuinely cannot tell the difference anymore. That loop is GAN training; now name its parts.
10.7.1 The Generator: From Noise Vector to Image
On one side, the generator : it consumes random noise and manufactures data. Architecturally it resembles a CNN run in reverse — instead of shrinking an image down to features, it grows a tiny feature volume up into an image using transpose convolutions (also called fractionally strided convolutions). Where a normal convolution asks "summarize this patch into fewer numbers," a transposed convolution asks the opposite: "expand this summary over more pixels," increasing the size of the volume layer by layer.
A typical arrangement traces like this:
- Take the incoming noise vector .
- Reshape (project) it into a small volume like .
- Stack transpose 2D convolution layers, each roughly doubling spatial size while reshaping channels:
- Stop when the output reaches, say, — a full RGB image.
All the convolution parameters are learned during optimization so that these images land close to the training distribution. Nothing about step 3 knows anything about faces or digits at initialization; every meaningful pattern in those kernels is discovered by training pressure from the adversary described next.
10.7.2 The Discriminator: A Binary Real-versus-Fake Classifier
On the other side, the discriminator : a classifier, naturally built from ordinary CNN layers — exactly the kind of stack you have used for classification all course — whose job is to decide whether an image came from the real training set or from the generator. It learns to emit a high value — 1 — for genuine training images and 0 for anything the generator produces. Think of it as a binary classifier: real input → output near 1; generated input → output near 0. Its final score passes through a sigmoid so the number can be read as a probability of being real.
Note the elegant division of labor: the discriminator trains on labeled data for free — labels are just "real" or "fake," known by construction — so from its own perspective this is plain supervised binary classification. The subtlety is entirely on the generator's side.
10.7.3 The Adversarial Loop
Now the adversarial dance, run as a procedure:
- Sample fake inputs. Draw a batch of noise vectors and generate images .
- Assemble the training pool. Mix the generated batch with a batch of genuine training images.
- Update the discriminator. Train on this mixed batch to say 1 for reals and 0 for fakes — an ordinary classification step.
- Update the generator. Freeze for the moment and adjust 's parameters so that the discriminator's verdict on fresh fakes moves toward "real."
- Repeat. With each round the discriminator gets better at identifying genuine data, yet eventually fails to catch fakes — because the generator improves enough to fool it.
The generator's goal deserves emphasis: it watches the discriminator's verdicts and adjusts its own parameters so that its output moves toward the true training-data distribution — it wants to pull the discriminator into believing a generated image is actually real. Neither network learns an explicit distribution; the generator implicitly produces data that resembles the original so well the discriminator cannot tell the difference. At the equilibrium point, catches real data reliably yet fails on fakes — its answers sit at chance level — and only survives as the useful artifact.
Trace of one round with toy numbers. Suppose the discriminator currently outputs on genuine images and on fakes. Step 3 pushes the first number up toward 1.0 and the second down toward 0.0 — say after the update they become 0.93 and 0.08. Step 4 then tunes the generator so its fakes score higher: perhaps climbs back to 0.22. Neither side wins outright; each update changes the landscape the other navigates. Over thousands of rounds, if all goes well, fakes drift up past 0.4 toward 0.5 while reals stay near 0.5 too — the dealer has stopped being able to separate the piles.
Pitfalls:
- Reading 's output as ground truth. During and after training, is a relative signal inside the game, not a calibrated likelihood; a value of 0.8 does not mean "80% probable under the data distribution."
- Expecting a fixed loss landscape. Unlike ordinary training, each player's update changes the other's objective — there is no single valley to descend into, only an equilibrium to approach.
- Letting one side dominate. If becomes perfect early, its verdicts carry almost no gradient information for ; balancing the two players is a running theme of GAN practice.
Real-world: this same loop, with convolutional stacks on both sides, powers face generation, photo upsampling, and dataset augmentation pipelines — anywhere realistic synthetic imagery saves collection cost.
Bridge: Two networks, opposite goals, one equilibrium. To reason about that contest precisely we need it as an equation — the minimax objective, next.
10.8 The Minimax Objective
Hook: One network wants a number to go up; the other wants it to go down. Both train simultaneously on the same expression. That single line of mathematics — part maximization, part minimization — is the engine of every GAN.
10.8.1 Reading the Value Function Term by Term
This is arguably the single most important formula of the topic — the building block describing GAN behavior — and it looks unlike every loss seen before: not a pure minimization nor a pure maximization, but both at once. The value function:
Name every symbol. is the random noise vector — small-dimensional, say , drawn from the noise prior . is the generator, mapping that vector to, for example, a image. ranges over the real training data under the data distribution , same shape. outputs a real number interpreted as "probability of being real." is called a value function rather than a loss precisely because one player climbs it instead of descending it. The end product of all training is : a network that takes vectors and creates semantically plausible images resembling the training set.
Maximize the whole expression with respect to :
- For any genuine training datum , a well-trained should output a value close to 1, making close to 0 (the log of a number near one sits just under zero).
- For any fabricated , should output close to 0, making close to 1 and so close to 0.
- If is untrained and fails at this, the function value is a large negative number. Training raises the value toward 0. That ascent is the discriminator's education: all real images score near 1, all generated images near 0.
Minimize with respect to : the generator wants to create such that is close to 1. Then is close to 0 and its logarithm is strongly negative — pushing the minimization hard. Minimizing the -part amounts to manufacturing data the discriminator scores as real, i.e., data very close to the original training distribution. Summing up: maximization over tunes the discriminator to certify training data as real and flag far-from-training data as fake; minimization over sharpens generation quality. Both happen simultaneously — a genuinely new kind of objective compared to everything earlier in the course.
Worked example — scoring three scenarios. Let real scores sit at and fake scores at for a well-matched pair of networks. Using natural logarithms:
Read them in order. A sharp discriminator against weak fakes earns the high value , close to the theoretical maximum of 0. An untrained or fooled discriminator leaves the value deeply negative (). At perfect equilibrium the generator makes fakes indistinguishable, so everywhere — chance level — and the value settles at , exactly . Sense-check: 's best case sits near 0, 's worst case is strongly negative, and equilibrium lands between — confirming the two forces pull in opposite directions on the same quantity.
10.8.2 Why GAN Training Is Unstable
Here is the honest bad news about GANs. Jointly optimizing a term that one player maximizes while the other minimizes creates training dynamics that are not very stable. Every generator step rewrites the very landscape the discriminator is climbing, and vice versa — so there is no fixed valley to descend. The loss frequently refuses to glide down asymptotically; instead it oscillates — drops, rises, drops again. This instability is the defining practical headache of GAN training, and upcoming sessions tackle it head-on by modifying the overall loss function and redesigning generator and discriminator architectures.
A useful way to picture it: ordinary deep learning is one hiker rolling downhill in fog. GAN training is two hikers on the same terrain, one told to reach the lowest point and the other the highest — each step either takes changes the ground under both feet.
10.8.3 The Original Training Loop (Pseudo-code)
The original algorithm interleaves the two players asymmetrically. One round proceeds as follows:
- For steps, repeat: sample a mini-batch of noise vectors from the noise prior and a mini-batch of examples from the data-generating distribution; then update the discriminator by ascending its gradient:
- After those steps, sample a mini-batch of fresh noise samples and update the generator by descending stochastic gradient on its slice of the loss:
Both updates are confirmed as written: each averages its per-sample terms over the mini-batch with the factor , exactly the standard stochastic form of the original algorithm; the discriminator ascends because its terms enter the value function positively, while the generator descends because only the second term involves its parameters. Note the generator's sum contains no piece — real images tell the generator nothing about how to improve.
Notes from the description: are the discriminator's parameters — ordinary CNN parameters; the noise comes from a random-number generator; nothing forbids adding momentum-based optimizers or similar extras. The count is a hyperparameter, often taken greater than 1: strengthen the discriminator first before letting the generator play. And throughout, the learning rates must be chosen carefully so the loss settles after some iterations instead of oscillating forever.
10.8.4 A Two-Player Game
This minimax structure is the same object game theorists study. Game theory was developed first in the economics community, originally to reason about demand-supply gaps, and the field's importance was recognized with a Nobel Prize in Economics. GANs import the two-player-game principle directly: the players are the discriminator and the generator, locked in the fight described above — trying to send toward 0, trying to drag it toward 1. Where ordinary training seeks a minimum, this game seeks an equilibrium: a pair that neither player can improve on alone — the same notion of stable outcome economists use when neither firm can profit by changing strategy unilaterally.
10.8.5 The Non-Saturating Trick: Maximizing
People who trained early GANs noticed something intuitive: creating meaningful data from a tiny random vector is a harder task than discriminating real-looking images from fake ones. So at the start of training, is weak while is strong — and since dominates, sits near 0. Now watch what that does to the generator's loss .
Write for the discriminator's raw score just before its final sigmoid, so . Differentiating both candidate objectives with respect to :
With early in training, the first derivative is about — the error signal reaching the generator is nearly flat, the same predicament as the vanishing gradient problem — while the second is about , full strength. Plug in numbers: at the old loss transmits a gradient scaled by , the new one by — roughly nineteen times stronger. That is why, with the naive objective, the generator struggles to learn anything useful early on.
The fix people originally adopted: replace that sluggish term with
Early in training is close to 0, so is large and its gradient is sharp — strong, usable information for updating . Operationally: stop doing gradient descent of on ; instead minimize , equivalently perform gradient ascent to maximize just . Same equilibrium target, radically better early dynamics. This swap is the classic non-saturating trick from the original formulation — "non-saturating" because the new loss refuses to flatten out (saturate) when fakes are easily caught.
10.8.6 Early Results and Limitations of the Original GAN
Real-world: applied to face images and to MNIST digits, the original GAN produced reasonable generations, and nearest-neighbor checks against the training set show many samples looking quite close to some real example. Still, the honest assessment: promising for grayscale images of modest size, but performance degraded on larger color images. The variants covered in subsequent sessions do significantly better. Real-world: an interactive playground implemented in Keras lets you manipulate the training dynamics yourself and builds genuine insight into how the two losses interact.
Exam note: Know the minimax value function cold: why maximization over drives and , why an untrained discriminator leaves the value strongly negative, and why minimization over pushes toward 1. Be ready to state the alternating update rule — discriminator ascent steps, then one generator descent step — and to explain the non-saturating swap .
10.9 Judging Generated Images I: The Inception Score
Hook: A GAN hands you a beautiful image — but is it a good generator or just a lucky draw? There is no likelihood to consult. So researchers borrowed a judge: a big pretrained image classifier that votes on what the picture looks like.
10.9.1 Why GANs Need External Judges
With every earlier generative model, judging output was easy in principle: you had learned an actual probability density, so you could pass a generated image back through it and see whether it received high probability — a low-probability score meant the sample sat far from the training distribution. GANs surrender that yardstick: no inferencing capability, no likelihood. So GAN-generated images require other ways of deciding whether they are reasonable. Two scores dominate practice: the Inception Score and the FID score.
10.9.2 Definition and the Two Properties It Rewards
The Inception Score (IS) for a GAN's outputs should be as high as possible. Mechanism: take a generated image and pass it through a large multi-class classifier trained on ImageNet — an Inception-style network with 1000 output classes, the architecture family introduced earlier in the course's CNN unit. The classifier produces class probabilities , where is the generated image and the predicted class label. Two properties are desired:
- Clarity / confidence. A generated image ought to resemble real images of some class, so the classifier should commit: one class probability high, the rest tiny. Equivalently, the entropy of should be low. Recall that entropy, written , measures how spread out a distribution is: zero when all mass sits on one outcome, when it spreads evenly over outcomes. If a generated cat image yields a high cat-class probability and near-zero elsewhere, entropy is low, which is good. Contrast the bad case: softmax outputs like 0.25, 0.25, 0.25, 0.25 across four classes — summing to 1 as softmax guarantees — spread the mass evenly, and the entropy of that output is , its maximum, signaling a muddled, unclassifiable image.
- Variety / diversity. Across many generated samples, the class distribution should mirror the training data's spread. If training images contain cats, dogs, rats, elephants, the generated pool should contain a reasonably matching share of cats, dogs, rats, and elephants. That is captured by the marginal — the average of over all generated images — which should approach a uniform-like distribution, i.e., have high entropy.
Combining the two demands gives the definition:
where is the entropy of the marginal class distribution and the average conditional entropy of predictions given images. High IS arises exactly when variety is high ( large — the generator is not regurgitating the same class repeatedly) and clarity is high ( small — each image confidently belongs to some class). Notation note: many texts write the same score as the exponential of an expected KL divergence,
which expands to the entropy form above once you write out the KL definition — two costumes, one quantity. A high IS certifies good quality in both variety and clarity — under one assumption: that the classifier's judgments track human perceptual similarity between generated images and the class concepts.
Worked example — computing an Inception Score on a tiny pool. Use a toy judge with classes and three generated images. The classifier returns confident predictions: image 1 gives , image 2 gives , image 3 gives — each concentrated on a different class, covering 3 of the 10 classes.
Step 1 — conditional entropies. For image 1's distribution, roughly :
Say all three images land near .
Step 2 — marginal. Averaging the three distributions spreads mass over exactly those 3 chosen classes, about each: .
Step 3 — combine:
Sense-check against the ceiling: with a uniform marginal over all 10 classes and zero conditional entropy, the score hits its maximum . Our pool covers few classes, so 2.46 sits well below the ceiling — variety is the weak leg here.
10.9.3 How One Image per Class Defeats the Score
But there is a hole in the score: a trivial case defeats it. Generate 1000 images, one for each of 1000 classes — one cat, one dog, one of everything else. Each image is confidently classified (low conditional entropy) and the marginal spreads evenly across classes (high marginal entropy). That set achieves a perfect-looking inception score, yet nothing about it says the images are diverse relative to the original training distribution or individually plausible beyond the classifier's verdict. A model that memorizes a single exemplar per class and replays it forever scores as well as a genuinely rich generator.
The IS does not genuinely measure diversity against real data — it never looks at real images at all. So the Inception Score alone is not enough; enter the FID score.
Pitfalls:
- Reading IS in isolation. High IS can coexist with severe mode dropping; always ask whether real data was consulted anywhere in the measurement.
- Trusting the classifier blindly. The score leans entirely on one network's opinions; swapping the classifier changes the numbers.
- Comparing IS across different judges or datasets. The score is only meaningful relative to the same classifier and label space used to define it.
Exam note: Remember both directions and both legs: IS rewards low conditional entropy (confident, clear images) plus high marginal entropy (varied classes), and remember the failure story — a one-image-per-class set defeats it because it measures neither fidelity to real data nor true diversity.
10.10 Judging Generated Images II: Fréchet Inception Distance
Hook: The Inception Score asks a classifier how confident and how varied the fakes look. It never asks whether they actually resemble your training images. The Fréchet Inception Distance fixes that blind spot by comparing two clouds of features — real versus generated — statistically.
10.10.1 From Softmax Outputs to Deep Features
The Fréchet Inception Distance (FID) repairs the blind spot by comparing distributions in feature space rather than trusting class probabilities. It uses the Inception v3 network — the CNN classifier architecture from Google that concatenates features from multiple stages, delivers high classification quality, and has modest memory requirements.
Pass the training images through Inception v3 and collect the activations of its CNN layers; recall that normally a softmax submodule sits after those features to classify — for FID, discard the softmax entirely and keep only the CNN-derived feature values (in practice the deep "pooling" layer just before classification). From these features compute two statistics for the real dataset:
- — the mean vector of real features;
- — the covariance matrix of real features, which records how the feature dimensions co-vary across images.
Run the generated images through the same pipeline to get their mean and covariance . The distance between these statistic pairs measures how far the generated feature cloud sits from the real one — closeness in this semantic feature space stands in for perceptual similarity.
10.10.2 The FID Formula and Its Behavior
This is the standard Fréchet distance between two multivariate Gaussians fitted to the two feature sets — exactly the form used for generative model evaluation. Here is the trace, the sum of a matrix's diagonal entries, and denotes the matrix square root — the symmetric matrix whose square equals . The first term penalizes shifted centers (different average content); the second penalizes differently shaped clouds (different spread and correlations).
Check the limiting case, as worked through below: if the covariances coincide, , then and the trace term collapses to nearly a zero matrix's trace — a small value. Combined with equal means (), FID approaches 0. Conversely, whenever the means drift apart or the covariance structures differ substantially, FID grows large. Low FID is preferred for a good generative model — unlike the Inception Score, where high is good, remember the direction flips here.
Worked example — identical statistics give zero distance. Use two-dimensional features. Real set: , . Generated set matches perfectly: , .
Step 1 — mean term: .
Step 2 — matrix product: , so .
Step 3 — trace term:
Step 4 — break the match. Keep the same covariances but shift the generated mean to : now and FID rises to 0.09. Or keep means equal but double every variance, : the square root becomes per axis, giving trace . Sense-check: any drift in center or shape inflates the score from zero, exactly as intended.
10.10.3 Putting Both Scores Together
The working evaluation protocol: generate a batch of images while varying the random vector ; collect them; pass them through Inception v3; compute FID — which should be low — and also compute the Inception Score — which should be high. A good generative model shows both signatures simultaneously.
Why insist on joint reading? Evidence from stress tests: take a good generated image and add increasing levels of noise and blur. As disturbance grows, the Inception Score barely changes, but the FID climbs steeply — the two scores disagree, and FID is the one telling the truth. Other cases invert it: an image can post a high IS while also carrying a high FID, and a side-by-side look shows it is worse than an alternative with low FID. Images of genuinely good quality are reliably indicated by the pair: high inception score together with low FID. Together they certify that results have significant variety and resemble the training-image classes effectively.
Exam note: Memorize the pairing rule — Inception Score high, FID low — and each score's failure story: IS falls to one-image-per-class sets and to classifier overconfidence; FID rises under noise and blur while IS stays flat. Expect a question on why neither score alone is trusted.
10.10.4 Student Questions and Answers
Q: For the noisy/blurred image case, shouldn't the inception score have risen? We saw it stay more or less unchanged as for the cleaner images — is that expected? A: Yes, it can happen — though it is not desired. Neither score is foolproof. That is exactly why the inception score alone is not enough: use both the inception score and the FID score and read them together. In most cases the pair matches perceptual evaluation by a human, but they are not perfect measurements.
A natural follow-up asked what to do when the numbers look bad.
Q: If the FID distance comes out larger, should we fine-tune the model with more data? A: Remember these are not definitive indicators of quality — ultimately the quality lives in human perception of the images. This pairing is simply what people use because nothing better has yet been settled on. And understand why the inception score can mislead: it leans on probabilities emitted by a neural classifier. Even a classifier that sorts the known training classes perfectly suffers false positives — an image unlike anything in training may still receive a confident, wrong classification. That is an overfitting-flavored failure present in any network, and since the IS computation consumes exactly those fallible probabilities, the IS itself can be wrong. Pair it with FID, trust neither absolutely, and remember the final judge: humans. Sometimes a technically beautiful image betrays itself through absurd artifacts — a road passing straight through a high-rise building — which no score catches but your eye does instantly.
Real-world: these two scores became the de facto report cards of generative vision research — papers quote FID curves epoch by epoch, and benchmark leaderboards rank models by low FID plus strong IS, keeping human eyeballs as the final arbiter above both.
Exam Guidance Summary
- Exam note: expect at least one component of assignment two to involve PixelCNN; the assignment lets you experiment with the VAE variants (beta-VAE, VQ-VAE, VQ-VAE-2) together with some GAN aspects.
- Exam note: the GAN minimax objective was flagged as the building block of the entire topic — know it cold, including the term-by-term reasoning for maximizing over and minimizing over , and why an untrained discriminator leaves the value very negative.
- Exam note: be able to reconstruct the VQ-VAE three-piece loss (reconstruction + codebook + commitment, with weighting commitment) and explain which parameter set each stop-gradient protects: freezes the encoder inside the codebook term; freezes the codeword inside the commitment term.
- Exam note: know both evaluation metrics directionally — Inception Score high, FID low — and the failure story of each (IS defeated by one-image-per-class sets and by classifier overconfidence; FID rising under noise/blur while IS stays flat).
- Study advice: work through the recommended multi-part blog series covering GAN basics, GAN evaluation, and GAN variants; explore the Keras GAN playground for intuition about training dynamics.
- Roadmap: multiple subsequent sessions continue with GAN variants — including the fully convolutional DCGAN — and with fixes for training instability, so treat this session's objective and pseudo-code as foundation material for what follows.
A compact revision order that matches this session's structure: first rebuild the VQ-VAE loss and its stop gradients from memory; then write out the minimax value function and narrate each term's behavior under trained, untrained, and fooled discriminators; finally rehearse both evaluation scores with their directions and failure cases.
Key Industry Applications
- Real-world: VQ-VAE powers speech modeling — male-to-female and speaker-to-speaker voice conversion, general voice style transfer — using WaveNet decoders from autoregressive audio modeling.
- Real-world: VQ-VAE handles ImageNet-scale image reconstruction successfully, and extends naturally to one-dimensional signal compression and generation.
- Real-world: VQ-VAE-2's clarity competes with GAN-generated imagery; its hierarchical coarse-to-fine scheme mirrors human painting workflows (outlines first, details conditioned on outlines).
- Real-world: GANs progressed from grayscale toys in 2014 to very high-resolution, large images from 2021 onward; DCGAN established the fully convolutional recipe that later variants built on.
- Real-world: Inception Score and FID rely on Inception-network classifiers trained on ImageNet — the same Google-origin architectures reused as perceptual measuring instruments, quoted epoch by epoch in research papers and benchmark leaderboards.
- Real-world: GAN training formalizes as a two-player game — mathematics pioneered in economics (demand-supply analysis) and recognized with a Nobel Prize in Economics.
- Real-world: PixelCNN serves both as an image prior and as the codebook-index prior enabling VQ-VAE sampling; PixelSNAIL upgrades that role in the hierarchical variant.
Together these threads show one pattern: the same small set of architectures keeps reappearing in new roles — CNNs as encoders, decoders, discriminators, and judges; autoregressive models as image generators and then as priors over discrete codes. Recognizing which role a network plays in a pipeline is most of the work in reading modern generative-system papers.
UDL Lecture 10 notes · Discrete Latent Spaces and Generative Adversarial Networks
Sections Breakdown
How the standard VAE learns Gaussian latent distributions, generates by sampling the prior, and why categorical data calls for a discrete latent space.
Weighting the KL term so latent axes become disentangled single-attribute sliders, at the cost of blurrier reconstructions.
Feature grids, nearest-neighbor codebook lookup, the three-piece loss with stop gradients, and dictionary-learning updates.
Why Gaussian sampling fails on discrete codes and how a PixelCNN prior over index sequences unlocks generation.
Top and bottom encoders with separate codebooks, coarse-to-fine conditioning, the painting analogy, and PixelSNAIL priors.
Implicit modeling versus the autoregressive, flow, and VAE likelihood families; parallel sampling with no inference.
Transpose-convolution generators, CNN binary-classifier discriminators, and the alternating adversarial training loop.
The GAN value function term by term, the alternating update loop, the game-theory framing, and the non-saturating trick.
Conditional and marginal entropy rewards, the score definition, and the one-image-per-class failure case.
Comparing real and generated feature statistics with the FID formula and reading IS and FID together.
Exam Revision Notes
Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.
Recap of Variational Autoencoders and Why Discrete Latent Spaces Matter
Must-know: The standard VAE encoder outputs the parameters of a distribution (mean and covariance) per input; a KL regularizer keeps that distribution close to a zero-mean unit-covariance Gaussian, and generation samples from the prior and decodes.
⚠️ Top pitfall: Forcing genuinely categorical factors (indoor/outdoor, male/female) through a continuous axis wastes capacity; discrete data calls for a discrete latent space.
Self-check: After training, how do you generate a new sample from a standard VAE?
Connects to: Section 10.3 (VQ-VAE) and Section 10.4 (Sampling from a Trained VQ-VAE).
Beta-VAE Refresher: Disentangled Latent Directions
Must-know: Beta-VAE adds a weight beta > 1 on the KL divergence term to push the latent space toward disentangled, independent axes for single-factor editing.
⚠️ Top pitfall: Raising beta too high starves reconstruction and produces blurry outputs; the trade must be tuned by watching both terms.
Self-check: What does beta-VAE trade away in exchange for disentangled latent axes?
Connects to: Section 10.1 (Recap of Variational Autoencoders) and Section 10.3 (VQ-VAE).
VQ-VAE: Vector Quantization of the Latent Space
Must-know: Rebuild the three-piece VQ-VAE loss (reconstruction + codebook loss + beta-weighted commitment), explain that sg[z_e] protects the encoder in the codebook term and sg[e] protects the codeword in the commitment term, and argue why the argmin codeword pick blocks backpropagation.
⚠️ Top pitfall: Attributing the lookup to the decoder or dropping a stop gradient: the argmin pick is non-differentiable, so without straight-through copying no gradient reaches the encoder.
Self-check: Which operation inside VQ-VAE training is not differentiable, and what is the fix?
Connects to: Section 10.1 (Recap of Variational Autoencoders) and Section 10.4 (Sampling from a Trained VQ-VAE).
Sampling from a Trained VQ-VAE via a PixelCNN Prior over Codes
Must-know: VQ-VAE sampling requires a learned discrete prior: collect per-image code-index sequences, fit a PixelCNN-style autoregressive model over them, sample indices, look up codewords, decode. Images impose raster order; audio gets its ordering from time.
⚠️ Top pitfall: Guessing codebook indices uniformly at random ignores learned combinations of neighboring codes and yields incoherent decodes.
Self-check: Why does the standard VAE sampler z = mu + sigma*epsilon not transfer to VQ-VAE?
Connects to: Section 10.3 (VQ-VAE) and Section 10.5 (VQ-VAE-2).
VQ-VAE-2: Hierarchical Vector Quantization
Must-know: VQ-VAE-2 conditions bottom-level codes on top-level decoded values; sampling runs the top prior first, then the bottom prior conditioned on sampled top codes. PixelSNAIL replaces PixelCNN as the prior model.
⚠️ Top pitfall: Forgetting that bottom codes are conditioned on top decoder outputs - independent per-level coding loses the coarse-to-fine benefit and the training difficulty rises without the quality gain.
Self-check: In VQ-VAE-2, what conditions what, and which order are the two priors sampled?
Connects to: Section 10.3 (VQ-VAE), Section 10.4 (Sampling from a Trained VQ-VAE), and Section 10.6 (Implicit Generative Modeling).
GANs as Implicit Generative Modeling versus Likelihood-Based Models
Must-know: AR = exact likelihood, slow sequential sampling, no latent space; flow = exact likelihood but bijective same-dim maps; VAE = ELBO approximation; GAN = implicit modeling, parallel sampling, no likelihood. Know the four-property checklist for generative models.
⚠️ Top pitfall: Assuming GANs are 'just another likelihood model' - they never write down a distribution, which is exactly why IS/FID exist to evaluate them.
Self-check: Name the four desirable properties of a generative model and say which one GANs give up.
Connects to: Section 10.7 (Generator versus Discriminator), Section 10.9 (Inception Score), and Section 10.10 (Frechet Inception Distance).
Generator and Discriminator Architecture and the Adversarial Loop
Must-know: Generator = transposed (fractionally strided) convolutions from a small volume like 4x4x16 up to e.g. 128x128x3; discriminator = ordinary CNN binary classifier toward 1 on reals and 0 on fakes; training alternates updates with the generator trying to pull D's verdict toward 'real'.
⚠️ Top pitfall: Treating D(G(z)) as a calibrated likelihood - it is only a verdict inside the contest, and if D gets too strong its gradient signal to G vanishes.
Self-check: Why does the discriminator's task reduce to standard supervised classification while the generator's does not?
Connects to: Section 10.6 (Implicit Generative Modeling) and Section 10.8 (The Minimax Objective).
The GAN Minimax Objective, Training Loop, Game Theory, and the Non-Saturating Trick
Must-know: Read the value function term by term: trained D sends both logs toward 0, an untrained D leaves a large negative value, minimizing over G pushes D(G(z)) toward 1. Updates alternate k discriminator ascent steps with generator descent; early training swaps log(1-D(G(z))) for -log D(G(z)).
⚠️ Top pitfall: Using the naive generator loss late into training: when D confidently rejects fakes its gradient scales with D itself and vanishes like a vanishing-gradient problem; the non-saturating loss keeps gradient magnitude near 1.
Self-check: Why does an untrained discriminator leave the value function strongly negative, and what does the non-saturating trick change?
Connects to: Section 10.7 (Generator versus Discriminator) and Section 10.9 (Inception Score).
Inception Score: Definition, Intuition, and Failure Case
Must-know: IS = exp(H(y) - H(y|x)): high marginal entropy means variety, low conditional entropy means clarity; the ceiling equals the number of classes; one confident image per class achieves a perfect-looking score without real-data diversity.
⚠️ Top pitfall: Treating a high IS as proof of quality: the score never looks at real images and leans wholly on one classifier's opinions, which can be confidently wrong.
Self-check: Construct a generated set that scores perfectly on IS while being obviously deficient - what property does it lack?
Connects to: Section 10.6 (Implicit Generative Modeling) and Section 10.10 (Frechet Inception Distance).
Frechet Inception Distance: Features, Statistics, Joint Use with IS
Must-know: FID = ||m - m_w||^2 + Tr(C + C_w - 2(CC_w)^{1/2}) on Inception v3 features; identical statistics give FID = 0; read scores jointly: high IS plus low FID; neither is foolproof and humans remain the final judge.
⚠️ Top pitfall: Trusting either score absolutely: IS can be inflated by classifier overconfidence on off-training images, and noise/blur can leave IS flat while FID climbs - only the pair (plus human inspection) tells the full story.
Self-check: Why does adding blur to a good generated image barely move the Inception Score but strongly increase FID?
Connects to: Section 10.9 (Inception Score).
Was this lecture useful?
BitsNotes AI Assistant
Subject Notes AssistantConfigure AI Chat
Choose how to access the chatbotSigned in as
Powered by BitsNotes — 20 messages per day. No API key needed. Want unlimited access? Use "Bring Your Own Key" mode.
Sign in to use AI Chat
Get 20 free AI messages per day to ask questions about your lecture notes. Sign in with Google or GitHub — it takes 5 seconds.
Sign In to BitsNotesSwitch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.