heptokens 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.
Files changed (61) hide show
  1. heptokens-0.1.0/.gitattributes +2 -0
  2. heptokens-0.1.0/.github/workflows/cd.yml +36 -0
  3. heptokens-0.1.0/.gitignore +35 -0
  4. heptokens-0.1.0/.pre-commit-config.yaml +17 -0
  5. heptokens-0.1.0/PKG-INFO +446 -0
  6. heptokens-0.1.0/README.md +429 -0
  7. heptokens-0.1.0/pixi.lock +4612 -0
  8. heptokens-0.1.0/profiles/local/config.yaml +6 -0
  9. heptokens-0.1.0/profiles/s3df/config.yaml +15 -0
  10. heptokens-0.1.0/pyproject.toml +80 -0
  11. heptokens-0.1.0/src/heptokens/__init__.py +0 -0
  12. heptokens-0.1.0/src/heptokens/callbacks/__init__.py +0 -0
  13. heptokens-0.1.0/src/heptokens/callbacks/finetuning.py +89 -0
  14. heptokens-0.1.0/src/heptokens/callbacks/monitor.py +88 -0
  15. heptokens-0.1.0/src/heptokens/callbacks/recon.py +91 -0
  16. heptokens-0.1.0/src/heptokens/conf/__init__.py +0 -0
  17. heptokens-0.1.0/src/heptokens/conf/callbacks/classify.yaml +33 -0
  18. heptokens-0.1.0/src/heptokens/conf/callbacks/encode.yaml +42 -0
  19. heptokens-0.1.0/src/heptokens/conf/callbacks/finetune.yaml +20 -0
  20. heptokens-0.1.0/src/heptokens/conf/callbacks/new_modality_encode.yaml +37 -0
  21. heptokens-0.1.0/src/heptokens/conf/callbacks/pretrain.yaml +24 -0
  22. heptokens-0.1.0/src/heptokens/conf/fit_preprocessors.yaml +20 -0
  23. heptokens-0.1.0/src/heptokens/conf/hydra/default.yaml +16 -0
  24. heptokens-0.1.0/src/heptokens/conf/model/classifier.yaml +12 -0
  25. heptokens-0.1.0/src/heptokens/conf/model/diffusion_vqvae.yaml +40 -0
  26. heptokens-0.1.0/src/heptokens/conf/model/feature_classifier.yaml +19 -0
  27. heptokens-0.1.0/src/heptokens/conf/model/new_modality_vqvae.yaml +24 -0
  28. heptokens-0.1.0/src/heptokens/conf/model/set2vec_vqvae.yaml +40 -0
  29. heptokens-0.1.0/src/heptokens/conf/model/token_classifier.yaml +23 -0
  30. heptokens-0.1.0/src/heptokens/conf/model/transformer_vqvae.yaml +40 -0
  31. heptokens-0.1.0/src/heptokens/conf/model/vector_classifier.yaml +21 -0
  32. heptokens-0.1.0/src/heptokens/conf/model/vqvae.yaml +30 -0
  33. heptokens-0.1.0/src/heptokens/conf/tokenize.yaml +20 -0
  34. heptokens-0.1.0/src/heptokens/conf/train.yaml +46 -0
  35. heptokens-0.1.0/src/heptokens/data/__init__.py +0 -0
  36. heptokens-0.1.0/src/heptokens/data/base.py +95 -0
  37. heptokens-0.1.0/src/heptokens/data/collation.py +185 -0
  38. heptokens-0.1.0/src/heptokens/data/flat_array.py +153 -0
  39. heptokens-0.1.0/src/heptokens/data/structured_array.py +519 -0
  40. heptokens-0.1.0/src/heptokens/data/transforms.py +221 -0
  41. heptokens-0.1.0/src/heptokens/export_tokens.py +245 -0
  42. heptokens-0.1.0/src/heptokens/fit_preprocessors.py +141 -0
  43. heptokens-0.1.0/src/heptokens/models/__init__.py +0 -0
  44. heptokens-0.1.0/src/heptokens/models/classifier.py +95 -0
  45. heptokens-0.1.0/src/heptokens/models/coders.py +382 -0
  46. heptokens-0.1.0/src/heptokens/models/new_modality_coders.py +134 -0
  47. heptokens-0.1.0/src/heptokens/models/optimisers.py +213 -0
  48. heptokens-0.1.0/src/heptokens/models/token_classifier.py +573 -0
  49. heptokens-0.1.0/src/heptokens/models/transformer.py +217 -0
  50. heptokens-0.1.0/src/heptokens/models/utils.py +185 -0
  51. heptokens-0.1.0/src/heptokens/models/vq_vae.py +243 -0
  52. heptokens-0.1.0/src/heptokens/train.py +103 -0
  53. heptokens-0.1.0/src/heptokens/utils/__init__.py +0 -0
  54. heptokens-0.1.0/src/heptokens/utils/hydra.py +201 -0
  55. heptokens-0.1.0/src/heptokens/utils/lightning.py +163 -0
  56. heptokens-0.1.0/src/heptokens/utils/schedulers.py +113 -0
  57. heptokens-0.1.0/src/heptokens/utils/torch_utils.py +519 -0
  58. heptokens-0.1.0/tests/conftest.py +37 -0
  59. heptokens-0.1.0/tests/test_configs.py +62 -0
  60. heptokens-0.1.0/tests/test_export_pos_tokens.py +128 -0
  61. heptokens-0.1.0/tests/test_integration.py +151 -0
@@ -0,0 +1,2 @@
1
+ # SCM syntax highlighting & preventing 3-way merges
2
+ pixi.lock merge=binary linguist-language=YAML linguist-generated=true
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: CD
3
+ on:
4
+ workflow_dispatch:
5
+ pull_request:
6
+ push:
7
+ branches: [main]
8
+ release:
9
+ types: [published]
10
+ jobs:
11
+ dist:
12
+ runs-on: ubuntu-latest
13
+ steps:
14
+ - uses: actions/checkout@v7
15
+ with:
16
+ fetch-depth: 0
17
+ - uses: hynek/build-and-inspect-python-package@v3.0.1
18
+ publish:
19
+ needs: [dist]
20
+ environment: pypi
21
+ permissions:
22
+ id-token: write
23
+ attestations: write
24
+ contents: read
25
+ runs-on: ubuntu-latest
26
+ if: github.event_name == 'release' && github.event.action == 'published'
27
+ steps:
28
+ - uses: actions/download-artifact@v8
29
+ with:
30
+ name: Packages
31
+ path: dist
32
+ - name: Generate artifact attestation for sdist and wheel
33
+ uses: actions/attest@v4
34
+ with:
35
+ subject-path: dist/*
36
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,35 @@
1
+ # pixi environments
2
+ .pixi/*
3
+ !.pixi/config.toml
4
+
5
+ # Snakemake files
6
+ .snakemake/
7
+
8
+ # Python cache files
9
+ __pycache__/
10
+ *.py[cod]
11
+ *$py.class
12
+ # Distribution / packaging
13
+ .Python
14
+ build/
15
+ develop-eggs/
16
+ dist/
17
+ downloads/
18
+ eggs/
19
+ .eggs/
20
+ lib/
21
+ lib64/
22
+ parts/
23
+ sdist/
24
+ var/
25
+ wheels/
26
+ pip-wheel-metadata/
27
+ share/python-wheels/
28
+ *.egg-info/
29
+
30
+ # VsCode settings
31
+ .vscode/
32
+
33
+ # Plots and other results
34
+ plot/
35
+ results/
@@ -0,0 +1,17 @@
1
+ ---
2
+ repos:
3
+ - repo: https://github.com/charliermarsh/ruff-pre-commit
4
+ rev: v0.11.13
5
+ hooks:
6
+ - id: ruff
7
+ args: [--fix, --show-fixes, --exit-non-zero-on-fix]
8
+ - id: ruff-format
9
+ - repo: https://github.com/lyz-code/yamlfix
10
+ rev: 1.16.1
11
+ hooks:
12
+ - id: yamlfix
13
+ - repo: https://github.com/adrienverge/yamllint.git
14
+ rev: v1.37.1
15
+ hooks:
16
+ - id: yamllint
17
+ args: [-d, '{extends: relaxed, rules: {line-length: disable}}']
@@ -0,0 +1,446 @@
1
+ Metadata-Version: 2.5
2
+ Name: heptokens
3
+ Version: 0.1.0
4
+ Author: Samuel Klein, Jeffrey Krupa, Michael Kagan
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: awkward>=2.8
7
+ Requires-Dist: h5py>=3.13
8
+ Requires-Dist: hydra-core>=1.3
9
+ Requires-Dist: lightning>=2.5
10
+ Requires-Dist: omegaconf>=2.3
11
+ Requires-Dist: rich>=14
12
+ Requires-Dist: scikit-learn>=1.3
13
+ Requires-Dist: torch>=2.4
14
+ Requires-Dist: uproot>=5.7
15
+ Requires-Dist: vector-quantize-pytorch
16
+ Description-Content-Type: text/markdown
17
+
18
+ # heptokens
19
+
20
+ [![pytorch](https://img.shields.io/badge/-PyTorch-EE4C2C?logo=pytorch&logoColor=white)](https://pytorch.org/)
21
+ [![lightning](https://img.shields.io/badge/-Lightning-792EE5?logo=lightning&logoColor=white)](https://lightning.ai/)
22
+ [![hydra](https://img.shields.io/badge/-Hydra-89b8cd?logo=hydra&logoColor=white)](https://hydra.cc/)
23
+ [![wandb](https://img.shields.io/badge/-WandB-orange?logo=weightsandbiases&logoColor=white)](https://wandb.ai)
24
+ [![pixi](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/prefix-dev/pixi/main/assets/badge/v0.json)](https://pixi.sh)
25
+
26
+ Tokenize HEP physics objects (jets, tracks, calorimeter clusters, …) with residual VQ-VAEs.
27
+
28
+ `heptokens` is an installable Python library. It ships:
29
+ - **Data classes** — generic HDF5 datasets and Lightning DataModules for structured (object + constituent) and flat (dense, maskless) data.
30
+ - **VQ-VAE model** — `LitVqVae` wrapping `ResidualVQ` with pluggable encoder/decoder.
31
+ - **CLI entry points** — `heptokens-fit-preprocessors`, `heptokens-train`, and `heptokens-export` for Hydra-configured preprocessing, training, and tokenization runs.
32
+
33
+ ## Quick Start
34
+
35
+ ### 1. Install
36
+
37
+ ```bash
38
+ pip install heptokens
39
+ ```
40
+
41
+ Or, for development with a [Pixi](https://pixi.sh/latest/installation/)-managed environment:
42
+
43
+ ```bash
44
+ git clone <repo>
45
+ cd heptokens
46
+ pixi shell # activates the environment
47
+ ```
48
+
49
+ ### 2. Write your datamodule config
50
+
51
+ Create a YAML file describing your data. This is the only config you must supply — the library bundles everything else (model, callbacks, trainer).
52
+
53
+ ```yaml
54
+ # my_configs/datamodule/my_jets.yaml
55
+ _target_: heptokens.data.structured_array.StructuredArrayModule
56
+ data_path: /path/to/data.h5
57
+ obj_group: jets
58
+ set_group: tracks
59
+ obj_features: [pt, eta, phi]
60
+ set_features: [pt, deta, dphi, d0, z0]
61
+ label_key: HadronConeExclTruthLabelID
62
+ mask_key: valid
63
+ train_frac: 0.7
64
+ val_frac: 0.15
65
+ test_frac: 0.15
66
+ batch_size: 1024
67
+ num_workers: 4
68
+ ```
69
+
70
+ Your HDF5 must have this layout (see `StructuredArrayHDF5Dataset` for full docs):
71
+
72
+ ```
73
+ <obj_group>/
74
+ <feature>: float [N]
75
+ <label_key>: int [N]
76
+ <set_group>/
77
+ <feature>: float [N, max_elements]
78
+ <mask_key>: bool [N, max_elements]
79
+ ```
80
+
81
+ ### 3. Fit preprocessors
82
+
83
+ The VQ-VAE expects normalised inputs. Use the `heptokens-fit-preprocessors` CLI to fit sklearn scalers on your training data and save them as joblib files:
84
+
85
+ ```bash
86
+ heptokens-fit-preprocessors -cd /path/to/my_configs \
87
+ datamodule=my_jets \
88
+ output_dir=resources
89
+ ```
90
+
91
+ Dataset-specific options (which modes to fit, which features to log-scale, etc.) live in a `preprocessing:` block inside your datamodule config so they don't need to be repeated on every invocation:
92
+
93
+ ```yaml
94
+ # my_configs/datamodule/my_jets.yaml
95
+ _target_: heptokens.data.structured_array.StructuredArrayModule
96
+ set_features: [pt, deta, dphi, d0, z0]
97
+ ...
98
+ preprocessing:
99
+ cst_modes: [quantile, log_quantile]
100
+ cst_log_feature_indices: [pt] # resolved via set_features — no separate feature list needed
101
+ fit_jets: true
102
+ ```
103
+
104
+ Then just run:
105
+
106
+ ```bash
107
+ heptokens-fit-preprocessors -cd /path/to/my_configs \
108
+ datamodule=my_jets \
109
+ output_dir=resources
110
+ ```
111
+
112
+ Individual keys can still be overridden on the CLI with `datamodule.preprocessing.<key>=...`:
113
+
114
+ ```bash
115
+ heptokens-fit-preprocessors -cd /path/to/my_configs \
116
+ datamodule=my_jets \
117
+ datamodule.preprocessing.cst_modes=[quantile,log_quantile]
118
+ ```
119
+
120
+ This saves `resources/cst_<mode>.joblib` (and `resources/jet_<mode>.joblib` when `fit_jets=true`) and writes `resources/preprocessor_config.yaml` with the file paths. Then add them to your datamodule config:
121
+
122
+ ```yaml
123
+ # append to my_configs/datamodule/my_jets.yaml
124
+ transforms:
125
+ preprocess:
126
+ _target_: heptokens.data.collation.preprocess_batch
127
+ _partial_: true
128
+ cst_fn:
129
+ _target_: joblib.load
130
+ filename: resources/cst_quantiles.joblib
131
+ jet_fn:
132
+ _target_: joblib.load
133
+ filename: resources/jet_quantiles.joblib
134
+ ```
135
+
136
+ See [Preprocessing](#preprocessing) for available modes and details.
137
+
138
+ ### 4. Train
139
+
140
+ ```bash
141
+ heptokens-train -cd /path/to/my_configs \
142
+ datamodule=my_jets \
143
+ project_name=my_project \
144
+ network_name=run_01 \
145
+ output_dir=results
146
+ ```
147
+
148
+ ### 5. Export tokens
149
+
150
+ ```bash
151
+ heptokens-export -cd /path/to/my_configs \
152
+ datamodule=my_jets \
153
+ ckpt_path=results/my_project/run_01/checkpoints/last.ckpt \
154
+ output_dir=results/tokens
155
+ ```
156
+
157
+ Output is an `.npz` with `indices [N, n_csts, num_quantizers]`, `labels [N]`, and `codebooks [Q, K, D]`.
158
+
159
+ ### Python API
160
+
161
+ For scripting or notebooks without Hydra:
162
+
163
+ ```python
164
+ from heptokens.data.structured_array import StructuredArrayHDF5Dataset
165
+ from heptokens.models.vq_vae import LitVqVae
166
+ from heptokens.models.coders import Encoder, Decoder
167
+ import lightning as L
168
+ from torch.utils.data import DataLoader
169
+
170
+ ds = StructuredArrayHDF5Dataset(
171
+ "data.h5",
172
+ obj_group="jets", set_group="tracks",
173
+ obj_features=["pt", "eta", "phi"],
174
+ set_features=["pt", "eta", "phi"],
175
+ mask_key="valid", label_key=None,
176
+ )
177
+ loader = DataLoader(ds, batch_size=256, shuffle=True)
178
+
179
+ sample = next(iter(loader))["csts"] # [B, N, 3]
180
+ model = LitVqVae(
181
+ encoder=Encoder, decoder=Decoder,
182
+ codebook_size=512, codebook_dim=64, num_quantizers=4,
183
+ data_sample=sample,
184
+ )
185
+
186
+ trainer = L.Trainer(max_epochs=10, logger=False)
187
+ trainer.fit(model, loader)
188
+
189
+ batch = next(iter(loader))
190
+ z_q, indices, _ = model.encode(batch) # indices: [B, N, num_quantizers]
191
+ ```
192
+
193
+ ## CLI Reference
194
+
195
+ All three commands are Hydra-based. Use `-cd` to point at your experiment's config directory containing the `datamodule/` folder. All other configs (model, callbacks, trainer) are bundled.
196
+
197
+ ### Full workflow
198
+
199
+ ```bash
200
+ # 1. Fit scalers on training data
201
+ heptokens-fit-preprocessors -cd /path/to/my_configs \
202
+ datamodule=my_jets \
203
+ output_dir=resources
204
+
205
+ # 2. Wire the saved joblib paths into your datamodule config
206
+ # (see resources/preprocessor_config.yaml for the generated snippet)
207
+
208
+ # 3. Train the VQ-VAE
209
+ heptokens-train -cd /path/to/my_configs \
210
+ datamodule=my_jets \
211
+ project_name=my_project \
212
+ network_name=run_01 \
213
+ output_dir=results
214
+
215
+ # 4. Export tokens from a trained checkpoint
216
+ heptokens-export -cd /path/to/my_configs \
217
+ datamodule=my_jets \
218
+ ckpt_path=results/my_project/run_01/checkpoints/last.ckpt \
219
+ output_dir=results/tokens
220
+ ```
221
+
222
+ ```bash
223
+ # Without installing (pixi environment):
224
+ pixi run python -m heptokens.fit_preprocessors -cd /path/to/my/configs datamodule=my_jets ...
225
+ pixi run python -m heptokens.train -cd /path/to/my/configs datamodule=my_jets ...
226
+ pixi run python -m heptokens.export_tokens -cd /path/to/my/configs datamodule=my_jets ...
227
+ ```
228
+
229
+ ### Bundled configs — `heptokens-train` / `heptokens-export`
230
+
231
+ | Group | Location | Description |
232
+ |---|---|---|
233
+ | `model` | `src/heptokens/conf/model/` | `vqvae`, `transformer_vqvae`, `classifier`, … |
234
+ | `callbacks` | `src/heptokens/conf/callbacks/` | `pretrain`, `encode`, `classify`, … |
235
+
236
+ `datamodule` is not bundled — it is experiment-specific. See `StructuredArrayModule` in `src/heptokens/data/structured_array.py` for the constructor args.
237
+
238
+ ### Bundled configs — `heptokens-fit-preprocessors`
239
+
240
+ The command ships `src/heptokens/conf/fit_preprocessors.yaml` with these key options:
241
+
242
+ Top-level keys (set on the CLI or in your own `fit_preprocessors.yaml`):
243
+
244
+ | Key | Default | Description |
245
+ |---|---|---|
246
+ | `output_dir` | `resources` | Directory to write joblib files and the config snippet |
247
+ | `max_batches` | — | Limit training batches used for fitting (null = full dataset) |
248
+
249
+ `preprocessing:` block keys (set inside your datamodule config, or via `datamodule.preprocessing.<key>=...` on the CLI):
250
+
251
+ | Key | Default | Description |
252
+ |---|---|---|
253
+ | `cst_modes` | `[quantile, standard]` | Scaler modes to fit for constituents |
254
+ | `jet_modes` | `[quantile, standard]` | Scaler modes to fit for jet-level features |
255
+ | `fit_jets` | `false` | Set `true` to also fit jet-level scalers |
256
+ | `cst_log_feature_indices` | — | Features to log-scale before the main transform (names resolved via `set_features`, or indices) |
257
+ | `jet_log_feature_indices` | — | Same for jet features (names resolved via `obj_features`) |
258
+ | `n_quantiles` | `500` | Number of quantiles for `QuantileTransformer` |
259
+ | `log_offset` | `1.0` | Offset in `log(x + offset)` |
260
+
261
+ ### Output layout
262
+
263
+ ```
264
+ <output_dir>/<project_name>/<network_name>/
265
+ checkpoints/
266
+ full_config.yaml # saved for reproducibility / resume
267
+ ```
268
+
269
+ ### Resuming a run
270
+
271
+ ```bash
272
+ heptokens-train -cd /path/to/my/configs \
273
+ full_resume=true ckpt_flag=last.ckpt \
274
+ output_dir=... project_name=... network_name=...
275
+ ```
276
+
277
+ Or from an explicit checkpoint path:
278
+
279
+ ```bash
280
+ heptokens-train -cd /path/to/my/configs \
281
+ full_resume=false ckpt_path=/abs/path/to/last.ckpt \
282
+ datamodule=my_atlas output_dir=... project_name=... network_name=...
283
+ ```
284
+
285
+ ## Repository Layout
286
+
287
+ ```
288
+ src/heptokens/
289
+ data/
290
+ structured_array.py # StructuredArrayHDF5Dataset / StructuredArrayModule
291
+ flat_array.py # FlatArrayHDF5Dataset / FlatArrayModule (dense, no mask)
292
+ base.py # BaseMapModule (shared DataLoader logic)
293
+ collation.py, transforms.py
294
+ models/
295
+ vq_vae.py # LitVqVae
296
+ coders.py # Encoder, Decoder (base classes + default MLP impl)
297
+ new_modality_coders.py # template for custom encoders/decoders
298
+ classifier.py, transformer.py, …
299
+ conf/ # bundled Hydra configs (model, callbacks)
300
+ callbacks/ # Lightning callbacks
301
+ utils/
302
+ train.py # heptokens-train entry point
303
+ export_tokens.py # heptokens-export entry point
304
+ fit_preprocessors.py # heptokens-fit-preprocessors entry point
305
+ tests/
306
+ profiles/ # Slurm executor profiles for pixi tasks
307
+ ```
308
+
309
+ ## Adding a New Modality
310
+
311
+ A modality is any input representation with its own data format, token definition, and reconstruction metric. The VQ-VAE core (`LitVqVae`, `ResidualVQ`) is modality-agnostic and never changes.
312
+
313
+ ### Token strategy
314
+
315
+ | Data type | Token strategy |
316
+ |---|---|
317
+ | Sparse set (tracks, clusters, PFOs) | One token per object. Boolean validity mask for variable-length padding. |
318
+ | Dense grid (η-φ image, calorimeter towers) | Fixed-size patching in `__getitem__`. Each patch is one token. No mask needed if all patches are always valid. |
319
+
320
+ ### Checklist
321
+
322
+ **1. Dataset / DataModule** — `src/heptokens/data/<modality>.py`
323
+
324
+ See `StructuredArrayModule` or `FlatArrayModule` for reference implementations.
325
+ - `MyDataset.__getitem__` returns a dict: constituent tensor + optional bool mask.
326
+ - `MyDataModule` extends `BaseMapModule`; implement `setup()` and `get_data_sample()`.
327
+
328
+ **2. Encoder / Decoder** — `src/heptokens/models/<modality>_coders.py`
329
+
330
+ Start from `src/heptokens/models/new_modality_coders.py`.
331
+ - Extend `Encoder` and `Decoder` from `heptokens.models.coders`.
332
+ - `Encoder.forward(batch)` → `[B, N, codebook_dim]`, masked positions zeroed.
333
+ - `Decoder.compute_loss(z_q, batch)` → scalar loss.
334
+ - Set `self.input_key` and `self.mask_key` to match your dataset's output keys.
335
+
336
+ **3. Model config** — `src/heptokens/conf/model/<modality>_vqvae.yaml`
337
+
338
+ Start from `src/heptokens/conf/model/new_modality_vqvae.yaml`.
339
+ Point `encoder._target_` and `decoder._target_` at your new classes.
340
+
341
+ **4. Datamodule config** — in your experiment repo's config directory
342
+
343
+ ```yaml
344
+ # my_configs/datamodule/my_modality.yaml
345
+ _target_: heptokens.data.<modality>.MyDataModule
346
+ data_path: /path/to/data.h5
347
+ batch_size: 512
348
+ num_workers: 4
349
+ # ... your fields
350
+ ```
351
+
352
+ **5. Callbacks config** *(optional)* — `src/heptokens/conf/callbacks/<modality>_encode.yaml`
353
+
354
+ For physical-space reconstruction metrics, subclass `BaseReconstructionMonitor`:
355
+
356
+ ```python
357
+ from heptokens.callbacks.recon import BaseReconstructionMonitor
358
+
359
+ class MyMonitor(BaseReconstructionMonitor):
360
+ def __init__(self, inverse_fn, **kwargs):
361
+ super().__init__(input_key="my_key", mask_key=None, **kwargs)
362
+ self.inverse_fn = inverse_fn
363
+
364
+ def compute_and_log_metrics(self, trainer, pl_module, batch, batch_idx):
365
+ import torch as T
366
+ with T.no_grad():
367
+ z_q = pl_module.encode(batch)[0]
368
+ recon = pl_module.decode(z_q, batch)
369
+ orig = self.inverse_fn(batch["my_key"].cpu())
370
+ reco = self.inverse_fn(recon.cpu())
371
+ pl_module.log("val/my_mae_unscaled", T.mean(T.abs(orig - reco)))
372
+ ```
373
+
374
+ **Train:**
375
+
376
+ ```bash
377
+ heptokens-train -cd /path/to/my/configs \
378
+ model=<modality>_vqvae callbacks=<modality>_encode \
379
+ datamodule=<modality> trainer.max_epochs=30
380
+ ```
381
+
382
+ ### Common pitfalls
383
+
384
+ - **`input_key` mismatch**: The encoder reads `batch[self.input_key]`. Set it consistently in the dataset and encoder.
385
+ - **`n_classes` not needed for VQ-VAE**: Omit or set to `null` in your datamodule config.
386
+ - **Mask dtype**: The mask must be `bool`, shape `[B, N]`. Float/int masks will silently produce wrong results.
387
+ - **Dense grids**: Make sure `N` (number of patches) is fixed across samples so batches stack without a mask.
388
+
389
+ ---
390
+
391
+ ## Preprocessing
392
+
393
+ The VQ-VAE expects normalised inputs. The library provides sklearn-based scalers in `heptokens.data.transforms` and a batch-level application function in `heptokens.data.collation`. The workflow is: **fit offline → save as joblib → load in your Hydra config** (shown in [Quick Start step 3](#3-fit-preprocessors)).
394
+
395
+ ### How it connects
396
+
397
+ `BaseMapModule` accepts a `transforms` kwarg. When set, it wraps the DataLoader's collate function so transforms run on every batch automatically — no manual intervention at train time.
398
+
399
+ ### Available modes (`create_preprocessing_transformer`)
400
+
401
+ | Mode | Description |
402
+ |------|-------------|
403
+ | `"quantile"` | `QuantileTransformer` on all features |
404
+ | `"standard"` | `StandardScaler` on all features |
405
+ | `"log_quantile"` | Log-scale selected features, then quantile-transform all |
406
+ | `"log_standard"` | Log-scale selected features, then standard-scale all |
407
+
408
+ Parameters: `mode`, `log_feature_indices` (which features to log-scale), `n_quantiles`, `log_offset`.
409
+
410
+ ### Inverse transforms
411
+
412
+ For evaluating reconstruction quality in physical units:
413
+
414
+ ```python
415
+ from heptokens.data.collation import inverse_preprocess_batch
416
+
417
+ original = inverse_preprocess_batch(batch, cst_fn=cst_scaler, jet_fn=jet_scaler)
418
+ ```
419
+
420
+ ---
421
+
422
+ ## Troubleshooting
423
+
424
+ ### DataLoader workers exit unexpectedly
425
+ - Set `num_workers=0` to confirm worker issue.
426
+ - Set `pin_memory=False` if worker shutdown appears unstable.
427
+
428
+ ### Training becomes slow
429
+ - Tune `num_workers`, `batch_size`, `pin_memory`.
430
+ - Avoid `reload_dataloaders_every_n_epochs=1` on iterable datasets unless necessary.
431
+
432
+ ### W&B run lands under wrong account
433
+ - Override `logger.entity=<username_or_team>` when calling `heptokens-train`.
434
+
435
+ ### Debugger uses wrong Python interpreter
436
+ - Use `.vscode/launch.json` with `"python": "${workspaceFolder}/.pixi/envs/default/bin/python"`.
437
+
438
+ ---
439
+
440
+ ## Resources
441
+ - [Pixi documentation](https://pixi.sh/)
442
+ - [Reproducible Machine Learning Workflows for Scientists, Matthew Feickert, 2025](https://carpentries-incubator.github.io/reproducible-ml-workflows/)
443
+ - [Good ML project structure](https://github.com/mattcleigh/JetSSL-Lite/tree/master)
444
+
445
+ ## Contributors
446
+ Jeffrey Krupa, Samuel Klein, Michael Kagan