Octonote AI
Make your own →

Gradient descent, from intuition to update rule

Sunil Tiwari · Oct 12, 2026 · 2 min read

Why stepping against the gradient works, how the learning rate changes everything, and a 10-line implementation.

Gradient descent is how almost every model learns. You stand somewhere on a loss surface and repeatedly take a step downhill. The canvas sketches the loop; the note derives the rule.

The setup

We have parameters θ\theta and a loss L(θ)L(\theta) that measures how wrong the model is. We want:

θ∗=arg⁡min⁡θL(θ)\theta^{*} = \arg\min_{\theta} L(\theta)

Why the negative gradient?

A first-order Taylor expansion around θ\theta for a small step Δ\Delta:

L(θ+Δ)≈L(θ)+∇L(θ)⊤ΔL(\theta + \Delta) \approx L(\theta) + \nabla L(\theta)^{\top}\Delta

Among all steps of a fixed length, ∇L⊤Δ\nabla L^{\top}\Delta is most negative when Δ\Delta points exactly opposite the gradient. That gives the update rule:

θt+1=θt−η ∇L(θt)\theta_{t+1} = \theta_{t} - \eta \, \nabla L(\theta_{t})

Here η\eta is the learning rate, the size of each step.

A worked example

Take L(θ)=θ2L(\theta) = \theta^2, so ∇L=2θ\nabla L = 2\theta. Start at θ0=4\theta_0 = 4 with η=0.25\eta = 0.25:

θt+1=θt−0.25⋅2θt=0.5 θt  ⇒  4, 2, 1, 0.5, ⋯→0\theta_{t+1} = \theta_t - 0.25 \cdot 2\theta_t = 0.5\,\theta_t \;\Rightarrow\; 4,\ 2,\ 1,\ 0.5,\ \dots \to 0

The learning rate decides everything

  • η=0.25\eta = 0.25: halves the distance every step. Smooth convergence.
  • η=1\eta = 1: θt+1=−θt\theta_{t+1} = -\theta_t. Bounces between 4 and −4 forever.
  • η>1\eta > 1: every step overshoots further. Diverges.

For this loss, convergence needs 0<η<10 < \eta < 1. In general the bound depends on the curvature: η<2/λmax⁡\eta < 2 / \lambda_{\max} of the Hessian.

The training loop

flowchart LR
  A[Initialise θ] --> B[Compute loss L θ]
  B --> C[Compute gradient ∇L]
  C --> D[θ ← θ − η∇L]
  D --> E{Converged?}
  E -- no --> B
  E -- yes --> F[Done]

Ten lines of code

def gradient_descent(grad, theta, lr=0.1, steps=100, tol=1e-8):
    for _ in range(steps):
        step = lr * grad(theta)
        theta = theta - step
        if abs(step) < tol:
            break
    return theta

gradient_descent(lambda t: 2 * t, theta=4.0, lr=0.25)  # → ~0.0

Published with Octonote AI · Make your own