Deep Learning
CSC_51054_EP · Year 1 · Period 1
Contents
- Introduction and overview
- 0. Review: matrix differential calculus and numerical stability
- 1. From the neuron to the deep network
- 2. Backpropagation
- 3. Optimization in practice
- 4. Convolutional networks (CNN)
- 5. Sequences: RNN, LSTM
- 6. Attention and transformers
- 7. Transfer learning and fine-tuning
- 8. Training in practice
- 9. Generative models: AE, VAE, GAN
- 10. Research at DaSciM (Vazirgiannis, Lutzeyer, Zhu)
- Exercises
- Projects and assessment
- References
Introduction and overview
| Module | Deep Learning — SynapseS sheet 2026-2027: “Programme d’approfondissement — Apprentissage automatique et apprentissage profond” (occurrence: “Machine and Deep learning”, computer science department) |
| Code | CSC_51054_EP |
| Team and workload | Responsible (sheet): Michalis Vazirgiannis · responsible of the 2026-2027 occurrence: Davide Buscaldi · teaching team: Inès Benito, Davide Buscaldi, Iakovos Evdaimon, Xiao Fei, Niklas Kormann, Johannes Lutzeyer, Achilleas Tsimichodimos · 36 h in person (no lecture / small-class split displayed) · 4.5 ECTS · assessment: not displayed for LLGA · prerequisites: not displayed · teaching language: English · from perceptrons to transformers, with the “graph” reading that prepares the Graph ML module. |
| Status in the program | Graph × LLM route one of the two ways to satisfy the “Deep Learning once” rule (the other is the P2 variant) · M1 · S1 / Period 1 — X-3A-P1 (fall semester, from 17/09/26 to 18/12/26) |
Audience: an engineer who has already trained an MNIST-like MLP (or a toy CNN) and wants to understand why it converges — or blows up into NaNs — before opening Cybenko. Empirical first: a stuck loss, a vanishing gradient, 99% train / 70% test accuracy; only then do we name depth, activations, backprop.
From perceptrons to transformers: networks, backpropagation, CNNs, RNNs, attention, generative models. The program’s LLMs are transformers; without this module, architecture, training and fine-tuning stay opaque. Guiding thread: a network is a computation graph; attention is reread as a GNN in Period 2.
What you will be able to do
- Build a neural network from scratch: layers, activations, initialization, and understand what depth buys.
- Unroll backpropagation by hand on a small network, and code it in PyTorch without copying a tutorial.
- Diagnose a failing training run: gradient explosion/vanishing, learning rate, normalization, numerical stabilization.
- Choose an architecture according to the data: CNNs for images, RNN/LSTM for sequences, transformers for everything else.
- Explain the attention mechanism and the transformer architecture, up to the explicit link with GNNs.
- Distinguish the generative families: autoencoders, VAEs, GANs and, in self-study, diffusion models — their objectives, their losses, their uses.
- Adapt a pretrained model to a new task by transfer learning and fine-tuning, with the right layer freezing/tuning reflexes.
- Launch a realistic training run: GPU, mixed precision, experiment tracking, reproducibility.
Official objectives and syllabus (2026-2027 catalog)
Official objectives: the SynapseS sheet publishes a description and a detailed programme but no separate “objectives” block. The description places the course in the era of large data sets, where the challenge is to extract knowledge from them and build intelligent services.
It presents deep learning as the paradigm that learns rich representations directly from raw data, through convolutional networks, transformers and large pretrained models, with applications in computer vision, natural language processing, data generation, bioinformatics and learning on graphs, and it announces both the theoretical foundations and concrete large-scale applications. The official keywords are machine learning, deep learning, artificial intelligence, graph neural networks.
The detailed programme (“minor changes may occur during the course”) has nine blocks, from a general introduction to machine learning to reinforcement learning. The table below gives one row per topic of that programme. The first five blocks, the machine-learning half, are taught in the twin module Machine Learning (MDC_51006_EP, mandatory in the same period); the rows give the exact sections there.
| Topic of the official programme (block) | Section that covers it |
|---|---|
| Machine learning paradigms (general introduction) | ML module, ch. 1 (note “Learning paradigms and the pipeline”) and ch. 7; here 1.5 (reinforcement) and 6.5 (self-supervised pretraining) |
| Machine learning pipelines (general introduction) | ML module, ch. 4 (4.2 nested cross-validation, 4.3 data leakage, 4.6 the reference pipeline); here 8.1 (the training recipe) |
| Generative and non-generative methods (supervised) | ML module, 3.3 (generative versus discriminative classifiers, proposition 3.8), with 3.1 (logistic regression) and 3.2 (SVM) as discriminative methods |
| Naive Bayes classification (supervised) | ML module, 3.3 (definition 3.7, example 3.9) |
| Decision trees (supervised) | ML module, 6.1 (CART) |
| Dimensionality reduction (unsupervised) | ML module, 7.3 (PCA, probabilistic PCA); here 9.1 (linear autoencoder = PCA, nonlinear autoencoders) |
| Clustering (unsupervised) | ML module, 7.1 (k-means) and 7.2 (Gaussian mixtures and EM) |
| Regularization (advanced concepts) | ML module, 2.2 (ridge, lasso); here 3.6 (dropout, weight decay, label smoothing, augmentation, early stopping) |
| Model selection (advanced concepts) | ML module, 1.2 (cross-validation), 4.2 (nested cross-validation) and ch. 8 (capacity) |
| Feature selection (advanced concepts) | ML module, 4.7 (filter, wrapper, embedded; the selection-bias trap) |
| Ensemble methods (advanced concepts) | ML module, 6.2 (bagging, random forests) and 6.3 (boosting) |
| Introduction to kernels (kernels) | ML module, ch. 5 (5.1 Moore-Aronszajn, 5.2 representer theorem) |
| Support vector machines (kernels) | ML module, 3.2 (primal, dual, KKT conditions) and 5.2 (kernel SVM) |
| Introduction to neural networks | ch. 1 (definition 1.1, 1.2 universal approximation, 1.3 initialization, 1.4 activations) |
| Perceptrons and backpropagation of the gradient | 1.1 (perceptron rule, Novikoff’s theorem, XOR) and ch. 2 (backpropagation) |
| Convolutional networks¹ (deep learning I) | ch. 4 |
| Recurrent networks (deep learning I) | ch. 5 (5.1 RNN and backpropagation through time, 5.2 LSTM and GRU) |
| Applications (deep learning I) | 5.3 (classification, detection and IoU, segmentation, sequence tasks) and 4.4 (historical architectures) |
| Modern natural language processing (deep learning II) | 6.5 (BPE tokenization, causal and masked language models, perplexity), ch. 6 (transformers) and ch. 7 (fine-tuning, LoRA) |
| Unsupervised deep learning (deep learning II) | ch. 9 (autoencoders, VAE, GAN; 9.4 diffusion, self-study) and 6.5 (self-supervised pretraining) |
| Embeddings² (deep learning II) | 6.5 (definition 6.5: embedding matrix, word2vec, contextual embeddings) |
| Autoencoders (deep learning II) | 9.1 (deterministic and linear autoencoders) and 9.2 (VAE) |
| Generative adversarial networks (deep learning II) | 9.3 |
| Reinforcement learning | 1.5 (MDP, policy, Bellman equation; introduction to the paradigm); the full treatment is in the Reinforcement Learning and Autonomous Agents module (Period 2) |
¹ The official sheet writes “réseaux de neurones conventionnels” (“conventional neural networks”), to be read as “convolutional” in view of the listed applications. ² The French sheet writes “intégrations”, a literal translation of “embeddings”. Referring the machine-learning half to the twin module is an organizational choice of these notes, flagged here. In return, these materials go beyond the official programme on three points: the detailed treatment of attention and transformers (the programme names only “modern natural language processing”), transfer learning and fine-tuning (ch. 7), and training in practice (ch. 8: GPU, mixed precision, reproducibility).
| Official field | Published value (SynapseS 2026-2027) |
|---|---|
| Fields | Computer Science |
| Workload | 36 h in person (no lecture / small-class split displayed) · enrollment min. 1, max. 156 |
| Period / language | X-3A-P1, fall semester, period 1 (17/09/26 – 18/12/26) · English |
| Responsible | Michalis Vazirgiannis · responsible of the 2026-2027 occurrence: Davide Buscaldi · teaching team: Inès Benito, Davide Buscaldi, Iakovos Evdaimon, Xiao Fei, Niklas Kormann, Johannes Lutzeyer, Achilleas Tsimichodimos |
| Prerequisites | Not displayed (the prerequisites tab is empty) |
| Assessment | Grade format: numeric out of 20 (and US letter grade) · the section for the LLGA track is empty: no assessment form, resit rule, pass threshold or ECTS is displayed for LLGA, and no breakdown of assessments is given for any degree · for the other degrees: unit acquired if final grade ≥ 10; resit allowed (max of the two grades for ViCAI, TRAI, X, exchange programs; resit grade kept, resit on request from an initial grade of 7, for the other masters); ECTS 5 (X, the masters, X-HEC, exchange programs, non-degree students), 4.5 (ViCAI, TRAI), 4 (Cybersecurity track) · these notes keep 4.5 ECTS for LLGA |
Where this course fits in the program
Year 1 · Period 1 course (36 h, 4.5 ECTS) preselected by the Graph × LLM route. It is one of the two ways to satisfy the “Deep Learning once” rule; the other is the P2 variant, taken in Period 2. It comes right after the Machine Learning module, of which it is the natural continuation: the perceptron is reread there as a linear model, optimization as stochastic gradient descent.
The official 2026-2027 sheet displays no prerequisites (its tab is empty); the positioning below describes the foundations actually assumed. The two refreshers — Refresher in Statistics and Refresher in Computer Science — are assumed acquired, notably NumPy matrix computation for the labs.
Downstream, this module (or its P2 variant) is the gateway to the “large models” part of the program: Introduction to Text Mining and NLP and Large Language Models (M2) build directly on the “Attention and transformers” chapter; Multimodal Generative AI extends the generative models (VAE, GAN) and fine-tuning. The attention chapter is also reread as a GNN in the Graph Machine and Deep Learning for Generative AI module: a transformer processes a set of tokens as a complete graph, and this reading unifies the two sides of the program.
The “Training in practice” chapter finally prepares the large-scale projects of Period 2 and the internships: this is where research code becomes engineering code.
Course outline
- Review: matrix differential calculus and numerical stability: gradients of matrix functions and conditioning — the background that avoids 80% of training bugs.
- From the neuron to the deep network: perceptron, activations, initialization, expressivity of depths — and, in closing (section 1.5), the reinforcement learning paradigm required by the official programme, taught in the last session as the sheet lists it last.
- Backpropagation: the chain rule on a computation graph, unrolled then automated.
- Optimization in practice: SGD and variants (momentum, Adam), learning-rate scheduling, batch normalization.
- Convolutional networks (CNN): convolution, pooling, classical architectures — learned vision.
- Sequences: RNN, LSTM: processing the sequential before attention, and understanding their limits.
- Attention and transformers: the mechanism underlying LLMs, also read as message passing on a graph, and its use on images (ViT).
- Transfer learning and fine-tuning: reusing a pretrained model — the most frequent professional gesture.
- Training in practice: GPU, mixed precision, experiment tracking — from research code to reproducible code.
- Generative models: AE, VAE, GAN: representing and generating data, three strategies compared, then diffusion in one self-study section.
- Research at DaSciM (Vazirgiannis, Lutzeyer, Zhu): the research of Michalis Vazirgiannis, Johannes Lutzeyer and Ye Zhu, from transformers to graphs.
Session plan
36 h in class = 12 sessions of 3 h. The volume is the one of the SynapseS 2026–2027 sheet (36 h in person).
The sheet gives no session-by-session timetable, but its detailed programme lists the topics in order, and the split below follows that order: its machine-learning blocks are taught first, in the Machine Learning module of the same period; then come neural networks and the perceptron (sessions 2–3), convolutional and recurrent networks with their applications (sessions 7–8), modern NLP (session 9), unsupervised deep learning (sessions 11–12), and reinforcement learning last (session 12), as on the sheet.
Optimization (ch. 3) and transfer learning and training practice (ch. 7–8) are additions of these notes, placed where the architectures need them.
Level 1 = foundations (reviews, definitions, first worked examples), 2 = core methods (backpropagation, optimization, the architectures), 3 = advanced material (generative models and their full derivations); the level never goes down from one session to the next.
| Session | Hours | Level | Content | Practice |
|---|---|---|---|---|
| 1 | 3 h | 1 | ch. 0 Review: matrix calculus, mini-batch noise, stable softmax | lab: log-sum-exp and NaNs in PyTorch (sheet in 0.3) |
| 2 | 3 h | 1 | ch. 1.1–1.2 Perceptron rule, Novikoff’s theorem and XOR; neuron and MLP, universal approximation | Ex. 2 |
| 3 | 3 h | 2 | ch. 1.3–1.4 Xavier and He initialization, activations; ch. 2 Backpropagation, with a NumPy gradient check | Ex. 1, 8 |
| 4 | 3 h | 2 | ch. 3.1–3.2 SGD on a quadratic, momentum | Ex. 5 |
| 5 | 3 h | 2 | ch. 3.3–3.4 Adam, step scheduling and warmup | Ex. 9 |
| 6 | 3 h | 2 | ch. 3.5–3.6 BatchNorm, LayerNorm, regularization | lab: dropout and weight decay on an MLP (sheet in 3.6) |
| 7 | 3 h | 2 | ch. 4 Convolutional networks, receptive field, residual blocks | Ex. 6 |
| 8 | 3 h | 2 | ch. 5 RNN, backpropagation through time, LSTM; 5.3 applications: classification, detection and IoU, segmentation, sequence tasks | lab: gradient norm through time (sheet in 5.2) |
| 9 | 3 h | 2 | ch. 6 Attention and transformers: positional encodings, cross-attention, GPU memory and FlashAttention; 6.5 modern NLP: BPE tokenization, embeddings (word2vec stated, derived later in NLP), causal and masked language models, perplexity; 6.6 vision transformers (ViT) | Ex. 3, 4 |
| 10 | 3 h | 2 | ch. 7 Transfer learning (linear probe, partial and full fine-tuning) and LoRA; ch. 8 Training in practice (mixed precision, tracking) | Ex. 7; Ex. 12 (start the project) |
| 11 | 3 h | 3 | ch. 9.1–9.2 Autoencoders (the linear autoencoder is PCA), VAE and the ELBO | Ex. 10 |
| 12 | 3 h | 3 | ch. 9.3 GAN: minimax game and equilibrium; then ch. 1.5 the reinforcement learning framework (MDP, policy, Bellman equation), last as in the official programme | Ex. 11; Ex. 12 (project) |
Self-study, outside the 36 h (about 5 h in total): ch. 9.4 Diffusion in one section, with a box on normalizing flows (≈ 2 h) · ch. 10 Research at DaSciM — Graph of Words, GNN expressivity, steering diffusion models (≈ 3 h).
How to study this module
- Take the review chapter seriously: numerical stability and matrix computation are presented there because they condition backpropagation, the pivotal chapter of the course.
- Unroll backpropagation by hand on a two-layer network before coding it: this is the exercise that separates those who understand from those who copy.
- Run all the notebooks: the course alternates derivation and experiment, and each chapter has its PyTorch lab whose reflexes (shapes, dtypes, device) serve until M2.
- After the attention chapter, redraw the transformer diagram from memory and identify where a “graph” would be: this reading will be asked of you again in the Graph ML module.
- Actually fine-tune a small pretrained model on your own data: the transfer learning chapter is a gesture, not a reading.
- If you have a gap in optimization or generalization, go back to the Machine Learning module: chapters 2 and 3 here are its direct continuation.
Notation Deviations from the site conventions (notation page). L is the depth of a network in ch. 1–2 (and in checkpointing), while in ch. 3 it is the smoothness constant of the gradient. Section 6.1 writes one token in column form, q_i = W_q x_i, next to the row form Q = XW_Q of the batch.
Everything else follows the site conventions:
- data D_n = \{(x_i, y_i)\}_{i=1}^n drawn i.i.d. from a distribution P, mini-batches of size b, learning rate \eta;
- a loss \ell(\hat y, y) with the prediction first, and a calligraphic \mathcal{L} that is always minimized;
- a linear layer h = Wx + b whose matrix W has size d_{\mathrm{out}} \times d_{\mathrm{in}}, as
nn.Linear.weight; - the VAE objective \mathrm{ELBO}(\theta, \phi; x), maximized (ch. 9); value functions V^\pi, Q^\pi with their superscript (1.5); vocabulary \mathcal{V}, while V is the value matrix (ch. 6).
independent note LLMs × graphs: this module is the hub — the transformer already reads as a network on a graph. Large-model engineering or a PhD: hands-on training mastery (shapes, LR, NaNs) matters as much as the architecture on the slide.
0. Review: matrix differential calculus and numerical stability
Deep learning is, 90% of it, differential calculus applied to functions with billions of parameters. This chapter consolidates the L3 tools we will need every week: differentiation of matrix functions, the central limit theorem (to understand why SGD works) and a bit of numerical stability (to understand why naive implementations produce NaNs).
L3 review — the basic mechanics
- Chain rule: (g \circ f)'(x) = g'(f(x))\, f'(x); in dimension: \nabla (g \circ f)(x) = J_f(x)^\top \nabla g(f(x)), where J_f is the Jacobian matrix (J_f)_{ij} = \partial f_i / \partial x_j.
- Gradient of quadratic forms: \nabla_x \tfrac12\|Ax - b\|^2 = A^\top(Ax - b) and \nabla_x x^\top A x = (A + A^\top)x.
- Derivatives of the usual activations: \sigma' = \sigma(1-\sigma), \tanh' = 1 - \tanh^2, \mathrm{ReLU}' = \mathbf{1}_{x>0}, and for the softmax \hat y = \mathrm{softmax}(z): \partial \hat y_k / \partial z_j = \hat y_k(\delta_{kj} - \hat y_j).
- CLT: the mean of m iid variables with variance \sigma^2 fluctuates around its expectation with standard deviation \sigma/\sqrt m (cf. Refresher Statistics module).
0.1. Differentiation of matrix functions
A network’s parameters are matrices; one must know how to differentiate with respect to a matrix. The most convenient convention: the gradient of a function f : \mathbb{R}^{m \times n} \to \mathbb{R} is the matrix G such that f(X + H) = f(X) + \langle G, H\rangle + o(\|H\|) with the Frobenius inner product \langle G, H \rangle = \mathrm{tr}(G^\top H). Three identities suffice for this whole course.
Proposition 0.1 — Useful differential identities For X \in \mathbb{R}^{m \times n}, a \in \mathbb{R}^m, b \in \mathbb{R}^n, A of compatible size: \frac{\partial}{\partial X}\,\mathrm{tr}(A^\top X) = A, \qquad \frac{\partial}{\partial X}\, a^\top X b = a\, b^\top, \qquad \frac{\partial}{\partial X}\, \tfrac12\|X A - B\|_F^2 = (XA - B)A^\top.
Proof. We prove the second (the others are identical). Write a^\top X b = \sum_{i,j} a_i X_{ij} b_j = \mathrm{tr}(b a^\top X). The differential is d(a^\top X b) = a^\top H b = \langle a b^\top, H\rangle for any perturbation H, so the gradient (in the Frobenius sense) is ab^\top.
For the third: f(X) = \tfrac12\|XA - B\|_F^2, df = \langle XA - B,\; HA\rangle = \langle (XA-B)A^\top,\; H\rangle, using the cyclicity of the trace \mathrm{tr}(M^\top H A) = \mathrm{tr}((M A^\top)^\top H) with M = XA - B. ∎
Practical rule In a network, “the gradient climbs back through the transposes”: if the forward pass contains z = Wx, the backward pass contains \nabla_x = W^\top \nabla_z and \nabla_W = \nabla_z\, x^\top.
Always check the dimensions: \nabla_W has the size of W, \nabla_x that of x. This is the most effective quality control against backprop bugs.
0.2. CLT and mini-batch noise
Why optimize on mini-batches rather than on the whole dataset? Let D_n = (\xi_1, \dots, \xi_n) be n iid samples from a distribution P, and the empirical risk \hat R_n(\theta) = \frac1n \sum_{i=1}^n \ell(\theta; \xi_i). For a mini-batch B = (\xi_{i_1}, \dots, \xi_{i_b}) of b indices drawn uniformly and independently, the mini-batch gradient is \hat g(\theta) = \frac1b \sum_{j=1}^b \nabla_\theta \ell(\theta; \xi_{i_j}).
Proposition 0.2 — The stochastic gradient is an unbiased estimator with 1/\sqrt b noise \mathbb{E}[\hat g] = \nabla \hat R_n and, if the individual gradients have finite covariance \Sigma = \mathrm{Cov}(\nabla \ell(\theta; \xi)), then \mathrm{Cov}(\hat g) = \frac{1}{b}\,\Sigma.
Proof. Write G_j = \nabla \ell(\theta; \xi_{i_j}). By uniform sampling, \mathbb{E}[G_j] = \nabla \hat R_n, and linearity of expectation gives the mean of \hat g. For the covariance, the draws are independent: \mathrm{Cov}(\tfrac1b\sum_j G_j) = \tfrac{1}{b^2}\sum_j \mathrm{Cov}(G_j) = \tfrac1b \Sigma.
The standard deviation of the estimation therefore decreases as \|\Sigma\|^{1/2}/\sqrt b: multiplying the batch size by 100 divides the noise by only 10 — an economic argument for small batches, completed in chapter 3 (the noise also has a beneficial exploration effect). ∎
0.3. Numerical stability: softmax and the log-sum-exp trick
The softmax \hat y_i = e^{z_i} / \sum_j e^{z_j} appears in all classification losses and in attention. In floating-point precision (float32, max \approx 3.4 \times 10^{38}), the naive implementation overflows: e^{1000} = \infty, and \infty/\infty = \mathrm{NaN}. The universal trick is to subtract the maximum before exponentiating.
Proposition 0.3 — log-sum-exp identity and stable softmax Set \mathrm{LSE}(z) = \log \sum_{j=1}^n e^{z_j} and m = \max_j z_j. Then: \mathrm{LSE}(z) = m + \log \sum_{j=1}^n e^{z_j - m}, \qquad m \;\le\; \mathrm{LSE}(z) \;\le\; m + \log n, \mathrm{softmax}(z)_i = \frac{e^{z_i - m}}{\sum_j e^{z_j - m}}, and this last form never overflows.
Proof. Factorization: \sum_j e^{z_j} = e^{m} \sum_j e^{z_j - m}, hence \mathrm{LSE}(z) = m + \log \sum_j e^{z_j - m}. Since 0 < e^{z_j - m} \le e^0 = 1 and at least one term equals exactly 1 (that of the maximum), the sum lives in [1, n], giving the bracket.
For the softmax, dividing numerator and denominator by e^m > 0 does not change the value.
Stability: all the exponents z_i - m \le 0, so each e^{z_i - m} \in (0, 1]: no overflow, and the dominant term of the denominator equals exactly 1, so the result stays accurate even when the other terms underflow toward 0 (which is harmless: the softmax simply tends toward a one-hot). ∎
import torch
z = torch.tensor([1000., 1001., 999.])
# print(torch.softmax(z, 0)) # NaN with a naive implementation
print(torch.logsumexp(z, 0)) # 1001.4076: stable (PyTorch always applies it)
print(torch.softmax(z - z.max(), 0)) # stable form: [0.2447, 0.6652, 0.0900]Numerical culture This section also prepares chapter 8: most NaNs during training come from an unprotected softmax/exponent, from the log of a zero probability (one minimizes -\log p via log-softmax, never -\log(\mathrm{softmax})), or from a too-large learning rate. The rule: when a NaN appears, walk back up the forward pass layer by layer until you find the first infinite activation.
Lab sheet — session 1: log-sum-exp and NaNs in PyTorch Goal: make a NaN appear on purpose, find where it comes from, and remove it.
- Code a naive softmax and a naive cross-entropy in float32. Feed them logits scaled by 10, 100 and 1000, and note the first scale that gives
infornan. - Code the stable versions of proposition 0.3 and compare them with
torch.logsumexpandF.cross_entropy(agreement to 10^{-6}). - Redo step 2 in float16. Find the scale at which a probability underflows to 0 and its log becomes
-inf, then fix it withF.log_softmax. - Train a small MLP with a learning rate 100 times too large. Register a forward hook that stops at the first non-finite activation, and name the layer.
Deliverable: the notebook and five lines saying where each NaN came from.
1. From the neuron to the deep network
Concrete scene: 2-layer MLP on MNIST-like data, ReLU, SGD. After 5 epochs, train loss ~0.08 and test ~0.35; you add an 8th layer and the loss freezes (or becomes NaN). This is not “deep learning is magic”: it is mis-calibrated initialization, activation and depth. This chapter names these objects — neuron, MLP, non-linearity — before the universal approximation theorem.
What breaks Stacking linear layers with no activation (the net collapses to one affine map); skipping initialization (vanishing); judging a run on train alone. All three sabotage an LLM fine-tune as badly as a toy MLP.
Definition 1.1 — Artificial neuron and MLP A neuron computes h = \sigma(\langle w, x\rangle + b) with \sigma a nonlinear activation function. A multilayer perceptron of depth L stacks: h^{(0)} = x, \qquad h^{(\ell)} = \sigma\big(W^{(\ell)} h^{(\ell-1)} + b^{(\ell)}\big), \qquad f_\theta(x) = W^{(L)} h^{(L-1)} + b^{(L)}. Without \sigma, the network would reduce to a single affine map (exercise 2): nonlinearity is the price of expressivity. Number of parameters: |\theta| = \sum_\ell (n_{\ell} n_{\ell-1} + n_\ell).
1.1. The perceptron: the first learning rule
The official syllabus opens its neural-network block with “perceptrons and backpropagation”. Rosenblatt’s perceptron (1958) is a single neuron with a sign activation, \hat y = \mathrm{sign}(\langle w, x\rangle), for labels y \in \{-1, +1\}; a bias is absorbed by appending a constant coordinate 1 to x. Its interest today is twofold: it is the simplest learning rule with a convergence proof, and its failure on non-separable data explains why hidden layers, and therefore backpropagation, are needed.
Definition 1.2 — Perceptron algorithm Start from w_0 = 0. Visit the examples in turn; whenever example i is misclassified, that is y_i\langle w, x_i\rangle \leq 0, update w \leftarrow w + y_i\, x_i, and leave w unchanged otherwise. Stop after a full pass without mistakes.
The update is a stochastic gradient step with step size 1 on the loss \max(0, -y\langle w, x\rangle), whose gradient is -y\,x on a mistake and 0 otherwise.
Theorem 1.3 — Convergence of the perceptron (Novikoff, 1962) Assume \|x_i\| \leq R for all i, and that the data are linearly separable with margin \gamma > 0: some unit vector u satisfies y_i\langle u, x_i\rangle \geq \gamma for all i. Then the perceptron makes at most (R/\gamma)^2 mistakes, whatever the order of the examples.
Proof. Let w_k be the weight vector after k mistakes. Each mistake on (x_i, y_i) increases the alignment with u: \langle u, w_k\rangle = \langle u, w_{k-1}\rangle + y_i\langle u, x_i\rangle \geq \langle u, w_{k-1}\rangle + \gamma, so \langle u, w_k\rangle \geq k\gamma.
The norm grows slowly, because a mistake means y_i\langle w_{k-1}, x_i\rangle \leq 0: \|w_k\|^2 = \|w_{k-1}\|^2 + 2y_i\langle w_{k-1}, x_i\rangle + \|x_i\|^2 \leq \|w_{k-1}\|^2 + R^2, so \|w_k\|^2 \leq kR^2.
By Cauchy–Schwarz, k\gamma \leq \langle u, w_k\rangle \leq \|w_k\| \leq \sqrt{k}\,R, hence k \leq (R/\gamma)^2.∎
Example 1.4 — XOR: where one neuron stops and two layers succeed Label the four points of \{0,1\}^2 by exclusive or: (1,0) and (0,1) are positive, (0,0) and (1,1) negative. No line separates them.
If w_1x_1 + w_2x_2 + b were positive exactly on the positive points, we would have b < 0, \qquad w_1 + w_2 + b < 0, \qquad w_1 + b > 0, \qquad w_2 + b > 0; adding the last two gives w_1 + w_2 + 2b > 0, so w_1 + w_2 + b > -b > 0, a contradiction. The perceptron therefore never stops on these data.
One hidden layer with two threshold units solves the problem:
- h_1 = \mathbf{1}[x_1 + x_2 - 0.5 > 0] computes OR;
- h_2 = \mathbf{1}[x_1 + x_2 - 1.5 > 0] computes AND;
- the output \mathbf{1}[h_1 - h_2 - 0.5 > 0] is XOR.
The perceptron rule cannot train h_1 and h_2, because no target is given for hidden units. Replacing thresholds by differentiable activations and propagating the error backwards through the layers is exactly what chapter 2 does.
1.2. The universal approximation theorem
Theorem 1.5 — Universal approximation (Cybenko, 1989; Hornik, 1991) Let \sigma be continuous and discriminatory: for a finite signed measure \mu on the compact K below, \int_K \sigma(w^\top x + b)\, d\mu(x) = 0 \ \text{ for all } w, b \quad\Longrightarrow\quad \mu = 0. Every continuous sigmoidal function (limits 0 at -\infty and 1 at +\infty) is discriminatory, so the sigmoid qualifies, and so does \tanh, an affine image of it. Then for every f \in \mathcal{C}(K) on a compact K \subset \mathbb{R}^d and every \varepsilon > 0, there exists g(x) = \sum_{j=1}^{J} \alpha_j\, \sigma(w_j^\top x + b_j) (a single hidden layer) such that \sup_{x \in K} |f(x) - g(x)| \le \varepsilon.
Proof. Guided sketch, in two parts — part (ii) is the technical core of Cybenko, part (i) gives its constructive intuition.
(i) Construction by sigmoidal “gates” (one-dimensional case). Let f be continuous on [0,1]. A steep sigmoid \sigma(k(x-a)) tends toward the indicator \mathbf{1}_{x > a} as k \to \infty; by taking differences, \pi_{k}(x) = \sigma(k(x - a)) - \sigma(k(x - b)), \qquad a < b, tends toward \mathbf{1}_{[a,b]}(x) (a gate).
Since f is uniformly continuous, the step function s_n = \sum_{i} f(t_i)\,\mathbf{1}_{[t_i, t_{i+1})} on a subdivision of step 1/n satisfies \|f - s_n\|_\infty \le \omega_f(1/n) \to 0.
Replacing each indicator by a steep gate \pi_k with k large enough (the error is concentrated on two intervals of width \sim 1/k around a and b, where it is bounded), one obtains \|f - g\|_\infty \le \varepsilon with g = \sum_i f(t_i)\,\pi_{k,i} — a finite linear combination of sigmoids.
(ii) Density by Hahn–Banach (the general argument). Let \mathcal{G} be the vector space spanned by the x \mapsto \sigma(w^\top x + b). Suppose the closure of \mathcal{G} for \|\cdot\|_\infty is not \mathcal{C}(K).
By the Hahn–Banach theorem (separation of a missing dense subspace), there exists a nonzero finite signed measure \mu on K such that \int g \,d\mu = 0 for every g \in \mathcal{G}, hence in particular \int_K \sigma(w^\top x + b)\, d\mu(x) = 0 \qquad \forall\, w \in \mathbb{R}^d,\ b \in \mathbb{R}.
Cybenko’s technical lemma (every continuous sigmoidal \sigma is discriminatory) then gives \mu = 0 — a contradiction. The idea of the lemma: if \hat\mu(t) = \int e^{t^\top x} d\mu(x) denotes the Fourier–Laplace transform of \mu, the vanishing above for a “rich enough” sigmoid forces \hat\mu \equiv 0 on an open set, hence \mu = 0 by injectivity of the Fourier transform on finite measures.
∎
ReLU and GELU too: Leshno et al. (1993) Leshno, Lin, Pinkus and Schocken proved the general form: for a continuous activation (more generally, locally bounded and piecewise continuous), one-hidden-layer networks are dense in \mathcal{C}(K) if and only if \sigma is not a polynomial. ReLU, GELU and every activation of section 1.4 are covered; a polynomial \sigma of degree k only spans polynomials of degree at most k.
What the theorem does not say It guarantees the existence of good weights, not that one can find them by optimization: the proof constructs sigmoids of slope k \to \infty, a regime gradient descent does not explore; and the required number of neurons J can be exponential in d. Depth partially corrects this last point.
Why depth? Some functions require an exponential number of neurons on one layer but a polynomial number on several (e.g. parity, products). Depth factorizes representations: edges → textures → objects (vision), characters → words → syntax (NLP), neighbors → communities → graphs (Graph ML).
1.3. Initialization: derivation of Xavier and He
A bad initialization produces activations that explode or vanish from the forward pass onward. Analyze a linear layer a = Wh with h \in \mathbb{R}^{n_{\mathrm{in}}}, \qquad W \in \mathbb{R}^{n_{\mathrm{out}} \times n_{\mathrm{in}}}, iid centered weights of variance v_W, iid centered inputs of variance v_h, independent of the weights.
Proposition 1.6 — Forward and backward variance \mathrm{Var}(a_i) = n_{\mathrm{in}}\, v_W\, v_h \quad\text{(forward pass)}, \qquad \mathrm{Var}\big[(\nabla_h)_j\big] = n_{\mathrm{out}}\, v_W\, v_\delta \quad\text{(backward pass, } \nabla_h = W^\top \delta\text{)}. To preserve the variance in both directions, one needs v_W = 1/n_{\mathrm{in}} and v_W = 1/n_{\mathrm{out}} simultaneously; the harmonic compromise of Glorot & Bengio (2010) is v_W = 2/(n_{\mathrm{in}} + n_{\mathrm{out}}).
Proof. Forward pass: a_i = \sum_{j=1}^{n_{\mathrm{in}}} W_{ij} h_j. The terms are independent and centered, \mathbb{E}[W_{ij}h_j] = \mathbb{E}[W_{ij}]\mathbb{E}[h_j] = 0, so the variance of the sum is the sum of the variances: \mathrm{Var}(a_i) = \sum_j \mathrm{Var}(W_{ij})\,\mathrm{Var}(h_j) = n_{\mathrm{in}} v_W v_h. Backward pass: symmetric computation on the columns, (\nabla_h)_j = \sum_{i=1}^{n_{\mathrm{out}}} W_{ij} \delta_i. Wanting n_{\mathrm{in}} v_W \approx 1 and n_{\mathrm{out}} v_W \approx 1, the harmonic mean 2/(n_{\mathrm{in}}+n_{\mathrm{out}}) approximates both constraints. ∎
He (2015) for ReLU ReLU zeroes half of its inputs: if h = \mathrm{ReLU}(a) with a centered, then \mathbb{E}[h^2] = \tfrac12 \mathrm{Var}(a). To compensate this \tfrac12 factor, He et al. (2015) propose v_W = 2/n_{\mathrm{in}} (or v_W = 2/n_{\mathrm{out}} if one preserves the backward variance instead). In practice: nn.init.kaiming_normal_ for ReLU/GELU, xavier_normal_ for tanh. Finally, zero initialization breaks the symmetry forever: all the neurons of a layer would receive the same gradient and remain identical.
1.4. Activation functions, compared
| Activation | Definition / derivative | Advantages | Pathologies |
|---|---|---|---|
| Sigmoid | \sigma' = \sigma(1-\sigma) \le \tfrac14 | probabilities, LSTM gates | saturation, max gradient 1/4, not centered |
| tanh | 1 - \tanh^2 | centered (Xavier) | saturation at the extremes |
| ReLU | \max(0,x), derivative \mathbf{1}_{x>0} | constant derivative 1, sparse, fast | dying ReLU: neuron stuck at 0 if pre-activation always negative |
| Leaky ReLU | \max(\alpha x, x) | nonzero gradient for x<0 | hyperparameter \alpha |
| GELU | x\,\Phi(x) = \tfrac{x}{2}\big(1 + \mathrm{erf}(x/\sqrt2)\big) | smooth, self-gated, transformers standard | cost of erf (usual tanh approximation) |
The usual approximation of GELU, used in BERT/GPT, is 0.5x\big(1 + \tanh\big(\sqrt{2/\pi}\,(x + 0.044715\,x^3)\big)\big). Note the kinship with ReLU — GELU weights x by the probability \Phi(x) that x is “activated” according to a standard Gaussian: it is a soft gate, differentiable at 0.
1.5. Beyond supervised: reinforcement learning
Everything in this chapter assumes labeled pairs (x, y). The official syllabus of the course lists a third paradigm, reinforcement learning: an agent interacts with an environment through actions and observes no label, but a scalar reward. This section sets up the framework; the full treatment (algorithms, theory, autonomous agents) is in the Reinforcement Learning and Autonomous Agents module (Period 2).
Definition 1.7 — Markov decision process (MDP) and policy An MDP is a tuple (\mathcal{S}, \mathcal{A}, P, r, \gamma): states, actions, transition kernel P(s' \mid s, a), reward r(s, a), discount factor \gamma \in [0,1). A policy \pi(a \mid s) chooses the action as a function of the state; the objective of the agent is to maximize the expectation of the discounted return J(\pi) = \mathbb{E}_\pi\Big[\sum_{t \geq 0} \gamma^t\, r(S_t, A_t)\Big]. The value function V^\pi(s) = \mathbb{E}_\pi[\sum_t \gamma^t r_t \mid S_0 = s] satisfies the Bellman equation V^\pi(s) = \mathbb{E}_{a \sim \pi}\big[r(s,a) + \gamma\,\mathbb{E}_{s'} V^\pi(s')\big]. This is the recursion that underlies all the algorithms: evaluate V^\pi (prediction), then improve \pi (control).
Why this paradigm concludes the chapter
- Reinforcement meets depth when V^\pi, \pi or the action-value function Q^\pi(s,a) are approximated by a network (this chapter): this is deep RL — DQN for the optimal Q^*, parametrized policies \pi_\theta optimized by policy gradient. The training machinery (ch. 2 and 3) applies as is, with in addition non-stationarity: the data depend on the current policy.
- Sequence link: an agent produces a trajectory — the exposure bias of RNNs (ch. 5) is a degenerate special case of it, where the “reward” is the true past output.
- Program side: multi-agent RL meets the collaborative learning of the Emerging Subjects in ML module; RL is also the framework for LLM alignment (RLHF) covered in M2.
2. Backpropagation
Training a network by gradient descent needs, at every step, the gradient of the loss with respect to every weight — millions of partial derivatives. Backpropagation computes all of them for the price of about two forward passes, by applying the chain rule backward on the computation graph; this chapter proves it, runs it by hand on a small example, and counts its memory cost.
2.1. The theorem and its proof
Theorem 2.1 — Backpropagation (chain rule on a computation graph) Consider an acyclic computation graph whose nodes v carry tensors, each node being a differentiable function of its predecessors, and \mathcal{L} the loss node. For every node v other than \mathcal{L}, with successors s_1, \dots, s_k: \frac{\partial \mathcal{L}}{\partial v} = \sum_{i=1}^{k} \frac{\partial \mathcal{L}}{\partial s_i}\, \frac{\partial s_i}{\partial v}, with base case \partial \mathcal{L}/\partial \mathcal{L} = 1. In particular, for an MLP where a^{(\ell)} = W^{(\ell)} h^{(\ell-1)} + b^{(\ell)} and \delta^{(\ell)} = \partial \mathcal{L}/\partial a^{(\ell)}:
Key result — the backpropagation recursion \delta^{(L)} = \nabla_{a^{(L)}} \mathcal{L}, \qquad \delta^{(\ell)} = \big(W^{(\ell+1)\top} \delta^{(\ell+1)}\big) \odot \sigma'(a^{(\ell)}), \frac{\partial \mathcal{L}}{\partial W^{(\ell)}} = \delta^{(\ell)} \, h^{(\ell-1)\top}, \qquad \frac{\partial \mathcal{L}}{\partial b^{(\ell)}} = \delta^{(\ell)}.
Proof. By descending induction along a reverse topological order (from outputs toward inputs).
Base. \partial \mathcal{L}/\partial \mathcal{L} = 1.
Heredity. Fix v and assume the formula true for all its successors s_i. Since the graph is acyclic, \mathcal{L} depends on v only through the values of s_1, \dots, s_k; writing \mathcal{L} = \Psi(s_1(v), \dots, s_k(v)) locally, the multivariate chain rule gives exactly \frac{d\mathcal{L}}{dv} = \sum_i \frac{\partial \mathcal{L}}{\partial s_i}\frac{ds_i}{dv}.
The MLP matrix formulas are merely the coordinate-by-coordinate application of this identity; the product W^{(\ell+1)\top}\delta^{(\ell+1)} transposes the linearity a^{(\ell+1)} = W^{(\ell+1)}h^{(\ell)} + \dots, and the term \odot\,\sigma'(a^{(\ell)}) comes from h^{(\ell)} = \sigma(a^{(\ell)}) applied component by component. ∎
Example 2.2 — Backprop by hand on a 5-node graph Take f(w_1, w_2) = \tfrac12\big(w_2 \tanh(w_1 x) - t\big)^2 with x = 1.5, w_1 = 0.3, w_2 = -0.8, t = 1.
Intermediate nodes: a = w_1 x, h = \tanh(a), y = w_2 h, \mathcal{L} = \tfrac12(y-t)^2.
| Forward pass | value | Local derivatives |
|---|---|---|
| a = w_1 x | 0.45 | \partial a/\partial w_1 = x = 1.5, \partial a/\partial x = w_1 |
| h = \tanh(a) | 0.4219 | \partial h/\partial a = 1-h^2 = 0.8220 |
| y = w_2 h | -0.3375 | \partial y/\partial w_2 = h, \partial y/\partial h = w_2 |
| \mathcal{L} = \tfrac12(y-t)^2 | 0.8944 | \partial \mathcal{L}/\partial y = y - t = -1.3375 |
Backward pass (products of local derivatives): \frac{\partial \mathcal{L}}{\partial w_2} = -1.3375 \times 0.4219 = -0.5643, \qquad \frac{\partial \mathcal{L}}{\partial w_1} = \underbrace{(-1.3375)(-0.8)}_{\partial\mathcal{L}/\partial h = 1.0700} \times\; 0.8220 \times 1.5 = 1.3193. The message \partial\mathcal{L}/\partial h = 1.07 is literally the gradient “passing backward” through the multiplication — same structure as the message passing of GNNs, but on the computation graph.
The same recursion, written for a batch, fits in a few lines of NumPy. The code below trains nothing: it computes the forward pass and the backward pass of a two-layer ReLU network with a softmax cross-entropy, then checks every partial derivative against a central finite difference in float64. Do this check once for every hand-written backward pass.
import numpy as np
rng = np.random.default_rng(0)
n, d_in, d_h, K = 16, 4, 32, 3 # batch, input, hidden, classes
X, y = rng.normal(size=(n, d_in)), rng.integers(0, K, n)
p = {"W1": rng.normal(0, np.sqrt(2 / d_in), (d_h, d_in)), "b1": np.zeros(d_h), # He init (1.3)
"W2": rng.normal(0, np.sqrt(2 / d_h), (K, d_h)), "b2": np.zeros(K)}
def forward(p):
A1 = X @ p["W1"].T + p["b1"] # a = W x + b, one example per row
H1 = np.maximum(A1, 0) # ReLU
Z = H1 @ p["W2"].T + p["b2"] # logits
Z = Z - Z.max(1, keepdims=True) # stable softmax (prop. 0.3)
P = np.exp(Z) / np.exp(Z).sum(1, keepdims=True)
return -np.log(P[np.arange(n), y]).mean(), (A1, H1, P)
def backward(p, cache):
A1, H1, P = cache
D2 = P.copy(); D2[np.arange(n), y] -= 1; D2 /= n # delta at the logits: softmax - one-hot
D1 = (D2 @ p["W2"]) * (A1 > 0) # (W2^T delta2) * sigma'(a1), theorem 2.1
return {"W1": D1.T @ X, "b1": D1.sum(0), "W2": D2.T @ H1, "b2": D2.sum(0)}
loss, cache = forward(p)
g = backward(p, cache)
eps = 1e-6 # central differences, in float64
for name, W in p.items():
num = np.zeros_like(W)
for idx in np.ndindex(W.shape):
old = W[idx]
W[idx] = old + eps; lp = forward(p)[0]
W[idx] = old - eps; lm = forward(p)[0]
W[idx] = old
num[idx] = (lp - lm) / (2 * eps)
rel = np.linalg.norm(num - g[name]) / (np.linalg.norm(num) + np.linalg.norm(g[name]))
print(name, f"relative error {rel:.0e}") # below 1e-9: the backward pass is rightThe error is measured on the whole tensor, because an entry-by-entry relative error blows up on entries whose gradient is nearly zero.
2.2. Cost: memory, compute, and how to reduce them
- Complexity. A single forward pass + one backward pass cost \mathcal{O}(|\theta|) operations (up to a constant factor): the gradient of all the weights for the price of about two evaluations — this is the decisive contribution of reverse mode (Linnainmaa, 1970; Rumelhart, Hinton & Williams, 1986) over forward-mode differentiation, which would require |\theta| passes.
- Memory. The backward pass needs the activations of every layer: memory grows like the batch size \times the number of activations, not like |\theta|. For a transformer, this is the limiting factor.
- Checkpointing (Griewank; Chen, 2016): store only one layer out of \sqrt L and recompute the missing intermediates during the backward pass — \mathcal{O}(\sqrt L) memory instead of \mathcal{O}(L), for ~33% extra compute.
torch.utils.checkpoint. - Mixed precision: store/compute in float16 or bfloat16 (2× memory and tensor throughput), while keeping float32 master copies of the weights and scaling up the loss (loss scaling) to prevent small gradients from canceling in fp16. bfloat16 has the same exponent range as fp32 — more robust.
import torch
torch.manual_seed(0)
x, y = torch.randn(8, dtype=torch.float64), torch.randn(2, dtype=torch.float64)
W1 = torch.randn(64, 8, dtype=torch.float64, requires_grad=True) # autograd tracks the operations
W2 = torch.randn(2, 64, dtype=torch.float64, requires_grad=True)
def f(W1, W2): return 0.5 * ((y - W2 @ torch.relu(W1 @ x))**2).sum()
loss = f(W1, W2)
loss.backward() # automatic backprop
print(W1.grad.shape, W2.grad.shape) # same shapes as W1, W2
# Check one entry by central finite difference, in float64 (do it for every new custom gradient)
j = int(W2.grad[0].abs().argmax()) # an entry with a nonzero gradient
eps = 1e-6
with torch.no_grad():
W2[0, j] += eps; lp = f(W1, W2)
W2[0, j] -= 2 * eps; lm = f(W1, W2)
W2[0, j] += eps
print((lp - lm).item() / (2 * eps), W2.grad[0, j].item()) # the two agree to about 9 digitsIn float32, a loss of order 10 to 100 carries a rounding error of about 10^{-6} to 10^{-5}, as large as the change that a perturbation of 10^{-6} produces: the two numbers then disagree. Use float64, or accept a rough check with \epsilon \approx 10^{-3} in float32.
Computation graph autograd dynamically builds the graph of operations (vertices = tensors, edges = operations) and applies the chain rule in reverse-mode differentiation. Deep learning is computation on a graph — the same idea will be applied to the data themselves in the Graph ML module. And since the graph is acyclic by construction, the induction of theorem 2.1 always runs without deadlock; RNNs (chapter 5) are “unrolled” in time precisely to recover an acyclic graph.
3. Optimization in practice
Training minimizes the risk R(\theta) = \mathbb{E}_{(x,y)\sim P}\big[\ell(f_\theta(x), y)\big] through its empirical version \hat R_n, by stochastic gradient descent: at each step, the gradient is estimated on a mini-batch (proposition 0.2). This chapter analyzes why each ingredient of the modern recipe (momentum, Adam, warmup, normalization, regularization) is there.
3.1. Convergence of SGD: the quadratic case, fully proved
The generic model of non-convexity is hard; the quadratic case, for its part, is solved exactly and illuminates all the others. Let f(\theta) = \tfrac12 \theta^\top A \theta - b^\top \theta with A symmetric positive definite, eigenvalues \lambda_1 \ge \dots \ge \lambda_d > 0, \lambda_1 = L (Lipschitz constant of the gradient), \lambda_d = \mu, condition number \kappa = L/\mu.
The minimizer \theta^\star = A^{-1}b satisfies \nabla f(\theta^\star) = 0, and the (for now deterministic) descent reads \theta_{k+1} = \theta_k - \eta (A\theta_k - b).
Theorem 3.1 — Guaranteed decrease if and only if \eta < 2/L Setting e_k = \theta_k - \theta^\star: e_{k+1} = (I - \eta A)\, e_k, \qquad \|e_k\| \le \rho^k \|e_0\|, \quad \rho = \max_i |1 - \eta\lambda_i|. Convergence takes place for every e_0 if and only if 0 < \eta < 2/L; the optimal rate is reached for \eta = 2/(L+\mu) and equals \rho = \frac{\kappa - 1}{\kappa + 1} \approx 1 - \frac{2}{\kappa}.
Proof. Since \theta^\star is a fixed point of the iteration, e_{k+1} = \theta_{k+1} - \theta^\star = (I - \eta A)(\theta_k - \theta^\star) = (I-\eta A)e_k, hence e_k = (I - \eta A)^k e_0. Diagonalize A = Q \Lambda Q^\top (orthonormal): I - \eta A = Q\,\mathrm{diag}(1 - \eta\lambda_i)\,Q^\top, so in the eigenbasis \|e_k\|^2 = \sum_i (1-\eta\lambda_i)^{2k} (q_i^\top e_0)^2. Each eigenmode contracts by |1-\eta\lambda_i| per step.
The maximum \rho of the |1 - \eta\lambda_i| is reached at \lambda_1 = L or \lambda_d = \mu.
One wants 1 - \eta L > -1 (i.e. \eta < 2/L) to avoid expanding the stiff modes, and \eta large to contract the flat modes.
The minimal \rho(\eta) = \max(|1-\eta L|,\, |1-\eta\mu|) equalizes the two terms, 1 - \eta\mu = \eta L - 1, i.e. \eta = 2/(L+\mu) and \rho = (L-\mu)/(L+\mu).
For \kappa \gg 1, \rho \approx 1 - 2/\kappa: \mathcal{O}(\kappa) iterations are needed to divide the error by a constant. ∎
Reading for what follows
- The step is bounded by the stiff directions but the slowness comes from the flat directions: the whole art of deep optimization consists in decoupling these scales — momentum (3.2), adaptive preconditioning (3.3), activation normalization (3.5).
- In noisy SGD, the same step 2/L remains the stability condition, and the residual noise fluctuates around the minimum at a distance proportional to \eta: decreasing \eta at the end of training (scheduling) amounts to “annealing”.
- On real networks, the landscape is non-convex, but saddle points — not local minima — are the main obstacle, and SGD noise helps precisely to escape them.
3.2. Momentum: convergence rates
Definition 3.2 — SGD with momentum (Polyak’s heavy ball) v_{k+1} = \beta v_k + \hat g_k, \qquad \theta_{k+1} = \theta_k - \eta\, v_{k+1}, \qquad \beta \in [0,1), with \hat g_k the mini-batch estimator of the gradient. The velocity v exponentially averages the past gradients: in a narrow valley where the gradient alternates +g, -g, +g, \dots (zigzag), the average cancels in the direction of the oscillation and accumulates in the direction of progress.
Proposition 3.3 — What momentum changes, mode by mode On the quadratic case of theorem 3.1 (exact gradient), the error follows e_{k+1} = (1 + \beta - \eta\lambda)\, e_k - \beta\, e_{k-1}. With the step \eta = (1-\beta)/L:
- (i) the stiff mode \lambda = L converges like (\sqrt\beta)^k;
- (ii) on a flat mode, the effective rate is 1 - \frac{\eta}{1-\beta}\lambda — everything happens as if the step were multiplied by 1/(1-\beta) on the slow directions without destabilizing the stiff ones.
The complete analysis (Polyak, 1964) gives a global rate in \mathcal{O}(1 - c/\sqrt\kappa) instead of \mathcal{O}(1 - c/\kappa), a rate optimally reached by Nesterov’s variant.
Proof. Inject the iteration into e_k: e_{k+1} = e_k - \eta A e_k + \beta(e_k - e_{k-1}), giving the announced difference equation. Per eigenmode (e_k collinear with the eigenvector q_i), the solutions are of the form e_k = z^k q_i where z solves the characteristic polynomial z^2 - (1 + \beta - \eta\lambda)\, z + \beta = 0. Write s = 1 + \beta - \eta\lambda. The product of the two roots equals \beta.
(i) Stiff modes. The roots are complex conjugates as soon as s^2 \le 4\beta, and their modulus then equals \sqrt{\beta} (product = \beta, equal modulus for two conjugates).
With \eta = (1-\beta)/L and \lambda \le L, one has \eta\lambda \le 1-\beta, so s \in [\,2\beta,\; 1+\beta).
For \lambda = L: s = 2\beta, and 2\beta \le 2\sqrt\beta whenever \beta \le 1 — condition satisfied, the stiff mode is damped by \sqrt\beta per step.
(ii) Flat modes. For \eta\lambda \ll 1, look for the root close to 1 in the form z = 1 - c\,\eta\lambda + o(\eta\lambda). Expanding z^2 - sz + \beta = 0 to first order with s = 1 + \beta - \eta\lambda: (1 - 2c\eta\lambda) - (1 + \beta - \eta\lambda)(1 - c\eta\lambda) + \beta = \eta\lambda\big(1 - c(1-\beta)\big) + o(\eta\lambda) = 0, hence c = 1/(1-\beta) and z_+ \approx 1 - \frac{\eta\lambda}{1-\beta}: the effective step of the flat modes is \eta/(1-\beta) — the moving average amplifies the displacement in the directions where the gradient is coherent, whereas (i) shows that it bounds the oscillation in the directions where it alternates.
∎
3.3. Adam, derived step by step
Algorithm 3.4 — Adam (Kingma & Ba, 2014) At each step t, with stochastic gradient g_t, \beta_1 = 0.9, \beta_2 = 0.999: m_t = \beta_1 m_{t-1} + (1-\beta_1) g_t \quad\text{(moving average of the gradient)}, v_t = \beta_2 v_{t-1} + (1-\beta_2) g_t^2 \quad\text{(moving average of squares, element-wise)}, \hat m_t = \frac{m_t}{1 - \beta_1^t}, \qquad \hat v_t = \frac{v_t}{1 - \beta_2^t} \quad\text{(bias correction)}, \theta_{t+1} = \theta_t - \eta\, \frac{\hat m_t}{\sqrt{\hat v_t} + \varepsilon}.
Proposition 3.5 — Why the bias correction is exact If the gradient is constant g_t \equiv g, then m_t = (1 - \beta_1^t)\, g and v_t = (1-\beta_2^t)\, g^2 (element by element). The correction therefore divides precisely by the underestimation factor: \hat m_t = g, \hat v_t = g^2.
Proof. By induction. m_t = (1-\beta_1)\sum_{k=1}^{t} \beta_1^{t-k} g_k. If g_k \equiv g: m_t = (1-\beta_1)\, g \sum_{j=0}^{t-1} \beta_1^{j} = (1-\beta_1)\, g\, \frac{1 - \beta_1^t}{1 - \beta_1} = (1-\beta_1^t)\, g (geometric sum).
Without correction, the moving average would start from m_0 = 0 and underestimate the gradient by a factor 1-\beta_1^t — by 90% at step 1 with \beta_1 = 0.9.
Adam’s first step would be ~10× too small (and for v, with \beta_2 = 0.999, ~1000× too small, which would make the update \hat m/\sqrt{\hat v} explode). The computation is identical for v_t with g^2. ∎
What Adam does, intuitively If the gradient is constant, \hat m_t / \sqrt{\hat v_t} \approx g/|g| = \mathrm{sign}(g): Adam moves by a step of size ~\eta per coordinate, independent of the gradient scale — a diagonal preconditioner that solves the decoupling \lambda_{\max}/\lambda_{\min} of theorem 3.1.
It is also its weakness: the weight of “calm” coordinates is relatively amplified, and the \varepsilon in the denominator must stay small (10^{-8}) so as not to crush small gradients.
| Optimizer | Update | Notes |
|---|---|---|
| SGD | \theta \leftarrow \theta - \eta\, \hat g | useful noise (escapes saddle points); \eta < 2/L |
| Momentum | v \leftarrow \beta v + \hat g; \theta \leftarrow \theta - \eta v | inertia, damps zigzags (prop. 3.3) |
| RMSProp | adaptive normalization by v alone | per-coordinate step, no momentum |
| Adam | bias-corrected first and second moments | universal default; tune lr first |
| AdamW | Adam + decoupled decay | see 3.6 — the transformers standard |
3.4. Step scheduling and warmup
- Warmup (linear from 0 to \eta over a few hundred/thousand steps): at the very start of training, the features are random and the first gradients have a large norm; moreover, the bias correction of \hat v_t (prop. 3.5) divides by 1 - \beta_2^t, which varies fast when t is small — the ratio \hat m/\sqrt{\hat v} is then very noisy. A small step at the start lets the statistics settle. Pre-norm architectures (chapter 6) strongly reduce this need.
- Decay: cosine \eta_t = \eta_{\min} + \tfrac12(\eta - \eta_{\min})(1 + \cos(\pi t/T)), or steps (\times 1/10). Quadratic motif (theorem 3.1): close to the minimum, too large a step makes the SGD noise orbit around the solution — decreasing \eta divides the oscillation radius.
- LR range test (Smith, 2015): grow \eta geometrically over one epoch and plot the loss; the optimal \eta sits just before the minimum of this curve (chapter 8).
3.5. BatchNorm and LayerNorm
Definition 3.6 — BatchNorm (Ioffe & Szegedy, 2015) and LayerNorm (Ba et al., 2016) BatchNorm normalizes each feature over the batch (the j-th coordinate of the activations, for a batch of size b): \hat h_{ij} = \frac{h_{ij} - \mu_j}{\sqrt{\sigma_j^2 + \varepsilon}}, \qquad \mu_j = \frac1b \sum_i h_{ij}, \quad \sigma_j^2 = \frac1b \sum_i (h_{ij} - \mu_j)^2, \qquad y_{ij} = \gamma_j \hat h_{ij} + \beta_j. At inference, \mu, \sigma are frozen moving averages. LayerNorm normalizes each example over its features (same formulas, but the means are taken over j at fixed i): independent of the batch, it is the norm of transformers.
Proposition 3.7 — Reparameterization invariance BatchNorm makes the layer output invariant when one replaces W by cW and b by cb (c > 0).
The statistics become c\mu, c^2\sigma^2, and \hat h is unchanged. The scaling effect is absorbed by \gamma.
Proof. If h' = cWh + cb = c\,h, then \mu' = c\mu, {\sigma^2}' = c^2\sigma^2 and \hat h' = (ch - c\mu)/\sqrt{c^2\sigma^2 + \varepsilon}. For \varepsilon small compared to \sigma^2, \hat h' \approx c(h-\mu)/(c\sigma) = \hat h.
The gradient of the loss with respect to the scale c of the weights is then ~zero: the optimization no longer “wastes” capacity correcting the scale of the activations, only their direction. ∎
The ICS controversy The historical explanation — “reducing internal covariate shift” — was largely debunked by Santurkar et al. (2018): BatchNorm works mainly because it reparameterizes the problem in a Lipschitz way (smoother loss landscape, better-conditioned gradients), not because it stabilizes distributions. Practical consequences: BatchNorm requires fairly large batches (the statistics become noisy otherwise) and behaves badly at inference with batch size 1; LayerNorm has no such dependencies. In transformers, LayerNorm is applied before each sub-block (pre-norm, chapter 6).
3.6. Regularization: the complete tour
Dropout (Srivastava et al., 2014): during training, each activation is multiplied by an iid mask M_j \sim \mathrm{Bernoulli}(1-p) then divided by 1-p (“inverted”); at inference, identity. Proof that the expectation is preserved: \mathbb{E}[M_j/(1-p)] = 1, hence \mathbb{E}[\tilde h_j] = h_j — no scaling is needed at test time. Ensemble interpretation: each mask defines a sub-network; training samples 2^{n} architectures sharing their weights, and inference approximately averages their consensus (the exact “mean network” approximation holds for a single final linear block; Gal & Ghahramani, 2016, give it a Bayesian reading, used as MC dropout in Privacy and Uncertainty Quantification, ch. 8, M2).
Weight decay \tfrac{\lambda}{2}\|\theta\|^2: SGD + decay gives \theta \leftarrow (1 - \eta\lambda)\theta - \eta \hat g — multiplicative shrinkage at each step (implicit ridge). AdamW (Loshchilov & Hutter, ICLR 2019) applies the decay directly to the weights and not through Adam’s preconditioner: via \hat m/\sqrt{\hat v}, the decay would undergo a per-coordinate normalization that makes it uneven; decoupled, it becomes a homogeneous ridge again. It is the standard for transformers (typically \lambda \sim 10^{-2}, much larger than in the SGD era).
Label smoothing \varepsilon \in [0.05, 0.2]: the target becomes q_k = (1 - \varepsilon)\,\mathbf{1}[k = y] + \varepsilon/K. The cross-entropy penalizes -\log p_k \to \infty as p_k \to 0.
A hard target pushes the probability of the true class toward p^\star \to 1, so \log p^\star \to 0, which needs a logit gap that grows without bound (overconfidence). The smoothed target puts the optimum at p^\star = 1 - \varepsilon + \varepsilon/K < 1, a finite logit gap, and improves calibration.
Data augmentation: inject the known invariances (rotations/crops in vision, synonyms in NLP) — the cheapest regularization in parameters; it acts on the data, not on the model.
Early stopping: stop when the validation loss rises again — a regularization at zero compute cost, equivalent to an implicit penalization of the norm (cf. Machine Learning module, bias-variance).
Overfitting, order of profitability Diagnosis: a train/validation gap that opens while the train loss decreases. Remedies in order: 1) more data, 2) augmentation, 3) dropout, 4) weight decay, 5) shrink the model as a last resort. A model that cannot overfit a small batch (chapter 8) is often too small or badly wired — the capacity to overfit is first and foremost a health check.
Lab sheet — session 6: dropout and weight decay on an MLP Goal: open a train/validation gap on purpose, then close it with the tools of this section.
- Train an MLP 784–512–512–10 on 1,000 MNIST images (validation: 10,000 others) with no regularization, until the gap is clear.
- Add inverted dropout with p \in \{0.1, 0.3, 0.5\}. Check numerically that the mean activation is the same in
model.train()andmodel.eval(). - Add weight decay with \lambda \in \{10^{-5}, 10^{-4}, 10^{-3}\}, once as an L2 term inside Adam and once with AdamW. Log the weight norm.
- Add label smoothing \varepsilon = 0.1 and compare the confidence of the wrong predictions.
Deliverable: a table of final gaps and validation accuracies, and one paragraph explaining the ranking.
4. Convolutional networks (CNN)
A fully connected layer on a 224 × 224 colour image needs about 150,000 weights per neuron, and it ignores that neighbouring pixels are related and that an object means the same thing wherever it appears. A convolutional layer solves both problems by sliding one small filter over the whole image. This chapter defines the convolution, computes output sizes and receptive fields, and explains why residual connections let these networks grow deep.
4.1. Discrete convolution: general definition and dimension arithmetic
Definition 4.1 — 1D convolution with stride, padding, dilation For
- an input x of length I, a kernel k of length K,
- stride s \in \mathbb{N}^*, padding p (zeros added on each side) and dilation d (gap between the kernel taps):
(x * k)(u) = \sum_{j=0}^{K-1} x(u + d j - d(K-1))\; k(K{-}1{-}j), the output being sampled at positions u = u_0 + s\,t, t = 0, 1, 2, \dots In 2D, the same formula applies on each axis (kernel K_1 \times K_2).
The same filter is applied at every point: shared weights ⇒ translation equivariance (shifting the input shifts the feature map by the same amount, for stride 1) and a parameter count independent of the image size. Invariance only comes after a global pooling. The count is \#\text{params} = C_{\mathrm{in}} K_1 K_2 C_{\mathrm{out}} + C_{\mathrm{out}}.
Theorem 4.2 — Output dimension formula (and proof) O = \left\lfloor \frac{I + 2p - d(K-1) - 1}{s} \right\rfloor + 1.
Proof. With padding p, the effective input has valid indices in [-p,\, I - 1 + p]. An output position t places the kernel’s first tap at u = s\,t - p and the last at u + d(K-1).
The convolution is defined only if all the taps fall within the valid indices of the padded input: s t - p \ge -p and s t - p + d(K-1) \le I - 1 + p. The number of allowed steps t is therefore the number of integers in \big[0,\; \frac{I - 1 + 2p - d(K-1)}{s}\big], that is \lfloor (I + 2p - d(K-1) - 1)/s \rfloor + 1 (length of a discrete interval [0, n] = n + 1, with a floor for stride alignment). ∎
Example 4.3 — Immediate checks
- Conv 3×3, padding 1, stride 1 (I=I'): \lfloor (I + 2 - 2 - 1)/1 \rfloor + 1 = I.
- Downsampling /2 with 3×3, padding 1: \lfloor (I + 2 - 2 - 1)/2 \rfloor + 1 = \lfloor (I-1)/2 \rfloor + 1 (for I = 224 (ImageNet): 112).
- Two 3×3 convs (stride 1) have the same receptive field as a 5×5 conv for 28% fewer parameters (2 \times 9 = 18 weights per channel pair instead of 25) and one more nonlinearity — VGG’s argument.
4.2. Receptive field
Proposition 4.4 — Receptive field, formula by induction For convolutional layers with kernels k_\ell, strides s_\ell (dilation 1), the receptive field of a unit of layer \ell equals \mathrm{RF}_1 = k_1, \qquad \mathrm{RF}_\ell = \mathrm{RF}_{\ell-1} + (k_\ell - 1)\prod_{i < \ell} s_i.
Proof. By induction. Initialization: a unit of layer 1 reads k_1 pixels.
Heredity: let \Delta_{\ell} be the distance (in input pixels) between the receptive fields of two adjacent units of layer \ell. Clearly \Delta_1 = s_1 (shifting the output by one unit shifts the window by s_1), and \Delta_\ell = s_\ell \Delta_{\ell-1} = \prod_{i \le \ell} s_i.
A unit of layer \ell aggregates k_\ell contiguous units of layer \ell - 1: its field covers the field of one unit (RF_{\ell-1}) plus the gap between the centers of the first and last aggregated neighbors, (k_\ell - 1)\Delta_{\ell-1}. Hence the formula. ∎
Two stacked 3×3 convs RF = 3 + 2\times 1 = 5: stacking beats a large kernel — depth again. In practice the theoretical receptive fields quickly exceed the image, but the effective field (measured by occlusion, or by the gradient analysis of Luo et al., 2016) grows much more slowly; low layers encode edges, high layers concepts.
4.3. Transposed conv (deconvolution)
The gradient of the convolution with respect to the input is itself a convolution, by the flipped kernel and with adjusted padding — called transposed convolution, and used as is to upsample (GANs, segmentation, autoencoders).
Case with no stride, no dilation: a “valid” conv (p=0) maps I \to O = I - K + 1; its transpose maps O \to I = O + K - 1 by inserting K-1 border zeros and convolving with the flipped kernel.
Proof: write \mathrm{conv} as a linear map y = Cx by blocks; then \nabla_x = C^\top \nabla_y, and C^\top is the matrix of the transposed conv.
With stride and padding, the general formula: I' = s\,(O - 1) - 2p + d(K-1) + \mathrm{op} + 1, where \mathrm{op} is an optional extra padding — the exact mirror image of theorem 4.2. Tap overlap when s > 1 creates “checkerboard” artifacts, fixed by upsample + conv.
4.4. Historical architectures, parameters on the counter
| Network | Year | Key idea | Parameters |
|---|---|---|---|
| LeNet-5 | 1998 | conv + pooling + FC, gradient by backpropagation | ≈ 60 k |
| AlexNet | 2012 | ReLU, dropout, GPU, augmentation — wins ImageNet | ≈ 60 M |
| VGG-16 | 2014 | uniformity: only 3×3, depth 16-19 | ≈ 138 M |
| ResNet-50 | 2015 | residual connections, 50 layers and more | ≈ 25.6 M |
Example 4.5 — Counting VGG-16 parameters (a computation to redo) A 3×3 block from C_{\mathrm{in}} \to C_{\mathrm{out}} channels costs 9\,C_{\mathrm{in}} C_{\mathrm{out}} + C_{\mathrm{out}}. The first (3 → 64): 9 \times 3 \times 64 + 64 = 1\,792. A 64 → 64 block: 9 \times 64^2 + 64 = 36\,928.
Summing the five stages (64, 128, 256, 512, 512), the convolutions total \approx 14.7 M — but the three fully connected layers (after flattening 7 \times 7 \times 512 = 25\,088 features) weigh 25\,088 \times 4\,096 + 4\,096 \times 4\,096 + 4\,096 \times 1\,000 \approx 123\ \text{M}: 90% of the parameters live in the classifier!
Hence global pooling (GoogLeNet) then residual blocks: ResNet-50 does better with 25.6 M — of which ~23 M in 1×1/3×3 bottleneck convs.
Proposition 4.6 — Why residuals allow depth A residual block learns h^{(\ell+1)} = h^{(\ell)} + F(h^{(\ell)}) (then activation/normalization).
- Trivial identity: the choice F \equiv 0 realizes the exact identity — with standard initialization, F is small, so every added block starts “close to the identity”: adding layers no longer degrades the initial model.
- Gradient without attenuation: by the chain rule, \frac{\partial \mathcal{L}}{\partial h^{(\ell)}} = \frac{\partial \mathcal{L}}{\partial h^{(\ell+1)}}\Big( I + \frac{\partial F}{\partial h^{(\ell)}} \Big), the I term transports the gradient as is, whatever the depth — direct contrast with the product of L factors <1 of RNNs (chapter 5).
- Landscape: loss-function visualizations (Li et al., 2018) show markedly smoother valleys along the residual directions.
Residuals everywhere We will find exactly these skip connections in transformers (x + \mathrm{Attention}(\mathrm{LN}(x)), chapter 6) and GNNs (skip connections of message passing, Graph ML module): everywhere one stacks blocks, the identity path protects the gradient.
import torch.nn as nn
conv = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, padding=1)
# parameters: 3*3*3*32 + 32 = 896, independent of the H x W size
x = torch.randn(16, 3, 64, 64) # batch of 16 RGB 64x64 images
print(conv(x).shape) # [16, 32, 64, 64] (theorem 4.2 formula)
class ResBlock(nn.Module):
def __init__(self, c):
super().__init__()
self.conv1 = nn.Conv2d(c, c, 3, padding=1)
self.conv2 = nn.Conv2d(c, c, 3, padding=1)
self.norm1, self.norm2 = nn.BatchNorm2d(c), nn.BatchNorm2d(c)
def forward(self, x):
h = torch.relu(self.norm1(self.conv1(x)))
return torch.relu(x + self.norm2(self.conv2(h))) # skip connectionCNNs and graphs A convolution is a filter applied to a regular neighborhood (a grid). The GNNs of the Graph ML module generalize this idea to irregular neighborhoods: the filter becomes a function of the aggregated neighbors. Same DNA: weight sharing + local aggregation. For the full link with signal processing (circular convolution, convolution theorem, spectral graph filters), cf. the Signal Processing module and the Graph ML module.
5. Sequences: RNN, LSTM
Text, audio and time series have a variable length and an order that matters, so the network must carry information from one step to the next. A recurrent network does this with a hidden state updated at every step. This chapter shows why its gradient vanishes or explodes over long sequences, and how the gates of the LSTM mitigate the problem.
5.1. RNN and backpropagation through time
Definition 5.1 — RNN (Elman) h_t = \tanh(W_h h_{t-1} + W_x x_t + b), \qquad y_t = W_y h_t A hidden state that summarizes the past; weights shared across time (like the CNN kernel across space). The sequence (x_1, \dots, x_T) is processed by unrolling the network: T copies of the same block — the computation graph becomes acyclic again (chapter 2), and backprop applies to it “through time” (BPTT). Memory cost: \mathcal{O}(T) activations.
Theorem 5.2 — Exponential explosion or vanishing of the gradient For a loss at the final step T, writing D_t = \mathrm{diag}\big(\tanh'(a_t)\big): \frac{\partial \mathcal{L}_T}{\partial h_0} = \Big( \prod_{t=1}^{T} W_h^\top D_t \Big) \frac{\partial \mathcal{L}_T}{\partial h_T} \quad\Rightarrow\quad \Big\| \frac{\partial \mathcal{L}_T}{\partial h_0} \Big\| \;\le\; \|W_h\|^{T}\, \prod_{t=1}^{T}\|\tanh'(a_t)\|_\infty\, \Big\| \frac{\partial \mathcal{L}_T}{\partial h_T} \Big\|. If \|W_h\| \cdot \max_t \|\tanh'(a_t)\|_\infty < 1, the gradient decays exponentially with T (vanishing). Since \|\tanh'\|_\infty \le 1, explosion requires \|W_h\| > 1; this condition is necessary, not sufficient (Pascanu, Mikolov & Bengio, 2013).
Proof. By theorem 2.1 applied to the unrolled graph, since h_{t-1} has only one successor h_t, \partial \mathcal{L}_T/\partial h_{t-1} = (\partial h_t / \partial h_{t-1})^\top \partial \mathcal{L}_T/\partial h_t. Now h_t = \tanh(W_h h_{t-1} + W_x x_t + b), so the Jacobian equals J_t = D_t W_h with D_t diagonal (derivative of tanh component by component).
Composing from t = T down to t = 1 and using sub-multiplicativity \|ABC\| \le \|A\|\,\|B\|\,\|C\| (operator norm): \|\prod_t J_t^\top\| \le \prod_t \|J_t^\top\| \le \prod_t \|D_t\|\,\|W_h\|, and \|D_t\| = \max_i \tanh'(a_{t,i}) \le 1. The maximum is below 1 only when every coordinate is away from 0, and it becomes small only when every coordinate saturates: one saturated coordinate does not lower it.
Hence the bound: exponential decay in T as soon as the per-step factor is < 1. If \|W_h\| \le 1, every factor is at most 1 and the gradient cannot grow, so \|W_h\| > 1 is necessary for explosion. It is not sufficient: the bound is only an upper bound, and growth depends on the actual product of Jacobians. Experiments show both regimes. Explosion is handled by gradient clipping (truncating \|\hat g\| at a threshold); vanishing, for its part, is structural. ∎
5.2. LSTM: complete equations and the role of the gates
Definition 5.3 — LSTM (Hochreiter & Schmidhuber, 1997) Four “gates” (vectors of [0,1]^d via sigmoids, acting as multiplicative valves) and a cell state c_t that transitions additively: f_t = \sigma(W_f h_{t-1} + U_f x_t), \qquad i_t = \sigma(W_i h_{t-1} + U_i x_t), o_t = \sigma(W_o h_{t-1} + U_o x_t), \qquad \tilde c_t = \tanh(W_c h_{t-1} + U_c x_t), c_t = f_t \odot c_{t-1} + i_t \odot \tilde c_t, \qquad h_t = o_t \odot \tanh(c_t).
- f_t, forget gate: fraction of the old memory kept — it is what carries long memory; often initialized with b_f > 0 (positive forget bias) so that f \approx 1 at the start.
- i_t, input gate: how much of the candidate \tilde c_t is written; \tilde c_t: the proposed content.
- o_t, output gate: how much of the cell is exposed in h_t.
- Why it mitigates vanishing: the cell follows c_t = f_t \odot c_{t-1} + (\dots), an additive highway — the gradient \partial c_t/\partial c_{t-1} = \mathrm{diag}(f_t) + i_t-terms stays close to the identity when f_t \approx 1 and i_t modest, where the RNN systematically multiplied by W_h^\top D_t. The product of the Jacobians can stay ~1 over long horizons: long dependencies get through. (The problem is not solved: for very long dependencies, attention will fix it — chapter 6.)
GRU (Cho et al., 2014) and comparison z_t = \sigma(W_z h_{t-1} + U_z x_t), \quad r_t = \sigma(W_r h_{t-1} + U_r x_t), \quad h_t = (1 - z_t) \odot h_{t-1} + z_t \odot \tanh\big(W h_{t-1} \odot r_t + U x_t\big). Two gates instead of three, no separate cell state (z_t merges forget and write, r_t filters the read past): ~25% fewer parameters, generally comparable performance. In practice LSTM for long series, GRU for small datasets.
Teacher forcing and exposure bias When training a sequence-to-sequence model, the decoder is fed the true tokens (teacher forcing): the loss is computed in a single parallel pass, but the model only learns to predict given the exact past. At inference, it feeds on its own (possibly wrong) outputs — an exposure mismatch that makes long generations drift; mitigated by scheduled sampling or reinforcement learning (cf. RL module, and NLP module).
Lab sheet — session 8: gradient norm through time Goal: see theorem 5.2 on a plot, then see the LSTM escape it.
- Build an Elman RNN (
nn.RNN, tanh, 64 hidden units) on random sequences of length T \in \{10, 50, 100, 200\}, with a loss on the last step only. - Call
retain_grad()on every hidden state and plot \log \|\partial \mathcal{L}_T / \partial h_t\| against t. Initialize W_h as an orthogonal matrix times c \in \{0.5, 1, 1.5\}. - Read the slope of each curve as the log of a per-step factor, and compare it with the per-step bound of theorem 5.2, \log c plus the mean over t of \log \max_i \tanh'(a_{t,i}).
- Redo step 2 with an LSTM whose forget bias is 1, then clip the gradient norm at 1.0 in the exploding case.
Deliverable: two plots and a paragraph linking each slope to \|W_h\| and to saturation.
5.3. Applications: matching the architecture to the task
The official syllabus closes its “Deep learning I” block with applications. The same backbones (a CNN for grids, an RNN for sequences) serve very different tasks; what changes is the output head, the loss and the evaluation.
Definition 5.4 — Output heads for the main tasks
- Image classification: the feature maps are averaged over space (global average pooling), then a linear layer and a softmax give K class probabilities; loss: cross-entropy.
- Object detection: for each candidate region the network outputs K class scores and 4 box coordinates; loss: cross-entropy plus a regression loss (L1 or smooth L1) on the coordinates. A predicted box counts as correct when its intersection over union \mathrm{IoU}(A, B) = |A \cap B| / |A \cup B| with a true box reaches a threshold, usually 0.5.
- Semantic segmentation: one class per pixel; an encoder reduces the resolution, a decoder restores it with transposed convolutions (section 4.3), and skip connections carry fine detail from encoder to decoder (U-Net); loss: the per-pixel cross-entropy averaged over the image.
- Sequences (RNN, LSTM): many-to-one tasks such as sentiment classification read the last state h_T; many-to-many tasks such as tagging apply a softmax to every h_t; sequence-to-sequence tasks such as translation or speech recognition use an encoder that summarizes the input and a decoder that generates the output, trained with teacher forcing (note above). Squeezing the whole input into one vector is the bottleneck that attention removes (chapter 6).
Example 5.5 — IoU and segmentation shapes A predicted box with corners (0, 0) and (4, 4) and a true box with corners (2, 2) and (6, 6) both have area 16.
Their intersection is the square from (2, 2) to (4, 4), of area 4, and their union has area 16 + 16 - 4 = 28. The IoU is 4/28 \approx 0.14, far below 0.5: the detection is a miss, although the boxes overlap.
For segmentation, take an input of shape 3 \times 256 \times 256 and an encoder of four stride-2 stages ending at 512 \times 16 \times 16. Four transposed convolutions with kernel 2 and stride 2 each double the side, since (n - 1) \times 2 + 2 = 2n, giving back 256 \times 256.
A final 1 \times 1 convolution to K channels yields logits of shape K \times 256 \times 256, and the loss averages 65{,}536 pixel-wise cross-entropies.
6. Attention and transformers
A recurrent network reads a sequence one step at a time: training cannot be parallelized over positions, and information from far back must survive many multiplications. Attention lets every token look directly at every other token in a single matrix operation. This chapter defines it, explains the \sqrt{d_k} scaling, and assembles the transformer block on which every LLM is built.
6.1. Scaled dot-product: why \sqrt{d_k}
Definition 6.1 — Scaled dot-product attention (Vaswani et al., 2017) For tokens i = 1..n with embeddings x_i, one computes q_i = W_q x_i,\quad k_i = W_k x_i,\quad v_i = W_v x_i, with W_q, W_k \in \mathbb{R}^{d_k \times d} in the column form of a linear layer. Code stacks the n tokens as the rows of X \in \mathbb{R}^{n \times d} and uses the row form Q = X W_Q, \qquad W_Q = W_q^\top \in \mathbb{R}^{d \times d_k}, so that row i of Q is q_i^\top; likewise K = XW_K and V = XW_V. Then:
Key result — scaled dot-product attention \mathrm{Attention}(Q, K, V) = \mathrm{softmax}\!\Big(\frac{Q K^\top}{\sqrt{d_k}}\Big) V, \qquad \alpha_{ij} = \frac{\exp(q_i^\top k_j / \sqrt{d_k})}{\sum_{j'} \exp(q_i^\top k_{j'} / \sqrt{d_k})}.
Multi-head: h attention heads in parallel (projections W^q_m, W^k_m, W^v_m, dimensions d_k = d/h), concatenated then projected — several independent “communication channels”.
Proposition 6.2 — The variance of the scores grows like d_k If the components of q and k are iid, centered, with variance 1, then q^\top k = \sum_{\ell=1}^{d_k} q_\ell k_\ell is centered with variance exactly d_k.
Without normalization, the standard deviation of the scores is \sqrt{d_k} (32 for d_k = 1024): the softmax becomes a one-hot argmax, its gradients vanish — saturation, cf. chapter 0, proposition 0.3. Dividing by \sqrt{d_k} brings the variance back to 1, independent of the dimension.
Proof. Centering (independence): \mathbb{E}[q_\ell k_\ell] = \mathbb{E}[q_\ell]\,\mathbb{E}[k_\ell] = 0. Variance: the terms q_\ell k_\ell are mutually iid, so \mathrm{Var}(\sum_\ell q_\ell k_\ell) = \sum_\ell \mathrm{Var}(q_\ell k_\ell) = d_k\, \mathbb{E}[q_\ell^2]\mathbb{E}[k_\ell^2] = d_k. After dividing by \sqrt{d_k}, the variance of the normalized score equals 1.
Consequence for saturation: the typical gaps between normalized scores are \mathcal{O}(1), the exponential ratios \exp(s_i - s_j) stay in a reasonable range and the softmax keeps a nonzero gradient; without scaling, gaps of order \sqrt{d_k} \gg 1 produce a near one-hot distribution, whose gradient (\hat y_k(\delta_{kj} - \hat y_j)) tends to 0. ∎
6.2. Block architecture: pre-norm, positions, RoPE
Post-norm (Vaswani et al., original): y = \mathrm{LN}(x + \mathrm{Att}(x)) — the residual connection passes through the normalization. Pre-norm (GPT-2 and after): y = x + \mathrm{Att}(\mathrm{LN}(x)) — the identity path is intact (proposition 4.6): the gradient reaches the input without attenuation, which makes training stable at large depth and reduces the need for warmup; a final LayerNorm compensates for the absence of output normalization. The current standard.
Absolute positional encodings. Attention alone ignores the order of the tokens (6.4), so the original transformer adds to the embedding x_m of the token at position m a vector p_m \in \mathbb{R}^d. The sinusoidal code of Vaswani et al. is p_{m,2i} = \sin(m\,\omega_i), \qquad p_{m,2i+1} = \cos(m\,\omega_i), \qquad \omega_i = 10000^{-2i/d}. Each pair of coordinates turns at its own frequency, so p_{m+k} is a fixed rotation of p_m, the same for every m: an offset is a linear function of the code.
Learned positional encodings. A table P \in \mathbb{R}^{n_{\max} \times d} is trained with the rest of the model (BERT, GPT-2, ViT). It adapts to the data but has no vector for positions beyond n_{\max}.
RoPE (rotary position embedding, Su et al., 2021): instead of adding a positional code, one rotates each pair of coordinates (q_{2i}, q_{2i+1}) by an angle m\,\theta_i depending on the position m of the token (and on i), with \theta_i = b^{-2i/d}.
Relative character, in three lines (the full derivation is theorem 2.3 of the LLMs module): planar rotations commute and R(m)^\top R(n) = R(n - m), so \langle R(m)\, q,\; R(n)\, k \rangle = q^\top R(m)^\top R(n)\, k = q^\top R(n-m)\, k, the score depends only on the gap n - m: position is encoded within the interaction — this is the encoding of modern LLMs. The rotation is defined at every position, but a model generalizes poorly beyond its training context; extending the window rescales the angles (interpolation, YaRN), usually with a short fine-tuning (Advanced Topics in LLMs, ch. 3).
6.3. Costs and efficient attention
Complexity: \mathcal{O}(n^2 d) time and \mathcal{O}(n^2) memory (QK^\top matrix of size n \times n per head) — the LLM bottleneck. The MLP is \mathcal{O}(n d^2): attention dominates as soon as n \gtrsim d.
Where the time goes: the GPU memory hierarchy. A GPU has two memories that matter here. HBM is the large “GPU RAM” (40–80 GB on an A100, about 1.5–2 TB/s). SRAM is the small on-chip memory of each streaming multiprocessor (192 KB on each of the 108 of an A100, about 20 MB in all, roughly ten times faster).
An A100 computes about 300 TFLOP/s in bf16, so an operation that does fewer than about 150 FLOPs per byte read from HBM waits for memory: it is memory-bound. Softmax, masking and dropout do a few FLOPs per byte, and standard attention writes the n \times n scores to HBM and reads them back, \Theta(n^2) traffic. This paragraph is the program’s reference for the cost of FlashAttention; the P2 variant, ch. 6 develops the roofline model.
FlashAttention (Dao et al., 2022): exact, but IO-aware — it tiles the computation of \mathrm{softmax}(QK^\top)V into blocks loaded into SRAM (the GPU’s fast memory) and never writes the n \times n matrix to HBM, maintaining online log-sum-exp statistics (proposition 0.3 makes the softmax incremental: blocks are merged with m and the partial sum).
Result: same FLOPs, \mathcal{O}(n) memory, and \Theta(n^2 d^2 / M) HBM accesses for an SRAM of size M instead of \Theta(n^2) (Dao et al., theorem 2), hence ×2 to ×4 speed in practice.
Approximations: sparse, linear, sliding window (cf. LLMs module, M2).
“Graph” reading (Karpathy, “Let’s build GPT” lecture, 2023) — the bridge to the Graph ML module A transformer is a neural network on a dynamic graph:
- each token = a node carrying a vector;
- attention computes weighted edges \alpha_{ij} from the data (dynamic graph, unlike GNNs);
- \sum_j \alpha_{ij} v_j is a message passing: the nodes exchange their “values”;
- the MLP block = the local computation of each node; residual + LayerNorm = plumbing so that the “graph” stays trainable;
- a transformer layer = communication (attention) then computation (MLP), exactly the alternation of a GNN.
The LLGA program exploits this double reading: the same mathematical object seen “from inside the LLM” (M2 module) and “on structured data” (Graph ML module).
6.4. A complete block in PyTorch
import torch, torch.nn as nn, torch.nn.functional as F
class Block(nn.Module):
"""A pre-norm transformer block: multi-head attention (causal by default) + MLP."""
def __init__(self, d, n_heads, p_drop=0.1, causal=True):
super().__init__()
self.ln1, self.ln2 = nn.LayerNorm(d), nn.LayerNorm(d)
self.n_heads, self.d_head, self.causal = n_heads, d // n_heads, causal
self.qkv = nn.Linear(d, 3 * d)
self.proj = nn.Linear(d, d)
self.mlp = nn.Sequential(nn.Linear(d, 4 * d), nn.GELU(), nn.Linear(4 * d, d))
self.drop = nn.Dropout(p_drop)
def forward(self, x): # x: (B, n, d)
B, n, d = x.shape
q, k, v = self.qkv(self.ln1(x)).chunk(3, -1)
# multi-head: (B, n, d) -> (B, n, h, d_head) -> (B, h, n, d_head)
def split(t): return t.view(B, n, self.n_heads, self.d_head).transpose(1, 2)
q, k, v = split(q), split(k), split(v)
mask = (torch.tril(torch.ones(n, n, dtype=torch.bool, device=x.device)) # causal mask:
if self.causal else None) # True = may attend
att = F.scaled_dot_product_attention(q, k, v, # softmax(QK^T/sqrt(d_head))V
attn_mask=mask, dropout_p=0.0)
att = att.transpose(1, 2).reshape(B, n, d) # merge the heads back
x = x + self.drop(self.proj(att)) # residual 1 (pre-norm)
x = x + self.drop(self.mlp(self.ln2(x))) # residual 2
return x
torch.manual_seed(0)
x = torch.randn(2, 16, 128)
model = nn.Sequential(*[Block(128, 4) for _ in range(4)])
print(model(x).shape) # [2, 16, 128]
# Without positions (and without the causal mask), self-attention is permutation-
# equivariant: permuting the tokens permutes the outputs. Positions are added to x (6.2).
max_n, d = 512, 128
pos = torch.arange(max_n).unsqueeze(1) # (max_n, 1)
freq = 10000 ** (-torch.arange(0, d, 2) / d) # (d/2,) frequencies omega_i
pe = torch.zeros(max_n, d)
pe[:, 0::2], pe[:, 1::2] = torch.sin(pos * freq), torch.cos(pos * freq) # sinusoidal
learned = nn.Embedding(max_n, d) # or a learned table
n = x.shape[1]
print(model(x + pe[:n]).shape, model(x + learned(torch.arange(n))).shape)- Position: without positions, self-attention is permutation-equivariant: permuting the tokens permutes the outputs in the same way (proved as proposition 4.4 of Advanced DL). Invariance only comes after a symmetric pooling, such as a mean over tokens. To use the order, one adds positional encodings (sinusoidal, learned, or RoPE, 6.2) — and on graphs: the analogue is the problem of positional/structural encodings, at the heart of chapter 10 and of the Advanced GNN module (M2);
- MLP: two layers with GELU, expansion ratio ~4 — this is where most of the parameters live (~2/3);
- Cross-attention (encoder–decoder models: the original transformer, T5): a second attention sub-block in the decoder takes its queries from the decoder states Y and its keys and values from the encoder output H,
\mathrm{CrossAtt}(Y, H) = \mathrm{softmax}\Big(\frac{(YW_Q)(HW_K)^\top}{\sqrt{d_k}}\Big)\, HW_V,
one output row per target token and no mask on the source. In code it is
F.scaled_dot_product_attention(q_from_Y, k_from_H, v_from_H). The same operation injects a text prompt into an image diffusion model (9.4). - Causal mask: forbid j > i for autoregression — exactly the factorization \mathbb{P}(x) = \prod_t \mathbb{P}(x_t \mid x_{<t}) of chapter 9 and of the causal language models of section 6.5.
6.5. Modern NLP: tokens, embeddings and pretraining objectives
The official syllabus lists “modern natural language processing” and “embeddings”. A transformer consumes vectors, not text: this section explains how a sentence becomes a sequence of vectors, and what a language model is trained to predict before any task-specific adaptation (chapter 7).
Definition 6.3 — Subword tokenization by byte-pair encoding (BPE) Start from a vocabulary of characters (or bytes) and split every word of the training corpus into them, with an end-of-word marker _. Repeatedly count all pairs of adjacent symbols, weighted by word frequency, and merge the most frequent pair into a new symbol, until the vocabulary \mathcal{V} reaches a chosen size |\mathcal{V}| (about 3 \times 10^4 to 2 \times 10^5 in current models). A new text is tokenized by applying the learned merges in the same order. No word is ever out of vocabulary, frequent words become single tokens and rare words are split into reusable pieces.
Example 6.4 — Five merges by hand Corpus: “low” ×5, “lower” ×2, “newest” ×6, “widest” ×3. The pairs e s, s t and t _ each occur 6 + 3 = 9 times, more than any other pair, so the first merges are es, then est, then est_ (ties broken by order of appearance). Next come l o and lo w, with 7 occurrences each. After these five merges the unseen word “lowest” is encoded as two tokens, low and est_: the tokenizer has discovered a stem and a suffix from frequencies alone.
Definition 6.5 — Embedding matrix, static and contextual embeddings Each token w \in \mathcal{V} is mapped to a row E_w of a learned matrix E \in \mathbb{R}^{|\mathcal{V}| \times d}; this is the product of the one-hot vector of w with E, so the gradient touches only the rows of tokens present in the batch.
Many language models reuse E at the output, computing the next-token logits as E\,h (weight tying).
A static embedding gives one vector per word whatever its context. Word2vec’s skip-gram with negative sampling learns it without labels; its loss, its gradient and its matrix-factorization reading are derived later, in theorem 4.1 of the NLP module (Period 2); here it is only stated. With a center vector v_w, a context vector u_c and k negatives n_i drawn in proportion to frequency^{3/4}, one minimizes \mathcal{L} = -\log\sigma(u_c^\top v_w) - \sum_{i=1}^{k}\log\sigma(-u_{n_i}^\top v_w). At the optimum, u_c^\top v_w is the pointwise mutual information of (w, c) minus \log k (Levy & Goldberg, 2014): words that share contexts get similar vectors.
The output of a transformer layer is a contextual embedding: the vector of “bank” differs in “river bank” and in “bank account”, because attention has mixed in the neighbouring tokens.
Definition 6.6 — Pretraining objectives A causal (autoregressive) language model factorizes \mathbb{P}(x_1, \dots, x_n) = \prod_t \mathbb{P}(x_t \mid x_{<t}) and minimizes the average negative log-likelihood \mathcal{L} = -\frac1n\sum_t \log p_\theta(x_t \mid x_{<t}), using the causal mask of section 6.4; this is the decoder-only family (GPT and most current LLMs).
A masked language model (BERT, an encoder) hides about 15% of the tokens and predicts them from the context on both sides; its representations serve classification and retrieval. Encoder–decoder models (T5) reconstruct masked spans of the input. In each case the labels come from the text itself: this is self-supervised learning.
The quality of a causal model is reported as its perplexity \exp(\mathcal{L}).
Example 6.7 — Perplexity by hand A model assigns probabilities \tfrac12, \tfrac14, \tfrac18, \tfrac12 to the four tokens of a sentence. Its loss, in nats, is \mathcal{L} = \tfrac14(\ln 2 + \ln 4 + \ln 8 + \ln 2) = \tfrac74\ln 2 \approx 1.21, and its perplexity is 2^{7/4} \approx 3.4: at each step the model is as uncertain as a uniform choice among about 3.4 tokens.
A uniform model over a vocabulary of 50{,}000 tokens has perplexity 50{,}000.
import torch, torch.nn.functional as F
vocab, n = 50_000, 4 # |V| tokens, n positions
logits = torch.randn(n, vocab) # one row of scores per position
targets = torch.randint(0, vocab, (n,)) # the next tokens
loss = F.cross_entropy(logits, targets) # average NLL over positions
print(loss.item(), torch.exp(loss).item()) # loss in nats, perplexity6.6. Transformers beyond text: the vision transformer (ViT)
A transformer only needs a sequence of vectors. The vision transformer of Dosovitskiy et al. (2021) turns an image into such a sequence by cutting it into patches, and then uses the encoder of 6.4 unchanged, without the causal mask.
Definition 6.8 — Vision transformer (ViT) For an image of size H \times W with C channels and a patch side P:
- Patchify: cut the image into N = HW/P^2 patches and flatten each into a vector of size P^2C.
- Linear projection: map each patch to \mathbb{R}^d with one shared matrix E \in \mathbb{R}^{P^2C \times d}, the same for every patch.
- [CLS] token: prepend one learned vector, whose final state serves as the summary of the image.
- Learned positions: add a learned table of N + 1 positions (6.2), so that the model knows where each patch was.
- Encoder and head: apply a stack of bidirectional blocks (12 in ViT-B), then a linear classifier on the final [CLS] state.
import torch, torch.nn as nn
B, C, H, W, P, d = 8, 3, 224, 224, 16, 768
x = torch.randn(B, C, H, W)
patchify = nn.Conv2d(C, d, kernel_size=P, stride=P) # = one shared linear map per patch
tok = patchify(x).flatten(2).transpose(1, 2) # (B, 196, 768)
cls = nn.Parameter(torch.zeros(1, 1, d)) # [CLS] token
pos = nn.Parameter(torch.zeros(1, 1 + tok.shape[1], d)) # learned positions
z = torch.cat([cls.expand(B, -1, -1), tok], 1) + pos # (B, 197, 768): ready for the blocks
print(z.shape)Example 6.9 — ViT-B/16 on the counter A 224 \times 224 RGB image with P = 16 gives N = 196 patches of 16 \cdot 16 \cdot 3 = 768 numbers, plus [CLS]: n = 197 tokens of width d = 768, through 12 blocks with 12 heads.
- Parameters: about 12d^2 = 7.1 M per block, hence about 86 M in all; the 12 encoder blocks of BERT-base have the same size.
- Compute per block: the projections and the MLP cost 12 n d^2 multiply–adds, the scores and their product with V cost 2n^2d.
- Total: about 17.5 \times 10^9 multiply–adds per image (the figure often quoted as “17.6 GFLOPs” counts multiply–adds). The n^2 term is only 4% of it at n = 197.
With P = 8 the image gives n = 785 tokens and the cost rises to about 78 \times 10^9 multiply–adds: a smaller patch buys resolution with compute, and the quadratic term starts to count.
Inductive bias, and where ViT goes next A CNN builds locality and translation equivariance into its weights (ch. 4); a ViT has neither, apart from the patch grid, and must learn them from data. This is why ViT matches or beats ResNets only after pretraining on large datasets (ImageNet-21k, JFT-300M), and why Exercise 12 compares the two on MNIST. ViT is the image encoder of CLIP and of most vision-language models (Multimodal Generative AI module); DeiT and Swin are treated in Advanced DL, ch. 4.
7. Transfer learning and fine-tuning
Training “from scratch” has become the exception: the dominant practice consists in starting from a model pre-trained on immense corpora (ImageNet for vision, terabytes of text for LLMs) and adapting it. This chapter gives the framework and the vocabulary; the LLMs module (M2) applies it at scale.
7.1. The three adaptation regimes
- Frozen features / linear probing: freeze the whole backbone, train a linear classifier (or a small head) on the pre-trained representations. A valuable diagnostic: feature quality is measured by the performance of a simple softmax on top (exercise 12, step (d)).
- Full fine-tuning: retrain all the weights with a smaller step (typically 10 to 100× smaller than pre-training) — the risk of catastrophic forgetting (loss of pre-trained knowledge) is managed by a decaying step and few epochs.
- Parameter-efficient fine-tuning (PEFT): train only a small fraction of new parameters, the rest staying frozen — all the more relevant as models grow.
Why it works The low layers learn quasi-universal features (chapter 4: edges and textures in vision; in a pretrained text transformer, parts of speech and local syntax, as the probing study of Tenney, Das & Pavlick, 2019, shows); task specificity lives in the high layers. The performance versus number of labeled domain examples curve shifts massively to the left — this is the most measurable practical benefit of modern deep learning.
Worked example — linear probe, partial and full fine-tuning of a ResNet-18 Adapt an ImageNet-pretrained ResNet-18 (11.18 M weights without its 1000-class head) to a 10-class task. The new head has 512 \times 10 + 10 = 5{,}130 weights.
| Regime | Trainable weights | The backward pass goes through | Learning rate |
|---|---|---|---|
| Linear probe | 5,130 (0.05%) | the head only | large (fresh head) |
| Partial: last stage + head | 8.40 M (75%) | layer4 and the head |
small for layer4, large for the head |
| Full fine-tuning | 11.18 M (100%) | the whole network | 10 to 100 × below pretraining |
- Partial fine-tuning is cheap in compute, not in parameters. The last stage holds three quarters of the weights of a ResNet-18, but the backward pass stops there and the frozen stages store no activations.
- The domain decides. On a target close to ImageNet with a few hundred labels per class, the probe often comes within a few points of full fine-tuning and barely overfits. The further the domain moves (medical images, sketches), the more of the high layers must be retrained.
- Run the probe first. It is the floor that any fine-tuning must beat, and it measures the quality of the features (exercise 12, step (d)). Keep frozen BatchNorm layers in
eval()mode, or their running statistics still move.
def set_regime(model, regime): # a torchvision resnet18 whose model.fc = nn.Linear(512, 10)
for p in model.parameters():
p.requires_grad = (regime == "full")
if regime == "partial":
for p in model.layer4.parameters():
p.requires_grad = True
for p in model.fc.parameters(): # the new head is always trained
p.requires_grad = True
return sum(p.numel() for p in model.parameters() if p.requires_grad) # 5130 / 8398858 / 111816427.2. Domain adaptation, in a nutshell
When the target has no labels (labeled source domain → unlabeled target domain), domain adaptation aligns the distributions: adversarial (a discriminator tries to guess the domain from the features: they must become non-discriminative), or via distribution distances (MMD, Wasserstein distances — a preview: they are defined in the Optimal Transport module and in Graph ML 9.6). The guiding idea: learn representations invariant to the domain but discriminative for the task.
7.3. LoRA: a mathematical sketch
Definition 7.1 — LoRA (Hu et al., 2021) For a pre-trained matrix W_0 \in \mathbb{R}^{d_{\mathrm{out}} \times d_{\mathrm{in}}}, one freezes W_0 and learns a low-rank update: W = W_0 + \Delta W = W_0 + \frac{\alpha}{r}\, B A, \qquad B \in \mathbb{R}^{d_{\mathrm{out}} \times r},\ A \in \mathbb{R}^{r \times d_{\mathrm{in}}},\ r \ll \min(d_{\mathrm{in}}, d_{\mathrm{out}}), with B initialized to zero and A Gaussian: \Delta W = 0 at the start, training departs exactly from the pre-trained model. \alpha/r sets the effective scale of the update.
Why a low rank suffices The working hypothesis, backed by Aghajanyan et al. (ACL 2021), is that weight updates during adaptation have a low “intrinsic rank”: \Delta W is well approximated by a product BA of small rank r (4 to 64 in practice).
Let us count: adapting a d \times d layer with r = 8 costs 2dr = 16d parameters instead of d^2 — for d = 4096, a factor of d/16 = 256.
Other benefits: a single W_0 kept in memory + per-task interchangeable (A, B) pairs (instant swap); and for inference latency, one can merge W = W_0 + BA at no extra cost. The generalizations (QLoRA: quantized backbone + LoRA) are covered in the LLMs module (M2), section 4.3.
import torch, torch.nn as nn
class LoRALinear(nn.Module):
def __init__(self, base: nn.Linear, r=8, alpha=16):
super().__init__()
self.base = base # W0 frozen
for p in self.base.parameters(): p.requires_grad = False
self.A = nn.Parameter(torch.randn(r, base.in_features) * 0.01)
self.B = nn.Parameter(torch.zeros(base.out_features, r))
self.scale = alpha / r
def forward(self, x):
return self.base(x) + self.scale * (x @ self.A.T @ self.B.T)
# trainable params: r*(in+out) instead of in*out8. Training in practice
A network that does not learn almost always has a mundane bug. This chapter is the diagnostic protocol we will apply in the labs, in the order in which it must be applied.
8.1. The training recipe, in order
- Shape sanity check: one forward pass without errors, the dimensions of every activation verified (rule of ch. 0: gradients have the shape of their variable).
- Overfit a single batch: 32 examples, train until the loss is \approx 0. If the model cannot do it, the bug is structural (data, loss, initialization, wild learning rate) — no point training longer. A model unable to memorize 32 examples is broken or too small; this is THE test that avoids weeks of silent error.
- LR range test (Smith, 2015): \eta increasing geometrically from 10^{-7} to 10^{0}, plot the loss: plateau → descent → divergence. Take the \eta at the dip (or slightly before): it sets AdamW/SGD in one epoch.
- Small full training run on ~10% of the data, with the train/val curves: check that the dynamics are healthy before scaling up.
- Scaling + regularization: larger batch (or gradient accumulation), mixed precision, data augmentation, dropout, weight decay — in that order of payoff (ch. 3).
- Checkpointing: save regularly (weights + optimizer state + current step + data generator seed), to resume exactly.
8.2. Monitoring: reading your curves
| Symptom | Likely cause | Response |
|---|---|---|
| loss = NaN | lr too large, log(0), unprotected softmax (ch. 0), fp16 overflow | divide lr by 10, log-softmax, loss scaling |
| one-off loss spikes | aberrant batch, lr near the edge of 2/L (thm. 3.1) | inspect the data, lower the lr, gradient clipping |
| exploding gradient norm | poorly conditioned recurrences (ch. 5) | clip \|\hat g\| to a threshold (standard: 1.0) |
| train goes down, val stagnates | overfitting | ch. 3.6, in order of payoff |
| neither train nor val moves | lr too small, blockage (dead ReLUs), loss mis-wired | LR range test, per-layer activation statistics |
Tools: tensorboard/wandb; systematically log the loss, accuracy, gradient norm, weight norm, the fraction of zero activations (dying ReLU), and the activation histograms of a few layers.
8.3. GPU: the levers that matter
- Mixed precision (bf16 preferably): ~2× throughput, memory divided by ~2 — the first reflex (ch. 2).
- Batch and accumulation: saturate the GPU (measure utilization); if memory runs out, accumulate small batches; adjust the BatchNorm statistics accordingly.
- DataLoader: workers > 0, pin_memory, prefetch — a GPU waiting for data is a wasted GPU (CPU preprocessing is often the real bottleneck).
- torch.compile, fused kernels (FlashAttention, ch. 6), avoid CPU→GPU synchronizations inside the loop (the .item() / prints at each step).
The loop below puts the first and last of these levers together with experiment tracking. Autocast runs the matrix products in 16 bits and keeps reductions in float32; the gradient scaler is needed only for float16, whose narrow exponent range lets small gradients underflow (ch. 2.2). It runs as is on a CPU, in bfloat16.
import torch, torch.nn as nn
from torch.utils.tensorboard import SummaryWriter # pip install tensorboard
device = "cuda" if torch.cuda.is_available() else "cpu"
model = nn.Sequential(nn.Linear(32, 256), nn.GELU(), nn.Linear(256, 10)).to(device)
opt = torch.optim.AdamW(model.parameters(), lr=3e-4, weight_decay=1e-2)
use_fp16 = device == "cuda" and not torch.cuda.is_bf16_supported() # old GPUs: fp16
dtype = torch.float16 if use_fp16 else torch.bfloat16
scaler = torch.amp.GradScaler(device, enabled=use_fp16) # loss scaling, needed for fp16 only
writer = SummaryWriter("runs/exp1") # then: tensorboard --logdir runs
for step in range(100):
x = torch.randn(64, 32, device=device)
y = torch.randint(0, 10, (64,), device=device)
with torch.autocast(device_type=device, dtype=dtype): # matmuls in 16 bits, reductions in fp32
loss = nn.functional.cross_entropy(model(x), y)
opt.zero_grad(set_to_none=True)
scaler.scale(loss).backward() # multiply the loss so that small fp16 gradients survive
scaler.unscale_(opt) # true gradients again, before clipping
gnorm = nn.utils.clip_grad_norm_(model.parameters(), 1.0)
scaler.step(opt) # skips the step if an inf or NaN appeared
scaler.update()
if step % 10 == 0: # .item() waits for the GPU: log every k steps only
writer.add_scalar("train/loss", loss.item(), step)
writer.add_scalar("train/grad_norm", gnorm.item(), step)
writer.close()8.4. Reproducibility
import torch, numpy as np, random
def seed_everything(seed=42):
random.seed(seed); np.random.seed(seed); torch.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
seed_everything(42)
torch.backends.cudnn.deterministic = True # determinism (speed cost)
torch.backends.cudnn.benchmark = False # disable non-deterministic autotuningSet the seeds (python/numpy/torch/cuda), the data shuffling, and record the library versions; some CUDA kernels remain non-deterministic by nature (atomics); aim for reproducibility up to a tolerance rather than bit-for-bit, and document configurations and seeds in every experiment. Reproducibility is also a debugging tool: a random bug you know how to reproduce is half fixed.
9. Generative models: AE, VAE, GAN
The networks of the previous chapters predict a label y from an input x; a generative model learns the distribution of x itself, so that it can produce new images or sentences. This chapter compares three ways of doing so — autoencoders, variational autoencoders and generative adversarial networks — and derives the training objective of each.
9.1. Deterministic autoencoder and its pathology
An autoencoder compresses x into a code z = E_\phi(x) and reconstructs \hat x = D_\theta(z), trained on \|x - \hat x\|^2. Useful for representation learning though it is, it is not a generative model: the latent space has no imposed structure — sampling z at random gives aberrant reconstructions. The VAE corrects precisely this.
Linear autoencoder and PCA (Baldi & Hornik, 1989) Take centred data, a linear encoder z = W_e x with W_e \in \mathbb{R}^{k \times d}, a linear decoder \hat x = W_d z and the squared reconstruction error.
The map x \mapsto W_d W_e x has rank at most k, so by the Eckart–Young theorem the best achievable error is that of the projection onto the top k principal directions, and every global minimizer reconstructs through exactly that projection (when \lambda_k > \lambda_{k+1}). The weights themselves are identified only up to an invertible k \times k change of basis of the code.
A linear autoencoder is thus PCA (Machine Learning module, section 7.3) learned by gradient descent; nonlinear encoders and decoders extend dimensionality reduction to curved data, and a denoising autoencoder, which reconstructs x from a corrupted copy, learns features that are robust to that corruption.
9.2. VAE: the ELBO fully derived
Sections 9.2 and 9.3 are the site’s reference derivations of the ELBO and of the GAN equilibrium: the Multimodal Generative AI module and others recall them and link here.
Definition 9.1 — VAE (Kingma & Welling, 2013) Diagonal Gaussian encoder q_\phi(z \mid x) = \mathcal{N}\big(\mu_\phi(x), \mathrm{diag}(\sigma_\phi^2(x))\big), decoder p_\theta(x \mid z), prior z \sim \mathcal{N}(0, I). One maximizes the ELBO (evidence lower bound): \mathrm{ELBO}(\theta, \phi; x) = \mathbb{E}_{q_\phi}\big[\log p_\theta(x \mid z)\big] - \mathrm{KL}\big(q_\phi(z \mid x)\,\|\,\mathcal{N}(0, I)\big), that is, one minimizes the training loss \mathcal{L}_{\mathrm{VAE}} = -\mathrm{ELBO}, averaged over the data.
Theorem 9.2 — Exact decomposition of the log-likelihood \log p_\theta(x) = \mathrm{ELBO}(\theta, \phi; x) + \mathrm{KL}\big(q_\phi(z\mid x)\,\big\|\,p_\theta(z \mid x)\big) \;\ge\; \mathrm{ELBO}(\theta, \phi; x). Maximizing the ELBO = maximizing a lower bound of \log p_\theta(x) and bringing q_\phi(z \mid x) closer to the exact posterior p_\theta(z \mid x).
Proof. Start from the definition of the KL between q_\phi(\cdot \mid x) and the posterior p_\theta(\cdot \mid x), both over z (at fixed x), and expand with p_\theta(x, z) = p_\theta(x \mid z)\, p(z) (Bayes): \mathrm{KL}\big(q_\phi \| p_\theta(\cdot \mid x)\big) = \mathbb{E}_q[\log q] - \mathbb{E}_q[\log p_\theta(x \mid z)] - \mathbb{E}_q[\log p(z)] + \log p_\theta(x). Now, by definition of the KL against the prior, \mathbb{E}_q[\log q] - \mathbb{E}_q[\log p(z)] = \mathrm{KL}(q_\phi \| \mathcal{N}(0,I)). Substituting: \mathrm{KL}\big(q_\phi \| p_\theta(\cdot \mid x)\big) = \mathrm{KL}(q_\phi \| \mathcal{N}) - \mathbb{E}_q[\log p_\theta(x \mid z)] + \log p_\theta(x), that is, rearranging: \log p_\theta(x) = \underbrace{\mathbb{E}_q[\log p_\theta(x \mid z)] - \mathrm{KL}(q_\phi \| \mathcal{N})}_{=\ \mathrm{ELBO}(\theta,\phi;x)} + \mathrm{KL}\big(q_\phi \| p_\theta(\cdot \mid x)\big). The KL is nonnegative (Jensen applied to \mathbb{E}_q[\log(q/p)] \ge -\log \mathbb{E}_q[p/q] = 0), giving the bound. Equality iff q_\phi(z \mid x) = p_\theta(z \mid x) exactly. ∎
Reading the proof One cannot optimize \log p_\theta(x) = \log \int p_\theta(x \mid z)\, p(z)\, dz directly: the integral is intractable. The ELBO is the only quantity that requires only (i) samples from q_\phi (Monte Carlo: a single one suffices in practice) and (ii) a closed-form KL. It is the same trade-off as in EM (Machine Learning module): the residual KL measures exactly what the bound loses.
Proposition 9.3 — Reparameterization: why z = \mu + \sigma \odot \varepsilon works If \varepsilon \sim \mathcal{N}(0, I) and z = \mu_\phi(x) + \sigma_\phi(x) \odot \varepsilon, then z \sim \mathcal{N}(\mu_\phi(x), \mathrm{diag}(\sigma_\phi^2(x))) and \nabla_\phi \mathbb{E}_{q_\phi}[f(z)] = \mathbb{E}_\varepsilon\big[\nabla_\phi f(\mu_\phi + \sigma_\phi \odot \varepsilon)\big]: the gradient gets through. Sampling z \sim q_\phi directly blocks the gradient (the sampling operation has no derivative with respect to its parameters).
Proof. The law of z is obtained by an affine change of variable, whose Jacobian \partial z/\partial \varepsilon = \mathrm{diag}(\sigma) is constant: the density of z is that of a Gaussian with mean \mu, covariance \mathrm{diag}(\sigma^2).
For the gradient: the expectation under q_\phi rewrites as an expectation under the fixed law of \varepsilon, \mathbb{E}_{q_\phi}[f(z)] = \mathbb{E}_{\varepsilon}[f(\mu_\phi + \sigma_\phi \odot \varepsilon)]; the distribution is no longer parameterized by \phi — \phi now appears only in the integrand, which gradient descent knows how to differentiate (theorem 2.1). ∎
Proposition 9.4 — Closed-form KL between diagonal Gaussians For q = \mathcal{N}(\mu, \mathrm{diag}(\sigma^2)) and p = \mathcal{N}(0, I) in dimension k: \mathrm{KL}(q \| p) = \frac12 \sum_{i=1}^{k} \big(\mu_i^2 + \sigma_i^2 - 1 - \log \sigma_i^2\big).
Proof. \mathrm{KL}(q\|p) = \mathbb{E}_q[\log q(z) - \log p(z)]. Coordinate by coordinate (the densities factorize), with \varphi the standard Gaussian density: \log q(z_i) - \log \varphi(z_i) = -\tfrac12\log\sigma_i^2 - \frac{(z_i - \mu_i)^2}{2\sigma_i^2} + \frac{z_i^2}{2}. Under q, z_i \sim \mathcal{N}(\mu_i, \sigma_i^2), so \mathbb{E}_q[(z_i - \mu_i)^2] = \sigma_i^2 and \mathbb{E}_q[z_i^2] = \mu_i^2 + \sigma_i^2. Taking the expectation: -\tfrac12\log\sigma_i^2 - \tfrac12 + \tfrac12(\mu_i^2 + \sigma_i^2), that is \tfrac12(\mu_i^2 + \sigma_i^2 - 1 - \log \sigma_i^2).
Along the way one checks that each term is \ge 0, zero iff \mu_i = 0, \sigma_i = 1 (study of u - 1 - \log u \ge 0). ∎
The ELBO trade-off in practice First term: reconstruction. Second: a regularizer that keeps the codes close to the prior — too strong, everything blurs together (codes ignored, blurry sampling); too weak, the latent space develops “holes” (partial posterior collapse). The connection with variational inference and EM is taken up again in the Machine Learning module; the extensions (\beta-VAE, VQ-VAE) are in Multimodal Generative AI.
9.3. GAN: the minimax game and its equilibrium
Definition 9.5 — GAN (Goodfellow et al., 2014) Minimax game between a generator G (often G(z) with z \sim \mathcal{N}(0, I)) and a discriminator D : \mathcal{X} \to (0,1): \min_G \max_D \ V(G, D), \qquad V(G, D) = \mathbb{E}_{x \sim p_{\mathrm{data}}}\big[\log D(x)\big] + \mathbb{E}_{z \sim p(z)}\big[\log(1 - D(G(z)))\big].
Theorem 9.6 — Optimal discriminator and global equilibrium
- For fixed G, the maximand reads (with p_G the law of G(z)) V(G,D) = \int \big[p_{\mathrm{data}}(x)\log D(x) + p_G(x) \log(1 - D(x))\big] dx, maximized pointwise at D^\star(x) = \frac{p_{\mathrm{data}}(x)}{p_{\mathrm{data}}(x) + p_G(x)}.
- The value of the game is then V(G, D^\star) = -\log 4 + 2\,\mathrm{JSD}(p_{\mathrm{data}} \| p_G), minimized over G exactly when p_G = p_{\mathrm{data}}: the global equilibrium exists and coincides with the law of the data.
Proof. 1) For each fixed x, maximize a\log D + b\log(1-D) with a = p_{\mathrm{data}}(x), b = p_G(x).
The derivative a/D - b/(1-D) = 0 gives D^\star = a/(a+b) (strict concavity in D \in (0,1)).
2) Rewrite \log D^\star = \log \frac{p_{\mathrm{data}}}{p_{\mathrm{data}}+p_G} = \log\frac{p_{\mathrm{data}}}{m} - \log 2 and \log(1 - D^\star) = \log \frac{p_G}{m} - \log 2, where m = \frac12(p_{\mathrm{data}} + p_G). Then V(G, D^\star) = \int p_{\mathrm{data}} \log\frac{p_{\mathrm{data}}}{m} + \int p_G \log\frac{p_G}{m} - 2\log 2 = 2\,\mathrm{JSD}(p_{\mathrm{data}} \| p_G) - \log 4, by definition of the Jensen–Shannon divergence (average of the KLs toward m).
Since \mathrm{JSD} \ge 0 with equality if and only if p_{\mathrm{data}} = p_G almost everywhere (each KL toward the mixture m vanishes only when the law equals m), the minimum -\log 4 is reached exactly at equilibrium.
Gaussian case: if p_{\mathrm{data}} = \mathcal{N}(\mu_d, \sigma_d^2) and G(z) = \mu + \sigma z, then p_G = \mathcal{N}(\mu, \sigma^2) and the equilibrium corresponds to the exact parameters (\mu, \sigma) = (\mu_d, \sigma_d).
The logit of D^\star, \log p_{\mathrm{data}} - \log p_G, is a degree-2 polynomial in x — a quadratic discriminator suffices. ∎
Why it is unstable nonetheless The theorem describes the equilibrium, not the dynamics: the two players descend their gradients simultaneously, and if D becomes too good too fast, the gradient of G vanishes (\log(1 - D) saturates). Emblematic pathology: mode collapse — G concentrates on the “easiest” modes of p_{\mathrm{data}} (a few very credible faces instead of all of them).
Historical remedies: Wasserstein-GAN (transportation distance instead of JSD — a preview: the distance is defined in the Optimal Transport module and Graph ML 9.6), gradient penalization, feature matching. In imaging, the family was superseded by diffusion (iterative denoising): section 9.4 gives its loss and sampler, Ye Zhu’s models (chapter 10) are recent developments of it, and the Multimodal Generative AI module treats them in detail.
LLMs, for their part, remain autoregressive: \mathbb{P}(x_t \mid x_{<t}), cross-entropy loss over tokens (LLMs module, M2).
| Family | Principle | Sampling | In the program |
|---|---|---|---|
| VAE | ELBO, Gaussian latent | decoder from z \sim \mathcal{N} | Multimodal GenAI |
| GAN | adversarial min-max | implicit | Multimodal GenAI |
| Diffusion | iterative noising/denoising | (reverse) process | 9.4 (self-study); Multimodal GenAI |
| Autoregressive | modeling \mathbb{P}(x_t \mid x_{<t}) | token by token | LLMs (M2), Graph GenAI |
9.4. Diffusion in one section (self-study)
A VAE samples in one decoder pass but blurs; a GAN is sharp but unstable. Diffusion models (Sohl-Dickstein et al., 2015; Ho, Jain & Abbeel, 2020) take a third route: a fixed process turns data into noise in many small Gaussian steps, and a network learns to undo one step at a time, with a plain regression as its loss.
This section gives the formulas that the rest of the program uses: discrete diffusion on graphs (Graph ML 9.5), Geometric Data ch. 7–8 and Advanced DL 10.4.
Definition 9.7 — Forward (noising) process Choose a schedule 0 < \beta_1 < \dots < \beta_T < 1 (Ho et al.: linear from 10^{-4} to 0.02, with T = 1000), and set \alpha_t = 1 - \beta_t, \qquad \bar\alpha_t = \prod_{s=1}^{t} \alpha_s . The forward chain adds a little Gaussian noise at each step: q(x_t \mid x_{t-1}) = \mathcal{N}\big(\sqrt{\alpha_t}\, x_{t-1},\ \beta_t I\big). Step t = 0 is the data. At t = T, \bar\alpha_T \approx 0 and x_T is almost pure noise.
Proposition 9.8 — Closed form at any step For every t, q(x_t \mid x_0) = \mathcal{N}\big(\sqrt{\bar\alpha_t}\, x_0,\ (1 - \bar\alpha_t)\, I\big), \qquad\text{that is}\qquad x_t = \sqrt{\bar\alpha_t}\, x_0 + \sqrt{1 - \bar\alpha_t}\; \varepsilon, \quad \varepsilon \sim \mathcal{N}(0, I). Training can therefore draw any step t directly, without running the chain.
Proof. By induction on t, with \bar\alpha_0 = 1. Assume x_{t-1} = \sqrt{\bar\alpha_{t-1}}\, x_0 + \sqrt{1 - \bar\alpha_{t-1}}\, \varepsilon'. Then x_t = \sqrt{\alpha_t}\, x_{t-1} + \sqrt{\beta_t}\, \varepsilon_t = \sqrt{\bar\alpha_t}\, x_0 + \Big(\sqrt{\alpha_t(1 - \bar\alpha_{t-1})}\, \varepsilon' + \sqrt{\beta_t}\, \varepsilon_t\Big). The bracket is a sum of two independent centred Gaussians, whose variances add up to \alpha_t(1 - \bar\alpha_{t-1}) + 1 - \alpha_t = 1 - \bar\alpha_t. ∎
From the ELBO to a regression. The reverse model is a Gaussian chain started from p(x_T) = \mathcal{N}(0, I): p_\theta(x_{t-1} \mid x_t) = \mathcal{N}\big(\mu_\theta(x_t, t),\ \sigma_t^2 I\big). Treating x_{1:T} as the latent variables of a VAE, theorem 9.2 gives \log p_\theta(x_0) \ge \mathrm{ELBO}, and the negative ELBO splits into one term per step: -\mathrm{ELBO} = L_T + \sum_{t=2}^{T} L_{t-1} + L_0, \qquad L_{t-1} = \mathbb{E}_q\, \mathrm{KL}\big(q(x_{t-1} \mid x_t, x_0)\,\big\|\,p_\theta(x_{t-1} \mid x_t)\big). L_T has no parameter, since the prior is fixed, and L_0 is a decoder term.
Proposition 9.9 — The ε-prediction loss (Ho et al., 2020) By Bayes’ rule on Gaussians, the forward posterior q(x_{t-1} \mid x_t, x_0) is Gaussian with variance \tilde\beta_t I and mean \tilde\mu_t: \tilde\beta_t = \frac{1 - \bar\alpha_{t-1}}{1 - \bar\alpha_t}\,\beta_t, \qquad \tilde\mu_t = \frac{1}{\sqrt{\alpha_t}}\Big(x_t - \frac{\beta_t}{\sqrt{1 - \bar\alpha_t}}\, \varepsilon\Big), where x_0 was replaced by its expression from proposition 9.8. Give the reverse mean the same form, with a network \varepsilon_\theta(x_t, t) in place of the unknown \varepsilon. Then, up to a constant C_t free of \theta, L_{t-1} = \frac{\beta_t^2}{2\sigma_t^2\, \alpha_t\, (1 - \bar\alpha_t)}\; \mathbb{E}\,\big\|\varepsilon - \varepsilon_\theta(x_t, t)\big\|^2 + C_t .
Proof. The KL between two Gaussians with covariances \tilde\beta_t I and \sigma_t^2 I is \|\tilde\mu_t - \mu_\theta\|^2 / (2\sigma_t^2) plus a term that depends on the variances only. The two means differ only through the noise: \tilde\mu_t - \mu_\theta = \frac{\beta_t}{\sqrt{\alpha_t}\,\sqrt{1 - \bar\alpha_t}}\,\big(\varepsilon_\theta(x_t, t) - \varepsilon\big), and squaring gives the weight. ∎
Key result — the diffusion training loss \mathcal{L}_{\mathrm{simple}}(\theta) = \mathbb{E}_{t,\, x_0,\, \varepsilon}\, \Big\| \varepsilon - \varepsilon_\theta\big(\sqrt{\bar\alpha_t}\, x_0 + \sqrt{1 - \bar\alpha_t}\, \varepsilon,\ t\big) \Big\|^2, \qquad t \sim \mathcal{U}\{1, \dots, T\}.
Ho et al. drop the weight of proposition 9.9: the samples get better, at the price of a looser bound.
Algorithm 9.10 — Ancestral sampling Draw x_T \sim \mathcal{N}(0, I). For t = T, \dots, 1, draw z \sim \mathcal{N}(0, I) (and set z = 0 at the last step), then x_{t-1} = \frac{1}{\sqrt{\alpha_t}}\Big(x_t - \frac{\beta_t}{\sqrt{1 - \bar\alpha_t}}\, \varepsilon_\theta(x_t, t)\Big) + \sigma_t z, \qquad \sigma_t^2 = \beta_t \ \text{ or } \ \tilde\beta_t . Output x_0. A sample costs T network evaluations, against one for a VAE or a GAN; DDIM and distillation cut this number (Multimodal GenAI, ch. 4).
Proposition 9.11 — Predicting the noise is estimating the score Let p_t be the law of x_t. The best predictor in \mathcal{L}_{\mathrm{simple}} is the conditional mean \varepsilon^\star(x, t) = \mathbb{E}[\varepsilon \mid x_t = x], and \nabla_x \log p_t(x) = -\frac{\varepsilon^\star(x, t)}{\sqrt{1 - \bar\alpha_t}} . A trained \varepsilon_\theta is thus an estimate of the score \nabla \log p_t, which links DDPM to score-based models and Langevin sampling (Song et al., 2021).
Proof. The minimizer of a squared error is the conditional expectation. Next, p_t(x) = \int q(x \mid x_0)\, p(x_0)\, dx_0; differentiating under the integral, \nabla p_t(x) = \int q(x \mid x_0)\, \nabla_x \log q(x \mid x_0)\; p(x_0)\, dx_0 . Dividing by p_t(x) and using Bayes’ rule, \nabla \log p_t(x) is the conditional mean of \nabla_x \log q(x \mid x_0) given x_t = x. By proposition 9.8, \nabla_x \log q(x \mid x_0) = -\frac{x - \sqrt{\bar\alpha_t}\, x_0}{1 - \bar\alpha_t} = -\frac{\varepsilon}{\sqrt{1 - \bar\alpha_t}}, and taking the conditional mean ends the proof. ∎
Classifier-free guidance (Ho & Salimans, 2022). To condition on a prompt c (a class, a caption), train one network \varepsilon_\theta(x_t, t, c) and replace c by an empty token \varnothing on about 10% of the examples. At sampling time, extrapolate from the unconditional prediction toward the conditional one: \tilde\varepsilon_w = \varepsilon_\theta(x_t, \varnothing) + w\,\big(\varepsilon_\theta(x_t, c) - \varepsilon_\theta(x_t, \varnothing)\big). With w = 1 this is the plain conditional model; w > 1 over-guides, giving samples more faithful to the prompt and less diverse. By proposition 9.11, it samples with the score \nabla \log p_t(x) + w\, \nabla \log p_t(c \mid x). This is the site’s convention for the guidance weight (notation page); the original paper writes w' = w - 1.
The toy below trains \varepsilon_\theta on a mixture of eight Gaussians in the plane and samples with algorithm 9.10. It runs on a CPU in under a minute.
import math, torch, torch.nn as nn
torch.manual_seed(0)
def data(m): # 8 Gaussians on a circle of radius 2
k = torch.randint(0, 8, (m,)) * (math.pi / 4)
return 2 * torch.stack([k.cos(), k.sin()], 1) + 0.1 * torch.randn(m, 2)
T = 100
beta = torch.linspace(1e-4, 0.2, T) # beta_1, ..., beta_T (index t - 1)
alpha, abar = 1 - beta, torch.cumprod(1 - beta, 0) # abar_t = alpha_1 ... alpha_t
net = nn.Sequential(nn.Linear(2 + 16, 256), nn.SiLU(), nn.Linear(256, 256), nn.SiLU(),
nn.Linear(256, 2))
def eps_theta(x, t): # the step t enters as sin/cos features
f = t.float().unsqueeze(1) / T * torch.arange(1, 9) * math.pi
return net(torch.cat([x, f.sin(), f.cos()], 1))
opt = torch.optim.Adam(net.parameters(), lr=1e-3)
for step in range(5000): # training: regress the noise
x0, t = data(256), torch.randint(0, T, (256,))
eps = torch.randn_like(x0)
xt = abar[t, None].sqrt() * x0 + (1 - abar[t, None]).sqrt() * eps # prop. 9.8
loss = ((eps - eps_theta(xt, t)) ** 2).mean() # L_simple
opt.zero_grad(); loss.backward(); opt.step()
with torch.no_grad(): # ancestral sampling (algorithm 9.10)
x = torch.randn(2000, 2)
for t in reversed(range(T)):
e = eps_theta(x, torch.full((2000,), t))
x = (x - beta[t] / (1 - abar[t]).sqrt() * e) / alpha[t].sqrt()
if t > 0:
x = x + beta[t].sqrt() * torch.randn_like(x) # sigma_t^2 = beta_t
ang = torch.arange(8) * (math.pi / 4)
dist = torch.cdist(x, 2 * torch.stack([ang.cos(), ang.sin()], 1)).min(1)
print(f"{(dist.values < 0.4).float().mean():.0%} of samples within 0.4 of a mode, "
f"{dist.indices.unique().numel()} modes out of 8") # about 90%, 8 modesNormalizing flows: an exact likelihood A flow is an invertible network g_\theta that maps the data x to a latent z = g_\theta(x) of the same dimension, with z \sim \mathcal{N}(0, I). The change of variables gives the exact log-likelihood: \log p_\theta(x) = \log \mathcal{N}\big(g_\theta(x);\, 0, I\big) + \log \big|\det J_{g_\theta}(x)\big| .
- Affine coupling (RealNVP: Dinh, Sohl-Dickstein & Bengio, 2017). Split x = (x_a, x_b), keep x_a, and transform x_b with scales and shifts computed from x_a: z_a = x_a, \qquad z_b = x_b \odot \exp\big(s(x_a)\big) + t(x_a).
- Cheap determinant, explicit inverse. The Jacobian is triangular, so its log-determinant is the sum of the entries of s(x_a). The inverse is x_b = (z_b - t(z_a)) \odot \exp(-s(z_a)), and the networks s and t can be anything.
- Trade-off. Stacking couplings that alternate the split gives a model trained by plain maximum likelihood, with no bound and no adversary. The price: the latent has the dimension of the data, and invertibility constrains the architecture.
From the VAE decoder to text-to-image. Latent diffusion (Rombach et al., 2022) runs the whole process of this section in the latent space of a pretrained autoencoder trained with a light KL penalty, as in 9.2. A 512 \times 512 \times 3 image becomes a 64 \times 64 \times 4 latent, the denoiser works there, and the decoder maps the final latent back to pixels.
The prompt enters through the cross-attention of 6.4, with keys and values computed by a frozen text encoder (in Stable Diffusion, the public release of latent diffusion, the CLIP text encoder of Radford et al., 2021), and classifier-free guidance sets how strongly it is followed. The families of this chapter thus end up in one pipeline, built in full in the Multimodal Generative AI module.
10. Research at DaSciM (Vazirgiannis, Lutzeyer, Zhu)
This chapter connects the course to the current research of three researchers of the DaSciM group: Michalis Vazirgiannis (responsible of the course on the sheet), Johannes Lutzeyer (in its teaching team) and Ye Zhu (not listed on the 2026–2027 sheet). All three topics are rooted in the previous chapters. The arXiv references are in the bibliography.
10.1. Michalis Vazirgiannis: from the “Graph of Words” to textual GNNs
Worked example — Graph of Words (Rousseau & Vazirgiannis, CIKM 2013) The bag-of-words representation throws away syntactic and order structure; the word graph restores it at almost no cost:
- Construction: each distinct term of the document = one node; a sliding window of size w over the text creates an edge between two terms if they co-occur in the window (weighted by the co-occurrence frequency). The document becomes a small, sparse weighted graph.
- From TF-IDF to TW-IDF: in a bag of words, the weight of a term is its frequency; in a word graph, it is its centrality. TW-IDF weights the term by its in-degree in that document’s own graph-of-words (the unweighted version worked best), with a pivoted normalization by document length, times the usual collection-level IDF. The group then used the k-core decomposition of the word graph for keyword extraction (Rousseau, Kiagias & Vazirgiannis, ECIR 2015). “Ad hoc” retrieval gains over TF-IDF: structurally important words emerge even when they are rare.
- Positioning with respect to the course: this is the first building block of the program — the data itself becomes a graph. The NLP module reuses these representations; the Graph ML module generalizes them.
GNN lineage: texts, expressivity, generation
- One graph per document (MPAD: Nikolentzos, Tixier & Vazirgiannis, AAAI 2020): each document is its own word graph, read by a message-passing network with attention. A new document is processed without rebuilding anything, whereas TextGCN (Yao et al., AAAI 2019) built a single transductive corpus graph. TextING (Zhang et al., ACL 2020) applies the same per-document idea to inductive text classification.
- DGoW-GNN (Abbahaddou, Lutzeyer & Vazirgiannis, NeurIPS 2023): discriminative word graphs — the edges are no longer fixed co-occurrences but are filtered/learned for the task, then a GNN propagates the representations. The loop is closed with chapter 2: the computation graph (backprop) and the data graph (message passing) answer each other.
- PathNN (Michel, Nikolentzos & Vazirgiannis, ICML 2023): going beyond classical message passing by aggregating paths (shortest paths, simple paths) emanating from each node; two variants are strictly more expressive than the Weisfeiler–Lehman test. This is the language of the Graph ML module, expanded in Advanced GNN (M2).
10.2. Johannes Lutzeyer: where are the parameters? Expressivity and position
Sparsifying the update step (Lutzeyer, Wu & Vazirgiannis, 2021) An MPNN (message passing neural network) chains two phases: the aggregation of neighbor messages and an “update step” — precisely the linear transformation + non-linearity of chapter 1, applied node by node. The paper’s question: what remains if one sparsifies this trainable step, initializing it directly sparse (ExpanderGNN, with a tunable sparsity rate) or even reducing it to a non-linearity alone (Activation-Only GNN)?
Key result: performance comparable to dense models with far fewer parameters — a direct empirical insight into how expressivity is distributed between aggregation (structure, not parametrized) and the update (parametrized), in the spirit of ch. 1 (what, in a network, carries the expressivity?).
Positional encodings on graphs (SHAKE-GNN, Cui, Lutzeyer et al., 2025) Chapter 6 showed that a transformer needs a positional encoding because, without positions, self-attention is permutation-equivariant: permuting the tokens only permutes the outputs, so the order is lost (invariance only comes after a symmetric pooling).
On a graph, the problem is deeper: there is no canonical ordering of the nodes — the “position” of a node is a structural notion (Laplacian spectrum, distances, spanning forests). SHAKE-GNN proposes hierarchical encodings based on Kirchhoff forests, computed in a scalable way. The parallel to remember: RoPE (relative absolute position, suited to sequences) vs spectral/structural encodings (position defined by the geometry of the graph); both answer the same fundamental symmetry (exercise 4). The Advanced GNN module (M2) systematizes this question.
10.3. Ye Zhu: steering diffusion models
From the loss to semantic control Section 9.4 gives the loss, the sampler and the guidance of diffusion models; the work of Ye Zhu shows how to steer them further:
- BoundaryDiffusion (Zhu et al., NeurIPS 2023): control the semantics of generation without retraining (learning-free), by warping the decision boundaries of the model’s latent space in the guidance plane — an elegant point of contact with theorem 9.6: where the GAN sought an equilibrium, here already-learned latent regions are moved geometrically.
- Discrete contrastive diffusion (ICLR 2023) and Diffusion in Diffusion (ICLR 2024): discrete cross-modal music-image diffusion and cyclic text-vision conditioning — the argument of the ch. 9 table (“multimodal”) made concrete.
- NoiseQuery (ICCV 2025): the initial noise z_T as an implicit control signal for goal-guided generation — it reverses the perspective: the “noise” becomes a structured input, which connects to the sensitivity to the initial noise studied for GANs/diffusion.
This work directly extends ch. 9 and is expanded in the Multimodal Generative AI module.
Exercises
★ Backprop on paper. Redo example 2.2 by hand (a scalar tanh network). Then write the backward pass of a two-layer ReLU network with the recursion of theorem 2.1, and check it numerically, as in the NumPy code of section 2.1, by central finite differences \frac{\mathcal{L}(\theta + \epsilon e_j) - \mathcal{L}(\theta - \epsilon e_j)}{2\epsilon} on a small network.
★ Activation. Show that if \sigma is linear, an MLP of arbitrary depth represents exactly the affine maps. Deduce why linear cascades are useless.
★ 1D attention by hand. For n = 3 tokens, d_k = 2, compute by hand QK^\top/\sqrt{d_k}, the row-wise softmax, and the result \mathrm{softmax}(\cdot)V. Implement it, compare, and check that the rows of the attention matrix sum to 1.
★ Permutation-equivariance. Take the block of 6.4 with
causal=False, ineval()mode and without positional encoding. Check experimentally that permuting the tokens permutes the output rows in the same way (equivariance), that the mean over the tokens is then invariant, and that adding a positional encoding breaks both properties. The proof is proposition 4.4 of Advanced DL.★ Quadratic SGD. Take A = \mathrm{diag}(4, 1), b = 0, \theta_0 = (1, 1).
Write the sequence (\theta_k) for \eta = 1/2 then \eta = 1, and verify theorem 3.1 (per-mode contraction, bound 2/L).
★ Convolution arithmetic. A 32 \times 32 input, three successive convs (5×5, stride 2, padding 2; 3×3, stride 1, padding 1; 3×3, stride 1, padding 1, dilation 2): intermediate output sizes and final receptive field (proposition 4.4).
★ LoRA. Count the trainable parameters of a GPT-like model with 12 blocks (d = 768, attention + MLP) adapted by LoRA r = 8 on the attention projections only, and compare with full fine-tuning.
★★ He initialization. Recover the factor 2 of He initialization: for h = \mathrm{ReLU}(a) with a symmetric zero-mean, compute \mathbb{E}[h^2] then the variance of the next layer.
★★ Adam bias correction. Prove proposition 3.5 for v_t (second moment), then compute the update \hat m_1/\sqrt{\hat v_1} at the first step and explain why the warmup protects.
★★ Gaussian KL. Derive the formula of proposition 9.4 in dimension 1, plot \mathrm{KL}(\mathcal{N}(\mu, \sigma^2) \| \mathcal{N}(0,1)) as a function of \mu and \sigma, and locate the minimum.
★★ Gaussian GAN. For p_{\mathrm{data}} = \mathcal{N}(0, 1) and p_G = \mathcal{N}(\mu, \sigma^2), write the logit of D^\star (difference of the log-densities) and check that it is a trinomial in x. Where does the equilibrium lie?
★★★ Project. In PyTorch: classify MNIST with (a) an MLP, (b) a small CNN, (c) a mini-transformer on patches (16 patches of 7×7, a 4 × 4 grid, as in the ViT of 6.6). Plot the train/val curves, compare the parameter counts and accuracy, comment with the bias-variance decomposition, then apply the protocol of chapter 8 (overfitting a batch, LR range test). (d) Train the CNN of (b) on the digits 0–4, freeze it, and train a linear classifier on its features for the digits 5–9 (linear probing, section 7.1); compare with the CNN trained from scratch on 5–9.
Solutions (Ex. 2, 3, 5, 6, 11) and hints (the others)
Ex. 1. Take \epsilon \sim 10^{-6} in float64 for the check; the error of the central finite difference is \mathcal{O}(\epsilon^2). In float32, rounding swamps such a small \epsilon (section 2.2).
Ex. 2. By induction: if h^{(\ell)} = \sigma(W^{(\ell)} h^{(\ell-1)} + b^{(\ell)}) with \sigma(t) = \alpha t, then h^{(\ell)} = \alpha W^{(\ell)} h^{(\ell-1)} + \alpha b^{(\ell)} remains affine in h^{(0)} = x — composing, f_\theta(x) = W x + c with W = \prod_\ell \alpha W^{(\ell)}: a single matrix, all the deep layers collapse into one.
Ex. 3. The row-wise softmax makes each row a vector of positive weights of sum 1; the multiplication by V makes each output a weighted average of the values: this is a convex interpolation, exactly the message passing of chapter 6.
Ex. 4. Permute the token dimension,
x[:, perm];x[perm]would permute whole sequences of the batch, a trivial check. Without the mask the property is exact up to rounding: the softmax over the keys is unchanged by re-indexing, and LayerNorm and the MLP act token by token. With the causal mask, token i sees only the tokens j \le i, and the check fails. Dropout must be off.Ex. 5. Decoupled modes: (\theta_k)_1 = (1 - 4\eta)^k, (\theta_k)_2 = (1-\eta)^k.
For \eta = 1/2: factors -1 (oscillation without decay: exactly \eta = 2/L, limiting case) and 1/2.
For \eta = 1: factors -3 (divergence: \eta > 2/L) and 0 (convergence in one step: \eta = 1/\lambda_2).
Ex. 6. Theorem 4.2: 32 \to 16 \to 16 \to 14 (the third one: \lfloor (16 + 2 - 2\cdot 2 - 1)/1 \rfloor + 1 = 14).
Receptive field (proposition 4.4, with dilation: replace (k-1) by d(k-1)): \mathrm{RF}_1 = 5, \mathrm{RF}_2 = 5 + 2 \cdot 2 = 9, \mathrm{RF}_3 = 9 + (2 \cdot 2)\cdot 2 = 17 pixels, for a product of strides \prod s = 2.
Ex. 7. Per block: 4 attention matrices d \times d, i.e. 4 \times 2 \times 8 \times 768 = 49{,}152 LoRA parameters, versus 4 \times 768^2 \approx 2.36 M for full — and the MLP is not adapted; LoRA total ~0.6 M for ~85 M full.
Ex. 8. By symmetry of a, \mathbb{E}[h^2] = \mathbb{E}[a^2 \mathbf{1}_{a>0}] = \tfrac12\mathbb{E}[a^2]: the variance of the next layer is halved, hence \mathrm{Var}(W) = 2/n_{\mathrm{in}}.
Ex. 9. Re-derive the geometric sum with g_k^2 constant; at step 1, \hat m_1 = g_1 and \hat v_1 = g_1^2.
The ratio is \mathrm{sign}(g_1), a step of size \eta whether g_1 is tiny or huge: hence the caution of the warmup when g_1 is atypical.
Ex. 10. The minimum of \tfrac12(\mu^2 + \sigma^2 - 1 - \log\sigma^2) is reached at \mu = 0, \sigma = 1 (derivative with respect to \sigma^2: \tfrac12(1 - 1/\sigma^2) = 0).
Ex. 11. Unique global minimum at (\mu, \sigma) = (0, 1); the logit of D^\star is \frac{x^2}{2}\big(\frac{1}{\sigma^2} - 1\big) - \frac{x\mu}{\sigma^2} + \frac{\mu^2}{2\sigma^2} + \log\sigma: a trinomial in x, identically zero at the equilibrium (\mu, \sigma) = (0, 1).
Projects and assessment
The SynapseS sheet gives the grade format (numeric out of 20, with a US letter grade), but “the section for the LLGA track is empty”: no assessment form, resit rule, pass threshold or ECTS is displayed for LLGA, and no breakdown of assessments is given for any degree. The subjects, the exam and the rubric below are therefore proposals of these notes, for instance half project and half written exam. They exercise objectives O1 (ML and DL foundations), O2 (generative modelling) and O3 (large language models), with O7 (hands-on practice) throughout.
Group projects 1 and 3 are the Deep Learning building blocks of two Year 1 end-of-year projects of the Graph × LLM route: a GraphRAG question-answering system (Y1.1) and the generation of molecules from text (Y1.4).
Solo projects
- [Solo · ≈ 20 h] Backprop from scratch and an initialization study. Does a hand-written backward pass match autograd, and which initializations keep the signal alive through depth?
- Implement: extend the NumPy MLP of 2.1 to any depth and to sigmoid, tanh, ReLU and GELU, and check it against PyTorch autograd and a float64 central-difference checker. Measure activation and gradient variances layer by layer in a 20-layer network for zero, Xavier and He initializations (1.3), and reproduce XOR (example 1.4).
- Data: synthetic Gaussian inputs, XOR, and MNIST (LeCun et al., 1998).
- Deliverables: code with tests, a 4-page report with one variance-versus-depth plot per activation, a 10-minute talk.
- Chapters: ch. 0, 1, 2.
- Success: a relative gradient error below 10^{-7} on every tensor. With width 256 and ReLU, He keeps the activation variance after 20 layers within a factor 2 of the input, while Xavier divides it by about 2^{20} \approx 10^6, as proposition 1.6 predicts.
- [Solo · ≈ 25 h] Paper study: decoupled weight decay (Loshchilov & Hutter, ICLR 2019). Is Adam with an L2 penalty really worse than AdamW, and does the best weight decay depend less on the learning rate once decoupled?
- Warm-up: check theorem 3.1 and proposition 3.3 on quadratics with \kappa \in \{10, 100, 1000\}. The number of iterations to reach an error of 10^{-6} should grow like \kappa for gradient descent and like \sqrt\kappa for tuned momentum.
- Implement: train a ResNet-20 (He et al., 2016) on CIFAR-10 (Krizhevsky, 2009) with Adam + L2 and with AdamW, over a 4 × 4 grid of learning rates and weight decays, with warmup and a cosine schedule (3.4). A 30-epoch run takes a few minutes on a free GPU tier.
- Paper: I. Loshchilov, F. Hutter, Decoupled Weight Decay Regularization, ICLR 2019 (its figures 1 and 2: test error over a grid of learning rates and weight decays).
- Deliverables: code, the two heatmaps, a 5-page report, a 10-minute talk.
- Chapters: ch. 3, 4, 8.
- Success: log-log slopes of 1 and 1/2 on the quadratics, within 10%; heatmaps that reproduce the paper’s finding (a basin less tilted for AdamW), or a report that explains why not.
Group projects
- [Group of 3 · ≈ 30 h each] Mini-GPT: tokenizer, pretraining and LoRA adaptation. What does each ingredient of a small decoder-only transformer buy, and how close does LoRA come to full fine-tuning?
- Implement: a BPE tokenizer (definition 6.3); a pre-norm causal transformer with RoPE (6.2–6.4) of about 10 M parameters, pretrained on TinyStories (Eldan & Li, 2023); ablations of the \sqrt{d_k} scaling and of pre- versus post-norm; then adaptation to SST-2 sentiment classification (Socher et al., 2013) by linear probe, LoRA with r \in \{4, 8, 16\} and full fine-tuning (ch. 7).
- Split: member A builds the tokenizer, the data pipeline and the perplexity evaluation; member B the model, the pretraining and the ablations; member C the adaptation and the attention maps drawn as graphs (6.3).
- Deliverables: a repository, a 6-page report, a 15-minute talk.
- Chapters: ch. 6, 7, 8; it leads to NLP, ch. 7 and Large Language Models, section 4.3.
- Success: a validation perplexity far below that of a unigram model; LoRA with r = 8 within 2 points of full fine-tuning with under 2% of the weights trained, or an explanation of the gap.
- [Group of 3 · ≈ 30 h each] Inductive biases on images: MLP, CNN, ViT and a graph network. How much data does each architecture need, and what does each one build in? This extends exercise 12 and bridges to Graph ML.
- Implement: on CIFAR-10, an MLP, a small ResNet (ch. 4), a ViT with 4 × 4 patches (6.6), and a GNN on SLIC superpixel graphs (Achanta et al., 2012). Train each on 1k, 5k and 50k images with the protocol of ch. 8, with tracked and seeded runs (8.4).
- Paper: the CIFAR10 superpixel benchmark of V. P. Dwivedi et al., Benchmarking Graph Neural Networks, JMLR 2023, whose GNN results the group reproduces for one model.
- Split: member A the MLP and the CNN; member B the ViT; member C the superpixel graphs and the GNN (Graph ML, ch. 5); shared training and logging code.
- Deliverables: a repository, a 6-page report, a 15-minute talk. Chapters: ch. 4, 6, 8, and Graph ML ch. 5.
- Success: a table of parameters, accuracy and data efficiency for the four models over three seeds; the reproduced GNN within the range reported by Dwivedi et al. for its size; a paragraph that explains the ranking at 1k images by the inductive biases of 4.1 and 6.6.
- [Group of 2 · ≈ 25 h each] VAE, GAN and diffusion: theory checks and failure modes. Do the generative families reach their theoretical optimum where it is known, and how do they fail?
- Implement: a linear autoencoder compared with PCA (9.1); a VAE with the reparameterization trick (9.2); a GAN on the eight-Gaussian ring and on MNIST, with the Gaussian check of theorem 9.6 and exercise 11; the diffusion toy of 9.4 on the same ring.
- Split: member A the autoencoders and the VAE (ELBO curves, posterior collapse); member B the GAN and diffusion (mode counts, samples, latent interpolations).
- Data: synthetic rings and MNIST. Deliverables: code, a 5-page report, a 10-minute talk.
- Chapters: ch. 9; it prepares the Multimodal Generative AI module.
- Success: principal angles between the autoencoder subspace and the PCA subspace below 1°; the number of ring modes covered by the GAN and by diffusion over five seeds; a fitted logit of D^\star that matches the trinomial of exercise 11.
Written exam (proposal)
Format: 2 hours, one handwritten A4 sheet allowed, no electronic device; four exercises, 20 points.
Question (5 points). Scaled dot-product attention. (a) Write single-head attention for n tokens of width d and give its cost. (b) If the components of a query and a key are i.i.d., centred, with variance 1, show that their dot product has variance d_k, and say what goes wrong without the factor 1/\sqrt{d_k}. (c) Without positions and without mask, show that self-attention is permutation-equivariant. How does one obtain an invariant output?
Expected:
- (a) The formula of definition 6.1, with time \mathcal{O}(n^2 d) and memory \mathcal{O}(n^2) (1 point).
- (b) The proof of proposition 6.2; without the factor, the softmax saturates into a one-hot vector and its gradient vanishes (2 points).
- (c) For a permutation matrix \Pi, the scores become \Pi QK^\top \Pi^\top, the row softmax commutes with this re-indexing, and the output becomes \Pi times the old one; a mean over the tokens is invariant (2 points).
Question (6 points). Take f(w_1, w_2) = \tfrac12\big(w_2\,\mathrm{ReLU}(w_1 x) - t\big)^2, \qquad x = 2,\ w_1 = 0.5,\ w_2 = -1,\ t = 1. Then: (a) compute the forward values. (b) Compute both partial derivatives by backpropagation. (c) Take one gradient step with \eta = 0.1 and give the new loss. (d) A 3 × 3 convolution from 3 to 16 channels, stride 2, padding 1, reads a 64 × 64 image: give the output size and the number of parameters.
Expected:
- (a) a = w_1 x = 1, h = 1, y = -1, loss 2 (1 point).
- (b) \partial\mathcal{L}/\partial y = y - t = -2, so \partial\mathcal{L}/\partial w_2 = -2 \cdot h = -2 and \partial\mathcal{L}/\partial w_1 = (-2)(-1)(1)(2) = 4 (2 points).
- (c) w_1 = 0.1 and w_2 = -0.8; the new loss is \tfrac12(1.16)^2 = 0.6728 (1.5 points).
- (d) Theorem 4.2 gives \lfloor 63/2 \rfloor + 1 = 32, so a 32 \times 32 output, with 3 \cdot 9 \cdot 16 + 16 = 448 parameters (1.5 points).
Question (5 points). For a fixed generator of density p_G, (a) prove that the discriminator maximizing V(G, D) is D^\star = p_{\mathrm{data}}/(p_{\mathrm{data}} + p_G); (b) deduce V(G, D^\star) = -\log 4 + 2\,\mathrm{JSD}(p_{\mathrm{data}} \,\|\, p_G), and say for which G the minimum is reached.
Expected: (a) pointwise maximization of a \log D + b \log(1 - D), concave, with zero derivative at D = a/(a+b) (2 points). (b) Substitute, introduce the mixture m = \tfrac12(p_{\mathrm{data}} + p_G) and recognize the two KLs toward m (2 points); the JSD is non-negative and vanishes only when p_G = p_{\mathrm{data}} (1 point).
Question (4 points). Gradient descent on f(\theta) = \tfrac12 \theta^\top A \theta with A = \mathrm{diag}(10, 1). (a) For which step sizes does it converge from every start? (b) Give the best constant step and its rate. (c) About how many iterations divide the error by 10^3?
Expected: (a) 0 < \eta < 2/L = 0.2 (1 point). (b) \eta^\star = 2/(L + \mu) = 2/11 \approx 0.18, rate \rho = (\kappa - 1)/(\kappa + 1) = 9/11 \approx 0.82, by theorem 3.1 (2 points). (c) k \ge \ln 1000 / \ln(11/9) \approx 34.4, so 35 iterations (1 point).
Grading rubric (proposal)
| Criterion | Weight | What earns the marks |
|---|---|---|
| Correctness and checks | 25 % | gradient checks and unit tests pass; numbers agree with the results of the chapters used |
| Experimental protocol | 20 % | baselines, several seeds with error bars, the recipe of ch. 8, tracked and reproducible runs |
| Analysis | 25 % | each result is explained by a proposition or theorem of the course; failures are diagnosed, not hidden |
| Report and figures | 15 % | 4–6 pages, plots with axes, units and legends, stated limitations |
| Talk and questions | 15 % | 10–15 minutes; every member can explain every part of the work |
References
Textbooks and courses
- I. Goodfellow, Y. Bengio, A. Courville, Deep Learning, MIT Press, 2016 — free online; chapters 6-8 for this module.
- A. Zhang, Z. Lipton, M. Li, A. Smola, Dive into Deep Learning, 2023 — d2l.ai: code-first interactive course (PyTorch), very close to the labs.
- A. Karpathy, Neural Networks: Zero to Hero — building a GPT from scratch. Its lecture Let’s build GPT: from scratch, in code, spelled out (2023) gives the reading “attention = communication between the nodes of a directed graph” that grounds the LLGA bridge of section 6.3.
- S. Raschka, Machine Learning with PyTorch and Scikit-Learn, Packt, 2022 — for practice.
Founding papers (course chronology)
- F. Rosenblatt, The Perceptron: A Probabilistic Model for Information Storage and Organization in the Brain, Psychological Review 65(6), 1958; A. Novikoff, On Convergence Proofs on Perceptrons, Symposium on the Mathematical Theory of Automata, 1962 — section 1.1.
- P. Baldi, K. Hornik, Neural Networks and Principal Component Analysis: Learning from Examples Without Local Minima, Neural Networks 2(1), 1989 — the linear autoencoder of section 9.1.
- G. Cybenko, Approximation by Superpositions of a Sigmoidal Function, Mathematics of Control, Signals and Systems, 1989 — theorem 1.5; M. Leshno, V. Lin, A. Pinkus, S. Schocken, Multilayer Feedforward Networks with a Nonpolynomial Activation Function Can Approximate Any Function, Neural Networks 6(6), 1993 — the non-polynomial case.
- X. Glorot, Y. Bengio, Understanding the Difficulty of Training Deep Feedforward Neural Networks, AISTATS 2010 — Xavier initialization.
- A. Krizhevsky, I. Sutskever, G. Hinton, ImageNet Classification with Deep CNNs, NeurIPS 2012 (AlexNet); K. Simonyan, A. Zisserman, Very Deep Convolutional Networks (VGG), ICLR 2015.
- D. Kingma, J. Ba, Adam: A Method for Stochastic Optimization, ICLR 2015 — algorithm 3.4, derived step by step.
- K. He et al., Delving Deep into Rectifiers (He init), ICCV 2015; Deep Residual Learning for Image Recognition (ResNet), CVPR 2016.
- S. Ioffe, C. Szegedy, Batch Normalization, ICML 2015; J. Ba, J. Kiros, G. Hinton, Layer Normalization, 2016; S. Santurkar et al., How Does Batch Normalization Help Optimization?, NeurIPS 2018.
- R. Pascanu, T. Mikolov, Y. Bengio, On the Difficulty of Training Recurrent Neural Networks, ICML 2013 — theorem 5.2.
- N. Srivastava et al., Dropout, JMLR 15, 2014; I. Loshchilov, F. Hutter, Decoupled Weight Decay Regularization (AdamW), ICLR 2019.
- D. Hendrycks, K. Gimpel, Gaussian Error Linear Units (GELU), 2016.
- T. Mikolov et al., Distributed Representations of Words and Phrases and their Compositionality (word2vec), NeurIPS 2013; O. Levy, Y. Goldberg, Neural Word Embedding as Implicit Matrix Factorization, NeurIPS 2014 — section 6.5.
- O. Ronneberger, P. Fischer, T. Brox, U-Net: Convolutional Networks for Biomedical Image Segmentation, MICCAI 2015 — section 5.3.
- R. Sennrich, B. Haddow, A. Birch, Neural Machine Translation of Rare Words with Subword Units (BPE), ACL 2016 — section 6.5.
- A. Vaswani et al., Attention Is All You Need, NeurIPS 2017 — the paper to read line by line.
- J. Devlin et al., BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding, NAACL 2019 — masked language modelling, section 6.5.
- J. Su et al., RoFormer: Enhanced Transformer with Rotary Position Embedding, 2021; T. Dao et al., FlashAttention, NeurIPS 2022.
- A. Dosovitskiy et al., An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale (ViT), ICLR 2021 — section 6.6.
- I. Tenney, D. Das, E. Pavlick, BERT Rediscovers the Classical NLP Pipeline, ACL 2019 — section 7.1.
- D. Kingma, M. Welling, Auto-Encoding Variational Bayes, ICLR 2014; I. Goodfellow et al., Generative Adversarial Nets, NeurIPS 2014.
- J. Sohl-Dickstein et al., Deep Unsupervised Learning using Nonequilibrium Thermodynamics, ICML 2015; J. Ho, A. Jain, P. Abbeel, Denoising Diffusion Probabilistic Models, NeurIPS 2020; Y. Song et al., Score-Based Generative Modeling through Stochastic Differential Equations, ICLR 2021; J. Ho, T. Salimans, Classifier-Free Diffusion Guidance, 2022 — section 9.4.
- L. Dinh, J. Sohl-Dickstein, S. Bengio, Density Estimation using Real NVP, ICLR 2017; R. Rombach et al., High-Resolution Image Synthesis with Latent Diffusion Models, CVPR 2022; A. Radford et al., Learning Transferable Visual Models From Natural Language Supervision (CLIP), ICML 2021 — section 9.4.
- E. Hu et al., LoRA: Low-Rank Adaptation of Large Language Models, ICLR 2022; A. Aghajanyan et al., Intrinsic Dimensionality Explains the Effectiveness of Language Model Fine-Tuning, ACL-IJCNLP 2021.
- L. Smith, Cyclical Learning Rates for Training Neural Networks, WACV 2017 (LR range test); T. Chen et al., Training Deep Nets with Sublinear Memory Cost, 2016 (checkpointing).
Research at DaSciM (Vazirgiannis, Lutzeyer, Zhu)
- F. Rousseau, M. Vazirgiannis, Graph-of-Word and TW-IDF: New Approach to Ad Hoc IR, CIKM 2013 — the “Graph of Words” of chapter 10; F. Rousseau, E. Kiagias, M. Vazirgiannis, Main Core Retention on Graph-of-Words for Single-Document Keyword Extraction, ECIR 2015.
- G. Nikolentzos, A. Tixier, M. Vazirgiannis, Message Passing Attention Networks for Document Understanding, AAAI 2020; for comparison, Y. Zhang, X. Yu, Z. Cui, S. Wu, Z. Wen, L. Wang, Every Document Owns Its Structure: Inductive Text Classification via Graph Neural Networks, ACL 2020.
- G. Michel, G. Nikolentzos, M. Vazirgiannis, Path Neural Networks: Expressive and Accurate Graph Neural Networks, ICML 2023.
- J. Lutzeyer, C. Wu, M. Vazirgiannis, Sparsifying the Update Step in Graph Neural Networks, 2021.
- Y. Abbahaddou, J. Lutzeyer, M. Vazirgiannis, Graph Neural Networks on Discriminative Graphs of Words, NeurIPS 2023 (extended version).
- Z. Cui, J. Lutzeyer et al., SHAKE-GNN: Scalable Hierarchical Kirchhoff-Forest Graph Neural Network, 2025.
- Y. Zhu et al., Boundary Guided Learning-Free Semantic Control with Diffusion Models, NeurIPS 2023; Discrete Contrastive Diffusion for Cross-Modal Music and Image Generation, ICLR 2023; Diffusion in Diffusion, ICLR 2024; The Silent Assistant: NoiseQuery as Implicit Guidance, ICCV 2025.