这组文章整理自 2024 年的课程学习笔记,保留原练习、代码和图表。运行前请先看系列目录中的环境与数据说明。 查看系列目录。
Stochastic Gradient Descent
The purpose of this notebook is to practice implementing the stochastic gradient descent (SGD) optimisation algorithm from scratch.
1 | import numpy as np |
We consider a linear regression problem of the form
y=β0+xβ1+ϵ ,ϵ∼N(0,σ2) y = \beta_0 + x \beta_1 + \epsilon\,,\quad \epsilon \sim \mathcal N(0, \sigma^2) y=β0+xβ1+ϵ,ϵ∼N(0,σ2)where x∈Rx\in\mathbb{R}x∈R are inputs and y∈Ry\in\mathbb{R}y∈R are noisy observations. The bias β0∈R\beta_0\in\mathbb{R}β0∈R and coefficient β1∈R\beta_1\in\mathbb{R}β1∈R parametrize the function.
In this tutorial, we assume that we are able to sample data inputs and outputs (xn,yn)(\boldsymbol x_n, y_n)(xn,yn), n=1,…,Kn=1,\ldots, Kn=1,…,K, and we are interested in finding parameters β0\beta_0β0 and β1\beta_1β1 that map the inputs well to the ouputs.
From our lectures, we know that the parameters β0\beta_0β0 and β1\beta_1β1 can be calculated analytically. However, here we are interested in computing a numerical solution using the stochastic gradient descent algorithm (SGD).
We will start by setting up a generator of synthetic data inputs and outputs, see: https://realpython.com/introduction-to-python-generators/.
1 | # define parameters for synthetic data |
1 | # Create generator for batch size 16 |
1 | <generator object data_generator at 0x7f5599713530> |
We can visualise the first batch of synthetic data along with the true underlying function.
1 | # Pull a batch of training data |

The loss that we wish to minimise is the expected mean squared error (MSE) loss computed on the training data:
L(β0,β1):=E(x,y)∼pdata[(y−β0−xβ1)2] \mathcal{L}(\beta_0, \beta_1) := \mathbb{E}_{(x, y)\sim p_{data}} \left[(y - \beta_0 - x\beta_1)^2\right] L(β0,β1):=E(x,y)∼pdata[(y−β0−xβ1)2]We first compute the mean squared error loss on a single batch of input and output data.
1 | ## EDIT THIS FUNCTION |
To check your implementation you can run this test:
1 | # This line verifies the correctness of the mse_loss implementation |
Before we can minimze the MSE loss we need to initialise the parameters β0\beta_0β0 and β1\beta_1β1.
1 | # Initialise the parameters |

Stochastic gradient descent samples a batch of KKK input and output samples, and makes a parameter update by computing the gradient of the loss function
∇(β0,β1)L(β0(i),β1(i)∣X(i),Y(i)), \nabla_{(\beta_0, \beta_1)}\mathcal{L}(\beta_0^{(i)}, \beta_1^{(i)} \mid \mathcal{X}^{(i)}, \mathcal{Y}^{(i)}), ∇(β0,β1)L(β0(i),β1(i)∣X(i),Y(i)),where β0(i),β1(i)\beta_0^{(i)}, \beta_1^{(i)}β0(i),β1(i) are the values of the parameters at the iii-th iteration of the algorithm, and X(i),Y(i)\mathcal{X}^{(i)}, \mathcal{Y}^{(i)}X(i),Y(i) are the iii-th batch of inputs and outputs.
The following function should compute the gradient of the MSE loss for a given batch of data, and current parameter values.
1 | ## EDIT THIS FUNCTION |
To check your implementation you can run this cell:
1 | # These lines verify that the derivatives delta_beta0 and delta_beta1 are computed correctled |
We have now established all ingredients needed to implement the SGD algorithm for our problem task.
Recall that SGD makes the following parameter update at each iteration:
(β0(i+1),β1(i+1))=(β0(i),β1(i))−η∇(β0,β1)L(β0(i),β1(i)∣X(i),Y(i)), (\beta_0^{(i+1)}, \beta_1^{(i+1)}) = (\beta_0^{(i)}, \beta_1^{(i)}) - \eta \nabla_{(\beta_0, \beta_1)}\mathcal{L}(\beta_0^{(i)}, \beta_1^{(i)} \mid \mathcal{X}^{(i)}, \mathcal{Y}^{(i)}), (β0(i+1),β1(i+1))=(β0(i),β1(i))−η∇(β0,β1)L(β0(i),β1(i)∣X(i),Y(i)),where η>0\eta>0η>0 is the learning rate.
Implement below a training of the parameters β0\beta_0β0 and β1\beta_1β1 using SGD over 2000 iterations and a learning rate η=0.001\eta=0.001η=0.001.
1 | ## EDIT THIS CELL |
1 | Learned parameters: |
We finally plot the fitted curve and the visualise the training over several iterations.
1 | # Plot the learned regression function and loss values |

Questions
- Does the solution above look reasonable?
- Play around with different values of the learning rate. How is the convergence of the algorithm affected?
- Try using different batch sizes and re-run the algorithm. What changes?

