Machine Learning · Insper

Gradient Descent & Regularization

Fundamental approach

How a model finds its weights by walking downhill, and how a brake keeps a flexible model from memorizing

Why the closed form is not enough

The closed form of ordinary least squares (OLS), \(\hat w = (X^\top X)^{-1}X^\top y\), solves linear regression in one move. But:

it does not scale

inverting \(X^\top X\) costs \(O(d^3)\) for \(d\) features: hopeless with huge feature counts

it does not exist

for most other models, starting with neural networks

it does not brake

it says nothing about controlling overfitting

Two tools for this lesson: gradient descent (the engine) and regularization (the brake).

The path of this part

  1. Walk downhillthe gradient, derived and computed by hand
  2. Tune the stepthe learning rate; batch, stochastic, mini-batch
  3. Lines → curvespolynomial features; underfitting and overfitting
  4. Regularizeridge (L2), lasso (L1) and the knob α
Each stage answers one question: how do we find the minimum without solving for it? → how big a step, and on how much data? → what happens when the model gets more flexible? → how do we keep that flexibility in check?
Stage 1 · how do we find the minimum without solving for it?

Gradient descent: walk downhill

Instead of solving \(\nabla J = 0\) on paper: measure the slope where you stand, step against it, repeat.

\[ w^{(t+1)} = w^{(t)} - \eta \, \nabla_w J\big(w^{(t)}\big) \]
  • \(J(w)\): the loss, the error the model makes with weights \(w\); \(t\): the iteration.
  • \(\eta\): the learning rate, the size of the step.
  • \(\nabla_w J\), the gradient, points where the loss grows fastest; the minus sign makes the method descend.
Predict. To turn this into code we need \(\nabla_w J\). For a line \(w_0 + w_1 x\) with squared error, what do you expect the derivative to be made of?

Where the gradient comes from

\[ J(w_0, w_1) = \frac{1}{n}\sum_{i=1}^{n}\big(\underbrace{y_i - w_0 - w_1 x_i}_{e_i}\big)^2 \]

\(n\) points \((x_i, y_i)\); \(e_i\) is the residual of point \(i\). Chain rule: the derivative of \(e_i^2\) is \(2e_i\) times how the residual reacts to the weight.

\(\partial e_i / \partial w_0 = -1\)

raising the intercept by one lowers every residual by one

\(\partial e_i / \partial w_1 = -x_i\)

raising the slope lowers the residual by \(x_i\): points far from the origin feel it more

\[ \frac{\partial J}{\partial w_0} = -\frac{2}{n}\sum_i e_i, \qquad \frac{\partial J}{\partial w_1} = -\frac{2}{n}\sum_i e_i x_i \]

Gradient descent, by hand

Points \((1,2), (2,4), (3,7)\); start at \(w_0 = w_1 = 0\); \(\eta = 0.1\). Predict. Which way will the first step move each weight, and how much of the loss of 23 will it remove?

Stage 2 · how big a step, and on how much data?

The learning rate

  • \(\eta\) too small → tiny steps, slow convergence
  • \(\eta\) too large → the steps overshoot; the loss oscillates or diverges
  • recipe: try \(\eta \in \{10^{-3}, 10^{-2}, 10^{-1}\}\) and watch the training loss fall smoothly

On \(J(w) = (w-3)^2\), slope \(2(w-3)\), subtract 3 from both sides of the update:

\[ w_{t+1} - 3 = (1 - 2\eta)\,(w_t - 3) \]

the distance to the minimum is multiplied by \(1 - 2\eta\) at every step.

so, on this loss

\(\eta < 0.5\)creeps in
\(\eta = 0.5\)the minimum in one move
\(0.5 < \eta < 1\)bounces, but closes in
\(\eta = 1\)bounces between two points for ever
\(\eta > 1\)explodes

Simulator: the learning rate

Predict. Set \(\eta = 1.05\) and step through it. Does it converge, bounce for ever or explode?

Batch, stochastic and mini-batch

The gradient sums over all \(n\) points: with millions of rows, one step costs a full pass over the data.

variantgradient computed oncost per stepbehavior
batch gradient descent (GD)the full dataset\(O(nd)\)exact, smooth descent
stochastic GD (SGD)one random sample\(O(d)\)noisy but cheap; escapes shallow traps
mini-batch GDa batch of ~32–512in betweenthe modern default

from sklearn.linear_model import SGDRegressor
model = SGDRegressor(loss='squared_error', penalty='l2', alpha=1e-4,
                     learning_rate='invscaling', max_iter=1000)
  
The same loop, with other losses, trains logistic regression, SVMs and neural networks. Learn it once.
Stage 3 · what happens when the model gets more flexible?

From lines to curves: polynomial features

Linear regression is linear in the parameters, not in the inputs: \(x \mapsto (x, x^2, \dots, x^p)\), and the same OLS fits the weights.


from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import PolynomialFeatures

model = make_pipeline(PolynomialFeatures(degree=3), LinearRegression())
  
Predict. 25 noisy points of a sine. Degree 1, degree 15: what goes wrong with each?

Flexibility cuts both ways

Polynomial underfit, overfit, and Ridge regularization

Degree 1 underfits: too rigid. Degree 15 overfits: 16 parameters chase 25 noisy points. Right: the same 16 parameters plus a Ridge penalty, and the curve relaxes back to the signal.

Underfitting and overfitting, measured

100 points of \(y = 0.5x^2 + x + 2\), noise with standard deviation 3; five-fold cross-validation. RMSE: root mean squared error, in units of \(y\).

degreetrain RMSEvalidation RMSE (mean)spread across folds
13.223.260.19
22.642.750.33
302.4610.4313.46

Degree 30, fold by fold: \(3.14 \quad 3.02 \quad 5.51 \quad \mathbf{37.29} \quad 3.20\)

The lowest training error belongs to the worst model. Overfitting is being wrong unpredictably: the spread across folds gives it away before the mean does.

A pocket diagnostic

too simple (underfitting)too complex (overfitting)
training errorhighlow
validation errorhigh, consistentlyhigh on average, occasionally low
spread across foldssmalllarge
what to domore capacity, better featuresregularize, more data, less capacity
There is a floor: the noise (standard deviation 3) does not depend on \(x\), and no model removes it. Degree 2 lands near that floor.
Stage 4 · how do we keep that flexibility in check?

Regularization: penalize the magnitude

Ridge (L2) · Tikhonov 1943; Hoerl & Kennard 1970

\[ \lVert y - Xw \rVert^2 + \alpha \sum_j w_j^2 \]
  • shrinks smoothly, never to exactly zero
  • spreads weight across correlated features
  • closed form: \((X^\top X + \alpha I)^{-1} X^\top y\)

Lasso (L1) · Tibshirani 1996

\[ \lVert y - Xw \rVert^2 + \alpha \sum_j \lvert w_j \rvert \]
  • lands exactly at zero for weak features
  • automatic feature selection
  • among correlated features, keeps one arbitrarily

\(\lVert y - Xw\rVert^2\): the sum of squared errors; \(\alpha \ge 0\): the strength of the penalty. L2 penalizes the sum of squares of the weights, L1 the sum of their absolute values. Elastic Net blends both (l1_ratio).

Ridge and lasso on one coefficient, by hand

One feature, \(\sum x_i^2 = 1\), \(\alpha = 1\); \(\hat w\) is the OLS coefficient. Predict. Which penalty can turn \(\hat w = 0.2\) into exactly zero, and why?

The knob α

  • \(\alpha \to 0\): plain OLS, no brake.
  • \(\alpha \to \infty\): every coefficient crushed to ~0, the model predicts the mean.
  • The right \(\alpha\) is not known in advance: choose it by cross-validation (RidgeCV, LassoCV, a grid search).
Scale before regularizing (in a Pipeline): the penalty compares coefficients across features, so a feature in kilometers would be penalized differently from the same one in meters. And the intercept is not penalized; scikit-learn does that for you.

Summary

  1. Gradient descent walks downhill: \(w \leftarrow w - \eta\nabla J\).
  2. For the squared error the gradient is a residual-weighted sum: \(-\frac{2}{n}\sum e_i\), \(-\frac{2}{n}\sum e_i x_i\).
  3. \(\eta\) too large diverges, too small creeps; mini-batches make each step cheap.
  4. Overfitting = low training error, high and unpredictable validation error.
  5. Ridge divides the coefficients, lasso subtracts and clips them to zero; scale first, choose \(\alpha\) by cross-validation.
symptomwhat to do
the loss grows at every stepdivide \(\eta\) by 10
training error far below validation, folds that disagreeregularize, more data, less capacity
Fundamental lab · about 25 min, in pairs

Downhill, one step at a time, steps 1 to 3

  • Step 1: walk down \(J(w) = (w-3)^2\) with a fixed \(\eta\). Step 2: push \(\eta\) until it breaks. Step 3: train a line on the three points of the hand table and check every number against the closed form.
  • Notebook on Colab (in Portuguese), sections 1 to 3: nothing to download. Save a copy to your Drive.
  • At every step, answer the Predict before running.
  • Simulations: the boundary case (step 2) and another starting point (step 3).

Pace: steps 1 and 2 and the first simulation in 12 min; step 3 and the second in 13 min.