We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Classifiers from Scratch step 5 of 5
Train Multiclass Classifier with Early Stopping
Implement train_with_early_stopping: train a linear classifier on the training set, use validation loss to choose a checkpoint, and return the best saved weights. Training and validation have different jobs: only training examples contribute to gradients.
Inputs and output
- x_train: (N_train, d), training features.
- y_train: (N_train,), integer-valued labels in [0, C), delivered as floats.
- x_val: (N_val, d), validation features.
- y_val: (N_val,), validation labels with the same class range.
- w0: (d, C), the supplied initial weights.
- lr: a finite, nonnegative learning rate.
- max_epochs: a nonnegative integer, the maximum number of full-batch updates.
- patience: a positive integer, the allowed number of consecutive updates without a new best validation loss.
Both datasets are nonempty, d is positive, and C is at least two. Shapes are consistent. Floating-point tensors are finite and share a dtype and device. Cast labels to integers when indexing. There is no separate bias; a supplied column of ones can act as one.
Return the selected weight matrix of shape (d, C), preserving dtype and device. Leave all inputs unchanged. If max_epochs=0, return w0's values. Otherwise, select among the weights after updates; do not evaluate w0 as an initial checkpoint.
One training update
Start from w=w0. At each epoch, compute class scores and probabilities from the current weights, then take a full-batch gradient step:
logits = x_train @ w
probs = softmax(logits, axis=-1)
grad = x_train.T @ (probs - one_hot(y_train, C)) / N_train
w = w - lr * grad
This is the gradient of mean training cross-entropy. Average over training examples once, not over classes or features. Use the updated weights on the next epoch, without shuffling, mini-batches, regularization or random initialization.
Validation loss
Immediately after each update, evaluate mean cross-entropy on the validation set using those updated weights. For each row of validation logits, compute stable log probabilities directly:
scores = x_val @ w
shifted = scores - row_max(scores)
log_probs = shifted - log(row_sum(exp(shifted)))
val_loss = -sum(log_probs[i, y_val[i]] for i in range(N_val)) / N_val
Keep the reduced axis when subtracting row maxima and row sums. Use the same subtract-max approach for training softmax. Do not add an epsilon to class probabilities before taking a log: that changes the loss and can make distinct large losses appear equal.
Saving and stopping
Initialize best_loss to infinity and no_improve to zero. After each validation:
- If val_loss is strictly less than best_loss, save these weights, record the new loss, and reset no_improve to zero.
- Otherwise, increment no_improve. Stop when it reaches patience.
Compare against the best loss so far, not just the preceding epoch's loss. A tie is not an improvement, and there is no minimum-improvement tolerance. The first updated checkpoint becomes the initial best. Save an independent copy where arrays are mutable, so later updates cannot overwrite it.
Stop after at most max_epochs updates. Whether patience or the epoch limit ends training, return the saved best weights rather than the latest weights. With lr=0, the weights stay unchanged: the first validation sets the best loss, and the next patience validations trigger stopping if the epoch limit allows them.
Example of the stopping rule
Suppose losses after successive updates are 0.8, 0.6, 0.6, 0.7 and patience=2. Update two is best. Update three ties the best, so the counter becomes one. Update four is worse, so the counter becomes two. Stop and return the weights from update two. These losses illustrate the rule independently of the training data.
Understand the ideas behind this exercise. The Problem tab contains the exact implementation requirements.
Set the learning rate and control gradient size
A learning-rate schedule changes the step size during training. Check its exact indexing: a warmup may start at zero or at a first positive fraction. Test the initial value, the warmup boundary, the decay endpoint, and any later steps. The schedule's name alone does not specify those choices.
Global norm clipping scales all gradients by the same factor:
$$\min\left(1,\frac{c}{\|g\|}\right),$$
where g represents all parameter gradients together and c is the norm limit.
For scalar gradients 3 and 4, the global norm is 5. Clipping to 2.5
multiplies both by 0.5, giving [1.5, 2]. Clipping each tensor separately can
change their relative direction. Handle zero norm without dividing by zero.
Keep a smoothed copy of the parameters
An exponential moving average (EMA) updates a separate parameter copy:
$$\bar\theta_t=\beta\bar\theta_{t-1}+(1-\beta)\theta_t.$$
For old average 2, new parameter 4, and beta = 0.9, the new average is
0.9*2 + 0.1*4 = 2.2. A larger beta retains more of the past. Initialization and
whether EMA runs before or after the optimizer step affect the result.
Use validation to decide when to stop
Evaluate using the intended inference behavior without changing model parameters. For mean per-example loss, weight each batch's contribution by its example count. Giving unequal batches equal weight changes the overall mean.
Early stopping monitors a validation metric and stops after a specified number of observations without improvement. Define ties, the minimum improvement, and patience precisely. Save an independent copy of the best parameters: the final step may not be the best one. Keep the test set out of the stopping decision so it remains an independent evaluation.
Your code, saved here
Sign in to access your accepted solutions and saved draft history. You can keep reading the lesson without an account.
Sign in to your accountStuck?
JAX reference solution
Sign in to track your attempts toward unlocking the reference solution.