eriklindernoren/ML-From-Scratch · error · NotImplementedError
NotImplementedError()
Error message
NotImplementedError()
What it means
This error is raised by the base Layer class's forward_pass method in mlfromscratch. It is an abstract-method stub: Layer is designed to be subclassed, and every concrete layer (Dense, Activation, etc.) must override forward_pass. Calling it on the base class (or on a custom layer that forgot to implement it) means no forward computation exists for that layer.
Source
Thrown at mlfromscratch/deep_learning/layers.py:27
class Layer(object):
def set_input_shape(self, shape):
""" Sets the shape that the layer expects of the input in the forward
pass method """
self.input_shape = shape
def layer_name(self):
""" The name of the layer. Used in model summary. """
return self.__class__.__name__
def parameters(self):
""" The number of trainable parameters used by the layer """
return 0
def forward_pass(self, X, training):
""" Propogates the signal forward in the network """
raise NotImplementedError()
def backward_pass(self, accum_grad):
""" Propogates the accumulated gradient backwards in the network.
If the has trainable weights then these weights are also tuned in this method.
As input (accum_grad) it receives the gradient with respect to the output of the layer and
returns the gradient with respect to the output of the previous layer. """
raise NotImplementedError()
def output_shape(self):
""" The shape of the output produced by forward_pass """
raise NotImplementedError()
class Dense(Layer):
"""A fully-connected NN layer.
Parameters:
-----------
n_units: intView on GitHub (pinned to a2806c6732)
Solutions
- Implement forward_pass(self, X, training) in your custom Layer subclass returning the layer's output for input X
- If you wanted a pass-through layer, subclass Layer and make forward_pass return X unchanged
- Don't instantiate the abstract Layer directly; use a concrete layer such as Dense
- Check for typos in the method name (forward_pass, not forward) so the override actually replaces the stub
Example fix
// before
class MyLayer(Layer):
def forward(self, X): # wrong name -> base stub raises
return X
// after
class MyLayer(Layer):
def forward_pass(self, X, training=True):
return X # custom forward computation
def backward_pass(self, accum_grad):
return accum_grad
def output_shape(self):
return self.input_shape Defensive patterns
Strategy: type-guard
Validate before calling
def layer_is_complete(layer):
return all(callable(getattr(layer, m, None)) and not _is_base_stub(layer, m)
for m in ('forward_pass', 'backward_pass', 'output_shape'))
def _is_base_stub(layer, method):
# the stubs only exist on the base Layer class
import mlfromscratch.deep_learning.layers as L
return getattr(type(layer), method, None) is getattr(L.Layer, method, None)
for layer in model.layers:
assert layer_is_complete(layer), f'{type(layer).__name__} is missing required Layer methods' Type guard
from mlfromscratch.deep_learning.layers import Layer
def is_fully_implemented_layer(obj) -> bool:
if not isinstance(obj, Layer):
return False
for m in ('forward_pass', 'backward_pass', 'output_shape'):
fn = getattr(type(obj), m, None)
if fn is None or fn is getattr(Layer, m, None):
return False
return True Prevention
- Never instantiate the abstract Layer directly; always use or derive a concrete subclass
- When creating custom layers, implement all three methods: forward_pass(X, training), backward_pass(accum_grad), output_shape()
- Run a one-layer smoke test (single forward + backward on tiny data) before wiring a custom layer into a full model
- Pin the library version so method signatures like the 'training' argument don't change under you
When it happens
Trigger: Instantiating mlfromscratch.deep_learning.layers.Layer directly and passing it to a NeuralNetwork, or writing a custom layer subclass that does not define forward_pass(X, training) and running model.fit/predict, which invokes layer.forward_pass during the network's forward propagation.
Common situations: Developers creating custom layers who copy a subset of the API (e.g. implement only backward_pass), using the base Layer as a placeholder/no-op layer, or upgrading versions where the method signature changed to require the extra 'training' argument so an old override with a different name/signature no longer overrides it.
Related errors
AI-assisted analysis of eriklindernoren/ML-From-Scratch@a2806c6732 (2026-08-27).
Data as JSON: /api/errors/f72e3d6547c4426b.
Report an issue: GitHub.