C.W.K.
Stream
Lesson 07 of 08 · published

The Forward Pass

~22 min · forward, shapes, autograd

Level 0Curious
0 XP0/73 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

What forward actually means

The forward pass is the act of taking input data x through every layer in order and producing output y (logits, probabilities, embeddings — whatever the head returns). On the way, PyTorch records every operation in a computation graph so backward can compute gradients later. This is the only thing your forward() method has to do correctly.

forward() is called automatically when you do model(x). Never call model.forward(x) directly — you would skip the hooks PyTorch uses for things like normalization mode, gradient tracking, and DDP synchronization.

Tip: If you write a forward(), write the shape of every intermediate tensor next to its line. Future-you (and the next person debugging your model) will thank you.

Train mode vs eval mode

Some layers behave differently in training and evaluation: dropout (active in train, identity in eval), batch normalization (uses batch statistics in train, running statistics in eval). Switch with model.train() and model.eval(). Forgetting eval() at validation is a famous bug that produces noisy metrics; we will see it again in the training-loop track.

Stop the gradient when you do not need it

For inference and for any "frozen" backbone in transfer learning, wrap forward calls in torch.no_grad() (or torch.inference_mode() for the latest, fastest path). PyTorch will skip building the computation graph and free memory you would otherwise tie up.

Principle: Three things to remember about forward: call the model, not .forward(); switch to eval() for inference; and use inference_mode() when you do not need gradients.

Code

A complete, shape-annotated forward pass·python
import torch, torch.nn as nn

class TinyVisionMLP(nn.Module):
    def __init__(self):
        super().__init__()
        self.flatten = nn.Flatten()
        self.fc1 = nn.Linear(28 * 28, 256)
        self.act = nn.ReLU()
        self.dropout = nn.Dropout(p=0.1)
        self.fc2 = nn.Linear(256, 10)
    def forward(self, x):              # x:    [B, 1, 28, 28]
        x = self.flatten(x)            # x:    [B, 784]
        x = self.act(self.fc1(x))      # x:    [B, 256]
        x = self.dropout(x)            # x:    [B, 256]
        return self.fc2(x)             # logits: [B, 10]

model = TinyVisionMLP()
batch = torch.randn(32, 1, 28, 28)

model.train()
logits_train = model(batch)

model.eval()
with torch.inference_mode():
    logits_eval = model(batch)

print(logits_train.shape, logits_eval.shape)

External links

Exercise

Write a forward pass for a 3-layer MLP that classifies CIFAR-10 (input shape [B, 3, 32, 32], output shape [B, 10]). Annotate every intermediate tensor's shape in a comment. Switch the model between train and eval and verify dropout behaves differently in each mode.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.