Neural Networks

Layer 3 · Code

Neural Networks

Building a multilayer perceptron from scratch with NumPy, then the idiomatic PyTorch equivalent.

12 min read110 XP

As layers are added, the decision boundary a network can draw becomes far more flexible.
python
import numpy as np

def relu(z):
    return np.maximum(0, z)

def softmax(z):
    z = z - z.max(axis=-1, keepdims=True)   # numerical stability
    e = np.exp(z)
    return e / e.sum(axis=-1, keepdims=True)

class MLP:
    def __init__(self, in_dim, hidden_dim, out_dim, seed=0):
        rng = np.random.default_rng(seed)
        self.W1 = rng.normal(0, 0.1, (hidden_dim, in_dim))
        self.b1 = np.zeros(hidden_dim)
        self.W2 = rng.normal(0, 0.1, (out_dim, hidden_dim))
        self.b2 = np.zeros(out_dim)

    def forward(self, x):                # x: (batch, in_dim)
        z1 = x @ self.W1.T + self.b1     # (batch, hidden_dim)
        a1 = relu(z1)
        z2 = a1 @ self.W2.T + self.b2    # (batch, out_dim)
        return softmax(z2)

mlp = MLP(in_dim=784, hidden_dim=128, out_dim=10)
x = np.random.randn(4, 784)
probs = mlp.forward(x)
print(probs.shape, probs.sum(axis=-1))   # (4, 10) [1. 1. 1. 1.]
A 2-layer MLP forward pass, entirely from scratch.