The problem
When a model predicts real numbers (a price, a reward, the brightness of a pixel), the standard loss is the MSE (mean squared error): for every prediction, take the error, square it, and average all the squares. It is the negative log-likelihood of Gaussian noise (see the theory page), and its gradient is the simplest one in this section.
The loss
For predictions and targets of the same shape, with numbers in total:
where:
- ("y hat") is the prediction
pred, and is its number ; - is the
target, and is its number ; - is the error on number , and runs over all numbers, whatever the shape.
Squaring does two things: every error becomes positive, so errors in opposite directions cannot cancel out; and large errors count much more than small ones (an error of 2 costs 4, an error of 10 costs 100).
Example.
pred = [1.5, 2, 2],target = [1, 2, 3].
- Errors: , , .
- Squares: , , .
- Average: .
The gradient
The gradient says, for every prediction, how the loss changes when that prediction moves. Only one term of the sum contains , and the derivative of is . With the in front:
where the symbols are the same as above.
Example. Same numbers: errors , , so the gradient is .
Training moves against the gradient: the first prediction goes down (it was too high), the second stays (it was right), the third goes up (it was too low).
What to implement
mse(pred, target): the loss, a single number (a Pythonfloator a 0-d array).mse_backward(pred, target): the gradient, an array shaped likepred.
Requirements
- Any shape: the mean is over all numbers, not over one axis.
- If the shapes differ, raise a
ValueError. Otherwise broadcasting hides a classic bug:predof shape minustargetof shape is an table, and the loss is wrong without any error. For example,[[1], [2]] - [1, 2]is[[0, -1], [1, 0]], whose MSE is , although the predictions are perfect. - No Python loops.
Hint
pred.size is the total number of elements , whatever the shape.