Normalizing Flows: Masked Autoregressive Models
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
- Raster scan ordering and masked convolutions — covered in Lecture 5
- MADE-style masking for density estimation — covered in Lecture 5
- Sequential generation as the autoregressive drawback — covered in Lecture 5
- Normalizing flows: base distribution and the bijectivity constraint — covered in Lecture 1
- Training by maximum likelihood — covered in Lectures 1 and 5
- Convolutional autoencoders — covered in Lecture 3
- Autoencoder training losses and backpropagation — covered in Lecture 3
These notes cover the flow-based branch of unsupervised deep learning: how masking works in autoregressive models, why flow models exist, how change of variables drives their training, and how specific architectures — MAF, IAF, affine flows, NICE, RealNVP, checkerboard-masked couplings, and Glow — trade sampling speed against likelihood evaluation. Two full exam-style worked problems on autoencoders close the notes.
The chapter builds in one straight line. First comes the motivation: autoregressive models generate data one coordinate at a time, and that serial bottleneck is what flows attack. Then comes the framework: a simple base distribution, an invertible transformation, and a change-of-variables rule that ties the two densities together. On top of that framework sit the concrete designs — masked autoregressive flows (fast at scoring data, slow at drawing samples), inverse autoregressive flows (exactly flipped), and the coupling-layer family from NICE through RealNVP to Glow. Two practical matters complete the theory: digital data must be dequantized before flows can touch it, and the trained models power super-resolution, text, audio, and 3D point-cloud generation. The final two sections are hands-on exam practice grounded in the coding assignments: tracking output sizes and parameter counts through a convolutional autoencoder, and running a full backward pass on a tiny binary autoencoder.
8.1 Masking and Autoregressive Modelling Recap
The class picks up where the previous session ended: masked auto-regression, masked autoregressive flow, and inverse autoregressive flow. One specific implementation of masked autoregressive flow is called MAF, and a companion implementation is the inverse autoregressive flow, IAF. The Eric Jang tutorial is the recommended reference for a detailed walkthrough of both.
Before any new machinery appears, two ideas from the previous session need to be firm, because everything in this lecture stands on them: the causal mask that lets a model predict one coordinate at a time, and the price that idea pays at generation time. This section refreshes both and then asks the question that motivates the whole chapter — why build yet another model at all?
8.1.1 Raster Scan Ordering and the Causal Mask
The basic property of masked auto-regression is simple: every predicted value must depend only on values that already happened in the past, never on data from the future. Masking is one way to enforce this. In PixelCNN, for example, a binary mask hides parts of the input so that when we estimate the probability density of one particular pixel — one feature dimension — we can only use the data that came before it.
What counts as "past" and "future" is a convention. Image data is read in raster scan format: left to right across the top row, then down a row, left to right again, and so on until the bottom-right corner. Under that ordering, a convolution estimating the density at some pixel may look at every position in previous rows and at positions to the left in the same row, and nothing else. Any position that comes later in the scan is future, and the mask blocks it.
A concrete pass makes the pattern visible. Take a 4 by 4 image and number its sixteen pixels in scan order, 1 through 16:
| col 1 | col 2 | col 3 | col 4 | |
|---|---|---|---|---|
| row 1 | 1 | 2 | 3 | 4 |
| row 2 | 5 | 6 | 7 | 8 |
| row 3 | 9 | 10 | 11 | 12 |
| row 4 | 13 | 14 | 15 | 16 |
Suppose the model wants the density of pixel 7 (row 2, column 3). The mask leaves six positions visible: the whole first row (pixels 1–4) and the two same-row neighbours to the left (pixels 5 and 6). The remaining ten positions — including every pixel below and to the right — are future, so their values are hidden. Move the target one step down to pixel 11 and the visible set grows to ten positions; move it anywhere and the rule never changes: all fully scanned rows, plus the part of the current row left of the target.
An everyday picture: filling in a puzzle book page by page. When you answer question 7, every earlier answer sits open on the desk and can inform your guess; questions 8 onward are face-down, and no fair solver peeks at them. The raster scan plays the role of the page order. The analogy has one limit worth naming: a book genuinely runs forward in time, while an image does not. "Past" for an image is only the scan convention — flip the reading direction and yesterday's "future" becomes "past". Nothing physical forces left-to-right, top-to-bottom; it is simply the fixed order everyone agrees on.
The same causal idea carries straight over into flow models. An autoregressive component conditions each output dimension on the dimensions before it, whether the component is predicting pixels directly or producing the parameters of a flow transformation. That single sentence is the seed of MAF later in this lecture: keep the mask, change what the masked network outputs.
Pitfalls:
- A mask that leaks even one future position breaks the whole factorization. The training likelihood can still look excellent — the model quietly reads the answer from the input — while generation collapses into noise. Always ask which side of the mask each connection sits on.
- Do not confuse scan-order "past" with causality in time. For images there is no clock; the ordering is a modelling convention chosen so the joint density factors into manageable pieces.
- Masked auto-regression estimates a full conditional distribution per position (mean and spread), not just one number. Remembering this makes MAF's Gaussian conditionals feel natural rather than new.
8.1.2 Why Build Another Model?
The autoregressive setup views training data as an n-dimensional vector , and the goal is to estimate the density . An autoregressive module can do this through the chain rule of probability: factor the joint density into conditional densities along the scan order,
and let a masked network produce each conditional. As a density estimator this works well. So a natural question arises: if we already have an autoregressive model, what motivates yet another model?
Q: We already have an autoregressive model. What is the key motivation for coming up with yet another model? Is it vanishing gradients? A: Vanishing gradient is rejected — that story ended long ago in the deep neural networks course. The one fundamental drawback of an autoregressive model is that data generation is sequential in nature. Generation produces first, then , then , and only after the whole scan do you see the image or sentence. That is exactly why asking ChatGPT to create an image takes a while. A flow model is conceptualized as a way to generate data in a parallel fashion instead. The deeper lesson: anything you build should provide some benefit compared to everything done before — a new model with no advantage is pointless.
Several students guessed gradients before the real reason surfaced, and the rejection is worth remembering as a habit: when someone proposes a new architecture, hunt for the deficiency it removes, not for a fashionable training pathology. Here the deficiency has a name — sequential data generation — and it is structural, not numerical. No amount of ReLU units or normalization layers removes it, because it lives in the factorization itself: needs , so sampling must walk.
So the primary purpose of flow models is to improve data generation speed. There is a secondary purpose as well: flow models are designed with the hope of also producing a latent representation of the data. The data you observe is , but something hidden may be generating it — those hidden values are the latents. In an autoencoder, the encoded dimensions are latent data: not observable directly, created by processing, and then used for decoding. Latent variables of this kind are absent from plain autoregressive models, so the flow model chases both goals at once: faster generation and a latent space.
Scope check on the promise: the speed gain is real but conditional on design choices, and the rest of the lecture shows the trade-off precisely. Masked autoregressive flows keep the slow sequential walk in the generative direction; inverse autoregressive flows push the slowness into evaluation instead; coupling architectures such as RealNVP and Glow make both directions parallel by giving up full autoregression. No free lunch appears anywhere — each design moves the bottleneck somewhere it hurts less for the intended use.
Real-world anchor: the sequential-decoding latency is not hypothetical. WaveNet produced striking audio quality but generated one audio sample after another, which pushed the follow-up system Parallel WaveNet toward exactly the flow ideas introduced here. Whenever a product needs many samples fast — image editing assistants, speech synthesizers, content filters — serial generation is the wall, and flows are one of the standard ladders against it.
8.1.3 Exam Framing for This Topic
Exam note: This course is closed book, and experience says you are always better off taking the regular exam rather than a makeup. Guessing is not a strategy — know the reasons, not just the names. Applied here: an answer like "MAF is used because it exists" earns little. Know why the mask exists (it enforces the chain-rule factorization), why flows exist (sequential generation is slow), and why the bijectivity requirement exists (sampling and scoring both need a well-defined inverse). Reasons survive exam pressure; memorized names do not.
8.2 The Normalizing Flow Framework
8.2.1 Base Distribution, Transform, and Sampling
Here is a strange design constraint to sit with for a moment: a generative network in which every single layer must be undoable — no information may ever be thrown away — can still carve a plain Gaussian into recognizable faces and speech. The rest of this section shows why that constraint exists and what it buys.
A flow model is defined by three pieces. First, the original data , an n-dimensional training sample. Second, a transformation applied to the data, written , which produces the latent space . Third, an assumption about the latent distribution: is simple — uniform, or more naturally a normal Gaussian.
The three ingredients of a flow model
- Data space. Each training example is a vector — for a 28 by 28 grayscale image flattened in scan order, .
- Invertible transformation. A map sends data into latents, , with inverse . Both directions must exist and be unique.
- Base density. The latent variable carries a chosen, easy distribution — uniform, or more naturally a standard normal Gaussian with mean zero and identity covariance.
Given these pieces, the sampling rule applies the inverse transform to a latent draw:
Draw one value from the base density, push it through the inverse transformation, and the result is a new data sample. Training shapes so that this operation produces samples obeying the data distribution.
Generation runs the transformation backwards, and two quick questions from class pin down the setup before any formulas appear.
Q: What is assumed about the probability distribution of the latent space in a flow model? A: The latent distribution is kept simple — for example uniform, or more naturally a normal Gaussian. Simplicity is the whole point of the base: we must be able to draw from it exactly and evaluate its density exactly, because both operations appear inside training. A standard normal makes both trivial.
Q: What is the relationship between the dimension of the original data and the dimension of the latent space the flow model generates? A: They match. The latent is again n-dimensional, just like the training data . An invertible map cannot merge or discard coordinates — if it did, information would be lost and no unique inverse could exist — so a 784-dimensional image needs a 784-dimensional latent.
Training is done so that applying to a latent sample creates a sample in the original space which obeys the data distribution. The means of achieving this is maximum likelihood: maximize the likelihood of the generated data. Both autoregressive models and flow-based models are likelihood-based models — the shared principle is that maximizing the likelihood of the data teaches the model the right thing. Section 8.3 turns that sentence into an explicit loss function.
There is one hard constraint on the transformation. When you sample from the space and invert it, you must get one result, not many. The forward function must be bijective — one-to-one.
Q: Which mappings are unacceptable as flow transformations? A: Squaring fails the bijectivity test: sends two different inputs onto one output — both and land on — so the map cannot be inverted cleanly. Given the output , was the input or ? No answer exists. A flow transformation must be strictly one-to-one in both directions.
Assumption: Every layer used to build must be invertible, and the inverse must be computable cheaply — not just in principle but in practice, because likelihood evaluation during training inverts the map on every batch.
Scope: This requirement is also the price. Ordinary network layers such as a plain dense layer followed by a ReLU freely destroy information (ReLU maps every negative value to zero, merging uncountably many inputs into one output), which is exactly why ordinary networks are not valid flows. Everything in Section 8.6 — coupling layers, masks, one-by-one convolutions — is engineering that recovers expressive power while respecting invertibility.
An everyday analogy keeps the geometry honest. Think of kneading dough with a rolling pin. Pressing and stretching moves the dough around and reshapes each region — thick spots flatten out, narrow spots spread — yet the total amount of dough never changes, and you can always imagine rolling time backwards to undo every motion. A flow transformation does to probability mass what the rolling pin does to dough: it relocates and reshapes a fixed total mass of probability. The analogy breaks exactly where the mathematics is strict: real dough tears and folds over itself, while an invertible transformation may never fold — folding is precisely the failure that squaring exhibits.
Visual intuition: picture the standard-normal bump as a smooth hill over the latent axis on the left. The transformation bends that axis like a flexible ruler — compressing some stretches, extending others — and on the right the hill reappears as a lumpy, multi-peaked landscape over data space. Arrows run both ways along the bent ruler: forward arrows generate samples (the generative direction), backward arrows take a real data point back to its latent coordinate. That backward trip earns the framework its name — pushing complex data densities through the inverse layers gradually normalizes them back to the Gaussian, giving us normalizing flows.
This is also why latents echo the autoencoder idea: hidden codes created by processing rather than observed directly, except here the transform is built to be invertible. The practical payoff of an exact, invertible latent code is a model that can score any data point with its true probability — the property behind anomaly detection systems that flag inputs receiving unusually low likelihood under a flow trained on normal data.
8.2.2 The Jacobian Constraint in Many Dimensions
In one dimension, finding is no big deal as long as the mapping is bijective. Many dimensions change the picture. For, say, 100-dimensional data, the inverse operation becomes a question about the Jacobian matrix of the transformation.
The Jacobian
For a transformation with inputs and outputs, the Jacobian is the matrix of all first partial derivatives, with entry equal to — how strongly output coordinate reacts to input coordinate :
It collects how every output coordinate reacts to every input coordinate, all in one table.
Why does this matrix appear the moment dimensions grow? Because in one dimension the derivative is a single number saying how much the map stretches near a point. In many dimensions the stretch depends on direction: a map can double lengths horizontally while halving them vertically. The Jacobian gathers those per-direction stretch factors, and its determinant condenses them into one number — the factor by which the map scales area (two dimensions) or volume (in general) at that point. Section 8.3 shows that this volume factor is exactly the correction term the change-of-variables rule needs.
Q: What should the inverse operation become when we extend flows from one-dimensional to general multidimensional data? A: The Jacobian matrix of the transformation must have a structure such that its determinant can be easily computed — and that determinant cannot be zero. For a 100 by 100 matrix, computing a determinant in a simple fashion requires imposing structure on the mapping, mainly a lower-triangular or upper-triangular Jacobian. The autoregressive construction is exactly what forces this structure.
Two facts make triangular matrices the hero. First, the determinant of a triangular matrix is just the product of its diagonal entries. For example,
with no work beyond multiplying the diagonal — and the same shortcut holds at any size, turning a 100-by-100 determinant from an expensive computation into one hundred multiplications. Second, a triangular matrix is invertible by back-substitution in about steps whenever no diagonal entry is zero, and its determinant is nonzero exactly when all diagonal entries are nonzero. One structure buys tractability and the guarantee of a valid inverse at the same time.
So the two key requirements for building masked autoregressive flow models are: the determinant of the Jacobian of the transformation from to must be easy to compute, and the triangular shape guarantees both tractability and a nonzero determinant. Keep these two requirements in view — every architecture in Section 8.6 is a different trick for satisfying them.
Pitfalls:
- Do not confuse the Jacobian of the forward map with the Jacobian of the inverse map . They are matrix inverses of each other, and their determinants are reciprocals; mixing them flips density corrections upside down.
- "Easy determinant" is a training requirement, not an aesthetic one. A full unstructured determinant costs roughly operations per data point per training step — the model becomes untrainable long before it becomes inaccurate.
- A zero diagonal entry in a triangular Jacobian means a squashed direction: volume collapses to zero, the determinant hits zero, and densities blow up or vanish — mathematically fatal, not merely inconvenient.
A flow pairs simple latents with data through an invertible map; sampling runs , scoring runs ; and everything hinges on a Jacobian whose determinant is cheap and nonzero. Next: the formula that says precisely how densities transform when their variables do — change of variables.
8.3 Change of Variables and Maximum Likelihood Training
8.3.1 Scaling, Shifting, and Skewing a Uniform Distribution
Before the general formula, consider what simple transformations do to a distribution — every intuition needed later lives in these small examples.
Take uniform training data on the interval — flat density at height 1, so the shaded rectangle has area — and apply
Every point moves to twice its position plus one, so the support stretches from to : the square-shaped region of support becomes rectangular, stretched to twice the length. The distribution remains uniform, but the density value changes: it was flat at 1 across the original interval, and now it is flat at one half across , because the same probability mass is spread over twice the range. The area check confirms nothing was created or destroyed:
Scaling stretches support and compensates by lowering height — double the range, half the height; triple the range, a third of the height. A pure shift, say , moves the interval without changing widths at all, so heights stay exactly where they were — sliding a rectangle sideways changes no areas.
A more general map fixes neither width nor straightness: it alters the shape of the distribution. A skewed transformation bends the flat uniform into a lopsided hump by compressing some regions (piling mass up into taller spikes) while stretching others (spreading mass thin). Rotations act on many dimensions at once: they stretch one axis and squeeze another while translating along both axes, and the result stays a valid probability density — the area under the curve remains the same after integration, because both sides of the transformation are probability distributions. Probability mass may be pushed around, but never manufactured or discarded.
Carry one sentence out of this warm-up: spread the support twice and the density height halves. Height is not stored anywhere — it is whatever value makes the total area come out to one after the transformation has had its way with the geometry.
Visual intuition: draw the before-picture as a unit square of density over the axis, and the after-picture as a wider, shorter rectangle of equal area sitting further along the axis. Mark the two landmarks: the leading edge moved from 1 to 3 (the stretch), and the plateau dropped from 1 to ½ (the compensation). Every change-of-variables computation later is bookkeeping for exactly this trade.
8.3.2 The Change-of-Variables Formula
The verbal rule from class: the density of equals the density of times the absolute value of the determinant of the derivative of with respect to . In higher dimensions:
Read it right to left: start from how plausible the latent coordinate is under the base density, then correct that plausibility by how much volume the transformation expands or shrinks near this point. The correction factor is the absolute Jacobian determinant from Section 8.2.2.
Where does such a formula come from? In one dimension it follows from conserving probability mass, and writing the argument once removes all mystery. Let be invertible with inverse ... more usefully, track a tiny interval: if sits in a window of width , then sits in the image window of width . The same probability mass must occupy both windows:
Divide both sides by and let the window shrink to zero; the approximation becomes equality and the one-dimensional version of the rule appears:
The multivariate formula above is the same statement with the stretch factor in each direction replaced by the single number that summarizes stretch in all directions — the absolute determinant. This is why the determinant matters: it captures how area (in two dimensions) or volume (in general) changes under the transformation. To create from , you must be able to calculate this determinant. The absolute value appears because probability values are always greater than zero, so the density ratio must stay positive even when the transformation flips orientation (a reflection has negative determinant but still only reshuffles mass).
A quick sanity pass on the formula using the warm-up example: there , so and the rule reads ... careful — direction matters, and this is the classic trip-up. If instead we transform from the uniform to data via with , then and , matching the halved height found by hand. Stretching output space by 2 divides the density by 2 — spread twice, height halves.
With trainable parameters, the transformation is implemented by a neural network, and the model density becomes:
This is the basic change-of-variables formula for probability distributions: a random variable is transformed into another random variable, and the distribution attached to the original variable changes for the transformed one.
Notation note: reference texts often write the same rule in the sampling direction as with . The two forms agree, because inverting a map reciprocates its Jacobian determinant: . The lecture keeps the normalizing direction (), which matches what training actually computes.
The autoregressive constraint now earns its central place. Because may depend only on , changing with cannot affect at all, so the partial derivative is zero whenever . Filling row after row with zeros on and above the diagonal leaves the Jacobian lower triangular,
(where marks possibly-nonzero entries), its determinant is trivial to evaluate — multiply the diagonal — and the determinant is nonzero by construction as long as each diagonal entry is nonzero, which the flow's design ensures. Without this trick, evaluating the determinant of a large Jacobian carefully would not even be feasible — that is the whole point of putting the autoregressive structure into the flow model.
Worked example — scoring one data point under a tiny flow.
Base distribution: standard normal, . Transformation (normalizing direction): , so the model generates samples through — stretched to twice the range, so the density should end up half as tall.
Score the observation .
Step 1 — latent coordinate: .
Step 2 — base density there:
Step 3 — Jacobian correction: everywhere, so the absolute "determinant" (one dimension, so just the absolute slope) is .
Step 4 — combine:
Answer: .
Sense check: this flow maps noise through , so the model density must be exactly — twice the standard deviation of the base. A Gaussian whose standard deviation doubles carries half the peak height, so should equal . Running the formula at : latent , base term , correction factor , product — exact match. Spread twice, height halves: the warm-up rule, now with numbers.
8.3.3 Maximum Likelihood Training and Composition
Training uses the principle of maximum likelihood. Assuming data points are independent and identically distributed, the data likelihood is a product of probabilities:
where are the training points. Products are difficult to deal with — gradients of long products misbehave numerically — so we take the logarithm, natural log throughout, and the product becomes a sum. Maximizing is equivalent to minimizing its negative, averaged over the data:
Minimizing the expected negative log-likelihood with respect to the parameters — by changing the transformation parameters — is how the probability transformation function learns; in a real scenario that function is implemented using a neural network.
Applying the same logarithm to the change-of-variables expression splits the per-point loss into two pieces, and writing the split line by line shows exactly what the network must supply:
So each training point costs two terms: the log-density of the base distribution evaluated at , plus the log of the absolute Jacobian determinant. (Some texts display the second term with a minus sign; that happens when the map is written in the sampling direction , where the determinant reciprocates — same quantity either way.) The first term pulls latent coordinates toward regions the base likes; the second term rewards transformations whose local volume change explains how the data spread out. The expectation over generated data is computed on batches: the loss for one step is the sum of over all training points in the mini-batch, and minimizing that sum drives learning. Batch processing exists for computational efficiency — GPUs chew through many points at once, and an average over a batch estimates the full-data expectation.
One practical warning before building anything:
The key requirement is that the Jacobian determinant must be easy to calculate and easy to differentiate. Training differentiates the loss, and the loss contains ; if gradients through the determinant are expensive or unavailable, the model cannot be trained at all — no matter how expressive the transformation is. This rules out whole families of otherwise attractive layers and motivates every structure choice in Section 8.6.
Flows also compose. Starting from , apply one invertible map to reach , another to reach , and a final one so that . Why do determinants multiply down the chain? Each stage has its own Jacobian , and the chain rule stacks them:
so taking determinants and using the fact that the determinant of a matrix product is the product of the determinants:
Each stage must itself be invertible. Practically this means you can use a multilayer network: compute the determinant locally at each layer, multiply the results, and you have the likelihood of the whole stack. Numerical spot-check with one-dimensional stretches: a stage that scales lengths by 2 contributes Jacobian determinant , a stage that scales by 3 contributes , and the composite stretches lengths by 6 — matching . X flows to , another flow applies to , another to — composition is free as long as every piece is invertible.
That freedom is what makes deep flow networks possible: stack simple invertible layers whose determinants are known in closed form, multiply their contributions inside the log-likelihood, and train the whole thing end to end with backpropagation.
Change of variables converts a tractable base density into a learnable data density, at the price of one Jacobian determinant per layer; maximum likelihood turns samples into a summed loss; composition turns layers into depth. With the framework fixed, the next question is architectural: what should one invertible layer look like? MAF answers first.
Real-world anchor: this exact objective — minimize mean negative log-likelihood over batches — is the same training loop used by language models and diffusion models' precursors alike. Learning it here transfers directly: wherever a system reports "loss: 3.2 nats", it is optimizing a formula shaped like the one above.
8.4 Masked Autoregressive Flow (MAF)
8.4.1 Generative Equations and Sequential Sampling
Opening question: can a flow generate data using nothing more exotic than a scaled shift — and still model any distribution? MAF's answer is yes, provided the scale and the shift are chosen by a masked network looking at everything generated so far.
The masked autoregressive flow generates each dimension from a latent sample using a shift scaled by an exponential. In class this was stated as: the generated value equals times to the power , plus , for running from 1 to n:
- is the i-th coordinate of the Gaussian base sample .
- is a log-scale value: multiplies the latent coordinate, so expands that axis and shrinks it. The exponential guarantees the scale stays positive — never zero, never negative — which keeps the Jacobian diagonal safely nonzero.
- shifts the result along its own dimension.
Both and come from a neural network that you are training, and — this is where the mask from Section 8.1 returns — that network may read only the coordinates already generated.
Concretely: . To calculate , you need , and the network predicts and using the information about all the data that has happened in the past — namely . Generally speaking, the network predicts and as functions of through :
Walk through the consequence: generation of depends on ; generation of depends on and , because and are functions of them. So data generation time stays sequential — the very thing flows wanted to escape, kept alive inside MAF. Each coordinate waits for all earlier ones; a million-dimensional image means a million dependent steps at sampling time.
Worked example — generating two dimensions of an image, step by step.
Suppose the base sample is .
Step 1. The network has no past coordinates to read for the first output, so it outputs fixed values, say and :
Step 2. The network now reads the observed past and outputs, say, and :
Answer: — but notice the price: Step 2 could not start until Step 1 finished, because its parameters needed . For dimensions this dependency chain forces sequential network evaluations per sample.
Sense check: both outputs used exactly the generative equation with real numbers, and each step consumed only coordinates that already existed — the causal-mask discipline of Section 8.1, now inside a flow.
8.4.2 Likelihood Factorization and Conditionally Gaussian Dimensions
MAF rests on the chain-rule assumption that the joint density factors into conditionals along the scan order — stated loosely in class as "probability of x given by the probabilities of each given the previous ones":
This product form is the standard autoregressive chain rule from Section 8.1.2, and it must be a product rather than a sum because joint probabilities multiply: the chance that all coordinates take their observed values together is the chance that takes its value, times the chance adds its value given , and so on. Sums appear one step later, when logarithms convert this product into the training loss — that is the only place addition enters.
Each conditional factor is a normal Gaussian — but not a fixed one. Its mean is a function of all the dimensions that came before, and its spread depends on those previous data points too:
where the shorthand collects every conditioning coordinate. In the notation , the second argument is a variance, and since plays the role of the standard deviation, the variance is .
Why is this the right conditional shape? Check it against the generative equation: if independently of everything else, then
is just a rescaled and shifted standard normal, so given is Gaussian centred at with standard deviation — exactly what the density above states. The two equations are two views of one design: the generative view samples, the density view scores.
So every individual dimension is Gaussian distributed, but the mean and variance of that Gaussian change from one pixel to the next. Letting both parameters drift with context is what gives MAF its pretty good modeling of the original data: flat regions get tiny variance (tight, confident conditionals), textured regions get large variance (wide, uncertain conditionals), and the mean chases local structure such as edges.
8.4.3 What MAF Is Fast At
Because the conditioning variables are observed when you want to score a data point, MAF gives fast evaluation of for arbitrary — the likelihood direction is cheap. Every and depends only on inputs that are already sitting in memory, so a single pass through the masked network produces all parameters at once, then all follow in parallel, and the change-of-variables machinery from Section 8.3 assembles the exact likelihood.
Sampling is the slow direction, since it must walk through the dimensions one at a time — the worked example above showed exactly why. The companion model flips exactly this trade-off, and it is next.
Pitfalls:
- Do not evaluate by sampling: the sampling path is the slow, sequential one, while direct evaluation is parallel and exact. Mixing up the two directions wastes orders of magnitude of compute.
- The variance is , not : confusing standard deviation with variance mis-scales every likelihood you compute.
- MAF's fast direction needs the full input . It cannot score a partially observed image without masking or imputing the missing coordinates first.
Real-world anchor: because exact, cheap density evaluation is MAF's strength, flows of this family fit naturally wherever "how normal is this input?" matters — industrial defect screening flags sensor readings whose learned likelihood drops below a threshold, and fraud pipelines score transactions the same way.
MAF = chain-rule factorization + conditionally Gaussian dimensions whose mean and log-scale are produced by a masked network. Fast at scoring, slow at drawing. Next: flip the direction and the strengths flip with it — IAF.
8.5 Inverse Autoregressive Flow (IAF)
8.5.1 Parallel Generation, Sequential Evaluation
The inverse autoregressive flow makes generation parallel, while training — fitting those transformation functions — stays slow and sequential. The trick is almost embarrassingly simple: IAF uses the same affine form as MAF, but lets the network read the latent sample instead of the data.
Start from the n-dimensional base distribution, sample through from a normal Gaussian in one shot, and compute every output at once:
where now the shift and log-scale are functions of the latent coordinates that came before position — not of any observed data.
The forward mapping from to is parallel: since every was drawn together at the start, all of them are available immediately, so the network calculates all the and values in one shot from the sampled 's — a masked computation tree exactly like PixelCNN's, but fed with latents — and then all appear together. One pass, one sample: generation no longer walks.
During training time, the reverse direction — producing from a given for likelihood evaluation — is sequential:
To recover the latent behind , subtract the shift and divide by the exponential scale — algebraically just the generative equation solved for .
Computing requires and , and those depend on latents up to index — on , not on . But is unknown until you invert the first equation, so the inversions must line up in order: get , feed it forward to get the parameters for level 2, get , and so on. So IAF is faster to sample from, but slow to evaluate the likelihood for a given data point, and direct maximum-likelihood training inherits that slowness — every gradient step needs a likelihood, and every likelihood needs the sequential inversion walk.
Worked example — one parallel generation pass versus its sequential undo.
Sample both latents in one shot: .
Parallel generation. The masked network produces for the first slot (no previous latents to read) and — because is already available — for the second. Both outputs compute simultaneously:
One network pass delivered the whole sample .
Sequential evaluation. Now score that same point. First recover the first latent:
Only now can the parameters for the second level be formed (they need ), after which
The recovered latents match the draw, confirming consistency — but notice they arrived one after another, two dependent steps instead of one shared pass. At dimension , evaluation costs such steps.
Sense check: the generative equations and their inverses used here are exact algebraic mirrors, so recovering the original latents is guaranteed when the arithmetic is right — which it is.
8.5.2 Choosing Between MAF and IAF
The two models are inverses of each other, and their strengths mirror that fact.
| Dimension | MAF | IAF |
|---|---|---|
| Conditioning inputs | Observed past data | Sampled latents |
| Sampling (generation) | Slow — sequential over dimensions | Fast — one parallel pass |
| Likelihood evaluation | Fast — single masked pass | Slow — sequential inversion |
| Direct maximum-likelihood training | Efficient | Inefficient (needs slow inversions) |
| Natural deployment role | Density scoring, anomaly detection | Fast synthesis, real-time generation |
Neither dominates; the application decides. If your product must draw samples under tight latency — speech responding in real time, images streaming into an editor — IAF's parallel sampling wins even though scoring is sluggish. If your system mostly scores incoming data and rarely samples — anomaly screening, calibration, compression — MAF's cheap exact likelihoods win. Pick by asking which direction your workload runs hot.
Real-world: models like Parallel WaveNet build on the IAF idea with a teacher-student arrangement — a slow but accurate teacher transfers its behavior to a fast parallel student — which was covered in the previous session. The teacher (a sequential autoregressive model) supplies training signal so the student never needs the expensive sequential inversions during learning; the deployed student inherits fast sampling. Real-world: this is the same tension behind ChatGPT producing images slowly: sequential decoding trades speed for autoregressive exactness, and IAF-style parallelism is one way out.
Pitfalls:
- The names mislead under time pressure: inverse autoregressive flow is the one whose forward/generative pass is parallel. Remember "IAF samples fast", not "IAF is inverted".
- IAF's slowness sits in evaluation and so in direct training — do not claim IAF trains quickly with plain maximum likelihood; fast IAF systems train through distillation from a teacher.
- Both models share the same affine building block ; what differs is only whether read data or latents. Saying "MAF and IAF use different math" confuses the architecture story entirely.
MAF and IAF are mirror images: masking against observed data makes MAF score fast; masking against sampled latents makes IAF generate fast. Choose per application, or pair a teacher with an IAF student to get fast sampling without sacrificing training quality. Next: leave full autoregression behind and see what simpler invertible blocks can build.
8.6 Flow Building Blocks from Affine Coupling to Glow
8.6.1 Affine Flows
The simplest concrete flow is the affine flow. In class: of is given by inverse of minus — all vectors and matrices:
Here is the base random variable with a normal Gaussian density, is an invertible matrix, and is a shift vector. The equivalence holds because multiplying by and adding are exact inverses of each other: start from , multiply both sides by , and , so .
Entries of the map look like and : each output mixes latent coordinates linearly. Pushing Gaussian data through this affine transformation yields a much more complex density for — described in class as being like a mixture of Gaussians. One clarification keeps the picture precise: a single Gaussian pushed through one affine map remains exactly a single Gaussian, but its shape changes in the ways that matter — the covariance becomes , so previously independent coordinates become correlated and the cloud tilts, stretches, and rotates instead of staying round. The genuinely mixture-like densities appear once such maps stack, or once the base is not a lone Gaussian; the class description points at that richer end result. The multiplication by supplies scaling and rotation, while the addition of supplies translation — three geometric motions, one formula.
The Jacobian of the transformation is the constant matrix — every partial derivative is just the corresponding entry of , independent of where you evaluate it — and the log-likelihood calculation involves the determinant of . You had better be able to evaluate easily, or the whole system cannot be trained. A numerical taste: for , , so this map inflates areas six-fold and every density value it produces carries the correction factor in the normalizing direction.
Affine flows alone share the fate of linear maps everywhere: no matter how you stretch, rotate, and translate a Gaussian cloud, it stays a Gaussian cloud. They are indispensable as components — normalizing layers inside bigger stacks — but they cannot carve a Gaussian into a face by themselves.
8.6.2 Element-wise Flows and Why Mixing Matters
Element-wise flows are much simpler: coordinate maps only to , only to , and so on. Each dimension passes through its own invertible nonlinearity, with no cross-talk anywhere. The Jacobian is simply diagonal — all off-diagonal partials vanish because coordinate never feels coordinate — and you may apply any valid invertible mapping independently per coordinate. Its determinant is just the product of the diagonal entries, so even a deep stack of element-wise layers costs only per-coordinate multiplications.
Conceptually this is a perfectly legal flow — but people have observed that the quality of newly generated data is not that good. Element-wise transforms have limited value precisely because coordinates never interact: each output axis is a bent copy of exactly one input axis, so the model can reshape marginal distributions one at a time yet can never express relationships between dimensions — and structure such as "this pixel sits next to a dark edge" lives entirely in those relationships.
It is very important in flow modeling to mix different dimensions of the base distribution in order to model complicated training data distributions accurately. Everything that follows — coupling layers, masks, one-by-one convolutions — is machinery for mixing.
| Element-wise flows | Linear/affine flows | Coupling flows | |
|---|---|---|---|
| Mixes coordinates? | Never | Yes, linearly only | Yes, nonlinearly |
| Jacobian | Diagonal | Full matrix | Triangular block form |
| Determinant cost | Cheap (product of diagonal) | Needs structured | Cheap by construction |
| Expressive power alone | Low | Low (Gaussian stays Gaussian) | High |
When to pick which: element-wise layers serve as cheap reshapers between mixing layers; affine layers normalize and correlate; coupling layers carry the real modelling load.
8.6.3 NICE: Additive Coupling Layers
NICE uses additive coupling layers. Suppose the total data dimension is n. Split the coordinates into two groups: dimensions 1 through , and dimensions through . The first group passes through untouched, and the second group gets shifted by a learned function of the first:
where is a neural network with input units and output units, and denotes the slice of coordinates from through . Part of the transformation is pure identity; the rest adds what that identity part produced.
The inverse mapping is immediate — this is the beauty of addition: whatever was added can be subtracted again, because both sides know :
No matrix inversion, no iteration — one forward pass of rebuilds the shift, and subtraction undoes the layer.
The Jacobian of the forward map is block triangular:
with an identity block in the upper-left, zeros in the upper-right, the derivatives of in the lower-left, and an identity block in the lower-right. Why do the derivatives of sit below the diagonal? Row block differentiates outputs against inputs; each such output depends on all inputs ( through , plus with derivative one), while rows of the top block never feel . Taking the determinant along the diagonal blocks then gives
and interestingly, in the Jacobian calculation you do not need to worry about the entries coming out of at all, because they sit below the diagonal — arbitrary networks may live there without touching the determinant. Nothing contracts or expands: this is volume preservation. The picture offered in class: take a square and press it sideways into a rhombus, like pushing a malleable block — the area stays the same, only the shape shears. Every NICE layer slides mass around at fixed volume, which is why the name reads nonlinear independent components estimation — it reshapes without inflating or deflating.
Still, NICE has good capability for creating high-quality new data, and face samples generated by NICE were shown as evidence. Depth compensates for each layer's modesty: shear after shear after shear accumulates into complicated global deformation, at zero determinant cost per layer.
Worked example — one additive coupling step and back.
Let , latent , and let the trained mixer be .
Forward: ; . Output .
Inverse: ; recompute ; . Original latents recovered.
Determinant check: here , so
Answer: , inverse recovers , volume factor regardless of what computes.
Sense check: the mixer's steepness changed the shape of the transformation but never the determinant — shear without stretch, as promised.
A rescaling layer extends NICE beyond pure volume preservation. For the first block of dimensions, multiply by a learned scale:
The Jacobian gains a diagonal of on top of the coupling triangle, and the determinant becomes the product
You must multiply all of them — so rescaling deliberately gives up volume preservation to gain expressive power: some axes inflate, others deflate, and the density correction term absorbs exactly those factors.
8.6.4 RealNVP: Affine Coupling Layers
RealNVP — the real-valued, non-volume-preserving sibling of NICE — is the more practical version. The coupling becomes multiplicative rather than purely additive:
where denotes element-wise multiplication (each coordinate times its own partner — the Hadamard product). Two neural networks are involved, each with input units and output units: one produces the log-scale values , whose exponentials multiply the kept half, and the other, , feeds the additive shift. The symbol matters: it says coordinate of one vector pairs only with coordinate of the other — no full matrix multiplication hides inside.
The first features remain an identity transformation from the original distribution side, and the coupling only lets dimensions through consume dimensions 1 through — so the construction stays autoregressive in spirit (later coordinates read earlier ones, never the reverse), and the Jacobian is again lower triangular. Writing it out makes the determinant fall out on its own:
because each coupled row's diagonal entry is the exponential scale acting on its own coordinate, and a triangular determinant multiplies diagonal entries. Because the scale enters through an exponential, the determinant can be greater than or less than one depending on the value of that exponential — positive sums of expand volume, negative sums contract it — and the map shrinks or expands volume freely, which is where the "non-volume preserving" name comes from. Training adjusts these scales per region, letting the model concentrate probability where data actually lives.
A common configuration splits the variables into halves, copying dimensions 1 through and coupling the remaining half, which reads as translation plus scaling and orientation of the base distribution.
8.6.5 Checkerboard Masks for Mixing Channels
Coupling layers expose a basic tension noted earlier: half the dimensions are merely copied, so within one layer nothing mixes across the whole set — the copied half just relays information unchanged. The fix used in CNN-based generators is to change the autoregressive pattern from channel to channel using binary masks. You are still copying — but because the pattern shifts across channels, information mixes in a different way each round.
Work through the four-by-four example from class. Number the sixteen positions of a 4 by 4 image row by row, 1 through 16:
| col 1 | col 2 | col 3 | col 4 | |
|---|---|---|---|---|
| row 1 | 1 | 2 | 3 | 4 |
| row 2 | 5 | 6 | 7 | 8 |
| row 3 | 9 | 10 | 11 | 12 |
| row 4 | 13 | 14 | 15 | 16 |
Positions 1, 5, 9, 13 fall in the first processing group; 2, 6, 10, 14 in the next; 3, 7, 11, 15 in the third; and the remaining column-four positions complete the fourth group — four interleaved sets, each taking every fourth stop along the raster scan:
- Group 1 = {1, 5, 9, 13}, Group 2 = {2, 6, 10, 14}, Group 3 = {3, 7, 11, 15}, Group 4 = {4, 8, 12, 16}.
Treating each pixel as having one channel, the original 4 by 4 tensor becomes a 2 by 2 by 4 tensor — four channel slices, each holding a quarter of the positions. The channel-wise mask sets for the first half of the channels and for the second half, so one coupling pass transforms Groups 1–2 conditioned on Groups 3–4, and flipping the mask next layer swaps their roles. Stacking layers with alternating masks lets information travel between positions that any single layer kept apart — a pixel that was copied in layer one is transformed in layer two, and everything communicates over depth.
On full-resolution images this idea takes its familiar visual form: a binary mask holding only ones and zeros in a checkerboard pattern — alternating 1,0,1,0 and 0,1,0,1 rows, like a chessboard — so that adjacent pixels sit on opposite sides of the mask and swap roles between consecutive layers.
Specific checkerboard patterns have been published for 32 by 32 images of the CIFAR-10 kind, and denotes the number of channels — RGB gives three, and multiple CNN stages may carry many more channels, with mixing happening across those as well. Illustrations contrast good versus bad partitionings: a badly partitioned dataset entangles information that later layers struggle to untangle, while a well-partitioned one is far better, even if still not perfect. Masking of this checkerboard kind is quite important for flow-based image generation.
8.6.6 Glow and One-by-One Convolutions
Flow++ and especially Glow matter enough that you should go over them yourself. Glow comes from OpenAI, performs strongly, and introduces a different modification technique than the couplings above: one-by-one convolutions, which pull information from multiple feature maps and channels at once, restoring the mixing that plain couplings lack. Mechanically, a 1×1 convolution applies the same small invertible linear map at every pixel position — think of an affine layer (Section 8.6.1) running independently at each location, re-weighting the channel axis while leaving the spatial grid untouched. Alternating coupling layers with these channel-shuffling convolutions means every half of the features eventually conditions on every other half.
Glow's signature demo is interpolation. Start from one image and travel toward another in latent space; intermediate points are coherent blends. Because you can move intelligently among base-distribution samples, you can also edit attributes: create smiling faces from a neutral portrait, make hair blonder, morph one face smoothly into another — animations shown in class even included celebrity likenesses, including the technique's inventor and a well-known film star. Very realistic new data and meaningful modifications come out of this technique.
Pitfalls:
- Do not stack identical coupling layers expecting full mixing: whichever coordinates are copied stay frozen until a later layer flips the mask. Alternate or shuffle between layers — checkerboard patterns and 1×1 convolutions exist precisely for this.
- Additive coupling preserves volume; affine coupling does not. Attributing RealNVP-style expansion to NICE-style layers mispredicts every determinant you compute afterwards.
- A 1×1 convolution is not a spatial filter — its "kernel" spans channels, not neighbours. It mixes feature maps at one position at a time.
Real-world anchor: the coupling-layer recipe powers production-grade image systems — GLOW-family models generate high-fidelity faces, audio variants (WaveGlOW-style speech synthesis) reuse the same invertible blocks on spectrograms, and the interpolation trick behind celebrity-morph demos is now standard footage in media-editing pipelines.
One design idea explains this whole gallery: keep the Jacobian triangular so determinants stay cheap, and find ever better ways to mix coordinates — additive shear (NICE), learned scales (RealNVP), shifted masks (checkerboard), channel rotations (Glow's 1×1 convolutions). Before trusting any of them on real pixels, though, one quiet assumption must be repaired: data has to be continuous. Next: dequantization.
8.7 Discrete Data and Dequantization
8.7.1 The Continuity Assumption Breaks on Digital Data
Everything in flow modelling rests on change of variables for random variables, and every partial derivative inside that machinery is a rate of infinitesimal change. The quiet assumption is that random variables are continuous — that between any two possible values lie infinitely many others, so slopes and volume factors are well defined everywhere. Practical data usually is not: unless you process analog signals from analog sensors, inputs such as images are digital, made of discrete sample values. An 8-bit pixel admits exactly 256 levels; a value of 137 is an atom, not a point on a continuum, and "just below 137" describes no pixel at all.
When this inherent continuity assumption is violated, training shows it immediately: the loss curve against training progress becomes erratic and unstable. The mechanism is worth one paragraph. A density over discrete values is a row of spikes with empty space between them; its logarithm lurches from very negative to extreme whenever the model shifts probability onto or off an atom, so gradients swing wildly from step to step. Continuous densities, by contrast, spread mass smoothly, and the same optimization settles into a steady descent.
Quantized data produces rough, unusable optimization behavior; the same pipeline on smoothed data settles down. Class demonstrations showed exactly this contrast on side-by-side training runs.
8.7.2 Dequantization: Adding Uniform Noise
The standard repair is dequantization. Draw noise uniformly over the D-dimensional unit cube, where D is the dimension of your data, and add it to every training value:
where is the original quantized data vector, is an independent noise vector with every coordinate drawn uniformly between 0 and 1, and is the continuous-valued input actually fed to the flow.
Why uniform noise does the job: each discrete level was an atom carrying all the mass at one point; adding smears that mass evenly across the interval , turning the spike into a smooth plateau. No information about which level a sample came from is destroyed — the integer part of recovers it — yet the input now lives on a continuum where derivatives exist. Adding this uniform noise to the training values makes the data continuous again, and the whole flow apparatus applies cleanly.
Micro-example — one gray pixel before and after dequantization.
A grayscale pixel holds the integer value 128. As raw training data it is a single point: the density concentrates all of that pixel's mass at exactly 128, with nothing on either side.
After dequantization, draw one uniform value, say :
Across the dataset, pixels of level 128 fill the interval evenly — a flat strip of density instead of a spike. Every partial derivative of the transformation now sees smoothly varying inputs.
Answer: the atom at becomes the interval , and derivatives exist again.
Class demonstrations showed discrete data trained poorly while dequantized data trained stably — the fix costs one line of code and is standard practice in every serious image-flow implementation, including Glow's own training recipe.
Scope: Dequantization applies to any quantized source — image intensities, audio samples stored as integers, sensor counts — and should be skipped only for genuinely continuous inputs. Do not confuse it with regularization noise: the purpose is not to prevent overfitting but to restore the continuity that change of variables requires.
8.8 Applications of Flow Models
8.8.1 Vision: Super-Resolution
SRFlow applies flow models to super-resolution: starting from a small image, it creates a big image. A plain regression decoder maps the low-resolution input to one fixed high-resolution guess, averaging away everything uncertain. SRFlow instead learns the conditional distribution of the large image given the small one: sampling walks through the invertible latent space, and different draws yield different plausible enlargements — sharp texture here, a slightly different strand of hair there. The invertible latent space gives control that plain regression decoders lack: by choosing where in the latent space to sample, the user steers which plausible version gets rendered, instead of accepting the single blurred average.
8.8.2 Text, Audio, and 3D Point Clouds
Flows also do well in text synthesis when you manipulate the latent with suitable assumptions on the latent dimensions — moving along chosen directions changes attributes such as sentence style while keeping content anchored. In audio synthesis, flow-based vocoders generate raw speech waveforms in parallel passes rather than sample-by-sample, attacking exactly the sequential-latency wall that motivated flows at the start of this lecture. Point-cloud generation matters particularly for 3D computer vision: autonomous-driving pipelines need thousands of plausible LiDAR-style point sets for simulation and testing, and invertible models can both synthesize new clouds and score real ones for anomalies.
Plenty of further detail exists; if these techniques touch your workplace, you will pick up the specifics from the principles covered here. The pattern to carry forward is constant across all four domains: an exact likelihood makes scoring possible, and an invertible latent makes generation controllable.
Flows earn their place wherever two needs coincide: samples on demand and exact probabilities for whatever arrives. Super-resolution exploits the controllable latent; text, audio, and point clouds reuse the same machinery wholesale.
8.9 Exam Worked Example: Convolutional Autoencoder Code Analysis
A new exam angle deserves attention: questions grounded in the coding assignments. Nobody expects you to write pipelines of code or memorize syntax. What is tested is whether you understand the libraries you used, the arguments of the functions you called, what each argument does and does not do, and what changes if you edit one line. Such questions will be based on the assignment you already completed — not on, say, the autoregressive implementations covered elsewhere, which stay numerical.
The running example is the encoder of a convolutional autoencoder, roughly:
Conv2D(32, (3, 3), padding="same", activation="relu", input_shape=(28, 28, 3))
MaxPooling2D((2, 2))
Conv2D(64, (3, 3), padding="same", activation="relu")
MaxPooling2D((2, 2))
Flatten()
Dense(30, name="latent")
Reading the arguments before computing anything: 32 is the number of filters; (3, 3) is the kernel size; padding="same" keeps spatial dimensions unchanged by surrounding the input with zeros; activation="relu" applies the rectifier to every output feature map; and input_shape=(28, 28, 3) declares 28-by-28 images with three channels — matching the three-channel input count that the parameter arithmetic below uses.
8.9.1 Layer-by-Layer Output Sizes
Q: Tell me the output dimension after each layer of this convolutional autoencoder. A: The input shape is 28 by 28 with three channels. Padding "same" means the convolution output keeps the input size, so the first layer emits 28 by 28 by 32 — 32 is the number of filters, also called channels. Without that padding the size would shrink: a "valid" 3-by-3 convolution loses one row and one column per side, giving 26 by 26 instead. The 2 by 2 max pooling halves each side: 14 by 14 by 32. The second convolution, again with same padding and 64 filters, gives 14 by 14 by 64. The second max pool gives 7 by 7 by 64. Flatten unrolls everything into one long vector of 7 times 7 times 64 = 3136 values. The final Dense layer with 30 units — named "latent" — outputs the 30-dimensional code.
The complete arithmetic deserves its own worked pass, step by step:
Worked example — tracking every output dimension with real numbers.
Step 1. Input: 28 × 28 × 3, declared by input_shape=(28, 28, 3).
Step 2. First convolution: padding "same" surrounds the input with zeros so each filter outputs one value per input position: height and width stay 28, and depth equals the filter count → 28 × 28 × 32.
Step 3. First pooling: each 2-by-2 window collapses to its maximum, applied on a stride-2 grid, so both spatial sides halve while channels ride along untouched → 14 × 14 × 32.
Step 4. Second convolution: same padding again, now 64 filters → 14 × 14 × 64.
Step 5. Second pooling: halve both sides once more → 7 × 7 × 64.
Step 6. Flatten: unroll all values in scan order into one vector: numbers.
Step 7. Dense(30): every one of the 3136 values feeds every one of 30 output units → 30, the latent code.
The same chain as a quick-reference table:
| Layer | Output shape | Why |
|---|---|---|
| Input | 28 × 28 × 3 | declared by input_shape |
| Conv2D(32) | 28 × 28 × 32 | "same" padding preserves height and width; depth = filter count |
| MaxPooling2D((2,2)) | 14 × 14 × 32 | each 2-by-2 window collapses to its maximum; sides halve |
| Conv2D(64) | 14 × 14 × 64 | same padding again; depth becomes 64 |
| MaxPooling2D((2,2)) | 7 × 7 × 64 | halve both spatial sides once more |
| Flatten | 3136 | , unrolled in order |
| Dense(30) | 30 | the latent code |
Answer: shapes run .
Sense check: convolutions changed only channel counts (same padding), pools changed only spatial sizes, flatten changed only arrangement — total values conserved from 7×7×64 to 3136 confirms nothing was lost in the unroll.
Two habits earn marks here: track all three numbers (height, width, channels) at every row, and know which argument changed what — pooling touches only the spatial sides, convolution depth comes only from the filter count.
8.9.2 Role of the Latent Layer: Thirty Units Versus More
Q: Why does the latent layer contain only 30 neurons, and what role does it play in representation learning? A: The Dense layer is a neural network whose input side carries 7 by 7 by 64 = 3136 values and whose output side carries 30 — that squeeze is the bottleneck doing the compressing. Raise the count and you compress less: 60 neurons hold more information than 30, so reconstruction quality goes up, and the signal-to-noise ratio of the reconstruction is expected to go up too. The comparison is exactly like using 30 PCA components versus 60 PCA components — fewer components, stronger compression, blurrier recovery. Which of 16 or 60 neurons yields the higher reconstruction SNR is a computation left for practice — the suggestion was to work it out and check the reasoning with ChatGPT.
Push the thought to its limit: if the latent held as many units as the flattened layer, you would get perfect reconstruction, because no information is lost — but the latent space would be junk, giving you nothing usable for representation learning. The bottleneck is the point: forcing 3136 values through 30 numbers compels the network to spend its capacity on the regularities that matter — strokes, shapes, parts — which is precisely what makes the code reusable for downstream tasks such as classification or search. Compression here is not storage-saving; it is curriculum for the network.
8.9.3 Counting Trainable Parameters
Q: How do you calculate the number of trainable parameters in the first convolution layer? A: Multiply the kernel area by the input channels by the number of filters, then add one bias per filter: kernel height times kernel width times input channels times filters, plus filters. Here: 3 times 3 times 3 input channels = 27 weights per filter; times 32 filters = 864; plus 32 biases = 896 total.
Each filter slides across the whole image, but it always reads all three input channels at once — that is why the channel count enters per filter, not once overall. The general counting rule for a convolution layer is
where are the kernel height and width, the input channel count, and the filter count; the "+1" per filter is the bias, present when the layer's bias option (use_bias) is switched on. One clarification settles a remark from class: the bias belongs to the layer's bias setting, not to the activation choice — turning activation from "relu" to "sigmoid" changes no parameter count, while disabling biases removes exactly of them.
Applying the same rule to the second layer:
For the Dense layer: — weights plus one bias per output unit. Summing the encoder: trainable parameters, with pooling and flatten contributing none. Notice where the mass sits: over ninety percent of the encoder's parameters live in the final Dense layer, because it connects every value of a large flattened vector to every latent unit — a useful intuition when deciding whether shrinking feature maps early saves real compute.
8.9.4 Removing Both Max-Pooling Layers
Q: What happens if both max pooling layers are removed? Discuss the effect on the latent representation, computational complexity, and reconstruction quality. A: Spatial sizes stop reducing: instead of 28 to 14 to 7, the maps stay at 28 by 28 all the way to the flatten. Features going into the Dense layer then grow sixteen-fold — not four times, sixteen — because removing each 2-by-2 pool doubles both width and height, and two removals compound: from the first removal and another from the second give . Concretely, 28 by 28 by 64 = 50176 values reach the Dense layer instead of 3136. Trainable parameters in that Dense layer and the compute cost rise accordingly. The latent layer still has its 30 units, so the compression burden intensifies — squeezing 50176 values into 30 instead of 3136 into 30 — and reconstruction quality suffers as a result. The recommendation: change these values in the code you already submitted and observe the effects yourself.
The sixteen-fold figure deserves its own emphasis because it is the classic trap: seeing "two pools removed" tempts a factor of four, but each pool halves both dimensions, so each removal contributes , and factors multiply down the stack. The Dense parameter count moves in lockstep — roughly against before, about sixteen times larger — so memory and training time balloon together with the harder compression task.
8.9.5 Wider Filters: Parameters, Training Time, and Receptive Field
Consider the variant encoder with a 32-filter convolution followed by a 64-filter convolution, and grow every kernel from 3 by 3 to 7 by 7.
Q: How do the trainable parameters change, and how does training time respond? A: Keep the input channel count symbolic, call it . The first layer moves from to — from 9 weights per filter to 49. The second moves from to . If symbols feel uncomfortable, assume three input channels and give the numbers: layer one rises from to , and layer two from to . More parameters means longer training time — expect the increase.
Q: How does the receptive field change? A: Stack two 3 by 3 convolutions: a pixel in the second output effectively sees a 5-wide neighborhood of the input — one ring from each layer adds up. Three stacked 3 by 3 layers reach 7. Direct 7 by 7 filters see wide areas immediately. Stacking two 7-by-7 layers reaches , which is the exact arithmetic behind the quick in-class tally of "around fifteen or so" for the wider arrangement. Either way: bigger filters look at bigger areas.
The ring-counting rule behind those numbers: each new convolution widens the view by one ring of pixels per side, so receptive field grows as . Two 3-by-3 layers: . Three: — matching one direct 7-by-7 layer, which is why small kernels stacked deep are usually preferred to single huge kernels: same view, far fewer parameters, plus an extra nonlinearity in between.
8.9.6 Filter Size Versus Image Content: MNIST Against CIFAR
Q: Discuss the possible positive and negative effects of bigger filters on reconstruction quality. A: The question asks for possible effects, because the answer depends on the image. Small receptive fields capture small, high-frequency details — lots of fine texture — better. Large filters preserve coarse, poster-level structures better. So on detail-rich images, small filters reconstruct more accurately; on smooth, large-structure images, large filters can win. Negative effects: more parameters, more computation, and — with a small dataset — a real overfitting risk.
How would you check such a statement seriously? Not as a classroom exercise but as a working engineer with a client image: run a controlled experiment, compare reconstructions, and decide which filter suits which material. That is the real context of the assignment pairing: one dataset of MNIST-style digits and one of CIFAR-10 images. CIFAR images carry far more intricacy than digits. The educated guess offered: on CIFAR, 7 by 7 filters will make things worse, while on MNIST they may improve reconstruction — because MNIST has little high-frequency content, and large smooth strokes suit large filters. Test it yourself.
Another self-test: shrink the 28 by 28 images to 7 by 7 and see whether you can still make sense of them. On digits you can probably still tell a 2 from an 8; on CIFAR you likely cannot identify much at all. That asymmetry mirrors what big receptive fields do to fine detail — averaging windows wipe out exactly the small-scale structure that CIFAR lives on. Expect higher reconstruction error for large filters on CIFAR, and the opposite possibility on digits.
8.9.7 Overfitting in Autoencoders and Split Discipline
Q: What is the meaning of overfitting in the context of autoencoders, where the whole goal is reconstruction quality? A: It looks like success at first glance: near-zero training reconstruction error. That is precisely the trap. An overfit autoencoder drives reconstruction error toward zero on the training data alone, while the error on validation data climbs — the network has memorized the training set instead of learning to encode and decode general structure. Once memorization takes over, validation and test error rise even as training error falls. That is precisely why assignments demand numbers on all three splits: train the network on the training set, use the validation set to make sure you are neither over-training nor under-training, and verify final performance on the test set.
The correction matters because autoencoders make overfitting unusually sneaky: unlike a classifier, there is no accuracy number staring at you, and a beautiful reconstruction montage can be pure memorization. The honest signals live in the split comparison — train loss falling while validation loss turns upward is the classic crossing pattern to catch early.
Exam grades aside, this is the habit that matters in the real world: getting exam numbers does not guarantee you will handle a live model well, and handling a live model well starts with disciplined experiments and honest validation.
Exam note: Assignment-code questions cover output-shape tracking, the meaning of library arguments like padding and activation, and the effect of changing one line — removing a pool, growing a kernel, widening the latent. Practice recomputing every table above by hand until the flow 28 → 28 → 14 → 14 → 7 → 3136 → 30 feels mechanical.
8.10 Exam Worked Example: Binary Autoencoder Backpropagation
8.10.1 Setup and Architecture Choices
Consider a fully connected autoencoder at iteration t. Inputs are two-dimensional and binary, drawn from 00, 01, 10, 11. There is one hidden layer with sigmoid activations, the weights at iteration t are given, the input vector is , and all biases are zero — so biases drop out of every calculation. The learning rate is , a momentum constant is supplied, and the weight values at iteration t−1 are supplied for the momentum terms.
Q: What activation function will you choose at the output node, and what loss function do you use for training this autoencoder? A: Sigmoid at the output, because the targets are binary. A sigmoid output squashes its weighted input into , which is exactly the range a probability-style answer for a 0-or-1 target needs — no other common activation matches that shape so directly. For the loss, binary cross entropy — and you compute it for both output nodes and add the two contributions.
The method discipline stated in class applies to every line that follows: go step by step with plain numbers rather than jumping to symbols.
8.10.2 Forward Pass at Iteration t
Go step by step with plain numbers rather than jumping to symbols. The weighted input to the hidden neuron collects the input products; with the given weights it comes to
so with zero bias the hidden activation is , where the logistic sigmoid is
One property of this curve does half the work today: a sigmoid always outputs one half at exactly zero input, and it squashes every real number into , which is what lets its outputs stand in for probabilities of binary targets. With known, both output nodes can be evaluated, and the loss assembled — the full trace runs below.
Worked example — the full forward pass and loss in one trace.
Given: input , zero biases, hidden activation , targets , learning rate .
Step 1 — hidden weighted input: with the given weights.
Step 2 — hidden activation:
Step 3 — first output: weighted input , prediction
Step 4 — second output: weighted input , prediction .
Step 5 — loss, node by node:
Answer: .
Sense check: both contributions are positive, the first sits below 0.7 because the model leaned the right way ( toward target 1), and the second equals the cost of predicting a coin flip against a certain 0 — all consistent with a network early in training.
8.10.3 Binary Cross-Entropy Loss Calculation
The loss for both nodes together is:
where is the target (1 or 0) and the predicted probability for output node k. Each term punishes confidence in the wrong answer: if , only survives, growing without bound as approaches zero.
Target output is , so exactly one term per node survives: for node 1, the term keeps ; for node 2, kills the first term and leaves . Substituting the forward-pass predictions gives the two contributions and their total, as traced in the worked example: , , summing to .
When this arithmetic was floated aloud in class some intermediate values wandered near 0.69 and 0.9 before settling — the reliable route is exactly the one traced above: evaluate each surviving log separately, then add.
8.10.4 Weight Updates by Chain Rule
Every weight moves by gradient descent, and the momentum term pulls from the previous iteration's stored values:
Written in the standard incremental form, the momentum contribution is a constant times the previous update, , where the supplied values at iteration t−1 fill in .
The weight sitting directly on an output path is simple: one derivative of the loss with respect to it suffices, because no layer stands between it and the loss. The weight feeding the hidden layer needs the chain rule of differentiation — take the derivative of the loss with respect to the output, then the derivative along each link down the path to the weight, and multiply the pieces:
where is the hidden activation, the first output's weighted input, and the hidden node's weighted input. Every factor in that chain has a closed form worth memorizing, and filling them in shows how short the algebra really is:
That last cancellation is the celebrated shortcut: with sigmoid outputs trained by cross entropy, the error signal reduces to prediction minus target. Numerically here,
Continuing down the chain toward with the given weights (the hidden-to-output path into node 1 carries weight 1, and ):
using . The gradient step then moves the weight uphill against this negative gradient:
with the final numeric value completed by inserting the supplied momentum constant and previous-update values from the problem sheet. The finished numerical answer sits in the posted problem set, and ChatGPT reproduces it on request — but the repetition odds for this exact question are ten to fifteen percent, so treat it as practice for the method, not a prediction. Practice several such problems; doing all of them can only help.
Pitfalls:
- Dropping one output node from the loss: binary cross entropy must be summed over both outputs before any gradient is taken.
- Sign slips in : with target 1 and prediction 0.62 the error is negative (the prediction must rise), which flips the direction of the weight update. Write explicitly rather than trusting instinct.
- Forgetting the sigmoid derivative factor , or plugging in the wrong activation value — recompute at every forward pass instead of reusing stale numbers.
- Adding momentum with the wrong sign or using weights from t−1 where updates from t−1 belong: momentum carries the previous change, not the previous parameter value.
Exam note: Expect quantitative numericals like this one; practice the posted papers and repeat-chance problems run ten to fifteen percent. The reusable skeleton is fixed: forward pass with real numbers, per-node cross entropy, error signals via , chain rule back through the hidden layer, gradient step plus momentum.
Exam Guidance Summary
- Closed book exam. Take the regular exam rather than a makeup whenever possible.
- Carry a scientific calculator. Most problems are quantitative, and minor calculation slips cost only small deductions given the working-professional audience.
- The course continues the deep neural networks course: refresh backpropagation-based weight updates, CNN architectures, convolution operations of every kind — including transposed convolutions — and parameter counting. Those are memory-refresh items, not new study.
- Syllabus scope is what was covered in class sessions so far: PCA and its variants; the autoencoder family — undercomplete, overcomplete, denoising, sparse, regularized, and the linearized version that implements PCA; autoregressive models — WaveNet, Parallel WaveNet, MADE, PixelCNN, PixelCNN++, and Gated PixelCNN; flow models and variants — MAF, IAF, RealNVP, affine flows. Material sitting in decks but never discussed in class will not appear.
- Previous question papers are posted with roughly twelve to fourteen questions; practicing them puts you in good shape. Generate extra problems with ChatGPT — for example on WaveNet or PixelCNN, sized small enough for hand calculation — and verify your results there. When answers disagree, the cause is usually a technique outside class coverage, and you will spot it.
- New this time: questions about your assignment code. Expect output-dimension tracking, the meaning of library arguments, and what one changed line does to the output. Not syntax memorization, and not implementation questions on the autoregressive models handled elsewhere — those stay numerical.
- Four main questions with sub-questions, mirroring the posted papers' patterns.
- Grading is relative across the whole class cohort: scoring 90 means trouble if everyone scores above 90; scoring 35 is comfortable when others sit at 30 or below. Do not obsess over individual question marks.
- Question difficulty aims low on purpose — typical averages near thirty percent, with strong students reaching eighty. Worked problems shown in class have a ten to fifteen percent chance of repeating in some form.
- Study the posted solutions; where understanding feels shaky, prompt ChatGPT for elaborate explanations with a reasonable prompt rather than a lazy one.
A practical reading order for revision falls straight out of this list: first re-derive the two worked autoencoder problems until each numeric step is automatic; second, re-run the parameter-counting and shape-tracking tables from the assignment code with one deliberate change per pass (remove a pool, grow a kernel, widen the latent); third, generate fresh small numericals on WaveNet-style and PixelCNN-style factorizations and solve them by hand against the calculator. Relative grading rewards steady, boring correctness over brilliance on any single question.
Key Industry Applications
- Real-world: sequential autoregressive decoding is why ChatGPT-style systems create images slowly; flow models attack exactly this latency problem with parallel sampling.
- Real-world: Glow (OpenAI) supports attribute editing and interpolation on faces — smiles, hair color, smooth morphs between identities — from intelligent movement among base-distribution samples.
- Real-world: SRFlow brings flow models to super-resolution, synthesizing large images from small ones with user-steerable latent choices instead of a single averaged guess.
- Real-world: flow-based text synthesis manipulates latent dimensions under explicit assumptions; audio synthesis and 3D point-cloud generation reuse the same machinery — point clouds matter especially for 3D computer vision and autonomous-driving simulation.
- Real-world: dequantization by adding uniform noise is mandatory whenever flow models meet digital sensor data — images, in practice — because change of variables needs continuous inputs to stay trainable.
- Real-world: exact likelihood evaluation turns flow models into anomaly screens: industrial inspection and fraud pipelines flag inputs whose learned probability drops below threshold.
- Real-world: the filter-size versus image-content analysis is a live engineering decision — with a client image, run controlled experiments on filter choices and let validation numbers decide.
Across every bullet runs one thread: the same two capabilities — draw a sample when you need one, price any input exactly — are what let these models move from lecture slides into production systems for media editing, sensing, and monitoring.
UDL Lecture 8 notes · Normalizing Flows: Masked Autoregressive Models
Sections Breakdown
Causal masking under raster-scan order, the sequential-generation bottleneck, and why flow models exist.
Data-to-latent invertible maps, simple base densities, bijectivity, and the Jacobian determinant requirement.
The density transformation rule derived from mass conservation, the negative log-likelihood loss, and layer composition.
Generative equations, conditionally Gaussian dimensions, fast scoring versus slow sequential sampling.
Parallel generation from latents, sequential likelihood evaluation, and how to choose between MAF and IAF.
Affine and element-wise flows, NICE additive coupling, RealNVP learned scales, checkerboard masks, and 1x1 convolutions.
Why quantized data breaks change of variables and how uniform noise restores continuity.
Super-resolution with SRFlow, text synthesis, parallel audio vocoders, and 3D point-cloud generation.
Shape tracking through convolution and pooling layers, parameter counting, pooling removal, kernel size effects, and overfitting discipline.
Full forward pass, binary cross-entropy loss, error signals, and chain-rule weight updates with momentum.
Closed-book logistics, syllabus scope, question patterns, relative grading, and a practical revision order.
Parallel generation latency fixes, face editing and interpolation, super-resolution, anomaly screening, and sensor dequantization.
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.
Masking and Autoregressive Modelling Recap
Must-know: Autoregressive generation is inherently sequential (x1 then x2 then x3); flows exist to generate in parallel and to provide latents — vanishing gradients are NOT the motivation.
⚠️ Top pitfall: Masking leaks: letting even one future position through breaks the factorization while training likelihood still looks fine.
Self-check: Under raster-scan ordering on a 4x4 grid, which positions may inform the density of pixel 7?
Connects to: The Normalizing Flow Framework (8.2); Masked Autoregressive Flow (8.4).
The Normalizing Flow Framework
Must-know: Flow transformations must be bijective (squaring fails: +a and -a collide), latents match data dimension, and the Jacobian determinant must be easily computed and nonzero — triangular structure guarantees both.
⚠️ Top pitfall: A zero diagonal entry in a triangular Jacobian collapses volume to zero and breaks the model.
Self-check: Why is f(x) = x^2 unacceptable as a flow transformation?
Connects to: Change of Variables and Maximum Likelihood Training (8.3); Flow Building Blocks from Affine Coupling to Glow (8.6).
Change of Variables and Maximum Likelihood Training
Must-know: p_X(x) = p_Z(z)|det(dz/dx)|: stretch the support twice and the density height halves (f(x)=2x+1 on [0,1] gives height 1/2 on [1,3], area still 1).
⚠️ Top pitfall: The determinant must be easy to calculate AND easy to differentiate, or the model cannot train at all.
Self-check: Why does an autoregressive construction make the Jacobian determinant trivial to compute?
Connects to: The Normalizing Flow Framework (8.2); Masked Autoregressive Flow (8.4).
Masked Autoregressive Flow (MAF)
Must-know: x_i = z_i*exp(alpha_i) + mu_i with mu_i, alpha_i functions of x_1..x_{i-1}; each conditional is N(mu_i, exp(alpha_i)^2), so exp(alpha) is the standard deviation.
⚠️ Top pitfall: Confusing the variance exp(alpha)^2 with the standard deviation exp(alpha); also evaluating densities by sampling instead of using the fast parallel scoring path.
Self-check: Why must MAF sample sequentially even though its Jacobian determinant is cheap?
Connects to: Masking and Autoregressive Modelling Recap (8.1); Inverse Autoregressive Flow (IAF) (8.5).
Inverse Autoregressive Flow (IAF)
Must-know: MAF: fast scoring, slow sampling. IAF: fast sampling, slow scoring and direct training; Parallel WaveNet distills a slow teacher into a fast IAF student.
⚠️ Top pitfall: The name misleads: IAF is the flow whose generative pass is parallel — "IAF samples fast".
Self-check: Which model would you deploy for real-time speech generation, and why?
Connects to: Masked Autoregressive Flow (8.4).
Flow Building Blocks from Affine Coupling to Glow
Must-know: Additive coupling keeps det = 1 (volume preservation); affine coupling gives det = exp(sum of scale outputs), so RealNVP is non-volume-preserving by design.
⚠️ Top pitfall: Stacking identical coupling layers without alternating masks or shuffles leaves half the coordinates permanently copied — nothing mixes.
Self-check: Why does the NICE Jacobian's determinant ignore everything m_theta computes?
Connects to: The Normalizing Flow Framework (8.2); Discrete Data and Dequantization (8.7).
Discrete Data and Dequantization
Must-know: Dequantization: x-tilde = x + u with u ~ Uniform(0,1)^D turns discrete atoms into smooth plateaus; quantized data trains erratically while dequantized data settles.
⚠️ Top pitfall: Mistaking dequantization for regularization noise — its purpose is restoring the continuity that derivatives need, not preventing overfitting.
Self-check: What does one 8-bit pixel value of 128 become after dequantization?
Connects to: Change of Variables and Maximum Likelihood Training (8.3); Flow Building Blocks from Affine Coupling to Glow (8.6).
Applications of Flow Models
Must-know: SRFlow = flows for super-resolution; flows also cover text, audio, and point clouds — exact likelihood enables scoring, invertible latents enable control.
⚠️ Top pitfall: Assuming regression-style decoders and flow decoders behave the same: regression averages away uncertainty, flows sample distinct plausible outputs.
Self-check: What advantage does SRFlow's invertible latent space give over a plain regression decoder?
Connects to: Flow Building Blocks from Affine Coupling to Glow (8.6).
Exam Worked Example: Convolutional Autoencoder Code Analysis
Must-know: Conv parameter count = (kernel area * input channels + 1 bias) * filters: layer one of the example is (3*3*3+1)*32 = 896; removing both pools grows Dense inputs sixteen-fold to 50176.
⚠️ Top pitfall: Overfit autoencoders hit near-zero training reconstruction error while validation error climbs — always report all three splits.
Self-check: Why do stacked 3x3 filters reach a receptive field of 5 with fewer parameters than one direct 7x7 filter?
Connects to: Binary Autoencoder Backpropagation (8.10).
Exam Worked Example: Binary Autoencoder Backpropagation
Must-know: Sigmoid output + binary cross entropy gives the shortcut dL/du = y - t; here L = -ln(0.6225) - ln(0.5) = about 1.17.
⚠️ Top pitfall: Dropping one output node from the loss, or losing the sigmoid derivative factor y(1-y) inside the chain rule.
Self-check: Why is the second output's loss contribution exactly -ln(0.5)?
Connects to: Convolutional Autoencoder Code Analysis (8.9).
Exam Guidance Summary
Must-know: Know reasons over names; practice posted papers (12-14 questions); worked problems repeat at ten to fifteen percent.
⚠️ Top pitfall: Obsessing over individual question marks — grading is relative across the cohort.
Self-check: What scope does the exam cover?
Connects to: Convolutional Autoencoder Code Analysis (8.9); Binary Autoencoder Backpropagation (8.10).
Key Industry Applications
Must-know: Two capabilities transfer everywhere: sample on demand and price any input exactly.
⚠️ Top pitfall: Deploying flows on raw quantized sensor data without dequantization destabilizes training.
Self-check: Which flow application needs dequantization first, and why?
Connects to: Discrete Data and Dequantization (8.7); Applications of Flow Models (8.8).
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.