| --- |
| license: mit |
| language: |
| - en |
| library_name: pytorch |
| pipeline_tag: feature-extraction |
| tags: |
| - cgm |
| - continuous-glucose-monitor |
| - self-supervised-learning |
| - jepa |
| - time-series |
| - masked-prediction |
| - biosignal |
| - healthcare |
| - pretrained-encoder |
| --- |
| |
| # CGM-JEPA Pretrained Encoders |
|
|
| Frozen self-supervised encoder weights from the paper *CGM-JEPA: Learning Consistent Continuous Glucose Monitor Representations via Predictive Self-Supervised Pretraining*. The repo contains the **exact checkpoints used to produce Tables 1–8 of the paper** for both the paper's main contributions (CGM-JEPA, X-CGM-JEPA) and the two re-pretrained baselines (GluFormer, TS2Vec). |
|
|
| > Companion repos: pretraining dataset [`CRUISEResearchGroup/CGM-JEPA-Pretraining`](https://huggingface.co/datasets/CRUISEResearchGroup/CGM-JEPA-Pretraining), labeled splits [`CRUISEResearchGroup/CGM-JEPA-Downstream`](https://huggingface.co/datasets/CRUISEResearchGroup/CGM-JEPA-Downstream), code [github.com/cruiseresearchgroup/CGM-JEPA](https://github.com/cruiseresearchgroup/CGM-JEPA). |
|
|
| > **MOMENT and Mantis are not redistributed here.** Those baselines are loaded directly from their upstream HF repos (`AutonLab/MOMENT-1-{small,large}`, `paris-noah/Mantis-8M`) by the eval pipeline. |
|
|
| ## Quick start |
|
|
| ```bash |
| huggingface-cli download CRUISEResearchGroup/CGM-JEPA --local-dir Output |
| ``` |
|
|
| Then from the [code repository](https://github.com/cruiseresearchgroup/CGM-JEPA): |
|
|
| ```bash |
| # Reproduce paper Tables 1–6 |
| python scripts/run_all_eval.py |
| ``` |
|
|
| The downstream eval will load all four checkpoints automatically from the subdirectories below. |
|
|
| ## Layout |
|
|
| ``` |
| . |
| ├── cgm_jepa/ |
| │ ├── model.safetensors |
| │ └── config.json |
| ├── x_cgm_jepa/ |
| │ ├── model.safetensors |
| │ └── config.json |
| └── baselines/ |
| ├── gluformer.pt |
| └── ts2vec.pkl |
| ``` |
|
|
| `cgm_jepa/` and `x_cgm_jepa/` use the standard `PyTorchModelHubMixin` layout — `model.safetensors` for weights, `config.json` for architecture hyperparameters — so they load via the standard `from_pretrained` one-liner (see [Loading examples](#loading-examples)). |
|
|
| `baselines/gluformer.pt` is `{"encoder": state_dict}` and `baselines/ts2vec.pkl` is a full pickled `TS2Vec` model object (per the upstream library's convention). Their architectures are documented in the [Architectures](#architectures) section. |
|
|
| ### Important note on the baselines |
|
|
| `gluformer.pt` and `ts2vec.pkl` are **not** vendored from upstream releases of those methods. They were **re-pretrained on the same open CGM corpus and compute budget as CGM-JEPA / X-CGM-JEPA** (Stanford + Colas, 101 epochs, batch 128, lr 1e-4, seed 43) so that the comparison in the paper isolates the pretraining objective rather than mixing in corpus or compute differences. Use these checkpoints when reproducing paper numbers; for other settings, prefer the original authors' releases. |
|
|
| ## Architectures |
|
|
| ### `cgm_jepa/cgm_jepa.pt` and `x_cgm_jepa/x_cgm_jepa.pt` |
|
|
| Both use the same `models.encoder.Encoder` class with identical hyperparameters; only the pretraining objective differs. At downstream / inference time only the temporal encoder is used, so the two checkpoints are drop-in interchangeable. |
|
|
| | Field | Value | |
| |---|---| |
| | `patch_size` | 12 | |
| | `encoder_kernel_size` | 3 | |
| | `encoder_embed_dim` | 96 | |
| | `encoder_embed_bias` | `True` | |
| | `encoder_nhead` | 6 | |
| | `encoder_num_layers` | 3 | |
| | `encoder_dropout` | 0.0 | |
|
|
| Input: a tensor of shape `(B, num_patches, patch_size)` (raw glucose values, z-scored). |
| Output: per-patch embedding of shape `(B, num_patches, embed_dim)`. Pool with `.mean(dim=1)` for a single embedding per sample. |
|
|
| X-CGM-JEPA adds a second pretraining branch that predicts Glucodensity image patches; only the temporal encoder is loaded at inference. |
|
|
| ### `baselines/gluformer.pt` |
|
|
| `models.gluformer.GluFormer`: |
|
|
| | Field | Value | |
| |---|---| |
| | `vocab_size` | 278 | |
| | `embed_dim` | 96 | |
| | `nhead` | 6 | |
| | `num_layers` | 3 | |
| | `dim_feedforward` | 192 | |
| | `max_seq_length` | 25000 | |
| | `dropout` | 0.0 | |
| | `pad_token` | 278 (= `vocab_size`) | |
|
|
| Input: a tensor of integer bin indices in `[0, vocab_size)` (raw glucose discretized into the 40–320 mg/dL range with width `(320 − 40) / vocab_size`). The downstream pipeline detaches GluFormer's output head and uses only the encoder embedding. |
|
|
| ### `baselines/ts2vec.pkl` |
|
|
| `models.ts2vec.TS2Vec` (loaded via `eval/baseline_utils/ts2vec_utils.py:load_pretrained_ts2vec`): |
|
|
| | Field | Value | |
| |---|---| |
| | `input_dims` | 1 | |
| | `output_dims` | 96 | |
| | `hidden_dims` | 64 | |
| | `depth` | 10 | |
|
|
| Saved as a Python pickle of the full model object, matching the upstream `ts2vec` library convention. |
|
|
| ## Loading examples |
|
|
| ### CGM-JEPA / X-CGM-JEPA — `from_pretrained` one-liner |
| |
| `Encoder` is a `PyTorchModelHubMixin` subclass, so the architecture hyperparameters and weights load in a single call directly from this repo: |
| |
| ```python |
| from models.encoder import Encoder |
| |
| encoder = Encoder.from_pretrained("CRUISEResearchGroup/CGM-JEPA", subfolder="cgm_jepa") |
| encoder.eval() |
| |
| # X-CGM-JEPA: same call, different subfolder |
| encoder_x = Encoder.from_pretrained("CRUISEResearchGroup/CGM-JEPA", subfolder="x_cgm_jepa") |
| ``` |
| |
| `config.json` for each subfolder is auto-introspected from `Encoder.__init__`, so no architecture wiring is needed on the user side. |
| |
| ### From the CGM-JEPA code repository |
| |
| `config/model_configs.py` looks for these checkpoints under `Output/cgm_jepa/`, `Output/x_cgm_jepa/`, and `Output/baselines/`. The `huggingface-cli download CRUISEResearchGroup/CGM-JEPA --local-dir Output` flow above produces exactly that structure, so the eval pipeline picks them up automatically. |
| |
| ### Standalone PyTorch — GluFormer |
| |
| ```python |
| import torch |
| import torch.nn as nn |
| from models.gluformer.gluformer import GluFormer |
| |
| vocab_size = 278 |
| gluformer = GluFormer( |
| vocab_size=vocab_size, |
| embed_dim=96, |
| nhead=6, |
| num_layers=3, |
| dim_feedforward=192, |
| max_seq_length=25000, |
| dropout=0.0, |
| pad_token=vocab_size, |
| ) |
| gluformer.load_state_dict( |
| torch.load("Output/baselines/gluformer.pt", map_location="cpu")["encoder"] |
| ) |
| gluformer.output_head = nn.Identity() # discard the LM head for embedding extraction |
| gluformer.eval() |
| ``` |
| |
| ### Standalone PyTorch — TS2Vec |
|
|
| ```python |
| from eval.baseline_utils.ts2vec_utils import load_pretrained_ts2vec |
| |
| ts2vec = load_pretrained_ts2vec( |
| checkpoint_path="Output/baselines/ts2vec.pkl", |
| device="cpu", |
| input_dims=1, |
| output_dims=96, |
| hidden_dims=64, |
| depth=10, |
| ) |
| ``` |
|
|
| ## Pretraining |
|
|
| All four encoders were pretrained on the [CGM-JEPA pretraining corpus](https://huggingface.co/datasets/CRUISEResearchGroup/CGM-JEPA-Pretraining) under identical conditions: |
|
|
| | Setting | Value | |
| |---|---| |
| | Corpus | 228 subjects (22 Stanford + 206 Colas), 389,365 readings at 5-min sampling | |
| | Window length | 288 timesteps (24 hours) | |
| | Masking ratio | 0.25 | |
| | Epochs | 101 | |
| | Batch size | 128 | |
| | Learning rate | 1e-4 | |
| | Random seed | 43 | |
|
|
| See [`config/config_pretrain.py`](https://github.com/cruiseresearchgroup/CGM-JEPA/blob/main/config/config_pretrain.py) for the full configuration. |
|
|
| ## Intended use |
|
|
| - **Frozen feature extraction** from raw CGM windows (24-hour, 5-min sampled, 288 timesteps). |
| - **Linear-probe or shallow-classifier downstream evaluation**, especially the IR / β-cell dysfunction tasks in the paper. |
| - **Comparison baseline** for new CGM representation methods, with identical pretraining conditions across all four encoders shipped here. |
|
|
| ## License & attribution |
|
|
| Released under the **MIT license**. When using these weights, please cite: |
|
|
| 1. Our paper (citation TBD; see code repo). |
| 2. The two upstream pretraining datasets — Metwally et al. 2025 (*Nature Biomedical Engineering*) and Colas et al. 2019 (*PLOS ONE*). |
| 3. The original baseline papers when using `gluformer.pt` or `ts2vec.pkl`. |
|
|
| ## Citation |
|
|
| > _Citation block to be filled once the CGM-JEPA paper has a stable venue / arXiv link._ |
|
|
| ## Code repository |
|
|
| [github.com/cruiseresearchgroup/CGM-JEPA](https://github.com/cruiseresearchgroup/CGM-JEPA) |
|
|