Forward Propagation
Consider a network that must decide whether an image contains a cat. It is given nothing but a grid of pixel intensities. Somewhere between the raw pixels and the final "cat" or "no cat" verdict, the network must transform the input. It does this through a sequence of intermediate representations. Each one is a step further from raw sensory data. Each is also a step closer to an abstract decision. Forward propagation is the precise mechanical process that performs this transformation. It takes an input vector and pushes it through a sequence of affine maps and nonlinearities. The result is an output. Every prediction a neural network ever makes — in vision, in speech, in language, in game-playing agents — is the result of a forward pass. Forward propagation matters because it is the computational backbone on which everything else in deep learning is built. Training requires computing a loss. The loss is defined on the output of a forward pass. Backpropagation, the algorithm used to compute gradients, is literally defined as a reversal of the forward computation graph. Inference in production systems is nothing but a forward pass. This is the thing that actually runs when you ask a voice assistant a question. It is also what runs when a self-driving car classifies a pedestrian. It is optimized for speed and executed billions of times per day. Understanding forward propagation deeply matters a great deal. It means understanding it as a sequence of matrix operations with well-defined shapes and costs. This is the prerequisite for understanding training. It is also the prerequisite for debugging shape mismatches. And it is needed for reasoning about inference latency. This article builds on your knowledge of The Multilayer Perceptron. It makes the layer-by-layer computation fully explicit. Rather than treating "the network computes an output" as a black box, we go further. We will write down the exact matrix multiplications. We will specify the exact shapes involved at each layer. We will also specify the exact order of operations. We will pay close attention to how the computation is vectorized across a batch of examples. Real systems never propagate one example at a time. Instead, they propagate thousands simultaneously to exploit modern hardware. By the end, you should be able to derive the shape and cost of every intermediate tensor in an MLP from first principles. You should be able to trace a concrete numerical example by hand. You should also see precisely how the forward pass sets up the machinery. This machinery is used later for Loss Functions for Deep Networks. It is also used for representing computation as Computational Graphs.
- Forward propagation computes a network's output by applying, layer by layer, an affine transform followed by a nonlinear activation.
- Each layer's computation is , then .
- Batching stacks examples into matrix columns (or rows), turning per-example vector ops into single matrix multiplications.
- Time cost is dominated by matrix multiplications: roughly multiply-adds for examples.
- Space cost requires caching every intermediate activation, since these values are needed later by backpropagation.
- Correctness follows by induction on layer index: each layer's output shape and semantics are guaranteed by the invariant that its input matches the previous layer's output.
Forward propagation is repeated matrix multiplication plus elementwise nonlinearity, carrying a fixed shape invariant from layer to layer until the input becomes the output.
The idea
A feedforward neural network with layers is defined by weight matrices , bias vectors , and activation functions . Forward propagation is the procedure that, given an input , computes the network's output by applying these layers in sequence. Concretely, define as the input, and for each layer compute two quantities: the pre-activation (or logit)
and the activation
The final activation is the network's output . The word "forward" refers to the direction of information flow: data moves strictly from the input layer toward the output layer, with no loops or backward edges, which is why this class of models is called a feedforward network. The key structural fact is that has shape , where is the width (number of units) of the previous layer and is the width of the current layer. This shape convention guarantees that is well-defined and produces a vector of length , which is exactly the width expected by layer . This is the "shape invariant" that forward propagation preserves at every step, and it is the single most useful fact for debugging real networks: any dimension mismatch in a forward pass is a violation of this invariant, almost always caused by a wrongly transposed matrix or a misconfigured layer width. In practice, we never run one input vector through the network at a time — we run a batch of examples simultaneously. Stacking the examples as columns of a matrix , the exact same equations apply with vectors replaced by matrices:
where the addition of to a matrix of shape is broadcast — the bias vector is added to every column. This batched form is what actually runs on GPUs: a handful of large matrix multiplications rather than millions of small vector operations, which is essential for computational efficiency (discussed in detail below).
How it works
Forward propagation proceeds as a simple loop over layers, each iteration performing one matrix multiply, one broadcasted bias addition, and one elementwise nonlinearity. The only subtlety is bookkeeping: every intermediate and must typically be cached, because although forward propagation alone does not need them after use, the backpropagation algorithm that computes gradients will need them.
Step-by-step mechanism: 1. Load the input batch into . 2. For each layer from to : a. Compute the pre-activation . b. Apply the nonlinearity elementwise: . c. Cache and for later use (e.g. by backpropagation). 3. Return as the prediction . The choice of varies by layer. Hidden layers commonly use ReLU, , or tanh; the output layer's activation is chosen to match the task — sigmoid for binary classification, softmax for multiclass classification, or the identity function for regression. This choice does not change the mechanics of forward propagation, only the specific function applied in step 2b. ``` function FORWARD_PROPAGATE(X, weights[1..L], biases[1..L], activations[1..L]):
# X has shape (n0, m): n0 input features, m examples in the batch A[0] = X cache = {} # will store Z[l], A[l] for every layer for l = 1 to L: W = weights[l] # shape (n_l, n_{l-1}) b = biases[l] # shape (n_l, 1), broadcast over m columns g = activations[l] Z[l] = MATMUL(W, A[l-1]) + b # shape (n_l, m) A[l] = ELEMENTWISE(g, Z[l]) # shape (n_l, m), same shape as Z[l] cache[l] = (Z[l], A[l-1]) # store what backprop will need
# (A[l] itself is available as A[l-1] of the next iteration,
# and also cached explicitly if this is the last layer) Yhat = A[L] return Yhat, cache ``` Two invariants make this loop correct by construction. First, the shape invariant: at the start of iteration , has shape by the induction hypothesis (true at since has shape by definition), and since has shape , the product has shape , matching what the next iteration expects. Second, the semantic invariant: always represents "the representation of the input batch as seen after layers of processing," so that composing layers computes exactly the function the architecture defines, namely .
Complexity & correctness
Time complexity. The dominant cost at layer is the matrix multiplication , where and . A standard (non-strassen) matrix multiply of an matrix by an matrix costs multiply-add operations, since each of the output entries is an inner product of length . The bias addition and elementwise activation cost only , which is dominated by the matrix multiply whenever . Summing over all layers, the total time for one forward pass over a batch of examples is
This is tight (not just an upper bound) for standard dense matrix multiplication, since every entry of every weight matrix must be read and multiplied by some activation at least once — there is no way to compute a general matrix-vector product faster than examining every matrix entry, in the absence of special structure (sparsity, low rank, etc.). If all hidden layers have roughly the same width , this simplifies to .
Space complexity. Two components matter. First, storing the parameters themselves costs , independent of the batch size — this is fixed at training/deployment time. Second, storing the activations for a forward pass costs , since each layer's output has entries. If the goal is inference only, one can discard as soon as is computed, needing only memory at any instant (two buffers). However, if a backward pass will follow (training), every and must be retained, since the chain rule needs them — this is precisely why training consumes far more memory than inference, and it is the reason techniques like gradient checkpointing exist (trading recomputation for memory).
Correctness. The forward pass computes exactly the function specified by the network architecture, and this can be shown by induction on the layer index . The base case is trivial: is the input by definition, matching the architecture's specification with zero layers applied. For the inductive step, assume correctly holds , the composition of the first layers applied to the input. Then by the algorithm's definition,
which is exactly the definition of applying layers. By induction this holds for all up to , so is the network's full function applied to , as required. Correctness of the shapes follows by the same induction using the shape invariant argued in the previous section.
Tradeoffs. Batching increases throughput (better hardware utilization, amortized memory-access overhead) but increases peak memory use linearly in ; very large batches can exceed device memory, forcing gradient accumulation or smaller batches at the cost of noisier gradient estimates during training. Caching every activation is essential for training but wasteful for inference-only deployment, where "forward-only" implementations deliberately drop this cache to save memory. Numerically, computing and applying separately (rather than some fused approximation) is exact but two full passes over the data; production systems often fuse the matmul, bias-add, and activation into a single kernel purely for speed, without changing the mathematical result.
Worked example
Consider a tiny network with input features, one hidden layer of width with ReLU activation, and a scalar output layer with sigmoid activation (binary classification). Take a batch of examples:
Here column of is example : example 1 is , example 2 is .
Layer 1 pre-activation:
Layer 1 activation (ReLU, elementwise):
Layer 2 pre-activation:
Layer 2 activation (sigmoid):
The table below traces the shapes at every step, confirming the shape invariant argued earlier:
| Step | Expression | Shape | Value |
|---|---|---|---|
| Input | |||
| Layer 1 pre-act | |||
| Layer 1 act | |||
| Layer 2 pre-act | |||
| Output |
Example 1 (features ) is predicted "positive class" with probability , and example 2 (features ) with probability ; both are cached along with for the backward pass that would compute gradients against a loss such as binary cross-entropy — the topic of Loss Functions for Deep Networks.
Common pitfalls & traps
| Pitfall | Why it happens | Fix |
|---|---|---|
| Shape mismatch in matmul | built with shape instead of | Fix the convention once and check every layer's expected input/output width |
| Forgetting to broadcast the bias | Treating as needing per-example duplication manually | Rely on broadcasting semantics; verify shape is , not |
| Applying activation before the affine map | Swapping steps 2a and 2b in the loop | Always compute first, then |
| Not caching intermediate values | Only computing the final output when training will also be needed | Cache every if a backward pass is planned |
| Numerical overflow in sigmoid/softmax | Computing directly for large | Use numerically stable formulations (e.g. subtracting the max before exponentiating) |
| Using training-time layers unchanged at inference | Dropout or batchnorm behave differently forward vs. eval mode | Explicitly set an inference/eval mode that changes those layers' forward behavior |
Pioneers & history
The forward pass as we use it today is the computational realization of ideas that trace back to the earliest formal models of neurons and to the linear-algebraic view of computation that became standard with the rise of vectorized numerical computing.
Origins · 1 minWarren McCulloch and how this was discovered
Where this matters
Every neural network deployed in production — image classifiers, speech recognizers, recommendation systems, large language models generating the next token — executes a forward pass to produce its output; training additionally requires a forward pass before every backward pass to compute gradients. Deep learning frameworks such as PyTorch and TensorFlow implement forward propagation as a graph of tensor operations, which is precisely the notion of a computational graph that later supports automatic differentiation. Hardware accelerators (GPUs, TPUs) are designed around the exact operation forward propagation demands most: dense matrix multiplication at scale, which is why matrix-multiply throughput (measured in FLOPs) is the headline specification of modern AI chips. Inference-serving systems (the software that answers a live user's request) optimize forward propagation specifically — through quantization, kernel fusion, and batching strategies — since inference-time forward passes, run at massive scale, dominate the operational cost of deployed AI products. Understanding forward propagation precisely is also the direct prerequisite for understanding Loss Functions for Deep Networks, since a loss is always computed as a function of the forward pass's output, and for understanding backpropagation, which is defined as a reverse traversal of the same computational graph.
:::quiz[If layer has units and layer has units, what is the shape of ?]
- ✓
:::quiz[Why is a bias vector added correctly to ?]
- Because matrix addition requires identical shapes, so no adjustment is needed
- Because the bias is broadcast across the columns, adding the same vector to every example ✓
- Because the bias is transposed before addition
- Because must always equal
:::quiz[Why must and typically be cached during a forward pass used for training?]
- They are needed to compute the loss directly, and nothing else uses them
- The backward pass (gradient computation) reuses these exact values via the chain rule ✓
- Caching improves numerical precision of the forward computation
- Only , the final output, is ever needed later
Ask the tutor: How does the cached forward-pass data get reused, step by step, when backpropagation computes gradients?
What is the difference between forward propagation and backpropagation?
Forward propagation computes the network's output given an input, moving strictly from the input layer toward the output layer through affine transforms and nonlinearities. Backpropagation is a separate algorithm, run afterward, that computes gradients of a loss with respect to every parameter by applying the chain rule in reverse order through the same layers. Forward propagation must run first because backpropagation reuses the cached intermediate values (, ) that only a forward pass produces. In short: forward propagation answers "what does the network predict?" while backpropagation answers "how should the parameters change to reduce the loss?" — the two together form one full training step.
Why do we batch examples into a matrix instead of looping over them one at a time?
Looping over examples individually performs many small matrix-vector multiplications, which underutilizes modern hardware (GPUs, TPUs) that are optimized for large matrix-matrix multiplications with high arithmetic intensity. Stacking examples as columns turns the per-example computation into a single matrix multiply , amortizing memory-access overhead and exploiting parallel hardware far more efficiently. The total number of arithmetic operations is essentially the same either way — batching does not reduce asymptotic FLOPs — but it dramatically improves wall-clock throughput because of how hardware executes matrix multiplication in parallel.
Does the choice of activation function change the complexity of forward propagation?
Not asymptotically. Applying an elementwise nonlinearity to a matrix of shape costs regardless of which function is used (ReLU, sigmoid, tanh, GELU, etc.), and this is always dominated by the cost of the preceding matrix multiplication whenever . Different activations do have different constant-factor costs in practice — sigmoid and tanh require evaluating exponentials, which are slower per-element than ReLU's simple comparison — but this affects wall-clock time by a constant factor, not the big-O complexity of the forward pass.
What happens differently at inference time compared to during training, for the same forward pass code?
During training, every intermediate activation must be cached because backpropagation needs it, and certain layers (dropout, batch normalization) behave stochastically or use batch statistics. At inference time, none of the cached values are needed afterward, so memory can be minimized by discarding each layer's input as soon as its output is computed. Layers like dropout are typically disabled entirely at inference (equivalent to keeping all units), and batch normalization switches from batch statistics to fixed running statistics estimated during training. The underlying matrix-multiply-plus-activation computation is identical; what changes is auxiliary layer behavior and memory management policy.
Can forward propagation be computed on any acyclic network, or only strictly layered MLPs?
The layer-by-layer description here is a special case of the more general rule: forward propagation is well-defined on any directed acyclic computational graph, since acyclicity guarantees a valid topological order in which every node's inputs are computed before the node itself. Strictly layered MLPs are the simplest such graph, a chain, but architectures with skip connections (residual networks), branching, or merging (as in many convolutional architectures) are also DAGs and are handled by the same principle: compute nodes in topological order, caching outputs as needed. This generalization is exactly the perspective formalized by Computational Graphs.
How does forward propagation relate to what I already know about the multilayer perceptron?
The Multilayer Perceptron defines the architecture — how many layers, how wide each layer is, which activation function each layer uses — as a static specification of a parameterized function. Forward propagation is the algorithm that evaluates this specification on actual data, turning the abstract definition into concrete numbers by executing the matrix multiplications and nonlinearities in order. Every MLP you have studied conceptually is executed, in practice, exactly via the forward propagation procedure described in this article.
What is the single most common bug when implementing forward propagation from scratch?
By far the most common bug is a shape mismatch or an unintended broadcast, typically from transposing a weight or bias matrix incorrectly. Because many numerical libraries broadcast shapes automatically rather than raising errors, a wrongly shaped bias or weight can produce code that runs successfully but computes a mathematically wrong function — for example, mixing information across examples in a batch instead of treating them independently. The reliable defense is to explicitly assert the expected shape of every tensor immediately after it is computed, rather than trusting that the absence of a runtime error implies correctness.