From fbb2673a8b8b7485eb65bc577796d2294af89a34 Mon Sep 17 00:00:00 2001 From: Severin Magel Date: Sat, 1 Aug 2026 23:34:44 -0400 Subject: [PATCH 1/6] README: state the framework-agnostic philosophy and the two usage modes Co-Authored-By: Claude Opus 4.8 --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 803544a..d2bee15 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,20 @@ The first pretext task is **CURTAIN** (occupancy / light-front forecast). The architecture is built so a new self-supervised method is a small plugin under `pretext/`, reusing the data, backbone, and training engine unchanged. +## Philosophy +The core is framework-agnostic and fits neatly into plain PyTorch: it depends +only on torch, pytorch-lightning and numpy. Readers are ordinary indexable +`Dataset`s satisfying a small contract, models are `nn.Module`s behind two +narrow interfaces (`Backbone`, `PretextTask`), and `fit()` takes injected +factories and callbacks. Around that core you choose your frame: + +- **Bring your own** — wire SPINE into your existing code for data loading, + configuration, versioning and logging; nothing in the core assumes Hydra, + wandb or graphnet. +- **Use the graphnet frame** — `spine_graphnet` (DeepIce backbone + reader + adapter), the Hydra config tree and the wandb hooks work neatly around the + core, and the emitted encoders load straight into graphnet's benchmarks. + ## Layout ``` src/spine/ From 05be368dfaa02d76506973a554dff961285bacd4 Mon Sep 17 00:00:00 2001 From: Severin Magel <116261790+sevmag@users.noreply.github.com> Date: Sat, 1 Aug 2026 23:40:17 -0400 Subject: [PATCH 2/6] Update README for clarity on Dataset and model interfaces Corrected wording in the README to clarify dataset and model descriptions. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d2bee15..fb8ed4c 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ architecture is built so a new self-supervised method is a small plugin under ## Philosophy The core is framework-agnostic and fits neatly into plain PyTorch: it depends only on torch, pytorch-lightning and numpy. Readers are ordinary indexable -`Dataset`s satisfying a small contract, models are `nn.Module`s behind two +`Dataset`s satisfying a small canonical data sample format, models are `nn.Module`s behind two narrow interfaces (`Backbone`, `PretextTask`), and `fit()` takes injected factories and callbacks. Around that core you choose your frame: @@ -22,6 +22,7 @@ factories and callbacks. Around that core you choose your frame: - **Use the graphnet frame** — `spine_graphnet` (DeepIce backbone + reader adapter), the Hydra config tree and the wandb hooks work neatly around the core, and the emitted encoders load straight into graphnet's benchmarks. +- **Use the Hydra configs** ## Layout ``` From f21b5dc8fe0124513685fba39144df684f972672 Mon Sep 17 00:00:00 2001 From: Severin Magel Date: Sat, 1 Aug 2026 23:42:31 -0400 Subject: [PATCH 3/6] README: drop dash punctuation; complete the Hydra point independently Co-Authored-By: Claude Opus 4.8 --- README.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index fb8ed4c..8192452 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Extensible self-supervised pretraining of transformers on neutrino-telescope data. The repo produces **pretrained backbones** (encoder checkpoints) that -downstream supervised benchmarks load and fine-tune — a *spine* is a backbone, +downstream supervised benchmarks load and fine-tune. A *spine* is a backbone, which is exactly what this emits. The first pretext task is **CURTAIN** (occupancy / light-front forecast). The @@ -12,17 +12,21 @@ architecture is built so a new self-supervised method is a small plugin under ## Philosophy The core is framework-agnostic and fits neatly into plain PyTorch: it depends only on torch, pytorch-lightning and numpy. Readers are ordinary indexable -`Dataset`s satisfying a small canonical data sample format, models are `nn.Module`s behind two +`Dataset`s emitting a small canonical sample format, models are +`nn.Module`s behind two narrow interfaces (`Backbone`, `PretextTask`), and `fit()` takes injected factories and callbacks. Around that core you choose your frame: -- **Bring your own** — wire SPINE into your existing code for data loading, +- **Bring your own.** Wire SPINE into your existing code for data loading, configuration, versioning and logging; nothing in the core assumes Hydra, wandb or graphnet. -- **Use the graphnet frame** — `spine_graphnet` (DeepIce backbone + reader - adapter), the Hydra config tree and the wandb hooks work neatly around the - core, and the emitted encoders load straight into graphnet's benchmarks. -- **Use the Hydra configs** +- **Use the Hydra configs.** The `configs/` tree composes complete runs + (backbone, task, optimizer, scheduler, callbacks, trainer, data) through + the launcher in `examples/`; every component is swapped by a config + override instead of a code change, with or without graphnet. +- **Use the graphnet frame.** `spine_graphnet` provides the DeepIce backbone + and a reader adapter over graphnet's datasets, and the emitted encoders + load straight into graphnet's benchmarks. ## Layout ``` From 6115760c4712e97d8c665a32a25b54ce7d87cceb Mon Sep 17 00:00:00 2001 From: Severin Magel Date: Sat, 1 Aug 2026 23:42:57 -0400 Subject: [PATCH 4/6] README: rewrap the philosophy paragraph Co-Authored-By: Claude Opus 4.8 --- README.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8192452..8ca40bd 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,9 @@ architecture is built so a new self-supervised method is a small plugin under ## Philosophy The core is framework-agnostic and fits neatly into plain PyTorch: it depends only on torch, pytorch-lightning and numpy. Readers are ordinary indexable -`Dataset`s emitting a small canonical sample format, models are -`nn.Module`s behind two -narrow interfaces (`Backbone`, `PretextTask`), and `fit()` takes injected -factories and callbacks. Around that core you choose your frame: +`Dataset`s emitting a small canonical sample format, models are `nn.Module`s +behind two narrow interfaces (`Backbone`, `PretextTask`), and `fit()` takes +injected factories and callbacks. Around that core you choose your frame: - **Bring your own.** Wire SPINE into your existing code for data loading, configuration, versioning and logging; nothing in the core assumes Hydra, From 76bf76aef94013e8f6ecb13e16d7600ece3bdb67 Mon Sep 17 00:00:00 2001 From: Severin Magel Date: Sat, 1 Aug 2026 23:44:21 -0400 Subject: [PATCH 5/6] README: Hydra and graphnet are optional conveniences, stated plainly Co-Authored-By: Claude Opus 4.8 --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ca40bd..bade3d7 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,9 @@ The core is framework-agnostic and fits neatly into plain PyTorch: it depends only on torch, pytorch-lightning and numpy. Readers are ordinary indexable `Dataset`s emitting a small canonical sample format, models are `nn.Module`s behind two narrow interfaces (`Backbone`, `PretextTask`), and `fit()` takes -injected factories and callbacks. Around that core you choose your frame: +injected factories and callbacks. Hydra and graphnet integrate neatly, but both are +strictly optional conveniences: use either, both, or neither. Around that +core you choose your frame: - **Bring your own.** Wire SPINE into your existing code for data loading, configuration, versioning and logging; nothing in the core assumes Hydra, From f2ca9b22120e2e442abbdcac1a4de21ba8d8c98d Mon Sep 17 00:00:00 2001 From: Severin Magel Date: Sat, 1 Aug 2026 23:46:58 -0400 Subject: [PATCH 6/6] README: emojis on the section headers Co-Authored-By: Claude Opus 4.8 --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index bade3d7..6282a58 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ The first pretext task is **CURTAIN** (occupancy / light-front forecast). The architecture is built so a new self-supervised method is a small plugin under `pretext/`, reusing the data, backbone, and training engine unchanged. -## Philosophy +## 🧭 Philosophy The core is framework-agnostic and fits neatly into plain PyTorch: it depends only on torch, pytorch-lightning and numpy. Readers are ordinary indexable `Dataset`s emitting a small canonical sample format, models are `nn.Module`s @@ -29,7 +29,7 @@ core you choose your frame: and a reader adapter over graphnet's datasets, and the emitted encoders load straight into graphnet's benchmarks. -## Layout +## 🗂️ Layout ``` src/spine/ data/ geometry + FeatureScaler scaling, datamodule (reader- & selection-agnostic) @@ -47,7 +47,7 @@ tests/ core-independence gate (spine imports no graphnet) See `DESIGN.md` for the module decomposition, interfaces, and the decisions behind them (graphnet surface, LMDB, selections stay the caller's, DDP gotchas). -## Runtime +## ⚙️ Runtime Needs Python 3.10, torch 2.6 and pytorch-lightning >= 2.5 (see `pyproject.toml`); install with `pip install -e .`, which provides `spine` and `spine_graphnet`. The DeepIce backbone additionally needs a graphnet @@ -55,7 +55,7 @@ checkout on the import path (graphnet is not on PyPI). Pretraining and finetuning must share one environment: the emitted encoders are loaded back into graphnet's DeepIce downstream. -## Running +## 🚀 Running Runs are composed with **Hydra** from `configs/` and launched via `examples/train_curtain.py`; the core library is Hydra-free (every component is `instantiate`d from config at the launcher). Override any group or value: @@ -65,7 +65,7 @@ python examples/train_curtain.py \ data.train_selection=train.parquet data.val_selection=val.parquet \ callbacks=curtain_auc task/objectives=v2 trainer.devices=4 ``` -## Reading data +## 📥 Reading data SPINE mandates **no reader**. Provide any PyTorch `Dataset` satisfying the contract stated canonically in `spine/data/datamodule.py`: `raw[i] -> {"event_no": int, "pulses": [P, F] raw, "sensor_key": [P] int}` --