ProtoSleepNet and ProtoSleepTransformer#
Two pretrained sleep stagers, trained on 28 sites from 12 public and clinical datasets and published on the Hugging Face Hub
in 4rooms/physioex:
Hub name |
Epoch encoder |
Sequence length |
Parameters |
|---|---|---|---|
|
SeqSleepNet |
20 |
0.79 M |
|
SleepTransformer |
21 |
3.98 M |
Both are physioex.models.protosleepnet.ProtoSleepNet networks: a per-channel epoch encoder, a channel mixer
that learns how much to trust each modality, a residual sequence encoder and a linear classifier. They are the models of
the paper Prototype-based interpretable sleep staging with physiologically meaningful sub-stage pattern discovery
(npj Digital Medicine; code and analyses in guidogagl/protosleepnet),
retrained on many sites at once. The weights of the paper itself (one dataset per model) are a separate archive.
Quick start#
import torch
from physioex.models import load_from_pretrained
model = load_from_pretrained("protosleeptransformer-gagliardi", verbose=True) # eval mode, CPU
# (batch, L, channels, T, F): log-power STFT spectrograms of EEG, EOG, EMG (T=29, F=129)
x = torch.randn(2, 21, 3, 29, 129)
with torch.no_grad():
logits = model(x) # (2, 21, 5): W, N1, N2, N3, REM
verbose=True prints the per-site test metrics stored with the weights. The input is what the seqsleepnet
pipeline preset produces for the channels ["EEG", "EOG", "EMG"], so the models can be fed
directly from any physioex dataset:
from physioex.data import get_dataset
ds = get_dataset("hmc")(channels=["EEG", "EOG", "EMG"], pipelines="seqsleepnet", sequence_length=21)
encode(x) returns the contextualised epoch embeddings (B, L, d_model). forward(x, quantize=True) replaces the epoch
embeddings by their nearest prototype, but it needs a codebook (set_codebook) that is learned after training from the
epoch embeddings; the checkpoints on the Hub contain no codebook, and quantize=False (the default) is the plain
classifier. The prototype analyses of the paper are in its repository, and relevance maps for these models are in
Explainability (LRP supports the default, non-quantised forward).
Training data#
Both models were trained jointly on the training subjects of 28 sites. The test and validation subjects of every site are disjoint from the training subjects (split by subject, per site).
Dataset |
Sites |
Source |
|---|---|---|
Sleep-EDF |
|
PhysioNet |
HMC |
|
PhysioNet |
DCSM |
|
ERDA / University of Copenhagen |
MASS |
|
CEAMS |
SHHS |
|
NSRR |
MESA |
|
NSRR |
MrOS |
|
NSRR |
HomePAP |
|
NSRR |
WSC |
|
NSRR |
STAGES |
|
NSRR |
Alzheimer’s disease study, healthy controls |
|
UZ Leuven |
Parkinson’s disease study, healthy older adults, night recordings |
|
UZ Leuven |
Recipe (the same for both models): 3 channels (EEG, EOG, EMG), seqsleepnet pipeline, site-balanced sampling
(make_site_sampler, every site gets the same probability mass, see Data), batch size 32, learning rate
1e-4 with a reduce-on-plateau scheduler, no weight decay, 300,000 windows per epoch, at most 20 epochs, channel dropout 0.5
in the channel mixer, seed 42. The released checkpoint is the one with the highest macro-averaged validation kappa among the
evaluated checkpoints (up to 30 validation subjects per site): step 161,500 (epoch 17) for PSN and step 129,000 (epoch 13)
for PST. Neighbouring checkpoints differ by about 0.001 kappa, so the choice is not critical.
Performance by training site#
Metrics are computed on the test subjects of each site, pooling the epochs of all of them (this is not a mean over
nights), with full-night sliding-window voting (windows of L epochs at L different offsets, overlapping predictions averaged). Accuracy, Cohen’s kappa and macro F1 over the five AASM
stages. Read the tables with these limits in mind:
The sites were seen in training (other subjects of the same sites), so this is not external validation: a new site, montage or population can perform differently.
Single training run (one seed), no confidence intervals. Several sites have 2-6 test subjects, so their values are noisy; SHHS is by far the largest test set (842 nights).
Per-site values mix population, scoring protocol and recording hardware; do not read a difference between two sites as a difference in model quality without checking the labels.
The two single-centre studies at the end of the training table (alzheimers_hc, parkinsons_night_hoa) were part of training but their per-site
metrics are not published, so the tables below list 26 of the 28 sites.
ProtoSleepNet (protosleepnet-gagliardi)#
Site |
Test subjects |
Accuracy |
Cohen’s kappa |
Macro F1 |
|---|---|---|---|---|
|
26 |
0.867 |
0.809 |
0.774 |
|
15 |
0.814 |
0.754 |
0.784 |
|
25 |
0.847 |
0.790 |
0.801 |
|
5 |
0.811 |
0.724 |
0.761 |
|
2 |
0.910 |
0.858 |
0.837 |
|
6 |
0.888 |
0.835 |
0.844 |
|
4 |
0.871 |
0.814 |
0.834 |
|
3 |
0.891 |
0.841 |
0.821 |
|
206 |
0.842 |
0.776 |
0.771 |
|
219 |
0.859 |
0.795 |
0.757 |
|
842 |
0.872 |
0.818 |
0.780 |
|
15 |
0.842 |
0.778 |
0.794 |
|
8 |
0.865 |
0.800 |
0.806 |
|
3 |
0.814 |
0.729 |
0.691 |
|
19 |
0.804 |
0.679 |
0.697 |
|
3 |
0.812 |
0.732 |
0.740 |
|
5 |
0.826 |
0.696 |
0.673 |
|
8 |
0.836 |
0.722 |
0.711 |
|
6 |
0.840 |
0.764 |
0.787 |
|
4 |
0.854 |
0.735 |
0.742 |
|
15 |
0.805 |
0.711 |
0.734 |
|
3 |
0.823 |
0.745 |
0.771 |
|
29 |
0.849 |
0.779 |
0.800 |
|
16 |
0.802 |
0.708 |
0.704 |
|
49 |
0.691 |
0.591 |
0.630 |
|
235 |
0.833 |
0.735 |
0.729 |
ProtoSleepTransformer (protosleeptransformer-gagliardi)#
Site |
Test subjects |
Accuracy |
Cohen’s kappa |
Macro F1 |
|---|---|---|---|---|
|
26 |
0.870 |
0.814 |
0.781 |
|
15 |
0.815 |
0.754 |
0.789 |
|
25 |
0.857 |
0.803 |
0.812 |
|
5 |
0.810 |
0.723 |
0.766 |
|
2 |
0.899 |
0.841 |
0.833 |
|
6 |
0.894 |
0.843 |
0.846 |
|
4 |
0.870 |
0.812 |
0.829 |
|
3 |
0.888 |
0.838 |
0.824 |
|
206 |
0.842 |
0.778 |
0.778 |
|
219 |
0.872 |
0.811 |
0.765 |
|
842 |
0.880 |
0.829 |
0.797 |
|
15 |
0.842 |
0.775 |
0.780 |
|
8 |
0.873 |
0.811 |
0.817 |
|
3 |
0.828 |
0.749 |
0.708 |
|
19 |
0.777 |
0.649 |
0.688 |
|
3 |
0.790 |
0.699 |
0.698 |
|
5 |
0.821 |
0.692 |
0.676 |
|
8 |
0.812 |
0.675 |
0.674 |
|
6 |
0.834 |
0.763 |
0.794 |
|
4 |
0.853 |
0.743 |
0.757 |
|
15 |
0.819 |
0.730 |
0.749 |
|
3 |
0.823 |
0.743 |
0.763 |
|
29 |
0.844 |
0.773 |
0.796 |
|
16 |
0.812 |
0.724 |
0.717 |
|
49 |
0.720 |
0.632 |
0.672 |
|
235 |
0.845 |
0.750 |
0.739 |
The same numbers are stored with the weights (metrics.json in each model folder on the Hub).
Intended use and limits#
For research on sleep staging and its interpretability; not a medical device, and not for clinical diagnosis. The models expect the spectrogram input described above: a different preprocessing, signal amplitude scale or montage changes the input distribution, so check the staging on a sample of your own data before relying on it. The channel set is fixed to EEG, EOG and EMG (the channel mixer was trained with random channel dropout, which makes the models tolerant to a missing channel, but this was not evaluated per site here).
Reproducibility#
Every model folder on the Hub has config.json with the factory call and the training summary, including the SHA-256 of
model.pt:
Hub name |
Checkpoint step |
SHA-256 of |
|---|---|---|
|
161,500 |
|
|
129,000 |
|
physioex/examples/pretrained/protosleepnet/export_release.py builds the folder from a training checkpoint and its per-site
evaluation; nothing is recomputed, and the metrics are copied unchanged.
API#
- class physioex.models.protosleepnet.ProtoSleepNet(epoch_encoder, sequence_encoder, classifier, n_channels=1, n_classes=5, d_model=128, use_channel_mixer=False, cdropout=0.5, cm_n_heads=4, cm_d_ff=256, cm_n_layers=1)[source]
Bases:
ModuleTemplate-based sleep staging model with dual residual connections.
Wraps any epoch_encoder + sequence_encoder with: - Optional channel mixer (for multi-channel input) - Residual sequence encoder: z = h + seq(h) - Single classifier
- Parameters:
epoch_encoder (Module) – maps (N, 1, T, F) → (N, d_model) for per-channel, or (N, C, T, F) → (N, d_model) for single-channel
sequence_encoder (Module) – maps (B, L, d_model) → (B, L, d_model)
classifier (Module) – maps (N, d_model) → (N, n_classes)
n_channels (int) – number of input channels (1 = no mixer)
n_classes (int) – number of output classes
d_model (int) – epoch encoder output dimension
use_channel_mixer (bool) – enable channel mixer (requires n_channels > 1)
cdropout (float) – channel dropout probability
cm_n_heads (int) – mixer transformer heads
cm_d_ff (int) – mixer transformer feedforward dim
cm_n_layers (int) – mixer transformer layers
- encode(x, quantize=False)[source]
Encode input spectrograms to contextualized per-epoch embeddings.
Calls epoch_encode → sequence_encode.
- Parameters:
x – (B, L, C, T, F) spectrogram input.
quantize – if True, replace epoch embeddings with nearest codebook entry. Requires set_codebook() first.
- Returns:
(B, L, d_model) contextualized epoch embeddings.
- epoch_encode(x, quantize=False)[source]
Encode input spectrograms to per-epoch embeddings.
Pipeline: per-channel epoch encoding → [channel mixer] → [VQ] → deep supervision (epoch_logits stored in metrics).
- Parameters:
x – (B, L, C, T, F) spectrogram input.
quantize – if True, replace epoch embeddings with nearest codebook entry. Requires set_codebook() first.
- Returns:
(B, L, d_model) epoch embeddings (pre-sequence).
- forward(x, quantize=False)[source]
Forward pass: encode → classify.
- Parameters:
x – (B, L, C, T, F) spectrogram input.
quantize – if True, replace epoch embeddings with nearest codebook entry. Requires set_codebook() first.
- Returns:
(B, L, n_classes) per-epoch logits.
- classmethod from_seq_sleep_net(n_channels=1, n_classes=5, F=129, D=32, nfft=256, lowfreq=0, highfreq=50, fs=100, seqnhidden1=64, seqnlayer1=4, attentionsize=32, seqnhidden2=64, seqnlayer2=4, **mixer_kwargs)[source]
Build ProtoSleepNet with SeqSleepNet backbone.
- classmethod from_sleep_transformer(n_channels=1, n_classes=5, d_model=128, n_heads=8, n_epoch_layers=4, n_seq_layers=4, d_ff=1024, d_clf=1024, dropout=0.1, attention_size=128, **mixer_kwargs)[source]
Build ProtoSleepNet with SleepTransformer backbone.
- sequence_encode(h)[source]
Contextualize epoch embeddings with residual sequence encoding.
- Parameters:
h – (B, L, d_model) epoch embeddings.
- Returns:
h + seq(h).
- Return type:
(B, L, d_model) contextualized embeddings
- set_codebook(codebook)[source]
Set VQ codebook for prototype quantization.
- Parameters:
codebook – (M, d_model) numpy array or torch tensor.