origami-astro 0.1.0__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.
- origami_astro-0.1.0/LICENSE +21 -0
- origami_astro-0.1.0/PKG-INFO +408 -0
- origami_astro-0.1.0/README.md +353 -0
- origami_astro-0.1.0/origami/__init__.py +9 -0
- origami_astro-0.1.0/origami/cli.py +183 -0
- origami_astro-0.1.0/origami/compare.py +123 -0
- origami_astro-0.1.0/origami/config.py +239 -0
- origami_astro-0.1.0/origami/embedders.py +95 -0
- origami_astro-0.1.0/origami/features.py +101 -0
- origami_astro-0.1.0/origami/lightcurves.py +167 -0
- origami_astro-0.1.0/origami/models/__init__.py +45 -0
- origami_astro-0.1.0/origami/models/astromer.py +77 -0
- origami_astro-0.1.0/origami/models/chronos.py +78 -0
- origami_astro-0.1.0/origami/models/mantis.py +63 -0
- origami_astro-0.1.0/origami/models/moirai.py +99 -0
- origami_astro-0.1.0/origami/models/moment.py +60 -0
- origami_astro-0.1.0/origami/models/starclr.py +270 -0
- origami_astro-0.1.0/origami/models/timestral.py +88 -0
- origami_astro-0.1.0/origami/models/toto.py +87 -0
- origami_astro-0.1.0/origami/tasks.py +161 -0
- origami_astro-0.1.0/origami/transforms.py +154 -0
- origami_astro-0.1.0/origami_astro.egg-info/PKG-INFO +408 -0
- origami_astro-0.1.0/origami_astro.egg-info/SOURCES.txt +38 -0
- origami_astro-0.1.0/origami_astro.egg-info/dependency_links.txt +1 -0
- origami_astro-0.1.0/origami_astro.egg-info/entry_points.txt +2 -0
- origami_astro-0.1.0/origami_astro.egg-info/requires.txt +46 -0
- origami_astro-0.1.0/origami_astro.egg-info/top_level.txt +1 -0
- origami_astro-0.1.0/pyproject.toml +56 -0
- origami_astro-0.1.0/setup.cfg +4 -0
- origami_astro-0.1.0/tests/test_cli.py +118 -0
- origami_astro-0.1.0/tests/test_compare.py +153 -0
- origami_astro-0.1.0/tests/test_lightcurves.py +112 -0
- origami_astro-0.1.0/tests/test_model_astromer.py +69 -0
- origami_astro-0.1.0/tests/test_model_chronos.py +19 -0
- origami_astro-0.1.0/tests/test_model_mantis.py +54 -0
- origami_astro-0.1.0/tests/test_model_moirai.py +100 -0
- origami_astro-0.1.0/tests/test_model_moment.py +63 -0
- origami_astro-0.1.0/tests/test_model_starclr.py +86 -0
- origami_astro-0.1.0/tests/test_model_timestral.py +59 -0
- origami_astro-0.1.0/tests/test_model_toto.py +52 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Lorenzo Monti
|
|
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,408 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: origami-astro
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Fold, embed, probe: compare foundation-model embeddings, hand-crafted and catalogue features of astronomical light curves.
|
|
5
|
+
Author-email: Lorenzo Monti <lorenzomonti42@gmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Repository, https://github.com/LorenzoMonti/origami.git
|
|
8
|
+
Project-URL: Documentation, https://github.com/LorenzoMonti/origami#readme
|
|
9
|
+
Project-URL: Issues, https://github.com/LorenzoMonti/origami/issues
|
|
10
|
+
Keywords: astronomy,light curves,time series,foundation models,embeddings,benchmark
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: numpy>=1.22
|
|
21
|
+
Requires-Dist: scipy>=1.10
|
|
22
|
+
Requires-Dist: pandas>=1.5
|
|
23
|
+
Requires-Dist: scikit-learn>=1.3
|
|
24
|
+
Requires-Dist: pyyaml>=6.0
|
|
25
|
+
Requires-Dist: tabulate>=0.9
|
|
26
|
+
Provides-Extra: features
|
|
27
|
+
Requires-Dist: light-curve>=0.9; extra == "features"
|
|
28
|
+
Provides-Extra: chronos
|
|
29
|
+
Requires-Dist: torch>=2.0; extra == "chronos"
|
|
30
|
+
Requires-Dist: chronos-forecasting>=2.0; extra == "chronos"
|
|
31
|
+
Provides-Extra: mantis
|
|
32
|
+
Requires-Dist: torch>=2.0; extra == "mantis"
|
|
33
|
+
Requires-Dist: mantis-tsfm>=1.1; extra == "mantis"
|
|
34
|
+
Provides-Extra: astromer
|
|
35
|
+
Requires-Dist: onnxruntime>=1.15; extra == "astromer"
|
|
36
|
+
Requires-Dist: huggingface_hub>=0.20; extra == "astromer"
|
|
37
|
+
Provides-Extra: starclr
|
|
38
|
+
Requires-Dist: torch>=2.0; extra == "starclr"
|
|
39
|
+
Requires-Dist: safetensors>=0.4; extra == "starclr"
|
|
40
|
+
Provides-Extra: timestral
|
|
41
|
+
Requires-Dist: torch>=2.4; extra == "timestral"
|
|
42
|
+
Provides-Extra: moirai
|
|
43
|
+
Requires-Dist: uni2ts>=2.0; extra == "moirai"
|
|
44
|
+
Requires-Dist: torch<2.5,>=2.1; extra == "moirai"
|
|
45
|
+
Requires-Dist: transformers<4.57; extra == "moirai"
|
|
46
|
+
Provides-Extra: moment
|
|
47
|
+
Requires-Dist: torch>=2.0; extra == "moment"
|
|
48
|
+
Requires-Dist: momentfm>=0.1.4; extra == "moment"
|
|
49
|
+
Provides-Extra: toto
|
|
50
|
+
Requires-Dist: torch>=2.5; extra == "toto"
|
|
51
|
+
Requires-Dist: toto-models>=1.0; python_version >= "3.12" and extra == "toto"
|
|
52
|
+
Provides-Extra: dev
|
|
53
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
54
|
+
Dynamic: license-file
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<picture>
|
|
58
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/LorenzoMonti/origami/main/docs/logo-dark.svg">
|
|
59
|
+
<img src="https://raw.githubusercontent.com/LorenzoMonti/origami/main/docs/logo.svg" alt="origami" width="300">
|
|
60
|
+
</picture>
|
|
61
|
+
</p>
|
|
62
|
+
|
|
63
|
+
<p align="center"><b>Fold, embed, probe.</b><br>
|
|
64
|
+
Compare foundation-model embeddings, hand-crafted features and catalogue columns
|
|
65
|
+
of astronomical light curves, under identical conditions.</p>
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
`origami` answers one kind of question: **which representation of a light curve carries
|
|
70
|
+
the information you need, and how robust is it?** It puts every candidate on the same
|
|
71
|
+
footing:
|
|
72
|
+
- the same objects;
|
|
73
|
+
- the same (sub)sampled epochs;
|
|
74
|
+
- the same folds;
|
|
75
|
+
- the same simple probe.
|
|
76
|
+
|
|
77
|
+
Candidates can be embeddings from frozen time-series foundation models, classical features,
|
|
78
|
+
values from a catalogue, or your own model. Typical questions:
|
|
79
|
+
- Do embeddings from a pretrained model add anything to Fourier parameters for predicting a
|
|
80
|
+
physical quantity?
|
|
81
|
+
- Which model separates my classes best, and does that survive when curves have 20
|
|
82
|
+
epochs instead of 200?
|
|
83
|
+
- Does a representation learned on bright objects transfer to faint ones, or from one
|
|
84
|
+
survey to another?
|
|
85
|
+
|
|
86
|
+
`origami` is a benchmarking and selection tool. It does not train foundation models, and
|
|
87
|
+
it is not a classifier for producing catalogues.
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
pip install "origami-astro[features,chronos]"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Highlights**
|
|
94
|
+
- **Light curves:** irregular, single-band, any length, each with a provenance tag
|
|
95
|
+
(survey, band).
|
|
96
|
+
- **Models:** 31 checkpoints from 10 model families behind one interface (Chronos,
|
|
97
|
+
Chronos-Bolt, Chronos-2, Moirai, MOMENT, Mantis, Toto 2.0, Timestral, Astromer, StarCLR).
|
|
98
|
+
Weights are downloaded on first use.
|
|
99
|
+
- **Tasks:** regression, classification, clustering and anomaly detection. Evaluation can use
|
|
100
|
+
cross-validation, an explicit train/test split, or metrics per group.
|
|
101
|
+
- **Robustness tests:** controlled epoch subsampling, identical for every representation.
|
|
102
|
+
- **Clusters:** a YAML + command-line workflow runs one SLURM array task per model, works on
|
|
103
|
+
compute nodes without internet, and collects everything into tables at the end.
|
|
104
|
+
|
|
105
|
+
## Contents
|
|
106
|
+
- [Quick start](#quick-start)
|
|
107
|
+
- [Concepts](#concepts)
|
|
108
|
+
- [Light curves](#light-curves)
|
|
109
|
+
- [Input transforms](#input-transforms)
|
|
110
|
+
- [Representations](#representations)
|
|
111
|
+
- [Tasks and metrics](#tasks-and-metrics)
|
|
112
|
+
- [Command-line workflow](#command-line-workflow)
|
|
113
|
+
- [Models](#models)
|
|
114
|
+
- [Installation and environments](#installation-and-environments)
|
|
115
|
+
- [Good practice](#good-practice)
|
|
116
|
+
- [Adding a model](#adding-a-model)
|
|
117
|
+
- [Licence](#licence)
|
|
118
|
+
|
|
119
|
+
## Quick start
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
import origami as ori
|
|
123
|
+
import pandas as pd
|
|
124
|
+
|
|
125
|
+
cat = pd.read_csv("catalog.csv") # one row per object: id, period, target, ...
|
|
126
|
+
lcs = ori.LightCurves.from_csv_dir("light_curves/", # one CSV per object: time, mag, err
|
|
127
|
+
ids=cat["id"], err_col="mag_err", survey="ztf", band="r")
|
|
128
|
+
lcs = lcs.with_periods(cat["period"]) # needed by folded inputs and Fourier features
|
|
129
|
+
|
|
130
|
+
reps = {
|
|
131
|
+
"chronos": ori.Embedder("chronos-bolt-small", input="folded-grid"),
|
|
132
|
+
"mantis": ori.Embedder("mantis-v2", input="folded-grid"),
|
|
133
|
+
"fourier": ori.HandCrafted("fourier"),
|
|
134
|
+
"physical": ori.HandCrafted("physical"),
|
|
135
|
+
"period": ori.Catalog(cat, ["period"]),
|
|
136
|
+
}
|
|
137
|
+
res = ori.compare(lcs, cat["target"], reps, task="regression",
|
|
138
|
+
combine=[("chronos", "physical"), ("mantis", "physical"), ("fourier", "period")],
|
|
139
|
+
subsample_epochs=["all", 50, 20], seeds=[0, 1, 2])
|
|
140
|
+
|
|
141
|
+
print(res.table()) # primary metric (RMSE): rows = representations, columns = epoch levels
|
|
142
|
+
res.records # every run with all metrics, as a DataFrame
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Concepts
|
|
146
|
+
|
|
147
|
+
### Light curves
|
|
148
|
+
`LightCurves` holds a set of single-band curves. Each curve has:
|
|
149
|
+
- its own time, magnitude and error arrays (any length);
|
|
150
|
+
- an identifier;
|
|
151
|
+
- a provenance tag (`survey`, `band`);
|
|
152
|
+
- optionally a period, a reference epoch and the period's origin (`"catalog"` or `"estimated"`).
|
|
153
|
+
|
|
154
|
+
| constructor | input |
|
|
155
|
+
|---|---|
|
|
156
|
+
| `LightCurves.from_csv_dir(dir, ids=..., ...)` | one CSV per object; magnitudes with errors, or fluxes (errors are then converted) |
|
|
157
|
+
| `LightCurves.from_frame(df, id_col=..., ...)` | a long table, one row per observation |
|
|
158
|
+
| `LightCurves.from_arrays(times, mags, errs, ...)` | lists of arrays |
|
|
159
|
+
|
|
160
|
+
Other operations:
|
|
161
|
+
- `lcs.with_periods(periods, epochs=None)` attaches periods.
|
|
162
|
+
- `lcs.subsample(k, seed)` keeps k random epochs per curve. The selection is reproducible and
|
|
163
|
+
does not depend on the other curves in the set.
|
|
164
|
+
|
|
165
|
+
### Input transforms
|
|
166
|
+
How a curve becomes the sequence a model sees. Set it per embedder with `input=`.
|
|
167
|
+
|
|
168
|
+
| `input` | sequence | needs a period |
|
|
169
|
+
|---|---|---|
|
|
170
|
+
| `raw` | magnitudes in time order, z-normalised, with real timestamps | no |
|
|
171
|
+
| `folded` | magnitudes sorted by phase, z-normalised | yes |
|
|
172
|
+
| `folded-grid` | phase-folded curve resampled on a regular grid (default 200 points), z-normalised, maximum light at phase 0 | yes |
|
|
173
|
+
| `padded-starembed` | last 200 points, zero left-padding: the protocol of [StarEmbed](https://arxiv.org/abs/2510.06200), for comparison | no |
|
|
174
|
+
|
|
175
|
+
How `folded-grid` resamples the curve:
|
|
176
|
+
- It uses a smoothing spline, with automatic smoothing chosen by GCV.
|
|
177
|
+
- If that fit collapses to a near-linear curve, it falls back to a Fourier series whose
|
|
178
|
+
number of harmonics is chosen by BIC.
|
|
179
|
+
- The curve is aligned on maximum light, so the sequence does not depend on the reference epoch.
|
|
180
|
+
|
|
181
|
+
Every transform also passes, for each curve, the times and the magnitude scale removed by
|
|
182
|
+
z-normalisation. Models that use timestamps receive the times; models trained on unscaled
|
|
183
|
+
magnitudes get the scale back.
|
|
184
|
+
|
|
185
|
+
### Representations
|
|
186
|
+
Anything with a `name` and a `transform(lcs) -> array (n_curves, dim)` method.
|
|
187
|
+
|
|
188
|
+
| class | what it gives |
|
|
189
|
+
|---|---|
|
|
190
|
+
| `Embedder(model, input=...)` | frozen foundation-model embedding: encoder states mean-pooled over the positions that hold real data; cached on disk |
|
|
191
|
+
| `HandCrafted("light-curve")` | about 30 period-free statistics from the [`light-curve`](https://github.com/light-curve/light-curve-python) package |
|
|
192
|
+
| `HandCrafted("fourier", n_harmonics=3)` | Fourier amplitudes and cos/sin of φ21, φ31 on the folded curve |
|
|
193
|
+
| `HandCrafted("physical")` | log period and folded peak-to-peak amplitude |
|
|
194
|
+
| `Catalog(table, columns)` | columns of an external table, row-aligned with the curves |
|
|
195
|
+
| your own object | e.g. an autoencoder: anything implementing `transform(lcs)` |
|
|
196
|
+
|
|
197
|
+
`combine=[("a", "b"), ...]` evaluates concatenations of representations. In distance-based
|
|
198
|
+
tasks each concatenated block is weighted by 1/√width, so a narrow feature block is not
|
|
199
|
+
outweighed by a wide embedding.
|
|
200
|
+
|
|
201
|
+
### Tasks and metrics
|
|
202
|
+
| `task` | probe | metrics |
|
|
203
|
+
|---|---|---|
|
|
204
|
+
| `regression` | standardised ridge regression (RidgeCV) | RMSE, MAE |
|
|
205
|
+
| `classification` | standardised logistic regression with balanced class weights | balanced accuracy, macro F1 |
|
|
206
|
+
| `clustering` | k-means (k = number of classes), HDBSCAN, or [CLiMB](https://github.com/LorenzoMonti/CLiMB) | ARI, NMI |
|
|
207
|
+
| `anomaly` | kNN distance or isolation forest, fitted on the normal objects of the training folds (`y` = 1 for anomalies) | AUROC, average precision |
|
|
208
|
+
|
|
209
|
+
The probes are deliberately simple and fixed, so that results measure the representation
|
|
210
|
+
and not the model on top of it.
|
|
211
|
+
|
|
212
|
+
Evaluation options of `compare`:
|
|
213
|
+
- **`folds`**: defaults to 5-fold cross-validation, stratified for classification and
|
|
214
|
+
anomaly. Pass your own fold index to reuse an existing protocol.
|
|
215
|
+
- **`split=(train_mask, test_mask)`**: train on one subset and score another, e.g. bright
|
|
216
|
+
versus faint, or one survey versus another.
|
|
217
|
+
- **`groups=labels`**: also report metrics per group, e.g. magnitude bins or classes. Read
|
|
218
|
+
them with `res.group_table()`.
|
|
219
|
+
- **`subsample_epochs` and `seeds`**: thin every curve to the given numbers of epochs,
|
|
220
|
+
identically for all representations.
|
|
221
|
+
- **Task options** are passed through, e.g. `method="hdbscan"`, `detector="isolation-forest"`
|
|
222
|
+
or `pca=20`.
|
|
223
|
+
|
|
224
|
+
## Command-line workflow
|
|
225
|
+
|
|
226
|
+
For large runs, especially on clusters whose compute nodes have no internet access, an
|
|
227
|
+
experiment is described by one YAML file:
|
|
228
|
+
|
|
229
|
+
```yaml
|
|
230
|
+
name: my_experiment
|
|
231
|
+
output: /path/to/runs/my_experiment
|
|
232
|
+
data:
|
|
233
|
+
light_curves: /path/to/light_curves # one CSV per object, "{id}.csv"
|
|
234
|
+
catalog: /path/to/catalog.csv # one row per object
|
|
235
|
+
id_col: id
|
|
236
|
+
time_col: time
|
|
237
|
+
mag_col: mag
|
|
238
|
+
err_col: mag_err # or flux_col + flux_err_col
|
|
239
|
+
survey: ztf
|
|
240
|
+
band: r
|
|
241
|
+
period_col: period # optional
|
|
242
|
+
epoch_col: epoch # optional
|
|
243
|
+
fold_col: fold # optional, otherwise k-fold
|
|
244
|
+
representations:
|
|
245
|
+
bolt: {model: chronos-bolt-small, input: folded-grid}
|
|
246
|
+
mantis: {model: mantis-v2, input: folded-grid}
|
|
247
|
+
moirai: {model: moirai-2.0-small, input: folded-grid, setup: "source ~/venvs/origami-moirai/bin/activate"}
|
|
248
|
+
astromer: {model: astromer2-macho, input: raw}
|
|
249
|
+
fourier: {features: fourier}
|
|
250
|
+
physical: {features: physical}
|
|
251
|
+
period: {catalog: [period]}
|
|
252
|
+
my_model: {python: "my_package.encoders:MyEncoder", path: /path/to/my_package, kwargs: {checkpoint: model.pt}, version: v1}
|
|
253
|
+
combine: [[bolt, physical], [mantis, physical], [fourier, period]]
|
|
254
|
+
tasks:
|
|
255
|
+
- {task: regression, target: my_target}
|
|
256
|
+
- {task: classification, target: class}
|
|
257
|
+
- task: classification
|
|
258
|
+
target: class
|
|
259
|
+
split: {train: "mag < 19", test: "mag >= 19"} # pandas queries, or {column, train, test}
|
|
260
|
+
groups: {column: mag, bins: [16, 18, 19, 20, 21]}
|
|
261
|
+
- {task: clustering, target: class, method: hdbscan}
|
|
262
|
+
subsample_epochs: [all, 50, 20]
|
|
263
|
+
seeds: [0, 1, 2]
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
origami models # available models (licence, size, install, installed?)
|
|
268
|
+
origami prefetch exp.yaml # on a machine with internet: download all weights
|
|
269
|
+
origami slurm exp.yaml --account ACC --partition PART \
|
|
270
|
+
--setup "module load python" --setup "source ~/venvs/origami/bin/activate"
|
|
271
|
+
sbatch origami_my_experiment.sbatch # one array task per model, each runs `origami embed`
|
|
272
|
+
origami status exp.yaml # which embeddings are stored / missing
|
|
273
|
+
origami collect exp.yaml # run all tasks, write results/*.csv and summary.md
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
What each step does:
|
|
277
|
+
- **`origami embed exp.yaml --representation NAME`** computes one representation for every
|
|
278
|
+
epoch level and seed. It also works without SLURM.
|
|
279
|
+
- **Embeddings** are stored under `output/embeddings`. Their key covers the model and its
|
|
280
|
+
settings, the input transform, the code version and the data, including subsampling and seed.
|
|
281
|
+
- **`collect` never runs a model.** If an embedding is missing, it says which representation
|
|
282
|
+
to rerun.
|
|
283
|
+
- **User models** (`python:`) are computed and cached like the foundation models. Change
|
|
284
|
+
`version` whenever your weights change.
|
|
285
|
+
- **`setup:`** gives a representation a shell line run by its own array task, for models
|
|
286
|
+
that need a separate environment.
|
|
287
|
+
- **Offline nodes:** the generated job sets `HF_HUB_OFFLINE=1`.
|
|
288
|
+
|
|
289
|
+
## Models
|
|
290
|
+
|
|
291
|
+
`origami models` prints the live list and whether each package is installed.
|
|
292
|
+
|
|
293
|
+
| family | checkpoints | params | licence of the weights | uses timestamps | extra |
|
|
294
|
+
|---|---|---|---|---|---|
|
|
295
|
+
| [Chronos](https://github.com/amazon-science/chronos-forecasting) (T5) | `chronos-t5-tiny/mini/small/base` | 8M–200M | Apache-2.0 | no | `chronos` |
|
|
296
|
+
| Chronos-Bolt | `chronos-bolt-tiny/small` | 9M–48M | Apache-2.0 | no | `chronos` |
|
|
297
|
+
| Chronos-2 | `chronos-2-small`, `chronos-2` | 28M, 120M | Apache-2.0 | no | `chronos` |
|
|
298
|
+
| [Moirai](https://github.com/SalesforceAIResearch/uni2ts) | `moirai-1.1-small/base`, `moirai-2.0-small` | 11M–91M | **CC-BY-NC-4.0 (non-commercial)** | no | `moirai` |
|
|
299
|
+
| [MOMENT](https://huggingface.co/AutonLab/MOMENT-1-small) | `moment-1-small/base/large` | 38M–346M | MIT | no | `moment` |
|
|
300
|
+
| [Mantis](https://huggingface.co/paris-noah/Mantis-8M) | `mantis-8m`, `mantis-plus`, `mantis-v2`, `mantis-v2-cls` | 4M–8M | Apache-2.0 | no | `mantis` |
|
|
301
|
+
| [Toto 2.0](https://github.com/DataDog/toto) | `toto-2.0-4m/22m/313m/1b/2.5b` | 4M–2.5B | Apache-2.0 | no | `toto` |
|
|
302
|
+
| [Timestral](https://github.com/mistralai/timestral) | `timestral-5m/28m/123m/209m` | 5M–209M | **Modified MIT: excludes companies above $20M monthly revenue** | no | `timestral` |
|
|
303
|
+
| [Astromer](https://github.com/astromer-science) | `astromer1-macho`, `astromer2-macho`, `astromer1-ztfdr20` | 0.7M–4M | CC-BY-4.0; **GPL-3.0 for `astromer1-ztfdr20`** | **yes** | `astromer` |
|
|
304
|
+
| [StarCLR](https://github.com/dj-y/StarCLR-Inference) | `starclr` | 19M | MIT | **yes** | `starclr` |
|
|
305
|
+
|
|
306
|
+
Notes on specific families:
|
|
307
|
+
- **Astromer** runs through the ONNX exports of the
|
|
308
|
+
[light-curve](https://github.com/light-curve/prep-models) project, so it needs neither
|
|
309
|
+
TensorFlow nor the original package.
|
|
310
|
+
- **StarCLR** uses a PyTorch re-implementation of the official inference code. Its weights
|
|
311
|
+
come from [Zenodo](https://doi.org/10.5281/zenodo.19728042), are verified by checksum,
|
|
312
|
+
and are stored in `$ORIGAMI_WEIGHTS`.
|
|
313
|
+
- **Toto, Timestral and Moirai** have no public embedding API. Their states are read from
|
|
314
|
+
internal modules, stated in each plugin's docstring, so their package versions are pinned.
|
|
315
|
+
- **Not included yet:**
|
|
316
|
+
- models that require `trust_remote_code`;
|
|
317
|
+
- models without public pretrained weights.
|
|
318
|
+
|
|
319
|
+
**The weights are not part of `origami`.** They are downloaded from their original
|
|
320
|
+
sources, and their licences govern your use of them. Check the non-commercial,
|
|
321
|
+
copyleft and revenue clauses marked above before using those models outside academic
|
|
322
|
+
research.
|
|
323
|
+
|
|
324
|
+
## Installation and environments
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
pip install "origami-astro[features,chronos,mantis,astromer,starclr]"
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
| extra | adds |
|
|
331
|
+
|---|---|
|
|
332
|
+
| `features` | hand-crafted features (`light-curve`) |
|
|
333
|
+
| `chronos`, `mantis`, `astromer`, `starclr`, `timestral` | those model families (they can share one environment) |
|
|
334
|
+
| `moirai`, `moment`, `toto` | those model families, **each in its own environment** (see below) |
|
|
335
|
+
| `dev` | tests (`pytest`) |
|
|
336
|
+
|
|
337
|
+
Some model packages pin incompatible versions:
|
|
338
|
+
|
|
339
|
+
| environment | extras | reason |
|
|
340
|
+
|---|---|---|
|
|
341
|
+
| main | `features, chronos, mantis, astromer, starclr, timestral` | — |
|
|
342
|
+
| moirai | `features, moirai` | `uni2ts` 2.0 pins `torch<2.5` and `numpy~=1.26` |
|
|
343
|
+
| moment | `features, moment` | `momentfm` pins `transformers==4.33.3` and `numpy==1.25.2` |
|
|
344
|
+
| toto | `features, toto` | `toto2` needs Python ≥ 3.12 |
|
|
345
|
+
|
|
346
|
+
In the YAML workflow, point each representation to its environment with `setup:`.
|
|
347
|
+
|
|
348
|
+
Timestral is not on PyPI; install it from GitHub:
|
|
349
|
+
```bash
|
|
350
|
+
pip install "timestral @ git+https://github.com/mistralai/timestral.git@a534bdbd244d64f3d9d743f46c7bf6fc330ed4ff"
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
On clusters, build environments on top of the site's Python/PyTorch module
|
|
354
|
+
(`python -m venv --system-site-packages ...`), so that only the model packages are added.
|
|
355
|
+
|
|
356
|
+
Environment variables:
|
|
357
|
+
- `ORIGAMI_CACHE`: embedding cache in interactive use (the CLI stores embeddings under `output/embeddings`).
|
|
358
|
+
- `ORIGAMI_WEIGHTS`: where weights not hosted on Hugging Face are stored.
|
|
359
|
+
- `HF_HUB_OFFLINE=1`: use only weights that are already downloaded.
|
|
360
|
+
|
|
361
|
+
Requires Python ≥ 3.10.
|
|
362
|
+
|
|
363
|
+
## Good practice
|
|
364
|
+
|
|
365
|
+
1. **Compare input transforms, not only models.** For periodic sources, folded and raw
|
|
366
|
+
inputs can give very different results with the same model. Each model also expects data
|
|
367
|
+
that looks like its pre-training data: scale, flux versus magnitude, regular versus
|
|
368
|
+
irregular sampling.
|
|
369
|
+
2. **Put back what normalisation removes.** Z-normalised, folded inputs carry no period and
|
|
370
|
+
no amplitude. Combine embeddings with `HandCrafted("physical")` or catalogue values
|
|
371
|
+
before comparing them with features that contain this information.
|
|
372
|
+
3. **Mind collapsed embeddings.** Some models map all objects to nearly parallel vectors,
|
|
373
|
+
with the information in small residual directions. Standardised probes, which `origami`
|
|
374
|
+
always uses, recover it; raw distances do not.
|
|
375
|
+
4. **Do not assume larger checkpoints are better.** Compare sizes within a family.
|
|
376
|
+
5. **Report variability.** Use several `seeds` and fixed `folds`, and check that differences
|
|
377
|
+
between representations exceed the fold-to-fold scatter before ranking them.
|
|
378
|
+
6. **Check where the labels come from.** If the target was derived from light-curve
|
|
379
|
+
features (e.g. a quantity computed from Fourier parameters), a representation can score
|
|
380
|
+
well by re-learning that relation. Validate on independently measured labels when possible.
|
|
381
|
+
|
|
382
|
+
## Adding a model
|
|
383
|
+
|
|
384
|
+
Add one file to `origami/models/`; it is discovered automatically.
|
|
385
|
+
|
|
386
|
+
```python
|
|
387
|
+
MODELS = {"my-model": dict(family="my", hf_id="org/my-model", license="MIT", extra="my",
|
|
388
|
+
context=512, params="10M", uses_time=False)}
|
|
389
|
+
|
|
390
|
+
class Encoder:
|
|
391
|
+
def __init__(self, spec, device=None):
|
|
392
|
+
... # heavy imports here, not at module level
|
|
393
|
+
|
|
394
|
+
def encode(self, values, masks, times, batch_size=256, scales=None): # `scales` is optional
|
|
395
|
+
... # return (n_curves, dim): states mean-pooled over positions where mask is True
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
Add a test in `tests/test_model_<name>.py` that checks:
|
|
399
|
+
- shape, finite values and determinism;
|
|
400
|
+
- that a curve's embedding does not change when it is batched with longer curves.
|
|
401
|
+
|
|
402
|
+
## Licence
|
|
403
|
+
|
|
404
|
+
`origami` is released under the [MIT licence](https://github.com/LorenzoMonti/origami/blob/main/LICENSE). Model weights are downloaded from
|
|
405
|
+
their original sources and keep their own licences (see [Models](#models)).
|
|
406
|
+
|
|
407
|
+
If you use `origami` in your work, please cite this repository and the papers of the
|
|
408
|
+
models you use.
|