Chapter 9 of 25
Linear Algebra for Neural Networks
Vectors, matrices, and why networks are just matrix math
Motivation
Here's a fact that surprises a lot of newcomers: a neural network with a million parameters isn't running a million separate little calculations when it makes a prediction. It's running a small handful of matrix multiplications. Every weighted sum inside a neuron, every layer's worth of neurons computed at once, every gradient flowing backward during training — all of it is linear algebra, dressed up in neural network vocabulary.
This matters for a very practical reason, not just an aesthetic one: linear algebra is why deep learning is fast. GPUs are extraordinarily good at one thing — multiplying large matrices — and the entire deep learning software stack is built around exploiting that fact. If you understand the operations in this chapter, every equation in the rest of this course will read as arithmetic you already know, instead of unfamiliar notation.
A Real-Life Scenario
Imagine a streaming service scoring how likely you are to enjoy a movie, based on a profile of features: how much you liked comedies, how much you liked action films, your average rating for movies from the last five years, and so on — say, 50 features in total. Now imagine it needs to do this not just for you, but for 10 million users, against a catalog of 20,000 movies, updated every night.
Doing this one multiplication at a time, in a Python for loop, would take unreasonably long. Doing it as one enormous matrix multiplication — every user's feature vector against every movie's feature vector, all at once — is something specialized hardware can chew through in seconds. The operations in this chapter are exactly what make that possible, and they are exactly what happens, at a smaller scale, inside every layer of an MLP.
Building the Intuition
Before the notation, here's the mental model to hold onto:
- A scalar is just a single number: your age, a temperature, a loss value.
- A vector is an ordered list of numbers — think of it as one row of a spreadsheet, or one data point's full set of features.
- A matrix is a grid of numbers — think of it as an entire spreadsheet, or a whole batch of data points stacked together.
- Inside an MLP, a layer's weights are a matrix, its bias is a vector, and a single input example is a vector. Multiplying the weight matrix by the input vector computes the pre-activation of every neuron in that layer, simultaneously — that single fact is the reason this chapter exists.
A scalar is a single number, e.g. . A vector is an ordered list of numbers, written as a column: . A matrix is a rectangular array with rows and columns, written . A tensor generalizes these to any number of dimensions — a scalar is a 0-dimensional tensor, a vector is 1-dimensional, a matrix is 2-dimensional.
Notation used throughout this course: lowercase italics () are scalars, lowercase bold () are vectors, uppercase bold () are matrices, is a transpose, and is the entry in row , column .
Vectors
Addition and Scalar Multiplication
Where: are same-size vectors and is a scalar.
Intuition: Addition combines vectors component by component — geometrically, place one vector's tail at the other's head and see where you land. Scalar multiplication stretches (), shrinks (), or flips () a vector without changing its underlying direction, aside from that sign flip.
The Dot Product
Where: .
Why it matters: This is the single most important operation in an entire MLP. The pre-activation of every neuron, , is nothing but a dot product between that neuron's weight vector and the input, plus a bias.
Geometric intuition: The dot product also equals , where is the angle between the vectors. It's large and positive when two vectors point in similar directions, zero when they're perpendicular, and negative when they point roughly opposite ways — it measures alignment.
Worked example: let and .
With bias , the neuron's pre-activation is — exactly the same arithmetic as a perceptron's weighted sum from two chapters ago, just written in vector notation.
Vector Norms
Where: (the Manhattan norm) sums absolute values; (the Euclidean norm) is the familiar straight-line length; is the single largest absolute component.
Why this matters: L1 and L2 norms of a weight vector underlie L1/L2 regularization, a technique you'll meet later in this course for discouraging overly large weights. The L2 norm of a gradient vector is also used for gradient clipping, a training-stability technique.
For : , and .
Matrices
Matrix Multiplication
Matrix multiplication is what lets you compute an entire layer of neurons in one shot, instead of looping over dot products one neuron at a time.
For and , the product is defined entry-by-entry as:
Where: (row , column of the result) is the dot product of row of with column of .
Critical requirement: the number of columns of must equal the number of rows of — this is the single most common source of shape-mismatch bugs when implementing networks from scratch.
Worked example: let and .
If is a layer's weight matrix and is the input, then every neuron's pre-activation in that layer is computed in a single step:
Intuition: each row of is one neuron's weight vector. Multiplying by simultaneously takes the dot product of every row with — that's every neuron's weighted sum, computed at once. This is exactly why deep learning frameworks are built around fast matrix multiplication, and why GPUs (which excel at exactly this operation) are central to modern deep learning.
in general — and often one of the two products isn't even defined, due to shape mismatches. Always check dimensions before multiplying; this is one of the most common bugs when implementing neural networks from scratch.
The Transpose
Intuition: transposing flips a matrix over its diagonal, turning rows into columns and vice versa. If , then . Transposes show up constantly in backpropagation, because gradients flow backward through the same weight matrices used in the forward pass, but with their roles — and dimensions — reversed.
Element-wise (Hadamard) Product
Where: and must have identical shape. Unlike matrix multiplication, this multiplies corresponding entries directly — no dot products, no summing.
Why this matters: the Hadamard product appears in backpropagation when combining a layer's upstream gradient with the local derivative of its activation function, since activation functions are always applied element-wise, one neuron at a time. You'll see this exact operation again in the backpropagation chapter, written with the symbol.
Matrix multiplication () combines rows with columns via dot products and can change the shape entirely. The Hadamard product () requires identical shapes and multiplies entry-by-entry, preserving shape. They solve different problems and are not interchangeable.
Special Matrices Worth Recognizing
| Matrix | Description |
|---|---|
| Identity (I) | 1s on the diagonal, 0s elsewhere; satisfies AI = IA = A |
| Zero matrix | Every entry is zero |
| Diagonal matrix | All off-diagonal entries are zero |
| Symmetric matrix | Satisfies A = Aᵀ |
| Orthogonal matrix | Satisfies AᵀA = I; preserves vector lengths and angles — relevant to some weight initialization schemes covered later in this course |
Implementing It
import numpy as np
# Vectors
u = np.array([1.0, 2.0, 3.0])
v = np.array([4.0, -1.0, 0.5])
print("u + v =", u + v)
print("dot(u, v) =", np.dot(u, v)) # equivalently u @ v
print("L2 norm(u) =", np.linalg.norm(u))
print("L1 norm(u) =", np.linalg.norm(u, 1))
# Matrices
W = np.array([[0.2, -0.5, 1.0],
[0.8, 0.1, -0.3]]) # shape (2, 3): 2 output units, 3 inputs
x = np.array([1.0, 0.5, -2.0]) # shape (3,)
b = np.array([0.1, -0.2]) # shape (2,)
z = W @ x + b # shape (2,): pre-activations of a layer
print("z =", z)
# Batch of examples: X has shape (batch_size, n_features)
X = np.array([[1.0, 0.5, -2.0],
[0.0, 1.0, 1.0]]) # 2 examples, 3 features each
Z = X @ W.T + b # shape (2, 2): pre-activations for both examples
print("Z (batched) =\n", Z)A few things worth noticing: the @ operator is NumPy's matrix multiplication, distinct from * (which does element-wise/Hadamard multiplication). Notice the batched line, X @ W.T + b: rather than looping over each of the two examples in Python, one matrix multiplication computes both examples' pre-activations at once, with b automatically broadcast across every row. This vectorized batch formulation, not manual loops, is what lets deep learning frameworks exploit fast, GPU-accelerated computation.
Always compute a batch's pre-activations as X @ W.T + b, where X has shape (batch_size, n_features) and W has shape (n_outputs, n_features). Getting this transpose backwards is one of the most common shape-mismatch errors when implementing a layer from scratch.
Key Takeaways
- Vectors and matrices are the basic data structures of an MLP: inputs, weights, and biases are all represented this way.
- The dot product computes one neuron's weighted sum; matrix multiplication computes an entire layer's pre-activations at once.
- Norms (, ) measure vector size and underlie regularization and gradient clipping.
- Matrix multiplication requires matching inner dimensions and is not commutative — check shapes carefully.
- The Hadamard (element-wise) product is a distinct operation from matrix multiplication, and it's exactly what backpropagation uses to combine gradients with activation derivatives.
- NumPy's
@operator and broadcasting make all of these operations efficient and concise in code.
Common Mistakes
W @ x and W * x do very different things in NumPy, and mixing them up silently produces wrong (but sometimes shape-compatible!) results. Matrix multiplication combines rows and columns via dot products; the Hadamard product multiplies entry-by-entry and requires identical shapes.
is only defined when 's column count matches 's row count — and even when both and happen to be defined, they are almost never equal. Always sanity-check shapes, especially when reshaping between single-example and batched code.
Interview Corner
Where This Shows Up in Practice
Every forward pass through every layer of an MLP is a matrix multiplication plus a bias vector; every backward pass reuses transposed weight matrices and Hadamard products with activation derivatives. The next chapter builds the other half of the toolkit — calculus — so that when we derive backpropagation, both the "what" (linear algebra, from this chapter) and the "why it works" (calculus, next) will already feel familiar.