Advanced reservoirs¶
Three heterogeneity extensions enrich the reservoir's dynamics. All keep the readout linear, so they remain fully compatible with the federated strategies — a deep reservoir, in particular, federates exactly.
See the measured comparison in the gallery and the results database (exp11_heterogeneity).
Heterogeneous leaking rates / time constants¶
Give each neuron its own leaking rate so different nodes integrate at different speeds — a single reservoir with multiple time-scales. One of the simplest yet most effective improvements for multi-scale signals (finance, chaotic systems).
from esnfed import EchoStateNetwork, topologies
a = topologies.leaking_rates(200, kind="layered", low=0.1, high=0.9, n_layers=4, rng=0)
esn = EchoStateNetwork(1, 1, W, spectral_radius=0.95, leaking_rate=a) # per-node a
kind can be "uniform", "log_uniform", "layered" (decreasing fast→slow blocks) or "constant". leaking_rate accepts a scalar or an array of shape (n_reservoir,).
Multi-type node nonlinearities¶
Mix activation functions within one reservoir — tanh, sigmoid, relu, sin (oscillator-like), identity — mimicking biological neuronal diversity and broadening the basis of dynamics.
from esnfed import topologies
from esnfed.esn import ACTIVATIONS # the available nonlinearities
acts = topologies.mixed_activations(200, types=("tanh", "sigmoid", "sin"), rng=0)
esn = EchoStateNetwork(1, 1, W, spectral_radius=0.9, activation=acts)
# activation also accepts a single name ("sigmoid") or any callable
Hierarchical (deep) reservoirs¶
Stack reservoir layers — the states of layer \(\ell\) feed layer \(\ell{+}1\) — each with its own size, spectral radius and (decreasing) leaking rate. This builds a hierarchy of progressively slower dynamics and markedly boosts memory and nonlinearity over a single layer of the same total size.
flowchart LR
u["input"] --> L1["reservoir 1<br/>fast (a=0.9)"]
L1 --> L2["reservoir 2<br/>medium (a=0.5)"]
L2 --> L3["reservoir 3<br/>slow (a=0.2)"]
L1 --> RO["readout<br/>(all layers' states)"]
L2 --> RO
L3 --> RO
RO --> y["output"] from esnfed import DeepEchoStateNetwork, topologies
Ws = [topologies.random_reservoir(50, density=0.1, rng=i) for i in range(3)]
deep = DeepEchoStateNetwork(
1, 1, Ws,
spectral_radius=0.95,
leaking_rate=[0.9, 0.5, 0.2], # per-layer: fast -> slow timescales
washout=100,
).fit(u_train, y_train)
y = deep.predict(u_test)
Per-layer hyper-parameters (spectral_radius, leaking_rate, activation, input_scaling) accept a single value or a list with one entry per layer; the readout is trained on the concatenation of all layers' states.
Federates exactly
A DeepEchoStateNetwork is a drop-in for EchoStateNetwork in a federated Client; its summed sufficient statistics reproduce pooled training to machine precision (verified by the test suite).
Finding from the research
The benefit is task-dependent: depth and heterogeneous leaking rates cut the long-memory Mackey-Glass error ~4× at a matched size, while multi-type nonlinearities help the faster Lorenz task. None is a universal win — match the extension to the task's time-scale structure.