Back to Blog
Deep Learning

Mastering Neural Networks from Scratch: Dive into Andrej Karpathy's nn-zero with NumPy Only

Claude Directory December 29, 2025
0 views

Discover how to build a fully functional neural network engine using just 100 lines of Python and NumPy, as showcased in Andrej Karpathy's nn-zero project. Perfect for demystifying backpropagation and ML fundamentals.

Why Build Neural Networks from Scratch?

Have you ever wondered what happens under the hood of deep learning frameworks like PyTorch or TensorFlow? Modern libraries abstract away the gritty details, making it easy to train massive models but hard to grasp the core mechanics. Enter Andrej Karpathy's nn-zero project—a compact, ~100-line NumPy implementation of a neural network with full backpropagation support. This isn't just a toy; it's a pedagogical powerhouse that lets you explore forward passes, backward propagation, and optimization in pure Python.

In this exploration, we'll break down the key questions: What makes nn-zero special? How does it implement the essentials of neural nets? And how can you extend it for real-world tasks? By the end, you'll have actionable steps to implement, tweak, and understand neural networks at a foundational level.

What is nn-zero and Why Does It Matter?

nn-zero strips machine learning to its essence: no external dependencies beyond NumPy, no GPUs, no fancy optimizers—just raw math and code. Karpathy released it alongside a detailed YouTube video walking through the implementation live. The goal? To teach backpropagation intuitively, helping beginners and experts alike debug their mental models.

Key benefits:

  • Transparency: Every operation is visible, from matrix multiplications to gradient computations.
  • Portability: Runs anywhere Python and NumPy do—no CUDA setups needed.
  • Learning accelerator: Ideal for interviews, courses, or refreshing fundamentals before diving into production ML.

Real-world application: Use it to prototype ideas quickly. For instance, educators can fork nn-zero for classroom demos, showing how tiny changes affect training dynamics.

Core Components: Breaking Down the Neural Net Engine

Let's dissect the architecture through a question-answer lens. nn-zero builds a Multi-Layer Perceptron (MLP) with these pillars:

Question: How does the forward pass work?

Answer: Data flows through layers via linear transformations and non-linear activations (like tanh). Here's a simplified view:

# Pseudo-code from nn-zero style
import numpy as np

class Neuron:
    def __init__(self, nin):  # Number of inputs
        self.w = np.random.randn(nin) / np.sqrt(nin)  # Weights
        self.b = np.zeros(1)  # Bias

    def __call__(self, x):
        # Linear: out = x * w + b
        self.x = x
        self.out = np.dot(x, self.w) + self.b
        return self.out

# Activation
class Tanh:
    def __call__(self, x):
        self.out = np.tanh(x)
        return self.out

Exploration: Weights are Xavier-initialized (divide by sqrt(nin)) to prevent vanishing gradients. In practice, feed in a batch: out = layer(inputs) chains neurons and activations.

Question: What's the magic of backpropagation?

Answer: Backprop computes gradients via the chain rule, flowing errors backward. nn-zero implements it manually—no autograd black magic.

For a single neuron:

    def parameters(self):
        return [self.w, self.b]

    def calc_grad(self, dout):  # Gradient of loss w.r.t. output
        # dL/dw = dL/dout * dout/dw = dout * x
        self.dw = dout * self.x.T
        self.db = dout * 1
        # Propagate to input: dx = dout * w
        self.dinputs = dout * self.w

For Tanh:

    def calc_grad(self, dout):
        # dtanh/dz = 1 - tanh(z)^2
        self.dinputs = dout * (1 - self.out ** 2)

Exploration: This recursive gradient flow enables end-to-end differentiability. Test it: Train on synthetic data like fitting y = sin(x) to see gradients light up during optimization.

Building and Training Your First Model

Step-by-Step: Replicating nn-zero

  1. Clone and setup: Grab the repo with git clone https://github.com/karpathy/nn-zero. Requires only pip install numpy matplotlib.

  2. Define the MLP:

    class MLP:
        def __init__(self, nin, nouts):
            layers = []
            sz = [nin] + nouts  # e.g., [784, 10, 1] for MNIST-like
            for i in range(len(nouts)):
                layers.append(Neuron(sz[i]))
                layers.append(Tanh())
            self.layers = layers
    
        def __call__(self, x):
            for layer in self.layers:
                x = layer(x)
            return x
    
        def parameters(self):
            return [p for layer in self.layers for p in layer.parameters()]
    
        def zero_grad(self):
            for layer in self.layers:
                layer.dw, layer.db = 0, 0
    
  3. Training loop:

    model = MLP(1, [50, 50, 1])  # Example: scalar regression
    optimizer = lambda params, lr: [p - lr * dp for p, dp in zip(params, grads)]
    
    for i in range(1000):
        # Forward
        out = model(xs)  # xs: inputs
        # Loss: MSE
        loss = np.mean((out - ys)**2)
        # Backward: call calc_grad on each layer in reverse
        dout = (out - ys) * 2 / len(xs)  # dMSE/dout
        for layer in reversed(model.layers):
            dout = layer.calc_grad(dout)
        # Update
        grads = [p for layer in model.layers for p in layer.grads()]
        for p, g in zip(model.parameters(), grads):
            p -= 0.01 * g  # SGD
    

Exploration: Karpathy's video demos training on a spiral dataset. Visualize with matplotlib: Plot decision boundaries to see the net learn non-linear separation.

Advanced Tweaks and Real-World Extensions

Once comfortable, ask: How to scale it?

  • Batch processing: Vectorize inputs (n_samples, n_features).
  • Better optimizers: Add Adam by tracking momentum/variance.
  • Datasets: Load MNIST via sklearn.datasets:
    from sklearn.datasets import load_digits
    digits = load_digits()
    xs = digits.data / 255.0
    ys = digits.target.reshape(-1, 1)
    # Hot-one encode ys, train classifier
    

Real-world app: Use in embedded systems or when frameworks are unavailable (e.g., microcontrollers with MicroPython). Or, debug PyTorch issues by comparing gradients.

Beyond nn-zero: Recent ML Context

nn-zero arrives amid exciting developments. OpenAI's o1 models excel at reasoning by 'thinking' step-by-step, reducing math errors in frontier LLMs. Analysis shows newer models like GPT-4o closing the gap on GSM8K benchmarks. Pair nn-zero with these: Understand token-level math before scaling to LLMs.

Other insights from The Batch:

  • Model scaling laws: Compute efficiency drives progress.
  • Safety alignments: Post-training matters as much as pre-training.

Actionable Next Steps

  1. Watch Karpathy's video and code along.
  2. Fork nn-zero, add ReLU or dropout.
  3. Benchmark vs. sklearn MLPRegressor on regression tasks.
  4. Contribute: Open issues for batch norms or convolutions.

This hands-on approach builds intuition no tutorial can match. Dive in, tweak, and own neural nets!


<div style="text-align: center; margin-top: 2rem;"> <a href="https://www.deeplearning.ai/the-batch/nothing-but-neural-net/" target="_blank" rel="noopener noreferrer" class="view-full-resource-btn" style="display: inline-block; background-color: #f97316; color: white; padding: 12px 24px; border-radius: 8px; text-decoration: none; font-weight: 600; transition: background-color 0.2s;">View Full Resource</a> </div>
GitHub Project

Comments

More Blog

View all
Data & Analysis

Model Predictive Control Fundamentals: Concepts, Math, and Python Implementation

Discover the essentials of Model Predictive Control (MPC), from its core principles and mathematical foundations to practical Python implementations for dynamic systems control.

C
Claude Directory
2
Data & Analysis

Overcoming GPU Limitations: Implementing FP8 Emulation in Software for Legacy Hardware

Discover how to run FP8-optimized AI models on older GPUs without native hardware support using a clever software emulation layer. Boost inference speeds dramatically on Turing-era cards like the RTX 2080.

C
Claude Directory
3
Data & Analysis

Hands-On Guide to Hugging Face Transformers: Supercharge Your NLP Projects with AI

Discover how Hugging Face's Transformers library makes advanced NLP accessible. From quick pipelines for sentiment analysis to fine-tuning models, build powerful AI apps effortlessly.

C
Claude Directory
1
Data & Analysis

Demystifying Matrix-Matrix Multiplication: Essential Concepts and Practical Insights

Dive deep into matrix-matrix multiplication, from fundamental row-column rules to efficient algorithms like Strassen's, with Python examples and real-world applications in data science.

C
Claude Directory
2
Data & Analysis

Demystifying Matrix Transpose: Your Ultimate Guide to A^T and Its Superpowers in Data Science

Dive into the exciting world of matrix transpose! Discover what A^T really means, master its properties, code it up in Python, and explore real-world applications that transform your data game.

C
Claude Directory
Data & Analysis

Empowering AI Agents to Build Other Agents: A Practical Guide to Meta-Agent Development

Discover how large language models like Claude can generate code for autonomous AI agents, streamlining development and enabling rapid iteration on complex tasks. This approach turns manual coding into an automated, scalable process.

C
Claude Directory