mimosa-ml 0.1.0a0__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.
@@ -0,0 +1,32 @@
1
+ name: Publish Python 🐍📦 to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*" # déclenche quand on push un tag qui commence par v
7
+
8
+ jobs:
9
+ build-and-publish:
10
+ runs-on: ubuntu-latest
11
+ environment: pypi
12
+ permissions:
13
+ id-token: write
14
+
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.10"
22
+
23
+ - name: Install build dependencies
24
+ run: |
25
+ python -m pip install --upgrade pip
26
+ pip install build twine
27
+
28
+ - name: Build package
29
+ run: python -m build
30
+
31
+ - name: Publish to PyPI
32
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Simon Lejoly
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,240 @@
1
+ Metadata-Version: 2.4
2
+ Name: mimosa-ml
3
+ Version: 0.1.0a0
4
+ Summary: MIMOSA: Multi-Input Multi-Output Sample Analysis - A fully-featured multi-task Gaussian process framework for analysing functional data.
5
+ Project-URL: Homepage, https://github.com/SimLej18/mimosa
6
+ Author-email: Simon Lejoly <simon.lejoly@unamur.be>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.10
13
+ Requires-Dist: beartype
14
+ Requires-Dist: equinox
15
+ Requires-Dist: jax
16
+ Requires-Dist: jaxtyping
17
+ Requires-Dist: kernax-ml
18
+ Requires-Dist: matplotlib
19
+ Requires-Dist: numpy
20
+ Requires-Dist: optimistix
21
+ Requires-Dist: polars
22
+ Provides-Extra: dev
23
+ Requires-Dist: pytest; extra == 'dev'
24
+ Description-Content-Type: text/markdown
25
+
26
+ # MIMOSA: Multi-Input Multi-Output Sample Analysis
27
+
28
+ A fully-featured *multi-task Gaussian process framework* for analysing functional data.
29
+ It is based on the [MagmaClust framework](https://jmlr.org/papers/v24/20-1321.html), with many enhancements for efficiency and modularity.
30
+
31
+ Its core features currently include:
32
+ * Joint learning across multiple samples (Multi-Task GPs) with unaligned sampling grids
33
+ * Clustering of samples
34
+ * Multi-dimensional inputs and outputs
35
+ * Probabilistic predictions with uncertainty quantification
36
+ * A multitude of training configuration to model complex relationships between tasks, clusters and inputs
37
+ * Deep kernax integration for complex kernels/means functions
38
+ * Support for training and predicting on GPUs and TPUs
39
+ * Full Jax/Equinox compatibility for vmap/grad/jit
40
+
41
+ Towards v1.0.0, we plan to add:
42
+ * Inter-output correlation learning
43
+ * Adaptation to non-gaussian data and classification tasks
44
+ * Sparse learning and approximations for scalability
45
+ * Visualisation tools for data and model outputs
46
+ * Clever initialisation for hyper-parameters of the models
47
+
48
+ > **⚠️ Project Status**: MIMOSA is currently in early development.
49
+ > While current features are functional in most cases, bugs can happen.
50
+ > The API and features are still subject to change.
51
+ > If you use the package for research/production, we encourage you to version-lock your mimosa dependency.
52
+
53
+ ---
54
+ ## Installation
55
+
56
+ You can install mimosa through pip:
57
+
58
+ ```bash
59
+ pip install mimosa-ml
60
+ ```
61
+
62
+ You can then import components of the package as:
63
+
64
+ ```python
65
+ from mimosa.hyperpost import Hyperpost # Import example
66
+ ```
67
+
68
+ N.b.: notice the difference between `mimosa-ml` (the PyPI ID of the package) and `mimosa` (the internal package name).
69
+
70
+ Python compatibility: mimosa is compatible with Python 3.10+.
71
+ We encourage using a more recent version to be compatible with latest releases of Jax and Equinox.
72
+
73
+ ---
74
+ ## Philosophy
75
+
76
+ We basically took Gaussian processes, and combined them with a ton of ✨*fancy components*✨
77
+ * ➡️ Multi-task learning based on [Magma](https://jmlr.org/papers/v24/20-1321.html)
78
+ * ➡️ Clustering as a mixture of Magma GPs
79
+ * ➡️ Multi-dimensional inputs thanks to efficient kernels from [Kernax](https://github.com/SimLej18/kernax-ml)
80
+ * ➡️ Multi-dimensional uncorrelated outputs by simply broadcasting the algorithm to another dimension
81
+ * ➡️ Multi-output correlation discovery by learning a [convolution process]([TODO]) with specific kernel
82
+
83
+
84
+ We use **JAX** as a back-end for every computation!
85
+ `jit` compilation saves us a lot of time,
86
+ `vmap` allows us to efficiently batch over all dimensions of the data and parameters,
87
+ `grad` spares us the hastle of implementing gradients for every component of the model,
88
+ and XLA support allows us to train and predict on GPUs and TPUs for scalability.
89
+
90
+ A GP library is nothing without a fast and modular **Kernel library**.
91
+ MIMOSA relies on the efficiency-focused [Kernax package](https://github.com/SimLej18/kernax-ml) for every kernel use
92
+ throughout the algorithms.
93
+
94
+ ---
95
+ ## Examples
96
+
97
+ Basic examples can be found in the `examples` directory. A quick example using the top-level API from Model can be found here:
98
+
99
+ ```python
100
+ import jax.random as jr
101
+ from jax import vmap
102
+ from kernax import ZeroMean, VarianceKernel, SEKernel, WhiteNoiseKernel
103
+
104
+ from mimosa.data_structures import Dimensions, Parameters, ModelConfig
105
+ from mimosa.synthetic import generate_data
106
+ from mimosa.models import BasicModel
107
+ from mimosa.grid import UnionGrid
108
+ from mimosa.plot import plot_dataset, plot_clusters, plot_single_task_prediction
109
+ from mimosa.sampling import sample_gp
110
+
111
+ key = jr.PRNGKey(0)
112
+
113
+ # 20 tasks, 2 clusters, 1D inputs/outputs, 25 points/task
114
+ dims = Dimensions(T=20, K=2, I=1, O=1, F=1, N=25, G=50)
115
+ config = ModelConfig(isotopic_tasks=False)
116
+
117
+ # Ground-truth parameters used to generate the synthetic dataset
118
+ init_params = Parameters(
119
+ cluster_mean=ZeroMean(),
120
+ cluster_kernel=VarianceKernel(1.0) * SEKernel(length_scale=1.0),
121
+ task_kernel=VarianceKernel(0.1) * SEKernel(length_scale=2.0),
122
+ noise_kernel=WhiteNoiseKernel(noise=0.01),
123
+ )
124
+
125
+ key, subkey = jr.split(key)
126
+ dataset, grid, hyperprior, mixture, parameters, cluster_means, tasks = generate_data(
127
+ subkey, dims, init_params, config, input_range=(-2.5, 2.5))
128
+
129
+ # Fit a model on the generated dataset, starting from the same parameters
130
+ fit_grid = UnionGrid()(dataset.inputs)
131
+ model = BasicModel(jr.PRNGKey(1), n_clusters=dims.K)
132
+ fitted_params, fitted_mixture = model.fit(dataset, fit_grid, mixture.proportions, parameters, n_iter=50)
133
+
134
+ # Predict the posterior distribution of every task, in every cluster
135
+ predictions = model.predict(dataset, fit_grid, fitted_mixture, fitted_params)
136
+ hyperposterior = model.hyperpost(dataset, fit_grid, fitted_mixture, fitted_params)
137
+
138
+ # Plot the fitted mean-processes over the dataset
139
+ fig, ax = plot_dataset(dataset, mixture=mixture, alpha=.3)
140
+ fig, ax = plot_clusters(fit_grid, hyperposterior=hyperposterior, fig=fig, ax=ax, legend=False)
141
+ ```
142
+
143
+ ![Fitted mean-processes over the dataset](docs/images/mean_processes.png)
144
+
145
+ ```python
146
+ # Draw samples from task 0's predictive distribution and plot them
147
+ t_id, o_id = 0, 0
148
+ k_id = int(fitted_mixture.assignments[t_id]) # task's dominant cluster
149
+ prediction = predictions[t_id, k_id, o_id]
150
+
151
+ key, sample_key = jr.split(key)
152
+ sample_keys = jr.split(sample_key, 64)
153
+ samples = vmap(lambda k: sample_gp(k, prediction.mean, prediction.covariance))(sample_keys)
154
+
155
+ fig, ax = plot_single_task_prediction(
156
+ dataset, fit_grid, hyperposterior, fitted_mixture, t_id, o_id, samples=samples)
157
+ ```
158
+
159
+ ![Prediction samples for task 0](docs/images/task0_prediction_samples.png)
160
+
161
+ MIMOSA is designed to have multiple layer of customisation. The "Model" API covers the most general use case of the
162
+ algorithm, but you should consider building your own training loops and combining/developping your own sub-modules to
163
+ create tailored models and pipelines.
164
+
165
+ ---
166
+ ## About configurations
167
+
168
+ MIMOSA has many training configurations to make it as precise as possible when modelling your specific data.
169
+ These configurations are stored in a `ModelConfig` dataclass.
170
+ Here is a quick overview of what each configuration option does.
171
+
172
+ * `shared_task_hps` (default `True`): whether task kernel/noise hyper-parameters are shared across all tasks, or learnt independently per task.
173
+ * `shared_cluster_hps` (default `True`): whether cluster mean/kernel hyper-parameters are shared across all clusters (mean-processes), or learnt independently per cluster.
174
+ * `shared_output_hps` (default `True`): whether hyper-parameters are shared across output dimensions, or learnt independently per output.
175
+ * `shared_features_hps` (default `True`): whether hyper-parameters are shared across features, or learnt independently per feature.
176
+ * `cluster_specific_task_hps` (default `True`): whether the task/noise kernels themselves vary depending on the cluster a task belongs to, or are shared across clusters.
177
+ * `isotopic_tasks` (default `True`): whether all tasks are observed at the same input locations, or each task has its own set of inputs.
178
+ * `isotopic_features` (default `True`): whether all features are observed at the same input locations, or each feature has its own set of inputs.
179
+
180
+ These configurations are independent of your choices of parameters (mean functions/kernels), leading to a large
181
+ number of ways to model your data.
182
+
183
+ The best way to get a feeling for which setup might be the best for your specific needs is to play
184
+ around with `generate_data` and varying configurations and parameters until you get something that looks like
185
+ your specific dataset.
186
+
187
+ ---
188
+ ## Troubleshooting
189
+
190
+ As with any GP-based framework, mimosa is subject to numerical stability issues.
191
+
192
+ We highly recommend to use Jax' 64bit precision:
193
+
194
+ ```python
195
+ import jax
196
+ jax.config.update("jax_enable_x64", True) # Should be called before any other jax/kernax/mimosa import
197
+ # ...other imports
198
+ ```
199
+
200
+ If you still have troubles (NaN in hyperpost/likelihoods, optimisation does not converge, odd-looking mean
201
+ processes/predictions/samples, ...), consider increasing the `jitter` used in the specific component or
202
+ directly at the Model level:
203
+
204
+ ```python
205
+ model = BasicModel(prng_key=key, n_clusters=K, jitter=jnp.asarray(1e-5))
206
+ ```
207
+
208
+ By default, Mimosa's jitter is fixed at 1e-8 for every component of the framework.
209
+
210
+ ---
211
+ ## Authors and citation
212
+
213
+ MIMOSA is primarily developed by the *Magma Task Force*, composed of:
214
+
215
+ * [Arthur Leroy](https://arthur-leroy.netlify.app/), researcher at Paris Saclay and INRAe (FR), main author of the original tool [MagmaClustR](https://arthurleroy.github.io/MagmaClustR/) and coordinator of the Task Force.
216
+ * [Simon Lejoly](https://researchportal.unamur.be/fr/persons/slejoly/), PhD student at UNamur (BE), main developper of the package and author of the [Kernax package](https://github.com/SimLej18/kernax-ml)
217
+ * [Alexia Grenouillat]([TODO]), PhD student at INSA Toulouse (FR), developper of multi-feature correlation discovery.
218
+ * [Térence Viellard]([TODO]), PhD student at INRAe (FR), working on sparse approximations and scalability.
219
+
220
+ If you use the package for your research, please consider citing the following paper:
221
+
222
+ [TODO]
223
+
224
+ If your research field could provide an interesting example of using MIMOSA, please consider publishing a toy example in
225
+ the documentation [TODO].
226
+
227
+ ---
228
+ ## Contributing
229
+
230
+ At this stage of development, we are not yet accepting contributions to the codebase. However, if you are interested
231
+ in contributing to the project, please feel free to reach out to us via email or through our GitHub repository.
232
+
233
+ ---
234
+ ## License
235
+
236
+ This work is distributed under the [MIT License](https://opensource.org/licenses/MIT). See `LICENSE` for more information.
237
+
238
+ ---
239
+
240
+
@@ -0,0 +1,215 @@
1
+ # MIMOSA: Multi-Input Multi-Output Sample Analysis
2
+
3
+ A fully-featured *multi-task Gaussian process framework* for analysing functional data.
4
+ It is based on the [MagmaClust framework](https://jmlr.org/papers/v24/20-1321.html), with many enhancements for efficiency and modularity.
5
+
6
+ Its core features currently include:
7
+ * Joint learning across multiple samples (Multi-Task GPs) with unaligned sampling grids
8
+ * Clustering of samples
9
+ * Multi-dimensional inputs and outputs
10
+ * Probabilistic predictions with uncertainty quantification
11
+ * A multitude of training configuration to model complex relationships between tasks, clusters and inputs
12
+ * Deep kernax integration for complex kernels/means functions
13
+ * Support for training and predicting on GPUs and TPUs
14
+ * Full Jax/Equinox compatibility for vmap/grad/jit
15
+
16
+ Towards v1.0.0, we plan to add:
17
+ * Inter-output correlation learning
18
+ * Adaptation to non-gaussian data and classification tasks
19
+ * Sparse learning and approximations for scalability
20
+ * Visualisation tools for data and model outputs
21
+ * Clever initialisation for hyper-parameters of the models
22
+
23
+ > **⚠️ Project Status**: MIMOSA is currently in early development.
24
+ > While current features are functional in most cases, bugs can happen.
25
+ > The API and features are still subject to change.
26
+ > If you use the package for research/production, we encourage you to version-lock your mimosa dependency.
27
+
28
+ ---
29
+ ## Installation
30
+
31
+ You can install mimosa through pip:
32
+
33
+ ```bash
34
+ pip install mimosa-ml
35
+ ```
36
+
37
+ You can then import components of the package as:
38
+
39
+ ```python
40
+ from mimosa.hyperpost import Hyperpost # Import example
41
+ ```
42
+
43
+ N.b.: notice the difference between `mimosa-ml` (the PyPI ID of the package) and `mimosa` (the internal package name).
44
+
45
+ Python compatibility: mimosa is compatible with Python 3.10+.
46
+ We encourage using a more recent version to be compatible with latest releases of Jax and Equinox.
47
+
48
+ ---
49
+ ## Philosophy
50
+
51
+ We basically took Gaussian processes, and combined them with a ton of ✨*fancy components*✨
52
+ * ➡️ Multi-task learning based on [Magma](https://jmlr.org/papers/v24/20-1321.html)
53
+ * ➡️ Clustering as a mixture of Magma GPs
54
+ * ➡️ Multi-dimensional inputs thanks to efficient kernels from [Kernax](https://github.com/SimLej18/kernax-ml)
55
+ * ➡️ Multi-dimensional uncorrelated outputs by simply broadcasting the algorithm to another dimension
56
+ * ➡️ Multi-output correlation discovery by learning a [convolution process]([TODO]) with specific kernel
57
+
58
+
59
+ We use **JAX** as a back-end for every computation!
60
+ `jit` compilation saves us a lot of time,
61
+ `vmap` allows us to efficiently batch over all dimensions of the data and parameters,
62
+ `grad` spares us the hastle of implementing gradients for every component of the model,
63
+ and XLA support allows us to train and predict on GPUs and TPUs for scalability.
64
+
65
+ A GP library is nothing without a fast and modular **Kernel library**.
66
+ MIMOSA relies on the efficiency-focused [Kernax package](https://github.com/SimLej18/kernax-ml) for every kernel use
67
+ throughout the algorithms.
68
+
69
+ ---
70
+ ## Examples
71
+
72
+ Basic examples can be found in the `examples` directory. A quick example using the top-level API from Model can be found here:
73
+
74
+ ```python
75
+ import jax.random as jr
76
+ from jax import vmap
77
+ from kernax import ZeroMean, VarianceKernel, SEKernel, WhiteNoiseKernel
78
+
79
+ from mimosa.data_structures import Dimensions, Parameters, ModelConfig
80
+ from mimosa.synthetic import generate_data
81
+ from mimosa.models import BasicModel
82
+ from mimosa.grid import UnionGrid
83
+ from mimosa.plot import plot_dataset, plot_clusters, plot_single_task_prediction
84
+ from mimosa.sampling import sample_gp
85
+
86
+ key = jr.PRNGKey(0)
87
+
88
+ # 20 tasks, 2 clusters, 1D inputs/outputs, 25 points/task
89
+ dims = Dimensions(T=20, K=2, I=1, O=1, F=1, N=25, G=50)
90
+ config = ModelConfig(isotopic_tasks=False)
91
+
92
+ # Ground-truth parameters used to generate the synthetic dataset
93
+ init_params = Parameters(
94
+ cluster_mean=ZeroMean(),
95
+ cluster_kernel=VarianceKernel(1.0) * SEKernel(length_scale=1.0),
96
+ task_kernel=VarianceKernel(0.1) * SEKernel(length_scale=2.0),
97
+ noise_kernel=WhiteNoiseKernel(noise=0.01),
98
+ )
99
+
100
+ key, subkey = jr.split(key)
101
+ dataset, grid, hyperprior, mixture, parameters, cluster_means, tasks = generate_data(
102
+ subkey, dims, init_params, config, input_range=(-2.5, 2.5))
103
+
104
+ # Fit a model on the generated dataset, starting from the same parameters
105
+ fit_grid = UnionGrid()(dataset.inputs)
106
+ model = BasicModel(jr.PRNGKey(1), n_clusters=dims.K)
107
+ fitted_params, fitted_mixture = model.fit(dataset, fit_grid, mixture.proportions, parameters, n_iter=50)
108
+
109
+ # Predict the posterior distribution of every task, in every cluster
110
+ predictions = model.predict(dataset, fit_grid, fitted_mixture, fitted_params)
111
+ hyperposterior = model.hyperpost(dataset, fit_grid, fitted_mixture, fitted_params)
112
+
113
+ # Plot the fitted mean-processes over the dataset
114
+ fig, ax = plot_dataset(dataset, mixture=mixture, alpha=.3)
115
+ fig, ax = plot_clusters(fit_grid, hyperposterior=hyperposterior, fig=fig, ax=ax, legend=False)
116
+ ```
117
+
118
+ ![Fitted mean-processes over the dataset](docs/images/mean_processes.png)
119
+
120
+ ```python
121
+ # Draw samples from task 0's predictive distribution and plot them
122
+ t_id, o_id = 0, 0
123
+ k_id = int(fitted_mixture.assignments[t_id]) # task's dominant cluster
124
+ prediction = predictions[t_id, k_id, o_id]
125
+
126
+ key, sample_key = jr.split(key)
127
+ sample_keys = jr.split(sample_key, 64)
128
+ samples = vmap(lambda k: sample_gp(k, prediction.mean, prediction.covariance))(sample_keys)
129
+
130
+ fig, ax = plot_single_task_prediction(
131
+ dataset, fit_grid, hyperposterior, fitted_mixture, t_id, o_id, samples=samples)
132
+ ```
133
+
134
+ ![Prediction samples for task 0](docs/images/task0_prediction_samples.png)
135
+
136
+ MIMOSA is designed to have multiple layer of customisation. The "Model" API covers the most general use case of the
137
+ algorithm, but you should consider building your own training loops and combining/developping your own sub-modules to
138
+ create tailored models and pipelines.
139
+
140
+ ---
141
+ ## About configurations
142
+
143
+ MIMOSA has many training configurations to make it as precise as possible when modelling your specific data.
144
+ These configurations are stored in a `ModelConfig` dataclass.
145
+ Here is a quick overview of what each configuration option does.
146
+
147
+ * `shared_task_hps` (default `True`): whether task kernel/noise hyper-parameters are shared across all tasks, or learnt independently per task.
148
+ * `shared_cluster_hps` (default `True`): whether cluster mean/kernel hyper-parameters are shared across all clusters (mean-processes), or learnt independently per cluster.
149
+ * `shared_output_hps` (default `True`): whether hyper-parameters are shared across output dimensions, or learnt independently per output.
150
+ * `shared_features_hps` (default `True`): whether hyper-parameters are shared across features, or learnt independently per feature.
151
+ * `cluster_specific_task_hps` (default `True`): whether the task/noise kernels themselves vary depending on the cluster a task belongs to, or are shared across clusters.
152
+ * `isotopic_tasks` (default `True`): whether all tasks are observed at the same input locations, or each task has its own set of inputs.
153
+ * `isotopic_features` (default `True`): whether all features are observed at the same input locations, or each feature has its own set of inputs.
154
+
155
+ These configurations are independent of your choices of parameters (mean functions/kernels), leading to a large
156
+ number of ways to model your data.
157
+
158
+ The best way to get a feeling for which setup might be the best for your specific needs is to play
159
+ around with `generate_data` and varying configurations and parameters until you get something that looks like
160
+ your specific dataset.
161
+
162
+ ---
163
+ ## Troubleshooting
164
+
165
+ As with any GP-based framework, mimosa is subject to numerical stability issues.
166
+
167
+ We highly recommend to use Jax' 64bit precision:
168
+
169
+ ```python
170
+ import jax
171
+ jax.config.update("jax_enable_x64", True) # Should be called before any other jax/kernax/mimosa import
172
+ # ...other imports
173
+ ```
174
+
175
+ If you still have troubles (NaN in hyperpost/likelihoods, optimisation does not converge, odd-looking mean
176
+ processes/predictions/samples, ...), consider increasing the `jitter` used in the specific component or
177
+ directly at the Model level:
178
+
179
+ ```python
180
+ model = BasicModel(prng_key=key, n_clusters=K, jitter=jnp.asarray(1e-5))
181
+ ```
182
+
183
+ By default, Mimosa's jitter is fixed at 1e-8 for every component of the framework.
184
+
185
+ ---
186
+ ## Authors and citation
187
+
188
+ MIMOSA is primarily developed by the *Magma Task Force*, composed of:
189
+
190
+ * [Arthur Leroy](https://arthur-leroy.netlify.app/), researcher at Paris Saclay and INRAe (FR), main author of the original tool [MagmaClustR](https://arthurleroy.github.io/MagmaClustR/) and coordinator of the Task Force.
191
+ * [Simon Lejoly](https://researchportal.unamur.be/fr/persons/slejoly/), PhD student at UNamur (BE), main developper of the package and author of the [Kernax package](https://github.com/SimLej18/kernax-ml)
192
+ * [Alexia Grenouillat]([TODO]), PhD student at INSA Toulouse (FR), developper of multi-feature correlation discovery.
193
+ * [Térence Viellard]([TODO]), PhD student at INRAe (FR), working on sparse approximations and scalability.
194
+
195
+ If you use the package for your research, please consider citing the following paper:
196
+
197
+ [TODO]
198
+
199
+ If your research field could provide an interesting example of using MIMOSA, please consider publishing a toy example in
200
+ the documentation [TODO].
201
+
202
+ ---
203
+ ## Contributing
204
+
205
+ At this stage of development, we are not yet accepting contributions to the codebase. However, if you are interested
206
+ in contributing to the project, please feel free to reach out to us via email or through our GitHub repository.
207
+
208
+ ---
209
+ ## License
210
+
211
+ This work is distributed under the [MIT License](https://opensource.org/licenses/MIT). See `LICENSE` for more information.
212
+
213
+ ---
214
+
215
+
@@ -0,0 +1,140 @@
1
+ """
2
+ Basic usage example of mimosa-ml.
3
+
4
+ Walks through the full pipeline: configure dimensions -> generate a synthetic dataset and remove
5
+ some points at random -> plot the raw dataset -> fit a BasicModel -> plot the fitted clusters ->
6
+ predict a task's output -> plot the prediction (mean + confidence interval) and samples from it.
7
+
8
+ Meant to be run cell-by-cell (e.g. in PyCharm/VSCode's "#%%" notebook mode), or as a plain script.
9
+ """
10
+ import jax
11
+
12
+ jax.config.update("jax_enable_x64", True)
13
+ jax.config.update("jax_disable_jit", False)
14
+ import jax.random as jr
15
+ import jax.numpy as jnp
16
+ from jax import vmap
17
+ import matplotlib.pyplot as plt
18
+
19
+ from kernax import ZeroMean, VarianceKernel, SEKernel, WhiteNoiseKernel
20
+
21
+ from mimosa import (
22
+ Dimensions, ModelConfig, DataRemovalConfig, Parameters,
23
+ BasicModel, generate_data, RandomDataRemover, save_csv, load_csv, build_parameters,
24
+ )
25
+ from mimosa.grid import UnionGrid
26
+ from mimosa.plot import plot_dataset, plot_clusters, plot_single_task_prediction
27
+ from mimosa.sampling import sample_gp
28
+
29
+ key = jr.PRNGKey(42)
30
+ plt.rcParams['figure.dpi']=300
31
+
32
+ #%% 1. Configuration
33
+ # Dimensions: T tasks, K clusters, I/O input/output dims, N points observed
34
+ # per task, G points in the full grid.
35
+ dims = Dimensions(T=32, K=2, I=1, O=2, F=1, N=50, G=150)
36
+
37
+ # ModelConfig controls which hyperparameters are shared (across tasks/clusters/outputs/features) and
38
+ # whether tasks/features share input locations.
39
+ model_config = ModelConfig(
40
+ shared_task_hps=True,
41
+ shared_cluster_hps=True,
42
+ shared_output_hps=True,
43
+ cluster_specific_task_hps=False,
44
+ isotopic_tasks=False,
45
+ )
46
+
47
+ # How many points to remove at random per task, to simulate missing data.
48
+ removal_config = DataRemovalConfig(max_missing=5, random_missing_count=True, same_missing_across_outputs=False)
49
+
50
+ #%% 2. Generative parameters
51
+ # These are the "true" parameters used to synthesise the toy dataset below. Swap any kernel/mean for
52
+ # another kernax one (e.g. MaternKernel, PeriodicKernel, LinearMean, ...) to change the shape of the
53
+ # data generated.
54
+ true_params = Parameters(
55
+ cluster_mean=ZeroMean(),
56
+ cluster_kernel=VarianceKernel(5.0) * SEKernel(length_scale=.5),
57
+ task_kernel=VarianceKernel(1.0) * SEKernel(length_scale=.4),
58
+ noise_kernel=WhiteNoiseKernel(noise=.05),
59
+ )
60
+
61
+ #%% 3. Generate synthetic data, then remove points at random
62
+ key, gen_key, removal_key = jr.split(key, 3)
63
+
64
+ dataset, grid, hyperprior, true_mixture, true_params, cluster_means, tasks = generate_data(
65
+ gen_key, dims, true_params, model_config, input_range=(-2.5, 2.5)
66
+ )
67
+ dataset = RandomDataRemover()(removal_key, dataset, removal_config)
68
+
69
+ #%% 3bis. Alternatively, you can load a dataset from a local file through load_csv.
70
+ # Check load_csv's doc or open the csv file to see the expected file format.
71
+ save_csv("./dummy.csv", dataset)
72
+ dataset = load_csv("./dummy.csv")
73
+
74
+ #%% 4. Plot the raw dataset (coloured by each task's true cluster)
75
+ fig, ax = plot_dataset(dataset, mixture=true_mixture, figsize=(8*dims.O, 6))
76
+ fig.suptitle("Synthetic dataset (colored by true cluster)")
77
+ plt.show()
78
+
79
+ #%% 5. Instantiate the model
80
+ # n_clusters can differ from the true K above (the model doesn't know it); jitter is the numerical
81
+ # stabiliser added before Cholesky factorizations, only increase it if you hit factorization errors.
82
+ key, model_key = jr.split(key)
83
+ model = BasicModel(prng_key=model_key, n_clusters=dims.K)
84
+
85
+ # Starting guess for the parameters to fit. In practice these would be a rough, uninformed guess
86
+ # rather than the true generative ones — feel free to try different starting kernels/values here.
87
+ init_params = Parameters(
88
+ cluster_mean=ZeroMean(),
89
+ cluster_kernel=VarianceKernel(2.0) * SEKernel(length_scale=1.),
90
+ task_kernel=VarianceKernel(.5) * SEKernel(length_scale=.5),
91
+ noise_kernel=WhiteNoiseKernel(noise=0.5))
92
+
93
+ # build_parameters batches the base kernels/mean below to match model_config's sharing structure
94
+ # (same helper generate_data uses internally), so their shapes line up with what model.fit expects.
95
+ init_params = build_parameters(init_params, dims, model_config)
96
+
97
+ # proportions of the dataset in each cluster, a priori
98
+ mixture_proportions = jnp.repeat(1 / dims.K, dims.K) # fixed, equal weight per cluster
99
+
100
+ #%% 6. Fit
101
+ # Grid construction (union of every task's input points) isn't jit-compatible, so it's built once
102
+ # here by the caller, outside of fit/predict, rather than owned by the model — see
103
+ # mimosa.grid.GridBuilder. Swap UnionGrid for another GridBuilder to change how the grid is built.
104
+ fitted_grid = UnionGrid()(dataset.inputs)
105
+
106
+ fitted_params, fitted_mixture = model.fit(dataset, fitted_grid, mixture_proportions, init_params, n_iter=50)
107
+
108
+ #%% 7. Plot the fitted clusters (mean-processes)
109
+ hyperposterior = model.hyperpost(dataset, fitted_grid, fitted_mixture, fitted_params, jitter=model.jitter)
110
+
111
+ fig, ax = plot_dataset(dataset, mixture=true_mixture, figsize=(8*dims.O, 6), alpha=.1)
112
+ fig, ax = plot_clusters(fitted_grid, hyperposterior=hyperposterior, figsize=(8*dims.O, 6), fig=fig, ax=ax)
113
+ fig.suptitle("Fitted clusters (mean-processes) on the dataset")
114
+ plt.show()
115
+
116
+ #%% 8. Predict
117
+ predictions = model.predict(dataset, fitted_grid, fitted_mixture, fitted_params) # MultivariateNormal, batched (T, K, O, G)
118
+
119
+ t_id, o_id = 0, 0
120
+ k_id = int(fitted_mixture.assignments[t_id]) # task's dominant cluster
121
+ prediction = predictions[t_id, k_id, o_id]
122
+
123
+ #%% 9. Plot the prediction: observed points, cluster means, and predictive mean + confidence interval
124
+ fig, ax = plot_single_task_prediction(
125
+ dataset, fitted_grid, hyperposterior, fitted_mixture, t_id, o_id, prediction=prediction, figsize=(8*dims.O, 6)
126
+ )
127
+ fig.suptitle(f"Prediction — task {t_id}, output {o_id}")
128
+ plt.show()
129
+
130
+ #%% 10. Draw samples from the prediction and plot them alongside it
131
+ key, sample_key = jr.split(key)
132
+ n_samples = 64
133
+ sample_keys = jr.split(sample_key, n_samples)
134
+ samples = vmap(lambda k: sample_gp(k, prediction.mean, prediction.covariance))(sample_keys) # (S, G)
135
+
136
+ fig, ax = plot_single_task_prediction(
137
+ dataset, fitted_grid, hyperposterior, fitted_mixture, t_id, o_id, samples=samples, figsize=(8*dims.O, 6)
138
+ )
139
+ fig.suptitle(f"Prediction samples — task {t_id}, output {o_id}")
140
+ plt.show()