← Back to the learning map
DEEP LEARNING / TURN GRADIENTS INTO PROGRESS

Week 3 — Optimization and Generalization

Week 2 asked whether useful gradients can reach the early layers. Now ask what happens after those gradients arrive: how does an optimizer move, and does the resulting model work on new data?

01Prediction
02Loss
03Gradients
04Update
BY THE END OF THIS WEEK
  • Distinguish the source of a gradient from the rule that turns it into an update.
  • Trace momentum, RMSProp, and Adam’s state through numerical examples.
  • Explain why AdamW, dropout, scheduling, and early stopping change different parts of training.
  • Design a controlled comparison using validation for selection and a reserved test set for final evaluation.
CONCEPT 01 · LECTURE SLIDES 2–4

A gradient is an estimate of what to change.

For a dataset of N observations, the empirical objective is the average of the individual losses. Full-batch gradient descent uses every observation for one update. Single-example SGD uses one observation; minibatch SGD averages a smaller group. In practice, “SGD” often refers to the minibatch version too.

L(θ) = (1/N) Σᵢ ℓᵢ(θ)
Full gradient: g = (1/N) Σᵢ ∇ℓᵢ(θ)
Batch estimate: gB = (1/|B|) Σᵢ∈B ∇ℓᵢ(θ)
MethodObservations per updateTrade-off
Full batchAll NExact gradient of this empirical objective at the current parameters, but potentially costly per update.
Single-example SGD1Frequent, inexpensive updates with high sampling variability.
Minibatch SGDA batch of BUses vectorized hardware efficiently while retaining sampling variability.

Under uniform sampling, a mean of per-example gradients is unbiased for the empirical mean gradient at a fixed parameter value. Larger batches generally reduce its sampling variance. This statement needs care with nonuniform sampling or operations whose outputs depend on the whole batch.

Noise changes the optimization path. It can help a run move through some flat or saddle-like regions, but can also slow convergence. Full-batch does not mean “correct about the population,” and noisy does not automatically mean “generalizes better.”

EXPLORE THE MECHANISM

The gradient changes when the batch changes.

For six observations, Lᵢ(θ) = ½(θ − yᵢ)², so gᵢ = θ − yᵢ. Every equally sized subset is equally likely in this illustration. We enumerate them all, without sampling with replacement.

y = -3g = 6.0000In this batch
y = -1g = 4.0000In this batch
y = 0g = 3.0000Outside this batch
y = 2g = 1.0000Outside this batch
y = 5g = -2.0000Outside this batch
y = 9g = -6.0000Outside this batch
Batch 1 of 15
Current batch gradient5.0000
Full-data gradient1.0000
Mean of all batch gradients1.0000
Batch-gradient standard deviation2.5298

The mean matches the full gradient; individual batches need not. At θ = 2 the full gradient is zero, yet small batches can still produce updates. This is noise in an estimator of the empirical gradient, not a guarantee of better generalization.

CONCEPT 02 · LECTURE SLIDES 5–6

A step size has to fit the geometry.

Backpropagation gives local sensitivity. Plain gradient descent multiplies that gradient by a learning rate and moves in the opposite direction. A very small rate can make progress hard to see; a large rate can oscillate or diverge.

θnext = θ − η∇L(θ)
Quadratic example: L(θ) = ½θᵀAθ, ∇L = Aθ
For positive-definite A: 0 < η < 2/λmax(A) gives convergence of plain gradient descent.

When one direction is much steeper than another, a single rate becomes a compromise. A rate small enough for the steep direction may make the flatter direction painfully slow. The quadratic below makes that conditioning visible without pretending to reproduce a complete neural-network loss surface.

EXPLORE THE MECHANISM

One bowl, four update rules.

L(x, y) = ½(x² + c·y²), starting at (2, 1). The same initial gradient goes into different optimizers. After they move, each evaluates the gradient at its own position.

-3-30033xy
Contours show equal loss. Hollow marker: common start · Filled marker: selected final point, when the path remains in view.
Selected optimizerSGD
Final x0.3774
Final y3.66e-5
Loss0.0712

For plain SGD on this bowl, convergence requires 0 < η < 2 / max(1, c). At c = 20, that upper bound is 0.1000. A common learning rate illustrates mechanisms; it is not a tuned optimizer benchmark or a generalization study.

CONCEPT 03 · LECTURE SLIDES 7–13

State turns the same gradient into a different update.

Momentum: remember direction

The velocity accumulates past gradients. Persistent signs reinforce each other; alternating signs can partially cancel. State can carry a run forward even when the current gradient becomes small.

vₜ = βvₜ₋₁ + gₜ
θₜ = θₜ₋₁ − ηvₜ

This unnormalized velocity convention matches the slides and ordinary PyTorch SGD momentum with zero dampening. Other presentations put a factor of (1 − β) on gₜ and use a correspondingly different scale.

RMSProp: remember scale

A running average of squared gradients rescales each coordinate. A large second-moment estimate makes the multiplier on that coordinate’s current gradient smaller. This concerns the effective multiplier, not a guarantee that its absolute update is smaller than every other coordinate’s.

sₜ = αsₜ₋₁ + (1 − α)gₜ²
θₜ = θₜ₋₁ − ηgₜ / (√sₜ + ε)

Adam: direction and scale, with bias correction

Adam tracks both first and second moments. Starting them at zero depresses early estimates. The correction compensates for that initialization under a stationary moment model; it is not a correction for biased training data.

mₜ = β₁mₜ₋₁ + (1 − β₁)gₜ
vₜ = β₂vₜ₋₁ + (1 − β₂)gₜ²
m̂ₜ = mₜ / (1 − β₁ᵗ), v̂ₜ = vₜ / (1 − β₂ᵗ)
θₜ = θₜ₋₁ − ηm̂ₜ / (√v̂ₜ + ε)

All squared operations and divisions above are coordinatewise. For a constant first gradient g, Adam’s first corrected estimates are g and g². Its resulting first step is approximately −η·sign(g) when g is not tiny relative to ε.

EXPLORE THE MECHANISM

Hold the gradients fixed. Inspect the optimizer’s memory.

Every method receives the selected gradient sequence, starts at θ = 2, and uses η = 0.1 with zero initial state. These supplied gradients isolate the update arithmetic; they are not recomputed from a loss surface.

tgₜDirection stateSquared-gradient stateUpdate Δθθ after update
1-3.0000-3.0000—0.30002.3000
2-2.0000-4.7000—0.47002.7700
3-1.0000-5.2300—0.52303.2930

Momentum uses vₜ = 0.9vₜ₋₁ + gₜ. RMSProp uses α = 0.9 with no momentum. Adam uses β₁ = 0.9, β₂ = 0.999 and bias correction. Both adaptive denominators use √state + 10⁻⁸, matching the PyTorch convention. The lecture’s RMSProp shorthand places ε inside the root; the rounded three-step trace is unchanged here.

Implementation references: PyTorch SGD, RMSprop, and the Adam paper.

CONCEPT 04 · LECTURE SLIDES 14–15, 21

Regularizers change different mechanisms.

Dropout, weight decay, and early stopping can all influence generalization, but they do different things. Use them to test a hypothesis about the training problem, rather than treating them as interchangeable switches.

MethodWhat changesWhat to check
DropoutActivations are randomly suppressed during training; inverted dropout rescales survivors.Use train() for training and eval() for evaluation. Dropout does not directly repair every optimization failure.
Weight decayParameter magnitudes shrink during updates.Check whether shrinkage is coupled to the gradient or applied separately. Consider which parameters should receive decay.
Early stoppingValidation behavior selects a training duration and checkpoint.Restore the selected weights and keep test data outside the stopping decision.

Why AdamW is not simply “Adam plus L2”

With the convention Ltotal = Ldata + (λ/2)‖w‖², the penalty contributes λw to the gradient. For plain SGD without momentum, its update equals a shrinkage term plus the ordinary data-gradient update. With Adam, that added gradient also changes the moment estimates and adaptive rescaling.

Plain SGD with this L2 penalty:
wnew = w − η(gdata + λw) = (1 − ηλ)w − ηgdata

AdamW:
wnew = (1 − ηλ)w + adaptive update computed from gdata

AdamW decouples shrinkage from the adaptive update. A learning-rate schedule also changes the amount of shrinkage per step through ηλ. Decay strengths therefore need tuning within the actual optimizer and schedule configuration.

EXPLORE THE MECHANISM

The same decay coefficient can produce different updates.

Start at w = 2 with zero optimizer state and η = 0.1. Compare a first Adam step on Ldata + (λ/2)w² with a first AdamW step using decoupled decay λ.

Gradient entering coupled Adam0.2000
w after Adam + L21.9000
w after AdamW1.9800
Coupled: g′ = gdata + λw; update using Adam(g′)
Decoupled: wnew = (1 − ηλ)w + Adam update from gdata

With zero data gradient, AdamW still shrinks w when λ > 0. With λ = 0 the two computations agree. The lesson uses λ/2 in the penalty so its derivative is λw; the slides’ λw² convention instead gives 2λw. Equal numeric settings do not imply equal regularization across algorithms.

Read the decoupled weight decay paper and PyTorch AdamW documentation.

CONCEPT 05 · LECTURE SLIDES 16–17

Plan how the response changes over time.

A schedule changes the learning rate used by later optimizer steps. Step decay encodes milestones, exponential decay reduces the rate proportionally, and cosine decay moves smoothly toward a lower endpoint. Warmup increases the rate during the beginning of a run before another schedule takes over.

Reduce-on-plateau instead responds to an observed metric. A plateau alone does not prove that a rate reduction is the right fix: inspect the data, objective, and training behavior too. Schedules do not replace the optimizer or calculate gradients.

EXPLORE THE MECHANISM

Choose how the learning rate changes over time.

These are explicit example schedules over 40 epochs, with peak rate 0.1. The plot shows the rate used for each epoch; it does not simulate training or guarantee that a schedule will work better.

00.050.112040Epoch
Step: drops after epochs 20 and 30 · Exponential: ×0.95 each epoch · Warmup: first 5 epochs.
Epoch1
Learning rate0.0200
ScheduleWarmup + cosine

Reduce-on-plateau differs: its drops depend on an observed metric, so an epoch-only plot cannot determine its shape. In PyTorch, call most schedulers after the optimizer’s update at the intended frequency; ReduceLROnPlateau receives the monitored metric.

API details and stepping order: PyTorch learning-rate scheduling.

CONCEPT 06 · LECTURE SLIDES 18–20, 23–24

Optimization and generalization ask different questions.

Optimization asks whether the training procedure improves its objective. Generalization asks whether performance transfers to relevant unseen data. A flexible model can lower training loss by fitting real structure, noise, or collection artifacts; the training curve alone cannot distinguish those explanations.

Observed patternPossible causesA useful next check
Both losses stay highInsufficient features or capacity, failed optimization, or a data/objective problemTry overfitting a tiny clean batch; inspect inputs, labels, gradients, and the output/loss pairing.
Training improves; validation worsensOverfitting or distribution mismatch; possibly inconsistent evaluationCheck the split and train/eval modes, then compare regularization or stopping choices using validation.
Loss is erratic or non-finiteUnstable updates, excessive step size, numerical problems, or pipeline issuesInspect finite values and gradient norms; change one factor at a time.
Progress is very slowA small learning rate, poor conditioning, or weak signalCompare a short controlled rate sweep and optimizer trajectories.
Training and validation both improveA useful fit on these development samplesConfirm with the reserved final evaluation and report sampling uncertainty.

Bias describes systematic error across possible training samples; variance describes sensitivity to which sample was used. Capacity can affect both, but a single pair of loss curves is not a direct measurement of that decomposition. A more expressive model can still perform poorly because its optimization failed.

CONCEPT 07 · LECTURE SLIDES 21–22

Early stopping selects a checkpoint.

At each epoch, evaluate a validation metric. Save a snapshot when it improves according to the chosen rule, reset the waiting counter, and otherwise increment the counter. Stop when patience is exhausted, then restore the selected snapshot.

A snapshot must not be a mutable reference that changes as training continues. In PyTorch, copy the state dictionary when retaining it in memory. Saving model state is sufficient for this inference comparison; exact training resumption requires more state.

EXPLORE THE MECHANISM

The last epoch is not necessarily the model to keep.

These curves are invented to illustrate checkpoint selection. Improvement means a strictly lower validation loss. Stop after the selected number of consecutive non-improving epochs and restore the best checkpoint seen so far.

00.511816Epoch
Solid: training · Dashed: validation · Filled marker: retained checkpoint · Hollow marker: last observed epoch.
Stop at epoch12
Restore epoch9
Retained validation loss0.4200
Test evaluations used for selection0

A short patience may stop before a later recovery. Tune patience using development data. The checkpoint here means model weights; exact training resumption also requires optimizer, scheduler, and relevant random-generator state.

Inspect only the epochs this run observed
EpochTraining lossValidation lossCheckpoint
10.86500.9000—
20.67920.7000—
30.53450.5600—
40.42180.5000—
50.33400.4800—
60.26570.4900—
70.21240.5000—
80.17100.4400—
90.13870.4200Retained
100.11350.4300—
110.09400.4400—
120.07870.4600—

Checkpoint handling: PyTorch’s saving and loading guide.

CONCEPT 08 · LECTURE SLIDES 25–27

Compare configured methods, not arbitrary defaults.

Keep comparableTune using validationReport
Task, split, input representation, architecture, loss, and initialization policyLearning rate and optimizer-specific state settingsTraining and validation trajectories
Seed policy, batch-order policy, stopping rules, and a declared resource budgetWeight decay and schedule choices, with an explicit tuning budgetEpochs, update counts or time, variation across seeds, and the final held-out result

The example below compares momentum SGD and AdamW, with two learning rates per method and two seeds. It uses the lecture’s 20 → 64 → 1 architecture with ReLU and dropout. Each seed starts from the same initial parameters and batch-order generator across configurations.

The data and split are fixed, and normalization statistics come only from training rows. Both methods start with zero weight decay so a later decay experiment can be explicit. Training and validation curves are measured in eval mode with dropout disabled, making their loss definitions comparable.

600 synthetic rows360 train / 120 validation / 120 test4 configurations × 2 seeds50-epoch maximum / patience 6

Choose a configuration by mean validation loss across the two seeds. The first seed is declared in advance for the final test report, so the script does not choose whichever seed happened to score best. This small study illustrates a procedure; it cannot establish a universal optimizer ranking.

RUN LOCALLY · PYTHON / PYTORCHCPU · NO DATA DOWNLOAD
python -m venv .venv
# Activate the environment for your operating system.
python -m pip install torch
python dl-week-3.py
Download the complete Python example ↓
Read the complete training and evaluation script
"""DL Week 3: Optimization and Generalization.

An independent teaching example accompanying the Algorithms II Week 4 material.
Run with: python -m pip install torch
          python dl-week-3.py

Creates synthetic data locally; writes learning curves, a comparison summary,
and an inference checkpoint in the current directory.
"""
import copy
import csv
import math
import statistics
import time

import torch
from torch import nn
from torch.utils.data import DataLoader, TensorDataset

torch.set_num_threads(1)
SEEDS = (17, 29)
MAX_EPOCHS = 50
PATIENCE = 6
BATCH_SIZE = 32
# Start without decay to study the optimizer/rate choices. Investigate
# regularization separately; equal decay numbers have different meanings
# for momentum SGD's coupled penalty and AdamW's decoupled shrinkage.
WEIGHT_DECAY = 0.0
CONFIGS = (
    ("momentum", 0.01), ("momentum", 0.05),
    ("adamw", 0.001), ("adamw", 0.01),
)

# The data generator and split are independent of each model's seed.
data_rng = torch.Generator().manual_seed(42)
X = torch.randn(600, 20, generator=data_rng)
signal = (1.4 * X[:, 0] - 0.9 * X[:, 1]
          + 0.6 * X[:, 2] * X[:, 3]
          + 0.5 * torch.randn(600, generator=data_rng))
y = (signal > 0).float().reshape(-1, 1)
indices = torch.randperm(len(X), generator=data_rng)
train_idx, val_idx, test_idx = indices[:360], indices[360:480], indices[480:]
X_train, y_train = X[train_idx], y[train_idx]
X_val, y_val = X[val_idx], y[val_idx]
X_test, y_test = X[test_idx], y[test_idx]
assert not set(train_idx.tolist()) & set(test_idx.tolist())
assert not set(val_idx.tolist()) & set(test_idx.tolist())

# Fit input statistics on training rows only.
train_mean = X_train.mean(dim=0)
train_std = X_train.std(dim=0, unbiased=False).clamp_min(1e-6)


class Classifier(nn.Module):
    def __init__(self):
        super().__init__()
        # Stored with the weights so inference accepts raw inputs.
        self.register_buffer("mean", train_mean.clone())
        self.register_buffer("std", train_std.clone())
        self.layers = nn.Sequential(
            nn.Linear(20, 64),
            nn.ReLU(),
            nn.Dropout(p=0.25),
            nn.Linear(64, 1),
        )

    def forward(self, features):
        return self.layers((features - self.mean) / self.std)


loss_fn = nn.BCEWithLogitsLoss()


def score(model, features, labels):
    model.eval()  # Disable dropout during both train-set and validation scoring.
    with torch.inference_mode():
        logits = model(features)
        loss = float(loss_fn(logits, labels))
        accuracy = float(((logits >= 0) == labels.bool()).float().mean())
    return loss, accuracy


curves = []


def fit_run(name, rate, seed):
    torch.manual_seed(seed)
    model = Classifier()
    # Separate generator: same initial batch order for a given seed/config.
    loader = DataLoader(
        TensorDataset(X_train, y_train), batch_size=BATCH_SIZE, shuffle=True,
        generator=torch.Generator().manual_seed(seed + 1000),
        num_workers=0,
    )
    if name == "momentum":
        optimizer = torch.optim.SGD(
            model.parameters(), lr=rate, momentum=0.9,
            weight_decay=WEIGHT_DECAY,
        )
    else:
        optimizer = torch.optim.AdamW(
            model.parameters(), lr=rate, weight_decay=WEIGHT_DECAY,
        )
    best_loss, best_epoch, waiting, best_state = math.inf, 0, 0, None
    started = time.perf_counter()
    for epoch in range(1, MAX_EPOCHS + 1):
        model.train()  # score() switches to eval, so reset every epoch.
        for features, labels in loader:
            optimizer.zero_grad(set_to_none=True)
            loss = loss_fn(model(features), labels)
            if not torch.isfinite(loss):
                raise RuntimeError("Non-finite training loss; inspect this run.")
            loss.backward()
            optimizer.step()

        # Both curves use eval mode and the same loss definition.
        train_loss, _ = score(model, X_train, y_train)
        val_loss, val_accuracy = score(model, X_val, y_val)
        if not math.isfinite(val_loss):
            raise RuntimeError("Non-finite validation loss.")
        curves.append({
            "optimizer": name, "lr": rate, "seed": seed, "epoch": epoch,
            "train_loss_eval_mode": train_loss,
            "validation_loss": val_loss, "validation_accuracy": val_accuracy,
        })
        if val_loss < best_loss:
            best_loss, best_epoch, waiting = val_loss, epoch, 0
            # A reference to state_dict() would keep changing during training.
            best_state = copy.deepcopy(model.state_dict())
        else:
            waiting += 1
            if waiting >= PATIENCE:
                break
    elapsed = time.perf_counter() - started
    assert best_state is not None
    model.load_state_dict(best_state)
    restored_loss, restored_accuracy = score(model, X_val, y_val)
    assert math.isclose(restored_loss, best_loss, abs_tol=1e-6)
    result = {
        "optimizer": name, "lr": rate, "seed": seed,
        "best_epoch": best_epoch, "epochs_run": epoch,
        "validation_loss": restored_loss,
        "validation_accuracy": restored_accuracy, "seconds": elapsed,
    }
    print(result)
    return model, result


runs = {}
summaries = []
for name, rate in CONFIGS:
    for seed in SEEDS:
        model, summary = fit_run(name, rate, seed)
        runs[(name, rate, seed)] = model
        summaries.append(summary)

# Choose the configuration using mean validation loss across the fixed seeds.
# Do not choose a favorable seed from its score.
mean_validation = {
    (name, rate): statistics.mean(
        row["validation_loss"] for row in summaries
        if row["optimizer"] == name and row["lr"] == rate
    )
    for name, rate in CONFIGS
}
selected = min(mean_validation, key=mean_validation.get)
print("Mean validation loss by configuration:", mean_validation)
print("Selected configuration:", selected)

# Prespecify the first seed's retained model for the single final test report.
# This is a small teaching study, not a robust ranking of optimizer families.
final_model = runs[(*selected, SEEDS[0])]
test_loss, test_accuracy = score(final_model, X_test, y_test)
print("Final held-out test loss / accuracy:", test_loss, test_accuracy)

for filename, rows in (
    ("dl-week-3-curves.csv", curves),
    ("dl-week-3-summary.csv", summaries),
):
    with open(filename, "w", newline="", encoding="utf-8") as handle:
        writer = csv.DictWriter(handle, fieldnames=list(rows[0]))
        writer.writeheader()
        writer.writerows(rows)

checkpoint = {
    "state_dict": final_model.state_dict(),
    "optimizer_name": selected[0], "learning_rate": selected[1],
    "seed": SEEDS[0], "feature_order": [f"x{i}" for i in range(20)],
}
torch.save(checkpoint, "dl-week-3.pt")
reloaded = Classifier()
reloaded.load_state_dict(
    torch.load("dl-week-3.pt", weights_only=True)["state_dict"]
)
final_model.eval()
reloaded.eval()
with torch.inference_mode():
    torch.testing.assert_close(final_model(X_val), reloaded(X_val))
print("Saved inference checkpoint; reloaded validation predictions match.")
print("Versions: PyTorch", torch.__version__)
print("Open dl-week-3-curves.csv in Excel; group by optimizer, lr, and seed.")
# For exact training resumption, also save optimizer/scheduler state, epoch,
# random-generator state, and any other state required by the input pipeline.

Inspect the outputs

  • dl-week-3-curves.csv: open in Excel, filter to one optimizer/rate/seed, and plot epoch against the two loss columns.
  • dl-week-3-summary.csv: compare retained validation performance, selected epochs, total epochs, and measured runtime.
  • dl-week-3.pt: model weights and fitted input statistics for inference. The script reloads it and checks that predictions match.
  • The final test loss and accuracy appear only after configuration selection. Keep that result out of subsequent tuning decisions.

Package versions and hardware can affect timing and exact numerical results. The script reports its PyTorch version. The examples and browser experiments are study companions to the supplied lecture, not measured results from its slides.

YOUR TURN / PREDICT, RUN, EXPLAIN

Make the mechanism visible.

  1. Enumerate the noise. Set θ = 2 in the batch demo. Explain why the full gradient is zero while individual minibatches need not be. Confirm that all equally likely batch estimates average to zero.
  2. Trace the lecture arithmetic. With gradients −3, −2, −1, η = 0.1, and β = 0.9, calculate the three momentum velocities and parameter values before checking the table. Repeat the squared-gradient trace for RMSProp with gradients 4, 2, 1.
  3. Find the stability boundary. Use SGD with curvature 20. Compare rates 0.08, 0.10, and 0.12. Explain the behavior of the steep coordinate from its multiplier, 1 − ηc.
  4. Separate two decay mechanisms. Set the data gradient to zero. Compare the first Adam + L2 and AdamW steps as λ changes, keeping the same rate. State which formula convention you used.
  5. Write a comparison before running it. Choose an experiment with a fixed split and a stated tuning budget. Use the CSV curves to report what happened, including a result that challenges your initial expectation.
EXPLAIN IT WITHOUT THE CODE

Week 3 interview questions

Try answering aloud before opening the explanation.

01What does the optimizer receive from backpropagation?

Gradients of the chosen objective with respect to parameters. The optimizer combines these with its learning rate, state, and update rules. Backpropagation itself does not choose the training strategy.

02Is every minibatch gradient an unbiased estimate?

For a fixed parameter value and uniformly sampled examples, the average of per-example gradients is an unbiased estimate of the empirical mean gradient. Different sampling or weighting schemes can change that property. Batch-dependent operations, such as BatchNorm, also complicate the simple per-example decomposition.

03Why does curvature affect the learning rate?

For a positive-definite quadratic with largest curvature λmax, plain gradient descent converges when 0 < η < 2/λmax. The steepest direction limits the step size, which can make progress slow in flatter directions. A nonconvex network is more complicated than this local illustration.

04How can identical current gradients give different momentum updates?

The stored velocity depends on previous gradients. With v = βv_previous + g, two runs with the same g but different v_previous produce different updates. Identical gradients do not imply identical optimizer state.

05How do RMSProp and Adam differ?

RMSProp rescales a coordinate using a moving average of squared gradients. Adam also maintains a moving average of gradients and corrects the zero-initialization bias in its first and second moment estimates. Exact defaults and options matter.

06Why does Adam need bias correction?

Starting its moving averages at zero reduces their early magnitude. Under a stationary moment model, dividing by 1 − β^t corrects that initialization bias. It does not remove dataset bias or guarantee a good update.

07Is AdamW simply Adam with an L2 term added to the loss?

No. A loss penalty contributes to the gradient and enters Adam’s adaptive moment calculations. AdamW applies parameter shrinkage separately. For plain SGD without momentum, a suitably scaled L2 penalty and decay can give the same update; that equivalence does not carry over unchanged to adaptive methods.

08Does a learning-rate schedule calculate gradients?

No. It changes the rate used by future optimizer steps. Some schedules depend on a training-time index; reduce-on-plateau depends on a monitored metric. The optimizer and gradient calculation still have their own jobs.

09Do low training loss and high validation loss prove overfitting?

They suggest a generalization problem, but distribution mismatch, a flawed split, or mismatched evaluation behavior may also contribute. Inspect the pipeline and compare controlled changes before choosing a remedy.

10Which model should early stopping return?

The checkpoint with the best validation behavior according to the specified improvement rule, not necessarily the final logged epoch. Validation has selected training duration. The final test set must stay outside that selection.

11Does model.eval() disable autograd?

No. It changes modules such as Dropout and BatchNorm into evaluation behavior. Use no_grad() or inference_mode() separately when gradients are unnecessary.

12What makes an optimizer comparison fair?

Use a common task, split, architecture, loss, and initialization policy; give each method an appropriate validation-based tuning budget. Report trajectories, cost, stopping rules, and variation across seeds. Evaluate the chosen procedure on held-out test data after selection.

PEOPLE BEHIND THE IDEAS

Research connections

NEXT / FROM GENERIC VECTORS TO SPATIAL STRUCTURE

The next week introduces locality, shared patterns, and convolutional neural networks, matching the lecture’s bridge to course Week 5.

Preview Week 4: Convolutional Neural Networks →
Back to the learning map ↑