<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ DeepLearning - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ DeepLearning - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Tue, 22 Sep 2026 05:05:23 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/deeplearning/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Neural Networks Explained: What They Are and How to Build One in Python  ]]>
                </title>
                <description>
                    <![CDATA[ Have you ever wondered how a computer can recognize a handwritten number, predict whether an email is spam, recommend a video, or understand a sentence? A lot of modern AI systems rely on something ca ]]>
                </description>
                <link>https://www.freecodecamp.org/news/neural-networks-explained-simply-in-python/</link>
                <guid isPermaLink="false">6a88c8b8c9a055790ae586e7</guid>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                    <category>
                        <![CDATA[ DeepLearning ]]>
                    </category>
                
                    <category>
                        <![CDATA[ software development ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Software Engineering ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Eva J Patel ]]>
                </dc:creator>
                <pubDate>Fri, 21 Aug 2026 21:52:56 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/e140594f-daab-4c39-8b59-91bc794d6430.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Have you ever wondered how a computer can recognize a handwritten number, predict whether an email is spam, recommend a video, or understand a sentence?</p>
<p>A lot of modern AI systems rely on something called a <strong>neural network</strong>.</p>
<p>Now, the name can make them sound much more complicated than they really are. You might imagine that you need advanced calculus, a huge computer, and thousands of lines of code to build one.</p>
<p>You don't.</p>
<p>At its most basic level, a neural network is a mathematical model that takes some numbers as input, performs calculations on those numbers, makes a prediction, checks how far that prediction was from the correct answer, and then adjusts itself so it can do a little better next time.</p>
<p>In this tutorial, we're going to build one ourselves using Python and NumPy.</p>
<h3 id="heading-heres-what-well-cover">Here's What We'll Cover:</h3>
<ul>
<li><p><a href="#heading-1-what-is-a-neural-network">1. What Is a Neural Network?</a></p>
</li>
<li><p><a href="#heading-2-why-are-they-called-neural-networks">2. Why Are They Called Neural Networks?</a></p>
</li>
<li><p><a href="#heading-3-the-three-main-parts-of-a-neural-network">3. The Three Main Parts of a Neural Network</a></p>
</li>
<li><p><a href="#heading-4-what-is-a-neuron">4. What Is a Neuron?</a></p>
</li>
<li><p><a href="#heading-5-what-is-a-weight">5. What Is a Weight?</a></p>
</li>
<li><p><a href="#heading-6-what-is-a-bias">6. What Is a Bias?</a></p>
</li>
<li><p><a href="#heading-7-why-do-we-need-activation-functions">7. Why Do We Need Activation Functions?</a></p>
</li>
<li><p><a href="#heading-8-building-our-first-neuron-in-python">8. Building Our First Neuron in Python</a></p>
</li>
<li><p><a href="#heading-9-from-one-neuron-to-a-layer">9. From One Neuron to a Layer</a></p>
</li>
<li><p><a href="#heading-10-how-does-a-neural-network-actually-learn">10. How Does a Neural Network Actually Learn?</a></p>
</li>
<li><p><a href="#heading-11-predictions-and-loss">11. Predictions and Loss</a></p>
</li>
<li><p><a href="#heading-12-what-are-gradients">12. What Are Gradients?</a></p>
</li>
<li><p><a href="#heading-13-what-is-gradient-descent">13. What Is Gradient Descent?</a></p>
</li>
<li><p><a href="#heading-14-what-is-backpropagation">14. What Is Backpropagation?</a></p>
</li>
<li><p><a href="#heading-15-the-complete-learning-cycle">15. The Complete Learning Cycle</a></p>
</li>
<li><p><a href="#heading-16-lets-build-a-neural-network-from-scratch">16. Let's Build a Neural Network From Scratch</a></p>
</li>
<li><p><a href="#heading-17-understanding-the-network-architecture">17. Understanding the Network Architecture</a></p>
</li>
<li><p><a href="#heading-18-setting-up-the-data">18. Setting Up the Data</a></p>
</li>
<li><p><a href="#heading-19-creating-the-weights-and-biases">19. Creating the Weights and Biases</a></p>
</li>
<li><p><a href="#heading-20-the-sigmoid-function">20. The Sigmoid Function</a></p>
</li>
<li><p><a href="#heading-21-forward-propagation">21. Forward Propagation</a></p>
</li>
<li><p><a href="#heading-22-calculating-the-loss">22. Calculating the Loss</a></p>
</li>
<li><p><a href="#heading-23-backpropagation-in-code">23. Backpropagation in Code</a></p>
</li>
<li><p><a href="#heading-24-updating-the-weights">24. Updating the Weights</a></p>
</li>
<li><p><a href="#heading-25-the-complete-numpy-neural-network">25. The Complete NumPy Neural Network</a></p>
</li>
<li><p><a href="#heading-26-testing-the-network">26. Testing the Network</a></p>
</li>
<li><p><a href="#heading-27-why-did-we-need-a-hidden-layer">27. Why Did We Need a Hidden Layer?</a></p>
</li>
<li><p><a href="#heading-28-what-happens-in-a-larger-neural-network">28. What Happens in a Larger Neural Network?</a></p>
</li>
<li><p><a href="#heading-29-do-you-have-to-build-neural-networks-from-scratch">29. Do You Have to Build Neural Networks From Scratch?</a></p>
</li>
<li><p><a href="#heading-30-building-the-same-network-with-pytorch">30. Building the Same Network With PyTorch</a></p>
</li>
<li><p><a href="#heading-31-training-the-network-with-pytorch">31. Training the Network With PyTorch</a></p>
</li>
<li><p><a href="#heading-32-numpy-vs-pytorch">32. NumPy vs. PyTorch</a></p>
</li>
<li><p><a href="#heading-33-what-is-deep-learning">33. What Is Deep Learning?</a></p>
</li>
<li><p><a href="#heading-34-where-are-neural-networks-used">34. Where Are Neural Networks Used?</a></p>
</li>
<li><p><a href="#heading-35-the-whole-process-in-one-picture">35. The Whole Process in One Picture</a></p>
</li>
<li><p><a href="#heading-36-the-most-important-ideas-to-remember">36. The Most Important Ideas to Remember</a></p>
</li>
<li><p><a href="#heading-37-what-should-you-learn-next">37. What Should You Learn Next?</a></p>
</li>
<li><p><a href="#heading-final-takeaway">Final Takeaway</a></p>
</li>
</ul>
<p>We'll start with a single artificial neuron, then gradually put together a complete neural network. By the end, you'll understand what weights and biases are, what activation functions do, how a network learns from its mistakes, what backpropagation and gradient descent actually mean, and how all of those pieces fit together.</p>
<p>You don't need to know advanced machine learning to follow along. Some basic Python and algebra will help, but I'll explain the important math as we go.</p>
<h2 id="heading-1-what-is-a-neural-network">1. What Is a Neural Network?</h2>
<p>Let's start with a simple example.</p>
<p>Imagine that we want a computer to predict whether a student will pass an exam.</p>
<p>We could give the computer information such as:</p>
<ul>
<li><p>How many hours the student studied</p>
</li>
<li><p>How many practice questions they completed</p>
</li>
<li><p>Their previous test score</p>
</li>
</ul>
<p>For example:</p>
<p><code>Study Hours = 5 Practice Questions = 80 Previous Score = 82</code></p>
<p>We also know whether the student actually passed:</p>
<p><code>Passed = 1</code></p>
<p>After seeing many examples like this, we want the computer to learn a pattern.</p>
<p>Maybe students who study more tend to perform better. Maybe previous test scores are useful. Maybe practice questions are helpful, too.</p>
<p>Instead of writing all of those rules ourselves, we can give the examples to a neural network and let it learn the relationships.</p>
<p>The basic idea looks like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/26be21fa-5503-402c-ac6c-7f77c5689e1e.png" alt="Visual idea about how a neural network works" style="display: block;" width="1536" height="1024" loading="lazy">

<p>The prediction could be something like: <code>0.92</code></p>
<p>If we're predicting the probability of passing, we could interpret that as approximately a 92% predicted chance of passing.</p>
<p>The important thing is that we didn't tell the network that...</p>
<blockquote>
<p>"Study hours are important, and previous scores are slightly more important."</p>
</blockquote>
<p>Instead, the network learns numbers called <strong>weights</strong> that determine how strongly different inputs affect its predictions.</p>
<h2 id="heading-2-why-are-they-called-neural-networks">2. Why Are They Called Neural Networks?</h2>
<p>The name comes from biological brains.</p>
<p>Your brain contains neurons that receive signals, process information, and pass signals to other neurons.</p>
<p>Artificial neural networks are <strong>not artificial brains</strong>. They don't work exactly like biological neurons. But the general idea of connecting many simple processing units inspired the name.</p>
<p>A very simplified artificial neuron looks like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/bd68424f-e1be-4dea-8f6a-7fc1ed5abb15.png" alt="Input and Output through a neural network" style="display: block;" width="1905" height="825" loading="lazy">

<p>The neuron receives numbers, performs some mathematical operations, and produces another number.</p>
<p>A neural network is made by connecting many of these artificial neurons together.</p>
<h2 id="heading-3-the-three-main-parts-of-a-neural-network">3. The Three Main Parts of a Neural Network</h2>
<p>A simple neural network can be divided into three types of layers:</p>
<ol>
<li><p>Input Layer</p>
</li>
<li><p>Hidden Layer(s)</p>
</li>
<li><p>Output Layer</p>
</li>
</ol>
<p>Let's look at each one.</p>
<h3 id="heading-the-input-layer">The Input Layer</h3>
<p>The input layer contains the information we give the network.</p>
<p>For our student example, we could have three inputs:</p>
<pre><code class="language-text">Input 1 = Study Hours
Input 2 = Practice Questions
Input 3 = Previous Score
</code></pre>
<p>So one student's input might look like:</p>
<pre><code class="language-text">[5, 80, 82]
</code></pre>
<p>The network doesn't necessarily understand that these numbers mean "study hours" or "test score." To the mathematical part of the network, they're simply numbers.</p>
<p>That's an important idea to remember:</p>
<blockquote>
<p>Neural networks work with numbers.</p>
</blockquote>
<p>Images, text, audio, and other information must eventually be represented as numbers before a neural network can process them.</p>
<h3 id="heading-hidden-layers">Hidden Layers</h3>
<p>After the input layer come the hidden layers.</p>
<p>A network might look like:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/6f177121-ce84-4a9d-a2b2-0ba98ad0e7d5.png" alt="Image showing how data moves from the Input Layer to the Hidden Layer and then to the Output layer" style="display: block;" width="1774" height="887" loading="lazy">

<p>The hidden layer contains neurons that perform calculations on the inputs.</p>
<p>A network can have one hidden layer or many hidden layers.</p>
<p>When a network has many layers, we often call it a <strong>deep neural network</strong>.</p>
<h3 id="heading-the-output-layer">The Output Layer</h3>
<p>The output layer produces the final result.</p>
<p>For a simple yes/no problem, we might represent the answers as:</p>
<pre><code class="language-text">0 = No
1 = Yes
</code></pre>
<p>For example:</p>
<pre><code class="language-text">0.12 → probably No
0.91 → probably Yes
</code></pre>
<p>For a problem with multiple categories, the output could contain several numbers:</p>
<pre><code class="language-text">Cat  = 0.05
Dog  = 0.90
Bird = 0.05
</code></pre>
<p>The largest value is associated with "Dog," so the model would predict Dog.</p>
<h2 id="heading-4-what-is-a-neuron">4. What Is a Neuron?</h2>
<p>Now let's zoom in on one neuron.</p>
<p>Suppose our neuron receives three inputs:</p>
<pre><code class="language-text">x₁
x₂
x₃
</code></pre>
<p>Each input has a corresponding <strong>weight</strong>:</p>
<pre><code class="language-text">w₁
w₂
w₃
</code></pre>
<p>The neuron multiplies each input by its weight and adds the results together.</p>
<p>It also adds something called a <strong>bias</strong>.</p>
<p>The equation is:</p>
<pre><code class="language-text">z = x₁w₁ + x₂w₂ + x₃w₃ + b
</code></pre>
<p>Don't worry if that equation looks intimidating.</p>
<p>It's basically just:</p>
<pre><code class="language-text">input × weight
+
input × weight
+
input × weight
+
bias
</code></pre>
<p>Let's use actual numbers.</p>
<p>Suppose:</p>
<pre><code class="language-text">x₁ = 2
x₂ = 3
x₃ = 4

w₁ = 0.5
w₂ = 0.2
w₃ = 0.8

b = 1
</code></pre>
<p>Then:</p>
<pre><code class="language-text">z = (2 × 0.5) + (3 × 0.2) + (4 × 0.8) + 1
</code></pre>
<p>Calculate each part:</p>
<pre><code class="language-text">2 × 0.5 = 1.0
3 × 0.2 = 0.6
4 × 0.8 = 3.2
</code></pre>
<p>Now add them:</p>
<pre><code class="language-text">z = 1.0 + 0.6 + 3.2 + 1
z = 5.8
</code></pre>
<p>The neuron has produced <code>5.8</code>.</p>
<p>But we're not finished yet.</p>
<h2 id="heading-5-what-is-a-weight">5. What Is a Weight?</h2>
<p>A weight controls how strongly an input affects a neuron.</p>
<p>Imagine we have:</p>
<pre><code class="language-text">x = 5
</code></pre>
<p>If the weight is:</p>
<pre><code class="language-text">w = 2
</code></pre>
<p>then:</p>
<pre><code class="language-text">x × w = 5 × 2
      = 10
</code></pre>
<p>But if the weight is:</p>
<pre><code class="language-text">w = 0.1
</code></pre>
<p>then:</p>
<pre><code class="language-text">x × w = 5 × 0.1
      = 0.5
</code></pre>
<p>The same input produced a very different result because the weight changed.</p>
<p>You can think of a weight as a volume knob.</p>
<p>A large positive weight makes an input have a stronger positive influence. A weight close to zero makes the input have little influence. A negative weight can push the result in the opposite direction.</p>
<p>The network learns these weights during training.</p>
<h2 id="heading-6-what-is-a-bias">6. What Is a Bias?</h2>
<p>The bias is another number added to the neuron's calculation.</p>
<p>Without the bias, we would have:</p>
<pre><code class="language-text">z = x₁w₁ + x₂w₂ + x₃w₃
</code></pre>
<p>With the bias:</p>
<pre><code class="language-text">z = x₁w₁ + x₂w₂ + x₃w₃ + b
</code></pre>
<p>Why add another number? Because it gives the neuron more flexibility.</p>
<p>Think of it like adjusting the starting point of the neuron's calculation.</p>
<p>The network learns the bias during training just like it learns the weights.</p>
<p>So when you see:</p>
<pre><code class="language-text">weights + bias
</code></pre>
<p>you're looking at some of the parameters the neural network can change while it learns.</p>
<h2 id="heading-7-why-do-we-need-activation-functions">7. Why Do We Need Activation Functions?</h2>
<p>At this point, our neuron can calculate a weighted sum:</p>
<pre><code class="language-text">z = x₁w₁ + x₂w₂ + ... + b
</code></pre>
<p>But neural networks need to learn more complicated relationships than simple weighted sums.</p>
<p>That's where <strong>activation functions</strong> come in. An activation function takes the neuron's calculated value and transforms it.</p>
<p>One common activation function is <strong>ReLU</strong>. ReLU stands for <strong>Rectified Linear Unit</strong>.</p>
<p>Its equation is:</p>
<pre><code class="language-text">ReLU(x) = max(0, x)
</code></pre>
<p>In simple terms:</p>
<ul>
<li><p>If the number is positive, keep it.</p>
</li>
<li><p>If the number is negative, turn it into zero.</p>
</li>
</ul>
<p>For example:</p>
<pre><code class="language-text">ReLU(-5) = 0
ReLU(-2) = 0
ReLU(0)  = 0
ReLU(3)  = 3
ReLU(10) = 10
</code></pre>
<p>In Python:</p>
<pre><code class="language-python">def relu(x):
    return max(0, x)
</code></pre>
<p>With NumPy arrays, we can use:</p>
<pre><code class="language-python">def relu(x):
    return np.maximum(0, x)
</code></pre>
<p>Activation functions are important because they allow neural networks with multiple layers to learn more complicated patterns.</p>
<h2 id="heading-8-building-our-first-neuron-in-python">8. Building Our First Neuron in Python</h2>
<p>Let's turn the math into Python.</p>
<p>First, import NumPy:</p>
<pre><code class="language-python">import numpy as np
</code></pre>
<p>NumPy gives us tools for working with numbers, arrays, vectors, and matrices.</p>
<p>Now let's create our inputs:</p>
<pre><code class="language-python">x = np.array([2, 3, 4])
</code></pre>
<p>This creates an array containing three values:</p>
<pre><code class="language-text">[2, 3, 4]
</code></pre>
<p>Now create the weights:</p>
<pre><code class="language-python">weights = np.array([0.5, 0.2, 0.8])
</code></pre>
<p>We have one weight for each input:</p>
<pre><code class="language-text">x₁ = 2    w₁ = 0.5
x₂ = 3    w₂ = 0.2
x₃ = 4    w₃ = 0.8
</code></pre>
<p>Next, create the bias:</p>
<pre><code class="language-python">bias = 1
</code></pre>
<p>Now we calculate the weighted sum:</p>
<pre><code class="language-python">z = np.dot(x, weights) + bias
</code></pre>
<p><code>np.dot()</code> performs the multiplication-and-addition operation we described earlier.</p>
<p>In this case:</p>
<pre><code class="language-text">np.dot(x, weights)
</code></pre>
<p>is equivalent to:</p>
<pre><code class="language-text">(2 × 0.5) + (3 × 0.2) + (4 × 0.8)
</code></pre>
<p>which equals:</p>
<pre><code class="language-text">4.8
</code></pre>
<p>Then we add the bias:</p>
<pre><code class="language-text">4.8 + 1 = 5.8
</code></pre>
<p>Now apply ReLU:</p>
<pre><code class="language-python">output = np.maximum(0, z)
</code></pre>
<p>Since <code>z</code> is <code>5.8</code>, ReLU leaves it unchanged:</p>
<pre><code class="language-text">output = 5.8
</code></pre>
<p>Finally:</p>
<pre><code class="language-python">print(output)
</code></pre>
<p>prints:</p>
<pre><code class="language-text">5.8
</code></pre>
<p>So our entire neuron is:</p>
<pre><code class="language-python">import numpy as np

x = np.array([2, 3, 4])
weights = np.array([0.5, 0.2, 0.8])
bias = 1

z = np.dot(x, weights) + bias
output = np.maximum(0, z)

print(output)
</code></pre>
<p>We have just created a tiny artificial neuron.</p>
<h2 id="heading-9-from-one-neuron-to-a-layer">9. From One Neuron to a Layer</h2>
<p>One neuron isn't enough for most interesting problems.</p>
<p>Instead, we can connect several neurons together.</p>
<p>For example:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/62aeadb8-9f22-4b3a-b7a4-a450df33a55b.png" alt="Input, Output and Hidden Layer depicted with neurons" style="display: block;" width="1774" height="887" loading="lazy">

<p>Those neurons together form a <strong>layer</strong>.</p>
<p>A small neural network might look like:</p>
<pre><code class="language-text">Input Layer
     ↓
Hidden Layer
     ↓
Output Layer
</code></pre>
<p>Every neuron in one layer can send its output to neurons in the next layer.</p>
<p>This is where neural networks start becoming much more powerful.</p>
<h2 id="heading-10-how-does-a-neural-network-actually-learn">10. How Does a Neural Network Actually Learn?</h2>
<p>So far, we've manually chosen the weights:</p>
<pre><code class="language-text">0.5
0.2
0.8
</code></pre>
<p>But a real neural network doesn't start out knowing the correct weights.</p>
<p>Instead, it starts with weights that are usually initialized to small random values.</p>
<p>Then it goes through a cycle:</p>
<pre><code class="language-text">Make a prediction
       ↓
Compare prediction with correct answer
       ↓
Measure the error
       ↓
Figure out how to change the weights
       ↓
Update the weights
       ↓
Try again
</code></pre>
<p>This process happens over and over, and the network gradually adjusts its parameters to make better predictions on the training data.</p>
<p>Let's break each part down.</p>
<h2 id="heading-11-predictions-and-loss">11. Predictions and Loss</h2>
<p>Suppose the correct answer is:</p>
<pre><code class="language-text">1
</code></pre>
<p>but our network predicts:</p>
<pre><code class="language-text">0.3
</code></pre>
<p>The prediction isn't very close to the target.</p>
<p>We need a way to measure how wrong it is. That's what a <strong>loss function</strong> does.</p>
<p>A loss function takes the prediction and the correct answer and produces a number representing the model's error.</p>
<p>For a simple example, we could use squared error:</p>
<pre><code class="language-text">Loss = (prediction - actual)²
</code></pre>
<p>Using our numbers:</p>
<pre><code class="language-text">Loss = (0.3 - 1)²
</code></pre>
<p>First:</p>
<pre><code class="language-text">0.3 - 1 = -0.7
</code></pre>
<p>Then square it:</p>
<pre><code class="language-text">(-0.7)² = 0.49
</code></pre>
<p>So:</p>
<pre><code class="language-text">Loss = 0.49
</code></pre>
<p>Generally, a smaller loss means the prediction is closer to the target.</p>
<p>In real neural networks, different problems use different loss functions. For binary classification, binary cross-entropy is commonly used.</p>
<h2 id="heading-12-what-are-gradients">12. What Are Gradients?</h2>
<p>Now we have a problem.</p>
<p>We know that the prediction was wrong, but how should we change the weights?</p>
<p>This is where <strong>gradients</strong> become useful. A gradient tells us how changing a parameter would affect the loss.</p>
<p>You can think of it like standing on a hill. Imagine that your goal is to reach the lowest point. If you know which direction slopes upward, you can move in the opposite direction to go downhill.</p>
<p>Training a neural network works with a similar idea. We want to reduce the loss. The gradients give us information about which direction the parameters should move.</p>
<h2 id="heading-13-what-is-gradient-descent">13. What Is Gradient Descent?</h2>
<p><strong>Gradient descent</strong> is the process of using gradients to adjust the network's parameters.</p>
<p>A simplified update rule is:</p>
<pre><code class="language-text">new weight = old weight - learning rate × gradient
</code></pre>
<p>In Python:</p>
<pre><code class="language-python">weight = weight - learning_rate * gradient
</code></pre>
<p>The <strong>learning rate</strong> controls how large the update is.</p>
<p>For example:</p>
<pre><code class="language-python">learning_rate = 0.01
</code></pre>
<p>If the learning rate is too large, the network can make huge changes and potentially jump around instead of settling on a good solution.</p>
<p>If it's too small, learning can take a very long time.</p>
<p>So training involves finding parameter updates that move the model toward lower loss without making the process unstable.</p>
<h2 id="heading-14-what-is-backpropagation">14. What Is Backpropagation?</h2>
<p>There's still one important question:</p>
<p>If a neural network has thousands or millions of weights, how does it figure out which weights contributed to the error?</p>
<p>That's where <strong>backpropagation</strong> comes in. Backpropagation calculates gradients for the parameters by working backward through the network.</p>
<p>Imagine a network like this:</p>
<pre><code class="language-text">Input
  ↓
Hidden Layer
  ↓
Output
  ↓
Loss
</code></pre>
<p>During the forward pass, information moves:</p>
<pre><code class="language-text">Input → Hidden Layer → Output
</code></pre>
<p>During backpropagation, gradient information moves backward:</p>
<pre><code class="language-text">Loss → Output → Hidden Layer → Input
</code></pre>
<p>The network uses these gradients to determine how its weights and biases should change.</p>
<p>You don't normally calculate all of these derivatives by hand when building real neural networks. Libraries such as PyTorch can calculate them automatically.</p>
<p>But understanding the basic idea is important:</p>
<blockquote>
<p>Backpropagation calculates how the parameters contributed to the error, and gradient descent uses that information to update them.</p>
</blockquote>
<h2 id="heading-15-the-complete-learning-cycle">15. The Complete Learning Cycle</h2>
<p>Now we can put everything together.</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/cdd30bf8-25b9-4a3e-b62e-ee764642c05a.png" alt="Learning cycle of neural network: input, prediction, loss, gradients, update (and then back to prediction...)" style="display: block;" width="2172" height="724" loading="lazy">

<p>More specifically:</p>
<pre><code class="language-text">Give the network data
          ↓
Calculate a prediction
          ↓
Compare it with the correct answer
          ↓
Calculate the loss
          ↓
Calculate gradients
          ↓
Update weights and biases
          ↓
Repeat
</code></pre>
<p>One complete pass through the training data is often called an <strong>epoch</strong>.</p>
<p>For example:</p>
<pre><code class="language-text">Epoch 1 → Loss: 0.82
Epoch 2 → Loss: 0.61
Epoch 3 → Loss: 0.43
Epoch 4 → Loss: 0.29
Epoch 5 → Loss: 0.18
</code></pre>
<p>These numbers are just an example, but ideally the loss decreases as training progresses.</p>
<h2 id="heading-16-lets-build-a-neural-network-from-scratch">16. Let's Build a Neural Network From Scratch</h2>
<p>Congrats! You now understand the basics of neural networks. Now it's time to put these ideas together.</p>
<p>We're going to build a small neural network using only:</p>
<pre><code class="language-text">Python + NumPy
</code></pre>
<p>Our network will learn a classic machine learning problem called <strong>XOR</strong>.</p>
<p>XOR is a logical operation with two inputs.</p>
<p>Its rules are:</p>
<pre><code class="language-text">0 XOR 0 → 0
0 XOR 1 → 1
1 XOR 0 → 1
1 XOR 1 → 0
</code></pre>
<p>In other words, the output is <code>1</code> when exactly one of the inputs is <code>1</code>.</p>
<p>Our training data will therefore be:</p>
<pre><code class="language-python">X = np.array([
    [0, 0],
    [0, 1],
    [1, 0],
    [1, 1]
])
</code></pre>
<p>And the correct answers are:</p>
<pre><code class="language-python">y = np.array([
    [0],
    [1],
    [1],
    [0]
])
</code></pre>
<p>We want our neural network to learn this pattern.</p>
<h2 id="heading-17-understanding-the-network-architecture">17. Understanding the Network Architecture</h2>
<p>Our network will contain:</p>
<pre><code class="language-text">2 input neurons
       ↓
4 hidden neurons
       ↓
1 output neuron
</code></pre>
<p>The two inputs represent the two numbers in each XOR example.</p>
<p>The four hidden neurons give the network enough flexibility to learn the XOR relationship.</p>
<p>The output neuron produces a number between <code>0</code> and <code>1</code>.</p>
<h2 id="heading-18-setting-up-the-data">18. Setting Up the Data</h2>
<p>Let's start our Python program.</p>
<pre><code class="language-python">import numpy as np
</code></pre>
<p>This imports NumPy. We'll use NumPy for arrays, matrix multiplication, and mathematical operations.</p>
<p>Next:</p>
<pre><code class="language-python">X = np.array([
    [0, 0],
    [0, 1],
    [1, 0],
    [1, 1]
])
</code></pre>
<p><code>X</code> contains our four training examples.</p>
<p>Each row is one example:</p>
<pre><code class="language-text">[0, 0]
[0, 1]
[1, 0]
[1, 1]
</code></pre>
<p>Now create the correct answers:</p>
<pre><code class="language-python">y = np.array([
    [0],
    [1],
    [1],
    [0]
])
</code></pre>
<p>The first row of <code>X</code> corresponds to the first row of <code>y</code>.</p>
<p>So:</p>
<pre><code class="language-text">[0, 0] → 0
[0, 1] → 1
[1, 0] → 1
[1, 1] → 0
</code></pre>
<h2 id="heading-19-creating-the-weights-and-biases">19. Creating the Weights and Biases</h2>
<p>Now we need the parameters of our network.</p>
<p>First:</p>
<pre><code class="language-python">np.random.seed(42)
</code></pre>
<p>This makes our random numbers reproducible.</p>
<p>Without this line, the network would receive different random starting weights each time we ran the program.</p>
<p>Now create the first layer's weights:</p>
<pre><code class="language-python">W1 = np.random.randn(2, 4)
</code></pre>
<p>Why <code>(2, 4)</code>?</p>
<p>Because:</p>
<ul>
<li><p>We have 2 input values.</p>
</li>
<li><p>We have 4 neurons in the hidden layer.</p>
</li>
</ul>
<p>So <code>W1</code> needs a weight connecting each input to each hidden neuron.</p>
<p>There are:</p>
<pre><code class="language-text">2 × 4 = 8
</code></pre>
<p>weights.</p>
<p>Next:</p>
<pre><code class="language-python">b1 = np.zeros((1, 4))
</code></pre>
<p>This creates four biases, one for each hidden neuron.</p>
<p>Now the second layer:</p>
<pre><code class="language-python">W2 = np.random.randn(4, 1)
</code></pre>
<p>There are four hidden neurons and one output neuron, so we need:</p>
<pre><code class="language-text">4 × 1 = 4
</code></pre>
<p>weights.</p>
<p>Finally:</p>
<pre><code class="language-python">b2 = np.zeros((1, 1))
</code></pre>
<p>This gives the output neuron one bias.</p>
<p>Our network parameters are therefore:</p>
<pre><code class="language-text">W1 → input-to-hidden weights
b1 → hidden-layer biases

W2 → hidden-to-output weights
b2 → output-layer bias
</code></pre>
<h2 id="heading-20-the-sigmoid-function">20. The Sigmoid Function</h2>
<p>Our output represents a probability, so we'd like it to be between <code>0</code> and <code>1</code>.</p>
<p>We can use the <strong>sigmoid function</strong>.</p>
<p>Its equation is:</p>
<pre><code class="language-text">sigmoid(x) = 1 / (1 + e⁻ˣ)
</code></pre>
<p>In Python:</p>
<pre><code class="language-python">def sigmoid(x):
    return 1 / (1 + np.exp(-x))
</code></pre>
<p>Let's see what it does:</p>
<pre><code class="language-text">sigmoid(-5) ≈ 0.007
sigmoid(0)  = 0.5
sigmoid(5)  ≈ 0.993
</code></pre>
<p>No matter how large or small the input is, the result stays between <code>0</code> and <code>1</code>.</p>
<p>That's useful when our output represents a probability.</p>
<h2 id="heading-21-forward-propagation">21. Forward Propagation</h2>
<p>Now we can send the data through the network. This is called <strong>forward propagation</strong>.</p>
<p>First, calculate the hidden layer:</p>
<pre><code class="language-python">z1 = X @ W1 + b1
</code></pre>
<p>There's a new symbol here:</p>
<pre><code class="language-text">@
</code></pre>
<p>In Python, <code>@</code> performs matrix multiplication.</p>
<p>You can think of this operation as performing many weighted sums at once.</p>
<p>Instead of manually calculating every neuron:</p>
<pre><code class="language-text">input × weight + input × weight + bias
</code></pre>
<p>NumPy can calculate all of them together.</p>
<p>The result is stored in <code>z1</code>.</p>
<p>Next:</p>
<pre><code class="language-python">a1 = np.tanh(z1)
</code></pre>
<p>Here we're using the <strong>tanh activation function</strong> for the hidden layer.</p>
<p>Tanh converts its input into values between <code>-1</code> and <code>1</code>.</p>
<p>Why use tanh here?</p>
<p>Because XOR isn't something a single simple linear calculation can solve. The nonlinear activation gives the hidden layer the flexibility it needs to learn the pattern.</p>
<p>Now calculate the output layer:</p>
<pre><code class="language-python">z2 = a1 @ W2 + b2
</code></pre>
<p>This takes the hidden layer's outputs and combines them using the second set of weights.</p>
<p>Finally:</p>
<pre><code class="language-python">a2 = sigmoid(z2)
</code></pre>
<p>Now <code>a2</code> contains our predictions.</p>
<p>For example, before training, the network might produce something like:</p>
<pre><code class="language-text">0.52
0.61
0.48
0.55
</code></pre>
<p>Those predictions aren't useful yet, but that's expected. The network hasn't learned anything yet.</p>
<h2 id="heading-22-calculating-the-loss">22. Calculating the Loss</h2>
<p>Now we need to measure how good those predictions are.</p>
<p>For binary classification, we'll use <strong>binary cross-entropy</strong>, which is a loss function used in machine learning for binary classification. It measures the performance of a model whose output is a probability value between 0 and 1.</p>
<p>The formula is:</p>
<pre><code class="language-text">Loss = -mean(
    y × log(prediction)
    +
    (1 - y) × log(1 - prediction)
)
</code></pre>
<p>That looks much more complicated than the squared-error example from earlier, but we don't need to memorize the formula.</p>
<p>In Python:</p>
<pre><code class="language-python">loss = -np.mean(
    y * np.log(a2 + 1e-8) +
    (1 - y) * np.log(1 - a2 + 1e-8)
)
</code></pre>
<p>The <code>1e-8</code> is a very small number.</p>
<p>It prevents problems if <code>a2</code> gets extremely close to <code>0</code> or <code>1</code>, because taking the logarithm of exactly zero isn't valid.</p>
<p>At the beginning of training, the loss will probably be relatively high. But as the network learns, we'd like it to decrease.</p>
<h2 id="heading-23-backpropagation-in-code">23. Backpropagation in Code</h2>
<p>Now comes the most mathematical part of our program.</p>
<p>We need to calculate the gradients.</p>
<p>Start with:</p>
<pre><code class="language-python">dz2 = a2 - y
</code></pre>
<p>This gives us the gradient of the loss with respect to the output layer's pre-activation value for the sigmoid + binary cross-entropy combination.</p>
<p>Next:</p>
<pre><code class="language-python">dW2 = (a1.T @ dz2) / len(X)
</code></pre>
<p>This calculates the gradient for <code>W2</code>.</p>
<p>The <code>.T</code> means transpose.</p>
<p>Our hidden-layer output has four neurons, while <code>dz2</code> represents the output layer's error. Matrix multiplication combines them to determine how each hidden-to-output weight contributed to the loss.</p>
<p>We divide by:</p>
<pre><code class="language-python">len(X)
</code></pre>
<p>because we have four training examples and we're calculating the average gradient.</p>
<p>Now calculate the output bias gradient:</p>
<pre><code class="language-python">db2 = np.mean(dz2, axis=0, keepdims=True)
</code></pre>
<p>This calculates the average gradient for the output bias.</p>
<p>Next:</p>
<pre><code class="language-python">da1 = dz2 @ W2.T
</code></pre>
<p>This sends the gradient information backward from the output layer toward the hidden layer.</p>
<p>Now we need to account for the derivative of the tanh activation function.</p>
<p>The derivative of tanh can be written as:</p>
<pre><code class="language-text">1 - tanh(x)²
</code></pre>
<p>Since we already have the hidden layer's activated values in <code>a1</code>, we can write:</p>
<pre><code class="language-python">dz1 = da1 * (1 - a1**2)
</code></pre>
<p>This tells us how the hidden layer's pre-activation values affected the loss.</p>
<p>Now calculate the gradients for the first layer's weights:</p>
<pre><code class="language-python">dW1 = (X.T @ dz1) / len(X)
</code></pre>
<p>And the hidden-layer biases:</p>
<pre><code class="language-python">db1 = np.mean(dz1, axis=0, keepdims=True)
</code></pre>
<p>At this point, we have gradients for all of our trainable parameters.</p>
<h2 id="heading-24-updating-the-weights">24. Updating the Weights</h2>
<p>Now we use gradient descent.</p>
<p>First:</p>
<pre><code class="language-python">W2 -= learning_rate * dW2
</code></pre>
<p>This updates the second layer's weights.</p>
<p>The <code>-=</code> means:</p>
<pre><code class="language-python">W2 = W2 - learning_rate * dW2
</code></pre>
<p>Then:</p>
<pre><code class="language-python">b2 -= learning_rate * db2
</code></pre>
<p>updates the output bias.</p>
<p>And:</p>
<pre><code class="language-python">W1 -= learning_rate * dW1
</code></pre>
<p>updates the first layer's weights.</p>
<p>Finally:</p>
<pre><code class="language-python">b1 -= learning_rate * db1
</code></pre>
<p>updates the hidden-layer biases.</p>
<p>These updates are what actually allow the network to learn.</p>
<h2 id="heading-25-the-complete-numpy-neural-network">25. The Complete NumPy Neural Network</h2>
<p>Now let's put everything together.</p>
<pre><code class="language-python">import numpy as np

# 1. Training data

X = np.array([
    [0, 0],
    [0, 1],
    [1, 0],
    [1, 1]
])

y = np.array([
    [0],
    [1],
    [1],
    [0]
])

# 2. Initialize parameters

np.random.seed(42)

W1 = np.random.randn(2, 4)
b1 = np.zeros((1, 4))

W2 = np.random.randn(4, 1)
b2 = np.zeros((1, 1))

learning_rate = 0.1

# 3. Activation functions

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 4. Training

for epoch in range(10000):

    # Forward propagation

    z1 = X @ W1 + b1
    a1 = np.tanh(z1)

    z2 = a1 @ W2 + b2
    a2 = sigmoid(z2)

    # Calculate loss

    loss = -np.mean(
        y * np.log(a2 + 1e-8) +
        (1 - y) * np.log(1 - a2 + 1e-8)
    )

    # Backpropagation

    dz2 = a2 - y

    dW2 = (a1.T @ dz2) / len(X)
    db2 = np.mean(dz2, axis=0, keepdims=True)

    da1 = dz2 @ W2.T

    dz1 = da1 * (1 - a1**2)

    dW1 = (X.T @ dz1) / len(X)
    db1 = np.mean(dz1, axis=0, keepdims=True)

    # Update parameters

    W2 -= learning_rate * dW2
    b2 -= learning_rate * db2

    W1 -= learning_rate * dW1
    b1 -= learning_rate * db1

    # Display progress

    if epoch % 1000 == 0:
        print(f"Epoch {epoch}, Loss: {loss:.4f}")
</code></pre>
<p>Let's go through the program from top to bottom.</p>
<h3 id="heading-line-by-line-explanation-of-the-full-code">Line-by-Line Explanation of the Full Code</h3>
<h4 id="heading-importing-numpy">Importing NumPy:</h4>
<pre><code class="language-python">import numpy as np
</code></pre>
<p>We import NumPy because our network will work with arrays and matrix operations.</p>
<h4 id="heading-creating-the-inputs">Creating the inputs</h4>
<pre><code class="language-python">X = np.array([
    [0, 0],
    [0, 1],
    [1, 0],
    [1, 1]
])
</code></pre>
<p>Each row is one XOR example.</p>
<p>There are four examples and two input values per example.</p>
<p>So the shape of <code>X</code> is:</p>
<pre><code class="language-text">4 × 2
</code></pre>
<h4 id="heading-creating-the-answers">Creating the answers</h4>
<pre><code class="language-python">y = np.array([
    [0],
    [1],
    [1],
    [0]
])
</code></pre>
<p>There are four correct answers, one for each row in <code>X</code>.</p>
<h4 id="heading-making-random-initialization-reproducible">Making random initialization reproducible</h4>
<pre><code class="language-python">np.random.seed(42)
</code></pre>
<p>This makes NumPy generate the same starting random values each time.</p>
<p>The number <code>42</code> isn't special. You could use another number.</p>
<h4 id="heading-creating-the-first-weight-matrix">Creating the first weight matrix</h4>
<pre><code class="language-python">W1 = np.random.randn(2, 4)
</code></pre>
<p>This creates a matrix containing random numbers.</p>
<p>Its shape is 2*4</p>
<p>There are two inputs and four hidden neurons.</p>
<h4 id="heading-creating-the-first-biases">Creating the first biases</h4>
<pre><code class="language-python">b1 = np.zeros((1, 4))
</code></pre>
<p>This creates four zeros:</p>
<pre><code class="language-text">[0, 0, 0, 0]
</code></pre>
<p>There is one bias for every hidden neuron.</p>
<h4 id="heading-creating-the-second-weight-matrix">Creating the second weight matrix</h4>
<pre><code class="language-python">W2 = np.random.randn(4, 1)
</code></pre>
<p>There are four hidden neurons and one output neuron.</p>
<p>Therefore:</p>
<pre><code class="language-text">4 × 1
</code></pre>
<p>weights are needed.</p>
<h4 id="heading-creating-the-output-bias">Creating the output bias</h4>
<pre><code class="language-python">b2 = np.zeros((1, 1))
</code></pre>
<p>The output layer has one neuron, so it needs one bias.</p>
<h4 id="heading-setting-the-learning-rate">Setting the learning rate</h4>
<pre><code class="language-python">learning_rate = 0.1
</code></pre>
<p>This controls how strongly the gradients affect each update.</p>
<h4 id="heading-creating-sigmoid">Creating sigmoid</h4>
<pre><code class="language-python">def sigmoid(x):
    return 1 / (1 + np.exp(-x))
</code></pre>
<p>This converts the output into a value between <code>0</code> and <code>1</code>.</p>
<h3 id="heading-starting-the-training-loop">Starting the Training Loop</h3>
<pre><code class="language-python">for epoch in range(10000):
</code></pre>
<p>This tells Python to repeat the training process 10,000 times.</p>
<p>Each repetition is an epoch, which is one complete pass of the entire training dataset through a neural network</p>
<h4 id="heading-calculating-the-hidden-layer">Calculating the hidden layer</h4>
<pre><code class="language-python">z1 = X @ W1 + b1
</code></pre>
<p>This performs the weighted-sum calculation for all four hidden neurons and all four training examples.</p>
<h4 id="heading-applying-tanh">Applying tanh</h4>
<pre><code class="language-python">a1 = np.tanh(z1)
</code></pre>
<p>This applies the nonlinear activation function to the hidden layer.</p>
<h4 id="heading-calculating-the-output-layer">Calculating the output layer</h4>
<pre><code class="language-python">z2 = a1 @ W2 + b2
</code></pre>
<p>This takes the hidden layer's values and calculates the output neuron's weighted sum.</p>
<h4 id="heading-applying-sigmoid">Applying sigmoid</h4>
<pre><code class="language-python">a2 = sigmoid(z2)
</code></pre>
<p>This turns the output into probabilities between <code>0</code> and <code>1</code>.</p>
<h4 id="heading-calculating-the-loss">Calculating the loss</h4>
<pre><code class="language-python">loss = -np.mean(
    y * np.log(a2 + 1e-8) +
    (1 - y) * np.log(1 - a2 + 1e-8)
)
</code></pre>
<p>This measures how different the predictions are from the correct answers.</p>
<p>A lower value generally means the predictions are better.</p>
<h4 id="heading-calculating-the-output-gradient">Calculating the output gradient</h4>
<pre><code class="language-python">dz2 = a2 - y
</code></pre>
<p>This calculates the gradient needed to update the output layer.</p>
<h4 id="heading-updating-the-second-layer-weight-gradients">Updating the second-layer weight gradients</h4>
<pre><code class="language-python">dW2 = (a1.T @ dz2) / len(X)
</code></pre>
<p>This determines how each weight connecting the hidden layer to the output layer contributed to the loss.</p>
<h4 id="heading-updating-the-output-bias-gradient">Updating the output bias gradient</h4>
<pre><code class="language-python">db2 = np.mean(dz2, axis=0, keepdims=True)
</code></pre>
<p>This calculates the average gradient for the output bias.</p>
<h4 id="heading-moving-backward-toward-the-hidden-layer">Moving backward toward the hidden layer</h4>
<pre><code class="language-python">da1 = dz2 @ W2.T
</code></pre>
<p>This passes the gradient information backward through the output layer.</p>
<h4 id="heading-applying-the-tanh-derivative">Applying the tanh derivative</h4>
<pre><code class="language-python">dz1 = da1 * (1 - a1**2)
</code></pre>
<p>This accounts for the effect of the tanh activation function.</p>
<h4 id="heading-calculating-the-first-layer-gradients">Calculating the first-layer gradients</h4>
<pre><code class="language-python">dW1 = (X.T @ dz1) / len(X)
</code></pre>
<p>This determines how the input-to-hidden weights contributed to the loss.</p>
<p>Then:</p>
<pre><code class="language-python">db1 = np.mean(dz1, axis=0, keepdims=True)
</code></pre>
<p>calculates the gradients for the hidden-layer biases.</p>
<h4 id="heading-updating-the-parameters">Updating the parameters</h4>
<pre><code class="language-python">W2 -= learning_rate * dW2
b2 -= learning_rate * db2

W1 -= learning_rate * dW1
b1 -= learning_rate * db1
</code></pre>
<p>These four lines are where the network changes what it has learned.</p>
<p>The gradients tell us which direction to move, while the learning rate determines how large the movement should be.</p>
<h4 id="heading-printing-the-loss">Printing the loss</h4>
<pre><code class="language-python">if epoch % 1000 == 0:
    print(f"Epoch {epoch}, Loss: {loss:.4f}")
</code></pre>
<p>The <code>%</code> operator gives us the remainder after division.</p>
<p>So:</p>
<pre><code class="language-python">epoch % 1000 == 0
</code></pre>
<p>is true every 1,000 epochs.</p>
<p>That means we don't print something 10,000 times. Instead, we get occasional updates such as:</p>
<pre><code class="language-text">Epoch 0, Loss: ...
Epoch 1000, Loss: ...
Epoch 2000, Loss: ...
...
</code></pre>
<p>If training is working well, the loss should generally decrease.</p>
<h2 id="heading-26-testing-the-network">26. Testing the Network</h2>
<p>After training, we can use the network to make predictions.</p>
<pre><code class="language-python">z1 = X @ W1 + b1
a1 = np.tanh(z1)

z2 = a1 @ W2 + b2
predictions = sigmoid(z2)

print(predictions)
</code></pre>
<p>The network should produce values close to:</p>
<pre><code class="language-text">[[0],
 [1],
 [1],
 [0]]
</code></pre>
<p>The actual values probably won't be exactly <code>0</code> and <code>1</code>.</p>
<p>You might get something more like:</p>
<pre><code class="language-text">[[0.01],
 [0.98],
 [0.99],
 [0.02]]
</code></pre>
<p>That's fine.</p>
<p>The network is producing probabilities.</p>
<p>We can convert those probabilities into classes using a threshold:</p>
<pre><code class="language-python">classes = (predictions &gt;= 0.5).astype(int)

print(classes)
</code></pre>
<p>The result should be:</p>
<pre><code class="language-text">[[0],
 [1],
 [1],
 [0]]
</code></pre>
<p>Our network has learned the XOR pattern.</p>
<h2 id="heading-27-why-did-we-need-a-hidden-layer">27. Why Did We Need a Hidden Layer?</h2>
<p>You might wonder why we couldn't just connect the two inputs directly to the output.</p>
<p>The reason is that XOR isn't something a single linear layer can represent.</p>
<p>The hidden layer gives the network additional transformations that allow it to learn the more complicated relationship.</p>
<p>This is one of the most important ideas behind neural networks: a network doesn't necessarily learn one giant rule. Instead, different layers can transform information step by step.</p>
<p>For an image recognition system, you can imagine a simplified process like:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/1bf62ced-92e8-4ee2-ba7f-fba16fde006f.png" alt="Image recognition system visually depicted" style="display: block;" width="1024" height="1536" loading="lazy">

<p>Real neural networks don't literally create neat layers called "edges," "shapes," and "objects." This is just an intuition for how increasingly complex representations can emerge through multiple layers.</p>
<h2 id="heading-28-what-happens-in-a-larger-neural-network">28. What Happens in a Larger Neural Network?</h2>
<p>The network we built is tiny. Modern neural networks can have millions, billions, or even more parameters.</p>
<p>A simplified network might look like:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/9007ed47-0c1f-4b72-99e6-194010fdfc20.png" alt="Simplified neural network visually depicted" style="display: block;" width="1086" height="1448" loading="lazy">

<p>Each connection can have its own weight.</p>
<p>The more neurons and connections a network has, the more parameters it may need to learn.</p>
<p>Large models therefore require significant amounts of computing power and memory.</p>
<p>But remember the basic process:</p>
<pre><code class="language-text">Input
 ↓
Calculations
 ↓
Prediction
 ↓
Loss
 ↓
Gradients
 ↓
Parameter Updates
</code></pre>
<p>The size of the network changes dramatically, but the basic training idea remains.</p>
<h2 id="heading-29-do-you-have-to-build-neural-networks-from-scratch">29. Do You Have to Build Neural Networks From Scratch?</h2>
<p>No. Building a neural network from scratch is useful for learning because it forces you to understand what's happening underneath the libraries.</p>
<p>But you normally wouldn't manually calculate every gradient when building a real machine learning application.</p>
<p>That's where machine learning frameworks come in. Some commonly used Python libraries include:</p>
<ul>
<li><p>NumPy</p>
</li>
<li><p>PyTorch</p>
</li>
<li><p>TensorFlow</p>
</li>
<li><p>Keras</p>
</li>
<li><p>scikit-learn</p>
</li>
</ul>
<p>For deep learning, <strong>PyTorch</strong> is one of the most commonly used frameworks. It can automatically calculate gradients and handle many of the mathematical operations involved in training.</p>
<h2 id="heading-30-building-the-same-network-with-pytorch">30. Building the Same Network With PyTorch</h2>
<p>Let's see how much shorter the network becomes with PyTorch.</p>
<p>First, install it:</p>
<pre><code class="language-bash">pip install torch
</code></pre>
<p>Then import it:</p>
<pre><code class="language-python">import torch
import torch.nn as nn
</code></pre>
<p>Now create the model:</p>
<pre><code class="language-python">model = nn.Sequential(
    nn.Linear(2, 4),
    nn.Tanh(),
    nn.Linear(4, 1),
    nn.Sigmoid()
)
</code></pre>
<p>Let's break that down.</p>
<pre><code class="language-python">nn.Linear(2, 4)
</code></pre>
<p>creates a layer that takes two inputs and produces four outputs.</p>
<p>That's our hidden layer.</p>
<p>Next:</p>
<pre><code class="language-python">nn.Tanh()
</code></pre>
<p>applies the tanh activation function.</p>
<p>Then:</p>
<pre><code class="language-python">nn.Linear(4, 1)
</code></pre>
<p>connects the four hidden neurons to one output neuron.</p>
<p>Finally:</p>
<pre><code class="language-python">nn.Sigmoid()
</code></pre>
<p>converts the output into a value between <code>0</code> and <code>1</code>.</p>
<p>So the architecture is:</p>
<pre><code class="language-text">2 inputs
   ↓
4 hidden neurons
   ↓
Tanh
   ↓
1 output neuron
   ↓
Sigmoid
</code></pre>
<p>Notice how much shorter this is than our NumPy implementation.</p>
<p>That's because PyTorch handles many of the calculations for us.</p>
<h2 id="heading-31-training-the-network-with-pytorch">31. Training the Network With PyTorch</h2>
<p>First, create the training data:</p>
<pre><code class="language-python">X = torch.tensor([
    [0., 0.],
    [0., 1.],
    [1., 0.],
    [1., 1.]
])

y = torch.tensor([
    [0.],
    [1.],
    [1.],
    [0.]
])
</code></pre>
<p>The decimal points are important because neural networks normally work with floating-point numbers.</p>
<p>Now create the model:</p>
<pre><code class="language-python">model = nn.Sequential(
    nn.Linear(2, 4),
    nn.Tanh(),
    nn.Linear(4, 1),
    nn.Sigmoid()
)
</code></pre>
<p>Next, choose our loss function:</p>
<pre><code class="language-python">loss_function = nn.BCELoss()
</code></pre>
<p><code>BCELoss</code> calculates binary cross-entropy loss.</p>
<p>Now create an optimizer:</p>
<pre><code class="language-python">optimizer = torch.optim.Adam(
    model.parameters(),
    lr=0.01
)
</code></pre>
<p>Adam is an optimization algorithm that updates the model's parameters during training.</p>
<p><code>model.parameters()</code> tells the optimizer which values it should update.</p>
<p><code>lr=0.01</code> sets the learning rate.</p>
<p>Now we can train:</p>
<pre><code class="language-python">for epoch in range(5000):

    predictions = model(X)

    loss = loss_function(predictions, y)

    optimizer.zero_grad()

    loss.backward()

    optimizer.step()

    if epoch % 500 == 0:
        print(
            f"Epoch {epoch}, Loss: {loss.item():.4f}"
        )
</code></pre>
<p>Let's look at the important parts.</p>
<p>First:</p>
<pre><code class="language-python">predictions = model(X)
</code></pre>
<p>This sends the training data through the network.</p>
<p>Then:</p>
<pre><code class="language-python">loss = loss_function(predictions, y)
</code></pre>
<p>compares the predictions with the correct answers.</p>
<p>Next:</p>
<pre><code class="language-python">optimizer.zero_grad()
</code></pre>
<p>clears gradients from the previous training step.</p>
<p>Then:</p>
<pre><code class="language-python">loss.backward()
</code></pre>
<p>calculates the gradients automatically using backpropagation.</p>
<p>Finally:</p>
<pre><code class="language-python">optimizer.step()
</code></pre>
<p>uses those gradients to update the model's parameters.</p>
<p>That's the same basic learning process we implemented manually with NumPy. The difference is that PyTorch takes care of many of the calculations.</p>
<h2 id="heading-32-numpy-vs-pytorch">32. NumPy vs. PyTorch</h2>
<p>So why did we build the network twice? Well, because the two versions teach different things.</p>
<p>With NumPy, we manually handled weights, biases, forward propagation,<br>loss, gradients, backpropagation, and parameter updates. That makes the mechanics easier to see.</p>
<p>With PyTorch, we can write the same general idea in much less code because the framework handles many of those calculations.</p>
<p>You can think of it like this:</p>
<img src="https://cdn.hashnode.com/uploads/covers/6a581501af6af179dc1987d5/6230c12c-34ef-4ab3-9f9f-f99eaebcf295.png" alt="Comparison between NumPy and PyTorch" style="display: block;" width="1086" height="1448" loading="lazy">

<p>Learning how the NumPy version works makes the PyTorch version much less mysterious.</p>
<h2 id="heading-33-what-is-deep-learning">33. What Is Deep Learning?</h2>
<p>You may have heard the term <strong>deep learning</strong>. Deep learning is a part of machine learning that uses neural networks with multiple layers.</p>
<p>For example:</p>
<pre><code class="language-text">Input
  ↓
Layer 1
  ↓
Layer 2
  ↓
Layer 3
  ↓
Layer 4
  ↓
Output
</code></pre>
<p>The word "deep" refers to the depth of the network, or the number of layers involved.</p>
<p>There isn't a magical point where a neural network suddenly becomes intelligent. Adding layers simply gives the model more opportunities to transform the input into useful representations.</p>
<h2 id="heading-34-where-are-neural-networks-used">34. Where Are Neural Networks Used?</h2>
<p>Neural networks are used in many different areas. Here are a few examples...</p>
<h3 id="heading-computer-vision">Computer Vision</h3>
<p>Neural networks can process images.</p>
<p>For example:</p>
<pre><code class="language-text">Image
  ↓
Neural Network
  ↓
Prediction
</code></pre>
<p>They can be used for tasks such as image classification and object detection.</p>
<h3 id="heading-natural-language-processing">Natural Language Processing</h3>
<p>Neural networks can also process text.</p>
<p>For example:</p>
<pre><code class="language-text">Text
  ↓
Neural Network
  ↓
Prediction
</code></pre>
<p>Modern language models use neural networks to process and generate text.</p>
<h3 id="heading-speech-recognition">Speech Recognition</h3>
<p>Neural networks can process audio and help convert spoken language into text.</p>
<pre><code class="language-text">Audio
  ↓
Neural Network
  ↓
Words
</code></pre>
<h3 id="heading-recommendation-systems">Recommendation Systems</h3>
<p>Neural networks can learn patterns from user behavior and help predict which content or products might be useful to someone.</p>
<h3 id="heading-generative-ai">Generative AI</h3>
<p>Large neural networks can also be used to generate text, images, audio, code, video, and much more.</p>
<p>These systems are much more complicated than the small XOR network we built, but they still rely on the same general idea of learning parameters from data.</p>
<h2 id="heading-35-the-whole-process-in-one-picture">35. The Whole Process in One Picture</h2>
<p>At this point, we've covered a lot.</p>
<p>Here's the entire training process:</p>
<pre><code class="language-text">Data
   ↓
Neural Network
   ↓
Prediction
   ↓
Loss
  ↓
Backpropagation
  ↓
Update Parameters
  ↓
Repeat
</code></pre>
<p>Once training is finished, we use the learned parameters to make predictions on new data:</p>
<pre><code class="language-text">New Data
   ↓
Trained Neural Network
   ↓
Prediction
</code></pre>
<p>That's the basic idea behind neural network training.</p>
<h2 id="heading-36-the-most-important-ideas-to-remember">36. The Most Important Ideas to Remember</h2>
<p>If you don't remember every equation from this tutorial, that's okay.</p>
<p>Start with these concepts.</p>
<h3 id="heading-inputs">Inputs</h3>
<p>The numbers we give to the network.</p>
<pre><code class="language-text">x₁, x₂, x₃...
</code></pre>
<h3 id="heading-weights">Weights</h3>
<p>Numbers that determine how strongly inputs affect neurons.</p>
<pre><code class="language-text">w₁, w₂, w₃...
</code></pre>
<h3 id="heading-biases">Biases</h3>
<p>Additional values that give neurons more flexibility.</p>
<pre><code class="language-text">b
</code></pre>
<h3 id="heading-activation-functions">Activation Functions</h3>
<p>Functions that transform neuron outputs and allow networks to learn nonlinear patterns.</p>
<p>Examples include:</p>
<pre><code class="language-text">ReLU
Tanh
Sigmoid
</code></pre>
<h3 id="heading-forward-propagation">Forward Propagation</h3>
<p>Sending data from the input toward the output.</p>
<pre><code class="language-text">Input → Hidden Layers → Output
</code></pre>
<h3 id="heading-loss">Loss</h3>
<p>A measurement of how different the prediction is from the correct answer.</p>
<h3 id="heading-backpropagation">Backpropagation</h3>
<p>Calculating gradients by working backward through the network.</p>
<h3 id="heading-gradient-descent">Gradient Descent</h3>
<p>Using those gradients to update the network's parameters.</p>
<p>And the entire learning process can be summarized as:</p>
<pre><code class="language-text">Predict
   ↓
Measure Error
   ↓
Calculate Gradients
   ↓
Update Parameters
   ↓
Repeat
</code></pre>
<h2 id="heading-37-what-should-you-learn-next">37. What Should You Learn Next?</h2>
<p>If you want to continue learning neural networks with Python, you don't need to jump directly into complicated research papers.</p>
<p>A useful learning path is:</p>
<pre><code class="language-text">Python
  ↓
NumPy
  ↓
Basic Linear Algebra
  ↓
Probability &amp; Statistics
  ↓
Machine Learning Basics
  ↓
Neural Networks
  ↓
PyTorch
  ↓
Deep Learning
  ↓
Computer Vision / NLP / Generative AI
</code></pre>
<p>You can also learn by building small projects.</p>
<p>For example:</p>
<ol>
<li><p>XOR classifier</p>
</li>
<li><p>House price predictor</p>
</li>
<li><p>Handwritten digit classifier</p>
</li>
<li><p>Simple image classifier</p>
</li>
<li><p>Spam message classifier</p>
</li>
<li><p>Neural network that learns a mathematical function</p>
</li>
</ol>
<p>The projects don't need to be huge. A small project that you completely understand is often more useful than a large project where you copied code without understanding it.</p>
<h2 id="heading-final-takeaway">Final Takeaway</h2>
<p>Neural networks can look intimidating because the systems used in modern AI can contain enormous numbers of parameters.</p>
<p>But the basic idea is much smaller.</p>
<p>A neural network takes numbers as input, combines them using weights and biases, applies mathematical functions, produces a prediction, measures how wrong that prediction was, and then adjusts its parameters.</p>
<p>The cycle looks like this:</p>
<pre><code class="language-text">Input
  ↓
Weighted Calculations
  ↓
Activation Functions
  ↓
Prediction
  ↓
Loss
  ↓
Gradients
  ↓
Parameter Updates
  ↓
Repeat
</code></pre>
<p>That's the foundation.</p>
<p>The XOR network we built in this tutorial is tiny compared with the neural networks used in modern AI. But the ideas you just learned (parameters, layers, activation functions, forward propagation, loss, backpropagation, gradients, and optimization) are fundamental ideas that appear again and again in deep learning.</p>
<p>The next time you hear that an AI model has millions or billions of parameters, it might still sound overwhelming.</p>
<p>But underneath all that scale, the basic learning loop is still familiar:</p>
<ol>
<li><p>Make a prediction.</p>
</li>
<li><p>Measure the error.</p>
</li>
<li><p>Figure out how to improve.</p>
</li>
<li><p>Update the parameters.</p>
</li>
<li><p>Try again.</p>
</li>
</ol>
<p>And that's the core idea behind a neural network.</p>
<p>Happy coding and keep learning!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
