A PyTorch implementation of Deep Echo State Networks (DeepESN) and related reservoir computing models, designed for efficient sequence representation with a fixed recurrent backbone and a linear ridge readout. Ref. accepted paper: C. Baccheschi and P. Dazzi, “An Analysis of Untrained Deep Reservoir Networks for Audio Surveillance,” in Proceedings of the IEEE International Conference on Advanced Video and Signal-Based Surveillance (AVSS), Lecce(Italy), 2026, forthcoming.
This repository focuses on the following idea:
- use a reservoir backbone as a nonlinear temporal feature extractor;
- keep the recurrent layers untrained;
- train only a linear readout, making the approach particularly attractive for large-scale settings where full backpropagation through time may be expensive.
The core implementation is provided in deepesn.py.
This repository implements:
- single-layer ESN
- deep ESN
- bidirectional DeepESN
- ridge-based linear readout
- support for sequence-to-sequence and sequence-to-one/sequence-to-vector tasks
- support for (mean)pooled or last-state outputs
- support for large datasets through a readout fitting procedure based on sufficient statistics
.
├── deepesn.py # main DeepESN model
├── reservoir.py # reservoir cell and bidirectional wrapper
├── readout.py # linear readout + ridge fitting utilities
└── ...
The main constructor is:
model = DeepESN(
input_size=your_input,
units=100,
num_layers=2,
input_scaling=1.0,
bias_scaling=1.0,
spectral_radius=0.9,
leaky=1.0,
bias_scaling_hidden=1.0,
spectral_radius_hidden=0.9,
input_scaling_hidden=1.0,
leaky_hidden=1.0,
readout_regularizer=[0,1e-4,1e-3,1e-2,1,10,100], # they will be used in sequence to find the best regularizer for the readout !
type="bi", # bidirectional or nobi
score="accuracy",
last_layer=False,
sequences=False, # extracting the last state returning 2D tensor
mean=False,
)
reservoir_states, all_states = model(x)
For multiclassification, remember to give to the readout the onehot representation. Conversely, for the binary case, just encode in {+1, -1}
val_error, fit_time_s, fit_time_ms = model.fit(
train=reservoir_statest_train,
labels=labels,
num_targets=num_classes,
validation_data=(reservoir_statest_val, val_labels),
verbose=True,
device=cpu|cuda
)
predictions = model.predict(test_data)
-Prof. Claudio Gallicchio — original DeepESN formulation and deep reservoir computing research
-Dr. Corrado Baccheschi — PyTorch implementation and extensions
If you use this code entirely or partially please cite the following:
Gallicchio, Claudio, Alessio Micheli, and Luca Pedrelli. "Deep reservoir computing: A critical experimental analysis." Neurocomputing 268 (2017): 87-99.
and
@inproceedings{baccheschidazzi2026,
author = {Corrado Baccheschi and Patrizio Dazzi},
title = {An Analysis of Untrained Deep Reservoir Networks for Audio Surveillance},
booktitle = {Proceedings of the IEEE International Conference on Advanced Visual and Signal-Based Systems (AVSS)},
year = {2026},
note = {accepted, forthcoming}
}