From a single neuron to the transformer
An interactive study companion built on Vanny Khon's lecture notes Language Modeling: A Mathematical Perspective and on his 22-slide lecture Language Modeling (A First Look). Each built chapter runs Introduction → Intuition → Theory → Visualization → Worked example → Code → Practice → Summary.
Your progress
Progress is saved in this browser only.
How to read this site
Blocks tagged From the lesson restate the original notes or lecture slides, keeping their notation and claims. Blocks tagged Tutor addition are extra explanations, examples, code and questions written for this site. Use Beginner / Advanced at the top to switch between plain-language boxes and rigorous extensions. The core lesson content is shown in both modes.
Chapters
Preface
Why these notes exist and how to use them.
- The notes cover deep-learning language models, presented as concisely as possible in mathematical terms, motivating each term along the way.
- The path runs from neural networks up to transformer-based language models, the kind of model used to build ChatGPT, and ends with the author's view on why they work and some open questions.
- Every theory part comes with code, written in PyTorch.
- The notes grew out of a class the author teaches to friends in Cambodia with the goal of improving language models for Khmer, and were revised for an NLP course at the Institute of Technology of Cambodia.
- Recommended order: read the theory part first for the concepts, then the code and implement it yourself.
Prerequisites for the whole course: vectors and matrices (matrix–vector products, transposes), functions and composition, partial derivatives and the gradient (for Chapter 4 onward), basic probability (for Chapters 5–9), and enough Python to read a class definition.
Two ways in. The 22-slide lecture Language Modeling: A First Look is a short tour of the whole idea, from “what is a language model?” to a small trained recurrent network. Chapter 1 starts the detailed path from a single neuron. The lecture's ideas return in Chapters 5–8, and each lesson section links to them.
Artificial Neural Network
How a chain of neurons becomes a function built from matrices, biases and gates, and why the gates are what make depth matter.
What you will learn
- Model one neuron as a weighted sum (a dot product) and a whole layer as a matrix–vector product $X^i = W^iX^{i-1}$.
- Explain why stacking purely linear layers gives nothing new: $W^L\cdots W^1$ is again one matrix.
- Use a gate (activation function) with a threshold (bias) to break that collapse: $X^{i+1}=\sigma(W^{i+1}X^i+b^{i+1})$.
- State the formal definition of an $L$-layer neural network as a composition of affine maps and pointwise non-linearities.
- Compare hard and soft gates (ReLU vs SiLU) and the common activations sigmoid, tanh and softplus.
A signal travelling through neurons
A signal $x$ (say, light entering the eye) flows to a first group of neurons $N_1^1,\dots,N_{k_1}^1$. Each processes what it receives and passes it to a deeper group $N_1^2,\dots,N_{k_2}^2$, and so on until depth $L$, where the last group $N_1^L,\dots,N_{k_L}^L$ produces an output, such as "cat" or "flower".
Neurons do not pass information on continuously. Between neuron A and neuron B there is a synaptic gap, and A only sends to B once it has enough signal: a gate that opens when a condition is met. The lesson's analogy is water seeping through a ceiling: surface tension holds it back until enough has gathered for gravity to pull a drop down.
From weighted sums to the definition
3.1 One neuron is a dot product
The simplest model of neuron $N_{\jc{j}}^i$ adds its inputs. Since connections differ in strength, we use a weighted sum instead of $\sum_k x_{\kc{k}}^{i-1}$: $$x_{\jc{j}}^{i}=\sum_{\kc{k}} w_{\kc{k},\jc{j}}^{i}\,x_{\kc{k}}^{i-1}=(W_{\jc{j}}^{i})^TX^{i-1},$$ where $w_{\kc{k},\jc{j}}^{i}$ is the strength of the connection from neuron $N_{\kc{k}}^{i-1}$ in layer $i-1$ to neuron $N_{\jc{j}}^i$ in layer $i$, $W_{\jc{j}}^{i}=(w_{\kc{1},\jc{j}}^{i},\ldots,w_{\kc{k_{i-1}},\jc{j}}^{i})^T$ is neuron $\jc{j}$'s weight vector and $X^{i-1}=(x_{\kc{1}}^{i-1},\ldots,x_{\kc{k_{i-1}}}^{i-1})^T$ is the output of layer $i-1$.
As in the original, teal indices $\kc{k}$ count neurons in the sending layer $i-1$ and red indices $\jc{j}$ count neurons in the receiving layer $i$. The superscript $i$ is the layer number, not a power.
3.2 A layer is a matrix
Stacking the weight vectors of all $k_i$ neurons of layer $i$ as rows gives the weight matrix $W^{i}=[W_{\jc{1}}^{i},\ldots,W_{\jc{k_i}}^{i}]^T$, and the layer output is $$X^{i}=\begin{bmatrix} (W_{\jc{1}}^{i})^TX^{i-1}\\ \vdots \\ (W_{\jc{k_i}}^{i})^TX^{i-1}\end{bmatrix}=\begin{bmatrix} w_{\kc{1},\jc{1}}^{i} & \cdots & w_{\kc{k_{i-1}},\jc{1}}^{i}\\ \vdots & \ddots & \vdots\\ w_{\kc{1},\jc{k_i}}^{i} & \cdots & w_{\kc{k_{i-1}},\jc{k_i}}^{i}\end{bmatrix}X^{i-1}=W^iX^{i-1}.$$ Starting from the input $X^0$ we get a dynamical system: $X^0=\text{input}$, $X^{i+1}=W^{i+1}X^i$.
3.3 Why purely linear layers collapse
There is a problem. The product of the matrices is another matrix $W$, so $X^L=WX^0$, and the whole process is just one layer with one matrix multiplication. Step through it:
3.4 The gate: ReLU with a threshold
To model the gate we use the rectified linear function $\text{ReLu}:\mathbb{R}\to\mathbb{R}$, $$\text{ReLu}(x)=\begin{cases}x & x>0\\ 0 & x\le 0\end{cases}$$ It lets information through only when it is positive. Neuron $N_{\jc{j}}^i$ gets its own threshold $b_{\jc{j}}^i$ and gate $\text{ReLu}(x-b_{\jc{j}}^i)$ (a self gate). For a whole layer we collect thresholds in the bias vector $b^i=(b_{\jc{1}}^i,\ldots,b_{\jc{k_i}}^i)^T$ and the dynamics become $$\begin{cases} X^0=\text{input}\\ X^{i+1}=\text{ReLu}(W^{i+1}X^i+b^{i+1})\end{cases}$$ with ReLu applied component-wise. The gate is usually called the activation function and written $\sigma$.
A threshold $\theta$ appears as $\text{ReLu}(x-\theta)$, while the layer formula uses $+b$. They agree when $b=-\theta$. A neuron with bias $b=-2$ fires only once its weighted input exceeds $2$. Both conventions appear in the lesson; the formal definition below uses $Wx+b$, as PyTorch does.
3.5 Linear and affine maps
A map $L:\mathbb{R}^n\to\mathbb{R}^m$, $L(x)=Wx$ with $W$ an $m\times n$ matrix, is a linear map. Their collection $\mathcal{L}(\mathbb{R}^n,\mathbb{R}^m)$ can be identified with the $m\times n$ matrices $M_{m\times n}$. The map $A(x)=Wx+b$ is an affine map, generalising the line $y=ax+b$.
A neural network is a function obtained by composing affine maps with non-linear functions. A neural network of $L$ layers is a function $NN:\mathbb{R}^n\to\mathbb{R}^m$, $$NN(x)=Af_L\circ\sigma_{L-1}\circ\cdots\circ Af_2\circ\sigma_1\circ Af_1(x),$$ where each $Af_i:\mathbb{R}^{k_{i-1}}\to\mathbb{R}^{k_i}$ is affine, $Af_i(x)=W^ix+b^i$ with $W^i\in\mathcal{L}(\mathbb{R}^{k_{i-1}},\mathbb{R}^{k_i})$, $b^i\in\mathbb{R}^{k_i}$, $k_0=n$, $k_L=m$, and each $\sigma_i$ is a non-linear function applied pointwise to the output of $Af_i$.
For $f:\mathbb{R}\to\mathbb{R}$ and $v=(v_1,\dots,v_N)$, applying $f$ pointwise means $f(v)=(f(v_1),\dots,f(v_N))$.
3.6 Architecture, hard and soft gates
Picture a network as neurons ordered in layers, connections between them whose strengths are stored in $W^i$, and a threshold (bias) $b^i$ for each neuron. The number of layers, the number of neurons per layer and the choice of activation together form the network's architecture.
$\text{ReLu}(x-b)$ either sends the input forward or does not, with no middle ground: a hard gate. A soft gate is $\text{SiLu}(x-b)=(x-b)\,\text{sigmoid}(x-b)$, where $\text{sigmoid}(x)=e^x/(1+e^x)\in(0,1)$, so the input is let through partly. For large $x$, $\text{sigmoid}(x)\approx1$ and $\text{SiLu}(x)\approx x$; for very negative $x$, $\text{SiLu}(x)\approx 0$; near $0$, SiLu is not simply $0$ as ReLu is. Other common activations are $$\text{sigmoid}(x)=\frac{e^{x}}{1+e^{x}},\qquad \tanh(x)=\frac{e^{x}-e^{-x}}{e^{x}+e^{-x}},\qquad \text{softplus}(x)=\ln(1+e^{x}).$$
- $\text{sigmoid}(x)=\dfrac{1}{1+e^{-x}}$, and $\text{sigmoid}'(x)=\text{sigmoid}(x)\,(1-\text{sigmoid}(x))$.
- $\tanh(x)=2\,\text{sigmoid}(2x)-1$, so tanh is a rescaled, re-centred sigmoid with range $(-1,1)$.
- $\text{softplus}'(x)=\text{sigmoid}(x)$: softplus is a smooth version of ReLu, and $\text{softplus}(x)-\text{ReLu}(x)\le\ln 2$ with equality at $x=0$.
- $\text{SiLu}'(x)=\text{sigmoid}(x)\big(1+x(1-\text{sigmoid}(x))\big)$. SiLu is not monotone: its minimum is about $-0.278$ at $x\approx-1.278$.
- ReLu is not differentiable at $0$; in practice the derivative there is set to $0$.
See the mathematics move
A 2 → 2 → 1 network by hand
Take $L=2$, $\sigma_1=\text{ReLu}$ and $$W^1=\begin{bmatrix}1&-1\\2&1\end{bmatrix},\quad b^1=\begin{bmatrix}0\\-1\end{bmatrix},\quad W^2=\begin{bmatrix}1&1\end{bmatrix},\quad b^2=0.5,\quad x=X^0=\begin{bmatrix}1\\2\end{bmatrix}.$$
The same mathematics in PyTorch
These snippets are tutor additions that mirror this chapter. Nothing runs in this page: there is no Python runtime here. Outputs below are the values you should see, worked out by hand.
import torch
W1 = torch.tensor([[1., -1.], [2., 1.]]) # W^1, shape (2, 2)
b1 = torch.tensor([0., -1.]) # b^1
W2 = torch.tensor([[1., 1.]]) # W^2, shape (1, 2)
b2 = torch.tensor([0.5]) # b^2
x0 = torch.tensor([1., 2.]) # X^0
z1 = W1 @ x0 + b1 # Af_1(x): pre-activation
x1 = torch.relu(z1) # sigma_1, applied pointwise
out = W2 @ x1 + b2 # Af_2: last layer, no activation
print(z1, x1, out)
no_gate = W2 @ z1 + b2 # same network with the gate removed
print(no_gate)
@Matrix product. W1 @ x0 is $W^1X^0$.torch.reluApplies $\text{ReLu}$ to every entry: the "pointwise" of the definition.1., -1.The dots make the entries floats. @ refuses to mix integer and float tensors (it raises a dtype error), so keep every tensor float.
import torch
import torch.nn.functional as F
x = torch.tensor([-2., 0., 2.])
print(torch.relu(x))
print(torch.sigmoid(x))
print(F.silu(x)) # x * sigmoid(x)
print(torch.tanh(x))
print(F.softplus(x)) # ln(1 + e^x)
import torch
import torch.nn as nn
A = nn.Linear(2, 3) # Af_1 : R^2 -> R^3
B = nn.Linear(3, 1) # Af_2 : R^3 -> R^1
x = torch.randn(5, 2) # a batch of 5 inputs
with torch.no_grad():
W = B.weight @ A.weight # W^2 W^1
b = B.weight @ A.bias + B.bias # W^2 b^1 + b^2
print(torch.allclose(B(A(x)), x @ W.T + b))
The last snippet is the collapse argument from §3.3 as a test: two affine layers with nothing in between are one affine layer. Insert torch.relu between A and B and the check will generally print False.
Check your understanding
Key ideas to keep
- Neuron: weighted sum $(W_j^i)^TX^{i-1}$. Layer: matrix product $W^iX^{i-1}$, with $W^i\in\mathbb{R}^{k_i\times k_{i-1}}$.
- Linear layers alone collapse: $W^L\cdots W^1$ is one matrix (affine layers collapse too).
- A gate (activation) with threshold breaks the collapse: $X^{i+1}=\sigma(W^{i+1}X^i+b^{i+1})$.
- Definition: $NN=Af_L\circ\sigma_{L-1}\circ\cdots\circ\sigma_1\circ Af_1$, with $\sigma$ applied pointwise and no activation after $Af_L$.
- Architecture = number of layers + neurons per layer + choice of activation.
- Hard gate ReLu vs soft gate SiLu; also sigmoid, tanh, softplus.
Common mistakes
Exam tips
- When asked for a parameter count, sum $k_ik_{i-1}+k_i$ over layers.
- For "why do we need activations?", give the two-line collapse proof, including biases.
- Always state domain and codomain of each $Af_i$; it shows you understand the shapes.
Coding Neural Networks with PyTorch
Tensors, slicing, nn.Linear as an affine map, and a first network written as a class.
What you will learn
- Import torch and matplotlib.pyplot, create tensors and do pointwise arithmetic.
- Slice a tensor with x[1,:] and x[:,2], remembering Python counts from 0.
- Read nn.Linear(n,m) as the affine map $L(x)=Wx+b$, with $W\in\mathbb{R}^{m\times n}$, acting on batches of shape [batch_size, n].
- Write the two-layer network $N=Af_2\circ\tanh\circ Af_1:\mathbb{R}\to\mathbb{R}^{20}\to\mathbb{R}$ as an nn.Module and plot the function it computes.
Tensors are the vectors and matrices of Chapter 1
The basic objects in PyTorch are tensors: multi-dimensional arrays. Coding is introduced throughout the notes layer by layer, alongside the theory.
In object-oriented programming an object has attributes (its internal state or data) and methods (actions on that state). nn.Linear(n,m) is an object whose attributes include the weight $W$ and bias $b$. Each of them carries more than numbers: it is a pair (value, gradient), which training will use later.
From tensors to nn.Module
3.1 Imports and tensors
To use a package you import it. We need matplotlib.pyplot for plotting and torch for tensors.
import torch
import matplotlib.pyplot as plt
a=torch.tensor([-1,2]) # create a tensor from a list of numbers from package torch
b=torch.tensor([2,-7])Operations are pointwise: a+b adds entrywise, 3*a multiplies each entry, b**2 squares each entry.
3.2 Plotting a function from a tensor
import torch
import matplotlib.pyplot as plt # shorten matplotlib.pyplot to plt
a = torch.linspace(-4, 4, 30) # create a tensor of 30 elements of numbers evenly spaced between -4 and 4
plt.plot(a,a**2-3*a) # plot a^2-3a on a axis
plt.title('graph of a^2-3a')
plt.xlabel('a')
plt.ylabel('a^2-3a')3.3 Slicing
x=torch.rand(2,3) # this create a tensor of 2 by 3 whose elements are random number between 0 and 1
x1=x[1,:] # we define a tensor x1 to be the second row of x
y1=x[:,2]
#Now we can print the above tensors
print(f'x= {x}')
print(f'x1={x1}')
print(f'y1={y1}')
Python counts from 0, so x[1,:] is the second row and x[:,2] the third column: $\texttt{x1}=(x_{21},x_{22},x_{23})$ of shape (3,), $\texttt{y1}=(x_{13},x_{23})$ of shape (2,).
3.4 nn.Linear is an affine map
import torch.nn as nn
L=nn.Linear(2,3) # this create an affine map taking 2 dimensional input and output 3 dimension
W=L.weight
b=L.bias
print(f'Weight W of L: {W}')
print(f'Bias b of L: {b}')
Mathematically, nn.Linear(2,3) creates $L(x)=Wx+b$ with $$W=\begin{bmatrix} w_{11} & w_{12}\\ w_{21} & w_{22}\\ w_{31} & w_{32}\end{bmatrix}\in\mathbb{R}^{3\times 2},\qquad b\in\mathbb{R}^{3},\qquad x\in\mathbb{R}^{2}.$$ Its entries are random. nn.Linear(2,3,bias=False) sets $b=0$. $W$ has 3 rows and 2 columns, the shape PyTorch prints, matching $W^i\in\mathbb{R}^{k_i\times k_{i-1}}$ from Chapter 1. PyTorch itself computes $xW^T+b$ with $x$ written as a row, which gives the same numbers.
During training it is efficient to process several data points at once, a batch. So the natural input of nn.Linear(n,m) has shape [batch_size, input_dim]: a stack $[v_1,\dots,v_k]$, $v_i\in\mathbb{R}^n$, is processed in parallel to give $[L(v_1),\dots,L(v_k)]$.
3.5 A two-layer network as a class
Build $N:\mathbb{R}\to\mathbb{R}$ by composing an affine map $A_1:\mathbb{R}\to\mathbb{R}^{20}$, then $\tanh$, then $A_2:\mathbb{R}^{20}\to\mathbb{R}$.
class NeuralNet(nn.Module):
def __init__(self): # this is the part where we define attribute inside object NeuralNet
super().__init__() # this initializes the base class nn.Module
self.A1=nn.Linear(1,20) # create A1 as an affine map from 1d to 20 dim
self.A2=nn.Linear(20,1)
def forward(self,x): # this is where we assemble all part/attribute of NeuralNet
y=self.A1(x)
y=torch.tanh(y)
y=self.A2(y)
return y
N = NeuralNet() # this create a neural network$$\begin{aligned} N&=Af_2\circ\tanh\circ Af_1:\ \mathbb{R}\to\mathbb{R}^{20}\to\mathbb{R},\\ Af_1(x)&=W^1x+b^1,\qquad W^1\in\mathbb{R}^{20\times 1},\ b^1\in\mathbb{R}^{20},\\ Af_2(h)&=W^2h+b^2,\qquad W^2\in\mathbb{R}^{1\times 20},\ b^2\in\mathbb{R}\end{aligned}$$ self.A1 and self.A2 are $Af_1$ and $Af_2$; torch.tanh is $\sigma$, applied pointwise. Writing N(x) calls the method forward, where the composition is written.
nn.ModuleThe base class for all networks. Inheriting from it makes PyTorch register A1, A2 and their parameters automatically.super().__init__()Runs nn.Module's own setup. Forgetting it gives an error as soon as you assign self.A1.forwardThe composition $Af_2\circ\tanh\circ Af_1$, read top to bottom. You never call forward directly; call N(x).
3.6 Plotting what the network computes
x = torch.linspace(-20, 20, 300) # create domain
with torch.no_grad(): # this code is there to stop pytorch from keeping track of derivative
y = N(x.view(-1,1)) # the 300 points as a stack of shape [300,1], processed at once
#plot the result
plt.figure(figsize=(10,5))
plt.plot(x, y)
plt.show()Training the network comes later, after stochastic gradient descent (Section 4.1–4.2).
Play with tensors and shapes
Everything below is computed by JavaScript that re-implements the same formulas. It is not running PyTorch; the output formatting imitates PyTorch's printing.
Tracing shapes through N(x.view(-1,1))
Extend the lesson code
Tutor additions. Not executed on this page; expected outputs worked out by hand.
import torch
import torch.nn as nn
class NeuralNet(nn.Module):
def __init__(self):
super().__init__()
self.A1 = nn.Linear(1, 20)
self.A2 = nn.Linear(20, 1)
def forward(self, x):
return self.A2(torch.tanh(self.A1(x)))
N = NeuralNet()
for name, p in N.named_parameters():
print(name, tuple(p.shape))
print(sum(p.numel() for p in N.parameters()))
x = torch.linspace(-20, 20, 300).view(-1, 1)
with torch.no_grad():
y = N(x)
print(x.shape, y.shape)
import torch
import torch.nn as nn
L = nn.Linear(2, 3)
V = torch.randn(4, 2) # batch of k=4 vectors in R^2
batch = L(V) # shape [4, 3]
loop = torch.stack([L.weight @ v + L.bias for v in V])
print(batch.shape, torch.allclose(batch, loop))
Check your understanding
Key ideas to keep
- Tensors are multi-dimensional arrays; arithmetic like a+b, 3*a, b**2 is pointwise.
- Indexing starts at 0: x[1,:] is row 2, x[:,2] is column 3.
- nn.Linear(n,m) is $L(x)=Wx+b$ with weight of shape (m,n) and bias of shape (m,); it maps a batch [k,n] to [k,m] via $xW^T+b$.
- A network is an nn.Module: layers are attributes set in __init__, the composition is written in forward, and N(x) calls it.
- torch.no_grad() turns off gradient tracking when you only evaluate.
Common mistakes
Language Modeling: A First Look
Vanny Khon's short lecture for the Department of Applied Mathematics and Statistics at the Institute of Technology of Cambodia, rebuilt as one connected lesson. It starts from “a model turns a sentence into a sentence” and ends with a recurrent network that learns to tell approval from disapproval.
What you will learn, and where every slide goes
- State a language model as a map $M:\mathcal{L}\to\mathcal{L}$ and see why it is hard to build.
- Tell apart words $\Sigma$, all word sequences $\Sigma^*$ and legitimate sentences $\mathcal{L}\subset\Sigma^*$.
- Build $M$ from a next-word map $M_0:\mathcal{L}\to\Sigma$.
- Give a computer numbers to work with: an embedding $E:\Sigma\to\mathbb{R}^d$ for the input and a probability vector in $\mathbb{R}^{|\Sigma|}$ for the output.
- Read a sentence word by word with a recurrent neural network $f:\text{words}\times\text{memory}\to\text{memory}$, and train one on approval vs disapproval.
The lecture is a first pass over ideas that the full notes develop later. This table says where each section meets a chapter of those notes. Chapters 2–10 are still outline pages here, so the links lead to their outlines.
| Slides | Lesson section | Chapter of the full notes | Why they meet |
|---|
Original deck: open the slides ↗. Blocks tagged “From the lesson · slide n” restate that slide; blocks tagged “Tutor addition” are explanations, toy models and code written for this site.
A model that turns a sentence into a sentence
A language model is an object that can turn a sentence into a sentence.
Let $\mathcal{L}$ be the set of sentences. A language model is a map $$M:\mathcal{L}\to\mathcal{L}.$$ But how do we build it?
The definition only fixes the type of $M$: a sentence goes in and a sentence comes out. Many everyday tasks have that shape. A question goes in and an answer comes out, as in slide 2's “Where do you study?”. A sentence in one language goes in and its translation comes out. The start of a text goes in and a continuation comes out. Notice what the definition does not say: it gives no recipe. The rest of the lecture is the recipe.
Words, sequences of words, and real sentences
$\Sigma$ is the set of words. For Khmer, $\Sigma=\{$ឆ្មា, ភ្លៀង, ទន្លេ, ញ៉ាំ, ខៀវ$,\dots\}$. For English, $\Sigma=\{\text{cat},\text{rain},\text{river},\text{eat},\text{blue},\dots\}$.
$\Sigma^*$ is the big region of all word sequences. Inside it sits the dashed region $\mathcal{L}$ of legitimate sentences, so $$\mathcal{L}\subset\Sigma^*.$$ The slide's examples inside $\mathcal{L}$: “the cat eats fish”, “it rains”, “I study NLP” and ឆ្មាស៊ីត្រី. Outside $\mathcal{L}$ but still in $\Sigma^*$: “rain cat blue”, “eat eat the”, “river of study at” and ខៀវភ្លៀងឆ្មា.
$\Sigma^*$ is every finite sequence of words: $\Sigma^*=\bigcup_{n\ge0}\Sigma^n$, where $\Sigma^n$ holds the sequences of exactly $n$ words. If $\Sigma$ has $|\Sigma|$ words then $|\Sigma^n|=|\Sigma|^n$. Being legitimate is a judgement by speakers of the language. There is no formula for “is in $\mathcal{L}$”, which is one reason a language model has to be learned from examples later on.
Building $M$ from a next-word map $M_0$
A language model is a function $$M:\Sigma^*\to\Sigma^*.$$ $M$ can be built from $M_0:\mathcal{L}\to\Sigma$. The diagram starts with $s_0=s$, feeds it into the box $M_0$, and $M_0$ produces an output.
$M_0$ reads a sentence and returns one word. The slide shows only the first step. The usual way to get a whole sentence out is to append the new word and run $M_0$ again: $$s_{k+1}=(s_k,\;M_0(s_k)),\qquad k=0,1,2,\dots$$ and stop when an “end” word appears. This repetition is what Chapter 8 calls an auto-regressive language model. A much smaller problem than “build $M$” remains: predict one next word.
How can a computer hold $M$?
The question: how to represent $M$ in a computer? The answer starts with a better way to represent words: embed words into vectors. Slide 8 sends the words cat, dog, apple and cabbage of $\Sigma$ to points of the plane $\mathbb{R}^2$, with cat and dog near each other and apple and cabbage near each other. The slide's side notes say there are “more words”, and that real embeddings use more than two dimensions (“3 dimensions” and beyond).
A computer can only do arithmetic. Words are not numbers. The cheapest fix is to number them: cat = 1, dog = 2, apple = 3. But then “dog is one more than cat” means nothing, and cat and apple being “two apart” is an accident of the numbering. A vector gives each word a position, and positions have distances. Place similar words close together and arithmetic on positions starts to carry meaning.
The embedding $E:\Sigma\to\mathbb{R}^d$
An embedding $E:\Sigma\to\mathbb{R}^d$ represents a word as a vector. The slide lists real models:
As the slide notes, for BERT, GPT, Llama, Qwen and DeepSeek the “words” $\Sigma$ are pieces of words (tokens). The right-hand column is a tutor addition: the count $|\Sigma|\cdot d$ of numbers an embedding table needs.
For a finite $\Sigma$, $E$ is a table with one row per word: a matrix $\mathbf{E}\in\mathbb{R}^{|\Sigma|\times d}$. Looking a word up means picking its row. Writing $e_w\in\mathbb{R}^{|\Sigma|}$ for the one-hot vector that has a single 1 at position $w$, the lookup is the matrix product $E(w)=e_w^{\,T}\mathbf{E}$. The numbers in the table are parameters: they are learned along with the rest of the model.
Numericalising the output
With embedded input, a language model is a map $M:(\mathbb{R}^d)^*\to\Sigma$. How to numericalise the output?
Draw the output $M(s)$ as a bar over every word. In the slide's example the bars for a, at, cat, I, rain, study, we, you are $0.03,\,0.07,\,0.01,\,0.48,\,0.01,\,0.10,\,0.17,\,0.05$, with the tallest at “I”, and the dots (⋮) stand for the remaining words. Stacking the bars gives a vector, so $$M:(\mathbb{R}^d)^*\to\mathbb{R}^{|\Sigma|}.$$
Entry $i$ of $M(s)$ is the model's confidence that the next word is word $i$ of $\Sigma$. Such a vector has non-negative entries that add up to 1, a probability vector. The eight visible entries add up to $0.92$, so the unseen words share the remaining $0.08$. A network's last layer usually produces unconstrained scores $z_i$, and the standard way to turn scores into probabilities is the softmax: $$p_i=\frac{e^{z_i}}{\sum_j e^{z_j}}.$$ The slides do not show how their bars are produced; softmax is the usual choice and returns in Chapter 6.
Reading with a memory: the recurrent neural network
The section opens with a person asked “What is your favorite food?”, and then shows a long geometry problem (an acute triangle $ABC$ inscribed in a circle $\Gamma$, with points $A_1,B_1,C_1$ and $P$) next to an empty thought bubble.
The lecture's own commentary is not on the slides, so this is an interpretation. A short question like the first is easy to take in at a glance. The geometry problem is too long to hold in your head at once: you read it a word at a time and keep a running understanding of what you have read so far. That running understanding is exactly what a recurrent network calls its memory.
A memory vector $h_0$ with blank entries sits above the sentence “What is your favorite food ?”, and the memory changes as the words are read. An RNN is a function $$f:\text{words}\times\text{memory}\to\text{memory}.$$
Read the words $w_1,\dots,w_n$ one at a time, always with the same $f$: $$h_t=f(w_t,\,h_{t-1}),\qquad t=1,\dots,n.$$ The slide's blank $h_0$ is the starting memory (zeros are the usual choice) and $h_n$ is a vector that summarises the whole sentence. The parameter names on slide 21, $\theta=(A_w,A_h,b,v,c)$, contain the three that make up $f$, so the standard form is $$h_t=\tanh\!\big(A_w\,e(w_t)+A_h\,h_{t-1}+b\big),$$ where $e(w_t)=E(w_t)\in\mathbb{R}^d$ is the embedding from Section 5. Which activation the lecture uses is not visible on the slides; $\tanh$ is the common one.
Example: approval or disapproval
8.1 The pipeline (slides 18–19)
Feed “the food was not bad” word by word through a chain of RNN boxes. The last memory $h_n$ goes into $v\cdot h_n+c$ to give a number $z$, and $\sigma$ turns $z$ into $p$: $$z=v_1h_{n,1}+v_2h_{n,2}+\cdots+v_hh_{n,h}+c=v\cdot h_n+c,\qquad p=\sigma(z).$$ Here $v_i$ says how much part $i$ of the memory counts toward approval.
The function $\sigma(z)=1/(1+e^{-z})$ squeezes any real number into $(0,1)$, so $p$ can be read as a probability of approval. A common decision rule is: approval if $p\ge\tfrac12$, i.e. if $z\ge0$. Since $z=v\cdot h_n+c$ is linear in the memory, the whole classifier is one RNN followed by one weighted vote.
8.2 Do the word vectors know about approval? (slide 20)
The slide plots word vectors in a plane (PC1 against PC2, with a 2D/3D switch). Blue words appear mostly in approvals, orange words mostly in disapprovals, black words in both. Words such as “delicious”, “tasty” and “enjoy” sit on one side, “terrible”, “bad” and “worse” on the other.
8.3 Parameters and loss (slide 21)
The model has parameters $\theta=(A_w,A_h,b,v,c)$, and $M_\theta(s)=p$, the probability that the sentence $s$ is an approval.
With embedding size $d$ and memory size $h$: $A_w\in\mathbb{R}^{h\times d}$ has $hd$ entries, $A_h\in\mathbb{R}^{h\times h}$ has $h^2$, and $b$, $v$ have $h$ each, plus the single number $c$: $$\#\theta=hd+h^2+2h+1.$$ The slide stops at defining $\theta$ and $M_\theta$. For a probability output the natural loss on labelled sentences $(s_k,y_k)$, with $y_k=1$ for approval, is the binary cross-entropy of Chapter 6: $$\mathcal{J}(\theta)=-\frac1N\sum_{k=1}^{N}\Big[y_k\ln M_\theta(s_k)+(1-y_k)\ln\big(1-M_\theta(s_k)\big)\Big].$$ Training lowers $\mathcal{J}$ by gradient descent (Chapter 4).
8.4 Train it (slide 22)
The demo uses 865 sentences, 692 to train and 173 to test. Each has a label $y_k$ (0 for disapproval, 1 for approval); the slide's rows include “the city is not clean” (0), “the library is quiet and comfortable” (1), “not a good meal at all” (0) and “the slides look nice” (1). Before training, test accuracy is 51%. You choose the memory size $h\in\{1,2,4,12\}$ and train. For “the food was not bad” the untrained model gives $p=\sigma(-0.10)=0.48$, so it says “disapproval”.
The lecture's pieces in PyTorch
These snippets are tutor additions that mirror Sections 5, 6 and 8. Nothing runs in this page: there is no Python runtime here. The outputs shown are the values and shapes the code is expected to give, worked out by hand.
import torch
import torch.nn as nn
vocab = ["cat", "dog", "apple", "rain"] # a toy Sigma
idx = {w: i for i, w in enumerate(vocab)}
E = nn.Embedding(num_embeddings=len(vocab), embedding_dim=3) # E : Sigma -> R^3
ids = torch.tensor([idx["cat"], idx["rain"]])
print(E(ids).shape) # one row per word looked up
print(E.weight.shape) # the table itself, |Sigma| x d
z = torch.tensor([2.0, 1.0, 0.0]) # scores for three words
p = torch.softmax(z, dim=0)
print(p)
print(torch.allclose(p.sum(), torch.tensor(1.0)))
class ApprovalRNN(nn.Module):
def __init__(self, d, h):
super().__init__()
self.h = h
self.Aw = nn.Linear(d, h, bias=False) # A_w
self.Ah = nn.Linear(h, h) # A_h (and the bias b)
self.v = nn.Linear(h, 1) # v and c
def forward(self, X): # X: [batch, n, d] embedded words
m = torch.zeros(X.shape[0], self.h) # h_0 = 0
for t in range(X.shape[1]): # read one word at a time
m = torch.tanh(self.Aw(X[:, t]) + self.Ah(m)) # h_t = f(w_t, h_{t-1})
return torch.sigmoid(self.v(m)).squeeze(-1) # p = sigma(v . h_n + c)
model = ApprovalRNN(d=3, h=4)
X = torch.randn(5, 6, 3) # 5 sentences, 6 words, d = 3
print(model(X).shape)
print(sum(q.numel() for q in model.parameters()))
y = torch.tensor([1., 0., 1., 0., 1.]) # labels: 1 = approval
loss_fn = nn.BCELoss()
opt = torch.optim.Adam(model.parameters(), lr=0.05)
for epoch in range(30):
opt.zero_grad()
loss = loss_fn(model(X), y)
loss.backward() # back-propagation through time
opt.step()
Parameter count check: $A_w$ has $4\cdot3=12$ numbers, $A_h$ has $4\cdot4+4=20$ (matrix and bias), and $v,c$ add $4+1=5$, total $37=hd+h^2+2h+1$. PyTorch's own nn.RNN keeps two bias vectors, whose sum plays the role of the single $b$ here.
Check your understanding
Key ideas to keep
- Slides 2–3. A language model turns a sentence into a sentence: $M:\mathcal{L}\to\mathcal{L}$.
- Slides 4–5. $\Sigma$ = words, $\Sigma^*$ = all word sequences, $\mathcal{L}\subset\Sigma^*$ = legitimate sentences.
- Slide 6. $M:\Sigma^*\to\Sigma^*$ can be built from a next-word map $M_0:\mathcal{L}\to\Sigma$ by repeating it.
- Slides 7–9. To compute, embed words as vectors: $E:\Sigma\to\mathbb{R}^d$, a table of $|\Sigma|\cdot d$ learned numbers.
- Slides 10–12. The output is a vector of next-word probabilities: $M:(\mathbb{R}^d)^*\to\mathbb{R}^{|\Sigma|}$.
- Slides 13–17. An RNN reads word by word with a memory: $f:\text{words}\times\text{memory}\to\text{memory}$.
- Slides 18–22. For approval vs disapproval, $z=v\cdot h_n+c$, $p=\sigma(z)$, with parameters $\theta=(A_w,A_h,b,v,c)$ trained on labelled sentences and judged on held-out ones.
Common mistakes
Where to go next
Each step of this lesson is developed properly in the full notes:
Learning by gradients
Homework 2 trained a network by searching (one coordinate at a time, or random directions). Lecture 2 trains its RNN with Adam, back-propagation and cross-entropy. This lesson explains that missing step, in the order you need it.
From searching to sliding downhill
The notes cover this material in Chapter 4 (Gradient Descent), 4.1 (Stochastic Gradient Descent) and 6 (Cross-Entropy), which are only outlines on this site. No new course file was needed: everything here is standard mathematics, written to connect what you have already done (Homework 2) with what Lecture 2 uses.
| You know (Homework 2) | Here you add | Used in |
|---|---|---|
| loss $L(P)\ge0$ measures error | its gradient $\nabla L(P)$ says which way is uphill | every training step |
| step $P+\eta v$ in a random direction $v$ | step $P-\eta\nabla L(P)$: the best local direction | Lecture 2 (Adam) |
| learning rate: small = slow, large = jumpy | the same, now exactly predictable | Lecture 2, lr 0.01 |
| squared ($L^2$) loss | cross-entropy for probabilities, softmax for many classes | Lecture 2 §6, §8 |
The gradient points uphill
For one parameter, the derivative $L'(w)$ is the slope: if $L'(w)>0$, increasing $w$ increases the loss. For $K$ parameters the gradient collects all the slopes:
$$\nabla L(P)=\Big(\frac{\partial L}{\partial p_1},\dots,\frac{\partial L}{\partial p_K}\Big)\in\mathbb{R}^K$$It points in the direction where $L$ grows fastest, so $-\nabla L(P)$ is the steepest way down. Coordinate descent (Homework 2 Q7) moved along one axis at a time; the gradient uses all $K$ slopes at once.
Numerical check: $\dfrac{\partial L}{\partial p_k}\approx\dfrac{L(P+he_k)-L(P-he_k)}{2h}$ with a tiny $h$. Slow, but a perfect test for a hand-derived gradient (used in the scripts below).
Gradient descent and the learning rate
Example: $L(w)=(w-3)^2$, $L'(w)=2(w-3)$, start at $w=0$.
| $\eta$ | $w_1,\dots,w_6$ | behaviour |
|---|---|---|
| 0.1 | 0.6, 1.08, 1.464, 1.771, 2.017, 2.214 | slow but steady (each step closes 20% of the gap) |
| 0.5 | 3, 3, 3, … | exact in one step (lucky for this parabola) |
| 0.9 | 5.4, 1.08, 4.536, 1.771, 3.983, 2.214 | jumps across the valley, slowly settles |
| 1.1 | 6.6, −1.32, 8.184, −3.221, 10.465, −5.958 | too big: diverges |
Here $w_{t+1}-3=(1-2\eta)(w_t-3)$: the gap is multiplied by $1-2\eta$ each step, so it shrinks only if $|1-2\eta|<1$, i.e. $0<\eta<1$. That is the exact version of Homework 2 Q9: small $\eta$ is slow, large $\eta$ jumps and may never settle.
Back-propagation = the chain rule, layer by layer
The Homework 2 network on one data point $(x,y)=(1.5,\,1)$ with $P=(w_1,b_1,w_2,b_2,v_1,v_2,c)=(1,0,-1,0.5,2,1,-0.5)$:
- Forward: $z_1=w_1x+b_1=1.5$, $z_2=w_2x+b_2=-1$; $a_1=\mathrm{ReLU}(z_1)=1.5$, $a_2=0$; $NN=v_1a_1+v_2a_2+c=2.5$; loss $(y-NN)^2=2.25$.
- Backward, last layer first: $\frac{\partial L}{\partial NN}=-2(y-NN)=3$. Then $\frac{\partial L}{\partial c}=3$, $\frac{\partial L}{\partial v_1}=3a_1=4.5$, $\frac{\partial L}{\partial v_2}=3a_2=0$.
- Through the gate: $\frac{\partial L}{\partial z_1}=3\cdot v_1\cdot\mathrm{ReLU}'(z_1)=3\cdot2\cdot1=6$, so $\frac{\partial L}{\partial w_1}=6x=9$, $\frac{\partial L}{\partial b_1}=6$. Neuron 2 is switched off ($z_2<0$, $\mathrm{ReLU}'=0$): $\frac{\partial L}{\partial w_2}=\frac{\partial L}{\partial b_2}=0$.
- Check: the numerical gradient gives exactly the same 7 numbers. One step with $\eta=0.05$ lowers the loss from 2.25 to 0.516.
Back-propagation reuses each intermediate derivative once, so the whole gradient costs about as much as one extra forward pass, even with millions of parameters. A closed gate passes no gradient: a neuron that is off for every data point never learns (a “dead ReLU”).
Probabilities need cross-entropy
For a yes/no answer the model outputs $p=\sigma(s)=1/(1+e^{-s})$ and is scored with $L=-[y\log p+(1-y)\log(1-p)]$ (Lecture 2 §6). Using $\sigma'(s)=p(1-p)$, the gradient becomes remarkably simple:
$$\frac{\partial L}{\partial s}=p-y$$Compare squared error on $p$, whose gradient is $2(p-y)\,p(1-p)$:
| $s$ | $p$ | $y$ | cross-entropy $\partial L/\partial s$ | squared error $\partial L/\partial s$ |
|---|---|---|---|---|
| −4.6 | 0.010 | 1 | −0.990 | −0.0195 |
| −1.9 | 0.130 | 1 | −0.870 | −0.197 |
| 0 | 0.500 | 1 | −0.500 | −0.250 |
| 1.9 | 0.870 | 1 | −0.130 | −0.0295 |
When the model is confidently wrong ($p=0.01$ for an approval), cross-entropy pushes hard (−0.99) while squared error barely moves (−0.02): that is why classifiers are trained with cross-entropy. The second row is Lecture 2's coffee sentence if its label were approval.
Many classes: softmax
A language model chooses among all words (First Look §6) or all 73 Khmer characters (Lecture 2 §8). Scores $z_c$ become probabilities and the loss is the minus log of the correct one:
$$p_c=\frac{e^{z_c}}{\sum_{c'}e^{z_{c'}}},\qquad L=-\log p_y,\qquad \frac{\partial L}{\partial z_c}=p_c-[c=y]$$Example: $z=(2,\,1,\,0.1)$ and the correct class is the first one → $p=(0.659,\,0.242,\,0.099)$, $L=0.417$, gradient $(-0.341,\,0.242,\,0.099)$: raise the correct score, lower the others in proportion to how likely they looked. With two classes this is exactly the sigmoid case.
Mini-batches and Adam
- Stochastic gradient descent: the loss is an average over $N$ examples; instead of the full gradient, use the average gradient of a small random batch (Lecture 2: 16 sentences). Noisier but far cheaper; one pass over all data is an epoch.
- Adam (what Lecture 2 uses, lr 0.01): keeps a running mean $m$ of recent gradients (momentum, $\beta_1=0.9$) and of their squares $v$ ($\beta_2=0.999$), and steps $-\eta\,\hat m/(\sqrt{\hat v}+\varepsilon)$. Each parameter gets its own step size, similar in spirit to Homework 2's adaptive learning rate.
Back-propagation through time (for RNNs)
An RNN uses the same $A_w, A_h, b$ at every word. Unroll it over the sentence ($h_1\to h_2\to\dots\to h_n$) and it is just a deep network with shared weights; back-propagate from the loss at the end back to the first word, and add up the gradient contributions of every time step for each shared weight.
Going back $k$ words multiplies by $A_h$ (and gate derivatives) $k$ times. In one dimension: $0.5^{20}\approx10^{-6}$ (the signal vanishes: early words cannot be learned), $1.5^{20}\approx3300$ (it explodes). Lecture 2's code therefore limits (clips) the gradient. LSTM and attention (Chapter 9, Transformer) were invented to fix this.
Check your understanding
Key ideas to keep
- $\nabla L(P)$ points uphill; gradient descent steps $P\leftarrow P-\eta\nabla L(P)$. The step size $\eta$ must be small enough to converge.
- Back-propagation computes the whole gradient with the chain rule from the output back; a closed ReLU gate passes no gradient.
- Sigmoid + cross-entropy gives $\partial L/\partial s=p-y$; softmax + cross-entropy gives $p_c-[c=y]$. Both push hardest when the model is confidently wrong.
- In practice: mini-batches (SGD) and Adam. For RNNs, back-propagation through time, with vanishing / exploding gradients and clipping.
- Next: Lecture 2 uses every one of these ideas.
Recurrent Neural Network
Vanny Khon's second lecture (Department of Applied Mathematics and Statistics, ITC). It rebuilds the RNN from one question, “what does the memory $h_n$ store?”, trains it on 865 sentences labelled approval / disapproval, and ends with a character-level language model trained on Khmer tales.
Where every slide goes
| Slides | Deck section | Here |
|---|---|---|
| 1–2 | Title · 1. Approval or disapproval | 1 · The task |
| 3–4 | 2. Recurrent Neural Network (reading word by word) | 2 · Reading with a memory |
| 5 | 3. Word embedding (EmbeddingGemma) | 3 · Words as vectors |
| 6–13 | 4. What is a concept? (features, gate, keys, the RNN equation) | 4 · What the memory stores + toy RNN lab |
| 14 | 5. Classifying a sentence | 5 · From memory to a decision |
| 15–19 | 6. Training (parameters θ, data, cross-entropy) | 6 · Training |
| 20–21 | 7. Example (training live, what each feature looks for) | 7 · The trained example |
| 22–26 | 8. Language model (Khmer characters) | 8 · A character language model |
Original deck: open the slides ↗ (needs your Google sign-in). Blocks tagged “From the lesson” restate the slides; “Tutor addition” blocks are explanations and checks written for this site. The interactive slides (training live, 2-D/3-D embedding views, the PyTorch model) only run in the original deck.
Approval or disapproval?
Given a sentence, is it an approval or a disapproval? A model reads the sentence and answers:
| sentence | model answer |
|---|---|
| I enjoy the coffee in the morning | approval |
| the food was bad and cold | disapproval |
| I do not dislike my job | approval |
The third sentence is the hard one: it contains the “bad” word dislike, yet it is an approval because of not. Counting good and bad words is not enough; the model has to remember what came before each word. That is exactly what the recurrent memory $h_n$ is for.
Reading with a memory
Slide 3 reads “What is your favorite food?” one word at a time. Slide 4 shows a long olympiad geometry statement (“Let $ABC$ be an acute triangle inscribed in a circle $\Gamma$ … Point $P$ makes $AB_1PC_1$ convex with the same area as $ABC$”): by the last sentence you must still remember $A_1$, $B_1$, $C_1$ from the beginning.
We read the same way: one word at a time, keeping a running summary. An RNN does the same with a vector: after word $n$ it holds $h_n\in\mathbb{R}^h$, a summary of everything read so far, and it updates the summary with each new word: $h_n=f(x_n,h_{n-1})$, $h_0=0$. The same function $f$ (the same weights) is used at every word, so a sentence of any length can be read.
Words as vectors
We use $E=$ EmbeddingGemma (Google, 2025), $E:\Sigma\to\mathbb{R}^{768}$. The slide shows the words of the data set projected to 2-D and 3-D.
In the deck's trained example the 768 numbers of each word are reduced to 48 by principal components (PCA), and this embedding is kept fixed: only $A_w, A_h, b, v, c$ are trained. Words with similar meaning land close together, so a feature vector $a_i$ that points toward “good” also responds to “enjoy” and “love”.
What does the memory store?
$h_n$ = the information in the sentence up to word $n$. It looks for features: feature 1 = a good word (good, enjoy, love, clean, …), feature 2 = a bad word (bad, boring, dirty, cold, …).
- Feature $i$ has a sample vector $a_i$, and $a_i\cdot x$ is big $\iff$ word $x$ looks like $a_i$.
- Combine the new word with what was read before, then pass it through a gate: $h_n=\mathrm{ReLU}(z_n+b)$ with $\mathrm{ReLU}(t)=\max(0,t)$. ReLU together with $b$ = gate.
- Toy model (slide 9): $z_{n,i}=a_i\cdot x_n+u_i\cdot h_{n-1}$, $h_n=\mathrm{ReLU}(z_n-1)$, $h_0=(0,0)$, $u_1=(1,0)$, $u_2=(0,1)$.
- In general there are $h$ features $a_1,\dots,a_h\in\mathbb{R}^d$ (a good word, a bad word, a negation, …). Stack them as rows of $A_w\in\mathbb{R}^{h\times d}$; then $A_wx_n=(a_1\cdot x_n,\dots,a_h\cdot x_n)$.
$A_h$ = how the previous information interacts with the new information. We call this equation a recurrent neural network. Each $a_i$ is a key; the same neurons read every word.
With $b_i=-1$ a feature only “switches on” when $z_{n,i}>1$: weak evidence is ignored. Because $u_i\cdot h_{n-1}=h_{n-1,i}$ in the toy model, each feature also carries its own past forward, minus 1 per word. So a memory slowly leaks: a strong “bad” signal survives a couple of neutral words, then fades. That is both a feature (old, weak evidence is forgotten) and a weakness (long sentences lose early information), which later lectures fix with LSTM / attention.
Run the toy RNN word by word
The deck's own toy numbers: words in $\mathbb{R}^2$, $a_1$ at 25°, $a_2$ at 115° (unit vectors), $A_h=I$, $b=(-1,-1)$, $v=(1,-1)$, $c=0$. Pick a sentence and step through it.
For the coffee was good but cold the exact values are $h_6=(0.72,\,2.57)$, $s=v\cdot h_6+c=-1.85$, $p=\sigma(-1.85)=0.136$ → disapproval. The slide shows the same numbers rounded: $h_6=(0.7,\,2.6)$, $s=-1.9$, $p=0.13$. Swap the order to …cold but good and the answer flips to approval ($p=0.98$): the “bad” memory leaks away before the end (see the gate note above). Script: RNN_ex1.py · output.
From memory to a decision
Add the concepts together to get a score, then turn the score into a probability:
$$s=v_1h_{n,1}+\dots+v_hh_{n,h}+c=v\cdot h_n+c,\qquad p=\sigma(s)=\frac{1}{1+e^{-s}}$$$v_i$ = how much concept $i$ counts toward approval. the coffee was good but cold: $h_6=(0.7,\,2.6)$, $v=(1,-1)$, $c=0$ → $s=-1.9$, $p=0.13$ → disapproval.
$\sigma$ squeezes any score into $(0,1)$: $s=0$ gives $p=0.5$ (undecided), large positive $s$ gives $p\to1$. The sign of $v_i$ says whether a feature votes for approval ($v_1=1$ for “good”) or against it ($v_2=-1$ for “bad”). Compare the First Look example: the food was not bad, $h_n=(0.9,-0.2)$, $v=(2,1)$ → $z=1.6$, $p=0.83$.
Training: what θ should be
To solve the problem we need the parameters $\theta=\{A_w,\,A_h,\,b,\,v,\,c\}$ with $A_w=(a_1;\dots;a_h)$, $A_h=(u_{ij})$, $b=(b_1,\dots,b_h)$, $v=(v_1,\dots,v_h)$. We want $\theta$ to predict as a human would; human judgement comes from experience, and this experience is the data $(s_1,y_1),\dots,(s_N,y_N)$ with $y_k=1$ approval, $0$ disapproval. With $M_\theta(s)$ = probability that $s$ is an approval:
$$\mathrm{loss}(\theta)=-\frac1N\sum_{k=1}^{N}\Big[y_k\log M_\theta(s_k)+(1-y_k)\log\big(1-M_\theta(s_k)\big)\Big]$$For one sentence with $p=M_\theta(s)$: if $y=1$ the term is $-\log p$, very large when the model disagrees ($p\to0$) and close to 0 when it agrees ($p\to1$); if $y=0$ the term is $-\log(1-p)$, the mirror image. We want $\theta$ that makes the loss small.
| $p$ | loss if $y=1$ | loss if $y=0$ |
|---|---|---|
| 0.99 | 0.010 | 4.605 |
| 0.90 | 0.105 | 2.303 |
| 0.70 | 0.357 | 1.204 |
| 0.50 | 0.693 | 0.693 |
| 0.10 | 2.303 | 0.105 |
| 0.01 | 4.605 | 0.010 |
Always answering $p=0.5$ gives loss $\log 2\approx0.693$: a trained model must beat that. A confident mistake ($p=0.01$ for an approval) costs 4.6, almost 500 times a confident correct answer: cross-entropy punishes overconfidence hard. This is the same loss as Chapter 6 of the notes (cross-entropy for classification). Script: RNN_ex2.py · output.
The trained example
Slide 20 trains the RNN live (choose $h=1,2,4$ or $12$ features) and shows, for test sentences, $M_\theta(s)$ for approvals and $1-M_\theta(s)$ for disapprovals, plus the features $h_n$. Slide 21 asks “what does $a_i$ look for?”: a table where each cell is $a_i\cdot x_n$, with the words of largest and smallest $a_i\cdot x$.
| Data | 865 short English sentences labelled 1 / 0 (e.g. “the app never crashes” 1, “I do not dislike my job” 1, “not worth the price” 0); the first 20% (173) are the test set, 692 train. |
|---|---|
| Words | EmbeddingGemma 768 → 48 numbers by PCA, fixed. |
| Model | $h=12$ features: $A_w$ 12×48, $A_h$ 12×12, $b,v\in\mathbb{R}^{12}$, $c$ → 745 trained numbers (52 for $h=1$, 105 for $h=2$, 217 for $h=4$). |
| Training | Adam, learning rate 0.01, batches of 16, 30 passes over the training set, loss = the cross-entropy above. |
Accuracy depends on the run and is shown live in the deck; it was not re-run here.
A character language model for Khmer
A language model is a function $M:\Sigma^*\to\mathbb{R}^{|\Sigma|}$ with $\sum_{c\in\Sigma}M(c_1\dots c_n)_c=1$. We use an RNN $M_\theta$ to approximate $M$. Text: $c_{n+1}\sim M_\theta(c_1\dots c_n)$, then $c_{n+2}$, … Training: make $-\frac1N\sum_t\log M_\theta(c_1\dots c_t)_{c_{t+1}}$ small.
$\Sigma$ = the Khmer characters, $x_n=E(c_n)\in\mathbb{R}^d$ with $E$ learned, and
$$h_n=\sigma(A_wx_n+A_hh_{n-1}+b)\in\mathbb{R}^h,\qquad y_n=Vh_n\in\mathbb{R}^k,\qquad p(c)=\frac{e^{u_c\cdot y_n+b_c}}{\sum_{c'\in\Sigma}e^{u_{c'}\cdot y_n+b_{c'}}}$$Data: six Khmer tales from Wikipedia. A chunk of $n+1$ characters gives $n$ data points (each prefix predicts the next character); slides show $n=16,32,64$ and train in the browser or load a PyTorch model.
- $|\Sigma|=73$ characters (space, consonants, independent vowels, dependent vowels, signs, ។ ៖ ៗ). Guessing uniformly costs $\ln 73\approx4.29$ per character.
- After 400 passes (PyTorch): loss 1.948 with $d=2$ and 1.417 with $d=16$. As perplexity $e^{\text{loss}}$: about 7.0 and 4.1, i.e. the model is as unsure as choosing among ~7 or ~4 equally likely characters instead of 73.
- The deck's code uses $\sigma=\tanh$ by default (ReLU, SiLU, sigmoid selectable), Adam, back-propagation through time, and clips the gradient because ReLU can blow up through the recurrence.
- Same equation as the classifier; only the head changes: instead of one score $v\cdot h_n+c$, a softmax over all 73 characters, and a prediction after every character instead of only at the end.
Sources of the data in the deck: Khmer Wikipedia tales (CC BY-SA). The six titles include រឿងភ្នំនាងកង្រី and រឿងខ្លា ស្វា និងទន្សាយ.
Check your understanding
Key ideas to keep
- An RNN reads word by word and keeps a memory $h_n=\mathrm{ReLU}(A_wx_n+A_hh_{n-1}+b)$, $h_0=0$, with the same weights at every word.
- Row $a_i$ of $A_w$ is a feature (a key): $a_i\cdot x_n$ is large when word $x_n$ looks like it. $A_h$ mixes in the past; ReLU with $b$ is a gate.
- Decision: $s=v\cdot h_n+c$, $p=\sigma(s)$. Training: find $\theta=(A_w,A_h,b,v,c)$ minimising the cross-entropy over labelled data.
- The same machinery with a softmax head over characters is a language model; on Khmer tales the loss falls from $\ln73\approx4.29$ (guessing) to 1.42.
- Weakness to remember: the toy gate makes old information leak away, so word order and distance matter.
Neural Networks and Embedding
Read a network, build one from its architecture and count its parameters, then see the whole network as a point $P\in\mathbb{R}^K$ that becomes a continuous function $NN_P$.
1 · Parts of a network (Q1–Q3)
The signal flows left to right: input layer → hidden layers → output layer. The example network maps $\mathbb{R}^2\to\mathbb{R}$ ($n=2$, $m=1$) with 3 hidden layers, counted as layers 0 to 4 (layer 0 is the input), so it has 4 layers in the course's counting.
Weight notation: $w^{i}_{k,j}$ is the connection from neuron $N^{i-1}_k$ (layer $i-1$) to neuron $N^{i}_j$ (layer $i$). So $w^{3}_{2,3}$ is the line from the 2nd neuron of layer 2 to the 3rd neuron of layer 3.
Q1–Q3 · reading a network diagram
Follow the signal from left to right: input → hidden layers → output.
Why: every layer only receives from the layer before it (feed-forward).
Read the sizes: 2 inputs, 3 hidden layers, 1 output, so $NN:\mathbb{R}^2\to\mathbb{R}$, layers 0–4.
Why: the input layer does no computation, so it has no weights.
Locate $w^{3}_{2,3}$: it enters layer 3, from neuron 2 of layer 2 to neuron 3 of layer 3.
Why: knowing the index order avoids the classic row/column swap.
2 · Building a network and counting parameters (Q4–Q9)
A network with layer sizes $s_0,s_1,\dots,s_L$ is a composition of affine maps and activations, e.g. $NN = Af_3\circ\sigma_2\circ Af_2\circ\sigma_1\circ Af_1$ with $Af_i(x)=W^i x+b^i$.
$$W^i\in\mathbb{R}^{s_i\times s_{i-1}},\qquad b^i\in\mathbb{R}^{s_i},\qquad \#Af_i = s_i\,s_{i-1}+s_i$$| Q | Question | Answer | Why |
|---|---|---|---|
| 4 | Build $2\to(3,5,3)\to1$ | sizes 2-3-5-3-1 | input 2, three hidden layers, output 1 |
| 5 | $Af_1:\mathbb{R}^4\to\mathbb{R}^2$, $Af_2:\mathbb{R}^2\to\mathbb{R}^2$, $Af_3:\mathbb{R}^2\to\mathbb{R}^3$ | sizes 4-2-2-3 | read the dimensions in order |
| 6 | Shape of $W^2$ | 5 × 3 | maps 3 neurons to 5: rows = output size |
| 7 | Parameters of $Af_2$ | 20 | 5·3 + 5 |
| 8 | Whole network | 51 | 9 + 20 + 18 + 4 |
| 9 | One extra neuron in hidden layer 2 (3, 6, 3) | +7 | $Af_2$: 20→24, $Af_3$: 18→21 |
Q4–Q9 · build the network and count parameters
Q4: $2\to(3,5,3)\to1$ means sizes 2-3-5-3-1.
Q6: $W^2$ maps 3 neurons to 5, so it is $5\times3$.
Why: rows = size of the new layer, columns = size of the previous one, so that $W^2x$ is defined.
Q7: $\#Af_2=5\cdot3+5=20$.
Q8: $9+20+18+4=51$ (figure).
Why: add every map; activations have no parameters.
Q9: one more neuron in hidden layer 2 (3, 6, 3): $Af_2$ 20 → 24, $Af_3$ 18 → 21: +7.
Why: a new neuron brings its incoming weights + bias (3 + 1) and its outgoing weights (3).
3 · Embedding the parameters into functions (Q10–Q12)
For a fixed architecture every parameter vector $P=(W^1,\dots,W^L,b^1,\dots,b^L)$ is a point of $\mathbb{R}^K$, and it gives a continuous function $NN_P$ on $X$. This is a map $\mathbb{R}^K\to C(X),\ P\mapsto NN_P$. Training means moving $P$ until $NN_P$ is close to a target $f$ in the sup-distance $d_\infty(NN_P,f)=\max_{x\in X}|NN_P(x)-f(x)|$.
- Q10. $NN_P(x)=\mathrm{ReLU}(x)+\mathrm{ReLU}(-2x+1)$ passes through $(-1,3)$, $(0,1)$, $(0.5,0.5)$, $(1,1)$: the bottom-left graph.
- Q11. One neuron $\mathrm{ReLU}(a_1x+a_2)$: $P=(-1.5,\,0.5)$ matches the target exactly (distance 0.00, pass mark 0.2).
- Q12. Fit $f(x)=\tfrac16\big((2x-1)^2+3|2x-1|\big)$ on $[-1,1]$ with two ReLU neurons. Submitted $(w_1,b_1,w_2,b_2,v_1,v_2,c)=(-3,1.5,1,0.5,1,1.5,-1.5)$; grade $=(1+\tfrac16)/(1+d_\infty)$.
Q10–Q12 · a parameter vector is a function
Q10: evaluate $\mathrm{ReLU}(x)+\mathrm{ReLU}(-2x+1)$ at $x=-1,0,0.5,1$: 3, 1, 0.5, 1 → the bottom-left graph.
Why: four points pin down a 3-piece graph with kinks at 0 and ½.
Q11: one neuron $\mathrm{ReLU}(a_1x+a_2)$; $P=(-1.5,0.5)$ reproduces the target exactly (distance 0).
Why: read the kink position $-a_2/a_1$ and the slope from the target graph.
Q12: two neurons for $f(x)=\tfrac16\big((2x-1)^2+3|2x-1|\big)$ on $[-1,1]$; submitted $P=(-3,1.5,1,0.5,1,1.5,-1.5)$.
Measure the fit: $d_\infty=1/6$ exactly (figure), so grade $(1+\tfrac16)/(1+\tfrac16)=1$.
Why: the formula gives full marks when the distance reaches 1/6, which this network cannot beat.
The script below recomputes every number above. Q12's distance is exactly 1/6 = 0.1667 (the PDF says ≈ 0.17), which is the best this two-neuron network can reach, so the grade is exactly 1.
"""Homework 1 checks: parameter counts and the two ReLU networks (plain Python)."""
relu = lambda z: max(z, 0.0)
def params(sizes):
# an affine map from s_{i-1} to s_i neurons has s_i*s_{i-1} weights + s_i biases
return [s * p + s for p, s in zip(sizes, sizes[1:])]
for sizes in ([2, 3, 5, 3, 1], [2, 3, 6, 3, 1], [4, 2, 2, 3]):
per = params(sizes)
print(f"{'-'.join(map(str, sizes)):12s} per map {per} total {sum(per)}")
# Q10: NN_P(x) = ReLU(x) + ReLU(-2x + 1)
q10 = lambda x: relu(x) + relu(-2 * x + 1)
print("Q10 points:", [(x, q10(x)) for x in (-1, 0, 0.5, 1)])
# Q12: best two-neuron fit of f(x) = ((2x-1)^2 + 3|2x-1|)/6 on [-1, 1]
f = lambda x: ((2 * x - 1) ** 2 + 3 * abs(2 * x - 1)) / 6
w1, b1, w2, b2, v1, v2, c = -3, 1.5, 1, 0.5, 1, 1.5, -1.5
nn = lambda x: v1 * relu(w1 * x + b1) + v2 * relu(w2 * x + b2) + c
xs = [-1 + 2 * i / 20000 for i in range(20001)]
d = max(abs(nn(x) - f(x)) for x in xs)
print(f"Q12 sup-distance on [-1, 1]: {d:.4f} (1/6 = {1/6:.4f}) grade = {(1 + 1/6) / (1 + d):.4f}")2-3-5-3-1 per map [9, 20, 18, 4] total 51
2-3-6-3-1 per map [9, 24, 21, 4] total 58
4-2-2-3 per map [10, 6, 9] total 25
Q10 points: [(-1, 3.0), (0, 1), (0.5, 0.5), (1, 1.0)]
Q12 sup-distance on [-1, 1]: 0.1667 (1/6 = 0.1667) grade = 1.0000Files: HW1_ex1.py · output
Why Q12 cannot reach 0
Two ReLU neurons give a piecewise-linear graph with at most 2 bends (3 straight pieces). The target is curved (a parabola plus a kink at $x=\tfrac12$), so some error must remain. More neurons → more pieces → smaller possible $d_\infty$. This is the first step toward the universal approximation idea.
The self-check questions of this homework are now in Part 3 · Practice → Revision mode (flashcards).
Source: Homework1_Neural_Networks_Summary.pdf (3 pages, all read).
Training Neural Networks
A network is a function with parameters; a loss scores it on data; training searches parameter space, first one coordinate at a time, then with all coordinates moving together.
1 · The network (Q1–Q3)
$$NN_P(x)=v_1\,\mathrm{ReLU}(w_1x+b_1)+v_2\,\mathrm{ReLU}(w_2x+b_2)+c$$ $$P=(w_1,b_1,w_2,b_2,v_1,v_2,c)\in\mathbb{R}^7$$- $w$ changes the steepness of a neuron, $b$ moves its kink left/right, $v$ scales it vertically ($v=0$ switches it off), $c$ shifts the whole graph.
- Piecewise linear with at most 2 kinks. $|x|$ is exact; $x^2$ can only be approximated.
Q1–Q3 · what each parameter does
Change one parameter at a time and watch the graph.
Why: isolating one parameter shows its role.
$w$ changes the slope of a hinge, $b$ moves its kink ($x=-b/w$), $v$ scales it ($v=0$ switches it off), $c$ shifts the whole graph.
Shape: piecewise linear with at most 2 kinks; $|x|$ is exact, $x^2$ only approximate.
Why: see Problem 2 of the Checking sheet for the proof.
2 · Loss (Q4–Q6)
$$\mathrm{loss}_D(P)=\frac1N\sum_{i=1}^{N}\big(y_i-NN_P(x_i)\big)^2\ \ge 0$$Squaring stops positive and negative errors cancelling. Worked example, errors $-0.70,-0.80,-0.05,0.45,0.55$:
| Loss | Formula | Value |
|---|---|---|
| $L^2$ (mean squared) | $\frac1N\sum e_i^2$ | 1.6375 / 5 = 0.3275 |
| $L^1$ (mean absolute) | $\frac1N\sum |e_i|$ | 0.51 |
| $L^\infty$ (max) | $\max_i |e_i|$ | 0.8 |
| signed mean (don't use) | $\frac1N\sum e_i$ | −0.11: errors cancel |
Q4–Q6 · scoring a network with a loss
Compute the errors on the five data points: −0.70, −0.80, −0.05, 0.45, 0.55.
Square and average: $L^2=(0.49+0.64+0.0025+0.2025+0.3025)/5=0.3275$.
Why: squaring makes every error count positively and punishes big errors more.
Compare: $L^1=0.51$, $L^\infty=0.8$; the signed mean is $-0.11$ (figure).
Why: the signed mean lets positive and negative errors cancel, so a bad model can score near 0.
Check: loss $\ge0$, and $=0$ only if every error is 0.
3 · Coordinate descent (Q7–Q8)
Fix all parameters but one, move that one to the minimum of the 1-D loss curve, go to the next, repeat. Each move never increases the loss; a second move on the same coordinate changes nothing; the order of coordinates leads to a different $P$ with about the same loss; it can stall short of the global minimum. Result: loss 0.328 → about 0.03 in one round, from either order.
Q7–Q8 · coordinate descent
Fix 6 parameters, plot the loss as a function of the 7th, move it to that curve’s minimum.
Why: a 1-D minimum is easy to find (scan or formula).
Go to the next coordinate and repeat; one round = all 7.
Observe: each move never increases the loss; redoing the same coordinate changes nothing; another order gives another $P$ with similar loss. Loss 0.328 → ≈ 0.03 in one round.
Why: the loss can only go down, but the path depends on the order.
4 · Evolutionary selection (Q9–Q11)
Try many random directions $v$ and move to the best $P+\eta v$; each round is a generation; $\eta$ is the learning rate.
| Method | What the runs showed |
|---|---|
| Fixed $\eta$ (Q9) | 0.01: slow but settles (0.741 after 50 gen.); 0.1: fast then jitters (0.464); 0.5 and 2: bounce and stay high (0.527, 1.088). Start large, end small. |
| Adaptive $\eta$ (Q10) | Success → $\eta\times1.5$, failure → $\eta\times0.7$. From 0.01 it grows, from 2 it shrinks; both meet after ~10 generations; near the bottom $\eta\to10^{-6}$ and the loss freezes. 0.415 vs 0.741 after 50 generations. |
| Average of $k$ best (Q11) | Weights $a_j=\dfrac{2(k+1-j)}{k(k+1)}$; $k=3$: ½, ⅓, ⅙. $k=5,20$ jump less (noise cancels); $k=50$ averages in poor points and stays higher. |
Q9–Q11 · random directions and the learning rate
Fixed $\eta$ (Q9): after 50 generations 0.741 (η = 0.01), 0.464 (0.1), 0.527 (0.5), 1.088 (2) (figure).
Why: small steps are safe but slow; large steps jump across the valley.
Adaptive $\eta$ (Q10): success → $\eta\times1.5$, failure → $\eta\times0.7$; both starts meet after ≈ 10 generations; 0.415 after 50.
Why: the step size tunes itself to the local shape of the loss.
Average of the $k$ best (Q11): weights $a_j=\frac{2(k+1-j)}{k(k+1)}$; for $k=3$: ½, ⅓, ⅙.
Why: scores $k,\dots,1$ sum to $k(k+1)/2$, so dividing makes the weights sum to 1.
Compare k: $k=5,20$ jump less (noise cancels); $k=50$ averages in poor directions and stays higher.
"""Homework 2 checks: the three losses on the worked example, and the k-best weights."""
from fractions import Fraction as F
errors = [-0.70, -0.80, -0.05, 0.45, 0.55]
n = len(errors)
print("squares:", [round(e * e, 4) for e in errors])
print("L2 (mean squared error):", round(sum(e * e for e in errors) / n, 4))
print("L1 (mean absolute error):", round(sum(abs(e) for e in errors) / n, 4))
print("Linf (max absolute error):", max(abs(e) for e in errors))
print("signed mean (why we square):", round(sum(errors) / n, 4))
for k in (1, 3, 5):
scores = [k + 1 - j for j in range(1, k + 1)]
total = sum(scores)
print(f"k={k}: scores {scores}, sum {total} = k(k+1)/2, weights {[str(F(s, total)) for s in scores]}")squares: [0.49, 0.64, 0.0025, 0.2025, 0.3025]
L2 (mean squared error): 0.3275
L1 (mean absolute error): 0.51
Linf (max absolute error): 0.8
signed mean (why we square): -0.11
k=1: scores [1], sum 1 = k(k+1)/2, weights ['1']
k=3: scores [3, 2, 1], sum 6 = k(k+1)/2, weights ['1/2', '1/3', '1/6']
k=5: scores [5, 4, 3, 2, 1], sum 15 = k(k+1)/2, weights ['1/3', '4/15', '1/5', '2/15', '1/15']Files: HW2_ex1.py · output. The generation-by-generation losses in the table come from your homework runs (random directions), so they are not re-run here.
Coordinate descent and evolutionary selection need no derivatives. Gradient descent (Chapter 4 of the notes) replaces “try 100 random directions” by the single best local direction $-\nabla\,\mathrm{loss}_D(P)$, and the learning-rate lessons from Q9–Q10 carry over unchanged.
The self-check questions of this homework are now in Part 3 · Practice → Revision mode (flashcards).
Source: homework2_training_neural_networks_lesson.md (all sections read).
Checking: Neural Networks — worked solutions
Full step-by-step solutions to the ten problems of the sheet. Every step says what we do and why, every problem has a figure that shows the idea, and every problem ends with the edge of the result: what it proves, what it does not say, and where it leads.
Contents
Each problem: the problem → what you need → solution in steps (with “Why”) → figure → answer → edge of the knowledge (✔ what it proves · ✖ what it does not say · → where it leads). To test yourself afterwards, go to Part 3 · Practice and choose “Problems · Checking NNs”.
Problem 1Sizes, parameters, and why we need an activation
A network has input in $\mathbb{R}^3$, one hidden layer with $4$ neurons and output in $\mathbb{R}^2$. Find the sizes of $W^1$ and $W^2$, and count the parameters.
Without an activation function, $NN(x)=W^2(W^1x+b^1)+b^2$. Prove that this is an affine map $Wx+b$. What does this say about adding more layers?
Size of $W^1$. Layer 1 sends $\mathbb{R}^3\to\mathbb{R}^4$, so $W^1\in\mathbb{R}^{4\times3}$ and $b^1\in\mathbb{R}^4$.
Why: $W^1x$ must be a vector of 4 numbers (one per hidden neuron), and $x$ has 3 numbers, so the matrix is out × in $=4\times3$. Row $j$ holds the 3 weights of neuron $j$.
Size of $W^2$. Layer 2 sends $\mathbb{R}^4\to\mathbb{R}^2$, so $W^2\in\mathbb{R}^{2\times4}$ and $b^2\in\mathbb{R}^2$.
Why: same rule: 2 outputs, 4 inputs.
Count. $\underbrace{4\cdot3}_{W^1}+\underbrace{4}_{b^1}+\underbrace{2\cdot4}_{W^2}+\underbrace{2}_{b^2}=12+4+8+2=26.$
Why: each entry of a weight matrix and each bias is one trainable number. General rule: a layer $\mathbb{R}^{n}\to\mathbb{R}^{m}$ has $mn+m$ parameters.
Expand the composition. $NN(x)=W^2(W^1x+b^1)+b^2=W^2W^1x+W^2b^1+b^2.$
Why: matrix multiplication distributes over addition: $W^2(u+v)=W^2u+W^2v$.
Name the pieces. Put $W=W^2W^1\in\mathbb{R}^{2\times3}$ and $b=W^2b^1+b^2\in\mathbb{R}^2$. Then $NN(x)=Wx+b$: an affine map. ∎
Why: $W$ does not depend on $x$ (a product of fixed matrices) and $b$ does not depend on $x$ (a fixed vector), which is exactly the definition of affine.
More layers. By induction, if $k$ linear layers give $W_kx+b_k$, one more gives $W^{k+1}(W_kx+b_k)+b^{k+1}$, affine again. So any depth without activation is still one affine map.
Why it matters: stacking layers adds parameters but no new functions. The power of a neural network comes from the non-linear activation between layers.
Problem 2Two ReLU neurons: what they can and cannot draw
Let $NN_P(x)=v_1\,\text{ReLU}(w_1x+b_1)+v_2\,\text{ReLU}(w_2x+b_2)+c$. Find $P$ such that $NN_P(x)=|x|$. At most how many straight pieces can the graph of $NN_P$ have? Can $NN_P$ equal $x^2$ on an interval? Explain.
Split $|x|$ by sign. $|x|=x$ for $x\ge0$ and $|x|=-x$ for $x<0$.
Why: we want each neuron to handle one side.
One hinge per side. $\mathrm{ReLU}(x)$ equals $x$ for $x\ge0$ and $0$ otherwise; $\mathrm{ReLU}(-x)$ equals $-x$ for $x<0$ and $0$ otherwise. Their sum is $|x|$ everywhere.
Why: for each $x$ exactly one of the two is “on”, and it gives the right value; the other adds 0.
Read off $P$. $(w_1,b_1,w_2,b_2,v_1,v_2,c)=(1,0,-1,0,1,1,0)$. (Checked on 13 points from −3 to 3: exact.)
Count kinks. Neuron $j$ changes slope only at $x=-b_j/w_j$ (if $w_j\ne0$). Two neurons → at most 2 kinks → at most 3 straight pieces.
Why: between kinks every neuron is either off (0) or a straight line, and a sum of straight lines is a straight line. $k$ cut points split a line into at most $k+1$ parts.
Can it be $x^2$ on an interval $I$? Suppose yes. $I$ has positive length but only ≤ 2 kinks, so it contains a sub-interval $J$ with no kink, where $NN_P(x)=\alpha x+\beta$. Then $x^2=\alpha x+\beta$ for all $x\in J$: the polynomial $x^2-\alpha x-\beta$ has infinitely many roots, impossible for a non-zero polynomial. So no.
Why (second view): on $J$ the second derivative of $NN_P$ is $0$, but $(x^2)''=2$. A curved function is curved on every interval; a ReLU network is straight on every small enough interval.
Problem 3The best constant: mean for $L^2$, median for $L^1$
The model is a constant $c$ and the data is $y_1,\ldots,y_N$. Prove that $L^2(c)=\frac1N\sum_i(y_i-c)^2$ is smallest when $c$ is the mean of the $y_i$.
For $y=0,1,2,5$, find the $c$ that minimizes $L^2$ and all the $c$ that minimize $L^1(c)=\frac1N\sum_i|y_i-c|$. Which loss is moved more by the point $5$?
Differentiate $L^2$. $\dfrac{dL^2}{dc}=\dfrac1N\sum_i2(y_i-c)(-1)=-\dfrac2N\sum_i(y_i-c).$
Why: chain rule on each square; the inner derivative of $y_i-c$ in $c$ is $-1$.
Set it to 0. $\sum_i(y_i-c)=0\iff\sum_iy_i=Nc\iff c=\bar y=\frac1N\sum_iy_i.$
Check it is a minimum. $\dfrac{d^2L^2}{dc^2}=2>0$, so $L^2$ is a parabola opening up and $\bar y$ is its unique minimum. ∎
Why (without calculus): $\sum_i(y_i-c)^2=\sum_i(y_i-\bar y)^2+N(\bar y-c)^2$ (expand and use $\sum_i(y_i-\bar y)=0$). The first term does not depend on $c$; the second is $\ge0$ and is $0$ only at $c=\bar y$.
Numbers for $L^2$. $\bar y=\frac{0+1+2+5}{4}=2$ and $L^2(2)=\frac{(0-2)^2+(1-2)^2+(2-2)^2+(5-2)^2}{4}=\frac{4+1+0+9}{4}=3.5.$
Slope of $L^1$. $\dfrac{dL^1}{dc}=\dfrac1N\big(\#\{y_i<c\}-\#\{y_i>c\}\big)$ away from the data points.
Why: each point below $c$ contributes $+1$ (moving $c$ right increases its distance), each point above contributes $-1$.
Where the slope is 0. For $c<1$: at most 1 point below, at least 3 above → slope < 0 (going down). For $1<c<2$: 2 below, 2 above → slope $=0$ (flat). For $c>2$: slope > 0. So every $c\in[1,2]$ minimizes $L^1$, with $L^1=\frac{1+0+1+4}{4}=1.5$.
Why: these $c$ are the medians: half of the data on each side. With an even number of points the median is a whole interval.
Effect of the point 5. In $L^2$ its error is squared: $3^2=9$ of the total $14$, and it pulls the mean up. In $L^1$ only its side matters. Test: replace 5 by 100 → the mean jumps to $25.75$, the $L^1$ minimizers stay $[1,2]$. So $L^2$ is moved more.
Why: the gradient of $L^2$ is proportional to each error, so a far point pulls hard; the gradient of $L^1$ gives every point a vote of size 1.
Problem 4Steepest descent and the learning rate
Let $\|V\|=1$. From $D_Vf(P_0)=\nabla f(P_0)\cdot V$, prove that $f$ decreases fastest in the direction $-\nabla f(P_0)/\|\nabla f(P_0)\|$.
Let $f(x,y)=x^2+3y^2$ and $P_0=(1,1)$. Compute $f(P_1)$ for $P_1=P_0-\eta\nabla f(P_0)$, with $\eta=0.1$ and with $\eta=0.5$. What does this say about the learning rate?
Bound the rate of change. By Cauchy–Schwarz, $D_Vf(P_0)=\nabla f\cdot V\ge-\|\nabla f\|\,\|V\|=-\|\nabla f\|.$
Why: no unit direction can make $f$ go down faster than $\|\nabla f\|$ per unit step.
When is the bound reached? Equality holds only when $V$ is parallel to $\nabla f$ and points the other way: $V=-\nabla f/\|\nabla f\|$. Check: $\nabla f\cdot\big(-\nabla f/\|\nabla f\|\big)=-\|\nabla f\|^2/\|\nabla f\|=-\|\nabla f\|$. ∎ (We need $\nabla f(P_0)\ne0$.)
Why: $\nabla f\cdot V=\|\nabla f\|\cos\theta$, smallest when $\cos\theta=-1$, i.e. angle $180°$.
Gradient at $P_0$. $\nabla f=(2x,\,6y)=(2,\,6)$ and $f(P_0)=1+3=4$.
$\eta=0.1$. $P_1=(1,1)-0.1(2,6)=(0.8,\,0.4)$, $f(P_1)=0.64+3(0.16)=1.12$. The value drops from 4 to 1.12.
$\eta=0.5$. $P_1=(1,1)-0.5(2,6)=(0,\,-2)$, $f(P_1)=0+3(4)=12$. The value rises from 4 to 12.
Why: the gradient is only a local direction. A big step goes past the bottom of the valley and lands higher on the other side.
See it per coordinate. One step maps $x\mapsto(1-2\eta)x$ and $y\mapsto(1-6\eta)y$. For $\eta=0.5$ the $y$-factor is $-2$: $y$ flips sign and doubles every step (12, 48, 192, … — it diverges). For $\eta=0.1$ both factors are in $(0,1)$ (1.12, 0.49, 0.27, … — it converges).
Why: convergence needs $|1-2\eta|<1$ and $|1-6\eta|<1$, i.e. $0<\eta<1/3$. The steepest direction (curvature 6) sets the limit.
Problem 5One gradient step by hand, and a dead neuron
Let $NN(x)=\text{ReLU}(wx+b)$, with one data point $(x,y)=(2,3)$ and $\text{loss}=(y-NN(x))^2$. Start at $w=1$, $b=0$. Compute $\partial\,\text{loss}/\partial w$ and $\partial\,\text{loss}/\partial b$, take one step with $\eta=0.1$, and find the new loss.
Now start at $w=-1$, $b=0$. Compute the gradient. Why can training not move from here?
Forward pass. $z=wx+b=1\cdot2+0=2$, $NN=\mathrm{ReLU}(2)=2$, $\mathrm{loss}=(3-2)^2=1$.
Why first: the backward pass needs the values $z$ and $NN$ to evaluate each local slope.
Local slopes. $\dfrac{\partial\,\mathrm{loss}}{\partial NN}=-2(y-NN)=-2$, $\dfrac{\partial NN}{\partial z}=\mathrm{ReLU}'(2)=1$, $\dfrac{\partial z}{\partial w}=x=2$, $\dfrac{\partial z}{\partial b}=1$.
Chain rule. $\dfrac{\partial\,\mathrm{loss}}{\partial w}=(-2)(1)(2)=-4$, $\dfrac{\partial\,\mathrm{loss}}{\partial b}=(-2)(1)(1)=-2$.
Why negative: the output is too small (2 < 3), so increasing $w$ or $b$ lowers the loss; the gradient points to “decrease”, so its sign is negative.
Update. $w\leftarrow1-0.1(-4)=1.4$, $b\leftarrow0-0.1(-2)=0.2$.
New loss. $NN=\mathrm{ReLU}(1.4\cdot2+0.2)=3.0$, so $\mathrm{loss}=(3-3)^2=0$.
Why exactly 0: a lucky hit for these numbers. In general one step only reduces the loss (for small enough $\eta$).
Start at $w=-1$, $b=0$. $z=-2<0$, $NN=0$, $\mathrm{loss}=9$. Now $\mathrm{ReLU}'(-2)=0$, so $\dfrac{\partial\,\mathrm{loss}}{\partial w}=(-6)(0)(2)=0$ and $\dfrac{\partial\,\mathrm{loss}}{\partial b}=(-6)(0)(1)=0$.
Why training is stuck. The update is $\theta\leftarrow\theta-\eta\cdot0=\theta$: nothing moves, forever. The loss is large (9), but the closed gate multiplies the error signal by 0. This is a dead ReLU.
Why: the gradient only sees the local slope. In the flat region small changes of $w,b$ do not change the output, so the gradient has no information about the fix (making $z$ positive).
Problem 6Words as vectors: inner product vs distance
Why do we represent words by vectors and not by the numbers $1,2,3,\ldots$?
Let $|u|=|v|=1$. Prove that $|u-v|^2=2-2\,u\cdot v$. What does this say about $u\cdot v$ when two words are close?
Let $a=(0.8,\,0.6)$, $x=(1.6,\,1.2)$ and $y=(0.9,\,3.7)$. Compute $a\cdot x$, $a\cdot y$, $|a-x|$ and $|a-y|$. Which vector has the larger inner product with $a$, and which is closer to $a$? Explain why they differ.
Why not numbers. Numbers $1,2,3$ put all words on one line with an order and fixed distances: word 2 would be “between” words 1 and 3, and $3=1+2$ would mean something. These relations are accidents of the numbering, not of meaning. Also one number cannot hold many independent properties (noun? positive? about food?).
Why vectors work: $\mathbb{R}^d$ has $d$ directions, so each direction can carry one kind of property, and similarity can be measured by geometry and learned from data.
Expand the distance. $|u-v|^2=(u-v)\cdot(u-v)=u\cdot u-2u\cdot v+v\cdot v=|u|^2-2u\cdot v+|v|^2=2-2u\cdot v.$ ∎
Why: the dot product is bilinear and symmetric; then use $|u|=|v|=1$.
Interpret. Distance small ⇔ $u\cdot v$ close to its maximum 1. Examples: $u\cdot v=1$ → distance 0; $u\cdot v=0$ → distance $\sqrt2$; $u\cdot v=-1$ → distance 2.
Why: for unit vectors $u\cdot v=\cos\theta$, so “close” = “small angle”.
Inner products. $a\cdot x=0.8(1.6)+0.6(1.2)=1.28+0.72=2.00$; $a\cdot y=0.8(0.9)+0.6(3.7)=0.72+2.22=2.94$.
Distances. $a-x=(-0.8,-0.6)$, $|a-x|=\sqrt{0.64+0.36}=1$; $a-y=(-0.1,-3.1)$, $|a-y|=\sqrt{0.01+9.61}=\sqrt{9.62}\approx3.10$.
Compare. $y$ has the larger inner product, but $x$ is closer.
Why they differ: $x$ and $y$ are not unit vectors ($|x|=2$, $|y|\approx3.81$), so step 2 does not apply. $a\cdot y=|a||y|\cos\theta$ is big because $y$ is long: $\cos(a,y)=2.94/3.81\approx0.77$, while $\cos(a,x)=1$ because $x=2a$ points exactly the same way.
Problem 7The ReLU gate is the answer to a sparsity problem
Let $z=a\cdot x$ and $h=\text{ReLU}(z+b)$. For which $z$ is the gate open?
For $\lambda>0$, prove that the $h\ge 0$ minimizing $\tfrac12(h-z)^2+\lambda|h|$ is $h=\text{ReLU}(z-\lambda)$. Which $b$ does this gate have?
Find the $h\ge 0$ minimizing $\tfrac12(h-z)^2+\lambda h^2$ when $z>0$. Can this $h$ be $0$? So which penalty should we use to have only a few concepts present at each word?
Gate open. $h=\mathrm{ReLU}(z+b)>0\iff z+b>0\iff z>-b$.
Why: $-b$ is a threshold: the feature is “present” only if the word matches it by more than $-b$.
Simplify the $L^1$ problem. For $h\ge0$, $|h|=h$, so minimise $g(h)=\tfrac12(h-z)^2+\lambda h$ on $h\ge0$. Its derivative is $g'(h)=h-z+\lambda$, and $g''=1>0$ (convex).
Case $z>\lambda$. $g'(h)=0$ at $h=z-\lambda>0$, which is allowed, so $h=z-\lambda$.
Case $z\le\lambda$. $g'(h)=h-(z-\lambda)\ge h\ge0$ for all $h\ge0$, so $g$ never decreases on $[0,\infty)$: the minimum is at $h=0$.
Why: the pull towards $z$ is weaker than the price $\lambda$ per unit of $h$, so it is cheapest to switch the feature off.
Combine. $h=\max(0,z-\lambda)=\mathrm{ReLU}(z-\lambda)$. ∎ Comparing with $\mathrm{ReLU}(z+b)$: $\boldsymbol{b=-\lambda}$.
Why it matters: a ReLU with a negative bias is exactly “keep the feature only if the evidence is worth its price $\lambda$”.
The $L^2$ penalty. $g(h)=\tfrac12(h-z)^2+\lambda h^2$, $g'(h)=h-z+2\lambda h=0\Rightarrow h=\dfrac{z}{1+2\lambda}$. For $z>0$ this is positive, so it is allowed and it is the minimum.
Can it be 0? No: $z>0$ and $1+2\lambda>0$ give $h>0$. $L^2$ only shrinks features; it never turns them off.
Why: near $h=0$ the slope of $\lambda h^2$ is $2\lambda h\to0$, so any positive pull $z$ wins. The slope of $\lambda|h|$ stays $\lambda$, so a pull $z\le\lambda$ loses.
Conclusion. Use the $L^1$ penalty $\lambda|h|$ to have only a few concepts present at each word. Numbers ($\lambda=1$): $z=0.5$ → $L^1$ gives $0$, $L^2$ gives $0.167$; $z=3$ → $2$ vs $1$.
Problem 8Running an RNN by hand
Let $h_n=\text{ReLU}(A_wx_n+A_hh_{n-1}+b)$, with $h_0=0$ and $$A_w=\begin{pmatrix}1&1\\-1&1\end{pmatrix},\quad A_h=\begin{pmatrix}0.5&0\\-1&0.5\end{pmatrix},\quad b=\begin{pmatrix}-1\\-1\end{pmatrix},\quad x_1=\begin{pmatrix}1\\1\end{pmatrix},\quad x_2=\begin{pmatrix}2\\0\end{pmatrix}.$$ Compute $h_1$ and $h_2$. What does row $i$ of $A_w$ represent? What does the entry $-1$ of $A_h$ do?
With $h=12$ and $d=768$, how many numbers do $A_w$, $A_h$ and $b$ have together? How does this number change for a longer sentence? Explain.
Word 1, input part. $A_wx_1=\begin{pmatrix}1+1\\-1+1\end{pmatrix}=\begin{pmatrix}2\\0\end{pmatrix}$, memory part $A_hh_0=\begin{pmatrix}0\\0\end{pmatrix}$.
Add bias, apply ReLU. $\begin{pmatrix}2\\0\end{pmatrix}+\begin{pmatrix}-1\\-1\end{pmatrix}=\begin{pmatrix}1\\-1\end{pmatrix}$, so $h_1=\mathrm{ReLU}\begin{pmatrix}1\\-1\end{pmatrix}=\begin{pmatrix}1\\0\end{pmatrix}$.
Why: concept 1 matched strongly enough (2 > threshold 1) and is on; concept 2 did not (0 < 1) and is off.
Word 2. $A_wx_2=\begin{pmatrix}2\\-2\end{pmatrix}$, $A_hh_1=\begin{pmatrix}0.5\cdot1+0\cdot0\\-1\cdot1+0.5\cdot0\end{pmatrix}=\begin{pmatrix}0.5\\-1\end{pmatrix}$.
Add and gate. $\begin{pmatrix}2+0.5-1\\-2-1-1\end{pmatrix}=\begin{pmatrix}1.5\\-4\end{pmatrix}$, so $h_2=\begin{pmatrix}1.5\\0\end{pmatrix}$.
Why 1.5: the new word gives 2, half of the old concept 1 is kept (0.5), the threshold removes 1.
Rows of $A_w$. $(A_wx_n)_i=a_i\cdot x_n$ where $a_i$ is row $i$. So row $i$ is a feature (key) vector: it scores how much the new word looks like feature $i$. Here $a_1=(1,1)$, $a_2=(-1,1)$.
The entry $-1$ of $A_h$ (row 2, column 1). It adds $-1\times(\text{concept 1 in the memory})$ to concept 2: if concept 1 was present, concept 2 is pushed down now — inhibition, like a “not” cancelling what follows. At $n=2$ it lowers concept 2 from $-3$ to $-4$.
Honest note: concept 2 is closed either way here, so the effect does not show in $h_2$; with another word it could decide whether the gate opens. The diagonal $0.5$ keeps half of each concept (memory that fades).
Count. $A_w$: $12\times768=9216$; $A_h$: $12\times12=144$; $b$: $12$. Total $9216+144+12=9372$.
Why these shapes: $A_w$ maps a word ($d=768$) to $h=12$ concepts; $A_h$ maps 12 old concepts to 12 new ones; $b$ has one threshold per concept.
Longer sentence. The number does not change: the same $A_w,A_h,b$ are used at every word (weight sharing). A longer sentence only means more steps of the same update.
Problem 9Does the RNN see word order?
Let $A_h=I$ and $b=0$, without ReLU, so $h_n=A_wx_n+h_{n-1}$. Prove that $h_T=A_w\sum_{n=1}^Tx_n$. What does this say about the order of the words?
Now take one neuron with $h_n=\text{ReLU}(z_n+h_{n-1})$ and $h_0=0$. Compute $h_3$ for $z=(3,-5,2)$ and for $z=(-5,3,2)$. Explain why the results differ.
Base case $T=1$. $h_1=A_wx_1+h_0=A_wx_1=A_w\sum_{n=1}^1x_n$.
Induction step. Assume $h_{T-1}=A_w\sum_{n=1}^{T-1}x_n$. Then $h_T=A_wx_T+A_w\sum_{n=1}^{T-1}x_n=A_w\sum_{n=1}^{T}x_n$. ∎
Why: $A_w$ is linear, so $A_wu+A_wv=A_w(u+v)$.
Order. $\sum x_n$ is the same for every ordering of the words, so this RNN cannot see word order: “dog bites man” and “man bites dog” give the same $h_T$. It is a bag of words. (Python check: a sequence and its reverse give the same $h_T$.)
Order $z=(3,-5,2)$. $h_1=\mathrm{ReLU}(3)=3$; $h_2=\mathrm{ReLU}(-5+3)=\mathrm{ReLU}(-2)=0$; $h_3=\mathrm{ReLU}(2+0)=2$.
Order $z=(-5,3,2)$. $h_1=\mathrm{ReLU}(-5)=0$; $h_2=\mathrm{ReLU}(3+0)=3$; $h_3=\mathrm{ReLU}(2+3)=5$.
Why different. Without ReLU both orders give $3-5+2=0$. With ReLU: in the first order the $-5$ arrives after the $3$, wipes it out, and the extra $-2$ is clipped and forgotten; in the second order the $-5$ comes first, is clipped while the memory is still 0, and costs nothing.
Why in one line: “add then clip” does not commute, while “add” does. The non-linearity is what makes an RNN sensitive to order.
Problem 10Sigmoid + cross-entropy: the gradient $-(1-p)$
A sentence has the score $s=v\cdot h_T+c$ and $p=\sigma(s)=\dfrac{1}{1+e^{-s}}$, with $\text{loss}=-\big[y\log p+(1-y)\log(1-p)\big]$. For $y=1$, prove that $\text{loss}=\log(1+e^{-s})$ and $\dfrac{d\,\text{loss}}{ds}=-(1-p)$. What happens to this derivative when the model is confident and right?
Let $h_T=(3,\,1)$, $v=(1,\,-1)$ and $c=0$. Compute $p$, and compute the loss for $y=0$ and for $y=1$.
Loss for $y=1$. The second term vanishes: $\mathrm{loss}=-\log p=-\log\dfrac{1}{1+e^{-s}}=\log(1+e^{-s})$. ∎
Differentiate. $\dfrac{d\,\mathrm{loss}}{ds}=\dfrac{1}{1+e^{-s}}\cdot(-e^{-s})=-\dfrac{e^{-s}}{1+e^{-s}}$.
Recognise $1-p$. $1-p=1-\dfrac{1}{1+e^{-s}}=\dfrac{e^{-s}}{1+e^{-s}}$, so $\dfrac{d\,\mathrm{loss}}{ds}=-(1-p)$. ∎ (Numerical derivative agrees at $s=-4,0,2,6$.)
Why it is so clean: the $\log$ in the loss undoes the $\exp$ in the sigmoid. In general $\dfrac{d\,\mathrm{loss}}{ds}=p-y$: “predicted minus true”.
Confident and right. $s\to+\infty$ ⇒ $p\to1$ ⇒ $\dfrac{d\,\mathrm{loss}}{ds}\to0$ (e.g. $s=6$: $-0.0025$). The example is already learned and barely moves the weights.
Contrast: confident and wrong ($s\to-\infty$) gives slope $\to-1$, a full push: the model learns most from its confident mistakes.
Score and probability. $s=v\cdot h_T+c=1\cdot3+(-1)\cdot1+0=2$, $p=\sigma(2)=\dfrac{1}{1+e^{-2}}\approx0.881$.
Losses. $y=1$: $-\log0.881\approx0.127$. $y=0$: $-\log(1-0.881)=-\log0.119\approx2.127$.
Why they differ by exactly 2: $\log(1+e^{s})-\log(1+e^{-s})=\log e^{s}=s=2$.
Every number and every figure on this page comes from running Python (3 Nov 2026): LessonWeb/NLP/code/CHK_ex.py (numbers, output in CHK_ex.out.txt) and LessonWeb/NLP/code/CHK_figs.py (figures). Main lines:
import numpy as np
relu = lambda z: np.maximum(z, 0); sig = lambda s: 1/(1+np.exp(-s))
# Q4 f = x^2 + 3y^2 from (1,1)
P0, g = np.array([1., 1.]), np.array([2., 6.])
for eta in (0.1, 0.5): P1 = P0 - eta*g; print(eta, P1, P1[0]**2 + 3*P1[1]**2)
# Q8 RNN by hand
Aw = np.array([[1, 1], [-1, 1.]]); Ah = np.array([[.5, 0], [-1, .5]]); b = np.array([-1, -1.])
h1 = relu(Aw@[1, 1] + b); h2 = relu(Aw@[2, 0] + Ah@h1 + b); print(h1, h2)
# Q9 order with ReLU
def one(zs):
h = 0.
for z in zs: h = max(z + h, 0.)
return h
print(one([3, -5, 2]), one([-5, 3, 2]))
# Q10 sigmoid + cross-entropy
s = np.dot([1, -1], [3, 1]); p = sig(s); print(p, -np.log(p), -np.log(1 - p))0.1 [0.8 0.4] 1.1199999999999999 0.5 [ 0. -2.] 12.0 [1. 0.] [1.5 0. ] 2.0 5.0 0.8807970779778823 0.12692801104297263 2.1269280110429714
Source: online problem sheet “Checking: Neural Networks” (ITC, Dept. of Applied Mathematics and Statistics; 10 problems, read 3 Nov 2026; opens with your Google sign-in). Solutions, explanations, figures and the “edge” boxes are tutor-written.
Question bank
Multiple-choice and numerical questions with instant feedback and step-by-step solutions. Your answers are remembered in this browser.
Formulas, definitions, flashcards
Everything from the First Look lesson, Chapter 1 and Section 1.1 in compact form, plus exam-style questions.
Formula reference
Open "What the symbols mean" under any formula for a symbol-by-symbol reading.
Key definition
$NN(x)=Af_L\circ\sigma_{L-1}\circ\cdots\circ Af_2\circ\sigma_1\circ Af_1(x)$, with affine $Af_i(x)=W^ix+b^i:\mathbb{R}^{k_{i-1}}\to\mathbb{R}^{k_i}$, $k_0=n$, $k_L=m$, and non-linear $\sigma_i$ applied pointwise.
$M:\mathcal{L}\to\mathcal{L}$, built from a next-word map $M_0:\mathcal{L}\to\Sigma$; with embedded inputs and probability outputs, $M:(\mathbb{R}^d)^*\to\mathbb{R}^{|\Sigma|}$. An RNN is $f:\text{words}\times\text{memory}\to\text{memory}$, and the approval classifier computes $p=\sigma(v\cdot h_n+c)$.
Key fact (proved in Chapter 1)
Without activations, $W^L\cdots W^1$ is a single matrix, so depth adds no expressive power. With biases: $W^2(W^1x+b^1)+b^2=(W^2W^1)x+(W^2b^1+b^2)$.
Flashcards
Exam-style questions
Source coverage
What was read from the original notes and what this site has built so far.
| Section | Original lesson | This site |
|---|
First Look lecture: slide coverage
The lecture “Language Modeling (A First Look)” has 22 slides. Each one was read, restated in the lesson section shown, and extended with tutor additions.
| Slide | Title on the slide | Taught in | Original lesson |
|---|
Original deck: open the slides ↗
Original source
Vanny Khon, Language Modeling: A Mathematical Perspective (lecture notes, published as a Google Apps Script web page). This site restates its mathematics for study purposes; read the original for the author's full wording and figures.