CodeBlanks Logo Icon CodeBlanks

Loss and optimizer

Use CrossEntropy loss and SGD optimizer.

Loss and optimiser

For two-class classification we use CrossEntropyLoss (2 logits). As the optimiser, Adam is fast and not very sensitive to tuning on small CNNs:

kayip_fn = nn.CrossEntropyLoss()
opt = torch.optim.Adam(model.parameters(), lr=0.01)
with torch.no_grad():
    print(kayip_fn(model(X_train), y_train).item())   # before training ≈ log(2) = 0.69

A loss around log(number of classes) before training is a sanity check showing the model still predicts at random and the setup is right.

The overfit-one-batch test

The fastest way to verify that a model can learn is making it memorise a single small batch. If the loss doesn't approach zero, there is a bug in the code (wrong labels, a missing zero_grad, a wrong loss):

xb, yb = X_train[:16], y_train[:16]
for _ in range(100):
    opt.zero_grad()
    kayip = kayip_fn(model(xb), yb)
    kayip.backward()
    opt.step()
print(kayip.item() < 0.05)   # True expected

This test takes a few seconds and prevents hours of wasted training.

Practice Sanity checks

Print that the loss before training is close to log(2) (abs(kayip - 0.693) < 0.1). Then train 100 steps on the first 16 examples and print that the loss is below 0.05.

Starter code

model.py
import torch
from torch import nn

torch.manual_seed(0)
def veri(n):
    X = torch.rand(n, 1, 16, 16) * 0.3
    y = torch.randint(0, 2, (n,))
    for k in range(n):
        if y[k] == 0:
            X[k, 0, 7:9, :] += 1.0
        else:
            X[k, 0, :, 7:9] += 1.0
    return X, y

X_train, y_train = veri(256)
X_test, y_test = veri(64)

model = nn.Sequential(
    nn.Conv2d(1, 8, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
    nn.Conv2d(8, 16, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
    nn.Flatten(), nn.Linear(16 * 4 * 4, 2))
kayip_fn = nn.CrossEntropyLoss()
opt = torch.optim.Adam(model.parameters(), lr=0.01)

# buraya yaz

Sample solution

model.py
import torch
from torch import nn

torch.manual_seed(0)
def veri(n):
    X = torch.rand(n, 1, 16, 16) * 0.3
    y = torch.randint(0, 2, (n,))
    for k in range(n):
        if y[k] == 0:
            X[k, 0, 7:9, :] += 1.0
        else:
            X[k, 0, :, 7:9] += 1.0
    return X, y

X_train, y_train = veri(256)
X_test, y_test = veri(64)

model = nn.Sequential(
    nn.Conv2d(1, 8, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
    nn.Conv2d(8, 16, 3, padding=1), nn.ReLU(), nn.MaxPool2d(2),
    nn.Flatten(), nn.Linear(16 * 4 * 4, 2))
kayip_fn = nn.CrossEntropyLoss()
opt = torch.optim.Adam(model.parameters(), lr=0.01)

with torch.no_grad():
    ilk = kayip_fn(model(X_train), y_train).item()
print(abs(ilk - 0.693) < 0.1)
xb, yb = X_train[:16], y_train[:16]
for _ in range(100):
    opt.zero_grad()
    kayip = kayip_fn(model(xb), yb)
    kayip.backward()
    opt.step()
print(kayip.item() < 0.05)

Expected output

True
True

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Roughly what should the loss be before training in a 10-class problem?

  • 10
  • 2.3 (log 10) Correct answer
  • 0
  • 0.69

Explanation: Random prediction gives each class probability 1/10: -log(0.1) ≈ 2.30.

2 Set up the Adam optimiser.

Question
opt = torch.optim.____(model.parameters(), lr=0.01)
Answer
opt = torch.optim.Adam(model.parameters(), lr=0.01)

Explanation: Adam uses adaptive learning rates.

3 Match the checks.

Term Meaning
initial loss ≈ log(K) Setup is right
overfitting a single batch The model can learn
loss not decreasing A bug in the code
Adam Adaptive optimiser

All lessons in Advanced