Skip to content
ELECTRONICS ENGINEERINGelectronics-engineering.com
Author's pick Machine Learning and Neural Networks

Regression and gradient descent: normal equations, convergence, logistic regression and overfitting

The supervised learning problem, the normal equations proved, convergence of gradient descent with the 2/L limit, logistic regression and cross-entropy, overfitting and ridge regularisation with experiments.

https://www.electronics-engineering.com/en/linear-regression-gradient-descent-overfitting/

No ratings yet: be the first to rate this page.

Machine learning builds models that learn from data instead of being programmed rule by rule: one chooses a family of functions with parameters, defines an error measuring how far predictions are from the data, and looks for the parameters that minimise it. All neural networks, even the largest, work this way. This first lesson presents the ingredients with the simplest models: linear regression (with the exact solution and the iterative one of gradient descent, whose convergence is proved), logistic regression for classification, and the central problem of the whole course, overfitting.

The supervised learning problem

There are n examples (\mathbf x_i, y_i): an input (a sensor’s measurements, an image’s pixels) and the right answer (a temperature, a digit). We want a function f_{\mathbf w}(\mathbf x) that predicts y also for new inputs. A loss \ell(f_{\mathbf w}(\mathbf x), y) is chosen and its average over the data is minimised:

    \[ J(\mathbf w) = \frac{1}{n}\sum_{i=1}^n\ell\big(f_{\mathbf w}(\mathbf x_i),\ y_i\big) \]

The real goal however is not to do well on the data at hand, but on the data that will come: this is why some examples are set aside (validation set and test set), not used for training and only used to measure.

Linear regression and the normal equations

With f_{\mathbf w}(\mathbf x) = \mathbf w^T\mathbf x (adding a constant component 1 to \mathbf x, the first weight acts as the intercept) and the squared error, putting the examples in the rows of a matrix X:

    \[ J(\mathbf w) = \frac{1}{n}\|X\mathbf w - \mathbf y\|^2 \]

Theorem. If X^TX is invertible, the minimum is \mathbf w^* = (X^TX)^{-1}X^T\mathbf y (normal equations).

Proof. J is a convex quadratic function; the gradient is \nabla J = \frac{2}{n}X^T(X\mathbf w - \mathbf y) and vanishes for X^TX\mathbf w = X^T\mathbf y. The Hessian \frac{2}{n}X^TX is positive definite (if the columns of X are independent), so the stationary point is the only minimum. Geometrically, X\mathbf w^* is the orthogonal projection of \mathbf y onto the space spanned by the columns of X: the residual X\mathbf w^* - \mathbf y is perpendicular to all columns. ∎

Gradient descent

For more complicated models there is no closed formula. One starts from any \mathbf w_0 and takes small steps in the direction in which the error decreases fastest, the opposite of the gradient:

    \[ \mathbf w_{k+1} = \mathbf w_k - \eta\,\nabla J(\mathbf w_k) \]

with \eta the learning rate. It is the algorithm that trains all neural networks.

Theorem (convergence on a quadratic). For a quadratic J with positive definite Hessian H, with eigenvalues 0 \lt  \mu \le \dots \le L, gradient descent converges to \mathbf w^* from any starting point if and only if 0 \lt  \eta \lt  \frac{2}{L}.

Proof. For a quadratic \nabla J(\mathbf w) = H(\mathbf w - \mathbf w^*), so the error \mathbf e_k = \mathbf w_k - \mathbf w^* evolves as \mathbf e_{k+1} = (I - \eta H)\mathbf e_k. In the eigenvectors of H each component is multiplied at every step by 1 - \eta\lambda_i, and tends to zero if and only if |1 - \eta\lambda_i| \lt  1, i.e. 0 \lt  \eta \lt  2/\lambda_i. The strictest condition is that of the largest eigenvalue, L. ∎

The speed depends on the condition number L/\mu: with the best step the reduction factor per step is \frac{L - \mu}{L + \mu}, close to 1 when the eigenvalues are very different. This is why inputs are normalised (same scale for all variables) and why the optimisers of lesson 4 exist.

Numerical example. With 50 points y = 2 + 3x + noise, the normal equations give \mathbf w^* = (1.927;\ 3.157). For these data 2/L = 0.771: gradient descent with \eta = 0.1, 0.5 and 0.694 converges to the same result (with \eta = 0.5 213 steps are needed for an error of 10^{-6}), while with \eta = 0.848, just beyond the limit, it diverges to values of 10^{158}.

Classification: logistic regression

To predict a class (yes or no, fault or no fault) the sigmoid \sigma(z) = \frac{1}{1 + e^{-z}} is used, which turns any number into a probability: P(y = 1 \mid \mathbf x) = \sigma(\mathbf w^T\mathbf x).

Theorem. Maximising the likelihood of the data is equivalent to minimising the cross-entropy J(\mathbf w) = -\frac{1}{n}\sum_i\big[y_i\log p_i + (1 - y_i)\log(1 - p_i)\big], with p_i = \sigma(\mathbf w^T\mathbf x_i), and the gradient is \nabla J = \frac{1}{n}\sum_i(p_i - y_i)\,\mathbf x_i.

Proof. The probability of observing y_i is p_i^{y_i}(1 - p_i)^{1 - y_i}; for independent examples the likelihood is the product, and its logarithm with changed sign and divided by n is J. For the gradient one uses \sigma'(z) = \sigma(z)(1 - \sigma(z)): \frac{\partial}{\partial z}\big[-y\log\sigma - (1 - y)\log(1 - \sigma)\big] = -y(1 - \sigma) + (1 - y)\sigma = \sigma - y. ∎

The gradient has the same form as in linear regression: (prediction − truth) × input. With several classes the sigmoid becomes the softmax p_k = e^{z_k}/\sum_je^{z_j} and the gradient with respect to z_k is still p_k - y_k: it is the last layer of almost all classification networks.

Overfitting

A model that is too flexible also learns the noise in the data. With 15 points of \sin 2\pi x plus noise, polynomials of increasing degree are fitted and the mean squared error is measured on the training data and on 200 new points:

degreetraining errorerror on new data
10.2520.259
30.0130.095
90.0070.808
140.00250.2
Polynomials of degree 1, 3 and 14 fitted to 15 points
The straight line, grey, is too rigid; the degree-3 polynomial, blue, follows the trend well; the degree-14 one, red, passes almost through every point but oscillates violently between them. In green the degree-14 polynomial with regularisation.

The training error always decreases, the error on new data first decreases and then explodes. Degree 1 underfits (too simple: high bias), degree 14 overfits (too flexible: high variance). This is the bias-variance trade-off: the expected error on a new point decomposes into squared bias, plus the model’s variance as the data change, plus irreducible noise.

Regularisation penalises large weights: J(\mathbf w) + \lambda\|\mathbf w\|^2 (ridge, or weight decay in networks), with solution (X^TX + \lambda I)^{-1}X^T\mathbf y (same proof as the normal equations). On the degree-14 polynomial with \lambda = 10^{-3} the error on new data drops from 50.2 to 0.069, better even than degree 3. The value of \lambda is chosen by looking at the validation set, never at the test set.

The code

import numpy as np

rng = np.random.default_rng(0)
x = rng.uniform(0, 1, 50)
y = 2 + 3 * x + rng.normal(0, 0.3, 50)
X = np.c_[np.ones(50), x]                                   # column of 1s for the intercept

w_exact = np.linalg.solve(X.T @ X, X.T @ y)                 # normal equations
L = 2 * np.linalg.eigvalsh(X.T @ X / 50).max()              # largest eigenvalue of the Hessian
print("normal equations:", np.round(w_exact, 4), " step limit 2/L =", round(2 / L, 3))
for eta in (0.5, 0.9 * 2 / L, 1.1 * 2 / L):
    w = np.zeros(2)
    for k in range(2000):
        w -= eta * 2 / 50 * X.T @ (X @ w - y)              # gradient descent
    print(f"eta = {eta:.3f}:", np.round(w, 4) if np.all(np.isfinite(w)) else "diverges")

# overfitting: polynomials on 15 points, error on 200 new points
f = lambda t: np.sin(2 * np.pi * t)
xa = np.sort(rng.uniform(0, 1, 15)); ya = f(xa) + rng.normal(0, 0.2, 15)
xn = rng.uniform(0, 1, 200); yn = f(xn) + rng.normal(0, 0.2, 200)
def fit(degree, lam=0.0):
    A = np.vander(xa, degree + 1, increasing=True)
    return np.linalg.solve(A.T @ A + lam * np.eye(degree + 1), A.T @ ya)      # ridge if lam > 0
def error(c, xs, ys):
    return np.mean((np.vander(xs, len(c), increasing=True) @ c - ys) ** 2)
for degree, lam in ((1, 0), (3, 0), (9, 0), (14, 0), (14, 1e-3)):
    c = fit(degree, lam)
    print(f"degree {degree:2d}, lambda {lam:g}: training {error(c, xa, ya):.4f}, new data {error(c, xn, yn):.4f}")

Running it reproduces the numbers in the text. The following lessons replace the linear model with neural networks, which are still trained by gradient descent and suffer from the same overfitting problems.

Subscribe
Notify of
guest
1 Comment
Oldest
Newest Most Voted
1
0
Would love your thoughts, please comment.x
()
x