OpenReservoirComputing 0.3.0__tar.gz → 0.3.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/JOSS/paper.md +8 -6
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/PKG-INFO +1 -1
- openreservoircomputing-0.3.3/imgs/benchmark_results_combined.png +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/pyproject.toml +3 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/OpenReservoirComputing.egg-info/PKG-INFO +1 -1
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/OpenReservoirComputing.egg-info/SOURCES.txt +3 -0
- openreservoircomputing-0.3.3/src/OpenReservoirComputing.egg-info/scm_file_list.json +86 -0
- openreservoircomputing-0.3.3/src/OpenReservoirComputing.egg-info/scm_version.json +8 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/__init__.py +1 -1
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/classifier/train.py +2 -3
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/control/models.py +1 -1
- openreservoircomputing-0.3.3/src/orc/control/train.py +213 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/drivers.py +1 -3
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/forecaster/base.py +1 -1
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/forecaster/train.py +116 -38
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/classifier/test_classifier_models.py +4 -6
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/control/test_control_models.py +151 -3
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/forecaster/test_forecast_models.py +296 -8
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/test_drivers.py +1 -1
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/test_readouts.py +10 -4
- openreservoircomputing-0.3.0/src/orc/control/train.py +0 -164
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/.github/CODEOWNERS +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/.github/workflows/docs.yml +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/.github/workflows/draft-pdf.yml +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/.github/workflows/publish.yml +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/.github/workflows/tests.yml +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/.gitignore +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/JOSS/CITATION.cff +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/JOSS/CODE_OF_CONDUCT.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/JOSS/joss-paper.pdf +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/JOSS/paper.bib +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/LICENSE +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/README.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/api/classifier.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/api/control.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/api/data.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/api/drivers.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/api/embeddings.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/api/forecaster.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/api/readouts.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/api/utils.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/contributing.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/getting-started/installation.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/getting-started/quickstart.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/imgs/ORC_logo_cropped.png +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/index.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/javascripts/mathjax.js +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/stylesheets/extra.css +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/user-guide/data.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/user-guide/drivers.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/user-guide/embeddings.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/user-guide/models.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/user-guide/overview.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/docs/user-guide/readouts.md +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/examples/benchmark_combined.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/examples/classification.ipynb +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/examples/continuous_rc.ipynb +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/examples/control.ipynb +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/examples/data_library.ipynb +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/examples/jit_compatibility.ipynb +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/examples/ks.ipynb +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/examples/lorenz.ipynb +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/examples/rc_background.ipynb +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/imgs/ORC_logo_cropped.png +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/imgs/architecture_paper.pdf +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/imgs/readme_example_forecast.png +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/mkdocs.yml +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/setup.cfg +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/OpenReservoirComputing.egg-info/dependency_links.txt +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/OpenReservoirComputing.egg-info/requires.txt +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/OpenReservoirComputing.egg-info/top_level.txt +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/classifier/__init__.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/classifier/base.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/classifier/models.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/control/__init__.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/control/base.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/data/__init__.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/data/integrators.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/embeddings.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/forecaster/__init__.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/forecaster/models.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/readouts.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/utils/__init__.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/utils/numerics.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/utils/regressions.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/src/orc/utils/visualization.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/data/test_integrators.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/test_embeddings.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/utils/test_numerics.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/utils/test_regressions.py +0 -0
- {openreservoircomputing-0.3.0 → openreservoircomputing-0.3.3}/tests/utils/test_visualization.py +0 -0
|
@@ -44,7 +44,7 @@ OpenReservoirComputing (ORC) is a Python library for reservoir computing (RC) bu
|
|
|
44
44
|
|
|
45
45
|
# Statement of Need
|
|
46
46
|
|
|
47
|
-
Time-series prediction, classification, and control are fundamental tasks across science and engineering, arising in applications from climate modeling and fluid dynamics to robotics and neuroscience. Deep learning approaches to these tasks typically require large datasets, long training times, and expensive tuning of optimization hyperparameters. RC offers a compelling alternative. Since only the readout layer is trained via a single ridge regression, RC models can be trained in a fraction of the time required by comparable recurrent neural networks, often with less data and fewer hyperparameters to tune [@lukosevicius2009reservoir
|
|
47
|
+
Time-series prediction, classification, and control are fundamental tasks across science and engineering, arising in applications from climate modeling and fluid dynamics to robotics and neuroscience. Deep learning approaches to these tasks typically require large datasets, long training times, and expensive tuning of optimization hyperparameters. RC offers a compelling alternative. Since only the readout layer is trained via a single ridge regression, RC models can be trained in a fraction of the time required by comparable recurrent neural networks, often with less data and fewer hyperparameters to tune [@lukosevicius2009reservoir;@pathak2018model;@wyder2025common]. This makes RC particularly attractive for rapid prototyping, real-time applications, and data-limited settings. However, realizing these benefits in practice requires software that is both efficient and adaptable.
|
|
48
48
|
|
|
49
49
|
ORC's built-in models provide an easy entry point for users new to the field. In particular, a new user can supply their own time-series data to instantiate, train, and forecast in three simple lines of code.
|
|
50
50
|
|
|
@@ -58,7 +58,7 @@ U_pred = esn.forecast(fcast_len=1000, res_state=R[-1])
|
|
|
58
58
|
|
|
59
59
|
Built-in visualization tools make it easy to evaluate model performance. Varying the hyperparameters of built-in models lets users explore how RC performance depends on configuration choices. ORC's JAX foundation makes scaling to higher-dimensional parallel reservoir architectures equally simple.
|
|
60
60
|
|
|
61
|
-
Much RC research is aimed at designing performant reservoir architectures. ORC makes this easy through its use of abstract base classes for Embedding, Driver, and Readout layers. Users need only define forward pass logic to integrate a new reservoir topology or readout strategy, while reusing the rest of the framework. This modular approach also enables ablation studies on how different components affect RC performance. Because of ORC's functional approach in JAX, built-in and user-created models provide end-to-end differentiability by default. This enables gradient-based optimization of input sequences for control problems. This also makes ORC well suited to integrate with deep learning models such as those presented
|
|
61
|
+
Much RC research is aimed at designing performant reservoir architectures. ORC makes this easy through its use of abstract base classes for Embedding, Driver, and Readout layers. Users need only define forward pass logic to integrate a new reservoir topology or readout strategy, while reusing the rest of the framework. This modular approach also enables ablation studies on how different components affect RC performance. Because of ORC's functional approach in JAX, built-in and user-created models provide end-to-end differentiability by default. This enables gradient-based optimization of input sequences for control problems. This also makes ORC well suited to integrate with deep learning models such as those presented by Özalp et al. [-@ozalp2023reconstruction; -@ozalp2025real].
|
|
62
62
|
|
|
63
63
|
# State of the Field
|
|
64
64
|
| | **ORC** | **ReservoirPy** | **RC.jl** |
|
|
@@ -81,12 +81,12 @@ First, ORC was *designed* on top of JAX [@jax2018github] and Equinox [@kidger202
|
|
|
81
81
|
Second, ORC has a different built-in feature set. ORC supports continuous-time reservoir dynamics via Diffrax [@kidger2021on], allowing users to define reservoir equations as ordinary differential equations solved with adaptive-step integrators. ORC also supports novel architectures such as Taylor-expanded and GRU-based drivers alongside standard echo state networks. ReservoirPy does not provide these functionalities.
|
|
82
82
|
Third, ORC models compose seamlessly with other deep learning models in Equinox, whereas ReservoirPy is suited to standalone RC tasks.
|
|
83
83
|
|
|
84
|
-
Other open source libraries for RC include
|
|
84
|
+
Other open source libraries for RC include PyTorch-ESN [@nardo2018pytorchesn] and ReservoirComputing.jl [@martinuzzi2022reservoircomputing]. PyTorch-ESN allows for integration with other PyTorch models, but is not as widely adopted and offers a much more limited feature set than ORC or ReservoirPy. For instance, it does not support sparse matrix operations or parallel reservoirs. ReservoirComputing.jl is a widely used Julia library for RC that influenced many of ORC's design choices, but lacks Python ML ecosystem integration. Table 1 summarizes the functionality of ORC, ReservoirPy, and ReservoirComputing.jl.
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
# Software Design
|
|
88
88
|
|
|
89
|
-

|
|
90
90
|
|
|
91
91
|
ORC models are decomposed into three components, illustrated in \autoref{fig:architecture}: (i) an embedding $f_E$ that lifts a low-dimensional input signal $u_t$ to a high-dimensional space, (ii) a driver $f_R$ that propagates the high-dimensional state $r_t$, and (iii) a readout $f_O$ that maps the latent state back to an approximation of some low-dimensional signal $y_t$. Depending on the task at hand, $y_t$ may be a future time-step of $u_t$, a label associated with input data, or some other target signal. ORC differs from many existing approaches that unify (i) and (ii). Separating the embedding from the reservoir state propagation allows for cleaner application of RC to non-standard tasks, such as acting as a surrogate model for model predictive control.
|
|
92
92
|
|
|
@@ -104,12 +104,14 @@ ORC also includes a data generation module with ODE and PDE integrators for stan
|
|
|
104
104
|
|
|
105
105
|

|
|
106
106
|
|
|
107
|
-
ORC enables easy reimplementation of architectures that integrate RC with larger neural networks [@ozalp2023reconstruction; @ozalp2025real], and makes it easier to iterate on these ideas than any existing library. We also benchmark ORC against ReservoirPy across reservoir sizes and
|
|
107
|
+
ORC enables easy reimplementation of architectures that integrate RC with larger neural networks [@ozalp2023reconstruction; @ozalp2025real], and makes it easier to iterate on these ideas than any existing library. We also benchmark ORC against ReservoirPy across reservoir sizes and numbers of training samples, as shown in \autoref{fig:comp}. We find that with GPU acceleration, ORC scales far more favorably than ReservoirPy. Moreover, ORC is the only current package that supports training RC for control tasks, enabled by its efficiency and the end-to-end differentiability that JAX and Equinox provide. RC-based control has recently been shown to be advantageous over other forms of RNN-based MPC [@williams2024reservoir]. ORC's performance also makes it well suited for the parallel architectures needed to extend RC to higher-dimensional settings.
|
|
108
108
|
|
|
109
109
|
|
|
110
110
|
# AI Usage Disclosure
|
|
111
111
|
|
|
112
|
-
Claude (Anthropic) was used for code assistance during
|
|
112
|
+
Claude (Anthropic, Opus 4-4.8) was used for code assistance during debugging, for proofreading and editing the text of this paper, and for generating the architecture visualization SVG (\autoref{fig:architecture}). ChatGPT (OpenAI, GPT-4o) was used to generate the ORC logo. All AI-assisted outputs, including code, paper text, and figures, were reviewed, edited, and validated by the authors before inclusion.
|
|
113
113
|
|
|
114
114
|
# Acknowledgements
|
|
115
115
|
The authors acknowledge support from the NSF AI Institute in Dynamic Systems (grant number 2112085). The authors also thank Anastasia Bizyaeva, Noa Kaplan, and Ling-Wei Kong for insightful conversations.
|
|
116
|
+
|
|
117
|
+
# References
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: OpenReservoirComputing
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: GPU accelerated implementations of common RC architectures
|
|
5
5
|
Author-email: "Jan P. Williams" <jmpw1@uw.edu>, Dima Tretiak <dtretiak@uw.edu>
|
|
6
6
|
Maintainer-email: "Jan P. Williams" <jmpw1@uw.edu>
|
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: OpenReservoirComputing
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: GPU accelerated implementations of common RC architectures
|
|
5
5
|
Author-email: "Jan P. Williams" <jmpw1@uw.edu>, Dima Tretiak <dtretiak@uw.edu>
|
|
6
6
|
Maintainer-email: "Jan P. Williams" <jmpw1@uw.edu>
|
|
@@ -46,11 +46,14 @@ examples/lorenz.ipynb
|
|
|
46
46
|
examples/rc_background.ipynb
|
|
47
47
|
imgs/ORC_logo_cropped.png
|
|
48
48
|
imgs/architecture_paper.pdf
|
|
49
|
+
imgs/benchmark_results_combined.png
|
|
49
50
|
imgs/readme_example_forecast.png
|
|
50
51
|
src/OpenReservoirComputing.egg-info/PKG-INFO
|
|
51
52
|
src/OpenReservoirComputing.egg-info/SOURCES.txt
|
|
52
53
|
src/OpenReservoirComputing.egg-info/dependency_links.txt
|
|
53
54
|
src/OpenReservoirComputing.egg-info/requires.txt
|
|
55
|
+
src/OpenReservoirComputing.egg-info/scm_file_list.json
|
|
56
|
+
src/OpenReservoirComputing.egg-info/scm_version.json
|
|
54
57
|
src/OpenReservoirComputing.egg-info/top_level.txt
|
|
55
58
|
src/orc/__init__.py
|
|
56
59
|
src/orc/drivers.py
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
{
|
|
2
|
+
"files": [
|
|
3
|
+
"mkdocs.yml",
|
|
4
|
+
"pyproject.toml",
|
|
5
|
+
"LICENSE",
|
|
6
|
+
"README.md",
|
|
7
|
+
".gitignore",
|
|
8
|
+
".github/CODEOWNERS",
|
|
9
|
+
".github/workflows/draft-pdf.yml",
|
|
10
|
+
".github/workflows/tests.yml",
|
|
11
|
+
".github/workflows/publish.yml",
|
|
12
|
+
".github/workflows/docs.yml",
|
|
13
|
+
"JOSS/paper.bib",
|
|
14
|
+
"JOSS/CODE_OF_CONDUCT.md",
|
|
15
|
+
"JOSS/joss-paper.pdf",
|
|
16
|
+
"JOSS/CITATION.cff",
|
|
17
|
+
"JOSS/paper.md",
|
|
18
|
+
"examples/jit_compatibility.ipynb",
|
|
19
|
+
"examples/benchmark_combined.py",
|
|
20
|
+
"examples/continuous_rc.ipynb",
|
|
21
|
+
"examples/classification.ipynb",
|
|
22
|
+
"examples/control.ipynb",
|
|
23
|
+
"examples/data_library.ipynb",
|
|
24
|
+
"examples/lorenz.ipynb",
|
|
25
|
+
"examples/rc_background.ipynb",
|
|
26
|
+
"examples/ks.ipynb",
|
|
27
|
+
"tests/test_drivers.py",
|
|
28
|
+
"tests/test_embeddings.py",
|
|
29
|
+
"tests/test_readouts.py",
|
|
30
|
+
"tests/utils/test_numerics.py",
|
|
31
|
+
"tests/utils/test_visualization.py",
|
|
32
|
+
"tests/utils/test_regressions.py",
|
|
33
|
+
"tests/control/test_control_models.py",
|
|
34
|
+
"tests/classifier/test_classifier_models.py",
|
|
35
|
+
"tests/data/test_integrators.py",
|
|
36
|
+
"tests/forecaster/test_forecast_models.py",
|
|
37
|
+
"imgs/readme_example_forecast.png",
|
|
38
|
+
"imgs/benchmark_results_combined.png",
|
|
39
|
+
"imgs/architecture_paper.pdf",
|
|
40
|
+
"imgs/ORC_logo_cropped.png",
|
|
41
|
+
"src/orc/readouts.py",
|
|
42
|
+
"src/orc/embeddings.py",
|
|
43
|
+
"src/orc/__init__.py",
|
|
44
|
+
"src/orc/drivers.py",
|
|
45
|
+
"src/orc/utils/regressions.py",
|
|
46
|
+
"src/orc/utils/__init__.py",
|
|
47
|
+
"src/orc/utils/numerics.py",
|
|
48
|
+
"src/orc/utils/visualization.py",
|
|
49
|
+
"src/orc/control/train.py",
|
|
50
|
+
"src/orc/control/__init__.py",
|
|
51
|
+
"src/orc/control/models.py",
|
|
52
|
+
"src/orc/control/base.py",
|
|
53
|
+
"src/orc/classifier/train.py",
|
|
54
|
+
"src/orc/classifier/__init__.py",
|
|
55
|
+
"src/orc/classifier/models.py",
|
|
56
|
+
"src/orc/classifier/base.py",
|
|
57
|
+
"src/orc/data/integrators.py",
|
|
58
|
+
"src/orc/data/__init__.py",
|
|
59
|
+
"src/orc/forecaster/train.py",
|
|
60
|
+
"src/orc/forecaster/__init__.py",
|
|
61
|
+
"src/orc/forecaster/models.py",
|
|
62
|
+
"src/orc/forecaster/base.py",
|
|
63
|
+
"docs/contributing.md",
|
|
64
|
+
"docs/index.md",
|
|
65
|
+
"docs/examples",
|
|
66
|
+
"docs/getting-started/installation.md",
|
|
67
|
+
"docs/getting-started/quickstart.md",
|
|
68
|
+
"docs/user-guide/overview.md",
|
|
69
|
+
"docs/user-guide/readouts.md",
|
|
70
|
+
"docs/user-guide/data.md",
|
|
71
|
+
"docs/user-guide/embeddings.md",
|
|
72
|
+
"docs/user-guide/models.md",
|
|
73
|
+
"docs/user-guide/drivers.md",
|
|
74
|
+
"docs/stylesheets/extra.css",
|
|
75
|
+
"docs/imgs/ORC_logo_cropped.png",
|
|
76
|
+
"docs/api/forecaster.md",
|
|
77
|
+
"docs/api/classifier.md",
|
|
78
|
+
"docs/api/readouts.md",
|
|
79
|
+
"docs/api/control.md",
|
|
80
|
+
"docs/api/data.md",
|
|
81
|
+
"docs/api/embeddings.md",
|
|
82
|
+
"docs/api/utils.md",
|
|
83
|
+
"docs/api/drivers.md",
|
|
84
|
+
"docs/javascripts/mathjax.js"
|
|
85
|
+
]
|
|
86
|
+
}
|
|
@@ -17,7 +17,7 @@ from orc import (
|
|
|
17
17
|
|
|
18
18
|
if not getattr(jax.config, "jax_enable_x64", False):
|
|
19
19
|
warnings.warn(
|
|
20
|
-
"For good performance, orc often requires float64 precision. Enable it "
|
|
20
|
+
"For good performance, orc often requires float64 precision. Enable it "
|
|
21
21
|
"before importing orc with: "
|
|
22
22
|
"jax.config.update('jax_enable_x64', True)",
|
|
23
23
|
UserWarning,
|
|
@@ -17,6 +17,7 @@ from orc.utils.regressions import (
|
|
|
17
17
|
|
|
18
18
|
VariableRCClassifier = TypeVar(name="VariableRCClassifier", bound=RCClassifierBase)
|
|
19
19
|
|
|
20
|
+
|
|
20
21
|
def train_RCClassifier(
|
|
21
22
|
model: VariableRCClassifier,
|
|
22
23
|
train_seqs: Array,
|
|
@@ -66,9 +67,7 @@ def train_RCClassifier(
|
|
|
66
67
|
raise ValueError("Number of training sequences must match number of labels.")
|
|
67
68
|
|
|
68
69
|
n_samples = train_seqs.shape[0]
|
|
69
|
-
initial_res_states = jnp.tile(
|
|
70
|
-
model.driver.default_state(), (n_samples, 1)
|
|
71
|
-
)
|
|
70
|
+
initial_res_states = jnp.tile(model.driver.default_state(), (n_samples, 1))
|
|
72
71
|
|
|
73
72
|
# Force all sequences through the reservoir in parallel via vmap
|
|
74
73
|
all_res_seqs = jax.vmap(model.force)(train_seqs, initial_res_states)
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""Training functions for reservoir computer controllers."""
|
|
2
|
+
|
|
3
|
+
from typing import TypeVar
|
|
4
|
+
|
|
5
|
+
import equinox as eqx
|
|
6
|
+
import jax.numpy as jnp
|
|
7
|
+
from jaxtyping import Array
|
|
8
|
+
|
|
9
|
+
from orc.control.base import RCControllerBase
|
|
10
|
+
from orc.control.models import ESNController
|
|
11
|
+
from orc.utils.regressions import (
|
|
12
|
+
_solve_all_ridge_reg,
|
|
13
|
+
_solve_all_ridge_reg_batched,
|
|
14
|
+
ridge_regression,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
VariableRCController = TypeVar(name="VariableRCController", bound=RCControllerBase)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def train_RCController(
|
|
21
|
+
model: VariableRCController,
|
|
22
|
+
train_seq: Array,
|
|
23
|
+
control_seq: Array,
|
|
24
|
+
target_seq: Array | None = None,
|
|
25
|
+
spinup: int = 0,
|
|
26
|
+
initial_res_state: Array | None = None,
|
|
27
|
+
beta: float = 8e-8,
|
|
28
|
+
batch_size: int | None = None,
|
|
29
|
+
multi_sequence: bool = False,
|
|
30
|
+
**force_kwargs,
|
|
31
|
+
) -> tuple[VariableRCController, Array]:
|
|
32
|
+
"""Unified training function for reservoir computer controllers.
|
|
33
|
+
|
|
34
|
+
Works with any model inheriting from RCControllerBase, including
|
|
35
|
+
ESNController and custom models with user-defined readout layers.
|
|
36
|
+
|
|
37
|
+
Parameters
|
|
38
|
+
----------
|
|
39
|
+
model : RCControllerBase
|
|
40
|
+
Reservoir computer controller model to train.
|
|
41
|
+
train_seq : Array
|
|
42
|
+
Training input sequence for reservoir. Shape ``(seq_len, data_dim)``
|
|
43
|
+
for a single trajectory, or ``(n_traj, seq_len, data_dim)`` when
|
|
44
|
+
``multi_sequence=True``. All trajectories must have the same length.
|
|
45
|
+
control_seq : Array
|
|
46
|
+
Control input sequence for reservoir. Shape ``(seq_len, control_dim)``
|
|
47
|
+
for a single trajectory, or ``(n_traj, seq_len, control_dim)`` when
|
|
48
|
+
``multi_sequence=True``.
|
|
49
|
+
target_seq : Array, optional
|
|
50
|
+
Target sequence for training reservoir. Shape ``(seq_len, data_dim)``
|
|
51
|
+
for a single trajectory, or ``(n_traj, seq_len, data_dim)`` when
|
|
52
|
+
``multi_sequence=True``. If None, defaults to train_seq[1:] (or
|
|
53
|
+
train_seq[:, 1:] for multi-sequence).
|
|
54
|
+
spinup : int
|
|
55
|
+
Initial transient of reservoir states to discard per trajectory.
|
|
56
|
+
initial_res_state : Array, optional
|
|
57
|
+
Initial reservoir state. If None, uses model.driver.default_state()
|
|
58
|
+
(tiled across trajectories when ``multi_sequence=True``). When
|
|
59
|
+
``multi_sequence=True`` and not None, must have a leading trajectory
|
|
60
|
+
axis, i.e. shape ``(n_traj, ...)``.
|
|
61
|
+
beta : float
|
|
62
|
+
Tikhonov regularization parameter.
|
|
63
|
+
batch_size : int, optional
|
|
64
|
+
Number of parallel reservoirs to process in each batch for ridge
|
|
65
|
+
regression. If None (default), processes all reservoirs at once.
|
|
66
|
+
Only used when readout.chunks > 0.
|
|
67
|
+
multi_sequence : bool
|
|
68
|
+
If True, treat train_seq, control_seq, and target_seq as batches of
|
|
69
|
+
trajectories with a leading trajectory axis. Reservoir states from all
|
|
70
|
+
trajectories are concatenated (after spinup) before solving the
|
|
71
|
+
regression. This flag is a static boolean suitable for use as
|
|
72
|
+
``static_argnums`` when wrapping with ``jax.jit``.
|
|
73
|
+
**force_kwargs
|
|
74
|
+
Additional keyword arguments passed to model.force().
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
model : RCControllerBase
|
|
79
|
+
Trained model.
|
|
80
|
+
tot_res_seq : Array
|
|
81
|
+
Full reservoir state sequence from teacher forcing. Shape
|
|
82
|
+
``(seq_len, ...)`` for single-sequence or ``(n_traj, seq_len, ...)``
|
|
83
|
+
for multi-sequence.
|
|
84
|
+
"""
|
|
85
|
+
if multi_sequence:
|
|
86
|
+
if train_seq.shape[:2] != control_seq.shape[:2]:
|
|
87
|
+
raise ValueError(
|
|
88
|
+
"train_seq and control_seq must have the same (n_traj, seq_len)."
|
|
89
|
+
)
|
|
90
|
+
else:
|
|
91
|
+
if train_seq.shape[0] != control_seq.shape[0]:
|
|
92
|
+
raise ValueError("train_seq and control_seq must have the same length.")
|
|
93
|
+
|
|
94
|
+
seq_len = train_seq.shape[1] if multi_sequence else train_seq.shape[0]
|
|
95
|
+
if spinup >= seq_len:
|
|
96
|
+
raise ValueError(
|
|
97
|
+
"spinup must be less than the length of the training sequence."
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
if initial_res_state is None:
|
|
101
|
+
default = model.driver.default_state()
|
|
102
|
+
if multi_sequence:
|
|
103
|
+
n_traj = train_seq.shape[0]
|
|
104
|
+
initial_res_state = jnp.broadcast_to(
|
|
105
|
+
default[None], (n_traj,) + default.shape
|
|
106
|
+
)
|
|
107
|
+
else:
|
|
108
|
+
initial_res_state = default
|
|
109
|
+
|
|
110
|
+
if target_seq is None:
|
|
111
|
+
tot_seq = train_seq
|
|
112
|
+
tot_control_seq = control_seq
|
|
113
|
+
target_seq = train_seq[:, 1:, :] if multi_sequence else train_seq[1:, :]
|
|
114
|
+
else:
|
|
115
|
+
if multi_sequence:
|
|
116
|
+
tot_seq = jnp.concatenate([train_seq, target_seq[:, -1:, :]], axis=1)
|
|
117
|
+
tot_control_seq = jnp.concatenate(
|
|
118
|
+
[control_seq, control_seq[:, -1:, :]], axis=1
|
|
119
|
+
)
|
|
120
|
+
else:
|
|
121
|
+
tot_seq = jnp.vstack((train_seq, target_seq[-1:]))
|
|
122
|
+
tot_control_seq = jnp.vstack((control_seq, control_seq[-1:]))
|
|
123
|
+
|
|
124
|
+
if multi_sequence:
|
|
125
|
+
tot_res_seq = eqx.filter_vmap(model.force)(
|
|
126
|
+
tot_seq, tot_control_seq, initial_res_state
|
|
127
|
+
)
|
|
128
|
+
res_seq = tot_res_seq[:, :-1]
|
|
129
|
+
res_seq_train = eqx.filter_vmap(model.readout.prepare_train)(res_seq)
|
|
130
|
+
train_target = eqx.filter_vmap(model.readout.prepare_target)(target_seq)
|
|
131
|
+
res_seq_train = res_seq_train[:, spinup:].reshape(
|
|
132
|
+
(-1,) + res_seq_train.shape[2:]
|
|
133
|
+
)
|
|
134
|
+
train_target = train_target[:, spinup:].reshape((-1,) + train_target.shape[2:])
|
|
135
|
+
else:
|
|
136
|
+
tot_res_seq = model.force(
|
|
137
|
+
tot_seq, tot_control_seq, initial_res_state, **force_kwargs
|
|
138
|
+
)
|
|
139
|
+
res_seq = tot_res_seq[:-1]
|
|
140
|
+
res_seq_train = model.readout.prepare_train(res_seq)
|
|
141
|
+
train_target = model.readout.prepare_target(target_seq)
|
|
142
|
+
res_seq_train = res_seq_train[spinup:]
|
|
143
|
+
train_target = train_target[spinup:]
|
|
144
|
+
|
|
145
|
+
if model.readout.chunks > 0:
|
|
146
|
+
if batch_size is None:
|
|
147
|
+
cmat = _solve_all_ridge_reg(res_seq_train, train_target, beta)
|
|
148
|
+
else:
|
|
149
|
+
cmat = _solve_all_ridge_reg_batched(
|
|
150
|
+
res_seq_train, train_target, beta, batch_size
|
|
151
|
+
)
|
|
152
|
+
else:
|
|
153
|
+
cmat = ridge_regression(res_seq_train, train_target, beta)
|
|
154
|
+
|
|
155
|
+
new_readout = model.readout.set_wout(cmat)
|
|
156
|
+
model = eqx.tree_at(lambda m: m.readout, model, new_readout)
|
|
157
|
+
|
|
158
|
+
return model, tot_res_seq
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def train_ESNController(
|
|
162
|
+
model: ESNController,
|
|
163
|
+
train_seq: Array,
|
|
164
|
+
control_seq: Array,
|
|
165
|
+
target_seq: Array | None = None,
|
|
166
|
+
spinup: int = 0,
|
|
167
|
+
initial_res_state: Array | None = None,
|
|
168
|
+
beta: float = 8e-8,
|
|
169
|
+
multi_sequence: bool = False,
|
|
170
|
+
) -> tuple[ESNController, Array]:
|
|
171
|
+
"""Training function for ESNController.
|
|
172
|
+
|
|
173
|
+
Parameters
|
|
174
|
+
----------
|
|
175
|
+
model : ESNController
|
|
176
|
+
ESNController model to train.
|
|
177
|
+
train_seq : Array
|
|
178
|
+
Training input sequence for reservoir, (shape=(seq_len, data_dim)).
|
|
179
|
+
control_seq : Array
|
|
180
|
+
Control input sequence for reservoir, (shape=(seq_len, control_dim)).
|
|
181
|
+
target_seq : Array
|
|
182
|
+
Target sequence for training reservoir, (shape=(seq_len, data_dim)).
|
|
183
|
+
If None, defaults to train_seq[1:].
|
|
184
|
+
initial_res_state : Array
|
|
185
|
+
Initial reservoir state, (shape=(res_dim,)).
|
|
186
|
+
spinup : int
|
|
187
|
+
Initial transient of reservoir states to discard.
|
|
188
|
+
beta : float
|
|
189
|
+
Tikhonov regularization parameter.
|
|
190
|
+
multi_sequence : bool
|
|
191
|
+
If True, treat train_seq and control_seq as batches of trajectories
|
|
192
|
+
with shape (n_traj, seq_len, ...). See train_RCController for details.
|
|
193
|
+
|
|
194
|
+
Returns
|
|
195
|
+
-------
|
|
196
|
+
model : ESNController
|
|
197
|
+
Trained ESN controller model.
|
|
198
|
+
res_seq : Array
|
|
199
|
+
Training sequence of reservoir states.
|
|
200
|
+
"""
|
|
201
|
+
if not isinstance(model, ESNController):
|
|
202
|
+
raise TypeError("Model must be an ESNController.")
|
|
203
|
+
|
|
204
|
+
return train_RCController(
|
|
205
|
+
model,
|
|
206
|
+
train_seq,
|
|
207
|
+
control_seq,
|
|
208
|
+
target_seq,
|
|
209
|
+
spinup,
|
|
210
|
+
initial_res_state,
|
|
211
|
+
beta,
|
|
212
|
+
multi_sequence=multi_sequence,
|
|
213
|
+
)
|
|
@@ -869,9 +869,7 @@ class GRUDriver(DriverBase):
|
|
|
869
869
|
super().__init__(res_dim=res_dim)
|
|
870
870
|
key = jax.random.key(seed)
|
|
871
871
|
gru = eqx.nn.GRUCell(res_dim, res_dim, key=key)
|
|
872
|
-
gru = eqx.tree_at(
|
|
873
|
-
lambda c: c.weight_ih, gru, gru.weight_ih * input_rescaling
|
|
874
|
-
)
|
|
872
|
+
gru = eqx.tree_at(lambda c: c.weight_ih, gru, gru.weight_ih * input_rescaling)
|
|
875
873
|
self.gru = gru
|
|
876
874
|
|
|
877
875
|
def advance(self, proj_vars, res_state):
|
|
@@ -391,7 +391,7 @@ class CRCForecasterBase(RCForecasterBase, ABC):
|
|
|
391
391
|
res_seq = sol.ys
|
|
392
392
|
return res_seq
|
|
393
393
|
|
|
394
|
-
def __call__(self, in_seq: Array, res_state: Array, ts: Array) -> Array:
|
|
394
|
+
def __call__(self, in_seq: Array, res_state: Array, ts: Array) -> Array: # ty: ignore[invalid-method-override]
|
|
395
395
|
"""
|
|
396
396
|
Teacher forces the reservoir, wrapper for `force` method.
|
|
397
397
|
|