PixelCNN Variants and 1D Normalizing Flows
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
- The Autoencoder Architecture (Encoder, Decoder, and Code) — covered in Lecture 3; this session reuses the idea of a learned latent space when scoring generative models.
- Convolutional Autoencoders — covered in Lecture 3; the convolution machinery there returns here as the engine behind PixelCNN's masked convolutions.
Where this session sits: Autoregressive models form one branch of the likelihood-based family of density estimators — models that can both score how likely a data point is and create new data. Earlier sessions built the idea in its masked-autoencoder form. This session carries it to images with PixelCNN, walks through the family tree of variants that fixed its flaws, then pivots at the end to a brand-new branch: normalizing flows.
The session has two halves. In the first half, we study PixelCNN: how a convolutional network is turned into an autoregressive density model by masking its kernels, why stacked masks create a blind spot, and how each successor variant — Gated PixelCNN, PixelCNN++, PixelSnail — attacks one specific weakness. We also see how conditioning turns the same machinery into a class-conditional generator, a super-resolution engine, and a colorizer.
In the second half, we reset the scoreboard for what any generative model should deliver, rebuild exactly the probability tools we need (densities, integrals, maximum likelihood), and set up the one-dimensional normalizing flow: learn an invertible transformation that pushes the data's distribution onto a simple law such as a Gaussian, and run it backward to generate.
A map of the road ahead:
| Section | Topic | One-line takeaway |
|---|---|---|
| 6.1 | Recap of likelihood-based autoregressive models | Score well, sample slowly, train stably |
| 6.2 | PixelCNN and masked convolutions | Zero out the future taps; predict each pixel from its past |
| 6.3 | The blind spot | Stacked 2D masks silently drop half the past |
| 6.4 | Gated PixelCNN | Vertical + horizontal split kills the blind spot; LSTM-style gating |
| 6.5 | PixelCNN++ | Replace 256-way softmax with a mixture of logistics |
| 6.6 | PixelSnail | Masked self-attention gives every pixel access to all of its past |
| 6.7 | Conditional generation | Labels, low-res maps, or grayscale inputs steer the same model |
| 6.8 | What we want from a generative model | The five-wish bucket list; where autoregressive models stand |
| 6.9 | Foundations of normalizing flows | Change of variables + invertible transforms = a trainable density |
Keep one thread in mind throughout: every design decision below exists to serve the same two masters — a probability law that assigns sensible densities to images, and a generation process that respects the rule "only the past may inform the present."
6.1 Recap: Likelihood-Based Autoregressive Models
Hook: How can a model create brand-new images while also telling you, honestly, how likely any image is? Likelihood-based models do both — and autoregressive models are the branch of that family that does it by reading only the past.
Autoregressive models form one branch of the likelihood-based family of density estimators. Their defining habit is to use only data that has already happened — the past — and never the current point or anything in the future. Think of a typist copying a sentence letter by letter: at every keystroke they know only what has been typed so far. An autoregressive model lives under exactly that restriction.
Earlier sessions built the masked-autoencoder version of this idea (the MADE-style estimator: a network whose connections are masked so each output can read only earlier inputs) and showed how to sample from it so new data can be created. This session carries the same idea to images with convolutional masks — that is PixelCNN.
6.1.1 Properties Shared by Likelihood-Based Models
Three traits recur across every method in this family, so keep them handy as a scorecard. We will reuse this scorecard at the end of the session when a new family — normalizing flows — walks on stage.
First, inference ability. Because training hands you access to the underlying probability distribution , the model can score any sample you show it. Given a generated data point, it answers the question "how likely is this?" Concretely: show the model an image and it returns the probability it would assign to seeing such an image. That is a built-in anomaly detector — feed it something strange and the probability comes out low.
Second, slow, sequential sampling. Producing one sample means producing values one after another — pixel after pixel, or audio sample after audio sample — because each value depends on the ones before it. Generation lags behind one-shot generators that produce everything in a single forward pass. Speed is the known tax of this family.
Third, stable training. The loss is a genuine likelihood — the negative log likelihood you will meet formally in Section 6.2.2 — so you can watch it fall in a reliable way. Stable does not mean perfect: a steady run can still end with mediocre samples. But the process behaves predictably, and that predictability matters when you debug. If your loss curve looks like noise, something is mechanically wrong; with adversarial-style training the same curve might mean nothing at all.
A compact comparison:
| Property | What it means | The catch |
|---|---|---|
| Inference ability | Can evaluate for any candidate x | — |
| Sampling | Creates genuinely new data | Sequential, one value at a time — slow |
| Training | True likelihood loss; stable, monotone progress | Stable ≠ good samples |
These methods also stretch across dimensionalities in a straightforward way: the chain-rule recipe does not care what the data looks like. They handle one-dimensional data such as raw audio waveforms, extend to natural language text as sequences of tokens, cover two-dimensional data such as images, and reach three-dimensional data too (for example, volumetric medical scans). One recipe, many shapes of data.
6.1.2 Prerequisites From Earlier Coursework
This course leans heavily on deep-learning basics from the earlier deep neural networks course. Before going further, make sure you are conversant with:
- Backpropagation — how the gradient of the loss reaches every weight by flowing backward through the network graph.
- Gradient descent updates — computing a weight update by hand, where is the learning rate.
- Small convolutions by hand — sliding a kernel over a small grid and computing each weighted sum with a calculator.
- Parameter counting — given a convolutional layer, writing down its number of trainable weights and biases from memory. For example, a layer with 16 filters of size operating on a single input channel has weights plus 16 biases.
PixelCNN will exercise all four skills, and the exam may too.
Exam note: The mid-sem exam may carry questions built around the assignment — expect about two. You will not write code, but you must read a snippet and explain what it does, based only on the lab sheets and the assignment. Nothing will ask you to understand code from material never taught. The questions sit around the assignment rather than on it. Also remember the standing expectation: your assignment observations should tally with what the technical community already knows — agreement with known findings is part of the grading.
6.1.3 Student Questions and Answers
Q: Can we get sample papers early so we have time to practice? A: Past question papers will be shared shortly. Making extra practice questions with ChatGPT works well too — those tend to be quite nice. About two exam questions will sit around the assignment so that practical skills get tested in the exam setting; nothing will demand syntax recall or unseen code. The safe preparation strategy: re-derive your own assignment results until you can explain every line of it aloud.
With the recap done, the session now builds its main character: PixelCNN, the convolutional take on "predict the future from the past."
Recap + bridge: Likelihood-based models can score any sample, train stably, but sample slowly — and the autoregressive trick is to factor the whole data distribution into a chain of per-position predictions conditioned only on the past. Next: how a masked convolution implements that chain for image pixels.
6.2 PixelCNN: Masked Convolutions for Image Density Estimation
Hook: A convolutional network is a champion at recognizing images — but can the same machinery create images, one pixel at a time, while assigning each image an honest probability? The answer is yes, provided you blindfold half of every kernel.
PixelCNN puts convolutional-network machinery to work on pixels. The CNN part of the name points at convolution layers; the pixel part says the input is an image grid. A sibling model, PixelRNN, instead processes pixels row by row with recurrent units such as LSTM cells. PixelCNN processes each pixel through its neighborhood, which makes 2D convolution the natural engine — convolutions are built to combine a pixel's neighbors efficiently, and that is exactly what per-pixel prediction needs.
Real-world: this model family is unusually well served by written walkthroughs. Multi-part blog series cover it from plain CNNs through every variant (one such series lives at thomasjubb.blog), and asking a chatbot "explain PixelCNN and its variant architectures step by step" walks the entire path in textual form with pictures. They make excellent second passes after these notes.
6.2.1 Masked 2D and 1D Convolutions
Picture a standard two-dimensional convolution with a three-by-three kernel. The kernel centers on a pixel and carries weights at all nine positions, so it reads the eight neighbors plus the center. Under an autoregressive ordering, though, some of those neighbors belong to the present or the future. If pixels arrive in raster-scan fashion — left to right along each row, top row first — then everything strictly to the right of a site, everything below it, and even the site's own value has not "happened yet" when we predict it.
Masked convolution fixes this by force: set the kernel entries that touch present-or-future positions to zero. For a raster-scan ordering, the surviving taps are the up-and-left neighborhood:
Kernel position Mask M Surviving weights
w11 w12 w13 1 1 1 past rows: all columns
w21 w22 w23 1 0 0 ← current row: only strict left; center zeroed
w31 w32 w33 0 0 0 future rows: nothing
In words: use information only from the past, and make every future entry zero so the layer physically cannot read it. No cleverness in the training can resurrect a weight that is hard-zeroed — the causality is enforced by the architecture itself, not learned.
The same trick works in one dimension. Center the mask on the current position, zero the center tap and everything after it, and keep only taps from positions that happened earlier. How far back the taps reach is your design choice — a five-tap mask looks further into the past than a three-tap one — but once you fix the data-occurrence convention, you must stick to that masking convention everywhere. Mixing conventions between layers or between training and generation silently corrupts what conditions on what.
Formalize: With mask applied element-wise to kernel , a masked convolutional layer computes
where is the kernel radius ( for ), the input map, the kernel weights, the bias, and zeroes exactly those offsets that reach the current position or anything after it under the chosen ordering. Every symbol here is trainable except , which is fixed by the ordering you chose.
Scope and assumptions: The masked-convolution guarantee holds only while (1) one single ordering is agreed on by every layer, (2) the center tap is zeroed in the layer whose output predicts the pixel itself, and (3) generation proceeds in the same order training assumed. Violate any of the three and the "past only" promise quietly breaks — the model may train happily while reading information it will not have at generation time.
6.2.2 Joint Distribution Factorization and Training Objective
Take an image with pixels, so values in total, and write for the intensity value at the i-th pixel under the chosen ordering. The goal is the probability of the whole image — the joint distribution of through . Estimating a joint over variables head-on is hopeless (for a grayscale image that is a distribution over combinations), but the chain rule of probability turns it into a product of conditionals, each of which is far more learnable:
Compact form, with shorthand for "all pixels before i":
Read it aloud: the probability of the image equals the probability of the first pixel, times the probability of the second given the first, times the probability of the third given the first two, and so on down the line. Nothing about the joint has changed — the chain rule is an identity — but now every factor is a small supervised prediction problem.
To learn this from data, maximize the product over all possible , where ranges over the training images. A product of many probabilities is awkward to handle numerically (hundreds of factors below 1 multiply toward machine zero), so take the natural logarithm; products become sums:
This sum is the log likelihood of the data. Maximizing likelihood and minimizing its negative are the same act, so attach a minus sign and average over the N training images to get the negative log likelihood, usually written NLL:
Here is the collection of trainable parameters (all kernel weights, biases, and softmax coefficients) and is the number of training images. Minimizing the average NLL is exactly maximizing the likelihood — gradient descent on this loss pushes every conditional toward agreeing with the training images.
One factor deserves special mention. The first term, , involves a single one-dimensional value, and a large training set offers many samples of it — so a histogram or similar estimate handles it directly, no network needed. Every later conditional, such as , conditions on a growing list of past pixels, and there a learner is needed. That learner is the masked convolutional network, and this is exactly where the "CNN" in PixelCNN comes from: the network's job is to produce the conditional distributions inside the chain-rule product.
Worked example — from factorization to NLL, with real numbers. Take a tiny binary image (four pixels, values in ) and suppose training has produced these conditionals:
For the image , the joint probability assembles factor by factor:
The log likelihood is . Now score a second image ; suppose the same conditionals give , so . The dataset NLL over these two images is
Sense check: every makes every log non-positive, so the NLL always lands non-negative — and a better model pushes it toward 0, never below. During real training this exact arithmetic happens over every pixel of every image, with the conditionals supplied by the masked network.
6.2.3 Architecture and the Per-Pixel Softmax Head
The pipeline runs as follows. The original data — say a simple RGB or grayscale image — enters a first masked convolution. After that come a bunch of further masked convolutions, standard CNN style, with ReLU activations along the way (occasionally one-by-one convolutions mix feature maps when several filters must interact). The stack produces feature maps, and the feature maps connect to a softmax layer holding the trainable coefficients' output.
Suppose the image is grayscale, so each pixel takes a value from 0 to 255. Rather than treating intensity as a bare number to regress, PixelCNN treats it as a 256-way classification problem per pixel. The softmax head then predicts a full categorical law per pixel:
That is 256 outputs for every single pixel — a MNIST-style image carries output probabilities. Training pushes probability mass onto whichever entry matches the true observed intensity and squeezes the other 255 entries down. Repeat this for every pixel in every training image. Once training ends, the network predicts any pixel's value from whatever happened earlier under the autoregressive ordering you attached — and sampling simply walks the image in order, drawing one value from each predicted law.
So the structure is CNN-like, but its output is the probability of a particular pixel having each intensity level given the training set.
The key difference from a standard CNN is the autoregressive ordering imposed through masking — that is the whole twist. Strip the masks away and you have an ordinary classifier; put them back and every output becomes a conditional law that may read only the past.
Pitfalls:
- Predicting intensities by plain regression (one linear output per pixel) instead of the categorical softmax loses multimodality: when the past admits both "dark" and "light" continuations, a regression averages them into a value that matches neither.
- Forgetting to zero the center tap in the very first layer lets the target pixel leak into its own prediction — the loss collapses suspiciously fast toward zero. If your NLL drops to near zero immediately, hunt for a mask bug.
- Reading the 256-way head as "the network outputs a number": it outputs a distribution; the number only appears once you sample or take the argmax.
6.2.4 Autoregressive Orderings
Nothing forces the raster scan. The famous default — left to right, top to bottom — is named for how the display elements of ancient TV screens used to get lit up, one row at a time: the electron beam swept each row before dropping to the next, and "raster" stuck as the name for that path. Row-wise orderings work too, and more exotic snaking paths work as well; an ordering of this flavor appeared earlier in the course in MADE — the masked autoencoder for distribution estimation — where input units were masked so each output could see only inputs earlier in a chosen order.
The designer owns this choice. You may specify any ordering, for whatever reason you have. The moment you fix it, though, the ordering implicitly fixes the masking structure: attaching to every pixel a notion of which one occurs before which tells you exactly which kernel taps must be zeroed. Raster scan is what people typically use, but the freedom is yours — the mathematics of Section 6.2.2 never mentioned directions, only "before."
6.2.5 Conditioning Across RGB Channels
Everything so far assumed grayscale — one input channel. With multiple color channels, attach an autoregressive ordering across channels as well: R occurs first, then G, then B. Write , , for the three channel values at pixel i. The green value depends not only on the green channel's past but also on what happened in the red data, and blue leans on both:
A note on scope, since the narration leaves it loose: in the standard formulation, the green channel at position i sees all channels of strictly earlier pixels plus the red value at the current position, and blue sees all of that plus green at the current position. So "its own past plus the red data" really means: everything already generated anywhere in the image, with same-position cross-channel reads allowed because R was declared to happen before G. The takeaway stands either way: for color images, each conditional exploits the autoregressive structure inside its own channel and stacks the cross-channel structure on top — R first, then G given R, then B given both R and G. In practice this is implemented by splitting each color's prediction into separate one-dimensional masked operations, one per channel, with slightly different scopes.
6.2.6 First Extensions: Depth, Skip Connections, Gating
Several variants of PixelCNN exist, and their innovations are fairly natural upgrades.
Upgrade one: go deeper. With enough data, more layers should raise the ability to learn the probability density — after training, the NLL should land at a smaller value than a shallow stack achieves. But deep convolution stacks invite vanishing and exploding gradients: repeated multiplication by small derivatives shrinks the error signal until early layers stop learning. The cure is borrowed straight from ResNet: skip connections that let gradients bypass layers, so deep PixelCNN architectures train efficiently. A skip connection adds a layer's input back onto its output, giving the gradient a short highway around the new computation.
Upgrade two: control the flow of past information with a gating structure, in the spirit of LSTM. A gating function — often denoted by a sigmoid — decides which past inputs deserve weight and which do not. A filter function — a hyperbolic tangent — then decides how much of the chosen information passes into the density calculation. Multiplying the two, element by element, gives fine control over what the estimate uses. Both upgrades reappear concretely under Gated PixelCNN next — and they arrive together with the fix to PixelCNN's most famous flaw, the blind spot.
Recap + bridge: PixelCNN factorizes the image distribution into per-pixel conditionals via the chain rule, learns them by minimizing NLL, and computes each conditional with kernels masked to read only the past under a designer-chosen ordering. But stacking those 2D masks has a hidden geometric cost — some legitimate past pixels never enter anyone's view. Next: the blind spot.
6.3 The Blind Spot Problem
Hook: PixelCNN follows one simple rule — condition on every past pixel. Here is the uncomfortable discovery: it does not, and no amount of training will make it. A whole wedge of the legitimate past is invisible to the network, purely because of how masked windows stack.
Every later variant exists largely because of one structural flaw in plain PixelCNN, so this flaw deserves careful attention. It is known as the blind spot.
6.3.1 How Stacked Masks Lose Pixels
Set the scene: raster-scan ordering, and you want — the law of one pixel given all pixels before it. Intention says every past pixel should inform the estimate. Now inspect what the machinery actually sees.
At the target pixel's own layer, a three-by-three masked kernel reads only the up-and-left neighbors — the left column and the top row of its window; the center and right taps are zeroed. So layer one sees a small L-shape hugging the target's top-left.
Deeper layers widen the view, but watch how the widening behaves. Layer two aggregates layer-one outputs, each of which read their own up-and-left L-shapes. Composing the two, layer two effectively sees one more ring up-left; layer three, another. The reachable region grows diagonally toward the top-left corner. Trace which cells have been touched after three such doublings:
Rows above target (each symbol = whether that pixel feeds the target)
row i-3 : X X X . . . X = reached by some stacked mask
row i-2 : X X X . . . . = blind spot (valid past, never read)
row i-1 : X X X X X .
row i : X X ? ? = target; left neighbors are fine
↑
columns strictly left of the target, low rows: unreachable
The upper-right part of the past gets covered as depth grows, and the directly-left pixels do get used. But a stair-shaped wedge of legitimate past pixels — sitting below-left of the diagonal growth path, in rows between the higher rows and the target's own row — never enters anyone's view. Information from those pixels simply never contributes to the probability of the target.
A concrete way to feel it: take an image, change one pixel located down-and-left of a target, and recompute the model's probability for that same target. Nothing moves. The model is provably indifferent to information the ordering says it should be using.
6.3.2 Why the Blind Spot Matters
Name the quantity at fault: the receptive field, meaning the region of the original input image that can influence a unit's output through any path of stacked layers. In ordinary CNN terms, receptive fields grow with depth — with kernel width three, layer one sees three inputs, layer two five, layer three seven, and so on. Masked convolutions inherit that growth but clip its direction: only up-and-left expansion survives the masks.
The design intent is to condition on all pixels numbered 1 through . The two-dimensional masking structure breaks that promise — pixels arranged in the staircase pattern go unused, and for a target sitting low in the image, roughly half of the valid past can be lost. Half of the evidence, silently discarded from every probability estimate.
So although we intend to use every past pixel, the masking lets us consume mainly what lies diagonally up-left; right-side history survives (through later rows' wide top-row coverage), bottom-left history does not.
Pitfalls:
- Assuming "masked convolution" automatically means "correct autoregressive conditioning." The mask enforces causality per layer, but stacking changes which past is reachable.
- Confusing the blind spot with small receptive fields generally: even a deep plain PixelCNN never recovers the staircase wedge, while it does grow coverage elsewhere. Depth alone cannot fix a shape problem.
- Testing causality only by checking that future pixels cannot leak in. The failure here is the opposite one — valid past pixels failing to contribute.
Eliminating this defect became the first order of business for every successor design — and Gated PixelCNN, next, does it with a surprisingly simple geometric trick: split the single diagonal-growing 2D mask into two clean 1D passes.
Real-world: why care about a subtle conditioning flaw? Every downstream consumer of these probabilities — anomaly detection on manufacturing images, compression, conditional generation — inherits whatever the receptive field ignores. A model blind to half its past assigns the same likelihood to images differing in exactly the details it cannot see, which quietly caps how good any sample or score can get.
Recap + bridge: Stacked masked kernels grow their reach diagonally up-left, stranding a stair-shaped wedge of valid past pixels outside every receptive field — roughly half the conditioning evidence for low targets. Next: Gated PixelCNN kills the blind spot with vertical + horizontal convolution streams and adds LSTM-style gating.
6.4 Gated PixelCNN
Hook: One architectural idea — splitting one diagonal mask into a vertical pass plus a horizontal pass — makes half the lost past reappear. Gated PixelCNN arrived right after PixelCNN carrying exactly that fix, plus the LSTM-style gating sketched earlier.
6.4.1 Vertical and Horizontal Convolution Split
Rather than one masked two-dimensional convolution, Gated PixelCNN runs two passes, one after the other.
First comes the vertical convolution: a stack-style pass going down the rows, using a mask that reads only rows strictly above the current position (never the current row itself). Process the whole image this way and you hold a vertically convolved map in which every site has aggregated all past rows above it — every column, every width, nothing skipped. A column-only mask has no diagonal growth to hide information in, so no vertical blind spot can exist by construction.
Then apply a horizontal mask to the result of the vertical pass, reading only the current row's prefix — positions strictly to the left on the same row. Any past pixel is now reachable. Pixels above the current row travel through the vertical stream; pixels earlier in the same row travel through the horizontal stream. The union covers everything that happened in the past — the blind spot problem is gone.
Vertical stream sees: Horizontal stream sees:
. . . . . . . . . .
. . . . . rows above ← ? . . . current-row prefix only
. . . . . (all columns) (then combined with vertical output)
─────────
← ? . . . nothing below ? = target pixel
In short: plain PixelCNN uses one 2D masked convolution; Gated PixelCNN breaks that 2D mask into a vertical piece and a horizontal piece, does the vertical piece first, and feeds the horizontal piece on top of the vertical output.
Scope: The split restores reachability of the whole past, not automatic use of it — the network still learns which pixels matter. It also roughly doubles the per-layer computation (two convolutions instead of one), a cost later variants weigh against attention-based alternatives.
6.4.2 Gating and Residual Blocks
On top of the split sits the gating structure, just as in LSTM-kind architectures. Written out, the controlled signal is a gate times a filter, combined element by element:
where is the sigmoid function , producing values between 0 and 1 and acting as the gate selecting which past inputs deserve weight; is the hyperbolic tangent, producing values between −1 and 1 and acting as the filter setting how much of each selected input passes; and denotes element-wise multiplication of equally shaped feature maps. A sigmoid near zero slams a feature channel shut; near one it flings it open. The filter then shapes how much, signed positive or negative, of each opened channel flows into the current pixel's density estimate.
Worked example — one gating computation, element by element. Suppose for two feature entries the pre-activations are and .
Step 1, gate values: (channel wide open) and (mostly closed).
Step 2, filter values: and .
Step 3, multiply element-wise:
Sense check: both outputs sit in , as they must, since and . Notice entry 2: a huge filter response (0.995) still lands small because the gate keeps it nearly shut — gating lets the model ignore available information, which is exactly the freedom the blind-spot repair needs to exploit its now-complete receptive field.
Every one of these weights — the vertical-mask kernel, the horizontal-mask kernel, the gate weights, the filter weights — is learnable, and they are learned as part of the overall loss-minimization process. Nothing about the masks or gates is hand-designed beyond their zero patterns; minimizing the NLL trains the filters, the masks, and both gating components together, end to end.
Depth safety comes from a ResNet block: the skip connection reduces the vanishing-gradient problem so the architecture can grow, and a deeper stack approximates the density better.
6.4.3 NLL Results on CIFAR-10
Here is the payoff measured as NLL on the CIFAR-10 image dataset — the same dataset family as the assignment, reported in bits per pixel dimension (smaller is better). A baseline near 3.14 falls to 3.03 for Gated PixelCNN on the validation/test side, with the training-side figure shown alongside. Read it this way: smaller NLL means a better probability estimate, and the drop from 3.14 to 3.03 is the improvement. To pin down the comparison rows precisely: the 3.14 figure belongs to plain PixelCNN (its published test score, with about 3.08 on the training side), while Gated PixelCNN reaches 3.03 test (about 2.90 train) — and for context, the recurrent sibling PixelRNN sits near 3.00 at a much higher sampling and training cost. So the gated redesign closes most of the gap to the LSTM-style model at less than half the training expense.
Two causes earn the gain. Better receptive field, delivered by the vertical-plus-horizontal decomposition that removes the blind spot — the model finally conditions on all the evidence the ordering promises it. More expressive architecture, delivered by many ResNet-like layers plus the gating mechanism deciding which and how much past information enters each estimate.
| Model | Test NLL (bits/dim) | Blind spot? |
|---|---|---|
| Plain PixelCNN | ≈ 3.14 | Yes — stair-shaped wedge unused |
| Gated PixelCNN | 3.03 | No |
| PixelRNN (recurrent sibling) | 3.00 | No |
Real-world: this decomposition-plus-gating pattern — factor a global operation into clean directional streams, then let learned multiplicative gates route information — recurs across generative modeling, notably in WaveNet-style audio models where the same gated unit generates raw speech waveforms sample by sample.
Exam note: Remember the NLL comparison cold: baseline about 3.14 versus Gated PixelCNN 3.03 on CIFAR-10, and be ready to explain why smaller NLL means a better probability estimate and which architectural changes bought the improvement — blind-spot removal through the vertical/horizontal split, plus gating.
Recap + bridge: Two orthogonal streams cover all rows above and the current row's prefix — no stranded wedge — while sigmoid-gate-times-tanh-filter blocks and ResNet skips deepen the model safely, dropping CIFAR-10 NLL from about 3.14 to 3.03. Next: PixelCNN++ attacks a different weakness entirely — the wastefulness of those 256-way softmax heads.
6.5 PixelCNN++
Hook: What if the biggest problem with your image model is not its architecture but its output layer — 256 independent categories per pixel, most of them predicting values that almost never occur? PixelCNN++ starts exactly there.
The next variant, PixelCNN++, attacks a different weakness: the sheer wastefulness of predicting 256 independent categories per pixel.
6.5.1 Wasteful 256-Way Softmax Outputs
Both PixelCNN and Gated PixelCNN stack masked convolutions, sprinkle ReLUs, sometimes add one-by-one convolutions when multiple filters mix at a layer, and finish with a softmax. For a grayscale pixel that means 256 softmax nodes per pixel — one output node for each possible intensity — and the winning node names the pixel's value. Memory requirements balloon, and much of the machinery is redundant.
Why redundant? In real images, neighboring pixel values sit close together most of the time. If a pixel holds intensity , its predecessors likely held , or , or — not . The exceptions are edges and color changes, but count the edge pixels in a typical natural image and they form a small fraction of the total — a few percent. An unrestricted 256-way law spends its capacity on empty ground: wasted memory, far more parameters to estimate, more training data consumed, longer training time, heavier compute. It is an inefficient design.
The design insight: replace "256 unrelated categories" with "a smooth little distribution centered near what the neighbors suggest." A continuous, low-parameter law that concentrates mass around plausible intensities captures the same information with a handful of numbers.
6.5.2 Mixture of Logistics Output Law
PixelCNN++ keeps the fact that nearby intensities co-occur and rebuilds the output around it: express the pixel-value law as a mixture model — specifically a mixture of logistic distributions:
Here are the mixture coefficients (non-negative weights that sum to one, saying how much each component contributes), the mean of each logistic component (where its bell peaks), and its scale — the spread, playing the role that standard deviation plays for a Gaussian. Recall the mixture-of-Gaussians work from the machine-learning course's unsupervised clustering part: a batch of mixing coefficients learned alongside component parameters by iterative optimization. The same skeleton applies here, learned during PixelCNN++ training by gradient descent on the NLL — typically with small , such as ten components per pixel channel, instead of 256 free category probabilities.
What does a logistic distribution look like? Close to a Gaussian, but slightly flatter — a bit broader in the shoulders around the peak. Its density is
with setting the width. Now the fact the speaker hedged on ("I'm not sure, but I think…") can be settled outright: yes, this density integrates to exactly the familiar sigmoid curve. Differentiate using the chain rule and the sigmoid derivative identity :
where writing turns the last equality into algebra: . So the area under the logistic density from up to is precisely
the sigmoid curve — rising smoothly from 0 to 1, steepest at the mean . A Gaussian mixture could serve too, but logistics reportedly fit image intensities better and give more realistic behavior in intensity space.
6.5.3 Discretizing the Continuous Density
One wrinkle: the mixture is a continuous law over real-valued , while pixel intensities are discrete integers — 0, 1, 2, and so on up to 255. The bridge is a differencing trick applied to the mixture's cumulative distribution function (CDF):
In words: the probability that the integer-valued pixel equals is the probability mass the continuous law places inside the half-unit-wide window straddling . Nothing deeper is happening — a continuous density becomes a discrete, binned representation, one bin per integer, each bin half a unit on either side of the integer.
Worked example — probability that an intensity equals 170. Suppose one dominant logistic component carries , . Using :
Step 1: read the CDF just above the integer:
Step 2: read it just below:
Step 3: subtract:
Sense check: the window sits symmetrically around the peak , so it should capture a large chunk — about a quarter — of the component's mass; 0.245 fits. With a full mixture you simply repeat this subtraction per component and add them weighted: for components and ,
Every step used nothing beyond evaluating the sigmoid and adding weighted pieces — that is all "discretizing a continuous mixture" ever involves.
6.5.4 Reading the Logistic PDF and CDF Plots
The plots reward a careful look — they are the same object seen twice. Each logistic PDF is a bell peaking at its mean (horizontal axis: intensity ; vertical axis: density ), and the scale sets how rapidly the values fall off around that peak. The CDF of any density integrates the PDF from minus infinity up to ; it rises from 0 toward 1 and its maximum value is exactly 1.0, because total probability must sum to one.
For the standard member with and , the bell is narrow, so the CDF climbs sharply in a small window — nearly vertical around the origin. Take instead the wide member — the red curve with standard deviation 4 in the demonstration plot — and its CDF rises smoothly and gradually over a span several times wider.
The reading rule that makes these curves useful:
- Steep CDF ⇒ packed mass. Most pixels in a narrow range, few outside. A model confident about a pixel's neighborhood looks like this.
- Gentle CDF ⇒ spread mass. Plenty of pixels between minus 5 and plus 5 relative to the mean, few clustered tightly at the peak — the model hedges.
Learning to read CDF steepness is learning where a density stores its data: the steep segment of the CDF sits directly above the dense part of the histogram, and flat segments above the empty parts.
6.5.5 Downsampling and Long-Range Structure
PixelCNN++ also adds downsampling to capture long-term dependencies — because even with the blind spot fixed, stacking local convolutions means distant pixels influence each other only through many layers. Six residual blocks form the backbone — residual connections again, letting many layers cooperate on approximating the density. Along the way the maps shrink: the original drops to , then to . Then the maps grow back — holds, then , then . Skip connections join the same-size maps across the squeeze.
Why does shrinking help reach? Each convolution sees a fixed neighborhood; halving the map size doubles how much image one position effectively stands for. After two downsamplings, a single position aggregates evidence spanning a large share of the whole image — long-range structure becomes cheap. The arithmetic is stark: a convolution operating on an map touches 64 positions instead of the 1,024 positions of a map — sixteen times less work per filter — which is exactly what lets the model afford enough depth to use that reach.
Trace — the squeeze-and-expand path. (downsampling stages, coarse structure accumulates) (upsampling stages, fine detail restored). At every matching scale a skip connection carries the encoder-side map straight across — , — so spatial detail lost in the bottleneck is re-injected rather than re-invented. Sense check: the final map matches the input size, as it must for per-pixel prediction.
The measured NLL lands at 2.92 — a real drop against the 3.14-and-3.03 figures above, earned by the mixture output head, the downsampling backbone, and the residual blocks together. Worth noting: PixelRNN also does reasonable work in this league, processing rows in one-dimensional fashion left to right with recurrent units.
Real-world: the discretized-mixture-of-logistics trick now appears far beyond PixelCNN++ — any model that must produce integer-valued data (pixel values, audio sample codes, token IDs) borrows the same CDF-differencing bridge between continuous densities and discrete data.
Recap + bridge: PixelCNN++ swaps 256 free categories for a mixture of logistics whose CDF gets binned into integer probabilities, and adds a downsample-upsample residual backbone — NLL falls to 2.92 on CIFAR-10. Next: PixelSnail replaces convolution's bounded window with attention's unlimited reach.
6.6 PixelSnail: Masked Self-Attention
Hook: Every variant so far still gathers the past through windows — three-by-three, five-by-five, a few rings deep. What if a pixel could look at every pixel that came before it, in one step, without stacking dozens of layers? That is PixelSnail's bet.
The last variant swaps convolution's locality for attention's reach. PixelSnail stands for improved likelihood thinking fused with a non-local, transformer-style mechanism.
6.6.1 Attention versus Convolution
Every variant so far gathers past information through convolutions. Even with the 2D-mask broken into 1D pieces and many layers stacked, the reachable past stays limited unless the network grows very deep — each layer extends reach by only a few pixels. Self-attention removes that ceiling.
Convolution couples each site to a fixed window — a three-by-three or five-by-five mask, a bounded extent of information no matter what the content is. Self-attention, especially in transformer form, lets every position consult every other position through matrix-vector multiplications: each site emits a query ("what am I looking for?"), every other site offers a key ("what do I contain?"), and query-key matches — scaled and passed through a softmax — decide how much of each site's value (its content) flows back. Distance plays no role: pixel 5 can attend to pixel 500 as easily as to its neighbor.
Applied to an autoregressive model, it wears a mask: masked attention zeroes access to the future, enforcing causality — before the softmax over keys, any key sitting at or after the current position is set so it receives zero weight. Masking supplies the order in which information operates — and that order remains a designer's choice, exactly as before. Whatever autoregressive structure you design dictates the masking strategy that guarantees causality.
There is a practical bonus. Encoding a fancy custom ordering as a zero-one kernel pattern for masked convolution is cumbersome — you must redesign the 0/1 layout by hand for each new ordering, and verify no tap leaks. Doing it with attention is much easier, because the choice point is explicit everywhere: for each query site you simply declare which keys it may read — flip one boolean per pair, done.
The transformer toolbox carries over wholesale: multi-head self-attention — several attention computations in parallel, each free to hunt for a different kind of dependency — plus the usual feed-forward blocks from the earlier deep-learning treatment all apply here, with the single standing rule that no future information may leak.
6.6.2 Receptive Field Wins and Compute Costs
Set the variants side by side on receptive field:
| Model | How the past is gathered | Effective receptive field |
|---|---|---|
| Plain PixelCNN | Stacked 2D masked kernels | Diagonal growth; stair-shaped wedge lost |
| Gated PixelCNN | Vertical + horizontal streams | Full past reachable, but only after enough depth |
| PixelCNN++ | Same split + downsampling stages | Full past; long-range links via bottleneck |
| PixelSnail | Masked self-attention | Everything available at the current point, in one layer |
Standard PixelCNN wastes much of its usable past — significant information loss. Gated PixelCNN loses less, helped by its decomposition and extras. PixelCNN++ sees part of the past directly and the rest through its downsampled bottleneck. PixelSnail, thanks to masked attention, uses everything available at the current point immediately.
The reward shows in the numbers: PixelSnail pushes the NLL down to the smallest values in this lineup. The price: training is slow, and the transformer backbone is computationally expensive — attention compares every position against every other, a cost that grows quadratically with the number of positions, whereas a convolution touches each position with only its small window.
Real-world: this exact trade — attention's global reach bought with quadratic cost — is the defining engineering tension of modern sequence models; managing it (through sparse, linear, or windowed attention) is a whole research area, and image autoregression was one of the first places the tension showed up.
Recap + bridge: Masked self-attention gives each pixel immediate access to its entire past, lifting NLL below every convolutional variant at a steep computational price — and the masking-as-ordering principle survives unchanged from convolutions. Next: how conditioning inputs turn this whole machinery into a directed tool for labels, super-resolution, and colorization.
6.7 Conditional Generation with PixelCNN
Hook: Everything so far generated "an image, any image." But suppose you want a five, or the high-resolution version of this thumbnail, or colors for this sketch. One small change to the input delivers all three.
Plain PixelCNN learns the unconditional law of images — . Feed it side information during training and generation, and the same machinery serves directed tasks: the law becomes .
6.7.1 Class-Conditioned Generation
Train a PixelCNN on MNIST — handwritten digits from 0 to 9, the same kind of data as the assignment. At generation time you may want only fives. The mechanism: encode the label as a one-hot vector — one followed by zeros, a different position hot for each digit 0 through 9 (so digit 5 is ) — and inject this encoding, call it , into the network during both training and generation. The model then learns instead of plain .
A few extra weights learn how should bend the density — typically by adding 's contribution into the feature maps at every layer, including inside the gating functions, so the condition can open or close information pathways rather than merely nudge one output. After training, fixing to the digit-5 slot steers every sample onto fives; sliding through walks the model across the whole alphabet of digits. During training the true label rides along with every image, so each conditional in the chain-rule product quietly becomes label-aware.
6.7.2 Super-Resolution and Colorization
Super-resolution works the same way with a spatial condition instead of a categorical one.
Worked example — building the low-resolution condition map. Take the original image and average non-overlapping four-by-four blocks, replacing each block of 16 pixels with its single average value.
Step 1: count the grid — blocks per side, so the coarse map is , each entry the mean of its block:
Step 2: for a block whose sixteen intensities average, say, 200, the coarse map stores 200 there — a blurry but faithful thumbnail. Corresponding to the real image you now hold a low-resolution embedding.
Step 3: during training, pass this coarse map in as conditioning information alongside the fine image, so the model learns the law of high-resolution pixels given their low-resolution context — . After training, supply any low-res map and the model generates the full-resolution version. Bold takeaway: as long as training saw low-res and high-res pairs, the conditional law is yours to sample.
Color creation follows identically: condition on the grayscale version and generate colors, learning and going from grayscale to color images. Nothing about the network changes across these three tasks — labels, thumbnails, and gray channels are all just extra inputs.
Pitfalls:
- Conditioning must be present in both phases. Train unconditionally and inject only at test time: the network has never learned what means, so it ignores it.
- For super-resolution, the low-res map must be built the same way at train and test time (same block size, same averaging) — mismatched pipelines shift the meaning of the condition.
- The model samples plausible detail, not recovered ground truth: super-resolved textures are inventions consistent with the blur, which is why evaluation compares distributions, not exact pixels.
Real-world: class-conditioned sampling, super-resolution, and colorization all reduce to one recipe — send conditional information in as another input during probability-density learning. The same pattern powers practical tools today: text-conditioned image generators are the scaled-up descendants of exactly this conditioning idea, and photo-restoration pipelines use learned conditional laws for deblurring and colorization of archival material.
Recap + bridge: One mechanism — append side information to the inputs — converts an unconditional pixel-law learner into a class generator ( = one-hot label), a super-resolver ( = averaged thumbnail), or a colorizer ( = grayscale image). Next: step back and ask what we ever wanted from a generative model in the first place.
6.8 What We Want From a Generative Model
Hook: Before meeting a new family of models, do what a shrewd customer does before shopping: write the wish list first. Five wishes cover everything we could ask of a generative model — and almost no model fills every slot.
Before flows, reset the scoreboard: what should any generative model deliver?
6.8.1 The Bucket List
Five wishes, in order.
- Estimate the probability distribution from training data, obtaining with learned parameters .
- Sample from that distribution — and remember how big sampling lives: even a small image is 784-dimensional data, and a bag-of-words text over a vocabulary of 1,000 lives in 1,000 dimensions. Sampling well in high dimensions is genuinely hard.
- Train stably, watching a well-behaved loss fall.
- Evaluate fresh samples — after generating new data, say how likely it is. This is the self-audit wish: a model that can score its own outputs can be compared against others on equal terms.
- Carry a meaningful latent representation or embedding space: a smaller-dimensional code for the data — of the kind an autoencoder's coding layer provides — from which you can even sample to create new data.
All five sit in the bucket list; almost no model fills every slot. Each family you meet is best understood by which wishes it grants and which it quietly drops.
6.8.2 Scoring Autoregressive Models and Previewing Flows
Score the autoregressive family honestly against the list:
| Wish | Autoregressive models |
|---|---|
| Estimate | Yes — explicit density via the chain rule |
| Sample | Yes, but sequential and slow |
| Train stably | Yes — true likelihood loss |
| Evaluate new samples | Yes — just run the factorization |
| Latent representation to sample from | No |
Good fit to training data: yes, especially with many layers. Ability to evaluate how likely a new is: yes. Ability to sample: yes. Drawbacks: sampling is sequential and slow; there is no latent representation to sample from; and the family shines mainly on discrete data — image intensities 0 through 255, for instance — at least where it has proved most effective.
Flow models promise every capability on the list, with solid mathematics underneath: an explicit density (via change of variables), sampling (invert the transform), stable likelihood training, evaluation for free, and — the wish autoregressive models drop — a genuine latent space you can sample from.
Their historic weak spot is qualitative: the raw samples trail the best later models. Newer work narrows that gap — TARFlow, a Transformer-based autoregressive flow out of Apple around 2024, performs very well indeed. One more upfront note: flows are born in the continuous domain, and a minor but important adaptation called dequantization bridges the continuous formulation to discrete images and text; that arrives next session.
Real-world: the bucket list is not academic bookkeeping — it is the checklist practitioners actually run when choosing a generative approach. Need certified likelihoods (compression, anomaly detection, scientific density estimation)? Wishes 1 and 4 dominate. Need fast high-quality generation for media? Wish 2 dominates, and families that sacrifice likelihoods often win.
Recap + bridge: The five-wish list exposes exactly where autoregressive models stop: no latent space, slow sampling, discrete-data comfort. Normalizing flows claim all five wishes — next section builds them from one probability identity.
6.9 Foundations of Normalizing Flows
Hook: Could you learn a complicated probability law by learning a reversible machine that warps it into one you already know how to sample — a plain Gaussian? That single idea is a normalizing flow, and it rests entirely on properties of derivatives of probabilities. Build from the ground up.
Flow models lean significantly on probability and statistics — specifically derivatives of probabilities and how they behave under transformations. Every tool used below is rebuilt here from first principles, so the construction needs no outside machinery.
6.9.1 Probability Refresher: Densities and Integrals
For a continuous random variable , the function is the probability density function (PDF): a non-negative curve whose total area is exactly 1. A density itself may exceed 1 at a point — only areas carry probability. The chance that falls between two points and comes from integrating the density between them:
Concrete instance: suppose the interesting window runs from 0.35 to 0.45. Given the density curve , compute as the integral from 0.35 to 0.45 of of , . Geometrically: calculate the area under the curve over that window — the area under the curve is the probability. On axes labeled "" (horizontal) and "density" (vertical), the region between the curve, the horizontal axis, and the two vertical cuts at 0.35 and 0.45 is exactly the answer.
Q: Suppose we skip the integral — how else could we compute the probability between 0.35 and 0.45? A: Break the interval into pieces and turn integration into summation. Evaluate the density at each slice, multiply by the slice width, and add everything up — the sum replaces the integral and still approximates the area under the curve.
Worked version of that answer, with real numbers. Split the span into ten slices of width each (the narration's loose "multiply all of them by 0.1" should read this way: the whole interval is 0.10 wide, so ten equal slices are 0.01 wide apiece). Take a concrete rising density, on , whose values at the left edges run from 0.70 up to 0.88:
The ten left-edge heights sum to , so the estimate is . Sense check: integrating exactly, — the slice sum lands just under it, because every left-edge height slightly undershoots a rising curve. Smaller slices close the gap; in the limit of infinitely many, sum becomes integral.
Hold onto this pairing — integral equals area, summation approximates it. It is the kind of thing worth remembering years from now.
6.9.2 Fitting Densities by Maximum Likelihood
How do you fit a density model to data? Maximize the likelihood. Assume samples are independent of one another; then their joint probability is the product of individual probabilities:
Maximize this product over the parameters . Products are hard to evaluate and differentiate (hundreds of factors below one multiply toward zero), so take the natural logarithm — products become sums:
Flip the sign and minimize the negative log likelihood instead — in practice the average over all training samples:
Different density families plug into the same recipe. Choose a plain Gaussian and minimization hands you the mean vector and the covariance matrix in closed form. Find a Gaussian too restrictive — real histograms are lumpy, skewed, multimodal? Use a mixture of Gaussians:
Here are mixture weights (, summing to 1), the constituent means, and the constituent standard deviations. On the one-dimensional slide shown, sigma runs through as plain standard deviations; multidimensional Gaussians demand covariance matrices instead. More components, more bumps — mixtures can hug arbitrarily complicated histograms, which is precisely why they will reappear as flow building blocks later in this session.
6.9.3 The Flow Idea: Learn a Push to a Simple Law
Now the main construction. Start from a training sample — treat it as one-dimensional, a scalar, not a vector. Plot all training samples as a histogram: that histogram is the empirical probability distribution of the data. The ambition is an analytical function for that law — a closed-form expression mixing exponentials, powers, and logarithms — because once an analytical law exists, a CDF follows, and sampling follows the CDF.
Here is the sampling link worth internalizing. Build the CDF from the analytical density by integrating from minus infinity to ; the CDF climbs from 0 to a maximum of exactly 1.0, since probabilities sum to one. Draw uniformly along the CDF's vertical axis — pick a random height between 0 and 1 — then read across to the value beneath that height. Each such readout is one sample obeying the law: tall dense regions occupy large vertical stretches of CDF, so uniform draws land there often; thin regions barely register. Generating new data, then, means generating an analytical probability distribution and sampling it.
The flow model builds that analytical distribution by pushing data through transformations. Apply a transformation to , feed the result to , continue through :
These transformations are not handed down — they are designed as part of training, realized as layers of a deep network. The training goal: choose them so that the pushed data obeys a simple law. should be a uniform distribution, a Gaussian, a mixture of Gaussians — something with a closed form you can sample easily. Generation then runs the movie backward: sample from the simple latent law, pass it through the inverse transformations, and a new data point falls out. That is the whole idea at altitude: learn transforms that push data to a simple latent law, then invert them to create.
An everyday picture for the push: think of kneading dough. Each layer folds and stretches the dough a little more; after enough folds, an originally lumpy blob becomes a smooth, uniform ball. Training learns the folding recipe; generation un-folds a smooth ball back into a lumpy — but realistic — shape. The analogy breaks where it must: dough folds lose information, while flow layers are forbidden from losing any (next subsection).
6.9.4 Invertibility: Which Transformations Qualify
Generation travels the chain backward, so the forward map must be one-to-one — a bijective transformation: start from one data point, go forward, invert, and exactly one point comes back, never several. If the inverse of were not a unique partner, sampled latents would spawn multiple candidate outputs and generation breaks down — which half of the ambiguity do you render?
Q: Is a bijective, one-to-one transformation? A: No. Fix ; both and produce it, so the inverse cannot decide, and even powers are not invertible. Odd powers behave: keeps the sign of its input — , — so odd powers stay invertible while every even power folds two inputs into one output.
This exchange corrects a tempting shortcut ("powers are fine, aren't they?") and hides the general rule: admissible transformations are monotonic — rising everywhere or falling everywhere, never changing direction. A parabola changes direction at its vertex, so it fails; a cubic never does, so it passes. Equivalently, check the derivative: if flips sign anywhere, some pair of inputs collides.
One honest caveat, flagged upfront: many people suspect this invertibility-only restriction is why classical flows occasionally trail newer generators in sample quality — constraining every layer to be one-to-one may throttle the method's data-generation ability. Newer designs chip away at exactly this suspicion, adding expressive power without giving up the reversible guarantee.
6.9.5 Change of Variables
Everything now rests on one probability identity. Write , where is the learned transformation, the training data, and the transformation's parameters; must land in a simple, analytical, samplable law. The variable carries its own density , and carries another, . Both are probability laws, so both integrate to one:
That shared-total-probability fact forces the two densities to move together wherever the transformation stretches or squeezes space. Here is the derivation, every step annotated. Assume first that is monotonically increasing:
If is decreasing instead, the integration bounds swap and a minus sign appears; a density can never be negative, so the general statement keeps the magnitude of the slope:
Read it aloud: the density at equals the latent density evaluated at the transformed location, times the magnitude of the transformation's slope. The intuition matches the stretching picture: stretch a region of the axis and its probability mass spreads thinner (slope above 1 lowers the density); compress it and mass piles up (slope below 1 raises the density). The absolute value exists because a probability density function must stay positive — slopes may be negative, densities may not. A notation care-point: the here belongs to the transformation, not to a fitted density; if , then bundling the coefficient and the cube into describes the whole map at once. Textbooks sometimes write the equivalent form in the other direction — with generatively, — which agrees with ours because inverting a map reciprocates its slope.
Worked example — stretching a uniform density. Let follow a uniform distribution between 0 and 1: flat height 1 across the unit interval, so the enclosed rectangle has area . Define , and ask what law obeys.
Step 1: range. As sweeps , sweeps — the output range doubles to span two units.
Step 2: apply the rule. Here is the output of the map , so use the reciprocal reading of the identity — the density of an output equals the input density at the corresponding location divided by the slope:
Step 3: sense-check by area. Width doubled ( units) and height halved (), so the enclosed area is — total probability survives intact, as it must. Bold takeaway: stretching a density horizontally squashes it vertically; total probability refuses to change. Run the same map backward as a flow layer () and the height doubles instead — same law, opposite direction, area still 1.
Q: On the diagrams, the vertical axis reads — is the second plotted curve showing ? A: No — the plotted curve is the density of the training data itself, the empirical histogram of the samples. Nobody knows its closed form; that is exactly what we want to learn. Modeling it with, say, a mixture of Gaussians would mean collects the mixture weights through , the means through , and the sigmas through . The task is to find the best analytical approximation to that empirical red curve — not to plot the latent law.
6.9.6 The Flow Training Objective
Training a flow means maximizing likelihood, now powered by the change-of-variables identity. Take natural logs of both sides — the product inside turns into a sum of two terms:
Sum over the training set and optimize:
Two terms, two messages. The first rewards placing transformed data where the latent law is generous — land your pushed points near the peak of and that term grows. The second rewards transformations whose slope spreads the mass appropriately — squash everything into a tiny interval and the slope term punishes you, because a small makes its log deeply negative. Neither term alone suffices: cramming data onto the latent peak with a collapsing map scores well on term one and terribly on term two.
Equivalently, minimize the negative of this sum; practitioners speak of driving the NLL small. Either way, stochastic gradient descent adjusts the parameters of the transformation layers across the whole training set.
Trace — evaluating the objective on the toy map. Take the compressed map , a latent uniform on with , and the data point .
Step 1: forward location. , inside the latent support. Step 2: latent term. . Step 3: slope term. everywhere, so . Step 4: total. , i.e. — exactly the height of the original unit uniform. Bold takeaway: the objective reconstructs the true density on . Sense check: the two terms cancel for a pure translation-and-rescale that maps uniform to uniform, as they must.
Once training ends, is frozen, and generation is trivial: draw from the latent law — under a standard normal, sampling is as easy as it gets — and apply to harvest a new . Notice the latent-representation wish from the bucket list quietly granted: the -space is exactly a meaningful latent space you can sample from to get the original data back. And the name finally earns itself: "normalizing flow" means lands on a normal Gaussian with mean zero and standard deviation one.
6.9.7 Choosing Invertible Functions
Which function families qualify as layers? The monotonic test from earlier is the gatekeeper, and it sorts candidates quickly.
The quadratic fails: rising on one side of zero, falling on the other — its derivative switches sign, so it folds inputs together and cannot be inverted. The cubic passes: monotonic through the origin, one output per input.
A rich, easy-to-adopt class follows immediately: polynomials carrying only positive coefficients and only odd powers, such as with all . Every member is monotonic — each term rises everywhere and positive sums of rising terms rise — so each can be inverted. More candidates: the exponential works (strictly increasing for any real ); the shifted scaled sigmoid with works (sigmoid is monotonic, and positive scaling plus shifting preserves that); and so do cumulative distribution functions — the CDF of a mixture of Gaussians, or weighted sums of logistics — because every CDF rises from 0 to 1 by construction.
Composition closes the system neatly: apply one transformation, then another, then another — and the entire chain can be replaced by a single equivalent transformation (the composition of the parts, whose slope is the product of the individual slopes). Flows obey composition, which is why stacking invertible layers stays principled: depth adds expressiveness without ever endangering reversibility.
6.9.8 Watching a Flow Learn: Worked Walkthrough
Make the abstraction concrete with the picture sequence. Begin with the raw training data and its histogram — a lumpy empirical distribution, perhaps with scattered sample dots around it. Pick an arbitrary starting transformation . Push the histogram through it: the transformed histogram comes out misshapen — not Gaussian yet, just differently lumpy.
Now run the training procedure from Section 6.9.6 with fixed as a standard Gaussian. Iteration by iteration, gradient steps reshape wherever the objective complains: points pushed into low-latent-density zones drag on the first term; over-compressed stretches drag on the slope term. Afterward, pushing the original data through the learned transformation produces a histogram closely matching a Gaussian bell — the learned transformation has bent the data's law onto the target law.
Swap the target to a uniform distribution and repeat: the starting transformation tunes itself into a different final shape, and the empirical distribution of flattens to uniformity. Generation completes the loop: sample from the tidy latent law — this sample is your latent-space draw — pass it through the inverse flow, and a brand-new appears, distributed like the training data. In one sentence: a trained flow reshapes the empirical histogram toward the chosen latent law, then runs backward to create.
6.9.9 CDF Parameterization and Layer Choices
One observation ties the pieces together elegantly. Parameterize the flow directly as a cumulative distribution function — let itself be a parameterized CDF, such as the CDF of a mixture of Gaussians or of logistics. The derivative of a CDF is the PDF itself:
so fitting the parameterized CDF as a flow recovers the original objective of fitting the corresponding parameterized PDF — the two views coincide, one object seen from the derivative's angle or the integral's. Practical instantiations use exactly those families: Gaussian-mixture CDFs and mixtures of logistics, both monotonic (every CDF is) and both differentiable, so they are admissible flow layers out of the box.
Layer selection obeys two hard requirements. Every transformation must be invertible — otherwise one latent sample spawns several outputs and generation loses meaning. And every transformation must be differentiable — without derivatives there is no slope term, and without the slope term there is no gradient training at all. Happily, the everyday activations qualify: sigmoid, hyperbolic tangent, and ReLU are all monotonic, so they are safe to invert — a sigmoid maps each input to exactly one output, tanh likewise, and ReLU (with a strictly positive slope on its active side) survives with the usual care at the hinge. What fails is anything quadratic-shaped: , , curves fold inputs and are barred.
Where next: the following session extends flows to two dimensions and n dimensions, covers dequantization — the trick that ports this continuous formulation onto discrete images and text — and a revision session follows. Later, in the application classes on vision and natural language processing, autoregressive models return: pre-trained autoregressive models are the basis behind GPT and the whole family of ChatGPT-style systems.
Real-world: one-dimensional flows are not merely a teaching device — density modeling of scalar quantities is a real task in quantitative finance (modeling daily return distributions, whose fat tails defeat single Gaussians) and in anomaly detection on sensor streams, where the learned density flags readings the law finds improbable. And the composition-of-invertible-layers principle scales straight up to the image and audio flow models used for high-fidelity speech synthesis.
Recap + bridge: Change of variables — latent density times absolute slope — turns any invertible differentiable push into an explicit density, and maximizing the two-term objective trains it; monotonic functions (odd-power polynomials, exponentials, sigmoids, CDFs) supply legal layers. Next session: flows grow from one dimension to images, with dequantization bridging discrete pixels into the continuous world.
Exam Guidance Summary
Exam note: Everything in this list came from the instructor directly — treat it as the revision checklist for the mid-sem.
- Assignment-anchored questions. Mid-sem questions may be framed around the assignment — expect about two. No code writing; you must read a snippet and explain what it does, drawing only on the lab sheets and the assignment. Nothing from untaught territory — the questions sit around the assignment, not on unseen material.
- Deep-learning prerequisites to retain by memory (from the earlier coursework): backpropagation, weight updates via gradient descent, small convolutions computed by hand or with a calculator, and parameter counting for convolution layers. For the last one, rehearse the pattern: filters × kernel height × kernel width × input channels weights + one bias per filter.
- Assignment observations must tally with known results. Alignment of your empirical findings with what the technical community already knows is part of the grading expectation — check your numbers against published behavior before submitting.
- Practice material. Past question papers will be shared shortly; supplement them with ChatGPT-generated practice questions, which work well for extra drilling.
- Know the NLL leaderboard cold, including why smaller is better: baseline about 3.14, Gated PixelCNN 3.03 on CIFAR-10, PixelCNN++ 2.92, PixelSnail lowest of all. Expect conceptual questions on why each variant improves: blind-spot removal (vertical/horizontal split), mixture-of-logistics outputs (smooth low-parameter pixel laws instead of 256-way softmax), and masked attention (full receptive field).
- Change of variables and the flow objective. Understand and the two-term objective well enough to explain each symbol — the slope term and the latent-density term carry distinct roles: one rewards landing data where the latent law is generous, the other punishes compressing mass away.
A suggested revision order: re-derive the chain-rule factorization and NLL from scratch; sketch the blind-spot staircase and its vertical/horizontal fix; compute one discretized-mixture probability end to end; then derive change of variables once without notes.
Key Industry Applications
- Cross-domain generation. Audio synthesis, language modeling, and image and 3D generation all run on the same autoregressive recipe — factor the joint into per-position conditionals and sample sequentially. The recipe transfers across dimensionalities, from one-dimensional waveforms to volumetric data. The same family underlies modern text generators: pre-trained autoregressive models power GPT-class systems and ChatGPT-style applications.
- Class-conditional image generation. One-hot label conditioning on MNIST-style digits produces on-demand samples of any chosen class — the mechanism behind controllable synthesis tools that must honor a user's category request.
- Super-resolution. Condition a PixelCNN on a seven-by-seven averaged embedding of a image (each entry the mean of one four-by-four block), and it synthesizes the full-resolution version. Any domain with paired low-res/high-res data supports the same trick — satellite imagery, medical scans, legacy photo restoration.
- Colorization. Conditioning on grayscale inputs lets the trained density paint plausible colors, the same conditional law applied to archival footage restoration and old-photo colorization services.
- Study tooling. Multi-part written walkthroughs such as the thomasjubb.blog series, and step-by-step chatbot prompts ("explain PixelCNN and its variant architectures step by step"), both serve as supplementary references alongside the formal material.
- Frontier flows. TARFlow — a Transformer-based autoregressive flow from Apple, circa 2024 — shows the flow family competing on generation quality, narrowing the historic sample-quality gap that kept flows behind later model families.
The common thread across every row: one probability-law learner, steered or scaled by what you feed it — labels, low-res pairs, grayscale twins, or attention instead of convolutions.
UDL Lecture 6 notes · PixelCNN Variants and 1D Normalizing Flows
Sections Breakdown
Shared properties of likelihood-based models - inference ability, slow sequential sampling, stable training - plus the deep-learning prerequisites.
Chain-rule factorization, NLL training, masked convolutions that read only the past, the 256-way softmax head, orderings, and RGB conditioning.
How stacked masked kernels grow diagonally up-left and strand a stair-shaped wedge of valid past pixels outside every receptive field.
The vertical-plus-horizontal split that removes the blind spot, sigmoid-gate times tanh-filter gating, ResNet skips, and CIFAR-10 NLL gains.
Replacing the wasteful 256-way softmax with a discretized mixture of logistics, CDF-differencing bins, and a downsampling residual backbone.
Masked attention gives every pixel access to its entire past in one layer, at quadratic compute cost.
One-hot labels, averaged low-resolution maps, and grayscale inputs steer the same conditional machinery for class generation, super-resolution, and colorization.
The five-wish bucket list for generative models and where autoregressive models stand against it.
Probability refresher, maximum likelihood, invertible transformations, change of variables, and the two-term flow training objective.
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.
Likelihood-Based Autoregressive Models
Must-know: The three shared properties (inference ability, slow sequential sampling, stable training) and that about two mid-sem questions sit around the assignment (read-and-explain code from lab sheets only)
⚠️ Top pitfall: Stable training does not imply good samples; a steady loss can still end in mediocre generation
Self-check: Name three properties every likelihood-based model shares.
Connects to: PixelCNN Masked Convolutions (6.2), What We Want From a Generative Model (6.8)
PixelCNN Masked Convolutions
Must-know: The chain-rule factorization p(x)=prod p(x_i|x_<i), its log form, and why NLL minimization equals likelihood maximization; masked convolution zeroes present-and-future taps by force
⚠️ Top pitfall: A nonzero center tap in the first masked layer lets a pixel see itself; NLL collapsing to near zero instantly signals this mask bug
Self-check: Why does the first factor p(x_1) need no network while later conditionals do?
Connects to: The Blind Spot Problem (6.3), PixelCNN++ (6.5), Conditional Generation (6.7)
The Blind Spot Problem
Must-know: The blind spot: per-layer masking is causal, but stacked masks only extend coverage diagonally up-left, so a staircase of past pixels never influences the target's probability
⚠️ Top pitfall: Believing depth fixes the blind spot — it widens coverage elsewhere but never recovers the stranded wedge
Self-check: Sketch which pixels a three-layer stack of masked 3x3 kernels can and cannot reach for a target pixel in raster-scan order.
Connects to: PixelCNN Masked Convolutions (6.2), Gated PixelCNN (6.4), PixelSnail Masked Self-Attention (6.6)
Gated PixelCNN
Must-know: The vertical+horizontal decomposition removes the blind spot; the gate g = sigma(a_gate) ⊙ tanh(a_filter); NLL drops 3.14 -> 3.03 on CIFAR-10 and smaller is better
⚠️ Top pitfall: Quoting the improvement without the cause: the gain comes from both receptive-field repair and the more expressive gated architecture
Self-check: Why can no vertical blind spot exist in a mask that reads only strictly-above rows?
Connects to: PixelCNN Masked Convolutions (6.2), The Blind Spot Problem (6.3), PixelCNN++ (6.5)
PixelCNN++
Must-know: Why neighboring intensities make the 256-way softmax wasteful; the mixture-of-logistics law; P(X=v) = F(v+0.5) - F(v-0.5); the logistic CDF is exactly the sigmoid sigma((x-mu)/s)
⚠️ Top pitfall: Forgetting the half-unit window edges: F(v+0.5) - F(v-0.5), not F(v) - F(v-1); the bin must straddle the integer symmetrically
Self-check: Compute P(X=100) for a single logistic component with mu=100, s=1 using sigmoid values.
Connects to: PixelCNN Masked Convolutions (6.2), Gated PixelCNN (6.4), Foundations of Normalizing Flows (6.9)
PixelSnail Masked Self-Attention
Must-know: Masked self-attention zeroes future keys to enforce causality; receptive-field ranking: PixelSnail (full past) > PixelCNN++ > Gated PixelCNN > plain PixelCNN; cost is quadratic in positions
⚠️ Top pitfall: Forgetting that custom orderings are easier to express with attention (declare allowed keys) than with convolution kernels (redesign the 0/1 layout by hand)
Self-check: Why does attention's compute grow quadratically while convolution's grows linearly in image size?
Connects to: The Blind Spot Problem (6.3), Gated PixelCNN (6.4), PixelCNN++ (6.5)
Conditional Generation
Must-know: The conditioning recipe: one-hot label for class generation; 4x4 block averaging of a 28x28 image yields the 7x7 condition map for super-resolution; condition must appear in both training and generation
⚠️ Top pitfall: Training without the condition and injecting it only at test time — the model never learned to read h and ignores it
Self-check: Why does 28/4 = 7 make four-by-four block averaging the natural way to build a super-resolution condition map?
Connects to: PixelCNN Masked Convolutions (6.2), PixelSnail Masked Self-Attention (6.6)
What We Want From a Generative Model
Must-know: The five bucket-list wishes in order; autoregressive models grant four of five but offer no samplable latent space; flows promise all five with dequantization bridging continuous math to discrete data
⚠️ Top pitfall: Judging generative models by sample quality alone — likelihood evaluation (wish 4) is what makes model comparison fair
Self-check: Which single bucket-list wish do autoregressive models fail to grant?
Connects to: Likelihood-Based Autoregressive Models (6.1), Foundations of Normalizing Flows (6.9)
Foundations of Normalizing Flows
Must-know: Change of variables p_theta(x) = p_Z(f_theta(x))|df/dx| with every symbol's role; the two-term objective (latent-density term rewards landing near the latent peak, slope term punishes compression); even powers are not invertible while monotonic functions are; CDF parameterization makes derivative-of-CDF equal the fitted PDF
⚠️ Top pitfall: Ignoring the absolute value — slopes may be negative but densities cannot; also assuming x^4-style even powers qualify as flow layers when they fold two inputs into one output
Self-check: Why does squashing data into a tiny interval fail despite placing points at the latent peak?
Connects to: What We Want From a Generative Model (6.8), PixelCNN++ (6.5)
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.