Backpropagation

How does backpropagation compute the loss gradient for a weight two layers back?

The idea

Every gradient is a product of local derivatives along a path from the loss back to that number, summed over every path that reaches it. Backpropagation computes those products once, from the loss backwards, so all of them together cost one backward pass: a small constant multiple of the forward pass, not one pass per weight.

Builds on Reverse-Mode Automatic Differentiation.

The picture

The network in the figure reads two inputs, x=[0.5, −1]x=[0.5,\,-1], passes them through three hidden units, and predicts y^≈0.128\hat y\approx0.128. The target is 0.250.25. The loss J=12(y^−y)2J=\tfrac12(\hat y-y)^2 sees only that one output, yet every weight, even one two layers back, has to learn which way to move. The figure works it out in three moves.

  1. Forward. Values flow from the inputs towards the loss. Each hidden unit adds up its weighted inputs and a bias to get zz, then squashes it with h=tanh⁡zh=\tanh z; the readout mixes the three hh into y^\hat y, and the loss compares y^\hat y with the target. Every value is kept, because the way back needs it.
  2. Local derivatives. Each edge carries one number: how much its end moves when its start moves a little. On a weight's edge it is the weight. Across a tanh it is 1−h21-h^2, near 1 while the unit sits near zero and near 0 once it saturates towards ±1\pm1. On the last edge, from y^\hat y to the loss, it is the error y^−y\hat y-y.
  3. Backward. Gradients flow the other way, starting from 1 at the loss. Crossing an edge multiplies the gradient by that edge's number. Where a node feeds several others, as each input feeds all three hidden units, the gradients coming back along the separate paths add.

So a weight's gradient is a product: the error, times each factor on the path back to the weight, times the input the weight multiplied on the way forward. A hidden unit learns only when two things hold at once: something downstream depends on it, and its own tanh still responds.

Nothing is computed twice. Each node's gradient is found once and then reused by everything behind it, which is why one backward pass delivers the gradient of every weight at once.

Predict first

The network predicts y^≈0.128\hat y \approx 0.128 but the target is 0.250.25. The readout weights from the three hidden units to y^\hat y are W2=[0.25, −0.15, 0.2]W_2 = [0.25,\ -0.15,\ 0.2]. Before you look: what signs do the gradients ∂J/∂h1\partial J/\partial h_1, ∂J/∂h2\partial J/\partial h_2, ∂J/∂h3\partial J/\partial h_3 have?

The mathematics

For a simple feed-forward network, write activations as

h0=x,zℓ=Wℓhℓ−1+bℓ,hℓ=ϕ(zℓ),h_0=x,\qquad z_\ell=W_\ell h_{\ell-1}+b_\ell,\qquad h_\ell=\phi(z_\ell),

for layers ℓ=1,…,K\ell=1,\dots,K. For one training example, use column-vector shapes:

hℓ−1∈Rnℓ−1,Wℓ∈Rnℓ×nℓ−1,bℓ,zℓ,hℓ∈Rnℓ.h_{\ell-1}\in\mathbb{R}^{n_{\ell-1}},\quad W_\ell\in\mathbb{R}^{n_\ell\times n_{\ell-1}},\quad b_\ell,z_\ell,h_\ell\in\mathbb{R}^{n_\ell}.

Let the scalar loss be

J=ℓ(hK,y).J=\ell(h_K, y).

Backpropagation tracks sensitivities flowing backward from the loss. Define

δℓ=∂J∂zℓ∈Rnℓ.\delta_\ell = \frac{\partial J}{\partial z_\ell}\in\mathbb{R}^{n_\ell}.

For the final layer,

δK=∇hKJ⊙ϕ′(zK).\delta_K = \nabla_{h_K}J \odot \phi'(z_K).

If the output layer is the identity, then hK=zKh_K=z_K and δK=∇hKJ\delta_K=\nabla_{h_K}J. For squared error J=12∥y^−y∥2J=\frac12\|\hat y-y\|^2, this gives δK=y^−y\delta_K=\hat y-y.

For earlier layers, the chain rule gives

δℓ=(Wℓ+1Tδℓ+1)⊙ϕ′(zℓ).\delta_\ell = (W_{\ell+1}^{\mathsf T}\delta_{\ell+1}) \odot \phi'(z_\ell).

Read the two factors separately. Wℓ+1Tδℓ+1=∂J/∂hℓW_{\ell+1}^{\mathsf T}\delta_{\ell+1}=\partial J/\partial h_\ell is the signal layer ℓ\ell receives from downstream: how the loss changes with its activations. ϕ′(zℓ)\phi'(z_\ell) is the local derivative: how much those activations change with their pre-activations, computed from layer ℓ\ell alone. The product ⊙\odot is taken unit by unit.

Once δℓ\delta_\ell is known, the parameter gradients are local:

∂J∂Wℓ=δℓhℓ−1T,∂J∂bℓ=δℓ.\frac{\partial J}{\partial W_\ell} = \delta_\ell h_{\ell-1}^{\mathsf T},\qquad \frac{\partial J}{\partial b_\ell}=\delta_\ell.

This is the core efficiency: the same downstream sensitivity δℓ\delta_\ell is reused to compute gradients for both parameters and earlier activations. For a scalar loss with many parameters, one backward pass computes the full gradient needed by gradient descent.

For a batch, the same local rules apply per example, then weight and bias gradients are summed or averaged across the batch dimension.

Worked pass: the notebook network

This is the network in the figure and in the Code below. It has n0=2n_0=2 inputs, n1=3n_1=3 tanh hidden units and one identity output, so K=2K=2, and the loss is J=12(y^−y)2J=\tfrac12(\hat y-y)^2. Units and inputs are counted from 1: W1[i,j]W_1[i,j] is the weight from input xjx_j into hidden unit ii, called Hii. The givens, with their shapes:

x=[0.5−1] (2×1),y=0.25,W1=[0.6−0.2−0.30.40.10.5] (3×2),b1=[0.050−0.05] (3×1),x=\begin{bmatrix}0.5\\-1\end{bmatrix}\ (2\times1),\qquad y=0.25,\qquad W_1=\begin{bmatrix}0.6&-0.2\\-0.3&0.4\\0.1&0.5\end{bmatrix}\ (3\times2),\qquad b_1=\begin{bmatrix}0.05\\0\\-0.05\end{bmatrix}\ (3\times1),
W2=[0.25−0.150.2] (1×3),b2=0.02 (1×1).W_2=\begin{bmatrix}0.25&-0.15&0.2\end{bmatrix}\ (1\times3),\qquad b_2=0.02\ (1\times1).

The forward pass keeps every value the backward pass will reuse:

z1=W1x+b1=[0.55−0.55−0.5],h1=tanh⁡(z1)=[0.500520−0.500520−0.462117],y^=W2h1+b2=0.127785,J=12(0.127785−0.25)2=0.007468.\begin{aligned} z_1&=W_1x+b_1=\begin{bmatrix}0.55\\-0.55\\-0.5\end{bmatrix},\qquad h_1=\tanh(z_1)=\begin{bmatrix}0.500520\\-0.500520\\-0.462117\end{bmatrix},\\ \hat y&=W_2h_1+b_2=0.127785,\qquad J=\tfrac12(0.127785-0.25)^2=0.007468. \end{aligned}

The output is the identity, so δ2=y^−y=−0.122215\delta_2=\hat y-y=-0.122215. It is negative: raising y^\hat y would lower the loss. Each hidden unit then gets its two factors and their product:

W2Tδ2⏟received=[−0.0305540.018332−0.024443],1−h12⏟local derivative=[0.7494800.7494800.786448],δ1=[−0.0228990.013740−0.019223].\underbrace{W_2^{\mathsf T}\delta_2}_{\text{received}}=\begin{bmatrix}-0.030554\\0.018332\\-0.024443\end{bmatrix},\qquad \underbrace{1-h_1^2}_{\text{local derivative}}=\begin{bmatrix}0.749480\\0.749480\\0.786448\end{bmatrix},\qquad \delta_1=\begin{bmatrix}-0.022899\\0.013740\\-0.019223\end{bmatrix}.

Hidden unit 1, step by step. H1 reaches the loss by one route, z1,1→h1,1→y^→Jz_{1,1}\to h_{1,1}\to\hat y\to J, through the readout weight W2[1]=0.25W_2[1]=0.25. So the signal it receives is ∂J/∂h1,1=0.25×(−0.122215)=−0.030554\partial J/\partial h_{1,1}=0.25\times(-0.122215)=-0.030554: raising h1,1h_{1,1} would lift y^\hat y toward the target and lower the loss. Its local derivative ignores everything downstream: 1−0.5005202=0.7494801-0.500520^2=0.749480, because tanh is still fairly steep at z=0.55z=0.55. The delta is the product, δ1,1=−0.030554×0.749480=−0.022899\delta_{1,1}=-0.030554\times0.749480=-0.022899.

Now the weights. H1's pre-activation is z1,1=W1[1,1] x1+W1[1,2] x2+b1[1]z_{1,1}=W_1[1,1]\,x_1+W_1[1,2]\,x_2+b_1[1], so ∂z1,1/∂W1[1,j]=xj\partial z_{1,1}/\partial W_1[1,j]=x_j: each weight's gradient is the delta times the input that weight multiplied. Row 1 of the gradient is

∂J∂W1[1,:]=δ1,1 xT=−0.022899×[0.5−1]=[−0.0114500.022899].\frac{\partial J}{\partial W_1[1,:]}=\delta_{1,1}\,x^{\mathsf T}=-0.022899\times\begin{bmatrix}0.5&-1\end{bmatrix}=\begin{bmatrix}-0.011450&0.022899\end{bmatrix}.

The signs carry meaning. The first entry is negative because x1x_1 is positive, so gradient descent increases W1[1,1]W_1[1,1]. The second is positive because x2=−1x_2=-1 flips it, so descent decreases W1[1,2]W_1[1,2]. For this input both moves raise z1,1z_{1,1}, which lifts y^\hat y toward the target through the positive readout weight.

H2 and H3. H2's readout weight is negative, so its received signal is positive, 0.0183320.018332: raising h1,2h_{1,2} would push y^\hat y further below the target. Its local derivative equals H1's because h1,2=−h1,1h_{1,2}=-h_{1,1} and squaring removes the sign. H3 follows the same two steps with its own numbers: received −0.024443-0.024443, local derivative 0.7864480.786448 at z=−0.5z=-0.5, delta −0.019223-0.019223. Its gradient row is left for you to finish in the practice below.

The same deltas give ∂J/∂b1=δ1\partial J/\partial b_1=\delta_1, the readout gradient ∂J/∂W2=δ2h1T=[−0.061171, 0.061171, 0.056478]\partial J/\partial W_2=\delta_2h_1^{\mathsf T}=[-0.061171,\ 0.061171,\ 0.056478] and the signal passed to the input, ∂J/∂x=W1Tδ1=[−0.019784, 0.000464]T\partial J/\partial x=W_1^{\mathsf T}\delta_1=[-0.019784,\ 0.000464]^{\mathsf T}. You can check any entry by nudging one parameter: the central difference (J(θ+ε)−J(θ−ε))/2ε\big(J(\theta+\varepsilon)-J(\theta-\varepsilon)\big)/2\varepsilon with ε=10−6\varepsilon=10^{-6} matches it.

A weight used in two places

In this network each weight is used once. When a value is used by several later operations, as a weight tied across positions or an input feeding several units is, each use contributes its own term, and the terms add; Baydin et al. (2018, Section 3.2) show the same accumulation for an input that reaches the output through two intermediate values. A two-branch graph makes it concrete:

a=wx,b=w+s x,y=ab,L=12(y−t)2,dLdw=aˉ x+bˉ,dLdx=aˉ w+s bˉ,a=wx,\qquad b=w+s\,x,\qquad y=ab,\qquad L=\tfrac12(y-t)^2, \qquad \frac{dL}{dw}=\bar a\,x+\bar b,\qquad \frac{dL}{dx}=\bar a\,w+s\,\bar b,

with vˉ=∂L/∂v\bar v=\partial L/\partial v, so yˉ=y−t\bar y=y-t, aˉ=yˉ b\bar a=\bar y\,b and bˉ=yˉ a\bar b=\bar y\,a. Take s=1s=1, w=3w=3, x=2x=2 and t=20t=20. Forward, a=6a=6, b=5b=5, y=30y=30 and L=50L=50; backward, yˉ=10\bar y=10, aˉ=50\bar a=50 and bˉ=60\bar b=60. Then dL/dw=100+60=160dL/dw=100+60=160 and dL/dx=150+60=210dL/dx=150+60=210; keeping only one path would give the derivative of a different graph. With s=−1s=-1 and t=1t=1 instead, yˉ=5\bar y=5, aˉ=5\bar a=5 and bˉ=30\bar b=30, so dL/dw=10+30=40dL/dw=10+30=40 while dL/dx=15−30=−15dL/dx=15-30=-15: the two paths to xx now partly cancel. Both the branch and the target changed between the two cases, so they do not compare one variable; the rule of adding every path's contribution is the same in both. The practice below works both cases.

Try it

First a worked example, then one to finish, then problems on your own. Check your answer before you look at the solution. Answers typed here are not kept when you leave.

  1. 1 · Worked example

    One weight row, by hand

    The figure's network: x=[0.5, −1]x = [0.5,\ -1], target y=0.25y = 0.25, prediction y^=0.127785\hat y = 0.127785. Hidden unit H1 has activation h1=0.500520h_1 = 0.500520 and readout weight W2[1]=0.25W_2[1] = 0.25. Find the gradients of the two weights coming into H1, ∂J/∂W1[1,:]\partial J/\partial W_1[1,:].

    1. Error. ∂J/∂y^=y^−y=0.127785−0.25=−0.122215\partial J/\partial \hat y = \hat y - y = 0.127785 - 0.25 = -0.122215.

    Say the next step to yourself first.
  2. 2 · Finish it

    Finish H3's weight

    Same network. H3 has readout weight W2[3]=0.2W_2[3] = 0.2 and activation h3=−0.462117h_3 = -0.462117. The first two steps are done. What is ∂J/∂W1[3,2]\partial J/\partial W_1[3,2], the gradient of the weight from x2=−1x_2 = -1 into H3? Give four decimal places.

    1. Across the readout edge. ∂J/∂h3=−0.122215×0.2=−0.024443\partial J/\partial h_3 = -0.122215 \times 0.2 = -0.024443.

    2. The local derivative. 1−h32=1−(−0.462117)2=0.7864481 - h_3^2 = 1 - (-0.462117)^2 = 0.786448.

    3. Your turn.

  3. 3 · On your own

    Three paths into one input

    Input x2x_2 feeds all three hidden units. The hidden units' gradients are ∂J/∂z=[−0.022899, 0.013740, −0.019223]\partial J/\partial z = [-0.022899,\ 0.013740,\ -0.019223], and the weights leaving x2x_2 are W1[:,2]=[−0.2, 0.4, 0.5]W_1[:,2] = [-0.2,\ 0.4,\ 0.5]. Find ∂J/∂x2\partial J/\partial x_2 to six decimal places.

  4. 4 · Finish it

    One weight, used twice

    A smaller graph, where one parameter feeds two branches: a=wxa = wx, b=w+xb = w + x, y=aby = ab and L=12(y−t)2L = \tfrac12(y - t)^2, with w=3w = 3, x=2x = 2 and target t=20t = 20. The first two steps are done. What is dL/dwdL/dw?

    1. Forward. a=6a = 6, b=5b = 5, y=30y = 30 and L=12(30−20)2=50L = \tfrac12(30 - 20)^2 = 50.

    2. Back to the two branches. yˉ=y−t=10\bar y = y - t = 10, then aˉ=yˉ b=50\bar a = \bar y\,b = 50 and bˉ=yˉ a=60\bar b = \bar y\,a = 60.

    3. Your turn.

  5. 5 · On your own

    Change the branch, and the paths partly cancel

    Same w=3w = 3 and x=2x = 2, but now the second branch is b=w−xb = w - x and the target is t=1t = 1. What is dL/dxdL/dx?

  6. 6 · On your own

    A louder signal that gets through less

    Change one weight: W1[3,2]W_1[3,2] goes from 0.50.5 to 2.52.5, so z3=−2.5z_3 = -2.5 and H3 is deep in tanh's flat tail. The prediction falls further from the target, and the gradient arriving at h3h_3 almost doubles, from −0.024-0.024 to −0.045-0.045. What happens to ∂J/∂z3\partial J/\partial z_3, H3's own learning signal?

    Choose one

The code

import numpy as np

# The notebook network: separate numbers from the interactive Cases A/B/C.
# Shapes (column vectors):
# x: (2, 1), W1: (3, 2), b1: (3, 1)
# W2: (1, 3), b2: (1, 1), y: (1, 1)
x = np.array([[0.5], [-1.0]])
y = np.array([[0.25]])

W1 = np.array([[0.6, -0.2],
               [-0.3, 0.4],
               [0.1, 0.5]])
b1 = np.array([[0.05], [0.0], [-0.05]])

W2 = np.array([[0.25, -0.15, 0.2]])
b2 = np.array([[0.02]])

# Forward pass: store what the backward pass reuses
z1 = W1 @ x + b1            # (3, 1) pre-activations
h1 = np.tanh(z1)            # (3, 1) hidden activations
z2 = W2 @ h1 + b2           # (1, 1)
pred = z2                   # identity output, y-hat
loss = 0.5 * float(np.sum((pred - y) ** 2))

# Backward pass
delta2 = pred - y           # dJ/dz2, (1, 1)
dW2 = delta2 @ h1.T         # (1, 3)
db2 = delta2

dh1 = W2.T @ delta2         # received signal dJ/dh1, (3, 1)
phi_prime = 1 - h1 ** 2     # local derivative tanh'(z1), (3, 1)
delta1 = dh1 * phi_prime    # dJ/dz1 = received * local, (3, 1)
dW1 = delta1 @ x.T          # (3, 1) @ (1, 2) -> (3, 2)
db1 = delta1
dx = W1.T @ delta1          # input cotangent, (2, 1)


def show(name, value):
    print(f"{name:<10}", np.round(np.ravel(value), 6))


print("loss:", round(loss, 6))
for name, value in [("z1", z1), ("h1", h1), ("pred", pred), ("delta2", delta2),
                    ("dh1", dh1), ("phi_prime", phi_prime), ("delta1", delta1)]:
    show(name, value)
show("dW1 row 1", dW1[0])

# Row 3 (Python index 2): hidden unit 3's delta times the input row x^T
row3 = delta1[2, 0] * x.T   # (1, 2)
show("dW1 row 3", row3)
assert np.allclose(row3, dW1[2])

show("dW2", dW2)
show("dx", dx)
print("hidden signal shape:", delta1.shape)
print("first-layer gradient shape:", dW1.shape)
print("input cotangent shape:", dx.shape)

It prints the same named values as the worked pass, in this order: loss, z1, h1, pred for y^\hat y, delta2, dh1 for the received signal W2Tδ2W_2^{\mathsf T}\delta_2, phi_prime for the local derivative 1−h121-h_1^2, delta1, row 1 of dW1, H3's row delta1[2, 0] * x.T checked against dW1[2], then dW2, dx and the three shapes. Python counts from 0, so H3 is index 2. That row answers the H3 exercise above, so try it first.

This tiny network has one hidden layer, but it shows the recurrence: delta2 moves through W2.T, becomes delta1 after the tanh derivative, and then produces both dW1 and dx. A deeper network repeats those lines once per layer, from the loss back to the input.

Keep it

  1. How do you get the gradient of the loss with respect to one weight deep inside a network?

    Answer from memory, then check

    Multiply the local derivatives on the path from the loss back to that weight: the error, then each edge's factor (a weight, or an activation's slope), ending with the input the weight multiplied.

  2. A node feeds several later nodes. How is its gradient formed?

    Answer from memory, then check

    Add the contributions from every path back to the loss, one product per path. Paths with opposite signs can cancel, so a small total does not mean nothing flows through.

  3. One weight is used in two places in the forward pass. How is its gradient formed?

    Answer from memory, then check

    One contribution per use, each the gradient arriving at that use times the local derivative there, then add them. Tied weights get their gradient this way.

  4. Why does a saturated tanh unit barely learn, even when a large gradient reaches it?

    Answer from memory, then check

    Its local derivative 1−h21 - h^2 is nearly zero when hh is near ±1\pm 1. Everything passing back through the unit, including its incoming weights' gradients, is multiplied by that tiny factor.

  5. Why does computing every gradient take one backward pass, not one pass per parameter?

    Answer from memory, then check

    Going backwards from a single loss, each node's gradient is computed once and reused by everything behind it. Each edge is crossed once on the way back, with a fixed amount of arithmetic, so the backward pass costs a small constant multiple of the forward pass however many parameters there are.

  6. The prediction lands exactly on the target. What are the gradients?

    Answer from memory, then check

    All zero. Every path back from the loss starts with the factor y^−y\hat y - y.

Recalling an answer from memory makes it last longer than rereading it (Roediger and Karpicke, 2006). Add these 6 cards and they come back tomorrow, then after gaps of 3, 7, 16, 35 and 75 days while you still remember them. They stay in this browser only.

The edge

As an algorithm, backpropagation is settled: it is the chain rule, evaluated from the loss backwards so that each intermediate result is computed once. Two questions around it are not.

Brains learn, but a neuron has no obvious way to send an exact error backwards through the same synapses it used going forward. Whether the brain approximates backpropagation, and how, is argued over (Lillicrap et al., 2020, “Backpropagation and the brain”). One surprise from that line of work: fixed random backward weights, in place of the transposed forward ones, still let a network learn (Lillicrap et al., 2016).

The other question is why following these gradients works so well at all. The loss of a deep network is far from a simple bowl, yet small steps downhill reliably find good solutions, and a full explanation is still missing.

Next thoughtNow every weight knows which way is downhill. How far should it step, and what goes wrong if the step is too big?Gradient Descent →
The full worked trace: the network step by step, a saturated variant, and three new networks to predict

Limits of this page

  • The weights are chosen by hand so the arithmetic stays visible. Nothing on this page is trained.
  • One example, three tanh units and a squared-error loss. With a batch, the same per-example gradients are summed or averaged.
  • The figure keeps both biases fixed; only the inputs, the weights and the target move.
  • A gradient says which way lowers the loss for this one example. How far to move is the optimizer's decision.
  • The Python runs on your machine, not in the page.

Sources

  1. Rumelhart, Hinton, and Williams (1986). Learning representations by back-propagating errors.

    Nature 323, 533–536. Adjusts the weights of hidden units by propagating error signals backwards; the paper that made the method widely known, though earlier forms exist (Linnainmaa 1970; Werbos 1974).

  2. Baydin et al. (2018). Automatic differentiation in machine learning: a survey.

    Journal of Machine Learning Research 18(153), 1–43. Shows backpropagation as a special case of reverse-mode automatic differentiation on a computation graph.

  3. Goodfellow, Bengio, and Courville (2016). Deep Learning.

    MIT Press. Section 6.5 derives back-propagation on computational graphs and shows that the gradient costs the same order of computation as the forward pass.

  4. Lillicrap et al. (2016). Random synaptic feedback weights support error backpropagation for deep learning.

    Nature Communications 7, 13276. Networks still learn when fixed random weights replace the transposed forward weights in the backward pass.

  5. Lillicrap et al. (2020). Backpropagation and the brain.

    Nature Reviews Neuroscience 21, 335–346. Reviews whether and how the brain could approximate backpropagation.

What the claims rest on

Central claim: Backpropagation applies reverse-mode autodiff to neural networks so one scalar loss can train many parameters.

Each claim below lists the passages it cites and how far it has been checked against them. These are the site’s own checks, not independent replication.

Claim (checked against the cited passages): Backpropagation computes neural-network gradients by storing needed forward-pass values, then applying the chain rule backward from a scalar loss: each layer receives a downstream sensitivity, combines it with its local derivatives, and reuses that signal to form parameter gradients in one reverse pass.

Sources: Learning representations by back-propagating errors; Automatic differentiation in machine learning: a survey

What the sources support: Rumelhart, Hinton, and Williams describe back-propagating error signals to adjust hidden-unit weights; Baydin et al. frame backpropagation as reverse-mode automatic differentiation on computation graphs for efficient derivative evaluation.

On this page: the note on Learning representations by back-propagating errors, the note on Automatic differentiation in machine learning: a survey, Equation 1, Code example 1, the figure

Caveat: Checks the differentiable feed-forward scalar-loss mechanism, not optimizer choice, biological plausibility, recurrent/dynamic variants, full batching, nonsmooth primitives, or stability. Reverse-mode systems may save values directly or recover some through checkpointing.

Connections

Builds on Reverse-Mode Automatic Differentiation.

Leads to Gradient Descent, SGD and Momentum, Adam Optimizer, Gradient Clipping & Explosion Prevention and Residual Connections & Skip Connections.

Cite this page

Continuous Function. “Backpropagation.” Revised 2026-10-09. https://continuousfunction.ai/domains/calculus/backpropagation/

BibTeX
@misc{cf-backpropagation,
  title = {Backpropagation},
  author = {{Continuous Function}},
  year = {2026},
  note = {Revised 2026-10-09},
  url = {https://continuousfunction.ai/domains/calculus/backpropagation/}
}