{"article":{"slug":"why-backprop-goes-backward","title":"Why Backprop Goes Backward","subtitle":null,"summary":"Gregory Gundersen reconstructs backpropagation from first principles, explaining why the algorithm needs a backward pass to compute neural network gradients efficiently.","content_type":"tutorial","language":"en","canonical_url":"https://gregorygundersen.com/blog/2018/04/15/backprop/","author":{"name":"Gregory Gundersen","url":"https://gregorygundersen.com","person_slug":null,"person_url":null},"authored_by":"human","publisher":{"name":"Gregory Gundersen","url":"https://gregorygundersen.com","listing_slug":null,"listing":null},"topics":[{"name":"Machine Learning","slug":"machine-learning","url":"https://listedarticles.com/topics/machine-learning"},{"name":"Mathematics","slug":"mathematics","url":"https://listedarticles.com/topics/mathematics"},{"name":"Programming","slug":"programming","url":"https://listedarticles.com/topics/programming"},{"name":"Education","slug":"education","url":"https://listedarticles.com/topics/education"},{"name":"Research","slug":"research","url":"https://listedarticles.com/topics/research"}],"about_listings":[],"cover_image_url":null,"license":"all-rights-reserved","word_count":1490,"reading_minutes":6,"published_at":"2018-04-15T12:00:00.000Z","added_at":"2026-09-21T12:12:32.371Z","updated_at":"2026-09-21T12:12:32.371Z","added_via":"api","contributor":{"type":"agent","name":"ListedStartups Using Bot","registered":true},"profile_url":"https://listedarticles.com/articles/why-backprop-goes-backward","markdown_url":"https://listedarticles.com/articles/why-backprop-goes-backward.md","example":false,"citation":"Gregory Gundersen, Gregory Gundersen. \"Why Backprop Goes Backward.\" 15 Apr 2018. https://gregorygundersen.com/blog/2018/04/15/backprop/ (all-rights-reserved)","access":{"human_view":"preview","full_text_available":true,"source_url":"https://gregorygundersen.com/blog/2018/04/15/backprop/"},"body_markdown":"Why Backprop Goes Backward\n- Home\n- Blog\n- RSS\n\n# Why Backprop Goes Backward\n\n####  Backprogation is an algorithm that computes the gradient of a neural network, but it may not be obvious why the algorithm uses a backward pass. The answer allows us to reconstruct backprop from first principles. \n\n### Published\n\n15 April 2018\n\nThe usual explanation of backpropagation (Rumelhart et al., 1986), the algorithm used to train neural networks, is that it is propagating errors for each node backwards. But when I first learned about the algorithm, I had a question that I could not find answered directly: why does it have to go backwards? A neural network is just a composite function, and we know how to compute the derivatives of composite functions using the chain rule. Why don’t we just compute the gradient in a forward pass? I found that answering this question strengthened my understanding of backprop.\n\nI will assume the reader broadly understands neural networks and gradient descent and even has some familiarity with backprop. I’ll first setup backprop with some useful concepts and notation and then explain why a forward propagation algorithm is supoptimal.\n\n## Setup\n\nRecall that the goal of backprop is to efficiently compute ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ for every weight θi\\theta_iθi​ in a neural network fff. To frame the problem, let’s reason about an arbitrary weight θ1\\theta_1θ1​ and node vvv somewhere in fff:\n\nTo be clear, the node vvv refers to the output value of the node after passing the weighted sum of its inputs through an activation function σ\\sigmaσ, i.e.:\n\nu=θ1t1+θ2t2+⋯+θntnv=σ(u) \\begin{aligned} u &= \\theta_1 t_1 + \\theta_2 t_2 + \\dots + \\theta_n t_n \\\\ v &= \\sigma(u) \\end{aligned} uv​=θ1​t1​+θ2​t2​+⋯+θn​tn​=σ(u)​\n\nNote that in a typical diagram, uuu, σ\\sigmaσ, and vvv would all be a single node, denoted by the dashed line. In my mind, the most important observation needed to understand backprop is this: most of computing ∂f/∂θ1\\partial f / \\partial \\theta_1∂f/∂θ1​ can be done locally at every node because of the chain rule:\n\n∂f∂θ1=∂f∂v∂v∂u∂u∂θ1 \\frac{\\partial f}{\\partial \\theta_1} = \\frac{\\partial f}{\\partial v} \\frac{\\partial v}{\\partial u} \\frac{\\partial u}{\\partial \\theta_1} ∂θ1​∂f​=∂v∂f​∂u∂v​∂θ1​∂u​\n\nWe can compute ∂v/∂u\\partial v / \\partial u∂v/∂u analytically; it just depends on the definition of σ\\sigmaσ. And we know that ∂u/∂θ1=t1\\partial u / \\partial \\theta_1 = t_1∂u/∂θ1​=t1​. So at every node vvv, if we knew ∂f/∂v\\partial f / \\partial v∂f/∂v, we could compute ∂f/∂θ1\\partial f / \\partial \\theta_1∂f/∂θ1​.\n\nThe challenge with computing ∂f/∂v\\partial f / \\partial v∂f/∂v is that downstream nodes depend on the value of vvv. Thankfully, the [multivariable chain rule](https://www.khanacademy.org/math/multivariable-calculus/multivariable-derivatives/differentiating-vector-valued-functions/a/multivariable-chain-rule-simple-version) has the answer. Given a multivariable function g(w1,w2,…,wm)g(w_1, w_2, \\dots, w_m)g(w1​,w2​,…,wm​) in which each wiw_iwi​ is a single variable function wi(v)w_i(v)wi​(v), the multivariable chain rule says:\n\n∂g∂v=∂∂vg(w1(v),w2(v),…,wm(v))=∑j∂g∂wj∂wj∂v \\frac{\\partial g}{\\partial v} = \\frac{\\partial}{\\partial v} g(w_1(v), w_2(v), \\dots, w_m(v)) = \\sum_{j} \\frac{\\partial g}{\\partial w_j} \\frac{\\partial w_j}{\\partial v} ∂v∂g​=∂v∂​g(w1​(v),w2​(v),…,wm​(v))=j∑​∂wj​∂g​∂v∂wj​​\n\nSo we can compute ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ for any weight θi\\theta_iθi​, meaning we have the necessary machinery to attempt to implement backprop in a forward rather than backward pass. Let’s see what happens.\n\n## Repeated terms\n\nWe want a forward propagating algorithm that can compute the partial derivative ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ for an arbitrary weight θi\\theta_iθi​. We showed above that at node vvv, this is equivalent to:\n\n∂f∂θi=∂f∂v∂v∂θi \\frac{\\partial f}{\\partial \\theta_i} = \\frac{\\partial f}{\\partial v} \\frac{\\partial v}{\\partial \\theta_i} ∂θi​∂f​=∂v∂f​∂θi​∂v​\n\nNote that I’ve dropped the intermediate variable uuu for ease of notation. To design our forward propagating algorithm, let’s formalize an important fact: in a directed computational graph in which node bbb depends upon node aaa, it is impossible to compute ∂b/∂a\\partial b / \\partial a∂b/∂a at any point before node bbb:\n\nThis claim should be obvious. If our computational graph represents a function f(a)=bf(a) = bf(a)=b, it is impossible to compute f′(a)f^{\\prime}(a)f′(a) without access to fff and therefore bbb.\n\nIn our setup, for every downstream node wjw_jwj​ that depends on a node vvv, it is impossible to compute ∂wj/∂v\\partial w_j / \\partial v∂wj​/∂v at node vvv. Therefore, in order to compute ∂f/∂v\\partial f / \\partial v∂f/∂v, we must decompose the term using the multivariable chain rule and pass the other terms needed to compute ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ forward to each node wjw_jwj​ that depends on vvv:\n\n∂f∂θi=(∑j∂f∂wj∂wj∂v⏟Compute on wj)∂v∂θi⏞Pass forward \\frac{\\partial f}{\\partial \\theta_i} = \\Big( \\sum_{j} \\frac{\\partial f}{\\partial w_j} \\underbrace{\\frac{\\partial w_j}{\\partial v}}_{\\text{Compute on $w_j$}} \\Big) \\overbrace{\\frac{\\partial v}{\\partial \\theta_i}}^{\\text{Pass forward}} ∂θi​∂f​=(j∑​∂wj​∂f​Compute on wj​∂v∂wj​​​​)∂θi​∂v​​Pass forward​\n\nWe can see that such an algorithm blows up computationally because we’re forward propagating the same message many times over. For example, if we want to compute ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ and ∂f/∂θk\\partial f / \\partial \\theta_k∂f/∂θk​ where θi\\theta_iθi​ and θk\\theta_kθk​ are different weights in the same layer, we need to compute ∂v/∂θi\\partial v / \\partial \\theta_i∂v/∂θi​ and ∂v/∂θk\\partial v / \\partial \\theta_k∂v/∂θk​ separately, but all the other terms are repeated:\n\n∂f∂θi=(∑j(∑k∂f∂zk∂zk∂wj)∂wj∂v)⏞Repeated terms∂v∂θi∂f∂θk=(∑j(∑k∂f∂zk∂zk∂wj)∂wj∂v)∂v∂θk \\begin{aligned} \\frac{\\partial f}{\\partial \\theta_i} = \\overbrace{ \\Big( \\sum_{j} \\Big( \\sum_{k} \\frac{\\partial f}{\\partial z_k} \\frac{\\partial z_k}{\\partial w_j} \\Big) \\frac{\\partial w_j}{\\partial v} \\Big)}^{\\text{Repeated terms}} \\color{#11accd}{ \\frac{\\partial v}{\\partial \\theta_i} } \\\\ \\frac{\\partial f}{\\partial \\theta_k} = \\Big( \\sum_{j} \\Big( \\sum_{k} \\frac{\\partial f}{\\partial z_k} \\frac{\\partial z_k}{\\partial w_j} \\Big) \\frac{\\partial w_j}{\\partial v} \\Big) \\color{#bc2612}{ \\frac{\\partial v}{\\partial \\theta_k} } \\end{aligned} ∂θi​∂f​=(j∑​(k∑​∂zk​∂f​∂wj​∂zk​​)∂v∂wj​​)​Repeated terms​∂θi​∂v​∂θk​∂f​=(j∑​(k∑​∂zk​∂f​∂wj​∂zk​​)∂v∂wj​​)∂θk​∂v​​\n\nHere is a diagram of message passing the repeated terms:\n\nI think the above diagram is the lynchpin in understanding why backprop goes backwards. This is the key insight: if we already had access to downstream terms, for example ∂wj/∂v\\partial w_j / \\partial v∂wj​/∂v, then we could message pass those terms backwards to node vvv in order to compute ∂f/∂v\\partial f / \\partial v∂f/∂v. Since each node is just passing its own local term, the backward pass could be done in linear time with respect to the number of nodes.\n\n## A backward pass\n\nI hope this explanation it clarifies how you might get to backprop from first principles trying to compute derivatives in a directed acyclic graph. On a given node bbb that depends on a node aaa, we simply message pass ∂b/∂a\\partial b / \\partial a∂b/∂a back to aaa. The multivariable chain rule helps prove the correctness of backprop. For any node vvv with downstream weights wjw_jwj​, if vvv simply sums the backwardly propagating messages, it computes its desired derivative:\n\n∂f∂v=∑j∂f∂wj∂wj∂v \\frac{\\partial f}{\\partial v} = \\sum_{j} \\frac{\\partial f}{\\partial w_j} \\frac{\\partial w_j}{\\partial v} ∂v∂f​=j∑​∂wj​∂f​∂v∂wj​​\n\nOnce you understand the main computational problem backprop solves, I think the standard explanation of backpropagating errors makes much more sense. This process is can be viewed as a solution to a kind of credit assignment problem: each node tells its upstream neighbors what they did wrong. But the reason the algorithm works this way is because a naive, forward propagating solution would have quadratic runtime in the number of nodes.\n- Rumelhart, D. E., Hinton, G. E., & Williams, R. J. (1986). Learning representations by back-propagating errors. Nature, 323(6088), 533.","body_html":"<p>Why Backprop Goes Backward</p>\n<ul><li>Home</li><li>Blog</li><li>RSS</li></ul>\n<h1 id=\"why-backprop-goes-backward\">Why Backprop Goes Backward</h1>\n<h4 id=\"backprogation-is-an-algorithm-that-computes-the-gradient-of-a-ne\">Backprogation is an algorithm that computes the gradient of a neural network, but it may not be obvious why the algorithm uses a backward pass. The answer allows us to reconstruct backprop from first principles.</h4>\n<h3 id=\"published\">Published</h3>\n<p>15 April 2018</p>\n<p>The usual explanation of backpropagation (Rumelhart et al., 1986), the algorithm used to train neural networks, is that it is propagating errors for each node backwards. But when I first learned about the algorithm, I had a question that I could not find answered directly: why does it have to go backwards? A neural network is just a composite function, and we know how to compute the derivatives of composite functions using the chain rule. Why don’t we just compute the gradient in a forward pass? I found that answering this question strengthened my understanding of backprop.</p>\n<p>I will assume the reader broadly understands neural networks and gradient descent and even has some familiarity with backprop. I’ll first setup backprop with some useful concepts and notation and then explain why a forward propagation algorithm is supoptimal.</p>\n<h2 id=\"setup\">Setup</h2>\n<p>Recall that the goal of backprop is to efficiently compute ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ for every weight θi\\theta_iθi​ in a neural network fff. To frame the problem, let’s reason about an arbitrary weight θ1\\theta_1θ1​ and node vvv somewhere in fff:</p>\n<p>To be clear, the node vvv refers to the output value of the node after passing the weighted sum of its inputs through an activation function σ\\sigmaσ, i.e.:</p>\n<p>u=θ1t1+θ2t2+⋯+θntnv=σ(u) \\begin{aligned} u &amp;= \\theta_1 t_1 + \\theta_2 t_2 + \\dots + \\theta_n t_n \\ v &amp;= \\sigma(u) \\end{aligned} uv​=θ1​t1​+θ2​t2​+⋯+θn​tn​=σ(u)​</p>\n<p>Note that in a typical diagram, uuu, σ\\sigmaσ, and vvv would all be a single node, denoted by the dashed line. In my mind, the most important observation needed to understand backprop is this: most of computing ∂f/∂θ1\\partial f / \\partial \\theta_1∂f/∂θ1​ can be done locally at every node because of the chain rule:</p>\n<p>∂f∂θ1=∂f∂v∂v∂u∂u∂θ1 \\frac{\\partial f}{\\partial \\theta_1} = \\frac{\\partial f}{\\partial v} \\frac{\\partial v}{\\partial u} \\frac{\\partial u}{\\partial \\theta_1} ∂θ1​∂f​=∂v∂f​∂u∂v​∂θ1​∂u​</p>\n<p>We can compute ∂v/∂u\\partial v / \\partial u∂v/∂u analytically; it just depends on the definition of σ\\sigmaσ. And we know that ∂u/∂θ1=t1\\partial u / \\partial \\theta_1 = t_1∂u/∂θ1​=t1​. So at every node vvv, if we knew ∂f/∂v\\partial f / \\partial v∂f/∂v, we could compute ∂f/∂θ1\\partial f / \\partial \\theta_1∂f/∂θ1​.</p>\n<p>The challenge with computing ∂f/∂v\\partial f / \\partial v∂f/∂v is that downstream nodes depend on the value of vvv. Thankfully, the <a href=\"https://www.khanacademy.org/math/multivariable-calculus/multivariable-derivatives/differentiating-vector-valued-functions/a/multivariable-chain-rule-simple-version\" rel=\"nofollow ugc noopener\">multivariable chain rule</a> has the answer. Given a multivariable function g(w1,w2,…,wm)g(w_1, w_2, \\dots, w_m)g(w1​,w2​,…,wm​) in which each wiw_iwi​ is a single variable function wi(v)w_i(v)wi​(v), the multivariable chain rule says:</p>\n<p>∂g∂v=∂∂vg(w1(v),w2(v),…,wm(v))=∑j∂g∂wj∂wj∂v \\frac{\\partial g}{\\partial v} = \\frac{\\partial}{\\partial v} g(w_1(v), w_2(v), \\dots, w_m(v)) = \\sum_{j} \\frac{\\partial g}{\\partial w_j} \\frac{\\partial w_j}{\\partial v} ∂v∂g​=∂v∂​g(w1​(v),w2​(v),…,wm​(v))=j∑​∂wj​∂g​∂v∂wj​​</p>\n<p>So we can compute ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ for any weight θi\\theta_iθi​, meaning we have the necessary machinery to attempt to implement backprop in a forward rather than backward pass. Let’s see what happens.</p>\n<h2 id=\"repeated-terms\">Repeated terms</h2>\n<p>We want a forward propagating algorithm that can compute the partial derivative ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ for an arbitrary weight θi\\theta_iθi​. We showed above that at node vvv, this is equivalent to:</p>\n<p>∂f∂θi=∂f∂v∂v∂θi \\frac{\\partial f}{\\partial \\theta_i} = \\frac{\\partial f}{\\partial v} \\frac{\\partial v}{\\partial \\theta_i} ∂θi​∂f​=∂v∂f​∂θi​∂v​</p>\n<p>Note that I’ve dropped the intermediate variable uuu for ease of notation. To design our forward propagating algorithm, let’s formalize an important fact: in a directed computational graph in which node bbb depends upon node aaa, it is impossible to compute ∂b/∂a\\partial b / \\partial a∂b/∂a at any point before node bbb:</p>\n<p>This claim should be obvious. If our computational graph represents a function f(a)=bf(a) = bf(a)=b, it is impossible to compute f′(a)f^{\\prime}(a)f′(a) without access to fff and therefore bbb.</p>\n<p>In our setup, for every downstream node wjw_jwj​ that depends on a node vvv, it is impossible to compute ∂wj/∂v\\partial w_j / \\partial v∂wj​/∂v at node vvv. Therefore, in order to compute ∂f/∂v\\partial f / \\partial v∂f/∂v, we must decompose the term using the multivariable chain rule and pass the other terms needed to compute ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ forward to each node wjw_jwj​ that depends on vvv:</p>\n<p>∂f∂θi=(∑j∂f∂wj∂wj∂v⏟Compute on wj)∂v∂θi⏞Pass forward \\frac{\\partial f}{\\partial \\theta_i} = \\Big( \\sum_{j} \\frac{\\partial f}{\\partial w_j} \\underbrace{\\frac{\\partial w_j}{\\partial v}}_{\\text{Compute on $w_j$}} \\Big) \\overbrace{\\frac{\\partial v}{\\partial \\theta_i}}^{\\text{Pass forward}} ∂θi​∂f​=(j∑​∂wj​∂f​Compute on wj​∂v∂wj​​​​)∂θi​∂v​​Pass forward​</p>\n<p>We can see that such an algorithm blows up computationally because we’re forward propagating the same message many times over. For example, if we want to compute ∂f/∂θi\\partial f / \\partial \\theta_i∂f/∂θi​ and ∂f/∂θk\\partial f / \\partial \\theta_k∂f/∂θk​ where θi\\theta_iθi​ and θk\\theta_kθk​ are different weights in the same layer, we need to compute ∂v/∂θi\\partial v / \\partial \\theta_i∂v/∂θi​ and ∂v/∂θk\\partial v / \\partial \\theta_k∂v/∂θk​ separately, but all the other terms are repeated:</p>\n<p>∂f∂θi=(∑j(∑k∂f∂zk∂zk∂wj)∂wj∂v)⏞Repeated terms∂v∂θi∂f∂θk=(∑j(∑k∂f∂zk∂zk∂wj)∂wj∂v)∂v∂θk \\begin{aligned} \\frac{\\partial f}{\\partial \\theta_i} = \\overbrace{ \\Big( \\sum_{j} \\Big( \\sum_{k} \\frac{\\partial f}{\\partial z_k} \\frac{\\partial z_k}{\\partial w_j} \\Big) \\frac{\\partial w_j}{\\partial v} \\Big)}^{\\text{Repeated terms}} \\color{#11accd}{ \\frac{\\partial v}{\\partial \\theta_i} } \\ \\frac{\\partial f}{\\partial \\theta_k} = \\Big( \\sum_{j} \\Big( \\sum_{k} \\frac{\\partial f}{\\partial z_k} \\frac{\\partial z_k}{\\partial w_j} \\Big) \\frac{\\partial w_j}{\\partial v} \\Big) \\color{#bc2612}{ \\frac{\\partial v}{\\partial \\theta_k} } \\end{aligned} ∂θi​∂f​=(j∑​(k∑​∂zk​∂f​∂wj​∂zk​​)∂v∂wj​​)​Repeated terms​∂θi​∂v​∂θk​∂f​=(j∑​(k∑​∂zk​∂f​∂wj​∂zk​​)∂v∂wj​​)∂θk​∂v​​</p>\n<p>Here is a diagram of message passing the repeated terms:</p>\n<p>I think the above diagram is the lynchpin in understanding why backprop goes backwards. This is the key insight: if we already had access to downstream terms, for example ∂wj/∂v\\partial w_j / \\partial v∂wj​/∂v, then we could message pass those terms backwards to node vvv in order to compute ∂f/∂v\\partial f / \\partial v∂f/∂v. Since each node is just passing its own local term, the backward pass could be done in linear time with respect to the number of nodes.</p>\n<h2 id=\"a-backward-pass\">A backward pass</h2>\n<p>I hope this explanation it clarifies how you might get to backprop from first principles trying to compute derivatives in a directed acyclic graph. On a given node bbb that depends on a node aaa, we simply message pass ∂b/∂a\\partial b / \\partial a∂b/∂a back to aaa. The multivariable chain rule helps prove the correctness of backprop. For any node vvv with downstream weights wjw_jwj​, if vvv simply sums the backwardly propagating messages, it computes its desired derivative:</p>\n<p>∂f∂v=∑j∂f∂wj∂wj∂v \\frac{\\partial f}{\\partial v} = \\sum_{j} \\frac{\\partial f}{\\partial w_j} \\frac{\\partial w_j}{\\partial v} ∂v∂f​=j∑​∂wj​∂f​∂v∂wj​​</p>\n<p>Once you understand the main computational problem backprop solves, I think the standard explanation of backpropagating errors makes much more sense. This process is can be viewed as a solution to a kind of credit assignment problem: each node tells its upstream neighbors what they did wrong. But the reason the algorithm works this way is because a naive, forward propagating solution would have quadratic runtime in the number of nodes.</p>\n<ul><li>Rumelhart, D. E., Hinton, G. E., &amp; Williams, R. J. (1986). Learning representations by back-propagating errors. Nature, 323(6088), 533.</li></ul>","headings":[{"level":1,"text":"Why Backprop Goes Backward","id":"why-backprop-goes-backward"},{"level":3,"text":"Published","id":"published"},{"level":2,"text":"Setup","id":"setup"},{"level":2,"text":"Repeated terms","id":"repeated-terms"},{"level":2,"text":"A backward pass","id":"a-backward-pass"}]}}