The Perceptron

The perceptron (Frank Rosenblatt, 1958) is the simplest neural network: a single artificial neuron that computes a weighted sum of its inputs and outputs 1 if the sum exceeds a threshold, 0 otherwise. It is a linear binary classifier with a remarkably simple learning rule, and it is the building block that, stacked into layers with differentiable activations, becomes the feedforward neural network.


1. The Model

The Perceptron: Weighted Sum + Step Function x1 w1 x2 w2 x3 w3 1bias b Σ wᵢxᵢ + b step(z)1 if z ≥ 00 otherwise ŷ ∈ {0,1}

Given input x ∈ Rn, weights w and bias b, the perceptron outputs ŷ = step(w · x + b). Geometrically, w · x + b = 0 is a hyperplane; w is its normal vector and b shifts it away from the origin. Everything on one side is class 1, everything on the other is class 0.

2. The Learning Rule

Perceptron Learning Rule Take sample (x, y) Predict ŷstep(w·x + b) ŷ ≠ y ?mistake check w += η(y−ŷ)xb += η(y−ŷ) Converges in a finite number of updates if the data is linearly separable (Novikoff, 1962).

For each training example, if the prediction is wrong, nudge the weights toward the correct answer: w ← w + η(y − ŷ)x. For a false negative this adds x to w, rotating the boundary to include it; a false positive subtracts it. Correct predictions leave weights unchanged. The perceptron convergence theorem guarantees a separating hyperplane is found in at most (R/γ)2 mistakes, where R bounds the input norm and γ is the margin.

3. From-Scratch Implementation

import numpy as np
from sklearn.datasets import make_blobs
from sklearn.linear_model import Perceptron as SkPerceptron

class Perceptron:
    def __init__(self, lr=1.0, epochs=50):
        self.lr, self.epochs = lr, epochs

    def fit(self, X, y):
        self.w = np.zeros(X.shape[1]); self.b = 0.0
        for epoch in range(self.epochs):
            mistakes = 0
            for xi, yi in zip(X, y):
                err = yi - self.predict(xi[None])[0]
                if err:
                    self.w += self.lr * err * xi
                    self.b += self.lr * err
                    mistakes += 1
            if mistakes == 0:                     # converged: data separated
                print(f"converged after {epoch + 1} epochs")
                break
        return self

    def predict(self, X):
        return (X @ self.w + self.b >= 0).astype(int)

X, y = make_blobs(n_samples=200, centers=2, cluster_std=1.0, random_state=42)
p = Perceptron().fit(X, y)
print("scratch accuracy:", (p.predict(X) == y).mean())

sk = SkPerceptron(max_iter=1000, tol=1e-3).fit(X, y)
print("sklearn accuracy:", sk.score(X, y))

# XOR: never converges; accuracy stays at or below 0.75
X_xor = np.array([[0, 0], [0, 1], [1, 0], [1, 1]]); y_xor = np.array([0, 1, 1, 0])
print("xor accuracy:", (Perceptron(epochs=100).fit(X_xor, y_xor).predict(X_xor) == y_xor).mean())

4. Limits: Linear Separability and XOR

Linearly Separable vs XOR AND-like: separable ✓ XOR: no line works ✗ yellow = class 0, green = class 1. Fix for XOR: a hidden layer (multi-layer perceptron).

A single perceptron can represent AND, OR and NOT, but not XOR, because no straight line separates XOR's classes. Minsky and Papert's 1969 book Perceptrons formalized such limits, which contributed to reduced interest in neural networks during the 1970s. The answer was multi-layer networks: one hidden layer of neurons can carve the plane into regions that a final neuron combines. Training them required replacing the non-differentiable step with smooth activations (sigmoid, tanh, later ReLU) and using backpropagation.

On non-separable data the basic perceptron never stops updating and its final weights depend on sample order. The pocket algorithm keeps the best weights seen; the averaged perceptron averages weights over all steps and generalizes better.

5. Relation to Other Models

When to use it today: mainly for teaching and as a fast online linear classifier on huge sparse feature sets (the averaged perceptron was a strong baseline for NLP tagging). Scale your features: the rule is sensitive to feature magnitudes.

6. A Worked Training Trace: Learning AND

Learn the AND function with learning rate η = 1, weights and bias starting at zero, and the convention step(z) = 1 if z > 0, else 0. Present the four examples in order (0,0)→0, (0,1)→0, (1,0)→0, (1,1)→1:

EpochInputTargetz = w·x + bPredUpdateNew w, b
1(0,0)000none(0,0), 0
1(0,1)000none(0,0), 0
1(1,0)000none(0,0), 0
1(1,1)100+x, b+1(1,1), 1
2(0,0)011b−1(1,1), 0
2(0,1)011−x, b−1(1,0), −1
2(1,0)000none(1,0), −1
2(1,1)100+x, b+1(2,1), 0

Continuing the same way, the weights keep rotating until every example is classified correctly; with this ordering the trace settles at w = (2, 1), b = −2 during epoch 5, and epoch 6 makes no mistakes, which confirms convergence. Any of infinitely many separating lines would do — the perceptron stops at the first one it finds, which is why its final boundary depends on the data order and is usually not the maximum-margin line an SVM would choose.

Two details from the trace generalise. The bias is just a weight on a constant input of 1, which is how most implementations handle it. And the learning rate does not matter for the basic perceptron when weights start at zero: scaling η scales every weight and the bias by the same factor, so the sign of w·x + b, and therefore every prediction, is unchanged.

7. Solving XOR with a Hidden Layer

Solving XOR with Two Layers of Perceptrons x1 input 0 or 1 x2 input 0 or 1 h1 = OR w=(1,1), b=-0.5 h2 = NAND w=(-1,-1), b=1.5 y = AND(h1,h2) w=(1,1), b=-1.5 XOR(x1,x2) = OR(x1,x2) AND NAND(x1,x2): true when exactly one input is 1

XOR is not linearly separable, but it is the AND of two functions that are: OR and NAND. Each hidden unit above is an ordinary perceptron with hand-set weights. For input (1,0): h1 = step(1 − 0.5) = 1, h2 = step(−1 + 1.5) = 1, and the output step(1 + 1 − 1.5) = 1. For (1,1): h1 = 1, h2 = step(−2 + 1.5) = 0, so the output is 0. The hidden layer has re-mapped the four points into a space where a single line separates them.

The difficulty was never representing such networks; it was learning the hidden weights. The perceptron rule needs to know the correct output of each neuron, and hidden neurons have no targets. Backpropagation solved this by replacing the step with a differentiable activation so the error gradient can be pushed back through every layer — the step from here to the multi-layer perceptron.

8. Perceptron Variants

VariantChangeWhy
Pocket (Gallant, 1990)Keep the weights with the fewest training errorsUsable result on non-separable data
Voted / averaged (Freund & Schapire, 1999)Vote or average all intermediate weight vectorsBetter generalisation, less order-dependence
Margin perceptronUpdate also when the score is correct but below a marginPushes the boundary away from the data
Kernel perceptronStore mistakes, score with a kernel sumNonlinear boundaries without explicit features
Multiclass perceptronOne weight vector per class; on error add x to the true class, subtract from the predictedMulticlass tagging (e.g. part-of-speech)
Structured perceptron (Collins, 2002)Predict a whole sequence with Viterbi, update on feature differencesSequence labelling in classic NLP

scikit-learn's Perceptron is a thin wrapper over SGDClassifier(loss="perceptron", learning_rate="constant", eta0=1, penalty=None); it supports partial_fit for streaming data and early_stopping on a validation split. The averaged variant is available through SGDClassifier(average=True).

9. Historical Context

McCulloch and Pitts (1943) described the threshold neuron as a logical unit with fixed weights. Rosenblatt's contribution in 1958 was the learning rule, demonstrated on the Mark I Perceptron, a hardware machine that learned to classify simple visual patterns from a grid of photocells. Widrow and Hoff's ADALINE (1960) used the same linear unit but trained it with the least-mean-squares rule on the continuous output before thresholding — a gradient method that converges even when classes overlap, and an early ancestor of the training used today. Minsky and Papert's analysis in 1969 showed what single-layer networks cannot compute; backpropagation's popularisation by Rumelhart, Hinton and Williams in 1986 showed how multi-layer networks could be trained, and the modern field grew from there.

10. Further Reading