Gradient descent
Underfitting and overfitting
The perceptron
A linear classifier
Neural networks extend the perceptron by introducing multiple layers of interconnected neurons (i.e., multi-layer perceptron), enabling the learning of complex, non-linear relationships in data.
From simple linear regression to the perceptron:
From simple linear regression to the perceptron:
XOR is not linearly separable (Minsky & Papert, 1969)
Perceptron with a general activation
Basis functions
Richer hypothesis spaces:
Multilayer perceptron (MLP)
Training is costly but inference is cheap
Multilayer perceptron (MLP)
Multilayer perceptron (MLP)
The Universal Approximation theorem states that a neural network with one hidden layer can approximate any continuous function on a compact subset of
Feedforward Neural Network:
Tasks: regression and classification
Data: fixed-length feature vectors such as tabular records and engineered features
Key idea: fully connected layers learn the basis functions from data
Limitation: ignores spatial and temporal structure in the input
Feedforward Neural Network:
First, recall the general form of a linear model with nonlinear basis functions:
where
Feedforward Neural Network:
First, recall the general form of a linear model with nonlinear basis functions:
where
In neural networks, the basis functions themselves are parameterized and learned. The network is constructed as a sequence of transformations.
Feedforward Neural Network:
1. Linear combination of inputs (first layer):
where
Feedforward Neural Network:
1. Linear combination of inputs (first layer):
where
2. Basis function of the inputs or nonlinear activation (hidden layer):
Feedforward Neural Network:
2. Basis function of the inputs or nonlinear activation (hidden layer):
The designer chooses
Training learns these weights. The curve
Feedforward Neural Network:
3. Linear combination of hidden activations (output layer):
where
Feedforward Neural Network:
3. Linear combination of hidden activations (output layer):
where
The activations
Feedforward Neural Network:
The overall network function combines these stages. For sigmoidal output unit activation functions, takes the form:
Feedforward Neural Network:
The overall network function combines these stages. For sigmoidal output unit activation functions, takes the form:
The bias parameters can be absorbed:
Feedforward Neural Network:
The overall network function combines these stages. For sigmoidal output unit activation functions, takes the form:
The bias parameters can be absorbed:
An activation function is a fixed curve applied to one unit's score. On a hidden unit,
Sigmoid Function:
Range:
Derivative:
Hyperbolic Tangent:
Range:
Derivative:
ReLU (Rectified Linear Unit):
Range:
Derivative:
Choosing
Nonlinear: a linear
Derivative: training follows the slope of
Saturation: sigmoid and tanh flatten in the tails. ReLU keeps slope 1 for positive scores, which helps deeper networks
Range: tanh is centred at 0. A sigmoid hidden unit is always positive
Output activation follows the task. Identity for regression, sigmoid for two classes, softmax for more than two classes.
Training Process:
Given a training set of
Training Process:
Given a training set of
Each pair was generated by an unknown function
Training Process:
Given a training set of
Each pair was generated by an unknown function
We want to find a hypothesis
Training Process (regression problem):
Giving a probabilistic interpretation to the network outputs:
where
Training Process (regression problem):
Giving a probabilistic interpretation to the network outputs:
where
For an i.i.d. training set, the likelihood function corresponds to:
Training Process (regression problem):
Training Process (regression problem):
Maximising the likelihood function is equivalent to minimising the sum-of-squares error function given by:
Training Process (binary classification):
The network output is:
We use a single target variable
Training Process (binary classification):
The network output is:
We use a single target variable
Training Process (binary classification):
The network output is:
We use a single target variable
For an i.i.d. training, the error function is the cross-entropy error:
We choose any starting point and then compute an estimate of the gradient. We then move a small amount in the steepest downhill direction, repeating until we converge on a point in the weight space with (local) minima loss.
Gradient Descent Algorithm:
Initialize w
repeat
for each w[i] in w
Compute gradient: g = ∇Loss(w[i])
Update weight: w[i] = w[i] - α * g
until convergence
The size of the step is given by the parameter
Error backpropagation is an efficient algorithm for computing gradients in neural networks using the chain rule of calculus.
Error Backpropagation Algorithm:
Error Backpropagation Algorithm:
1. Forward Pass to compute all activations and outputs for an input vector.
Error Backpropagation Algorithm:
1. Forward Pass to compute all activations and outputs for an input vector.
2. Error Evaluation for all outputs using:
Error Backpropagation Algorithm:
1. Forward Pass to compute all activations and outputs for an input vector.
2. Error Evaluation for all outputs using:
3. Backward Pass: for each hidden unit in the network using:
Error Backpropagation Algorithm:
1. Forward Pass to compute all activations and outputs for an input vector.
2. Error Evaluation for all outputs using:
3. Backward Pass: for each hidden unit in the network using:
4. Derivatives Evaluation for each parameter using:
Gradient Descent Update Rule:
Gradient Descent Update Rule:
Gradient Descent Update Rule:
Gradient Descent Update Rule:
Where
Python implementation: scikit-learn
hidden_layer_sizes: number of hidden layers and units per layer
alpha: the
Defaults: ReLU activation and the Adam optimiser
from sklearn.neural_network import MLPClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
model = make_pipeline(
StandardScaler(),
MLPClassifier(
hidden_layer_sizes=(8,), # one hidden layer, 8 units
alpha=1e-4, # L2 penalty
max_iter=3000,
random_state=42,
),
)
model.fit(X_train, y_train)
print(model.score(X_test, y_test))
Python implementation: PyTorch
Forward pass: model(X)
Backpropagation: loss.backward()
Update: optimiser.step() applies
import torch
from torch import nn
model = nn.Sequential(
nn.Linear(D, 8), # W(1), b(1)
nn.Tanh(), # h(.)
nn.Linear(8, 1), # W(2), b(2)
)
loss_fn = nn.BCEWithLogitsLoss() # sigmoid + cross-entropy
optimiser = torch.optim.SGD(model.parameters(), lr=0.1)
for epoch in range(100):
optimiser.zero_grad()
loss = loss_fn(model(X).squeeze(1), y)
loss.backward()
optimiser.step()
Deep learning extends neural networks by using multiple hidden layers to learn hierarchical representations of data, enabling the automatic discovery of complex features.
Key Characteristics:
Vanishing and Exploding Gradients: In deep networks, gradients can become very small (vanishing) or very large (exploding) during backpropagation:
Vanishing and Exploding Gradients: In deep networks, gradients can become very small (vanishing) or very large (exploding) during backpropagation:
Regularisation: Dropout,
Weight Initialization:
Xavier/Glorot Initialization:
He Initialization (for ReLU):
Where
Batch normalisation:
Where
Modern Optimisers:
Optimisers train models by efficiently navigating the loss landscape to find optimal parameters. They help in accelerating convergence, avoiding local minima, and improving generalisation.
Regularization Techniques:
Dropout: Randomly deactivate neurons during training
Early Stopping: Stop training when validation loss increases
Data Augmentation: Create additional training examples through transformations
Architecture
Number of layers
Hidden units
Activation
Training
Learning rate
Epochs and batch size
Optimiser: SGD or Adam
Regularisation strength
Tasks: forecasting, sequence classification, language modelling, and speech recognition
Data: time series, text, audio, and sensor signals
Key idea: a hidden state carries memory from one time step to the next
Limitation of the MLP: sequences have an order and a variable length, and an MLP expects a fixed-size input
Example: the next character
Sequence: the 11 characters in "el temblor "
Each step: one character, as a one-hot vector
Hidden state: memory of the characters already read
Task: the next character, m
Python implementation: PyTorch
A window of characters to the next character
Layers: nn.RNN, then a score for each character
Clipping: clip_grad_norm_ before each update
from torch import nn
class SequenceModel(nn.Module):
def __init__(self, n_chars, n_hidden):
super().__init__()
self.rnn = nn.RNN(n_chars, n_hidden, batch_first=True)
self.head = nn.Linear(n_hidden, n_chars)
def forward(self, x): # x: (batch, T, n_chars)
out, h_T = self.rnn(x) # tanh hidden state
return self.head(h_T[-1]) # scores for the next character
# in the training loop
nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
Tasks: dimensionality reduction, denoising, anomaly detection, and generation
Data: unlabelled inputs such as images, signals, and feature vectors
Key idea: learn to reconstruct the input through a small latent code
Example: handwritten digit images
Input: one image, with no label
Latent code: a short vector
Output: the reconstructed image
Task: reconstruction, such as spotting an unusual digit from a large error
Python implementation: PyTorch
An autoencoder for vectors of size
Latent code: smaller than
Loss: squared error between the input and the reconstruction
Target: the input itself, so no labels are needed
from torch import nn
class Autoencoder(nn.Module):
def __init__(self, D, M, latent_dim):
super().__init__()
self.enc = nn.Sequential(nn.Linear(D, M), nn.ReLU(), nn.Linear(M, latent_dim))
self.dec = nn.Sequential(nn.Linear(latent_dim, M), nn.ReLU(), nn.Linear(M, D))
def forward(self, x):
z = self.enc(x)
return self.dec(z)
def ae_loss(x_hat, x):
return ((x - x_hat) ** 2).sum()
Tasks: generating new samples and learning a continuous latent space
Data: unlabelled inputs such as images, signals, and feature vectors
Key idea: the encoder outputs a distribution over the latent code
Example: the same digit images
Input: one image, with no label
Latent code: a sample from a learned distribution
Decode: a new image from a drawn code
Task: generating new digits
Python implementation: PyTorch
A VAE for vectors of size
log_var:
KL term: closed form for Gaussians
Added here: mu, log_var, and the KL term
import torch
from torch import nn
class VAE(nn.Module):
def __init__(self, D, M, latent_dim):
super().__init__()
self.enc = nn.Sequential(nn.Linear(D, M), nn.ReLU())
self.mu = nn.Linear(M, latent_dim)
self.log_var = nn.Linear(M, latent_dim)
self.dec = nn.Sequential(nn.Linear(latent_dim, M), nn.ReLU(), nn.Linear(M, D))
def forward(self, x):
h = self.enc(x)
mu, log_var = self.mu(h), self.log_var(h)
z = mu + torch.exp(0.5 * log_var) * torch.randn_like(mu) # reparameterisation
return self.dec(z), mu, log_var
def vae_loss(x_hat, x, mu, log_var):
rec = ((x - x_hat) ** 2).sum()
kl = -0.5 * (1 + log_var - mu ** 2 - log_var.exp()).sum()
return rec + kl
Tasks: node classification, link prediction, and graph classification
Data: graphs such as social networks, molecules, and road or sensor networks
Key idea: each node updates its representation with messages from its neighbours
Example: a sensor network, such as seismic stations
Nodes: sensors
Edges: nearby sensors are connected
Node features: recent readings
Task: node regression, such as the shaking at each station
Python implementation: PyTorch
A GCN layer in plain PyTorch
PyTorch Geometric: GCNConv implements this layer
import torch
from torch import nn
class GCNLayer(nn.Module):
def __init__(self, n_in, n_out):
super().__init__()
self.linear = nn.Linear(n_in, n_out) # W(l)
def forward(self, H, A): # H: (N, n_in), A: (N, N)
A_tilde = A + torch.eye(A.shape[0]) # self-loops
D_inv_sqrt = torch.diag(A_tilde.sum(dim=1).pow(-0.5))
A_hat = D_inv_sqrt @ A_tilde @ D_inv_sqrt # degree normalisation
return torch.relu(A_hat @ self.linear(H))
Tasks: image classification, object detection, and segmentation
Data: grid-structured inputs such as images, video frames, spectrograms, and maps
Key idea: local connectivity, shared weights, and pooling
Example: small colour photographs
Input: one RGB image of size 32 times 32
Local patterns: an edge or a texture can appear anywhere
Shared weights: one kernel is reused across the image
Task: classification into 10 classes, such as airplane, car, or bird
Python implementation: PyTorch
RGB images of size
Training loop: the same as for the MLP
Loss: CrossEntropyLoss applies the softmax
from torch import nn
model = nn.Sequential(
nn.Conv2d(3, 32, kernel_size=3, padding=1), # 32 feature maps
nn.ReLU(),
nn.MaxPool2d(2), # 32x32 to 16x16
nn.Conv2d(32, 64, kernel_size=3, padding=1),
nn.ReLU(),
nn.MaxPool2d(2), # 16x16 to 8x8
nn.Flatten(),
nn.Linear(64 * 8 * 8, 10), # 10 classes
)
loss_fn = nn.CrossEntropyLoss()
Linear regression
Linear classifiers
Hypothesis space and loss
Gradient descent
Underfitting and overfitting
The perceptron
A linear classifier
Feedforward (MLP)
Tasks: regression and classification
Data: feature vectors
Recurrent (RNN, LSTM, GRU)
Tasks: forecasting, language, speech
Data: sequences
Autoencoders and VAEs
Tasks: compression, denoising, generation
Data: unlabelled inputs
GANs and diffusion
Tasks: generating images and audio
Data: unlabelled samples
Graph neural networks
Tasks: node, link, and graph prediction
Data: graphs
CNNs and ResNets
Tasks: classification, detection, segmentation
Data: images and grids
_script: true
This script will only execute in HTML slides
_script: true