ReservoirPy: Echo State Networks Without Writing the Reservoir by Hand
A simple and flexible code for Reservoir Computing architectures like Echo State Networks
At a glance
- What is it?
- ReservoirPy packages reservoir computing into composable Python nodes, with offline and online training, feedback loops, and an optional hyperopt-driven search. It fits engineers who want an ESN baseline quickly, not those who need GPU-scale training or a maintained 1.0 API.
- Who is it for?
- Adopt ReservoirPy if you are prototyping Echo State Networks on time series or classification and want the reservoir, readout and training rule expressed as composable Python objects rather than hand-written matrix code. Do not adopt it if you need a long-term stable API surface, since the release history shows both a 0.3.x line and a 0.4.x line, or if your workload depends on GPU-scale training, which the supplied material does not describe.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What ReservoirPy Actually Removes From Your Code
An Echo State Network has two parts that behave very differently. The reservoir is a large recurrent layer whose weights are set once and never trained. The readout is a small linear layer fitted by regression. Writing this by hand means building a sparse random matrix, normalising it to a target spectral radius, stepping the state update for every timestep, discarding a warmup window, then solving a ridge regression on the collected states. Each of those steps is a place to get the scaling wrong.
ReservoirPy's README describes the library as "simple and flexible code for Reservoir Computing architectures like Echo State Networks". The flexibility claim is the more specific one. The feature list names multi-reservoir architectures, deep reservoirs, multiple readouts, feedback loops and both offline and online training. That is a wider scope than a single ESN class. It is a small node framework where reservoirs, readouts and training rules are separate objects you wire together.
The audience follows from that. If you are an engineer who wants one ESN on one series, the README example is roughly six lines. If you are researching architectures, the same primitives let you stack reservoirs and attach several readouts without rewriting the state update each time.
Nodes, Connections and the Spectral Radius Contract
The training model in the README example is the clearest view of the data flow. An ESN is constructed with units, sr (spectral radius), lr (leak rate) and ridge (the ridge regression coefficient). Fitting takes the training inputs, the training targets and a warmup count: esn.fit(x_train, y_train, warmup=100). The warmup parameter tells the network how many initial timesteps to run before it starts collecting states for the regression, which is the standard way to wash out the influence of the zero initial state.
After fit, esn.run(x_test) produces predictions, and the README evaluates them with rmse and rsquare from reservoirpy.observables. So the split is explicit: run generates states and readout outputs, fit solves for the readout weights. The reservoir itself is never trained by gradient descent in this path.
The feature list adds mechanisms that change that picture. Feedback connections route outputs back into the reservoir, which matters for generative or closed-loop tasks. Online training and advanced rules such as Intrinsic Plasticity, Local Plasticity and NVAR modify the reservoir or the readout during the run rather than only at fit time. Parallelization across sequences is listed as a feature, and the documentation points to custom weight matrices for sparse matrix computations. The README does not state the exact sparse format used, so if memory layout is your constraint, read the custom weight matrices section of the docs before assuming a particular backend.
Installation and the First Working Script
The README gives one installation command: pip install reservoirpy. It then notes that a more complete installation, including hyperparameter search, is documented in the advanced install guide on ReadTheDocs. That distinction matters because the hyperparameter tooling depends on hyperopt, which the README names as the library behind the graphical exploration tools. If you install only the base package and then reach for the hyperparameter search, expect to install the extra dependencies yourself.
The worked example is a Mackey-Glass forecasting task. The dataset comes from reservoirpy.datasets: X = mackey_glass(n_timesteps=2000), described as a (2000, 1)-shaped array. The helper to_forecasting(X, test_size=0.2) shifts X to build targets and performs the train/test split in one call. The model is ESN(units=100, sr=1.25, lr=0.3, ridge=1e-5), fitted with warmup=100.
The README prints a result for this configuration: an RMSE of 0.0020282 and an R^2 score of 0.99992. Treat that as the README's own reported figure on a synthetic benchmark, not as a general accuracy claim. Mackey-Glass at this horizon is a task reservoir computing handles well, and the number says more about the benchmark than about your data.
Where the Abstraction Costs You
The node abstraction is the main limitation. When you compose reservoirs and readouts as objects, the state update and the regression solve happen behind the interface. That is fine until you need to inspect or replace part of it. Debugging a diverging reservoir means reasoning about what each node did to the state, and the README does not describe a diagnostic or tracing facility for that.
The hyperparameter story is similarly split. The README advertises graphical tools to explore hyperparameters with hyperopt, but it does not describe the search space, the objective interface, or how a search interacts with the warmup parameter. A hyperparameter search over sr, lr and ridge is only as meaningful as the validation split you give it, and the README's example uses a single train/test split with no validation set at all. Running the documented example as-is gives you no basis for choosing between two configurations.
The wrong-tool case is scale. Nothing in the supplied material describes GPU execution or distributed training. The Jax backend tutorial exists in the tutorial list, which suggests an alternative compute path is available, but the README excerpt does not state what it accelerates or what its constraints are. If your requirement is training a recurrent network end to end with gradients, this is a different class of tool.
How It Compares to a Gradient-Trained RNN
The closest alternative in practice is a standard recurrent network built in PyTorch or TensorFlow, trained by backpropagation through time. The difference is not speed, it is what gets learned. In a gradient-trained RNN, the recurrent weights are the parameters, and training adjusts them. In ReservoirPy, the recurrent weights are fixed at construction from sr and the reservoir size, and only the readout is fitted, by ridge regression in the documented example.
That changes the cost profile in a way that matters for adoption. Fitting a readout is a linear solve, so it is fast and repeatable, and you can refit on new data without retraining a recurrent network. The trade-off is capacity: you are betting that a fixed random reservoir plus a linear readout can represent your function. The README's own benchmark, Mackey-Glass, is a case where that bet pays off, which is exactly why it is the demo.
ReservoirPy also lists a ScikitLearnNode for interfacing with scikit-learn models. That is a different kind of alternative: instead of replacing the library, you use a scikit-learn estimator as a component inside a reservoir pipeline. For teams already standardised on scikit-learn pipelines and cross-validation utilities, that integration may be more useful than the built-in hyperopt path.
Release Lines, Maintenance and the MIT Licence
The release history in the supplied material shows two lines moving in parallel: v0.4.2 on 2026-06-08, and v0.3.16 three days earlier on 2026-06-05, with v0.3.15 before that in 2025-09-24. A patch release on an older minor line alongside a newer one usually means the older line is still receiving fixes, but it also means the API between 0.3.x and 0.4.x is not assumed to be identical. The README does not include a changelog section; the changelog link is commented out in the source, pointing readers to the GitHub releases page instead.
For an adopter, the practical consequence is pinning. Specify the version you validated in your requirements file rather than accepting whatever the resolver picks, and read the release notes for the line you pin. The repository is not archived and the last push is dated 2026-09-01, so the project is active.
The licence is MIT, which is permissive and places few conditions on redistribution or modification beyond preserving the licence notice. That is a statement about the licence text, not legal advice; if you are shipping the library inside a product, have your own counsel confirm the obligations that apply to you.
Adoption Checklist Before You Depend On It
Start by reproducing the README's Mackey-Glass script unchanged. If the printed RMSE and R^2 differ substantially from the documented 0.0020282 and 0.99992, something in your environment differs from the one the maintainers used, and you want to know that before you build on top of it.
Then replace mackey_glass with your own array and confirm the shape contract holds. The README states the dataset is (2000, 1)-shaped, and to_forecasting handles the shift and split. If your series is multivariate, the README excerpt does not show that case, so check the user guide before assuming the same call works.
Decide early whether you need hyperparameter search, because that determines whether pip install reservoirpy is enough or whether you need the advanced install described in the developer guide. And if your design depends on online training or a plasticity rule, confirm the specific class exists in your pinned version: the README links to IPReservoir, LocalPlasticityReservoir and NVAR in the API reference, and those links are the fastest way to check.
Editorial conclusion
Adopt ReservoirPy if you are prototyping Echo State Networks on time series or classification and want the reservoir, readout and training rule expressed as composable Python objects rather than hand-written matrix code. Do not adopt it if you need a long-term stable API surface, since the release history shows both a 0.3.x line and a 0.4.x line, or if your workload depends on GPU-scale training, which the supplied material does not describe. Before committing, run the Mackey-Glass example from the README against your own data shape, confirm which release line your dependency resolver picks, and check that the learning rule you need (Intrinsic Plasticity, Local Plasticity or NVAR) exists in the version you install.
Community notes