eriklindernoren/ML-From-Scratch · error · NotImplementedError
NotImplementedError()
Error message
NotImplementedError()
What it means
Loss.gradient is an abstract method on the Loss base class in mlfromscratch/deep_learning/loss_functions.py and raises NotImplementedError. During training, NeuralNetwork.backpropagate calls loss.gradient(y, y_pred) to get dL/dy_pred; if the loss object is the base Loss (or a custom subclass that didn't implement gradient), this stub raises. Note loss() on the base class returns NotImplementedError instead of raising — a related latent bug — but gradient() is the hard failure.
Source
Thrown at mlfromscratch/deep_learning/loss_functions.py:11
from __future__ import division
import numpy as np
from mlfromscratch.utils import accuracy_score
from mlfromscratch.deep_learning.activation_functions import Sigmoid
class Loss(object):
def loss(self, y_true, y_pred):
return NotImplementedError()
def gradient(self, y, y_pred):
raise NotImplementedError()
def acc(self, y, y_pred):
return 0
class SquareLoss(Loss):
def __init__(self): pass
def loss(self, y, y_pred):
return 0.5 * np.power((y - y_pred), 2)
def gradient(self, y, y_pred):
return -(y - y_pred)
class CrossEntropy(Loss):
def __init__(self): pass
def loss(self, y, p):
# Avoid division by zeroView on GitHub (pinned to a2806c6732)
Solutions
- Implement gradient(self, y, y_pred) in your Loss subclass returning the derivative of the loss w.r.t. y_pred (e.g. 0.5 * (y_pred - y) for SquareLoss in this library)
- Use a built-in concrete loss (SquareLoss, CrossEntropy, etc.) instead of the base Loss class
- Match the method exactly: def gradient(self, y, y_pred): — two arguments besides self
- If prototyping, subclass an existing loss like SquareLoss and override only what changes
Example fix
// before
class MyLoss(Loss):
def loss(self, y, y_pred):
return np.mean((y - y_pred) ** 2)
# gradient missing -> NotImplementedError on first fit() backward pass
// after
class MyLoss(Loss):
def loss(self, y, y_pred):
return np.mean((y - y_pred) ** 2)
def gradient(self, y, y_pred):
return 2 * (y_pred - y) / y.shape[0] # dL/dy_pred
def acc(self, y, y_pred):
return 0 Defensive patterns
Strategy: validation
Validate before calling
from mlfromscratch.deep_learning.loss_functions import Loss
fn = getattr(type(model.loss_function), 'gradient', None)
assert fn is not None and fn is not Loss.gradient, (
'Loss object does not implement gradient(y, y_pred); '
'use a built-in loss or implement gradient in your subclass') Type guard
from mlfromscratch.deep_learning.loss_functions import Loss
def is_complete_loss(obj) -> bool:
if not isinstance(obj, Loss):
return False
for m in ('loss', 'gradient', 'acc'):
fn = getattr(type(obj), m, None)
if fn is None or fn is getattr(Loss, m, None):
return False
return True Try / catch
try:
model.fit(X_train, y_train, n_epochs=10)
except NotImplementedError as e:
raise TypeError(
f'Loss {type(model.loss_function).__name__} is incomplete; '
'implement gradient(y, y_pred) or use SquareLoss/CrossEntropy') from e Prevention
- Use built-in losses (SquareLoss, CrossEntropy) unless you truly need a custom one
- A custom loss must implement loss, gradient, AND acc — gradient is what backprop consumes
- Return the gradient w.r.t. y_pred, matching the shape of y_pred
- Unit-test a new loss with model.fit on a few dummy samples before a full training run
When it happens
Trigger: Instantiating mlfromscratch.deep_learning.loss_functions.Loss and passing it as NeuralNetwork(loss=...), then calling fit; or defining a custom Loss subclass that implements loss/acc but not gradient(y, y_pred). The error occurs on the first backward pass of model.fit.
Common situations: Writing a custom loss (e.g. weighted cross-entropy) and forgetting the gradient method; assuming the library computes numerical gradients from loss() (it doesn't — gradients are analytic and must be supplied); version upgrades where the gradient method signature changed.
Related errors
AI-assisted analysis of eriklindernoren/ML-From-Scratch@a2806c6732 (2026-08-27).
Data as JSON: /api/errors/ccfee711ebbc8487.
Report an issue: GitHub.