bugcatcher commited on
Commit
bde77eb
Β·
verified Β·
1 Parent(s): eb244fc

Upload README.md with huggingface_hub

Browse files
Files changed (1) hide show
  1. README.md +442 -0
README.md CHANGED
@@ -1,3 +1,445 @@
1
  ---
2
  license: mit
 
 
 
 
 
 
 
 
 
 
3
  ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
  license: mit
3
+ library_name: pytorch
4
+ pipeline_tag: feature-extraction
5
+ tags:
6
+ - electrodermal-activity
7
+ - eda
8
+ - wearables
9
+ - physiological-signals
10
+ - time-series
11
+ - contrastive-learning
12
+ - foundation-model
13
  ---
14
+
15
+ # 🌸 UME: Foundation Model for Electrodermal Activity (EDA) Signals
16
+
17
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
18
+ [![PyTorch](https://img.shields.io/badge/PyTorch-2.0+-ee4c2c.svg)](https://pytorch.org/)
19
+ [![Lightning](https://img.shields.io/badge/Lightning-2.0+-792ee5.svg)](https://lightning.ai/)
20
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
21
+ [![DOI](https://img.shields.io/badge/DOI-10.1145%2F3857981-blue.svg)](https://doi.org/10.1145/3857981)
22
+ [![arXiv](https://img.shields.io/badge/arXiv-2603.16878-b31b1b.svg)](https://arxiv.org/abs/2603.16878)
23
+
24
+ See also πŸ«› **EDAMAME**, the large-scale EDA pretraining collection we curated to train UME: [repository](https://github.com/LeonardoAlchieri/EDAMAME) Β· [website](https://pc.inf.usi.ch/datasets/edamame/) (see [Pretraining data](#pretraining-data)).
25
+
26
+ ---
27
+
28
+ <a id="quick-use"></a>
29
+
30
+ ## πŸš€ Quick Use (UME)
31
+
32
+ ```bash
33
+ pip install git+https://github.com/LeonardoAlchieri/eda-foundation-models.git
34
+ ```
35
+
36
+ ```python
37
+ import torch
38
+ from ume import UMEPipeline
39
+
40
+ # Downloads the base UME weights from the Hugging Face Hub
41
+ pipeline = UMEPipeline.from_pretrained()
42
+
43
+ # NOTE: default UME requires 60s windows (at 4Hz sampling rate) and 3 channels (mixed, phasic and tonic)
44
+ x = torch.randn(8, 240, 3) # (batch, seq_len, channels)
45
+ embeddings = pipeline.embed(x)
46
+ print(embeddings.shape) # (8, 64)
47
+ ```
48
+
49
+ To load from a local clone instead, pass the weights file: `UMEPipeline.from_pretrained(weights_path="model.safetensors")` (see [Checkpoints and Weights](#checkpoints)). A runnable walkthrough is in [`notebook/pipeline_demo.ipynb`](notebook/pipeline_demo.ipynb); for other ways to install, see [Installation](#installation).
50
+
51
+ ---
52
+
53
+ ## πŸ“‹ Table of Contents
54
+
55
+ - [Overview](#overview)
56
+ - [Model Card](#model-card)
57
+ - [Installation](#installation)
58
+ - [Fine-Tune](#fine-tune)
59
+ - [Retrain](#retrain)
60
+ - [Pretraining data](#pretraining-data)
61
+ - [UME Architecture (Base)](#architecture)
62
+ - [UME Configurations](#configurations)
63
+ - [Checkpoints and Weights](#checkpoints)
64
+ - [Citation](#citation)
65
+ - [License](#license)
66
+
67
+ ---
68
+
69
+ <a id="overview"></a>
70
+
71
+ ## 🎯 Overview
72
+
73
+ This repo contains the code and weights for **UME**, the first foundation model for wearable EDA data. **UME** is based on EfficientNet architecture and is trained using sample-wise contrastive learning, using the set of data augmentations from [Katie Matton](https://github.com/kmatton/contrastive-learning-for-eda).
74
+
75
+ We release the weights for base UME, the default and suggested configuration, as well as other configurations (tiny, small and large). See below for more information on repo usage.
76
+
77
+ ---
78
+
79
+ <a id="model-card"></a>
80
+
81
+ ## πŸͺͺ Model Card
82
+
83
+ - **What it is:** an encoder that turns 60-second windows of wrist electrodermal activity (EDA) into 64-dimensional embeddings.
84
+ - **Architecture:** EfficientNet-style 1D CNN (stem convolution, 16 MBConv1D blocks with squeeze-and-excitation, head convolution, global average pooling, linear projection). See [`ume/model/efficientnet_contrastive.py`](ume/model/efficientnet_contrastive.py) and [UME Architecture](#architecture).
85
+ - **Training objective:** sample-wise contrastive learning (InfoNCE, temperature 0.1) between two augmented views of the same window, using the EDA augmentations of [Matton et al. (2024)](https://arxiv.org/abs/2404.08783).
86
+ - **Files:** see [Checkpoints and Weights](#checkpoints).
87
+ - **Developed by:** Leonardo Alchieri, UniversitΓ  della Svizzera italiana (USI).
88
+ - **Paper:** [doi.org/10.1145/3857981](https://doi.org/10.1145/3857981) Β· [arXiv:2603.16878](https://arxiv.org/abs/2603.16878)
89
+
90
+ ### Input
91
+
92
+ - Shape `(batch, 240, 3)`: 240 samples = 60 s at 4 Hz.
93
+ - Channels, in order: mixed EDA, phasic component, tonic component.
94
+ - Signals at other sampling rates or window lengths should be resampled and cut to match.
95
+
96
+ ### Intended use
97
+
98
+ - Extracting features from wearable EDA for research on downstream tasks such as stress, cognitive load, or sleep/wake classification.
99
+ - Fine-tuning on a labelled research dataset with `UMEPipeline.fit` (see [Fine-Tune](#fine-tune)).
100
+
101
+ ### Out-of-scope use
102
+
103
+ - Clinical diagnosis, or any medical or safety-critical decision about an individual.
104
+ - Inferring sensitive traits or emotional states of people without their informed consent, including workplace or surveillance monitoring.
105
+ - Signals that are not wrist EDA (e.g. PPG, ECG) or that are sampled very differently, without first validating performance.
106
+
107
+ ### Training data
108
+
109
+ Pretrained without labels on 17 public and research EDA datasets from the EDAMAME collection (see [Pretraining data](#pretraining-data)). The data is not distributed with the model. Recordings come mostly from research studies with wrist-worn devices such as the Empatica E4, which shapes the populations, devices and settings the model has seen.
110
+
111
+ ### Evaluation
112
+
113
+ Downstream evaluation (frozen features and a classical classifier, validated leave-one-person-out) is run by `train.py` through the optional `edamame_downstream` package. Results are reported in the [paper](https://doi.org/10.1145/3857981).
114
+
115
+ ### Limitations and risks
116
+
117
+ - **Population and device bias.** Performance can drop on populations, devices, body locations or recording conditions that are underrepresented in the pretraining data.
118
+ - **Artifacts.** EDA is sensitive to motion, temperature and sensor contact. The model does not detect or flag poor-quality signal.
119
+ - **Individual differences.** EDA varies a lot between people. Validate with person-independent splits (e.g. leave-one-person-out) rather than random splits, which overestimate performance.
120
+ - **Privacy.** Physiological signals are personal data. Handle any data you use with the model according to its consent terms and applicable law.
121
+
122
+ ---
123
+
124
+ <a id="installation"></a>
125
+
126
+ ## πŸ”§ Installation
127
+
128
+ ### Pixi (recommended)
129
+
130
+ The environment is defined in [`pixi.toml`](pixi.toml). Install [Pixi](https://pixi.sh), then:
131
+
132
+ ```bash
133
+ git clone https://github.com/LeonardoAlchieri/eda-foundation-models.git
134
+ cd eda-foundation-models
135
+ pixi install --frozen
136
+ ```
137
+
138
+ `--frozen` installs the default environment straight from `pixi.lock`. Without it, Pixi also checks the optional `downstream` environment, which needs the sibling repository described below.
139
+
140
+ ### pip
141
+
142
+ ```bash
143
+ pip install -e . # inference and fine-tuning (UMEPipeline)
144
+ pip install -e ".[train]" # + everything train.py needs for pretraining
145
+ ```
146
+
147
+ Other extras: `mantis` (Mantis-8M backbone), `dev` (pytest, black, flake8, isort), `notebook`. See [INSTALL.md](INSTALL.md).
148
+
149
+ ### Optional: downstream evaluation
150
+
151
+ After pretraining, `train.py` can evaluate the new model on labelled downstream tasks. This needs the separate [`edamame_downstream`](https://github.com/LeonardoAlchieri/pretrained_foundation_models_physiological_data) package, cloned next to this repository:
152
+
153
+ ```bash
154
+ git clone https://github.com/LeonardoAlchieri/pretrained_foundation_models_physiological_data.git ../pretrained_foundation_models_physiological_data
155
+ pixi install -e downstream
156
+ pixi run -e downstream python train.py --config-name conf-ume
157
+ ```
158
+
159
+ Without it, `train.py` pretrains as usual and skips the downstream step with a warning. Set `downstream.enabled=false` to skip it explicitly.
160
+
161
+ ---
162
+
163
+ <a id="fine-tune"></a>
164
+
165
+ ## πŸŽ“ Fine-Tune (UME)
166
+
167
+ Beyond frozen-feature extraction, the pipeline can be **supervised fine-tuned** for classification through a scikit-learn-style API (`fit` / `predict` / `predict_proba`). A classification head (`LayerNorm -> Linear` by default, matching Mantis and Pulse-PPG) is attached on top of the encoder embedding and trained with cross-entropy.
168
+
169
+ > **Note:** fine-tuning is currently supported **only for the EfficientNet (UME) encoder** (`model_name="efficientnet"`). MAE returns per-patch tokens rather than a pooled embedding, so it (and Mantis) raise `NotImplementedError`.
170
+
171
+ ```python
172
+ import torch
173
+ from ume import UMEPipeline
174
+
175
+ pipeline = UMEPipeline.from_pretrained()
176
+
177
+ X = torch.randn(256, 240, 3) # (n_samples, seq_len, channels)
178
+ y = torch.randint(0, 2, (256,)).numpy() # labels may be ints or strings
179
+
180
+ pipeline.fit(X, y, fine_tuning_type="full", num_epochs=20)
181
+
182
+ probs = pipeline.predict_proba(X) # (n_samples, num_classes); column j -> pipeline.classes_[j]
183
+ preds = pipeline.predict(X) # labels in the original space passed to `fit`
184
+ ```
185
+
186
+ Labels are encoded internally to contiguous integer ids (sorted unique values, exposed as `pipeline.classes_`) and mapped back by `predict`.
187
+
188
+ ### Fine-tuning strategies
189
+
190
+ | `fine_tuning_type` | Behaviour |
191
+ |--------------------|-----------|
192
+ | `"full"` (default) | Fine-tune the whole encoder + head. Pass `backbone_lr` for a smaller encoder LR than the head's `learning_rate`. |
193
+ | `"head"` | Freeze the encoder (linear probe) and train the head only; the backbone stays in eval mode so BatchNorm statistics are not updated. |
194
+ | `"scratch"` | Re-initialise the encoder and train everything from random weights, ignoring the pretrained checkpoint β€” the "no pretraining" baseline. |
195
+
196
+ ### Validation, early stopping and best-checkpoint selection
197
+
198
+ Supply a validation set either explicitly with `validation_data=(X_val, y_val)` or by holding out a stratified fraction of the training data with `validation_split` (e.g. `0.2`). `validation_data` takes precedence when both are given.
199
+
200
+ ```python
201
+ pipeline.fit(
202
+ X, y,
203
+ fine_tuning_type="full",
204
+ learning_rate=1e-3,
205
+ backbone_lr=1e-4,
206
+ num_epochs=100,
207
+ validation_split=0.2,
208
+ class_weight="balanced", # inverse-frequency CE weights (or pass a tensor)
209
+ early_stopping=True,
210
+ monitor="val_macro_f1", # or "val_acc" (maximized) / "val_loss" (minimized)
211
+ patience=10,
212
+ restore_best_weights=True, # roll back to the best epoch when training ends
213
+ )
214
+ ```
215
+
216
+ Without `early_stopping`, all `num_epochs` are run and no checkpoint selection happens. With it, training stops after `patience` epochs without a `min_delta` improvement in `monitor`, and `restore_best_weights=True` (the default) restores the encoder + head from the best epoch.
217
+
218
+ ### Refit on the full dataset
219
+
220
+ On small labelled datasets, permanently holding out labels for validation hurts the final model. `refit_on_full_data=True` (which requires `early_stopping=True`) instead runs training in two phases:
221
+
222
+ 1. **Phase 1** trains with the validation hold-out purely to find the optimal training budget β€” the *optimizer-step* count of the best epoch (steps, not epochs, because the full dataset yields more batches per epoch).
223
+ 2. **Phase 2** resets the encoder + head to their initial weights, rebuilds the optimizer, and retrains on 100% of the data (train + validation combined) for exactly that step budget, with no validation set.
224
+
225
+ ```python
226
+ pipeline.fit(
227
+ X, y,
228
+ validation_split=0.2,
229
+ early_stopping=True,
230
+ refit_on_full_data=True,
231
+ )
232
+ ```
233
+
234
+ The refit model cannot be validated internally, so use an outer evaluation loop (e.g. leave-one-person-out) for unbiased performance estimates. `restore_best_weights` is ignored in this mode, since the refit replaces the phase-1 model entirely.
235
+
236
+ ### Key `fit` arguments
237
+
238
+ | Argument | Default | Purpose |
239
+ |----------|---------|---------|
240
+ | `fine_tuning_type` | `"full"` | `"full"` / `"head"` / `"scratch"` (see above). |
241
+ | `learning_rate` | `1e-3` | LR for the head (and the backbone when `backbone_lr` is None). |
242
+ | `backbone_lr` | `None` | Optional separate, typically smaller, encoder LR. |
243
+ | `batch_size` / `num_epochs` | `64` / `100` | Mini-batch size and epoch count. |
244
+ | `weight_decay` | `0.0` | AdamW weight decay. |
245
+ | `validation_data` / `validation_split` | `None` / `0.0` | Explicit validation set, or stratified hold-out fraction. |
246
+ | `class_weight` | `None` | `"balanced"` for inverse-frequency CE weights, or a `(num_classes,)` tensor. |
247
+ | `early_stopping` / `patience` / `monitor` / `min_delta` | `False` / `10` / `"val_macro_f1"` / `0.0` | Early-stopping controls. |
248
+ | `restore_best_weights` | `True` | Roll back to the best monitored epoch at the end of training. |
249
+ | `refit_on_full_data` | `False` | Two-phase budget-then-refit training (see above). |
250
+ | `use_layer_norm` | `True` | `LayerNorm -> Linear` head; set `False` for a bare linear head. |
251
+ | `verbose` | `True` | Print per-epoch loss / macro-F1. |
252
+
253
+ ---
254
+
255
+ <a id="retrain"></a>
256
+
257
+ ## πŸ‹οΈ Retrain (UME)
258
+
259
+ We provide Hydra config files to reproduce the experiments from our work. Modify them to try different configurations. Retraining needs the pretraining data, which is not included in this repository (see [Pretraining data](#pretraining-data)).
260
+
261
+ Notes on the defaults:
262
+
263
+ - **Logging.** Runs log to [Weights & Biases](https://wandb.ai) under your default entity. Add `pretrain/logger=csv` (or `tensorboard`, `none`) to train without a W&B account.
264
+ - **Epoch length.** An "epoch" is 3000 randomly sampled batches of 256 windows (`pretrain.trainer.limit_train_batches`), as for the released model. Set it to `null` to use the full training set per epoch.
265
+ - **Quick check.** Add `pretrain.trainer.fast_dev_run=5` to run a few batches end to end.
266
+
267
+ ### 1. Train base UME
268
+
269
+ ```bash
270
+ pixi run python train.py --config-name conf-ume
271
+ ```
272
+
273
+ ### 2. Train other model and dataset sizes
274
+
275
+ ```bash
276
+ # Base (default)
277
+ python train.py --config-name conf-ume model_size=base
278
+
279
+ # Other presets
280
+ python train.py --config-name conf-ume model_size=tiny
281
+ python train.py --config-name conf-ume model_size=small
282
+ python train.py --config-name conf-ume model_size=large
283
+ ```
284
+
285
+ ```bash
286
+ # Base (default)
287
+ python train.py --config-name conf-ume pretrain.dataset.subsample=1.0
288
+
289
+ # Other presets
290
+ python train.py --config-name conf-ume pretrain.dataset.subsample=0.05
291
+ python train.py --config-name conf-ume pretrain.dataset.subsample=0.5
292
+ python train.py --config-name conf-ume pretrain.dataset.subsample=0.75
293
+ ```
294
+
295
+ We also provide templates for sweeps for the model and dataset size (see [sweep-ume-ablation-size.yaml](configs/sweep-ume-ablation-size.yaml) and [sweep-ume-ablation-subsample.yaml](configs/sweep-ume-ablation-subsample.yaml)).
296
+
297
+ ---
298
+
299
+ <a id="pretraining-data"></a>
300
+
301
+ ## πŸ«› Pretraining data
302
+
303
+ UME was pretrained on πŸ«› **EDAMAME**, which we release in two versions:
304
+
305
+ - **Open**: freely downloadable.
306
+ - **Restricted**: the full collection, available after signing a data sharing agreement.
307
+
308
+ See the [EDAMAME repository](https://github.com/LeonardoAlchieri/EDAMAME) for a description of the collection and the [EDAMAME website](https://pc.inf.usi.ch/datasets/edamame/) for access to both versions. The data itself is **not** included in this repository.
309
+
310
+ The base UME was pretrained on these datasets from the collection (the list in [`configs/conf-ume.yaml`](configs/conf-ume.yaml)):
311
+
312
+ BiHeartS, big-ideas-glycemic-wearable, Dynamics, EmpaticaE4Stress, EPM, LAUREATE, MEFAR, M2Sleep, PPG_FieldStudy, SEED, SEED-II-Lab, SEED-II-Wild, Stress Predict Dataset, ToadStool, WEEE, WESD, Workplaces.
313
+
314
+ `train.py` reads the data from `pretrain.dataset.base_path` (default `data_online.nosync/`), with one folder per dataset:
315
+
316
+ ```
317
+ data_online.nosync/
318
+ └── <dataset_name>/
319
+ └── *.h5 # one or more pandas HDFStore files
320
+ ```
321
+
322
+ Each key in an HDF5 store is one recording, stored as a pandas DataFrame with the EDA channels as columns (mixed, phasic, tonic, sampled at 4 Hz). An optional `Timestamp` column is dropped. Each key's storer has an `attrs.metadata` dict with `user`, `session`, `dataset_name` and `len_data` (number of samples). The loader cuts 60 s windows (240 samples) on the fly with a stride of `shift` samples, and splits train and validation by recording, so windows from one recording never end up in both.
323
+
324
+ ---
325
+
326
+ <a id="architecture"></a>
327
+
328
+ ## πŸ—οΈ UME Architecture (Base)
329
+
330
+ UME is an EfficientNet-inspired 1D encoder for contrastive learning:
331
+
332
+ ```
333
+ Input (N, T, C)
334
+ -> Stem Conv1D + BN + Swish
335
+ -> MBConv1D blocks (repeated)
336
+ -> Head Conv1D + Global Pool
337
+ -> Linear embedding
338
+ -> Contrastive loss on two augmented views
339
+ ```
340
+
341
+ Base preset (default), set through the `model_size` presets in [`configs/conf-ume.yaml`](configs/conf-ume.yaml):
342
+
343
+ | Parameter | Base Value |
344
+ |-----------|------------|
345
+ | `stem_channels` | `64` |
346
+ | `mbconv_channels` | `64` |
347
+ | `num_mbconv_blocks` | `16` |
348
+ | `head_channels` | `248` |
349
+ | `embedding_dim` | `64` |
350
+ | `kernel_size` | `3` |
351
+ | `dropout` | `0.1` |
352
+ | `loss temperature` | `0.1` |
353
+ | optimizer | Adam, lr `5e-4`, weight decay `1e-3` |
354
+
355
+ Contrastive training setup (augmentations, optimizer, scheduler):
356
+
357
+ - [`configs/pretrain/contrastive.yaml`](configs/pretrain/contrastive.yaml)
358
+ - [`configs/pretrain/engine/contrastive.yaml`](configs/pretrain/engine/contrastive.yaml)
359
+
360
+ ---
361
+
362
+ <a id="configurations"></a>
363
+
364
+ ## πŸ§ͺ UME Configurations
365
+
366
+ We recommend the **base UME** preset, and only its weights are released. The other presets and the pretraining-data subsamples used in our ablations can be retrained with the configs below.
367
+
368
+ ### UME model-size presets
369
+
370
+ Defined in [`configs/conf-ume.yaml`](configs/conf-ume.yaml):
371
+
372
+ | Preset | Stem | MBConv | Blocks | Head | Embedding | Kernel | Dropout |
373
+ |--------|------|--------|--------|------|-----------|--------|---------|
374
+ | `tiny` | `32` | `32` | `4` | `96` | `32` | `5` | `0.1` |
375
+ | `small`| `48` | `48` | `8` | `160` | `48` | `7` | `0.1` |
376
+ | `base` | `64` | `64` | `16` | `248` | `64` | `3` | `0.1` |
377
+ | `large`| `96` | `96` | `24` | `384` | `96` | `11` | `0.1` |
378
+
379
+ Sweeps over model size and pretraining-data size: [`sweep-ume-ablation-size.yaml`](configs/sweep-ume-ablation-size.yaml) and [`sweep-ume-ablation-subsample.yaml`](configs/sweep-ume-ablation-subsample.yaml).
380
+
381
+ ---
382
+
383
+ <a id="checkpoints"></a>
384
+
385
+ ## πŸ’Ύ Checkpoints and Weights
386
+
387
+ Three files hold the same base UME weights:
388
+
389
+ | File | Contents | Use it for |
390
+ |------|----------|------------|
391
+ | [`model.safetensors`](model.safetensors) + [`config.json`](config.json) | Encoder weights in [safetensors](https://huggingface.co/docs/safetensors) format, with the model config. Holds tensors only, so loading never runs code. This is what `from_pretrained()` downloads from the Hugging Face Hub. | Inference and fine-tuning (recommended). |
392
+ | [`artifacts/ume_base_inference.pt`](artifacts/ume_base_inference.pt) | Encoder `state_dict` and model config in one PyTorch file. Loads with `torch.load(..., weights_only=True)`. | Same as above, without the safetensors dependency. |
393
+ | [`artifacts/ume_base_training.ckpt`](artifacts/ume_base_training.ckpt) | Full PyTorch Lightning checkpoint, including optimizer and scheduler state. Needs `weights_only=False`. | Resuming or inspecting training. |
394
+
395
+ **Are they the same model?** Yes. All three hold the same 366 encoder tensors, bit-for-bit, and give identical embeddings. They differ only in what else they contain:
396
+
397
+ - `ume_base_training.ckpt` is about 3Γ— larger because it also stores the training state (mostly the Adam optimizer state, plus epoch, step, callback and hyperparameter records). Its weight keys carry a `model.` prefix, which `from_pretrained` strips.
398
+ - `ume_base_training.ckpt` has no model config: `from_pretrained` infers the architecture from the tensor shapes and gets the same model. The other two files include the config.
399
+ - Only `ume_base_training.ckpt` needs `weights_only=False`, which can run code stored in the file, so load it only from a source you trust.
400
+
401
+ Use `ume_base_training.ckpt` only to resume pretraining. For inference and fine-tuning, use `model.safetensors` or `ume_base_inference.pt`.
402
+
403
+ `UMEPipeline.from_pretrained` accepts any of them through `weights_path`. With no `weights_path`, it downloads `model.safetensors` and `config.json` from the Hub repo given by `repo_id` (default: the released base UME); `revision` and `cache_dir` are passed to the download.
404
+
405
+ ---
406
+
407
+ <a id="citation"></a>
408
+
409
+ ## πŸ“š Citation
410
+
411
+ If you use UME, please cite the paper ([doi.org/10.1145/3857981](https://doi.org/10.1145/3857981), [arXiv:2603.16878](https://arxiv.org/abs/2603.16878)). You can also cite this repository (GitHub's "Cite this repository" button uses [`CITATION.cff`](CITATION.cff)):
412
+
413
+ ```bibtex
414
+ @software{ume_eda_foundation_model,
415
+ title = {{UME}: a foundation model for wearable electrodermal activity},
416
+ author = {Alchieri, Leonardo},
417
+ year = {2026},
418
+ url = {https://github.com/LeonardoAlchieri/eda-foundation-models}
419
+ }
420
+ ```
421
+
422
+ The data augmentations used for contrastive pretraining come from:
423
+
424
+ ```bibtex
425
+ @article{matton2024contrastive,
426
+ title={Contrastive Learning of Electrodermal Activity Representations for Stress Detection},
427
+ author={Matton, Katie and Lewis, Robert and Guttag, John and Picard, Rosalind},
428
+ journal={arXiv preprint arXiv:2404.08783},
429
+ year={2024}
430
+ }
431
+ ```
432
+
433
+ ---
434
+
435
+ <a id="license"></a>
436
+
437
+ ## πŸ“„ License
438
+
439
+ This project is licensed under the MIT License. See [`LICENSE`](LICENSE).
440
+
441
+ ---
442
+
443
+ <p align="center">
444
+ <i>People Centered Computing Lab @ USI, Switzerland.</i>
445
+ </p>