HomeProjectsNotes
Theme
Back to Notes

Vectorization in Neural Networks

2026-04-01


Table of Contents

  1. What is Vectorization?
  2. When to Use Vectorization
  3. Mathematical Foundations
  4. General Rules and Key Formulas
  5. Step-by-Step Algorithm
  6. Numerical Example 1 — Basic Dot Product (Single Neuron)
  7. Numerical Example 2 — Two-Layer Neural Network
  8. Comparing the Two Examples
  9. Geometric Intuition
  10. Advantages of Vectorization
  11. Limitations of Vectorization
  12. Complete Formula Reference
  13. Summary

What is Vectorization?

Vectorization is a technique where operations are performed on entire arrays (vectors or matrices) at once, replacing explicit loops with compact linear-algebra expressions that hardware can execute in parallel.

Vectorization finds the most efficient representation of a computation by expressing it as matrix and vector operations, retaining the same numerical result while dramatically reducing wall-clock time.

Core Idea

Given a dataset with n n n observations and p p p features, and a weight vector w ∈ R p \mathbf{w} \in \mathbb{R}^p w∈Rp, the output z z z can be computed as:

  • Loop-based: iterate over each element w i x i w_i x_i wi​xi​ one at a time
  • Vectorized: compute z = w T x + b z = \mathbf{w}^T \mathbf{x} + b z=wTx+b as a single dot product

When to Use Vectorization

Situation Use Vectorization?
Large datasets ( n ≫ 1 n \gg 1 n≫1) ✅ Yes — essential
Deep / wide neural networks ✅ Yes — required
GPU / TPU acceleration ✅ Yes — only way to exploit hardware
Training loops with many iterations ✅ Yes — orders-of-magnitude speedup
Single scalar calculation ❌ No — overhead not worth it
Inherently sequential computation ❌ No — e.g., RNN hidden state roll-out
Debugging step-by-step ❌ No — loops are clearer to inspect

Mathematical Foundations

Vector Representation

A single input sample with p p p features is a column vector:

x = [ x 1 x 2 ⋮ x p ] ∈ R p \mathbf{x} = \begin{bmatrix} x_1 \\ x_2 \\ \vdots \\ x_p \end{bmatrix} \in \mathbb{R}^p x= ​x1​x2​⋮xp​​ ​∈Rp

Dot Product (Single Neuron, No Bias)

z = w T x = ∑ i = 1 p w i x i z = \mathbf{w}^T \mathbf{x} = \sum_{i=1}^{p} w_i x_i z=wTx=i=1∑p​wi​xi​

Affine Transformation (Single Neuron with Bias)

z = w T x + b z = \mathbf{w}^T \mathbf{x} + b z=wTx+b

Matrix Form — One Layer, m m m Neurons, n n n Samples

Z = W X + b   1 T Z = W X + \mathbf{b}\,\mathbf{1}^T Z=WX+b1T

Where:

  • W ∈ R m × p W \in \mathbb{R}^{m \times p} W∈Rm×p — weight matrix ( m m m neurons, p p p inputs each)
  • X ∈ R p × n X \in \mathbb{R}^{p \times n} X∈Rp×n — input matrix ( p p p features, n n n samples)
  • b ∈ R m \mathbf{b} \in \mathbb{R}^m b∈Rm — bias vector
  • Z ∈ R m × n Z \in \mathbb{R}^{m \times n} Z∈Rm×n — pre-activation output

Activation Function (Element-wise)

A = g ( Z ) = [ g ( z 11 ) ⋯ g ( z 1 n ) ⋮ ⋱ ⋮ g ( z m 1 ) ⋯ g ( z m n ) ] A = g(Z) = \begin{bmatrix} g(z_{11}) & \cdots & g(z_{1n}) \\ \vdots & \ddots & \vdots \\ g(z_{m1}) & \cdots & g(z_{mn}) \end{bmatrix} A=g(Z)= ​g(z11​)⋮g(zm1​)​⋯⋱⋯​g(z1n​)⋮g(zmn​)​ ​

Common choices: g ( z ) = σ ( z ) = 1 1 + e − z g(z) = \sigma(z) = \dfrac{1}{1+e^{-z}} g(z)=σ(z)=1+e−z1​ (sigmoid), ReLU ( z ) = max ⁡ ( 0 , z ) \text{ReLU}(z) = \max(0,z) ReLU(z)=max(0,z), tanh ⁡ ( z ) \tanh(z) tanh(z)


General Rules and Key Formulas

Rule 1: Loop-Based vs. Vectorized

Loop (scalar):

z = b + ∑ i = 1 p w i x i z = b + \sum_{i=1}^{p} w_i x_i z=b+i=1∑p​wi​xi​

Vectorized:

z = w T x + b \boxed{z = \mathbf{w}^T \mathbf{x} + b} z=wTx+b​

General Rule: Any summation ∑ i w i x i \sum_i w_i x_i ∑i​wi​xi​ over features or samples can be replaced by a single matrix/vector product.


Rule 2: Layer-Wise Forward Pass Formula

Z [ l ] = W [ l ] A [ l − 1 ] + b [ l ] \boxed{Z^{[l]} = W^{[l]} A^{[l-1]} + b^{[l]}} Z[l]=W[l]A[l−1]+b[l]​ A [ l ] = g [ l ]  ⁣ ( Z [ l ] ) \boxed{A^{[l]} = g^{[l]}\!\left(Z^{[l]}\right)} A[l]=g[l](Z[l])​

Key dimension rules (always verify these):

Quantity Shape
W [ l ] W^{[l]} W[l] ( n [ l ] ,   n [ l − 1 ] ) (n^{[l]},\ n^{[l-1]}) (n[l], n[l−1])
b [ l ] b^{[l]} b[l] ( n [ l ] ,   1 ) (n^{[l]},\ 1) (n[l], 1)
Z [ l ] Z^{[l]} Z[l] ( n [ l ] ,   m ) (n^{[l]},\ m) (n[l], m)
A [ l ] A^{[l]} A[l] ( n [ l ] ,   m ) (n^{[l]},\ m) (n[l], m)

where n [ l ] n^{[l]} n[l] = number of neurons in layer l l l, m m m = number of training samples.


Rule 3: Speed Rule

Method Time Complexity Hardware Utilisation Speed
Loop O ( n ⋅ p ) O(n \cdot p) O(n⋅p) sequential CPU only (1 core) Slow 🐢
Vectorization O ( n ⋅ p ) O(n \cdot p) O(n⋅p) parallel CPU/GPU/TPU SIMD Fast 🚀

Rule of thumb: On modern hardware, a vectorized matrix multiply on GPU can be 10 × 10\times 10×– 1000 × 1000\times 1000× faster than the equivalent Python loop, depending on matrix size.


Rule 4: Gradient (Backprop) Vectorization

d W [ l ] = 1 m   d Z [ l ] ( A [ l − 1 ] ) T \boxed{dW^{[l]} = \frac{1}{m}\, dZ^{[l]} \left(A^{[l-1]}\right)^T} dW[l]=m1​dZ[l](A[l−1])T​ d b [ l ] = 1 m   ∑ j = 1 m d Z [ : , j ] [ l ] \boxed{db^{[l]} = \frac{1}{m}\, \sum_{j=1}^{m} dZ^{[l]}_{[:,j]}} db[l]=m1​j=1∑m​dZ[:,j][l]​​ d A [ l − 1 ] = ( W [ l ] ) T d Z [ l ] \boxed{dA^{[l-1]} = \left(W^{[l]}\right)^T dZ^{[l]}} dA[l−1]=(W[l])TdZ[l]​

All three backprop formulas are matrix products — no loops required.


Rule 5: Memory and Numerical Considerations

Consideration Vectorized Approach Loop Approach
Memory layout Contiguous (cache-friendly) Scattered (cache misses)
Numerical stability Same as loop Same as vectorized
Overflow risk Use float32/float64 carefully Same
Batch processing Handles m m m samples at once Requires outer loop

Step-by-Step Algorithm

Algorithm: Vectorized Forward Pass — L-Layer Neural Network
 
Input:  Input matrix X ∈ ℝ^(p×m), weights {W^[l], b^[l]} for l = 1…L
Output: Final activation A^[L] ∈ ℝ^(n^[L]×m)
 
Step 1: INITIALISE
        A^[0] = X         (shape: p × m)
 
Step 2: FOR EACH LAYER l = 1 to L:
 
    Step 2a: LINEAR STEP
             Z^[l] = W^[l] · A^[l-1] + b^[l]
             (broadcasting adds b^[l] to every column)
 
    Step 2b: ACTIVATION STEP
             A^[l] = g^[l]( Z^[l] )     (element-wise)
 
Step 3: OUTPUT
        Ŷ = A^[L]
 
Step 4: COMPUTE LOSS (e.g., cross-entropy for classification)
        L = -(1/m) Σ_j [ y_j log(ŷ_j) + (1-y_j) log(1-ŷ_j) ]
 
Step 5: BACKPROP (vectorized)
        For l = L down to 1:
            dZ^[l]   = dA^[l] ⊙ g'^[l](Z^[l])
            dW^[l]   = (1/m) dZ^[l] · (A^[l-1])^T
            db^[l]   = (1/m) sum(dZ^[l], axis=1, keepdims=True)
            dA^[l-1] = (W^[l])^T · dZ^[l]
 
Step 6: UPDATE WEIGHTS
        W^[l] ← W^[l] - α · dW^[l]
        b^[l] ← b^[l] - α · db^[l]

Numerical Example 1 — Basic Dot Product (Single Neuron)

Scope: p = 3 p = 3 p=3 input features, 1 1 1 neuron, n = 1 n = 1 n=1 sample — reduce a weighted sum to a single scalar output.


Step 1 — Define Inputs

w = [ 2 3 4 ] , x = [ 1 2 3 ] , b = 1 \mathbf{w} = \begin{bmatrix} 2 \\ 3 \\ 4 \end{bmatrix}, \quad \mathbf{x} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix}, \quad b = 1 w= ​234​ ​,x= ​123​ ​,b=1

Step 2 — Loop-Based Computation

z = w 1 x 1 + w 2 x 2 + w 3 x 3 + b z = w_1 x_1 + w_2 x_2 + w_3 x_3 + b z=w1​x1​+w2​x2​+w3​x3​+b z = ( 2 × 1 ) + ( 3 × 2 ) + ( 4 × 3 ) + 1 z = (2 \times 1) + (3 \times 2) + (4 \times 3) + 1 z=(2×1)+(3×2)+(4×3)+1 z = 2 + 6 + 12 + 1 = 21 z = 2 + 6 + 12 + 1 = 21 z=2+6+12+1=21

Step 3 — Vectorized Computation

z = w T x + b = [ 2    3    4 ] [ 1 2 3 ] + 1 = 20 + 1 = 21 \boxed{z = \mathbf{w}^T \mathbf{x} + b = [2\ \ 3\ \ 4]\begin{bmatrix}1\\2\\3\end{bmatrix} + 1 = 20 + 1 = 21} z=wTx+b=[2  3  4] ​123​ ​+1=20+1=21​

👉 Same result — one line 🔥


Step 4 — Apply Activation Function

Using sigmoid σ ( z ) = 1 1 + e − z \sigma(z) = \dfrac{1}{1 + e^{-z}} σ(z)=1+e−z1​:

a = σ ( 21 ) = 1 1 + e − 21 ≈ 1 1 + 7.58 × 10 − 10 ≈ 0.99999999 a = \sigma(21) = \frac{1}{1 + e^{-21}} \approx \frac{1}{1 + 7.58 \times 10^{-10}} \approx 0.99999999 a=σ(21)=1+e−211​≈1+7.58×10−101​≈0.99999999

Final Result — Example 1

Quantity Value
w \mathbf{w} w [ 2 ,   3 ,   4 ] [2,\ 3,\ 4] [2, 3, 4]
x \mathbf{x} x [ 1 ,   2 ,   3 ] [1,\ 2,\ 3] [1, 2, 3]
b b b 1 1 1
z = w T x + b z = \mathbf{w}^T\mathbf{x}+b z=wTx+b 21 21 21
a = σ ( z ) a = \sigma(z) a=σ(z) ≈ 1.0 \approx 1.0 ≈1.0

A single dot product replaced three multiplications and two additions executed in a loop — and the pattern scales to millions of features with zero code change.


Numerical Example 2 — Two-Layer Neural Network

Scope: p = 2 p = 2 p=2 input features, Layer 1 has m 1 = 2 m_1 = 2 m1​=2 neurons (ReLU), Layer 2 has m 2 = 1 m_2 = 1 m2​=1 neuron (Sigmoid). n = 3 n = 3 n=3 training samples.


Step 1 — Define Inputs and Parameters

Input matrix ( p × n = 2 × 3 p \times n = 2 \times 3 p×n=2×3):

X = [ 1 2 3 4 5 6 ] X = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} X=[14​25​36​]

Layer 1 ( m 1 × p = 2 × 2 m_1 \times p = 2 \times 2 m1​×p=2×2):

W [ 1 ] = [ 1 0 0 1 ] , b [ 1 ] = [ 1 1 ] W^{[1]} = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}, \quad b^{[1]} = \begin{bmatrix} 1 \\ 1 \end{bmatrix} W[1]=[10​01​],b[1]=[11​]

Layer 2 ( m 2 × m 1 = 1 × 2 m_2 \times m_1 = 1 \times 2 m2​×m1​=1×2):

W [ 2 ] = [ 0.5 0.5 ] , b [ 2 ] = [ 0 ] W^{[2]} = \begin{bmatrix} 0.5 & 0.5 \end{bmatrix}, \quad b^{[2]} = \begin{bmatrix} 0 \end{bmatrix} W[2]=[0.5​0.5​],b[2]=[0​]

Step 2 — Layer 1: Linear Step

Z [ 1 ] = W [ 1 ] X + b [ 1 ] Z^{[1]} = W^{[1]} X + b^{[1]} Z[1]=W[1]X+b[1] Z [ 1 ] = [ 1 0 0 1 ] [ 1 2 3 4 5 6 ] + [ 1 1 ] Z^{[1]} = \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix} \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} + \begin{bmatrix} 1 \\ 1 \end{bmatrix} Z[1]=[10​01​][14​25​36​]+[11​] = [ 1 2 3 4 5 6 ] + [ 1 1 1 1 1 1 ] = [ 2 3 4 5 6 7 ] = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix} + \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix} = \begin{bmatrix} 2 & 3 & 4 \\ 5 & 6 & 7 \end{bmatrix} =[14​25​36​]+[11​11​11​]=[25​36​47​]

Step 3 — Layer 1: Activation (ReLU)

A [ 1 ] = ReLU ( Z [ 1 ] ) = max ⁡ ( 0 ,   Z [ 1 ] ) = [ 2 3 4 5 6 7 ] A^{[1]} = \text{ReLU}(Z^{[1]}) = \max(0,\ Z^{[1]}) = \begin{bmatrix} 2 & 3 & 4 \\ 5 & 6 & 7 \end{bmatrix} A[1]=ReLU(Z[1])=max(0, Z[1])=[25​36​47​]

All values are positive, so ReLU makes no change here.


Step 4 — Layer 2: Linear Step

Z [ 2 ] = W [ 2 ] A [ 1 ] + b [ 2 ] Z^{[2]} = W^{[2]} A^{[1]} + b^{[2]} Z[2]=W[2]A[1]+b[2] = [ 0.5 0.5 ] [ 2 3 4 5 6 7 ] + [ 0 ] = \begin{bmatrix} 0.5 & 0.5 \end{bmatrix} \begin{bmatrix} 2 & 3 & 4 \\ 5 & 6 & 7 \end{bmatrix} + \begin{bmatrix} 0 \end{bmatrix} =[0.5​0.5​][25​36​47​]+[0​] = [ 0.5 ( 2 ) + 0.5 ( 5 ) 0.5 ( 3 ) + 0.5 ( 6 ) 0.5 ( 4 ) + 0.5 ( 7 ) ] = \begin{bmatrix} 0.5(2)+0.5(5) & 0.5(3)+0.5(6) & 0.5(4)+0.5(7) \end{bmatrix} =[0.5(2)+0.5(5)​0.5(3)+0.5(6)​0.5(4)+0.5(7)​] Z [ 2 ] = [ 3.5 4.5 5.5 ] Z^{[2]} = \begin{bmatrix} 3.5 & 4.5 & 5.5 \end{bmatrix} Z[2]=[3.5​4.5​5.5​]

Step 5 — Layer 2: Activation (Sigmoid)

A [ 2 ] = σ ( Z [ 2 ] ) = [ σ ( 3.5 ) σ ( 4.5 ) σ ( 5.5 ) ] A^{[2]} = \sigma(Z^{[2]}) = \begin{bmatrix} \sigma(3.5) & \sigma(4.5) & \sigma(5.5) \end{bmatrix} A[2]=σ(Z[2])=[σ(3.5)​σ(4.5)​σ(5.5)​] σ ( 3.5 ) = 1 1 + e − 3.5 ≈ 0.9706 \sigma(3.5) = \frac{1}{1+e^{-3.5}} \approx 0.9706 σ(3.5)=1+e−3.51​≈0.9706 σ ( 4.5 ) = 1 1 + e − 4.5 ≈ 0.9890 \sigma(4.5) = \frac{1}{1+e^{-4.5}} \approx 0.9890 σ(4.5)=1+e−4.51​≈0.9890 σ ( 5.5 ) = 1 1 + e − 5.5 ≈ 0.9959 \sigma(5.5) = \frac{1}{1+e^{-5.5}} \approx 0.9959 σ(5.5)=1+e−5.51​≈0.9959 A [ 2 ] = [ 0.9706 0.9890 0.9959 ] \boxed{A^{[2]} = \begin{bmatrix} 0.9706 & 0.9890 & 0.9959 \end{bmatrix}} A[2]=[0.9706​0.9890​0.9959​]​

Final Result — Example 2

Sample x 1 x_1 x1​ x 2 x_2 x2​ z [ 2 ] z^{[2]} z[2] y ^ = a [ 2 ] \hat{y} = a^{[2]} y^​=a[2]
Sample 1 1 4 3.5 0.9706
Sample 2 2 5 4.5 0.9890
Sample 3 3 6 5.5 0.9959

All three samples processed simultaneously in one matrix multiply per layer — no outer loop over samples required.


Comparing the Two Examples

Property Example 1 (Single Neuron) Example 2 (Two-Layer Network)
Input shape p = 3 p = 3 p=3, n = 1 n = 1 n=1 p = 2 p = 2 p=2, n = 3 n = 3 n=3
Network depth 1 layer 2 layers
Weight shapes W ∈ R 1 × 3 W \in \mathbb{R}^{1\times3} W∈R1×3 W [ 1 ] ∈ R 2 × 2 W^{[1]} \in \mathbb{R}^{2\times2} W[1]∈R2×2, W [ 2 ] ∈ R 1 × 2 W^{[2]} \in \mathbb{R}^{1\times2} W[2]∈R1×2
Activation Sigmoid ReLU → Sigmoid
Loops replaced 1 loop (3 iterations) 2 layer loops + 1 sample loop
Output Scalar y ^ ≈ 1.0 \hat{y} \approx 1.0 y^​≈1.0 Row vector Y ^ ∈ R 1 × 3 \hat{Y} \in \mathbb{R}^{1\times3} Y^∈R1×3
Key vectorization benefit Clarity / conciseness Batch parallelism over n n n samples

Geometric Intuition

PCA rotates a coordinate system; vectorization transforms a dataset in the same spirit:

  1. Weight matrix W W W — applies a linear transformation (rotation + scaling) to the input space
  2. Bias b b b — shifts (translates) the transformed space
  3. Activation g g g — bends the space non-linearly

The Geometry of a Forward Pass

Instead of transforming one point at a time, the matrix multiply transforms all n n n points simultaneously — this is the geometric essence of vectorization.


Advantages of Vectorization

Advantage Description
Speed Exploits SIMD / GPU parallelism — 10 × 10\times 10×– 1000 × 1000\times 1000× faster 🚀
Simplicity 3 lines of math replace 30 lines of loops
Scalability Same code runs on 10 samples or 10 million samples
Numerical BLAS-optimised routines reduce floating-point error
Batch norm Batch statistics computed trivially across the sample axis

Limitations of Vectorization

Limitation Description Alternative
Memory Large matrices may exceed GPU VRAM Mini-batch gradient descent
Debugging Hard to inspect intermediate per-sample values Use loop version for debugging
Sequential ops RNNs with data-dependent control flow resist full vectorization Truncated BPTT, scan ops
Sparse data Dense matrix ops waste compute on zero entries Sparse matrix formats
Numerical overflow Large z z z in softmax causes inf Stable log-sum-exp trick

Complete Formula Reference

Formula Expression
Dot product z = w T x + b z = \mathbf{w}^T\mathbf{x} + b z=wTx+b
Layer linear step Z [ l ] = W [ l ] A [ l − 1 ] + b [ l ] Z^{[l]} = W^{[l]} A^{[l-1]} + b^{[l]} Z[l]=W[l]A[l−1]+b[l]
Layer activation A [ l ] = g [ l ] ( Z [ l ] ) A^{[l]} = g^{[l]}(Z^{[l]}) A[l]=g[l](Z[l])
Sigmoid σ ( z ) = 1 1 + e − z \sigma(z) = \dfrac{1}{1+e^{-z}} σ(z)=1+e−z1​
ReLU ReLU ( z ) = max ⁡ ( 0 , z ) \text{ReLU}(z) = \max(0, z) ReLU(z)=max(0,z)
Backprop — d Z dZ dZ d Z [ l ] = d A [ l ] ⊙ g ′ [ l ] ( Z [ l ] ) dZ^{[l]} = dA^{[l]} \odot g'^{[l]}(Z^{[l]}) dZ[l]=dA[l]⊙g′[l](Z[l])
Backprop — d W dW dW d W [ l ] = 1 m   d Z [ l ] ( A [ l − 1 ] ) T dW^{[l]} = \dfrac{1}{m}\,dZ^{[l]}(A^{[l-1]})^T dW[l]=m1​dZ[l](A[l−1])T
Backprop — d b db db d b [ l ] = 1 m ∑ j = 1 m d Z [ : , j ] [ l ] db^{[l]} = \dfrac{1}{m}\displaystyle\sum_{j=1}^{m} dZ^{[l]}_{[:,j]} db[l]=m1​j=1∑m​dZ[:,j][l]​
Backprop — d A [ l − 1 ] dA^{[l-1]} dA[l−1] d A [ l − 1 ] = ( W [ l ] ) T d Z [ l ] dA^{[l-1]} = (W^{[l]})^T dZ^{[l]} dA[l−1]=(W[l])TdZ[l]
Weight update W [ l ] ← W [ l ] − α   d W [ l ] W^{[l]} \leftarrow W^{[l]} - \alpha\, dW^{[l]} W[l]←W[l]−αdW[l]
Cross-entropy loss L = − 1 m ∑ j [ y j log ⁡ y ^ j + ( 1 − y j ) log ⁡ ( 1 − y ^ j ) ] \mathcal{L} = -\dfrac{1}{m}\displaystyle\sum_j \bigl[y_j \log \hat{y}_j + (1-y_j)\log(1-\hat{y}_j)\bigr] L=−m1​j∑​[yj​logy^​j​+(1−yj​)log(1−y^​j​)]

Summary

INPUT (p × m)
    │
    ▼
LAYER 1 — LINEAR:   Z¹ = W¹ · X + b¹
    │
    ▼
LAYER 1 — ACTIVATE: A¹ = g¹(Z¹)
    │
    ▼
LAYER 2 — LINEAR:   Z² = W² · A¹ + b²
    │
    ▼
LAYER 2 — ACTIVATE: A² = g²(Z²)
    │
    ▼
OUTPUT Ŷ = A^[L]   (all m samples processed at once)
    │
    ▼
LOSS → BACKPROP (all gradients are matrix products)
    │
    ▼
UPDATE WEIGHTS (W ← W − α · dW)

Key Takeaways

  1. Vectorization = no loops — replace ∑ i w i x i \sum_i w_i x_i ∑i​wi​xi​ with w T x \mathbf{w}^T \mathbf{x} wTx
  2. Batch processing — stack m m m samples as columns; one matrix multiply handles all
  3. Shape discipline — always verify ( m l ,   m l − 1 ) × ( m l − 1 ,   n ) = ( m l ,   n ) (m_l,\,m_{l-1}) \times (m_{l-1},\,n) = (m_l,\,n) (ml​,ml−1​)×(ml−1​,n)=(ml​,n)
  4. Both forward and backward passes are fully vectorizable
  5. Hardware wins — vectorized code automatically benefits from BLAS, CUDA, and TPU kernels
  6. Same math, any scale — code for n = 3 n=3 n=3 runs unchanged on n = 3,000,000 n=3{,}000{,}000 n=3,000,000
  7. Linear algebra is the language of deep learning — mastering it unlocks everything