AgenticWorks

A community for developers awakening to agentic AI. Hands-on lessons, enterprise-grade context engineering, and a forum that earns its quiet.

Platform

  • Learn
  • Forum
  • Showcase

Project

  • About

Community

  • Network
  • Code of conduct

Field reports

Monthly notes on what shipped, what broke, and what we learned.

© 2026 AgenticWorks. Built in public.

AgenticWorks
LearnShowcaseForumCommunity
Sign in

Track 1 · ML foundations

Brain's Decision Committee
  1. 01The first neuron
  2. 02A single neuron
  3. 03Activation functions
  4. 04The perceptron
  5. 05Training
  6. 06Evaluation
  7. 07Hidden layers
  8. 08Deep learning challenges
  9. 09Full implementation
  10. 10What's next
MatricesPart 1 · 45 min · beginner

The language of the committee

Meet the Brain's Decision Committee and learn why images become matrices before a model can reason about them.

Open in ColabDownload notebookFull lab fallback
Kernel: ColdSections: 0/18

Neural Network Fundamentals

A Journey from Matrices to Machine Learning


Part 0: Welcome to the Brain's Decision Committee

"The best way to understand something is to build it from scratch."


What is This Notebook?

Welcome to a hands-on journey through the fundamentals of neural networks. Whether you're a complete beginner curious about AI, a data professional looking to solidify your foundations, or someone who's used machine learning libraries but never quite understood what's happening "under the hood", this notebook is for you.

By the end of this journey, you won't just know what a neural network is. You'll have built one yourself, piece by piece, understanding every component along the way.


Why Should You Care About Fundamentals?

In 2025, it's easy to import a library and train a model in three lines of code:

from magic_library import NeuralNetwork
model = NeuralNetwork()
model.fit(data)  # Done!

So why bother understanding what's inside?

The Problem with Black Boxes

When something goes wrong (and it will), you'll be lost. When your model doesn't learn, when accuracy plateaus, when predictions make no sense, without fundamentals, you're just randomly adjusting knobs hoping something works.

The Power of Understanding

When you understand the fundamentals:

  • Debugging becomes intuitive - "Oh, the gradients are vanishing because of my activation choice"
  • Architecture decisions make sense - "I need more hidden layers because this problem isn't linearly separable"
  • You can innovate - The people who created transformers, GANs, and diffusion models didn't follow tutorials; they understood principles deeply enough to create something new

This Notebook's Promise

We're going to start with nothing but basic Python and NumPy and build our way up to a working neural network that can recognize patterns. Every step will be explained, visualized, and practiced.

No magic. No black boxes. Just understanding.


🧠 Why "The Brain's Decision Committee"?

Throughout this notebook, we use a consistent analogy: The Brain's Decision Committee. Here's why this analogy works so well and why it will help you understand neural networks more deeply than any mathematical formula alone.

The Inspiration: Your Actual Brain

Neural networks were inspired by biological neurons in your brain. When you look at an image and recognize a face, you're not running a single calculation. Instead:

  1. Millions of neurons receive signals (light hitting your retina)
  2. Each neuron decides whether to "fire" based on its inputs
  3. Information flows through layers of neurons, each extracting more abstract features
  4. A final decision emerges - "That's my friend Sarah!"

This is remarkably similar to how artificial neural networks work.

The Committee Analogy

Imagine a committee of experts tasked with making a decision. Let's say they need to determine: "Is this image showing a vertical line or a horizontal line?"

Real CommitteeNeural Network
Each member reviews the evidenceEach neuron receives input data
Members have different areas of expertiseNeurons have different weights (priorities)
Each member has their own threshold for saying "yes"Each neuron has a bias
Members vote based on the evidenceNeurons output based on their activation function
The committee learns from past mistakesThe network trains on examples
Sub-committees handle specialized questionsHidden layers extract features

Why This Analogy Matters

This isn't just a cute metaphor, it's a mental model that will help you:

  1. Intuitively understand what's happening inside a neural network
  2. Debug problems by thinking "What would a confused committee member do wrong?"
  3. Design better networks by asking "What kinds of specialists do I need?"
  4. Explain concepts to others without drowning in mathematics

As we progress through this notebook, we'll keep returning to our committee. You'll meet:

  • The First Committee Member (a single neuron)
  • Different Voting Methods (activation functions)
  • The Learning Process (training via backpropagation)
  • The Full Committee (multi-layer networks)
  • Committee Challenges (overfitting, vanishing gradients)

Story Progression as we go through each part

PartStory BeatThe Committee's Journey
Part 0Introduction"Meet the committee - they have a job to do"
Part 1Learning the Language"The committee learns to read images as numbers"
Part 2The First Member"One brave committee member steps up to try first"
Part 3Learning to Vote"The member learns different ways to cast their vote"
Part 4First Attempt"The untrained member makes random guesses"
Part 5Learning from Mistakes"The member reflects on errors and adjusts"
Part 6Becoming an Expert"After training, the member is now skilled"
Part 7Assembling the Team"One expert isn't enough - we need a full committee"
Part 8Growing Pains"The committee faces challenges as it grows"
Part 9Mastery"The complete, trained committee works in harmony"
Part 10The Future"What other problems can committees solve?"

Complete Analogy Mapping and Main Technical concepts coverd in this Notebook that covers most of the core concepts in Nural Netwoks and Deeplearning.

Technical ConceptCommittee AnalogyFirst Introduced
Neural NetworkThe Brain's Decision CommitteePart 0
Input DataEvidence/documents to reviewPart 1
MatrixOrganized evidence report (grid format)Part 1
Feature ScalingTranslating to a common languagePart 1.5
Dot ProductMeasuring agreement between opinion and evidencePart 1.6
Matrix MultiplicationMultiple members reviewing evidence at oncePart 1.7
NeuronA single committee memberPart 2
WeightsHow strongly a member values each piece of evidencePart 2.4
BiasPersonal threshold ("I need THIS much to say yes")Part 2.6
Activation FunctionThe voting methodPart 3
Step FunctionBinary vote (YES or NO, nothing in between)Part 3.2
SigmoidConfidence vote (0-100% sure)Part 3.3
TanhCentered vote (-100% to +100%)Part 3.4
ReLU"If not convinced, stay silent"Part 3.5
Dead ReLUPermanently skeptical member (never speaks again)Part 3.5
SoftmaxConsensus vote (all options must sum to 100%)Part 3.6
PerceptronThe first working committee memberPart 4
Forward PassInformation flowing through the committeePart 4.3
Loss/ErrorHow wrong the committee's decision wasPart 5.1
MSEAverage squared wrongnessPart 5.2
Cross-EntropyWrongness for yes/no decisionsPart 5.3
Gradient DescentRolling downhill to find the best solutionPart 5.4
Local MinimumCommittee deadlock (stuck on mediocre solution)Part 5.4
Learning RateHow much to adjust after each mistakePart 5.5
GradientDirection to improvePart 5.6
BackpropagationTracing blame back through the committeePart 5.7
TrainingCommittee meetings where they learn and arguePart 5
InferenceUsing the final handbook (no more learning)Part 6.1
Saliency/InterpretabilityCommittee report highlighting key evidencePart 6.4
Hidden LayerSub-committee of specialistsPart 7
Multiple NeuronsDifferent members looking for different thingsPart 7.3
OverfittingMemorizing specific cases instead of learning patternsPart 8.1
RegularizationRules to prevent memorizationPart 8.3
DropoutRandomly silencing members to prevent over-reliancePart 8.3
Vanishing GradientWhispered feedback lost through too many layersPart 8.4
Exploding GradientFeedback echoing too loudly, causing chaosPart 8.5
Batch NormalizationKeeping everyone's voice at similar volumePart 8.6

By the end, you'll have a complete mental model that maps perfectly to the mathematics.


📐 A Note on Mathematics: Please Engage!

This notebook includes mathematical formulas. Please don't skip them!

Why Math Matters Here

Neural networks are, at their core, mathematical functions. The "magic" is just:

  • Multiplication
  • Addition
  • Some special functions (like sigmoid)
  • Derivatives (for learning)

That's it. No advanced calculus, no abstract algebra. If you can multiply numbers and understand that "slope tells you which way is downhill," you have everything you need.

Our Approach to Math

For every formula, we provide:

  1. The formula itself - Because precision matters
  2. A plain-English explanation - What does this actually mean?
  3. A worked example - Let's calculate it together
  4. Code implementation - See it running

The Request: Get Your Hands Dirty

This notebook is interactive. You're not just reading - you're building.

Please:

  • Run every code cell - Don't just read the output
  • Modify values - Change a number and see what happens
  • Do the exercises - They're there to cement understanding
  • Break things - Set the learning rate to 100 and watch chaos unfold
  • Ask "what if" - Curiosity drives learning

A Promise

By the end of this notebook, you will be able to:

  1. Look at a neural network diagram and understand every component
  2. Implement a neural network from scratch (no libraries hiding the logic)
  3. Debug common training problems by understanding their causes
  4. Explain neural networks to others using clear analogies

Let's begin.

cell 007
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# =============================================================================# SETUP: Import our tools# =============================================================================# Run this cell first! Everything else depends on these imports. import numpy as np                    # For numerical operations (matrices, math)import matplotlib.pyplot as plt       # For visualizationimport matplotlib.patches as patches  # For drawing shapesfrom matplotlib.colors import LinearSegmentedColormap  # Custom colormapsfrom IPython.display import display, clear_output, HTML  # For notebook display # Try to import ipywidgets (optional - some features won't work without it)try:    import ipywidgets as widgets    WIDGETS_AVAILABLE = Trueexcept ImportError:    WIDGETS_AVAILABLE = False    print("⚠️  ipywidgets not installed. Interactive features will be limited.")    print("   Install with: pip install ipywidgets") # Configure matplotlib for better-looking plots# Try different style names for compatibility across matplotlib versionsstyle_options = ['seaborn-v0_8-whitegrid', 'seaborn-whitegrid', 'ggplot', 'default']for style in style_options:    try:        plt.style.use(style)        break    except OSError:        continue plt.rcParams['figure.figsize'] = [10, 6]  # Default figure sizeplt.rcParams['font.size'] = 12            # Readable font sizeplt.rcParams['axes.titlesize'] = 14       # Slightly larger titles # Set random seed for reproducibility# This ensures you get the same "random" numbers as the examplesnp.random.seed(42) print(" All libraries imported successfully!")print(f"   NumPy version: {np.__version__}")print(f"   Matplotlib version: {plt.matplotlib.__version__}")if WIDGETS_AVAILABLE:    print(f"   IPyWidgets available: Yes")else:    print(f"   IPyWidgets available: No (interactive labs won't work)")print("\n Welcome to Neural Network Fundamentals!")print("   Let's build a brain together.")

Part 1: The Language of the Brain - Matrices

"Before our committee can deliberate, they need a common language to describe what they see. That language is mathematics - specifically, matrices."


1.1 What is a Matrix?

At its simplest, a matrix is just a grid of numbers arranged in rows and columns. That's it. No magic, no complexity - just organized numbers.

You've seen matrices before, even if you didn't call them that:

  • A spreadsheet is a matrix
  • A seating chart is a matrix
  • A game board (chess, sudoku) is a matrix
  • And most importantly for us: an image is a matrix

The Anatomy of a Matrix

A matrix is described by its dimensions: the number of rows and columns it has.

  • A 3x3 matrix has 3 rows and 3 columns (9 numbers total)
  • A 2x4 matrix has 2 rows and 4 columns (8 numbers total)
  • A 1xN matrix is a single row (also called a "row vector")
  • A Nx1 matrix is a single column (also called a "column vector")

Mathematical Notation

We typically use capital letters for matrices and subscripts for elements. For example, element a_ij means "the element in row i, column j".

A = [a₁₁  a₁₂  a₁₃]
    [a₂₁  a₂₂  a₂₃]
    [a₃₁  a₃₂  a₃₃]
cell 009
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# =============================================================================# Creating Matrices in NumPy# =============================================================================# Let's create our first matrices and explore their properties # A simple 3x3 matrixA = np.array([    [1, 2, 3],    [4, 5, 6],    [7, 8, 9]]) print("Matrix A:")print(A)print(f"\nShape: {A.shape}")  # (rows, columns)print(f"This is a {A.shape[0]}x{A.shape[1]} matrix")print(f"Total elements: {A.size}") # Accessing individual elementsprint(f"\nElement at row 1, column 2 (a_12): {A[0, 1]}")  # Note: Python uses 0-based indexing!print(f"Element at row 2, column 3 (a_23): {A[1, 2]}")print(f"Element at row 3, column 1 (a_31): {A[2, 0]}")

1.2 Our First 3x3 Image: The Line Detection Problem

Here's the key insight that makes neural networks possible: images are just matrices of numbers.

Every digital image is a grid of pixels, and each pixel is represented by a number. A grayscale image is literally a matrix where:

  • 0 = black (no light)
  • 1 = white (full light)
  • Values in between = shades of gray

Our Mission's Data

Remember our mission: detect vertical vs horizontal lines. Let's represent them as 3x3 matrices.

Vertical Line (label = 1): The middle column is "lit up"

Horizontal Line (label = 0): The middle row is "lit up"

These tiny 3x3 images are the "evidence" that our committee will analyze!

Vertical LineLabel: 1
0
1
0
0
1
0
0
1
0
Horizontal LineLabel: 0
0
0
0
1
1
1
0
0
0

As flattened vectors

Vertical Line:[0, 1, 0, 0, 1, 0, 0, 1, 0]
Horizontal Line:[0, 0, 0, 1, 1, 1, 0, 0, 0]
cell 011
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# =============================================================================# Creating Our Line Images# =============================================================================# These are the images our neural network will learn to classify # Vertical line: middle column is 1, rest is 0vertical_line = np.array([    [0, 1, 0],    [0, 1, 0],    [0, 1, 0]]) # Horizontal line: middle row is 1, rest is 0horizontal_line = np.array([    [0, 0, 0],    [1, 1, 1],    [0, 0, 0]]) print("Vertical Line (Label = 1):")print(vertical_line)print("\nHorizontal Line (Label = 0):")print(horizontal_line)
cell 012
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# =============================================================================# Visualizing Our Line Images# =============================================================================# Let's see what these matrices look like as actual images# Don't get too bogged down by the code here, it's just for visualization. # Most of the code used in the match to denote the matrices will like the one above as simple as possible to get the core concepts across. def visualize_matrix(matrix, title="Matrix", show_values=True, cmap='gray_r'):    """Visualize a matrix as a heatmap with optional value annotations."""    fig, ax = plt.subplots(figsize=(5, 5))    im = ax.imshow(matrix, cmap=cmap, vmin=0, vmax=1)    ax.set_xticks(np.arange(-0.5, matrix.shape[1], 1), minor=True)    ax.set_yticks(np.arange(-0.5, matrix.shape[0], 1), minor=True)    ax.grid(which='minor', color='black', linestyle='-', linewidth=2)        if show_values:        for i in range(matrix.shape[0]):            for j in range(matrix.shape[1]):                value = matrix[i, j]                text_color = 'white' if value > 0.5 else 'black'                ax.text(j, i, f'{value:.1f}', ha='center', va='center',                        color=text_color, fontsize=16, fontweight='bold')        ax.set_title(title, fontsize=14, fontweight='bold')    ax.set_xticks(range(matrix.shape[1]))    ax.set_yticks(range(matrix.shape[0]))    plt.tight_layout()    return fig, ax # Visualize both line types side by sidefig, axes = plt.subplots(1, 2, figsize=(12, 5)) for ax, (matrix, title, label) in zip(axes, [    (vertical_line, "VERTICAL LINE", "Label = 1"),    (horizontal_line, "HORIZONTAL LINE", "Label = 0")]):    im = ax.imshow(matrix, cmap='gray_r', vmin=0, vmax=1)    ax.set_xticks(np.arange(-0.5, 3, 1), minor=True)    ax.set_yticks(np.arange(-0.5, 3, 1), minor=True)    ax.grid(which='minor', color='black', linestyle='-', linewidth=2)        for i in range(3):        for j in range(3):            value = matrix[i, j]            text_color = 'white' if value > 0.5 else 'black'            ax.text(j, i, f'{int(value)}', ha='center', va='center',                    color=text_color, fontsize=20, fontweight='bold')        ax.set_title(f'{title}\n({label})', fontsize=14, fontweight='bold')    ax.set_xticks(range(3))    ax.set_yticks(range(3)) plt.suptitle('Our Mission: Tell These Apart!', fontsize=16, fontweight='bold', y=1.02)plt.tight_layout()plt.show() print("\n🎯 This is what our neural network will learn to distinguish!")print("   A 3x3 grid of numbers - simple, yet the same principle scales to")print("   recognizing faces, objects, and anything else in images.")

1.3 Matrix Addition: Combining Information

The simplest matrix operation is addition. When you add two matrices, you simply add corresponding elements.

The Rule

For matrices A and B of the same size, their sum C = A + B is calculated as:

c_ij = a_ij + b_ij (each element is the sum of elements at the same position)

Committee Analogy

"Imagine combining two reports from different sources. The combined report contains all the information from both."

Why This Matters for Neural Networks

Matrix addition is used to:

  • Add bias to weighted inputs (we'll see this soon)
  • Combine information from different sources
  • Add noise to data (for robustness training)

Let's see it in action by adding some "noise" to our clean line images:

cell 014
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# =============================================================================# Matrix Addition Example# =============================================================================# Adding two matrices element by element A = np.array([    [1, 2, 3],    [4, 5, 6],    [7, 8, 9]]) B = np.array([    [9, 8, 7],    [6, 5, 4],    [3, 2, 1]]) # Matrix addition - just add corresponding elementsC = A + B print("Matrix A:")print(A)print("\n  +  ")print("\nMatrix B:")print(B)print("\n  =  ")print("\nMatrix C (A + B):")print(C) # Let's verify one element by handprint(f"\nVerification: C[0,0] = A[0,0] + B[0,0] = {A[0,0]} + {B[0,0]} = {C[0,0]} ✓")
cell 015
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# =============================================================================# Practical Application: Adding Noise to Images# =============================================================================# In the real world, data is noisy. Let's see what happens when we add# random noise to our clean line images. # Create random noise (small random values)np.random.seed(42)  # For reproducibilitynoise = np.random.uniform(-0.2, 0.2, size=(3, 3)) print("Random Noise Matrix:")print(np.round(noise, 2)) # Add noise to our vertical linenoisy_vertical = vertical_line + noise # Clip values to stay in [0, 1] range (pixel values can't be negative or > 1)noisy_vertical = np.clip(noisy_vertical, 0, 1) print("\nOriginal Vertical Line + Noise = Noisy Vertical Line:")print(f"\n{vertical_line}")print("\n       +")print(f"\n{np.round(noise, 2)}")print("\n       =")print(f"\n{np.round(noisy_vertical, 2)}")
cell 016
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# =============================================================================# Visualizing Clean vs Noisy Images# =============================================================================# Can you still tell which is vertical? (Yes! And so will our neural network)# Again, this code is just for visualization. fig, axes = plt.subplots(1, 3, figsize=(14, 4)) images = [vertical_line, noise, noisy_vertical]titles = ['Original (Clean)', 'Noise Added', 'Result (Noisy)'] for ax, img, title in zip(axes, images, titles):    im = ax.imshow(img, cmap='gray_r', vmin=0, vmax=1)    ax.set_xticks(np.arange(-0.5, 3, 1), minor=True)    ax.set_yticks(np.arange(-0.5, 3, 1), minor=True)    ax.grid(which='minor', color='black', linestyle='-', linewidth=2)        for i in range(3):        for j in range(3):            value = img[i, j]            text_color = 'white' if value > 0.5 else 'black'            ax.text(j, i, f'{value:.2f}', ha='center', va='center',                    color=text_color, fontsize=12, fontweight='bold')        ax.set_title(title, fontsize=12, fontweight='bold')    ax.set_xticks(range(3))    ax.set_yticks(range(3)) plt.suptitle('Matrix Addition in Action: Adding Noise to an Image', fontsize=14, fontweight='bold')plt.tight_layout()plt.show() print("💡 Key Insight: Even with noise, the vertical pattern is still visible!")print("   A well-trained neural network should handle this noise gracefully.")
cell 018
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# =============================================================================# Scalar Multiplication Example# =============================================================================# Multiplying every element by a single number A = np.array([    [1, 2, 3],    [4, 5, 6],    [7, 8, 9]]) # Multiply by 2 (amplify)amplified = 2 * A # Multiply by 0.5 (dim)dimmed = 0.5 * A print("Original Matrix A:")print(A)print("\n2 x A (Amplified):")print(amplified)print("\n0.5 x A (Dimmed):")print(dimmed) # Visual demonstration: Brightening and dimming our vertical linefig, axes = plt.subplots(1, 3, figsize=(14, 4)) scalars = [0.3, 1.0, 2.0]for ax, k in zip(axes, scalars):    scaled = np.clip(k * vertical_line, 0, 1)    im = ax.imshow(scaled, cmap='gray_r', vmin=0, vmax=1)    ax.set_xticks(np.arange(-0.5, 3, 1), minor=True)    ax.set_yticks(np.arange(-0.5, 3, 1), minor=True)    ax.grid(which='minor', color='black', linestyle='-', linewidth=2)    for i in range(3):        for j in range(3):            value = scaled[i, j]            text_color = 'white' if value > 0.5 else 'black'            ax.text(j, i, f'{value:.1f}', ha='center', va='center',                    color=text_color, fontsize=14, fontweight='bold')    label = "Dimmed" if k < 1 else "Original" if k == 1 else "Amplified"    ax.set_title(f'{k} x Image\n({label})', fontsize=12, fontweight='bold') plt.suptitle('Scalar Multiplication: Adjusting Brightness', fontsize=14, fontweight='bold')plt.tight_layout()plt.show()
cell 020
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# =============================================================================# Feature Scaling Demonstration# =============================================================================# Why normalization matters for neural networks def min_max_normalize(x):    """Scale values to [0, 1] range"""    x_min = np.min(x)    x_max = np.max(x)    return (x - x_min) / (x_max - x_min) def z_score_normalize(x):    """Scale values to have mean=0, std=1"""    return (x - np.mean(x)) / np.std(x) # Example: A "real" image with 0-255 pixel valuesraw_image = np.array([    [0, 255, 0],    [0, 255, 0],    [0, 255, 0]]) # Normalize to 0-1normalized_image = min_max_normalize(raw_image) print("Raw Image (0-255 scale, typical for image files):")print(raw_image)print(f"Range: {raw_image.min()} to {raw_image.max()}") print("\nNormalized Image (0-1 scale, ready for neural network):")print(normalized_image)print(f"Range: {normalized_image.min()} to {normalized_image.max()}") print("\n" + "="*60)print("WHY NORMALIZATION MATTERS:")print("="*60)print("\n1. Without normalization:")print("   - Large values dominate the weighted sum")print("   - Gradients can explode or vanish")print("   - Training becomes unstable")print("\n2. With normalization:")print("   - All inputs contribute proportionally")print("   - Gradients stay in a healthy range")print("   - Training converges faster and more reliably")
cell 022
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# =============================================================================# The Dot Product - Step by Step# =============================================================================# Let's compute a dot product by hand to understand exactly what's happening a = np.array([1, 2, 3])b = np.array([4, 5, 6]) # Step by step calculationprint("Computing the dot product of a and b:")print(f"\na = {a}")print(f"b = {b}") print("\nStep 1: Multiply corresponding elements")element_products = a * bprint(f"a * b (element-wise) = {element_products}")for i in range(len(a)):    print(f"   a[{i}] * b[{i}] = {a[i]} * {b[i]} = {a[i] * b[i]}") print("\nStep 2: Sum all the products")dot_product = np.sum(element_products)print(f"Sum = {element_products[0]} + {element_products[1]} + {element_products[2]} = {dot_product}") print("\n" + "="*50)print(f"DOT PRODUCT: a · b = {dot_product}")print("="*50) # Verify with NumPy's built-in functionprint(f"\nVerification with np.dot(a, b) = {np.dot(a, b)}")
cell 023
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# =============================================================================# THE KEY INSIGHT: Dot Product for Pattern Matching# =============================================================================# This is where the magic happens! Let's see how dot product detects patterns. # Our images as flattened vectors (1D arrays)vertical_flat = vertical_line.flatten()    # [0,1,0,0,1,0,0,1,0]horizontal_flat = horizontal_line.flatten() # [0,0,0,1,1,1,0,0,0] print("Our images as vectors:")print(f"Vertical line:   {vertical_flat}")print(f"Horizontal line: {horizontal_flat}") # Now, let's create a "vertical detector" - weights that look for vertical lines# High values in the middle column (positions 1, 4, 7)vertical_detector = np.array([0, 1, 0, 0, 1, 0, 0, 1, 0]) print(f"\nVertical Detector (weights): {vertical_detector}") # Compute dot productsscore_vertical = np.dot(vertical_flat, vertical_detector)score_horizontal = np.dot(horizontal_flat, vertical_detector) print("\n" + "="*60)print("DOT PRODUCT SCORES (how well each image matches the detector):")print("="*60)print(f"\nVertical image · Vertical detector = {score_vertical}")print(f"Horizontal image · Vertical detector = {score_horizontal}") print("\n💡 KEY INSIGHT:")print(f"   The vertical image scores {score_vertical} (HIGH match!)")print(f"   The horizontal image scores {score_horizontal} (LOW match!)")print("\n   This is EXACTLY how a neuron 'sees' patterns!")print("   The weights define what it's looking for, and the dot product")print("   measures how well the input matches.")
cell 024
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# =============================================================================# Visualizing the Dot Product for Pattern Detection# =============================================================================# Let's see this visually - how the detector "overlays" on the image fig, axes = plt.subplots(2, 4, figsize=(16, 8)) # Top row: Vertical image analysisv_detector_2d = vertical_detector.reshape(3, 3)v_product = vertical_line * v_detector_2d images_top = [vertical_line, v_detector_2d, v_product]titles_top = ['Input: Vertical Line', 'Detector Weights', 'Element-wise Product'] for i, (ax, img, title) in enumerate(zip(axes[0, :3], images_top, titles_top)):    im = ax.imshow(img, cmap='RdYlGn' if i == 2 else 'gray_r', vmin=0, vmax=1)    ax.set_xticks(np.arange(-0.5, 3, 1), minor=True)    ax.set_yticks(np.arange(-0.5, 3, 1), minor=True)    ax.grid(which='minor', color='black', linestyle='-', linewidth=2)    for r in range(3):        for c in range(3):            val = img[r, c]            color = 'white' if val > 0.5 else 'black'            ax.text(c, r, f'{int(val)}', ha='center', va='center', color=color, fontsize=16, fontweight='bold')    ax.set_title(title, fontsize=11) axes[0, 3].text(0.5, 0.5, f'Sum = {score_vertical}', ha='center', va='center', fontsize=24, fontweight='bold')axes[0, 3].text(0.5, 0.3, 'HIGH MATCH!', ha='center', va='center', fontsize=14, color='green', fontweight='bold')axes[0, 3].set_xlim(0, 1); axes[0, 3].set_ylim(0, 1); axes[0, 3].axis('off')axes[0, 3].set_title('Dot Product Result', fontsize=11) # Bottom row: Horizontal image analysish_product = horizontal_line * v_detector_2dimages_bot = [horizontal_line, v_detector_2d, h_product]titles_bot = ['Input: Horizontal Line', 'Detector Weights', 'Element-wise Product'] for i, (ax, img, title) in enumerate(zip(axes[1, :3], images_bot, titles_bot)):    im = ax.imshow(img, cmap='RdYlGn' if i == 2 else 'gray_r', vmin=0, vmax=1)    ax.set_xticks(np.arange(-0.5, 3, 1), minor=True)    ax.set_yticks(np.arange(-0.5, 3, 1), minor=True)    ax.grid(which='minor', color='black', linestyle='-', linewidth=2)    for r in range(3):        for c in range(3):            val = img[r, c]            color = 'white' if val > 0.5 else 'black'            ax.text(c, r, f'{int(val)}', ha='center', va='center', color=color, fontsize=16, fontweight='bold')    ax.set_title(title, fontsize=11) axes[1, 3].text(0.5, 0.5, f'Sum = {score_horizontal}', ha='center', va='center', fontsize=24, fontweight='bold')axes[1, 3].text(0.5, 0.3, 'LOW MATCH', ha='center', va='center', fontsize=14, color='red', fontweight='bold')axes[1, 3].set_xlim(0, 1); axes[1, 3].set_ylim(0, 1); axes[1, 3].axis('off')axes[1, 3].set_title('Dot Product Result', fontsize=11) plt.suptitle('How the Dot Product Detects Patterns\n(Same detector applied to both images)', fontsize=14, fontweight='bold')plt.tight_layout()plt.show() print("🔍 Notice: The vertical detector has high values (1s) in the middle column.")print("   When we multiply element-wise with the vertical image, those 1s align perfectly!")print("   But with the horizontal image, the 1s don't overlap, giving a score of 0.")

1.7 Matrix Multiplication: The Full Committee Review

We've seen how one dot product lets one "detector" score one image. But what if we want:

  • Multiple detectors looking at the same image?
  • Multiple images being processed at once?

This is where matrix multiplication comes in - it's just many dot products organized efficiently!

The Rule

For matrix A (m x n) and matrix B (n x p), their product C = A x B is a matrix of size (m x p), where:

c_ij = (row i of A) · (column j of B)

Each element of C is a dot product!

Committee Analogy: Diversity of Opinion

"If everyone on the committee looks for the exact same thing, they're redundant. We need DIVERSITY - one member looking for the top of the line, one for the middle, one for the bottom. Matrix multiplication lets us run multiple specialists at once!"

Why This Matters for Neural Networks

In a neural network layer with multiple neurons:

  • Each neuron has its own set of weights (one row in the weight matrix)
  • All neurons process the same input simultaneously
  • Matrix multiplication computes ALL outputs in one operation

This is why neural networks can be so fast - we do everything in parallel!

cell 026
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# =============================================================================# Matrix Multiplication: Step by Step# =============================================================================# Let's understand matrix multiplication by computing it manually A = np.array([    [1, 2],    [3, 4],    [5, 6]])  # 3x2 matrix B = np.array([    [7, 8, 9],    [10, 11, 12]])  # 2x3 matrix print("Matrix A (3x2):")print(A)print("\nMatrix B (2x3):")print(B) # Matrix multiplication: C = A @ BC = A @ B  # (3x2) @ (2x3) = (3x3) print("\nMatrix C = A x B (3x3):")print(C) # Let's verify one element by handprint("\n" + "="*60)print("Verification: How C[0,0] is calculated")print("="*60)print("Remember we say c[0.0] thats refering to the location of the element \nin the matrix C which is the dot product of row 0 of A and column 0 of B")print(f"\nC[0,0] = (Row 0 of A) · (Column 0 of B)")print(f"       = {A[0,:]} · {B[:,0]}")print(f"       = ({A[0,0]}*{B[0,0]}) + ({A[0,1]}*{B[1,0]})")print(f"       = {A[0,0]*B[0,0]} + {A[0,1]*B[1,0]}")print(f"       = {C[0,0]}")
cell 027
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# =============================================================================# Practical Application: Multiple Detectors at Once# =============================================================================# This is EXACTLY how a neural network layer works! # Our input image (flattened)image = vertical_line.flatten()  # 9 elements # Create multiple detectors (each row is one "neuron's" weights)weight_matrix = np.array([    [0, 1, 0, 0, 1, 0, 0, 1, 0],  # Vertical detector    [0, 0, 0, 1, 1, 1, 0, 0, 0],  # Horizontal detector    [1, 0, 0, 0, 1, 0, 0, 0, 1],  # Diagonal detector]) print("Input image (flattened):", image)print(f"Shape: {image.shape}") print("\nWeight matrix (3 detectors, each with 9 weights):")print(weight_matrix)print(f"Shape: {weight_matrix.shape}") # Matrix multiplication: all detectors at once!outputs = weight_matrix @ image  # (3x9) @ (9,) = (3,) print("\n" + "="*60)print("OUTPUT: All detector scores computed at once!")print("="*60)print(f"\nVertical detector score:   {outputs[0]}")print(f"Horizontal detector score: {outputs[1]}")print(f"Diagonal detector score:   {outputs[2]}") print("\n💡 The vertical image triggers the vertical detector strongly (score = 3)")print("   but doesn't match horizontal or diagonal patterns (scores = 0 or 1)")print("\n   This is one forward pass through a layer of 3 neurons!")
cell 028
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# =============================================================================# Visualizing Multiple Detectors# =============================================================================# See what each "committee member" is looking for fig, axes = plt.subplots(1, 4, figsize=(16, 4)) # Show the input imageax = axes[0]im = ax.imshow(vertical_line, cmap='gray_r', vmin=0, vmax=1)ax.set_title('Input Image\n(Vertical Line)', fontsize=12, fontweight='bold')ax.set_xticks(np.arange(-0.5, 3, 1), minor=True)ax.set_yticks(np.arange(-0.5, 3, 1), minor=True)ax.grid(which='minor', color='black', linestyle='-', linewidth=2) # Show each detector's weightsdetector_names = ['Vertical Detector\n(Neuron 1)', 'Horizontal Detector\n(Neuron 2)', 'Diagonal Detector\n(Neuron 3)']scores = outputs for i, (ax, name, score) in enumerate(zip(axes[1:], detector_names, scores)):    weights_2d = weight_matrix[i].reshape(3, 3)    im = ax.imshow(weights_2d, cmap='Blues', vmin=0, vmax=1)    ax.set_title(f'{name}\nScore: {score}', fontsize=11, fontweight='bold')    ax.set_xticks(np.arange(-0.5, 3, 1), minor=True)    ax.set_yticks(np.arange(-0.5, 3, 1), minor=True)    ax.grid(which='minor', color='black', linestyle='-', linewidth=2)        for r in range(3):        for c in range(3):            val = weights_2d[r, c]            color = 'white' if val > 0.5 else 'black'            ax.text(c, r, f'{int(val)}', ha='center', va='center', color=color, fontsize=14, fontweight='bold') plt.suptitle('Matrix Multiplication = Multiple Dot Products = Multiple Neurons at Once!',              fontsize=14, fontweight='bold')plt.tight_layout()plt.show() print("  *Each detector (neuron) looks for a different pattern.")print("   When we have a layer with multiple neurons, matrix multiplication")print("   lets us compute ALL their outputs in a single operation!")

1.8 Hands-On Lab: Interactive Matrix Explorer

Now it's YOUR turn! Use the interactive tool below to experiment with matrices and see how they work.

What to Try:

  1. Create your own patterns - Draw different shapes in the input
  2. Design detectors - What weights would detect a specific pattern?
  3. Observe the scores - See how the dot product changes with different inputs

This hands-on exploration will cement your understanding of how matrices enable pattern detection!

Note: If you don't see interactive widgets below, you may need to install ipywidgets: pip install ipywidgets

cell 030full lab recommended
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# =============================================================================# Interactive Matrix Lab (requires ipywidgets)# =============================================================================# If widgets aren't available, we'll show a static version# Don't worry about code, just run the cell and use the sliders to explore how the dot product works.if WIDGETS_AVAILABLE:    def create_matrix_lab():        output = widgets.Output()                input_sliders = [widgets.FloatSlider(value=vertical_line.flatten()[i], min=0.0, max=1.0, step=0.1,            description=f'px{i}:', style={'description_width': '35px'}, layout=widgets.Layout(width='150px'))            for i in range(9)]                detector_sliders = [widgets.FloatSlider(value=vertical_detector[i], min=-1.0, max=1.0, step=0.1,            description=f'w{i}:', style={'description_width': '35px'}, layout=widgets.Layout(width='150px'))            for i in range(9)]                def update_display(change):            with output:                clear_output(wait=True)                input_vals = np.array([s.value for s in input_sliders])                detector_vals = np.array([s.value for s in detector_sliders])                dot_product = np.dot(input_vals, detector_vals)                                fig, axes = plt.subplots(1, 3, figsize=(12, 3.5))                for ax, data, title in zip(axes[:2], [input_vals.reshape(3,3), detector_vals.reshape(3,3)],                                            ['Input Image', 'Detector Weights']):                    ax.imshow(data, cmap='gray_r' if 'Input' in title else 'RdBu', vmin=-1 if 'Detector' in title else 0, vmax=1)                    ax.set_xticks(np.arange(-0.5, 3, 1), minor=True)                    ax.set_yticks(np.arange(-0.5, 3, 1), minor=True)                    ax.grid(which='minor', color='black', linestyle='-', linewidth=2)                    for r in range(3):                        for c in range(3):                            val = data[r, c]                            ax.text(c, r, f'{val:.1f}', ha='center', va='center',                                    color='white' if abs(val) > 0.5 else 'black', fontsize=11, fontweight='bold')                    ax.set_title(title, fontweight='bold')                                color = 'green' if dot_product > 1.5 else 'orange' if dot_product > 0 else 'red'                axes[2].text(0.5, 0.5, f'{dot_product:.2f}', ha='center', va='center', fontsize=32, fontweight='bold', color=color)                axes[2].text(0.5, 0.25, 'DOT PRODUCT', ha='center', va='center', fontsize=12)                axes[2].set_xlim(0, 1); axes[2].set_ylim(0, 1); axes[2].axis('off')                axes[2].set_title('Result', fontweight='bold')                plt.tight_layout()                plt.show()                for slider in input_sliders + detector_sliders:            slider.observe(update_display, names='value')                input_grid = widgets.GridBox(input_sliders, layout=widgets.Layout(grid_template_columns='repeat(3, 160px)'))        detector_grid = widgets.GridBox(detector_sliders, layout=widgets.Layout(grid_template_columns='repeat(3, 160px)'))                update_display(None)        return widgets.VBox([output, widgets.HBox([            widgets.VBox([widgets.HTML('<b>Input Pixels:</b>'), input_grid]),            widgets.VBox([widgets.HTML('<b>Detector Weights:</b>'), detector_grid])        ])])        print("🔬 INTERACTIVE MATRIX LAB - Adjust sliders to experiment!")    display(create_matrix_lab())else:    print("⚠️ Interactive widgets not available.")    print("   Install with: pip install ipywidgets")    print("   Then restart the kernel and run again.")

Part 1 Summary: What We've Learned

Congratulations! You've just learned the mathematical foundation of neural networks. Let's recap:

Key Concepts Mastered

ConceptWhat It IsWhy It Matters
MatrixA grid of numbersHow we represent images and data
Matrix AdditionAdding corresponding elementsCombining information, adding noise
Scalar MultiplicationMultiplying all elements by one numberScaling, adjusting intensity
Feature ScalingNormalizing to common range (0-1)Essential for stable training
Dot ProductMultiply + SumTHE core operation - measures pattern matching
Matrix MultiplicationMany dot products at onceEfficient multi-neuron computation

The Committee Connection

"Our committee now speaks a common language (matrices), can read evidence (images as numbers), and has learned to measure how well evidence matches what they're looking for (dot product). They're ready to meet their first member!"

What's Next?

In Part 2, we'll:

  • Meet our first "committee member" - a single artificial neuron
  • See how it uses weights (its priorities) and bias (its threshold)
  • Watch it make its first (random, wrong!) predictions

The neuron is just the dot product + a few extra pieces. You already understand the core!

cell 032
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# =============================================================================# PART 1 KNOWLEDGE CHECK# =============================================================================# Test your understanding before moving on! print("📝 KNOWLEDGE CHECK - Part 1")print("="*50)print("\nAnswer these questions to test your understanding:")print("\n1. What is a dot product, in plain English?")print("   (Hint: It measures something between two vectors)")print("\n2. Why do we need feature scaling?")print("   (Hint: Think about different measurement units)")print("\n3. What does matrix multiplication let us do efficiently?")print("   (Hint: Think about multiple neurons)")print("\n4. In our line detection problem, why does the vertical")print("   detector give a high score for vertical images?")print("   (Hint: Think about where the 1s align)") print("\n" + "="*50)print("Run the next cell for answers...")print("="*50)
cell 033
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# =============================================================================# ANSWERS - Run this cell after attempting the questions!# ============================================================================= print("✅ ANSWERS - Part 1 Knowledge Check")print("="*50) print("""1. WHAT IS A DOT PRODUCT?   The dot product measures how much two vectors "agree" or "align".   It multiplies corresponding elements and sums them up.   High value = vectors point in similar directions (match!)   Zero = vectors are unrelated   Negative = vectors point in opposite directions 2. WHY FEATURE SCALING?   Different features may be on different scales (e.g., age 0-100,    salary 0-1,000,000). Without scaling, large-scale features    dominate the learning. Scaling puts everyone on equal footing. 3. MATRIX MULTIPLICATION FOR EFFICIENCY   It lets us compute outputs for MULTIPLE neurons simultaneously.   Instead of doing one dot product at a time, we do them all at once.   This is why neural networks can run fast on GPUs. 4. WHY VERTICAL DETECTOR SCORES HIGH ON VERTICAL IMAGES   The vertical detector has 1s in positions [1, 4, 7] - the middle column.   A vertical image ALSO has 1s in positions [1, 4, 7].   When we multiply: 1*1 + 1*1 + 1*1 = 3 (high match!)   With a horizontal image, the 1s don't overlap: 0*1 + 0*1 + 0*1 = 0""") print("="*50)print("🎉 Great job completing Part 1!")print("   You now understand the mathematical foundation of neural networks.")print("   Let's meet our first neuron in Part 2!")print("="*50)

Illustrated step

Matrix

concept

Organized evidence report

Every pixel becomes a number the committee can inspect.

Dot product

concept

Agreement score

Inputs and weights multiply to measure how strongly evidence matches an opinion.

Feature scaling

concept

Common language

Values are normalized so every signal speaks at the same volume.

AI tutor

Tutor chat is staged for the next slice. For now, use the concept cards and run cells to test each idea directly.

Pinned output

Plots and code output render under each cell. Pinning outputs to this rail will land once the core runner is evaluated.