Deep LearningNeural Network Foundations › Day 197

Hands-on lab — Day 197: The Perceptron

Commands

Setup

pip install -r requirements/requirements.txt

Run

python3 examples/the_perceptron_lib.py

Test

./tests/run_tests.sh

File tree

examples/test_the_perceptron_lib.py
examples/the_perceptron_lib.py
expected-output/examples-run.txt
expected-output/FIELDS.md
expected-output/measured-values.txt
expected-output/starter-run.txt
expected-output/test-run.txt
metadata.yml
README.md
requirements/requirements.txt
security.md
starter/test_the_perceptron_lib.py
starter/the_perceptron_lib.py
tests/run_tests.sh
tests/test_the_perceptron_lib.py
troubleshooting.md

Lab README

Lab: Day 197 -- The Perceptron

Lesson

Day number: 197 of 365. Course: Course05-SS01 (Deep Learning - Neural Networks). Topic: The Artificial Perceptron and Linear Separability.

Purpose

Build Frank Rosenblatt's classic Artificial Perceptron and a two-layer Multi-Layer Perceptron (MLP) from scratch in pure NumPy. You will implement the Perceptron Learning Rule, train on linearly separable boolean logic gates (AND, OR), analyze the geometric failure on XOR parity, and solve XOR using a two-layer network.

Learning objectives

  • Implement the Perceptron dot-product and Heaviside step activation math.
  • Code the Perceptron Learning Rule for weight and bias adaptation.
  • Verify finite-step convergence on linearly separable datasets.
  • Construct a two-layer MLP that resolves the non-linear XOR parity problem.

Prerequisites

  • Linear algebra (dot products, vector addition).
  • Python 3.11+ with NumPy.

Supported operating systems

  • macOS (Apple Silicon / Intel)
  • Linux (Ubuntu, Debian, Fedora, Arch)
  • Windows 11 / WSL2

Hardware requirements

  • 1+ CPU cores.
  • 512 MB RAM.
  • 50 MB disk space.

Required software

  • Python 3.11 or newer.
  • pip package manager.
  • virtualenv or venv module.

Free and open-source options

All tools used in this lab (Python, NumPy, pytest) are free and open-source under BSD/MIT licenses.

Installation

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements/requirements.txt

File structure

  • starter/the_perceptron_lib.py: Student scaffold file.
  • examples/the_perceptron_lib.py: Complete reference implementation.
  • tests/test_the_perceptron_lib.py: Pytest automated validation suite.
  • expected-output/: Verified output logs and baseline values.

How to run

Execute the reference demonstration script:

python3 examples/the_perceptron_lib.py

What the commands do

  • Trains Perceptron on AND gate truth table.
  • Evaluates weight updates across epochs.
  • Verifies classification convergence.

Expected output

Perceptron Demo: AND Gate Predictions = [0, 0, 0, 1], Epochs = 6

Validation steps

  1. Verify that the Perceptron achieves 100% accuracy on AND and OR gates.
  2. Confirm that solve_xor_with_two_layers achieves 100% accuracy across all 4 XOR states.
  3. Ensure all unit test assertions pass.

Tests

Run the test runner script:

./tests/run_tests.sh

Cleanup

find . -type d -name "__pycache__" -exec rm -rf {} +
find . -type d -name ".pytest_cache" -exec rm -rf {} +

Troubleshooting

  • Infinite Loop on XOR: Ensure max_epochs is finite because XOR is linearly non-separable.

Security notes

All neural computations execute strictly on local CPU memory.

Extension exercises

  1. Implement Adaline (Adaptive Linear Neuron) using LMS gradient updates.
  2. Solve 3-Input Parity (x1 ^ x2 ^ x3) using a 2-layer network.
  • Lesson title: The Perceptron
  • Day number: 197 of 365
  • Lesson article: https://ai-roadmap-365.github.io/day-197-the-perceptron
  • Lab files: everything you need is in this directory — follow “How to run” below.
  • Browse the course locally: from the repository root, this lab also appears in the course website at /labs/day-197-the-perceptron when the site is running.

Expected output

FIELDS.md

# Expected Output Fields: Day 197

- `AND Gate Predictions`: Output array on boolean AND input combinations.
- `Convergence Epochs`: Epoch count at which zero training errors occurred.
- `XOR Accuracy`: Accuracy score of 2-layer MLP on XOR truth table.

examples-run.txt

Perceptron Demo: AND Gate Predictions = [0, 0, 0, 1], Epochs = 6

measured-values.txt

AND Gate Predictions: [0, 0, 0, 1]
Convergence Epochs: 6
XOR Accuracy: 1.0000

starter-run.txt

Starter scaffold executed. Ready for student implementation.

test-run.txt

============================= test session starts ==============================
collected 2 items

tests/test_the_perceptron_lib.py::test_perceptron_learns_and_and_or_gates PASSED [ 50%]
tests/test_the_perceptron_lib.py::test_two_layer_mlp_solves_xor PASSED           [100%]

============================== 2 passed in 0.08s ===============================

Source files

examples/test_the_perceptron_lib.py (781 bytes)
import pytest
import numpy as np
from examples.the_perceptron_lib import Perceptron, solve_xor_with_two_layers

def test_perceptron_learns_and_and_or_gates():
    X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
    y_and = np.array([0, 0, 0, 1])
    y_or = np.array([0, 1, 1, 1])

    p_and = Perceptron(learning_rate=0.1, max_epochs=50)
    p_and.fit(X, y_and)
    assert np.array_equal(p_and.predict(X), y_and)

    p_or = Perceptron(learning_rate=0.1, max_epochs=50)
    p_or.fit(X, y_or)
    assert np.array_equal(p_or.predict(X), y_or)

def test_two_layer_mlp_solves_xor():
    truth_table = [
        (0, 0, 0),
        (1, 0, 1),
        (0, 1, 1),
        (1, 1, 0)
    ]
    for x1, x2, expected in truth_table:
        assert solve_xor_with_two_layers(x1, x2) == expected
examples/the_perceptron_lib.py (1958 bytes)
import numpy as np

class Perceptron:
    def __init__(self, learning_rate: float = 0.1, max_epochs: int = 100):
        self.lr = learning_rate
        self.max_epochs = max_epochs
        self.weights = None
        self.bias = 0.0
        self.errors_per_epoch = []

    def predict(self, X: np.ndarray) -> np.ndarray:
        z = np.dot(X, self.weights) + self.bias
        return np.where(z >= 0.0, 1, 0)

    def fit(self, X: np.ndarray, y: np.ndarray) -> "Perceptron":
        n_samples, n_features = X.shape
        self.weights = np.zeros(n_features, dtype=float)
        self.bias = 0.0
        self.errors_per_epoch = []

        for epoch in range(self.max_epochs):
            total_errors = 0
            for i in range(n_samples):
                xi = X[i]
                target = y[i]
                y_hat = 1 if (np.dot(xi, self.weights) + self.bias) >= 0.0 else 0
                error = target - y_hat

                if error != 0:
                    self.weights += self.lr * error * xi
                    self.bias += self.lr * error
                    total_errors += 1

            self.errors_per_epoch.append(total_errors)
            if total_errors == 0:
                break

        return self

def solve_xor_with_two_layers(x1: int, x2: int) -> int:
    # Hidden Layer: NAND and OR
    h_nand = 1 if (-2.0 * x1 + -2.0 * x2 + 3.0) >= 0.0 else 0
    h_or = 1 if (2.0 * x1 + 2.0 * x2 - 1.0) >= 0.0 else 0
    # Output Layer: AND of hidden gates
    y_xor = 1 if (2.0 * h_nand + 2.0 * h_or - 3.0) >= 0.0 else 0
    return y_xor

def run_perceptron_demo():
    X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
    y_and = np.array([0, 0, 0, 1])

    p = Perceptron(learning_rate=0.1, max_epochs=20)
    p.fit(X, y_and)
    preds = p.predict(X)

    print(f"Perceptron Demo: AND Gate Predictions = {preds.tolist()}, Epochs = {len(p.errors_per_epoch)}")
    return p, preds

if __name__ == "__main__":
    run_perceptron_demo()
metadata.yml (427 bytes)
lesson_id: D197
day: 197
kind: lab
languages:
  - python
setup_commands:
  - 'pip install -r requirements/requirements.txt'
run_commands:
  - 'python3 examples/the_perceptron_lib.py'
test_commands:
  - './tests/run_tests.sh'
cleanup_commands:
  - 'find . -type d -name "__pycache__" -exec rm -rf {} +'
requires_network: false
requires_api_key: false
estimated_minutes: 45
last_executed: '2026-08-29'
executed_on: 'macos-arm64'
requirements/requirements.txt (28 bytes)
numpy>=1.26.0
pytest>=8.0.0
starter/test_the_perceptron_lib.py (781 bytes)
import pytest
import numpy as np
from examples.the_perceptron_lib import Perceptron, solve_xor_with_two_layers

def test_perceptron_learns_and_and_or_gates():
    X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
    y_and = np.array([0, 0, 0, 1])
    y_or = np.array([0, 1, 1, 1])

    p_and = Perceptron(learning_rate=0.1, max_epochs=50)
    p_and.fit(X, y_and)
    assert np.array_equal(p_and.predict(X), y_and)

    p_or = Perceptron(learning_rate=0.1, max_epochs=50)
    p_or.fit(X, y_or)
    assert np.array_equal(p_or.predict(X), y_or)

def test_two_layer_mlp_solves_xor():
    truth_table = [
        (0, 0, 0),
        (1, 0, 1),
        (0, 1, 1),
        (1, 1, 0)
    ]
    for x1, x2, expected in truth_table:
        assert solve_xor_with_two_layers(x1, x2) == expected
starter/the_perceptron_lib.py (622 bytes)
import numpy as np

class Perceptron:
    def __init__(self, learning_rate: float = 0.1, max_epochs: int = 100):
        self.lr = learning_rate
        self.max_epochs = max_epochs
        self.weights = None
        self.bias = 0.0

    def predict(self, X: np.ndarray) -> np.ndarray:
        # TODO: Compute z = X.w + b and apply step activation
        pass

    def fit(self, X: np.ndarray, y: np.ndarray) -> "Perceptron":
        # TODO: Implement Rosenblatt Perceptron Learning Rule
        pass

def solve_xor_with_two_layers(x1: int, x2: int) -> int:
    # TODO: Implement 2-layer manual MLP solving XOR
    pass
tests/run_tests.sh (227 bytes)
#!/usr/bin/env bash
set -euo pipefail
echo "========================================"
echo "Running Day 197 Lab Test Suite"
echo "========================================"
pytest tests/ -v
echo "All tests passed successfully."
tests/test_the_perceptron_lib.py (781 bytes)
import pytest
import numpy as np
from examples.the_perceptron_lib import Perceptron, solve_xor_with_two_layers

def test_perceptron_learns_and_and_or_gates():
    X = np.array([[0, 0], [1, 0], [0, 1], [1, 1]])
    y_and = np.array([0, 0, 0, 1])
    y_or = np.array([0, 1, 1, 1])

    p_and = Perceptron(learning_rate=0.1, max_epochs=50)
    p_and.fit(X, y_and)
    assert np.array_equal(p_and.predict(X), y_and)

    p_or = Perceptron(learning_rate=0.1, max_epochs=50)
    p_or.fit(X, y_or)
    assert np.array_equal(p_or.predict(X), y_or)

def test_two_layer_mlp_solves_xor():
    truth_table = [
        (0, 0, 0),
        (1, 0, 1),
        (0, 1, 1),
        (1, 1, 0)
    ]
    for x1, x2, expected in truth_table:
        assert solve_xor_with_two_layers(x1, x2) == expected

Troubleshooting

Troubleshooting: Day 197 - The Perceptron

Common Issues

  1. Non-Convergence on Non-Separable Data:
    • Cause: Single-layer perceptrons cannot converge on non-linearly separable datasets.
    • Fix: Use multi-layer networks (MLPs) with hidden layer representations.

Security notes

Security & Privacy: Day 197 - The Perceptron

Security Guidance

  • All neural computations execute locally without external network transmission.