<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Logit Solutions AI</title>
    <description>The latest articles on DEV Community by Logit Solutions AI (logitsolutionsai).</description>
    <link>https://dev.to/logitsolutionsai</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Forganization%2Fprofile_image%2F15583%2Ff8b421eb-e1a4-4eaa-a081-400de38046bb.png</url>
      <title>DEV Community: Logit Solutions AI</title>
      <link>https://dev.to/logitsolutionsai</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/logitsolutionsai"/>
    <language>en</language>
    <item>
      <title>How does a rolling ball skip small bumps?</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sun, 01 Nov 2026 01:20:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/how-does-a-rolling-ball-skip-small-bumps-390d</link>
      <guid>https://dev.to/logitsolutionsai/how-does-a-rolling-ball-skip-small-bumps-390d</guid>
      <description>&lt;p&gt;Momentum, step by step: give gradient descent a memory, and it rolls past the traps that stop it.&lt;/p&gt;

&lt;p&gt;Plain gradient descent looks only at the slope under its feet. Every step is&lt;/p&gt;

&lt;p&gt;&lt;code&gt;w ← w − η ∇L(w)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and nothing else. That makes it simple, but it also makes it forgetful: the moment the ground goes flat, it stops. Momentum fixes this with one extra number per weight, a velocity that remembers the slopes it has already rolled down. The examples below follow the CS878 lectures on gradient descent and scaling the optimization, and every number comes from running the update rule.&lt;/p&gt;

&lt;h2&gt;
  
  
  The trap
&lt;/h2&gt;

&lt;p&gt;Take one weight and a loss with two dips:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;L(w) = 0.12 (w − 2.5)² − 0.55 · exp(−(w + 1)² / 0.12)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Start at A, w = −3.5, where the loss is 4.32. There is a shallow dip B at w = −0.904 (loss 0.881) and the real minimum C at w = 2.5 (loss 0). Between them sits a bump only 0.13 higher than B.&lt;/p&gt;

&lt;p&gt;Plain gradient descent with η = 0.1 takes big steps on the steep slope, smaller and smaller ones as it nears B, and by step 21 it has arrived. At B the gradient is zero, so every step after that is zero too. At step 50, at step 100, it is still in B, at a loss of 0.88.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn7n5gro5ry9qkptvnalw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fn7n5gro5ry9qkptvnalw.png" alt="Plain gradient descent stops in the shallow dip B: the gradient is zero there, so learning stops." width="485" height="676"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Plain gradient descent stops in the shallow dip B: the gradient is zero there, so learning stops.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a velocity
&lt;/h2&gt;

&lt;p&gt;Momentum keeps a velocity v and moves along it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;v_t = β v_(t−1) + ∇L(w_t)&lt;/li&gt;
&lt;li&gt;w_(t+1) = w_t − η v_t&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With β = 0.9, each step keeps 90% of the old velocity and adds the new gradient. (This is the form PyTorch uses. Lecture notes often write v = βv + (1 − β)∇L, which only rescales the learning rate.)&lt;/p&gt;

&lt;p&gt;Run it from A with the same η = 0.1. By step 6 the ball is near B and its velocity is about 6. The gradient at B is zero, but the velocity isn't, so the ball keeps going: it clears the bump at step 7, overshoots all the way to w = 4.71, swings back without ever returning to the bump, and settles in C by step 89.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpxjy0irlqj0md8j9ekl2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpxjy0irlqj0md8j9ekl2.png" alt="Momentum carries the ball over the bump; plain GD's ghost is still stuck in B." width="525" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Momentum carries the ball over the bump; plain GD's ghost is still stuck in B.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What v remembers
&lt;/h2&gt;

&lt;p&gt;Unroll the velocity and it becomes a weighted sum of every gradient so far:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;v_t = ∇L_t + β ∇L_(t−1) + β² ∇L_(t−2) + …&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The latest gradient counts fully, the one before 90%, then 81%, 73%, 66% and so on. The weights add up to 1/(1 − β) = 10, so momentum remembers about ten steps. With β = 0.1 they would be 1, 0.1, 0.01: it forgets almost at once. In practice β is usually around 0.9.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fufusrqgc09ghwsgcjjiv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fufusrqgc09ghwsgcjjiv.png" alt="Eight bars, heights β^k, sum 1/(1 − β) = 10: gradients that agree stack toward 10; gradients that flip cancel, staying within ±0.53." width="509" height="572"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Eight bars, heights β^k, sum 1/(1 − β) = 10: gradients that agree stack toward 10; gradients that flip cancel, staying within ±0.53.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Agree or cancel
&lt;/h2&gt;

&lt;p&gt;That memory does two different things depending on the gradients:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When they agree (+1, +1, +1 …), they stack: v grows 1, 1.9, 2.71, 3.44 … toward 1/(1 − β) = 10. The step grows up to ten times.&lt;/li&gt;
&lt;li&gt;When they flip sign (+1, −1, +1 …), they cancel: v goes 1, −0.1, 0.91, −0.18, 0.84, −0.25 … and settles at about ±1/(1 + β) ≈ 0.53. The step stays small.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A narrow valley
&lt;/h2&gt;

&lt;p&gt;Now two weights and a valley that is steep across and almost flat along: L = ½(w₁² + 50 w₂²), starting at (−4, 1), where the loss is 33. Count the steps until the loss drops below 0.001, with η = 0.015:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Plain GD: 298 steps.&lt;/strong&gt; A bigger rate doesn't help: at η = 0.045, each step multiplies the across direction by 1 − 0.045 · 50 = −1.25 and it blows up. So plain GD has to crawl along the floor.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Momentum (β = 0.9): 73 steps.&lt;/strong&gt; The along direction keeps agreeing, so it builds speed there. But the across direction overshoots and swings from side to side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc9elyygi0ykfoaac8tra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fc9elyygi0ykfoaac8tra.png" alt="The narrow valley: plain GD crawls along the floor; momentum is faster but swings across." width="483" height="552"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The narrow valley: plain GD crawls along the floor; momentum is faster but swings across.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Nesterov: look before you step
&lt;/h2&gt;

&lt;p&gt;Nesterov momentum changes one thing: it takes the gradient where the velocity is about to carry the weight, not where the weight is now.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;v_t = β v_(t−1) + ∇L(w_t − η β v_(t−1))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If that look-ahead point is already uphill, the gradient there points back, and the step brakes before it overshoots. On the same valley, Nesterov needs &lt;strong&gt;18 steps&lt;/strong&gt;, with almost no swing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fabpckd4vobsph63v5xqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fabpckd4vobsph63v5xqr.png" alt="Nesterov looks ahead: the gradient at the look-ahead point brakes the swing. 298 · 73 · 18." width="543" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Nesterov looks ahead: the gradient at the look-ahead point brakes the swing. 298 · 73 · 18.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in PyTorch
&lt;/h2&gt;

&lt;p&gt;Every weight in a network gets its own velocity, with the same shape as the weight. In PyTorch it is one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SGD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.015&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                      &lt;span class="n"&gt;momentum&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nesterov&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the velocity itself, with gradients that flip sign:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints &lt;code&gt;[1.0, -0.1, 0.91, -0.18, 0.84]&lt;/code&gt;. Change every g to 1 and v climbs toward 10.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Plain gradient descent has no memory: it stops wherever the slope is zero, even in a shallow dip.&lt;/li&gt;
&lt;li&gt;Momentum keeps a velocity, v = βv + ∇L, and steps along it, so it can roll through flat spots and over small bumps.&lt;/li&gt;
&lt;li&gt;v is a sum of past gradients weighted by β^k, about 1/(1 − β) = 10 steps of memory at β = 0.9.&lt;/li&gt;
&lt;li&gt;Agreeing gradients stack (up to 10×); flipping ones cancel. That is why momentum speeds up along valleys.&lt;/li&gt;
&lt;li&gt;Nesterov takes the gradient at the look-ahead point, so it brakes before overshooting: 298 → 73 → 18 steps in the narrow valley.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Why train on a few examples at a time?</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sun, 01 Nov 2026 00:50:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/why-train-on-a-few-examples-at-a-time-50dl</link>
      <guid>https://dev.to/logitsolutionsai/why-train-on-a-few-examples-at-a-time-50dl</guid>
      <description>&lt;p&gt;Stochastic and mini-batch gradient descent: why every real training loop takes small, noisy steps.&lt;/p&gt;

&lt;p&gt;Gradient descent, as we wrote it earlier in this series, has one quiet assumption. To take a single step, it looks at every training example. That is fine for four examples. It is not fine for a million.&lt;/p&gt;

&lt;p&gt;Real training never does it that way. It takes a small random handful of examples, a mini-batch, and steps on that alone. This article shows why that works, what it costs, and how it looks in PyTorch. The numbers come from a tiny worked example and from the CS878 Deep Learning slides (lectures 07-08).&lt;/p&gt;

&lt;h2&gt;
  
  
  The gradient is an average
&lt;/h2&gt;

&lt;p&gt;The loss of a model is an average over the training examples: L = (1/N) Σ ℓᵢ, where ℓᵢ is the loss on example i. A derivative of an average is the average of the derivatives, so the gradient is an average too: ∇L = (1/N) Σ ∇ℓᵢ.&lt;/p&gt;

&lt;p&gt;Take a model with two weights, ŷ = w·x, a squared loss ℓᵢ = ½(ŷᵢ − yᵢ)², and four examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;x₁ = (4, −1), y₁ = 1&lt;/li&gt;
&lt;li&gt;x₂ = (0, 1), y₂ = 3&lt;/li&gt;
&lt;li&gt;x₃ = (1, 1), y₃ = 3&lt;/li&gt;
&lt;li&gt;x₄ = (1, −1), y₄ = 1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start at w = (0, 0). There each example's gradient is −yᵢ·xᵢ, so the four arrows are (−4, 1), (0, −3), (−3, −3) and (−1, 1).&lt;/p&gt;

&lt;p&gt;Put them tip to tail and they add up to (−8, −4). Divide by four and you get the true gradient, ∇L = (−2, −1). A step with learning rate ¼ moves the other way, to w = (½, ¼).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd62p3rrc9sit1b3wut22.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd62p3rrc9sit1b3wut22.png" alt="Four examples, four arrows, added tip to tail and divided by four: the true gradient (−2, −1)." width="535" height="710"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Four examples, four arrows, added tip to tail and divided by four: the true gradient (−2, −1).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Now make it a million examples. The slides use n = 2²⁰, about a million images. Every single step must touch all million. That is a lot of work for one small move.&lt;/p&gt;

&lt;h2&gt;
  
  
  A mini-batch is a cheap, honest guess
&lt;/h2&gt;

&lt;p&gt;So take a shortcut. Shuffle the data, cut it into small batches, and average the gradients of one batch only:&lt;/p&gt;

&lt;p&gt;g_B = (1/B) Σ over i in the batch of ∇ℓᵢ&lt;/p&gt;

&lt;p&gt;With our four examples and B = 2, say the shuffle gives batches {1, 3} and {2, 4}.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Batch one: ½[(−4, 1) + (−3, −3)] = (−7/2, −1). Too long.&lt;/li&gt;
&lt;li&gt;Batch two: ½[(0, −3) + (−1, 1)] = (−1/2, −1). Too short.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One-step guesses from them would land at (7/8, ¼) and (1/8, ¼), on either side of the true landing point (½, ¼). But their average is ½[(−7/2, −1) + (−1/2, −1)] = (−2, −1), exactly the true gradient.&lt;/p&gt;

&lt;p&gt;That is the key property. Over the random choice of batch, the expected value of g_B is ∇L. The estimate is noisy, but it is &lt;strong&gt;unbiased&lt;/strong&gt;: it does not lean in any direction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6v2381njovutaidc41z4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6v2381njovutaidc41z4.png" alt="Batch one's gradient is too long, batch two's too short; their average lands exactly on the true gradient." width="539" height="693"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Batch one's gradient is too long, batch two's too short; their average lands exactly on the true gradient.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How noisy is it?
&lt;/h2&gt;

&lt;p&gt;If one example's gradient has a spread of σ around the true gradient, a batch of B examples has a spread of σ/√B (when the data set is much bigger than the batch).&lt;/p&gt;

&lt;p&gt;That square root matters. Four times the batch costs four times the compute but only halves the noise. Going from 1 to 64 examples cuts the spread by a factor of 8. Past a point, a bigger batch buys very little extra accuracy for its cost. A small batch already points the right way.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F41q7a9kw3dtug0yr0zcj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F41q7a9kw3dtug0yr0zcj.png" alt="The cloud of mini-batch gradients around the true one shrinks like σ/√B, while the cost grows like B." width="543" height="734"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The cloud of mini-batch gradients around the true one shrinks like σ/√B, while the cost grows like B.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A race on one budget
&lt;/h2&gt;

&lt;p&gt;Give three methods the same budget: one pass over 1,024 examples, called one &lt;strong&gt;epoch&lt;/strong&gt;, with the same learning rate.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full batch&lt;/strong&gt; takes one careful step. After a whole epoch it is still far from the bottom.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pure SGD&lt;/strong&gt; (B = 1) takes 1,024 shaky steps. It reaches the bottom but keeps jittering around it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mini-batch&lt;/strong&gt; (B = 64) takes 16 steady steps and ends near the bottom with only a small wobble.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a hardware reason too. A GPU computes many examples in parallel. A batch of 64 is one GPU call that keeps all its lanes busy, so the mini-batch epoch is 16 calls instead of 1,024.&lt;/p&gt;

&lt;p&gt;If you plot the loss against iterations, as the lecture does, full batch is smooth, SGD is jagged, and mini-batch sits in between. That middle ground is why mini-batch SGD is the default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm9j2le4za3t6kpqsq4el.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fm9j2le4za3t6kpqsq4el.png" alt="One pass over 1,024 examples, all three at once: full batch takes 1 step, B = 64 takes 16, B = 1 takes 1,024; a B = 64 step lights all 64 GPU lanes together." width="531" height="737"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One pass over 1,024 examples, all three at once: full batch takes 1 step, B = 64 takes 16, B = 1 takes 1,024; a B = 64 step lights all 64 GPU lanes together.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in PyTorch
&lt;/h2&gt;

&lt;p&gt;In PyTorch the batch size lives in the &lt;code&gt;DataLoader&lt;/code&gt;. One batch is one &lt;strong&gt;iteration&lt;/strong&gt;, one optimizer step. One full pass over the data is an &lt;strong&gt;epoch&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shuffle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SGD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;epoch&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;xb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yb&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;loss_fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;net&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xb&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;yb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zero_grad&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MNIST has 60,000 training images. In batches of 64 that is ⌈60,000 / 64⌉ = 938 iterations per epoch, and the last batch holds the 32 images left over. You can check it without any real data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch.utils.data&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;D&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="n"&gt;X&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;dl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dl&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dl&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="mi"&gt;938&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change 64 to 1 and you get pure SGD: 60,000 steps per epoch. Change it to 60000 and you are back to full batch: one step per epoch. The optimizer is the same &lt;code&gt;optim.SGD&lt;/code&gt; either way. The batches are what make it mini-batch SGD.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqk4yqg7y31khgkh928f4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqk4yqg7y31khgkh928f4.png" alt="The PyTorch loop: one batch of 64 images flows through the network together, and 60,000 / 64 rounds up to 938 steps per epoch." width="495" height="732"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The PyTorch loop: one batch of 64 images flows through the network together, and 60,000 / 64 rounds up to 938 steps per epoch.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Noise can even help
&lt;/h2&gt;

&lt;p&gt;At a flat saddle point the true gradient is almost zero, so full-batch descent barely moves. A mini-batch gradient keeps a little noise, and that is enough to shake the weights loose and let them roll downhill.&lt;/p&gt;

&lt;p&gt;The noise does not fix everything. In a long, narrow valley the steps still zig-zag from wall to wall. Taming that zig-zag is the job of momentum, the next idea in this series.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The loss is an average over examples, so its gradient is an average of per-example gradients.&lt;/li&gt;
&lt;li&gt;A mini-batch gradient is a cheap estimate of the true gradient. It is noisy but unbiased: on average it is exactly right.&lt;/li&gt;
&lt;li&gt;Its noise shrinks like σ/√B, so four times the batch only halves the noise at four times the cost.&lt;/li&gt;
&lt;li&gt;In one epoch, mini-batches take many cheap steps that run in parallel on a GPU, between smooth full batch and jagged pure SGD.&lt;/li&gt;
&lt;li&gt;In PyTorch, &lt;code&gt;batch_size&lt;/code&gt; in the &lt;code&gt;DataLoader&lt;/code&gt; sets it: 60,000 images in batches of 64 is 938 steps per epoch.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Too big, it explodes. Too small, it crawls.</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sun, 01 Nov 2026 00:20:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/too-big-it-explodes-too-small-it-crawls-pio</link>
      <guid>https://dev.to/logitsolutionsai/too-big-it-explodes-too-small-it-crawls-pio</guid>
      <description>&lt;p&gt;The learning rate, step by step: why one number decides whether training works at all.&lt;/p&gt;

&lt;p&gt;Backpropagation tells every weight which way to move: its gradient. It doesn't say how far. That's the job of the learning rate, written η (eta). Every step of gradient descent is&lt;/p&gt;

&lt;p&gt;&lt;code&gt;w ← w − η ∇L&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The gradient comes from the model. The learning rate is a setting you choose, and it is the first one people tune. This article shows what it does on the smallest possible example, why there is a hard limit on how big it can be, and how practitioners pick it and change it during training. The ideas follow the CS878 Deep Learning lecture on learning rates.&lt;/p&gt;

&lt;h2&gt;
  
  
  One weight on a bowl
&lt;/h2&gt;

&lt;p&gt;Take a single weight and the loss L(w) = w², a bowl with its bottom at w = 0. The gradient is 2w, so one step is&lt;/p&gt;

&lt;p&gt;&lt;code&gt;w ← w − η · 2w = (1 − 2η) · w&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Start at w = 2, where the loss is 4, and try four learning rates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;η = 0.01:&lt;/strong&gt; each step multiplies w by 0.98. After ten steps, w has only reached 1.634 and the loss is still 2.67. It crawls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;η = 0.4:&lt;/strong&gt; each step multiplies w by 0.2. Two becomes 0.4, then 0.08, then 0.016. Fast.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;η = 0.9:&lt;/strong&gt; each step multiplies w by −0.8. The weight jumps to the other side of the bowl each time (−1.6, 1.28, −1.024, 0.819), but the jumps shrink, so it still lands.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;η = 1.1:&lt;/strong&gt; each step multiplies w by −1.2. The jumps grow: −2.4, 2.88, −3.456, 4.147. The loss climbs 5.76, 8.29, 11.94, 17.20. It explodes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvnahsjfvpgxl2to1p7li.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvnahsjfvpgxl2to1p7li.png" alt="One weight on the bowl L = w², four learning rates: crawls, fast, zig-zags, explodes." width="510" height="721"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One weight on the bowl L = w², four learning rates: crawls, fast, zig-zags, explodes.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why the edge is at one
&lt;/h2&gt;

&lt;p&gt;Everything depends on the factor 1 − 2η. After t steps, w_t = (1 − 2η)^t · w₀.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Below η = 0.5, the factor is between 0 and 1: the weight slides in without overshooting.&lt;/li&gt;
&lt;li&gt;At η = 0.5, the factor is 0: one jump lands exactly on the bottom.&lt;/li&gt;
&lt;li&gt;Between 0.5 and 1, the factor is between −1 and 0: the weight flips sides but shrinks.&lt;/li&gt;
&lt;li&gt;At η = 1, the factor is −1: it bounces between 2 and −2 forever.&lt;/li&gt;
&lt;li&gt;Past 1, the factor is below −1: it grows every step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing here is special to w². For any bowl L = (λ/2) w², with curvature λ (the second derivative), the factor is 1 − ηλ. So training is stable only if 0 &amp;lt; η &amp;lt; 2/λ, and one jump lands at η = 1/λ. For L = w², λ = 2: the edge is 1 and the one jump is 0.5.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6exwifz0oluvpjvm3yd2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6exwifz0oluvpjvm3yd2.png" alt="The factor 1 − 2η decides everything: slides in below 0.5, one jump at 0.5, zig-zags up to 1, explodes past 1." width="479" height="737"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The factor 1 − 2η decides everything: slides in below 0.5, one jump at 0.5, zig-zags up to 1, explodes past 1.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Millions of directions
&lt;/h2&gt;

&lt;p&gt;A real network has millions of weights, so the loss has millions of directions, and they are not equally steep. Take two weights and L = ½(w₁² + 10 w₂²): one direction with curvature 1 (flat), one with curvature 10 (steep). Each step multiplies w₁ by (1 − η) and w₂ by (1 − 10η).&lt;/p&gt;

&lt;p&gt;Starting from (4, 1):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;η = 0.02:&lt;/strong&gt; the steep direction shrinks fast (×0.8 per step) but the flat one barely moves (×0.98). After ten steps the weights are at (3.27, 0.11): done on the steep side, stuck on the flat side.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;η = 0.21:&lt;/strong&gt; 0.21 is past 2/10, the edge of the steep direction. w₂ is multiplied by −1.1 each step: 1, −1.1, 1.21, −1.331, 1.464. It explodes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;η = 2/11 ≈ 0.18:&lt;/strong&gt; the best single fixed rate, 2/(λ_min + λ_max). Both directions shrink by 9/11 per step, and after ten steps the weights are at (0.54, 0.13).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The steep direction sets the speed limit, η &amp;lt; 2/λ_max, and the flat direction then crawls. Even the best fixed rate shrinks the error by only (κ − 1)/(κ + 1) = 9/11 per step, where κ = λ_max/λ_min = 10 is how uneven the valley is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx8c5n1nqi92osmydjn3e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx8c5n1nqi92osmydjn3e.png" alt="The valley L = ½(w₁² + 10w₂²): the steep side sets the speed limit; the best fixed step is 2/11." width="541" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The valley L = ½(w₁² + 10w₂²): the steep side sets the speed limit; the best fixed step is 2/11.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Picking a starting rate
&lt;/h2&gt;

&lt;p&gt;Two quick checks get you most of the way:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Before training, look at the first loss. For softmax with C classes and small random weights, it should be about ln C, which is 2.30 for ten classes. If it isn't, something else is wrong.&lt;/li&gt;
&lt;li&gt;Try a few learning rates a factor of ten apart: 1e-1, 1e-2, 1e-3, 1e-4. Run each for about a hundred iterations and keep the one whose loss drops fast without blowing up. Too small barely moves; too big turns into NaN.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F37p749sg705gpob890lr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F37p749sg705gpob890lr.png" alt="Trying 1e-4 to 1e-1 from the same starting loss of 2.30: keep the one that drops fast." width="521" height="610"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Trying 1e-4 to 1e-1 from the same starting loss of 2.30: keep the one that drops fast.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in PyTorch
&lt;/h2&gt;

&lt;p&gt;The bowl example, at the learning rate that explodes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1.1&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints −2.4, 2.88, −3.456, 4.147. Change &lt;code&gt;lr&lt;/code&gt; to 0.5 and w lands on 0 in one step.&lt;/p&gt;

&lt;p&gt;In a real training loop the learning rate is one argument of the optimizer. A quick sweep tries a few values a factor of ten apart:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="c1"&gt;# model = your network
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1e-1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1e-2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1e-3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;1e-4&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optim&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SGD&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;            &lt;span class="c1"&gt;# train ~100 iterations, keep the lr whose loss drops fast
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Shrinking the rate during training (decay schedules) is its own episode.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The learning rate sets how far each gradient step goes; it is chosen, not learned.&lt;/li&gt;
&lt;li&gt;On a bowl with curvature λ, each step multiplies the error by 1 − ηλ: stable only if η &amp;lt; 2/λ, one jump at η = 1/λ.&lt;/li&gt;
&lt;li&gt;In a real network the steepest direction sets the speed limit, so the flat directions crawl.&lt;/li&gt;
&lt;li&gt;Start by checking the first loss (ln C), then try rates a factor of ten apart and keep the one that drops fast.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How does PyTorch find every gradient by itself?</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 23:50:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/how-does-pytorch-find-every-gradient-by-itself-3f24</link>
      <guid>https://dev.to/logitsolutionsai/how-does-pytorch-find-every-gradient-by-itself-3f24</guid>
      <description>&lt;p&gt;Autograd, step by step: PyTorch records the forward pass as a graph, then replays it backward.&lt;/p&gt;

&lt;p&gt;In the last article we did backpropagation by hand. We sent the error back through a tiny network, one node at a time, and found each weight's gradient. It worked, but nobody does that for a real network with millions of weights.&lt;/p&gt;

&lt;p&gt;In PyTorch you write the forward pass, call &lt;code&gt;L.backward()&lt;/code&gt;, and every gradient is there. This article shows what happens in between. The engine that does it is called &lt;strong&gt;autograd&lt;/strong&gt;, short for automatic differentiation.&lt;/p&gt;

&lt;p&gt;We'll use the same network and the same numbers as last time, from the CS878 Deep Learning slides.&lt;/p&gt;

&lt;h2&gt;
  
  
  The forward pass builds the graph
&lt;/h2&gt;

&lt;p&gt;Here is the network in PyTorch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;x&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;w1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requires_grad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;w2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;requires_grad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;z&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w1&lt;/span&gt;
&lt;span class="n"&gt;s&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;relu&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;yh&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w2&lt;/span&gt;
&lt;span class="n"&gt;L&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;yh&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first four lines make the leaves of the graph: the input x, the target y and the two weights. Only the weights have &lt;code&gt;requires_grad=True&lt;/code&gt;. That flag tells autograd we will want their gradients.&lt;/p&gt;

&lt;p&gt;Every line after that runs one operation, and autograd records it. &lt;code&gt;x * w1&lt;/code&gt; makes a multiply node that holds 1/3. &lt;code&gt;z.relu()&lt;/code&gt; adds a ReLU node, still 1/3. Multiplying by w2 gives 2/3, and the squared error gives the loss, 4/9.&lt;/p&gt;

&lt;p&gt;You can see the record in what each result prints. &lt;code&gt;z&lt;/code&gt; prints as &lt;code&gt;tensor(0.3333, grad_fn=&amp;lt;MulBackward0&amp;gt;)&lt;/code&gt;. The value is the number we expected. The &lt;code&gt;grad_fn&lt;/code&gt; part is new: it is the function that made &lt;code&gt;z&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcdiefuv317jl8zrk4a80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcdiefuv317jl8zrk4a80.png" alt="Typing the forward pass builds the graph, one node per line: the loss is 4/9." width="407" height="739"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Typing the forward pass builds the graph, one node per line: the loss is 4/9.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  grad_fn links make the backward graph
&lt;/h2&gt;

&lt;p&gt;Every result keeps its &lt;code&gt;grad_fn&lt;/code&gt;, and every &lt;code&gt;grad_fn&lt;/code&gt; keeps links to the functions that made its inputs. Follow those links from the loss and you have the whole graph, pointing backward.&lt;/p&gt;

&lt;p&gt;One line of code can hold more than one operation. &lt;code&gt;L = (yh - y)**2&lt;/code&gt; is a subtraction and then a power, so PyTorch records two nodes: &lt;code&gt;L.grad_fn&lt;/code&gt; is &lt;code&gt;PowBackward0&lt;/code&gt;, and its input comes from &lt;code&gt;SubBackward0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The weights asked for gradients, so each gets an extra node at the very end of the backward graph, called &lt;code&gt;AccumulateGrad&lt;/code&gt;. Think of it as a bucket: it is where the weight's &lt;code&gt;.grad&lt;/code&gt; will be stored. The input x and the target y did not ask for gradients, so autograd skips them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffo3nbdabmtrxk5nn0gqa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ffo3nbdabmtrxk5nn0gqa.png" alt="The backward graph: every operation is now its backward function, the arrows point down, and each weight has an AccumulateGrad bucket." width="525" height="740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The backward graph: every operation is now its backward function, the arrows point down, and each weight has an AccumulateGrad bucket.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  L.backward() walks the graph in reverse
&lt;/h2&gt;

&lt;p&gt;Calling &lt;code&gt;L.backward()&lt;/code&gt; starts with a gradient of 1 at the loss and visits the nodes in reverse order. Each node knows one small rule: take the gradient from above and multiply it by its own local derivative.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pow: the local derivative of d² is 2d, so d gets 1 × 2d = 4/3.&lt;/li&gt;
&lt;li&gt;Sub: the local derivative of ŷ − y with respect to ŷ is 1, so ŷ gets 4/3. The path to y is skipped.&lt;/li&gt;
&lt;li&gt;Mul: a multiply node swaps values. w2 gets 4/3 × s = 4/9, and s gets 4/3 × w2 = 8/3.&lt;/li&gt;
&lt;li&gt;ReLU: z was positive, so the gate is open and passes 8/3 through.&lt;/li&gt;
&lt;li&gt;Mul: w1 gets 8/3 × x = 8/3. The path to x is skipped.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The buckets fill: &lt;code&gt;w1.grad&lt;/code&gt; is &lt;code&gt;tensor(2.6667)&lt;/code&gt;, or 8/3, and &lt;code&gt;w2.grad&lt;/code&gt; is &lt;code&gt;tensor(0.4444)&lt;/code&gt;, or 4/9. Those are the numbers we found by hand.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy5b8fcvrcrbbe8pxuhua.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fy5b8fcvrcrbbe8pxuhua.png" alt="After L.backward(): the buckets hold 8/3 and 4/9, the same numbers as the hand-worked backprop." width="525" height="740"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;After L.backward(): the buckets hold 8/3 and 4/9, the same numbers as the hand-worked backprop.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  When a value is used twice, gradients add
&lt;/h2&gt;

&lt;p&gt;Take &lt;code&gt;y = w * w&lt;/code&gt; with w = 3. The multiply node has two inputs, and both are w. On the way back, each path sends 3 (the other input's value). The two contributions meet in w's bucket and add up to 6, which is the derivative of w², 2w. This is the multivariable chain rule: when a value feeds several paths, its gradient is the sum over the paths.&lt;/p&gt;

&lt;p&gt;The bucket keeps adding across calls too. Run the forward and backward pass again and &lt;code&gt;w.grad&lt;/code&gt; goes from 6 to 12. That's why every training loop calls &lt;code&gt;optimizer.zero_grad()&lt;/code&gt; (or sets the gradients to None) before each backward pass.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvzcill0im3blg0jy1qbs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvzcill0im3blg0jy1qbs.png" alt="Running backward twice: the bucket jumps from 6 to 12, so training loops call zero_grad." width="530" height="677"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Running backward twice: the bucket jumps from 6 to 12, so training loops call zero_grad.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why go backward?
&lt;/h2&gt;

&lt;p&gt;A network has one loss and millions of weights. You could also push derivatives forward, from one weight up to the loss. That's forward-mode differentiation, and it needs one pass per weight: a million weights, a million passes.&lt;/p&gt;

&lt;p&gt;Reverse mode, the one autograd uses, starts from the single loss and reaches every weight in one sweep. It costs about as much as a couple of forward passes, whatever the number of weights. With one output and many inputs, going backward is the only sensible direction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fznnekk4gk4nmnm1vw29y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fznnekk4gk4nmnm1vw29y.png" alt="Reverse mode: one wavefront sweeps down from the loss through every layer and reaches all 36 weights in a single pass." width="407" height="680"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reverse mode: one wavefront sweeps down from the loss through every layer and reaches all 36 weights in a single pass.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The graph is rebuilt every step
&lt;/h2&gt;

&lt;p&gt;After &lt;code&gt;backward()&lt;/code&gt;, PyTorch frees the graph. The next forward pass records a new one. Because the graph is built while your code runs, ordinary Python works inside a model: an &lt;code&gt;if&lt;/code&gt; can add a node on one step and leave it out on the next, and a loop can run a different number of times.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fujrc2z1281y24j7pgjod.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fujrc2z1281y24j7pgjod.png" alt="The same code records two different graphs: with s &gt; 0 the  raw `if` endraw  adds a ×2 node." width="503" height="739"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The same code records two different graphs: with s &amp;gt; 0 the &lt;code&gt;if&lt;/code&gt; adds a ×2 node.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in PyTorch
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;3.&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;requires_grad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints &lt;code&gt;tensor(12.)&lt;/code&gt;, not 6, because the second backward pass adds to the first. Add &lt;code&gt;w.grad = None&lt;/code&gt; between the two backward calls and it prints &lt;code&gt;tensor(6.)&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Autograd records every operation of the forward pass as a graph. Each result's &lt;code&gt;grad_fn&lt;/code&gt; is the function that made it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;L.backward()&lt;/code&gt; walks that graph in reverse. Each node multiplies the gradient from above by its local derivative.&lt;/li&gt;
&lt;li&gt;Weights with &lt;code&gt;requires_grad=True&lt;/code&gt; collect their gradient in &lt;code&gt;.grad&lt;/code&gt; through &lt;code&gt;AccumulateGrad&lt;/code&gt;. Tensors without the flag are skipped.&lt;/li&gt;
&lt;li&gt;Gradients from several paths add up, and &lt;code&gt;.grad&lt;/code&gt; keeps adding across steps, so training loops call &lt;code&gt;zero_grad()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Reverse mode gets every gradient in one sweep, and the graph is rebuilt on every forward pass, so plain Python control flow works.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Who's to blame when a network gets it wrong?</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 23:20:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/whos-to-blame-when-a-network-gets-it-wrong-3pbb</link>
      <guid>https://dev.to/logitsolutionsai/whos-to-blame-when-a-network-gets-it-wrong-3pbb</guid>
      <description>&lt;p&gt;Backpropagation, step by step: how one backward pass hands every weight its share of the blame.&lt;/p&gt;

&lt;p&gt;When a neural network makes a wrong prediction, training has to fix it. But a network has many weights, and each one played some part in the mistake. Before we can change anything, we need to know how much each weight is to blame.&lt;/p&gt;

&lt;p&gt;That's what backpropagation does. After the network makes its prediction (the forward pass), it sends the error back through the network (the backward pass). On the way, every weight picks up a number, its gradient, that says how much the loss would change if that weight moved a little. That number is the weight's share of the blame.&lt;/p&gt;

&lt;p&gt;The examples below are the ones from the CS878 Deep Learning lecture slides, with the same numbers.&lt;/p&gt;

&lt;h2&gt;
  
  
  A tiny graph, forward
&lt;/h2&gt;

&lt;p&gt;Start with something small enough to see all at once:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;f(x, y, z) = (x + y) · z&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Draw it as a graph with two steps. An add node computes d = x + y, and a multiply node computes f = d · z.&lt;/p&gt;

&lt;p&gt;Put in x = 1, y = −3 and z = 4. The add node gives d = 1 + (−3) = −2. The multiply node gives f = −2 · 4 = −8. That's the forward pass: values flow from the inputs to the output.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftuzrf0wpd3jut00pk0vr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ftuzrf0wpd3jut00pk0vr.png" alt="The forward pass. The add node turns 1 and −3 into −2, and the multiply node turns −2 and 4 into −8." width="497" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The forward pass. The add node turns 1 and −3 into −2, and the multiply node turns −2 and 4 into −8.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The same graph, backward
&lt;/h2&gt;

&lt;p&gt;Now go the other way. We want to know how f changes when each input changes: ∂f/∂x, ∂f/∂y and ∂f/∂z.&lt;/p&gt;

&lt;p&gt;Start at the output with a gradient of 1, because f changes exactly as much as f does.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;multiply node swaps&lt;/strong&gt;: each input gets the upstream gradient times the &lt;em&gt;other&lt;/em&gt; input's value. For f = d · z, the local gradients are ∂f/∂z = d and ∂f/∂d = z. So z gets 1 × (−2) = −2 (the value of d) and the sum gets 1 × 4 = 4 (the value of z).&lt;/p&gt;

&lt;p&gt;An &lt;strong&gt;add node copies&lt;/strong&gt;: it passes the gradient straight through to every input. For d = x + y, both local gradients are 1, so x and y each get 4 × 1 = 4.&lt;/p&gt;

&lt;p&gt;Check one of them with the chain rule: ∂f/∂x = ∂f/∂d · ∂d/∂x = 4 · 1 = 4.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ww6nms4i94qttt3jhc5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3ww6nms4i94qttt3jhc5.png" alt="The backward pass. Starting from 1 at the output, the multiply node sends −2 to z and 4 to the sum; the add node passes 4 to both x and y." width="523" height="645"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The backward pass. Starting from 1 at the output, the multiply node sends −2 to z and 4 to the sum; the add node passes 4 to both x and y.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Every node does the same job
&lt;/h2&gt;

&lt;p&gt;Look at what each node did. It took the gradient arriving from above, the upstream gradient, and multiplied it by its own local gradient. For any node, with &lt;em&gt;in&lt;/em&gt; one of its inputs and &lt;em&gt;out&lt;/em&gt; its output:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;∂L/∂in = ∂L/∂out · ∂out/∂in (upstream times local)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;That's the whole algorithm. Each node only needs to know its own small derivative. It never has to see the rest of the network. The chain rule from the last episode, applied node by node, from the output back to the inputs.&lt;/p&gt;

&lt;h2&gt;
  
  
  A real network
&lt;/h2&gt;

&lt;p&gt;Now a tiny network: one input x = 1, a first weight w₁ = 1/3, a ReLU, a second weight w₂ = 2, and a squared-error loss against a target of y = 0.&lt;/p&gt;

&lt;p&gt;Forward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;z = x · w₁ = 1/3&lt;/li&gt;
&lt;li&gt;s = max(0, z) = 1/3 (the ReLU's output; σ usually means the sigmoid)&lt;/li&gt;
&lt;li&gt;ŷ = s · w₂ = 2/3&lt;/li&gt;
&lt;li&gt;L = (ŷ − y)² = 4/9&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The network predicts 2/3 when the answer is 0. That's the mistake, and the loss of 4/9 measures it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3o10iy9cre4lf9zz3n8x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F3o10iy9cre4lf9zz3n8x.png" alt="The network after its forward pass. It predicts 2/3 instead of 0, a loss of 4/9." width="547" height="736"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The network after its forward pass. It predicts 2/3 instead of 0, a loss of 4/9.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Handing out the blame
&lt;/h2&gt;

&lt;p&gt;Backward, from the loss, one node at a time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At the output: ∂L/∂ŷ = 2(ŷ − y) = 4/3.&lt;/li&gt;
&lt;li&gt;The multiply node ŷ = s · w₂ swaps. The second weight gets 4/3 × s = 4/3 × 1/3 = &lt;strong&gt;4/9&lt;/strong&gt;, and the other branch gets 4/3 × w₂ = 4/3 × 2 = 8/3.&lt;/li&gt;
&lt;li&gt;The ReLU's input was positive (z = 1/3), so the gate is open and its local gradient is 1: z gets 8/3 × 1 = 8/3. Had z been negative, the gate would be shut and pass back nothing.&lt;/li&gt;
&lt;li&gt;The multiply node z = x · w₁ swaps too. The first weight gets 8/3 × x = 8/3 × 1 = &lt;strong&gt;8/3&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Multiply the factors along the path and you get the slides' chain rule, ∂L/∂w₁ = ∂L/∂ŷ · ∂ŷ/∂s · ∂s/∂z · ∂z/∂w₁ = 4/3 · 2 · 1 · 1.&lt;/p&gt;

&lt;p&gt;So the first weight gets six times as much of the blame as the second: 8/3 = 6 × 4/9. One backward pass found both numbers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqv0ynx6jl3oa5tgjytx6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fqv0ynx6jl3oa5tgjytx6.png" alt="The backward pass through the network. The first weight's gradient is 8/3, the second weight's is 4/9." width="527" height="736"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The backward pass through the network. The first weight's gradient is 8/3, the second weight's is 4/9.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One step downhill
&lt;/h2&gt;

&lt;p&gt;Gradient descent then moves every weight at once, each against its own gradient, scaled by a learning rate α:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;w ← w − α · ∂L/∂w&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With α = 0.05, the first weight moves six times as far as the second: w₁ goes from 1/3 to 1/3 − 0.05 · 8/3 = 0.20, and w₂ from 2 to 2 − 0.05 · 4/9 ≈ 1.98. Run the forward pass again with the new weights: z = 0.20, s = 0.20, ŷ ≈ 0.40, and the loss drops from 0.44 to about 0.16.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr7u2bfm3tcz0h4firzi5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fr7u2bfm3tcz0h4firzi5.png" alt="One gradient step with α = 0.05. The weights become 0.20 and 1.98, and the loss falls from 0.44 to 0.16." width="547" height="733"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One gradient step with α = 0.05. The weights become 0.20 and 1.98, and the loss falls from 0.44 to 0.16.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it matters
&lt;/h2&gt;

&lt;p&gt;A real network has millions of weights. Nudging them one at a time would take millions of forward passes per step. Backpropagation gets all of them in one backward pass that costs about as much as the forward pass. It does this by reusing work: the 4/3 at the output was computed once and shared by both weights.&lt;/p&gt;

&lt;p&gt;It became the standard way to train neural networks after Rumelhart, Hinton and Williams showed in 1986 that it lets hidden layers learn useful features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in PyTorch
&lt;/h2&gt;

&lt;p&gt;PyTorch runs backpropagation for you. Build the loss, call &lt;code&gt;backward()&lt;/code&gt;, and every weight's gradient appears in &lt;code&gt;.grad&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="n"&gt;requires_grad&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;relu&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backward&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;grad&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints &lt;code&gt;tensor([2.6667, 0.4444])&lt;/code&gt;: 8/3 and 4/9, the same numbers we found by hand. (Here x = 1 and y = 0, so they drop out of the formula.) Change 1/3 to −1/3 and both gradients become zero: the ReLU outputs 0, so no blame gets through.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The forward pass computes values; the backward pass sends gradients from the loss back to every weight.&lt;/li&gt;
&lt;li&gt;Each node multiplies the gradient from above by its own local gradient.&lt;/li&gt;
&lt;li&gt;A multiply node swaps: each input gets the gradient times the other's value. An add node copies: it passes the gradient straight through. An open ReLU multiplies by 1.&lt;/li&gt;
&lt;li&gt;In the slides' network, one backward pass gives the first weight 8/3 and the second 4/9, and one step with α = 0.05 takes the loss from 0.44 to 0.16.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How does one nudge ripple through ten layers?</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 22:50:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/how-does-one-nudge-ripple-through-ten-layers-4gll</link>
      <guid>https://dev.to/logitsolutionsai/how-does-one-nudge-ripple-through-ten-layers-4gll</guid>
      <description>&lt;p&gt;The chain rule, the idea that lets a network see through every one of its layers, with real numbers.&lt;/p&gt;

&lt;p&gt;A neural network is a chain. The input goes into the first layer, the first layer's output goes into the second, and so on, until the last layer produces an answer and a loss, one number that says how wrong that answer is.&lt;/p&gt;

&lt;p&gt;Training keeps asking one question: if I nudge this weight a little, how much does the loss move? For a weight ten layers down, the nudge has to travel through every layer above it before it reaches the loss. The chain rule tells you how big it is when it arrives.&lt;/p&gt;

&lt;h2&gt;
  
  
  A network is a chain
&lt;/h2&gt;

&lt;p&gt;Written as math, a ten-layer network is a function inside a function inside a function:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;f₁₀( ⋯ f₂( f₁(x) ) ⋯ )&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Picture it as a tower of dials on one shaft: the input at the bottom, a dial for each layer above it. Turn the bottom dial a little and every dial above it turns too, but not by the same amount. Each layer has its own ratio, which can make the turn bigger or smaller.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4jn5j39swe807orzodwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4jn5j39swe807orzodwu.png" alt="A network as a tower of dials. Turn the input at the bottom and every layer above it turns; the blue wedges show how far each one moved." width="560" height="701"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A network as a tower of dials. Turn the input at the bottom and every layer above it turns; the blue wedges show how far each one moved.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Two links, real numbers
&lt;/h2&gt;

&lt;p&gt;Take just two layers. The first triples its input, y = 3x, and the second squares that, z = y². Start the input at x = 1: then y = 3 and z = 9.&lt;/p&gt;

&lt;p&gt;Now raise the input by 0.01, to x = 1.01. Then y = 3.03: it moved 0.03, three times the nudge, so its ratio is 3.&lt;/p&gt;

&lt;p&gt;And z = 3.03² = 9.1809: it moved about 0.18, six times y's own move of 0.03, so its ratio is 6.&lt;/p&gt;

&lt;p&gt;Why six? Write out (3 + h)² = 9 + 6h + h². For a tiny h, the h² hardly matters, so the change is about 6h. That ratio is the slope of y² at y = 3: its derivative.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpokdztx0cb4bst0zkgih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fpokdztx0cb4bst0zkgih.png" alt="Close on two links. Raising the input by 0.01 moves the first layer by 0.03 (ratio 3) and the second by 0.18 (ratio 6)." width="560" height="810"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Close on two links. Raising the input by 0.01 moves the first layer by 0.03 (ratio 3) and the second by 0.18 (ratio 6).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The ratios multiply
&lt;/h2&gt;

&lt;p&gt;The first link multiplies the nudge by 3 and the second by 6, so together it's 3 × 6 = 18. The real numbers agree: z moved 0.18 for a nudge of 0.01, which is 18 times.&lt;/p&gt;

&lt;p&gt;That's the chain rule. Written with derivatives:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dz/dx = dz/dy · dy/dx = 6 × 3 = 18&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Each layer only needs to know its own slope: find each link's ratio where it stands, then multiply.&lt;/p&gt;

&lt;h2&gt;
  
  
  You've seen this on a clock
&lt;/h2&gt;

&lt;p&gt;A clock is a chain too. The minute hand turns 12 times as fast as the hour hand, and the second hand turns 60 times as fast as the minute hand. So the second hand turns 12 × 60 = 720 times as fast as the hour hand: you multiply the ratios along the chain, exactly as with the layers.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ten layers, ten ratios
&lt;/h2&gt;

&lt;p&gt;A network with ten layers multiplies ten ratios, and a product of many numbers moves fast in both directions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If every layer halves the turn, the top moves 0.5¹⁰ ≈ 0.001 as far as the input. The nudge has all but vanished.&lt;/li&gt;
&lt;li&gt;If every layer doubles it, the top moves 2¹⁰ = 1024 times as far. The nudge has exploded.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0fcw0j5j3qmhqweexyj8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0fcw0j5j3qmhqweexyj8.png" alt="Ten layers that each double the turn. The bottom barely moves, and the top spins 1024 times as far." width="560" height="906"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ten layers that each double the turn. The bottom barely moves, and the top spins 1024 times as far.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is why very deep networks were once so hard to train: the signal about how a deep weight affects the loss either faded away or grew out of control.&lt;/p&gt;

&lt;h2&gt;
  
  
  The same rule in a real network
&lt;/h2&gt;

&lt;p&gt;Here is a small three-layer network: two inputs, three hidden neurons with ReLU, and one output, scored by squared error against a target of 1. With inputs 2 and 1, the hidden neurons come out at 1, 0.5 and 0.2, the output is 3, and the loss is (3 − 1)² = 4.&lt;/p&gt;

&lt;p&gt;Pick one weight, w = 0.5, from the first input to the top hidden neuron, and follow its path to the loss. It has three links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the hidden neuron moves 2 times as much as w (the input it multiplies is 2);&lt;/li&gt;
&lt;li&gt;the output moves 3 times as much as that hidden neuron (its weight is 3);&lt;/li&gt;
&lt;li&gt;the loss moves 4 times as much as the output (the slope of (y − 1)² at y = 3).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So ∂L/∂w = 2 × 3 × 4 = 24. Check it: raise w from 0.50 to 0.51, and the loss goes from 4.00 to 4.24.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp37yiqo8bmbwgmz9lijk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fp37yiqo8bmbwgmz9lijk.png" alt="A three-layer network. One weight's path to the loss has ratios 2, 3 and 4, so the loss moves 24 times as much as the weight." width="560" height="798"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A three-layer network. One weight's path to the loss has ratios 2, 3 and 4, so the loss moves 24 times as much as the weight.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in PyTorch
&lt;/h2&gt;

&lt;p&gt;PyTorch applies the chain rule for you. &lt;code&gt;torch.func.grad&lt;/code&gt; returns a function's derivative, even when the function is a chain of other functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;
&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;f&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;z&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;y&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints &lt;code&gt;tensor(18.)&lt;/code&gt;, the same 3 × 6 we found by hand. Add a third layer that halves its input, and the gradient of the longer chain should come out at 9.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A network is a chain of layers, and a nudge at the bottom ripples through every layer above it.&lt;/li&gt;
&lt;li&gt;Each layer scales the nudge by its own ratio: its local slope, the derivative.&lt;/li&gt;
&lt;li&gt;The chain rule: multiply the ratios along the chain. dz/dx = dz/dy · dy/dx.&lt;/li&gt;
&lt;li&gt;With many layers the product can shrink to almost nothing (0.5¹⁰ ≈ 0.001) or blow up (2¹⁰ = 1024).&lt;/li&gt;
&lt;li&gt;In a real network, a weight's effect on the loss is the product of the ratios along its path: 2 × 3 × 4 = 24.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How do you find a valley blindfolded?</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 22:20:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/how-do-you-find-a-valley-blindfolded-1nfj</link>
      <guid>https://dev.to/logitsolutionsai/how-do-you-find-a-valley-blindfolded-1nfj</guid>
      <description>&lt;p&gt;Gradient descent, the walk every neural network takes while it learns, step by step with real numbers.&lt;/p&gt;

&lt;p&gt;Imagine standing in the hills with a blindfold on, trying to reach the bottom of the valley. You can't see the valley or the path. All you have is what you feel under your feet: which way the ground tilts, and how steeply.&lt;/p&gt;

&lt;p&gt;That's enough. If the ground tilts down to your left, step left, then feel again. Repeat until the ground is flat. That loop is gradient descent, and it's how almost every neural network is trained.&lt;/p&gt;

&lt;h2&gt;
  
  
  The ground is the loss
&lt;/h2&gt;

&lt;p&gt;A network in training is in the same position. Its loss, one number that says how wrong its answers are, depends on its weights: change a weight and the loss goes up or down.&lt;/p&gt;

&lt;p&gt;Picture a network with just two weights. For every pair of weights you can compute the loss, so you can draw it as a height over a flat map of the two weights. That gives a landscape. Where you stand on the map is the current weights. The height under your feet is the current loss. Training means finding the lowest point.&lt;/p&gt;

&lt;p&gt;In our example the landscape is a long valley:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;loss = (w₁ − 3)² + 3 · (w₂ − 1)²&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The bottom is at w₁ = 3 and w₂ = 1, where the loss is 0. We start at w₁ = 0 and w₂ = 3, where the loss is 21.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flluic9gryjmcbavtosco.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flluic9gryjmcbavtosco.png" alt="The valley the network can't see. The ball is the current weights; the blue patch is the only ground it can feel." width="560" height="809"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The valley the network can't see. The ball is the current weights; the blue patch is the only ground it can feel.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The network never sees this picture. A real network has millions of weights, so its landscape can't be drawn at all. Like the hiker, it only knows the ground where it stands.&lt;/p&gt;

&lt;h2&gt;
  
  
  The slope is the gradient
&lt;/h2&gt;

&lt;p&gt;The thing you feel under your feet has a name: the gradient. It's the slope of the loss in every weight's direction at once, and it points uphill, the way the loss grows fastest.&lt;/p&gt;

&lt;p&gt;At our starting point the gradient is (−6, 12). The 12 says the loss climbs steeply if weight 2 grows. The −6 says it also climbs if weight 1 shrinks. Going uphill would be a bad idea, so gradient descent does the opposite and steps against the gradient, downhill.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F97uo4edm5rpbnqx4e6zv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F97uo4edm5rpbnqx4e6zv.png" alt="The gradient points uphill (grey arrow). The step goes the other way, downhill (blue)." width="560" height="809"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The gradient points uphill (grey arrow). The step goes the other way, downhill (blue).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How big is a step?
&lt;/h2&gt;

&lt;p&gt;Each step is the gradient times a small number called the learning rate, written η (eta):&lt;/p&gt;

&lt;p&gt;&lt;code&gt;w ← w − η · ∇L&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;With a learning rate of 0.1, the first step moves the weights by 0.1 × (−6, 12) = (−0.6, 1.2) the other way. They go from (0, 3) to (0.6, 1.8), and the loss drops from 21 to 7.7.&lt;/p&gt;

&lt;p&gt;Then you feel the slope again and take the next step. Here is what twenty steps do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;after 1 step, the loss is 7.7;&lt;/li&gt;
&lt;li&gt;after 2 steps, 4.0;&lt;/li&gt;
&lt;li&gt;after 5 steps, 0.97;&lt;/li&gt;
&lt;li&gt;after 10 steps, 0.10;&lt;/li&gt;
&lt;li&gt;after 20 steps, 0.001, almost zero.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Notice that the steps get shorter by themselves. Near the bottom the ground flattens, so the gradient shrinks, and a small gradient times the learning rate makes a small step. Nobody tells the network to slow down near the minimum. The slope does it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fknyhcc8ocudvx81hozjn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fknyhcc8ocudvx81hozjn.png" alt="Twenty real steps at learning rate 0.1. The loss goes from 21 to almost zero, and the steps shrink as the ground flattens." width="560" height="831"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Twenty real steps at learning rate 0.1. The loss goes from 21 to almost zero, and the steps shrink as the ground flattens.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The learning rate is your stride
&lt;/h2&gt;

&lt;p&gt;The gradient gives the direction, and the learning rate decides how far you go each time. To see why that matters, look along the valley floor from the side, where it's a simple curve, loss = (w − 3)², starting at w = 0 with a loss of 9.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Learning rate 0.1:&lt;/strong&gt; the hops shrink as the curve flattens, and the ball settles at the bottom.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning rate 0.01:&lt;/strong&gt; tiny steps. After twenty of them the loss is still 4.0. You're walking the right way, just very slowly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Learning rate 1.1:&lt;/strong&gt; giant leaps. Every step overshoots the bottom and lands higher on the other side. Four steps later the loss has grown from 9 to 38.7, and it keeps growing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fubuhg07yehc1q8reo2og.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fubuhg07yehc1q8reo2og.png" alt="The valley floor from the side. At 1.1 every step leaps over the bottom and climbs (grey arcs); at 0.1 the hops shrink and the ball settles at the bottom (blue)." width="560" height="819"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The valley floor from the side. At 1.1 every step leaps over the bottom and climbs (grey arcs); at 0.1 the hops shrink and the ball settles at the bottom (blue).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;There's a simple reason for the blow-up. On this curve, each step multiplies your distance from the bottom by (1 − 2η). With η = 0.1 that's 0.8, so you get 20% closer every step. With η = 1.1 it's −1.2: you land on the other side, 20% farther away than before.&lt;/p&gt;

&lt;p&gt;That's why the learning rate is usually the first setting people tune. A common recipe from the lecture notes: try 0.1, 0.01, 0.001 and 0.0001, and keep the one that makes the loss drop fast within the first hundred steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in PyTorch
&lt;/h2&gt;

&lt;p&gt;PyTorch can compute the gradient for you. &lt;code&gt;torch.func.grad&lt;/code&gt; turns a function into its slope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;
&lt;span class="n"&gt;L&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;lambda&lt;/span&gt; &lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;grad&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints &lt;code&gt;tensor(2.9654)&lt;/code&gt;: twenty steps from 0 get within 0.035 of the bottom at 3. Change 0.1 to 1.1 and run it again to watch the steps leap out of the valley.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Training is a walk down the loss landscape, where your position is the weights and your height is the loss.&lt;/li&gt;
&lt;li&gt;The gradient is the slope under your feet. It points uphill, so each step goes against it: w ← w − η · ∇L.&lt;/li&gt;
&lt;li&gt;Steps shrink by themselves near the bottom, because the slope flattens.&lt;/li&gt;
&lt;li&gt;The learning rate is your stride. Too small and you crawl, too big and you leap out of the valley.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>This is what a confident mistake looks like</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 21:50:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/this-is-what-a-confident-mistake-looks-like-55d7</link>
      <guid>https://dev.to/logitsolutionsai/this-is-what-a-confident-mistake-looks-like-55d7</guid>
      <description>&lt;p&gt;Cross-entropy, the loss behind almost every classifier, as a landscape and as a bet.&lt;/p&gt;

&lt;p&gt;A classifier doesn't just pick an answer. It gives every class a score, and softmax turns those scores into probabilities: cat, dog, bird. To learn, the model needs one number that says how good those probabilities were. For classifiers, that number is almost always the cross-entropy loss.&lt;/p&gt;

&lt;h2&gt;
  
  
  One number, one log
&lt;/h2&gt;

&lt;p&gt;Cross-entropy looks at a single probability: the one the model gave to the right answer. Call it p. The loss is minus its log:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;loss = −log(p)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If the picture is a cat and the model said 67% cat, the loss is −log(0.67) ≈ 0.4. If it said 1% cat, the loss is −log(0.01) ≈ 4.6.&lt;/p&gt;

&lt;h2&gt;
  
  
  The loss as a landscape
&lt;/h2&gt;

&lt;p&gt;Take a classifier with three classes, and hold the bird score still. Two numbers are left: the cat score and the dog score. For every pair, cross-entropy gives a loss. Make that loss the height, and you get a landscape.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9ew59fzvlmxrq7tr8s3f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9ew59fzvlmxrq7tr8s3f.png" alt="The loss over the cat and dog scores: a landscape. The ball is a confidently wrong model: cat 1%, loss 4.61." width="560" height="870"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The loss over the cat and dog scores: a landscape. The ball is a confidently wrong model: cat 1%, loss 4.61.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Where the cat score wins, the ground is flat and close to zero. A model that's confident and correct sits there at almost no cost: at 98% cat, the loss is 0.02.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhh0y4yqwprz5defitop4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fhh0y4yqwprz5defitop4.png" alt="Where the cat score wins, the ground is flat and close to zero." width="560" height="768"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Where the cat score wins, the ground is flat and close to zero.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Where the dog score wins, the ground climbs, and it never levels off. Far enough up that ramp the loss grows by one for every extra point of dog score. There is no flat spot for a confident mistake.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ggjjpg8km5wvn09q4o0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F0ggjjpg8km5wvn09q4o0.png" alt="Where the dog score wins, the ground keeps climbing." width="560" height="738"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Where the dog score wins, the ground keeps climbing.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Training rolls downhill
&lt;/h2&gt;

&lt;p&gt;Training follows the slope. For softmax with cross-entropy, the slope with respect to each score is just the prediction minus the truth, where the truth is 1 for the right class and 0 for the others. So each training step moves the scores by that amount, times a learning rate:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;z ← z − (p − y)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Start at the confident mistake, cat 1% and dog 99%, with a learning rate of 1. Three steps take the cat from 1% to 7%, to 32%, to 64%, and the loss falls from 4.61 to 0.44. The ramp is steep exactly where the model is most wrong, so the push back is strongest there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F62m26fq5rxxdnys93v2i.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F62m26fq5rxxdnys93v2i.png" alt="Three real gradient-descent steps from the top of the ramp: cat 1% → 64%." width="560" height="852"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Three real gradient-descent steps from the top of the ramp: cat 1% → 64%.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The same loss as a bet
&lt;/h2&gt;

&lt;p&gt;Here's another way to see it. Think of the model's probabilities as a bet: 100 chips spread across the answers, 67 on cat, 24 on dog and 9 on bird. When the answer turns out to be a cat, cross-entropy sends a bill: minus the log of the cat's share, −log(67/100) ≈ 0.4.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4nyzu0wn9e4tblwfz7i2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4nyzu0wn9e4tblwfz7i2.png" alt="The model bets 100 chips. It's a cat, so the bill is −log(0.67) ≈ 0.4." width="560" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The model bets 100 chips. It's a cat, so the bill is −log(0.67) ≈ 0.4.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Halve the chips on the truth, and the bill grows by the same amount every time, log(2) ≈ 0.69:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;67 chips cost 0.40;&lt;/li&gt;
&lt;li&gt;34 chips cost 1.09;&lt;/li&gt;
&lt;li&gt;17 chips cost 1.79;&lt;/li&gt;
&lt;li&gt;one chip costs 4.61;&lt;/li&gt;
&lt;li&gt;zero chips: there is no limit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnrgnr0eihk63zf5set8u.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fnrgnr0eihk63zf5set8u.png" alt="Every halving adds 0.69. One chip costs 4.6; at zero, the bill has no limit." width="560" height="706"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Every halving adds 0.69. One chip costs 4.6; at zero, the bill has no limit.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's why a confident mistake costs so much: being sure of the wrong answer means betting almost nothing on the truth, and every halving of that bet keeps adding to the bill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it in PyTorch
&lt;/h2&gt;

&lt;p&gt;You never write the log yourself. &lt;code&gt;nn.CrossEntropyLoss&lt;/code&gt; takes the raw scores and the right class and does the softmax and the log for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;
&lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;([[&lt;/span&gt;&lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
&lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tensor&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;  &lt;span class="c1"&gt;# cat
&lt;/span&gt;&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CrossEntropyLoss&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It prints &lt;code&gt;tensor(0.4076)&lt;/code&gt;, the 0.4 from above. Pass it probabilities instead of raw scores and it applies softmax a second time, and the loss comes out wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cross-entropy = −log(probability of the right answer).&lt;/li&gt;
&lt;li&gt;Over the scores it is a landscape: flat where the model is right, a ramp with no top where it is confidently wrong.&lt;/li&gt;
&lt;li&gt;Its slope is prediction minus truth, so training pushes hardest where the model is most wrong.&lt;/li&gt;
&lt;li&gt;As a bet: every halving of the chips on the truth adds 0.69, and zero chips has no limit.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How does a network know it's wrong?</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 21:20:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/how-does-a-network-know-its-wrong-3b9</link>
      <guid>https://dev.to/logitsolutionsai/how-does-a-network-know-its-wrong-3b9</guid>
      <description>&lt;p&gt;Loss functions turn every mistake into one number. Here's how squared and absolute loss score the same misses very differently.&lt;/p&gt;

&lt;p&gt;A neural network can't feel embarrassed when it's wrong. It needs a way to measure its mistakes, so it knows which direction to improve.&lt;/p&gt;

&lt;p&gt;That measurement is the loss function. It turns all of a network's errors into a single number, and training is the process of pushing that number down.&lt;/p&gt;

&lt;h2&gt;
  
  
  One number for "how wrong"
&lt;/h2&gt;

&lt;p&gt;A loss function compares the network's predictions with the right answers and returns one number:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zero means every prediction is perfect.&lt;/li&gt;
&lt;li&gt;Bigger means worse.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's it. Everything a network learns, it learns by trying to make this number smaller.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple example
&lt;/h2&gt;

&lt;p&gt;Say a network draws a line to predict three data points. It doesn't fit perfectly. Its predictions miss the three points by 3, 2, and 1.&lt;/p&gt;

&lt;p&gt;How bad is that, in one number? It depends on which loss function you pick.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrvos6z7y8oslvn12mr4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fvrvos6z7y8oslvn12mr4.png" alt="The network's line misses three points by 3, 2 and 1." width="560" height="409"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The network's line misses three points by 3, 2 and 1.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Squared loss
&lt;/h2&gt;

&lt;p&gt;The squared loss squares each miss, then adds them up:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3² = 9&lt;/li&gt;
&lt;li&gt;2² = 4&lt;/li&gt;
&lt;li&gt;1² = 1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The total is 9 + 4 + 1 = 14. When you average it over all the data points, this is called the &lt;strong&gt;mean squared error&lt;/strong&gt;, or MSE. Here, that's 14 ÷ 3 ≈ 4.7.&lt;/p&gt;

&lt;p&gt;Squaring makes every miss positive, and it punishes big misses much more than small ones. A miss of 3 costs nine times as much as a miss of 1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff4qnu69by38u8x58gzl7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff4qnu69by38u8x58gzl7.png" alt="Squared loss: the misses 3, 2 and 1 cost 9, 4 and 1, for a total of 14." width="560" height="486"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Squared loss: the misses 3, 2 and 1 cost 9, 4 and 1, for a total of 14.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Absolute loss
&lt;/h2&gt;

&lt;p&gt;The absolute loss is simpler. It just adds up the size of each miss, ignoring whether the prediction was too high or too low:&lt;/p&gt;

&lt;p&gt;3 + 2 + 1 = 6.&lt;/p&gt;

&lt;p&gt;Averaged over the data points, this is called the &lt;strong&gt;mean absolute error&lt;/strong&gt;, or MAE. Here, that's 6 ÷ 3 = 2.&lt;/p&gt;

&lt;h2&gt;
  
  
  What one outlier does
&lt;/h2&gt;

&lt;p&gt;Now a new point arrives, and the network misses it by 5.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Squared, that one miss costs 5² = 25. That's more than all the other misses combined (14).&lt;/li&gt;
&lt;li&gt;The absolute loss only adds 5.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The totals jump from 14 to 39 for squared loss, but only from 6 to 11 for absolute loss.&lt;/p&gt;

&lt;p&gt;So one unusual point can dominate the squared loss. If your data has a few wild outliers, a network trained with squared loss will bend over backwards to reduce them, sometimes at the expense of fitting everything else.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2n2xvu82kyaqqqrv0382.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F2n2xvu82kyaqqqrv0382.png" alt="One new point misses by 5. Squared, it costs 25, more than the other three misses combined. Absolute only adds 5." width="560" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;One new point misses by 5. Squared, it costs 25, more than the other three misses combined. Absolute only adds 5.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How training uses the loss
&lt;/h2&gt;

&lt;p&gt;Training adjusts the network's weights to push the loss down, one small step at a time. Each step asks: "If I nudge this weight a little, does the loss go up or down?" Then it moves the weight in the direction that lowers the loss.&lt;/p&gt;

&lt;p&gt;Which loss you choose shapes what the network cares about. Squared loss cares a lot about big mistakes. Absolute loss treats every unit of error the same.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8p3z71up41qpw74p0yk4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F8p3z71up41qpw74p0yk4.png" alt="Training nudges the weights to push the loss down, one small step at a time." width="560" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Training nudges the weights to push the loss down, one small step at a time.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick check
&lt;/h2&gt;

&lt;p&gt;Your data has a few wild outliers. Which loss stays calmer: squared, or absolute?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer: absolute.&lt;/strong&gt; It grows in step with each miss, while squaring blows big misses up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A loss function turns all of a network's errors into one number. Zero is perfect.&lt;/li&gt;
&lt;li&gt;Squared loss squares each miss (3, 2, 1 → 9 + 4 + 1 = 14). Averaged, it's the mean squared error.&lt;/li&gt;
&lt;li&gt;Absolute loss adds the miss sizes (3 + 2 + 1 = 6). Averaged, it's the mean absolute error.&lt;/li&gt;
&lt;li&gt;Squared loss is very sensitive to outliers: a single miss of 5 costs 25.&lt;/li&gt;
&lt;li&gt;Training adjusts the weights, step by step, to push the loss down.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How do raw scores become probabilities?</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 20:50:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/how-do-raw-scores-become-probabilities-2lm5</link>
      <guid>https://dev.to/logitsolutionsai/how-do-raw-scores-become-probabilities-2lm5</guid>
      <description>&lt;p&gt;Softmax, the last step of almost every classifier, explained with three numbers.&lt;/p&gt;

&lt;p&gt;When a neural network looks at a photo and decides "cat," it doesn't jump straight to an answer. Its last layer produces a raw score for every possible class. Those scores are useful, but they aren't probabilities yet.&lt;/p&gt;

&lt;p&gt;Softmax is the small function that turns them into probabilities. It takes two steps, and you can do both by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raw scores are not probabilities
&lt;/h2&gt;

&lt;p&gt;Say a network has three classes: cat, dog, and bird. For one image, its last layer gives these raw scores (often called logits):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cat: 2&lt;/li&gt;
&lt;li&gt;Dog: 1&lt;/li&gt;
&lt;li&gt;Bird: 0&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cat clearly scores highest. But these numbers have two problems if you want to read them as probabilities. They can be negative, and they don't add up to 1. A score of 2 doesn't tell you "how sure" the network is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9f6mynjq8p0d5dan6btq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9f6mynjq8p0d5dan6btq.png" alt="The network's last layer gives one raw score per class: cat 2, dog 1, bird 0." width="560" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The network's last layer gives one raw score per class: cat 2, dog 1, bird 0.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: take the exponential
&lt;/h2&gt;

&lt;p&gt;First, softmax raises the number e (about 2.718) to the power of each score. This is called taking the exponential.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cat: e² ≈ 7.4&lt;/li&gt;
&lt;li&gt;Dog: e¹ ≈ 2.7&lt;/li&gt;
&lt;li&gt;Bird: e⁰ = 1&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exponential has a useful property: its result is always positive, even when the score is negative. A score of −3 becomes e⁻³ ≈ 0.05, small but still positive. It also stretches the gaps, so higher scores pull further ahead.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fduld04oatv78ruezerga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fduld04oatv78ruezerga.png" alt="Step 1: the exponential turns 2, 1 and 0 into about 7.4, 2.7 and 1. Every result is positive." width="560" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Step 1: the exponential turns 2, 1 and 0 into about 7.4, 2.7 and 1. Every result is positive.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: divide by the total
&lt;/h2&gt;

&lt;p&gt;Next, add the three results: 7.4 + 2.7 + 1 ≈ 11.1. Then divide each one by that total.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cat: 7.4 ÷ 11.1 ≈ 67%&lt;/li&gt;
&lt;li&gt;Dog: 2.7 ÷ 11.1 ≈ 24%&lt;/li&gt;
&lt;li&gt;Bird: 1 ÷ 11.1 ≈ 9%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, they add up to 100%. Now the numbers are real probabilities: all positive, and they sum to one.&lt;/p&gt;

&lt;p&gt;As a formula, for a class with score zᵢ: softmax(zᵢ) = e^(zᵢ) ÷ (the sum of e^(z) over all classes).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd1ogd3kq1agqujo9b0x4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fd1ogd3kq1agqujo9b0x4.png" alt="Step 2: divide each exponential by the total. Cat gets 67%, dog 24%, and bird 9%, adding up to 100%." width="560" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Step 2: divide each exponential by the total. Cat gets 67%, dog 24%, and bird 9%, adding up to 100%.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why "soft" max?
&lt;/h2&gt;

&lt;p&gt;A hard max would simply pick the winner and give it everything: cat 100%, dog 0%, bird 0%. That throws away information about how close the race was.&lt;/p&gt;

&lt;p&gt;Softmax is the soft version. The winner gets the biggest share, but the others keep a share too. That matters during training, because the network can learn from how confident it was, not just whether it was right.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl8xqkdpp5gyxu5m73ugd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl8xqkdpp5gyxu5m73ugd.png" alt="A hard max would give cat everything and the others nothing. Softmax keeps a share for every class." width="560" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A hard max would give cat everything and the others nothing. Softmax keeps a share for every class.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick check
&lt;/h2&gt;

&lt;p&gt;Add 10 to every score: cat 12, dog 11, bird 10. Do the probabilities stay the same, or does cat's share grow?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer: they stay the same.&lt;/strong&gt; Adding 10 multiplies every exponential by the same amount, e¹⁰. That common factor cancels when you divide by the total. Only the differences between scores matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A classifier's last layer outputs raw scores, which can be negative and don't sum to one.&lt;/li&gt;
&lt;li&gt;Softmax takes the exponential of each score, which makes every value positive.&lt;/li&gt;
&lt;li&gt;Then it divides by the total, so the results add up to 100%.&lt;/li&gt;
&lt;li&gt;Scores of 2, 1 and 0 become about 67%, 24% and 9%.&lt;/li&gt;
&lt;li&gt;Shifting every score by the same amount doesn't change the result. Only the gaps matter.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Without one bend, 100 layers act like one</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 20:20:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/without-one-bend-100-layers-act-like-one-4h3i</link>
      <guid>https://dev.to/logitsolutionsai/without-one-bend-100-layers-act-like-one-4h3i</guid>
      <description>&lt;p&gt;Why every neural network needs an activation function, explained with two simple equations.&lt;/p&gt;

&lt;p&gt;Deep networks stack layer after layer. But there's a catch hiding in that stack. Without one small ingredient, a hundred layers can do exactly what one layer does, and nothing more.&lt;/p&gt;

&lt;p&gt;That ingredient is the activation function. Here's why it matters, in a few lines of algebra.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a layer does
&lt;/h2&gt;

&lt;p&gt;Every layer in a neural network does two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It multiplies and adds: each input is multiplied by a weight, the results are summed, and a bias is added.&lt;/li&gt;
&lt;li&gt;It passes the result through an activation function: a small bend.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first step is simple arithmetic. The second step is the one that's easy to overlook, and it's the one that makes depth worth having.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens without the bend
&lt;/h2&gt;

&lt;p&gt;Let's remove the activation function and watch what happens with two tiny layers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Layer one doubles its input and adds one: &lt;code&gt;h = 2x + 1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Layer two triples that and subtracts four: &lt;code&gt;y = 3h − 4&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now put them together. Substitute the first into the second: &lt;code&gt;y = 3(2x + 1) − 4 = 6x − 1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two layers, and the result is a single multiply-and-add. It's still just one straight line.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7mqexi2p4vwiog4fc4gt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F7mqexi2p4vwiog4fc4gt.png" alt="Two layers without a bend collapse into a single line, 6x − 1" width="560" height="536"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Two layers without a bend: 2x + 1, then 3h − 4. Combined, they collapse into a single line, 6x − 1.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Stacking doesn't help
&lt;/h2&gt;

&lt;p&gt;This isn't a coincidence of the numbers we picked. Any multiply-and-add fed into another multiply-and-add is still a multiply-and-add.&lt;/p&gt;

&lt;p&gt;So stack a hundred of these layers, and they still collapse into one. All that depth, and the network can only draw a straight line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add the bend: ReLU
&lt;/h2&gt;

&lt;p&gt;Now add an activation function. The most popular one is called ReLU (rectified linear unit). Its rule is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Negative numbers become zero.&lt;/li&gt;
&lt;li&gt;Positive numbers pass straight through.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So −3 becomes 0, and 2 stays 2. That's it. It looks almost too simple to matter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx5ei7p2j85tmehjj3pfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx5ei7p2j85tmehjj3pfw.png" alt="ReLU: negative inputs become zero, positive inputs pass straight through" width="560" height="439"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;ReLU: negative inputs become zero, positive inputs pass straight through.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From bends to curves
&lt;/h2&gt;

&lt;p&gt;That one kink at zero is enough to stop the collapse. The layers can't be merged into a single line anymore.&lt;/p&gt;

&lt;p&gt;Better still, bends can be combined. Add two ReLUs, one of them flipped, and you get a peak. Combine many of them, with different positions and slopes, and they trace a curve, one straight piece at a time.&lt;/p&gt;

&lt;p&gt;This is how networks build complicated functions out of very simple parts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju5kikfmxrk3t11lh0y5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fju5kikfmxrk3t11lh0y5.png" alt="Many ReLU pieces combine to trace a curve" width="560" height="380"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Many ReLU pieces, each a straight segment with one bend, combine to trace a curve.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Sigmoid vs ReLU
&lt;/h2&gt;

&lt;p&gt;Older networks often used a smooth S-shaped curve called sigmoid, which squashes any number into the range between 0 and 1.&lt;/p&gt;

&lt;p&gt;Today, ReLU is the standard choice in most networks, because it's simple and fast to compute. It also tends to make deep networks easier to train.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh2525rym7q9gxomhgtgf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fh2525rym7q9gxomhgtgf.png" alt="Sigmoid, a smooth S-curve, compared with ReLU" width="560" height="381"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Sigmoid, a smooth S-curve, was common in older networks. ReLU is the standard choice today.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick check
&lt;/h2&gt;

&lt;p&gt;A network has ten layers, with no activation functions. Can it draw a curve, or only a straight line?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer: only a straight line.&lt;/strong&gt; Without a bend, all ten layers collapse into one multiply-and-add.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Every layer multiplies, adds, and then applies an activation function.&lt;/li&gt;
&lt;li&gt;Without the activation, any stack of layers collapses into a single straight line, like 2x + 1 and 3h − 4 becoming 6x − 1.&lt;/li&gt;
&lt;li&gt;ReLU turns negatives into zero and passes positives through. That one bend stops the collapse.&lt;/li&gt;
&lt;li&gt;Many bends combined can trace curves.&lt;/li&gt;
&lt;li&gt;Sigmoid was common in older networks. ReLU is the default today.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How do hidden layers bend a straight line?</title>
      <dc:creator>Syed Abdul Hanan</dc:creator>
      <pubDate>Sat, 31 Oct 2026 19:50:00 +0000</pubDate>
      <link>https://dev.to/logitsolutionsai/how-do-hidden-layers-bend-a-straight-line-1383</link>
      <guid>https://dev.to/logitsolutionsai/how-do-hidden-layers-bend-a-straight-line-1383</guid>
      <description>&lt;p&gt;They don't. They join many straight lines into shapes, and that's where a network's power comes from.&lt;/p&gt;

&lt;p&gt;A single neuron can only draw one straight line. Yet neural networks recognize faces, read handwriting, and trace curved boundaries everywhere. So where do the curves come from?&lt;/p&gt;

&lt;p&gt;The surprising answer: from straight lines, lots of them, combined by a hidden layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  One line can't fence in a cluster
&lt;/h2&gt;

&lt;p&gt;A neuron splits the plane in two with a straight line. Points on one side get a "yes," and points on the other side get a "no."&lt;/p&gt;

&lt;p&gt;That works when the classes sit on opposite sides of the page. But look at this case: the blue points form a cluster in the middle, surrounded by the others. Wherever you draw one straight line, it can't fence the cluster in.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6a670c4i6emqflbn8t9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6a670c4i6emqflbn8t9f.png" alt="Blue points sit in the middle, surrounded by others; no single straight line separates them" width="560" height="409"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The blue points sit in the middle. A single straight line can't separate them from the points around them.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a hidden layer
&lt;/h2&gt;

&lt;p&gt;So add a layer of neurons between the inputs and the output. This is a hidden layer. Give it three neurons.&lt;/p&gt;

&lt;p&gt;Each hidden neuron draws its own line, and each one asks a single question about any point: "Is this point on my side?" The answer is yes (1) or no (0).&lt;/p&gt;

&lt;h2&gt;
  
  
  The output neuron asks for agreement
&lt;/h2&gt;

&lt;p&gt;The output neuron adds up the three answers. It only fires when the sum passes 2.5, so it needs all three to say yes.&lt;/p&gt;

&lt;p&gt;The only place where all three lines agree is the region between them. Together, the three lines fence off a triangle.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdi5dxf4seqgzwe3l14qw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdi5dxf4seqgzwe3l14qw.png" alt="Three hidden neurons draw three lines that fence off a triangle" width="560" height="396"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Three hidden neurons draw three lines. The output fires only where all three agree, which is a triangle.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  A worked example
&lt;/h2&gt;

&lt;p&gt;Take a point inside the triangle. All three neurons say yes, so the sum is 1 + 1 + 1 = 3. That passes 2.5, so the output fires.&lt;/p&gt;

&lt;p&gt;Now take a point just past one of the lines. Only two neurons say yes, so the sum is 0 + 1 + 1 = 2. That's below 2.5, so the output stays off.&lt;/p&gt;

&lt;p&gt;That threshold turns the output neuron into an "AND" of all the hidden neurons.&lt;/p&gt;

&lt;h2&gt;
  
  
  More neurons, rounder shapes
&lt;/h2&gt;

&lt;p&gt;The triangle is a rough fit, and its corners catch a few outsiders. The fix is simple: use more hidden neurons.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With six neurons, you get six lines and a tighter hexagon.&lt;/li&gt;
&lt;li&gt;With twenty, the edge looks almost like a circle.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The edge is never truly curved. It's made of many short straight pieces, like a polygon with lots of sides. Add enough of them, and the difference stops mattering.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9hlzr5edu5qhnjw60phu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F9hlzr5edu5qhnjw60phu.png" alt="With twenty hidden neurons, the boundary looks almost like a circle" width="560" height="340"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;More hidden neurons means more straight edges. With twenty, the boundary looks almost like a circle.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Go deeper
&lt;/h2&gt;

&lt;p&gt;A second hidden layer can combine the shapes from the first one. That lets a network fence off things a single shape can't, like two separate islands, or a ring with a hole in the middle.&lt;/p&gt;

&lt;p&gt;This is why depth matters. Each layer builds on the shapes from the layer before it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjvirqfjtshj0wcfw1w5y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fjvirqfjtshj0wcfw1w5y.png" alt="A second hidden layer combines shapes into two islands or a ring with a hole" width="560" height="340"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;A second hidden layer combines shapes: two islands, or a ring with a hole.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick check
&lt;/h2&gt;

&lt;p&gt;A hidden layer has five neurons. Does the output fence off a pentagon, or a perfect circle?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Answer: a pentagon.&lt;/strong&gt; Five neurons draw five straight lines, so the edge has (at most) five sides. A perfect circle would need infinitely many.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;One neuron draws one straight line.&lt;/li&gt;
&lt;li&gt;A hidden layer draws many lines, and the output neuron fires only where they agree.&lt;/li&gt;
&lt;li&gt;Three lines make a triangle, six a hexagon, and twenty something close to a circle.&lt;/li&gt;
&lt;li&gt;More layers combine shapes into islands, rings, and other complex regions.&lt;/li&gt;
&lt;li&gt;Hidden layers never bend a line. They join many straight ones into a curve.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;em&gt;This article is part of Deep Learning, Visually by Logit Solutions AI: short animated explainers that cover one idea at a time, each with a written version like this one.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
