π Gradient Descent
Descriptionβ
< What is it? >β
- [The idea]
-
Gradient descent is the iterative optimizer behind almost all model training: start from random parameters, measure which direction increases the loss, and step the other way. Repeat until the loss stops improving (convergence).
-
The gradient
βJ(ΞΈ)(β: Nabla = differential operator, here is the gradient) is the vector of partial derivatives of the loss with respect to every parameter. It points in the direction of steepest increase, soββJ(ΞΈ)is the steepest descent direction β hence the minus sign:ΞΈ := ΞΈ β Ξ± Β· βJ(ΞΈ)β β βnew β gradient of the loss w.r.t. every parameterparams learning rate Ξ± (step size) -
Nothing about this is specific to neural networks. It is the same rule for linear regression, logistic regression and a 100-billion-parameter transformer β only the way the gradient is computed differs (a closed-form expression for the simple cases, backpropagation for deep nets).
-
- [What it requires]
- A loss that is differentiable with respect to the parameters. This is why classification models optimize cross-entropy rather than accuracy: accuracy is a step function with zero gradient almost everywhere.
- Models whose parameters are not fit by a continuous objective β decision trees and their ensembles β do not use it. They search over discrete splits instead.
- [The training loop]
repeat until converged:1. forward β compute predictions Ε· for a batch of examples2. loss β compare Ε· to y, get a single scalar J3. backward β backpropagate to get βJ(ΞΈ) for every parameter4. step β ΞΈ := ΞΈ β Ξ± Β· βJ(ΞΈ)
< Training-loop terminology >β
| Term | Meaning |
|---|---|
| Batch | A group of training examples processed together in one forward and backward pass |
| Mini-batch | A small batchβusually only part of the training setβused for one step. In practice, βbatchβ usually means βmini-batchβ |
| Iteration / step | One parameter update using one batch |
| Epoch | One complete pass through all training batches |
< Example >β
For example, suppose you have 1,000 training examples:
- Batch size = 100
- Each batch causes one parameter update
- Number of updates per epoch:
Therefore:
- 1 epoch = process all 1,000 examples once = 10 updates
- 5 epochs = process them five times = 50 updates
- 100 epochs = process them 100 times = 1,000 updates
< Batch, stochastic, mini-batch >β
| Variant | Examples per step | Gradient quality | Reality |
|---|---|---|---|
| Batch (full) | All m | Exact, smooth descent | One update per epoch. Too slow, and the dataset may not fit in memory |
| Stochastic (SGD) | 1 | Very noisy | Updates constantly, but wastes hardware β no vectorization |
| Mini-batch | 32 β 8192 | Noisy but usable | What everyone actually uses. Vectorizes on GPU and the noise is useful |
- The noise in mini-batch gradients is not purely a cost. It helps the optimizer escape saddle points and narrow minima, which is one reason a moderate batch size often generalizes better than an enormous one.
- Batch size and learning rate are coupled: multiplying the batch size by k roughly permits multiplying the learning rate by k (the linear scaling rule), because each gradient estimate is proportionally less noisy.
- Shuffle every epoch. Data that arrives sorted by label makes each batch's gradient point somewhere unrepresentative.
- Where to start: 32, 64, 128 or 256. The upper end of the table is reserved for large-scale distributed runs; the practical ceiling on a single device is GPU memory, since activations for the whole batch must be held for the backward pass.
- Too small has its own failure mode. Batch normalization estimates its statistics from the batch, so below roughly 8β16 examples those estimates get noisy enough to hurt, and a batch size of 1 leaves it undefined in training mode.
< The learning rate β the one knob that matters most >β
Ξ± too small Ξ± about right Ξ± too large
β² β² β² β±
β².... β² β² β± β diverges
β²....β’ β²___β’ β²β±
creeps, may never lands in the basin overshoots the valley,
reach the minimum in few steps loss β NaN
- Schedules decay Ξ± over training: step decay, cosine annealing, or
1/βt. Large steps early to cover ground, small steps late to settle. Cosine decay is the default for transformer training. - Warmup ramps Ξ± up from ~0 over the first few hundred/thousand steps. Adaptive optimizers have unreliable variance estimates at step 1, and a full-size step then can wreck the initialization.
- Find a starting value by sweeping Ξ± on a log scale (
1e-5 β¦ 1e-1) for a few hundred steps and taking the largest value whose loss still falls smoothly.
Key pointsβ
< Optimizers: what each one fixes >β
| Optimizer | Adds | Fixes |
|---|---|---|
| SGD | β | Baseline. Slow through ravines, sensitive to Ξ± |
| + Momentum | Velocity: an exponentially-weighted average of past gradients | Damps zig-zag across a narrow valley, accelerates along it |
| + Nesterov | Look-ahead gradient | Slightly better-damped momentum |
| AdaGrad | Per-parameter Ξ± scaled by accumulated squared gradients | Rare features get larger steps β but Ξ± decays to zero and training stalls |
| RMSProp | Same, with a moving average instead of a sum | Removes AdaGrad's terminal stall |
| Adam | RMSProp + momentum + bias correction | The robust default. Works well with little tuning |
| AdamW | Decouples weight decay from the adaptive step | Makes regularization behave correctly β see Regularization |
- In practice: AdamW for transformers and most NLP; SGD with momentum still matches or beats it on vision CNNs and often generalizes slightly better; plain SGD for convex problems where you can tune Ξ± properly.
- All of them are still gradient descent. They only reshape how the raw gradient is turned into a step.
< The landscape: why this works at all >β
- For convex losses (linear regression's MSE, logistic regression's log-loss) there is a single minimum and gradient descent provably finds it. Everything is well behaved.
- Deep networks are non-convex β a surface with countless critical points. The classical worry was getting trapped in a bad local minimum. In high dimensions that turns out to be rare: a local minimum requires every one of millions of directions to curve upward. What you actually hit are saddle points (up in some directions, down in others), and gradient noise plus momentum escape them.
- Most minima found in practice reach a similar loss. Flat minima β wide basins where nearby parameters give similar loss β tend to generalize better than sharp ones, which is another argument for the noise in mini-batch SGD.
< Reading the loss curve >β
| Symptom | Likely cause | Move |
|---|---|---|
| Loss β NaN / inf after a few steps | Ξ± too large, or exploding gradients | Cut Ξ± 10Γ, add gradient clipping, add warmup |
| Loss flat from step 0 | Ξ± far too small, dead ReLUs, or the gradient never reaches the params | Raise Ξ±; check requires_grad, zero_grad(), and that the loss is connected to the graph |
| Loss falls then plateaus high | Underfitting, or Ξ± now too large to settle | Add capacity, or decay Ξ± β see Bias & Variance |
| Very spiky loss | Batch too small, Ξ± too large, or unshuffled data | Larger batch, lower Ξ±, shuffle |
| Training loss falls, validation rises | Overfitting β not an optimizer problem | Early stopping, regularization |
| Slow zig-zag progress | Ill-conditioned surface from unscaled features | Normalize the inputs; use momentum or Adam |
< Things that quietly break it >β
- [Unscaled features] elongated loss contours cap Ξ± at whatever the steepest direction tolerates β the geometry argument in Data Normalization.
- [Exploding / vanishing gradients] deep stacks multiply gradients through many layers. Fixes are structural: gradient clipping, residual connections, careful initialization (He/Xavier([ΛzΓ¦vΙͺr])), and normalization layers.
- [Forgetting to reset gradients] PyTorch accumulates into
.grad; withoutoptimizer.zero_grad()every step uses the sum of all previous gradients. - [Loss scale under mixed precision] fp16 gradients underflow to zero. Use a gradient scaler, or bf16.
- [Tuning Ξ± against the test set] the learning rate is a hyperparameter like any other β see the validation-set rule in Bias & Variance.
< When not to use it >β
- Closed form exists. OLS linear regression has the normal equation
ΞΈ = (Xα΅X)β»ΒΉXα΅yβ exact, no Ξ± to tune. Gradient descent wins once n is large enough that invertingXα΅Xis expensive. - Second-order methods (Newton, L-BFGS) use curvature and converge in far fewer iterations, but need the Hessian or an approximation of it β quadratic in the parameter count. Practical for small convex problems, hopeless at deep-learning scale, which is why first-order methods dominate.
Implementationβ
< Linear Regression Using Gradient Descent >β
Question: Write a Python function that performs linear regression using gradient descent. The function should take NumPy arrays X (features with a column of ones for the intercept) and y (target) as input, along with the learning rate alpha and the number of iterations. Return the learned coefficients (weights) as a NumPy array.
Requirements:
- Minimize the Mean Squared Error (MSE) loss function: Here, is the prediction for training example , and is the number of training examples. The factor simplifies the gradient calculation.
- Initialize all weights to zero
- Use batch gradient descent (use all samples in each iteration)
The input matrix X has shape (m, n) where m is the number of training examples and n is the number of features (including the bias column of ones). The target vector y has shape (m,).
Input: X = np.array([[1, 1], [1, 2], [1, 3]]), y = np.array([3, 5, 7]), alpha = 0.1, iterations = 1000
Output: [1.0, 2.0]
Solution:
The vectorized loss is
so its gradient is
Step-by-step derivation of the gradient
Let the prediction error vector be
The squared norm is the sum of squared errors:
Therefore,
Derivation by expansionβ
Expand the product:
Differentiate each term with respect to :
because is symmetric, and
The final term does not depend on :
Putting everything together:
The factor in the loss cancels the produced when differentiating the squared error.
Element-by-element interpretationβ
For parameter ,
This means:
- Compute every prediction error, .
- Multiply each error by its corresponding feature value.
- Sum across all training examples using .
- Divide by .
Stacking all parameter derivatives into one vector gives
The gradient-descent update is consequently
import numpy as np
def linear_regression_gradient_descent(X: np.ndarray, y: np.ndarray, alpha: float, iterations: int) -> np.ndarray:
"""
Perform linear regression using gradient descent.
Args:
X: Feature matrix of shape (m, n) where first column is all ones (for intercept)
y: Target vector of shape (m,)
alpha: Learning rate
iterations: Number of gradient descent iterations
Returns:
Learned weights as a 1D array of shape (n,)
"""
m, n = X.shape
y = y.reshape(-1, 1) # Ensure y is a column vector
theta = np.zeros((n, 1)) # Initialize weights to zeros
for _ in range(iterations):
predictions = X @ theta
errors = predictions - y
gradient = (X.T @ errors) / m
theta = theta - alpha * gradient
return theta.flatten()
Q&Aβ
< What is convergence? >β
- Convergence is when the loss stops improving. In practice, this is usually defined as a plateau in the validation loss, or a small enough gradient norm. It does not necessarily mean that the model has reached the global minimum of the loss function, especially in non-convex problems like deep learning.
< Is convergence to the global optimum guaranteed? >β
-
Not always.
For convex loss functions, gradient descent is guaranteed to converge to the global optimum.
However, for non-convex loss functions, such as those encountered in deep learning, convergence to a global optimum is not guaranteed. Instead, the algorithm may converge to a local minimum or saddle point. -
Convex Objectivesβ
If is convex and differentiable, every local minimum is global. Gradient descent converges to a global optimum under standard conditions, such as:
- The gradient is Lipschitz-continuous.
- The learning rate is sufficiently small, often , where is the gradient smoothness constant.
- An optimum exists.
For a smooth convex function, the typical objective-gap rate is:
If the function is also strongly convex, convergence is geometric:
-
Non-Convex Objectivesβ
For non-convex objectives, including most neural networks, global optimality is not generally guaranteed. Gradient descent can encounter:
- Multiple local minima
- Saddle points
- Flat plateaus
- Poorly conditioned regions
- Vanishing or exploding gradients
Under smoothness assumptions, a common guarantee is only convergence toward a stationary point:
A stationary point can be a local minimum, local maximum, or saddle pointβnot necessarily a global optimum.
- Multiple local minima
-
Stochastic Gradient Descentβ
Stochastic gradient descent (SGD) uses a noisy gradient estimate from a sample or mini-batch:
Its noise makes updates cheaper and can help escape some saddle points or shallow local minima. However, with a fixed learning rate, SGD often fluctuates around a solution rather than converging exactly. Suitable decreasing learning rates, such as conditions
can provide convergence guarantees under additional assumptions.
-
Practical Takeawayβ
Convex problem:
Global convergence is often guaranteed with an appropriate learning-rate schedule.Strongly convex problem:
Global convergence is usually fast and the optimum is unique.Non-convex problem:
Usually only stationary-point convergence is guaranteed.Deep learning:
There is generally no global-optimum guarantee, although overparameterization, initialization, normalization, adaptive optimizers, and SGD often produce good solutions empirically.
Crash courseβ
- Gradient descent
- (Vanilla) Gradient Descent
- STOCHASTIC Gradient Descent
- MOMENTUM Gradient Descent
Referenceβ
- An overview of gradient descent optimization algorithms (Sebastian Ruder)
- Why Momentum Really Works (Distill)