Loading…
Loading…
Sleep stages from triaxial accelerometer recordings.
4-class sleep stage prediction, metric reports, and hypnograms.
Built with a focus on sleep-wake.
| Predicts | wake, light, deep, rem per 30-s epoch |
|---|---|
| For | Adults |
| Input | Timestamped triaxial accelerometer, 12 Hz or faster |
| Score | Cohen's κ 0.60 sleep/wake · 0.43 4-stage (SleepAccel, 28 subjects) |
| Review | ✅ Reviewed |
| License | MIT |
pip install 'arcasleep[bidoze,inference,hub]'
hf download arcascope/arcasleep-bidoze-adult --local-dir arcasleep-bidoze-adult
# One CSV per recording: epoch, start_s, wake, light, deep, rem, stage, stage_raw, is_nap, is_sib, is_spt, is_gap
# plus <name>_summary.csv: subject_id, tst_minutes, missing_data_minutes, nap_minutes
# --hypnogram also saves <name>.png (needs the [report] extra)
arcasleep bidoze predict arcasleep-bidoze-adult recordings/*.csv -o predictions/ --hypnogram
# Or draw hypnograms later from the CSVs
arcasleep hypnogram predictions/*.csv
Or from Python:
from arcasleep.predict import Predictor, read_accelerometer
predictor = Predictor("arcasleep-bidoze-adult") # load once, reuse
accel = read_accelerometer("night.csv") # (N, 4): t [s], x, y, z [g]
result = predictor.predict(accel)
result.probabilities # (epochs, 4): wake, light, deep, rem
result.labels # corrected stage per 30-s epoch, "gap" where no data
result.raw_labels # the model's raw stage, before filtering
result.summary # subject_id, tst_minutes, missing_data_minutes, nap_minutes
result.epoch_start_s # epoch start times, on the input clock
result.to_csv("night_stages.csv")
result.plot("night_stages.png") # hypnogram; needs the [report] extra
By default the corrected stage applies a GGIR-style sleep filter; the
definition depends on recording length:
stage is the model's own
scoring, stage_raw.is_spt). Inside this the model's scoring is unchanged. Outside it, sleep becomes
wake unless the wrist was still for at least 5 minutes (is_sib), and the
sleep that remains is flagged by is_nap == 1.A gap of 60 minutes or more without data splits a recording, and each part is
judged on its own length. Pass ggir_sleep_filter=False (or
--no-ggir-sleep-filter) for the unfiltered output. The hypnogram shows the
raw and filtered stages, the sleep the filter removed, and the SIB and SPT
tracks.
Pass origin= (seconds on the input clock, or "unix") to put epoch
boundaries somewhere other than the first sample, for example at the start of a
PSG recording you want to compare with.
Metrics compare model predictions with reference PSG scoring, macro-averaged over subjects, with 95% confidence intervals of the mean.
Protocol. The model is the F2 network, trained three times (three seeds) on all 634 revised-Weaver recordings (237 children) plus SleepAccel (28 recordings) and Wearanize+ (92 nights). SleepAccel and Wearanize+ were each split into five fixed, participant-level folds. The SleepAccel and Wearanize+ columns pool five fold models, each scoring the fold it did not train on, with one value per recording. The released model was trained on all of Weaver, SleepAccel and Wearanize+ and scored on SleepAccel-Clinical, which no model trained on.
All metrics, per cohort'Higher is better' and 'lower is better' describe how to read each metric; they do not indicate improvement over a control or baseline model or a comparison between cohorts.
| Metric | SleepAccel n = 28 |
SleepAccel-Clinical n = 32 |
Wearanize+ n = 92 |
|---|---|---|---|
| Cohen's κ, sleep/wake — higher is better | 0.60 0.54 to 0.66 |
0.58 0.52 to 0.65 |
0.61 0.57 to 0.65 |
| Sleep sensitivity (%) — higher is better | 95.8 94.9 to 96.7 |
94.5 92.8 to 96.2 |
94.5 93.9 to 95.1 |
| Wake specificity (%) — higher is better | 74.8 67.5 to 82.1 |
67.0 59.0 to 74.9 |
82.8 79.5 to 86.2 |
| TST error (min) | −5.6 −11.9 to +0.7 |
+17.1 +2.7 to +31.5 |
−12.1 −17.6 to −6.6 |
| WASO error (min) | +4.1 −1.1 to +9.4 |
−14.3 −23.8 to −4.7 |
+8.3 +3.3 to +13.4 |
| Metric | n | Mean | 95% CI | Median |
|---|---|---|---|---|
Cohen's κ, sleep/wake — higher is betterkappa_sleep_wake |
28 | 0.60 | 0.54 to 0.66 | 0.62 |
Sleep sensitivity (%) — higher is bettersleep_sensitivity |
28 | 95.8 | 94.9 to 96.7 | 96.3 |
Wake specificity (%) — higher is betterwake_specificity |
28 | 74.8 | 67.5 to 82.1 | 81.0 |
TST error (min)tst_error_minutes |
28 | −5.6 | −11.9 to +0.7 | −5.8 |
WASO error (min)waso_error_minutes |
28 | +4.1 | −1.1 to +9.4 | +4.5 |
| Metric | n | Mean | 95% CI | Median |
|---|---|---|---|---|
Cohen's κ, sleep/wake — higher is betterkappa_sleep_wake |
32 | 0.58 | 0.52 to 0.65 | 0.63 |
Sleep sensitivity (%) — higher is bettersleep_sensitivity |
32 | 94.5 | 92.8 to 96.2 | 96.0 |
Wake specificity (%) — higher is betterwake_specificity |
32 | 67.0 | 59.0 to 74.9 | 72.2 |
TST error (min)tst_error_minutes |
32 | +17.1 | +2.7 to +31.5 | +5.0 |
WASO error (min)waso_error_minutes |
32 | −14.3 | −23.8 to −4.7 | −15.0 |
| Metric | n | Mean | 95% CI | Median |
|---|---|---|---|---|
Cohen's κ, sleep/wake — higher is betterkappa_sleep_wake |
92 | 0.61 | 0.57 to 0.65 | 0.65 |
Sleep sensitivity (%) — higher is bettersleep_sensitivity |
92 | 94.5 | 93.9 to 95.1 | 95.2 |
Wake specificity (%) — higher is betterwake_specificity |
92 | 82.8 | 79.5 to 86.2 | 87.9 |
TST error (min)tst_error_minutes |
92 | −12.1 | −17.6 to −6.6 | −15.2 |
WASO error (min)waso_error_minutes |
92 | +8.3 | +3.3 to +13.4 | +10.2 |
Research estimates of sleep and wake, and of light, deep and REM sleep, from a wrist-worn accelerometer in adults. Running BiDoze does not require polysomnography (PSG). PSG can be used to measure its accuracy on your own cohort.
Sleep/wake is the primary task. Report stage estimates as cohort means, not as per-night measurements.
Not a medical device. Do not use it to diagnose sleep disorders (including obstructive sleep apnea), to screen individuals, or to make clinical decisions.
There are two adult releases of BiDoze v0.2.0:
arcasleep-bidoze-adult:
three networks; their outputs are averaged.arcasleep-bidoze-adult-small:
one network.How they are related.
adult-small network is seed 0 of adult; the weights are identical.adult, the network output used for labeling is the average of the three
networks' outputs.adult |
adult-small |
|
|---|---|---|
| Networks | 3 | 1 |
| Weights | 6,590,376 | 2,196,792 |
model.safetensors size |
26.5 MB | 8.8 MB |
| Compute per recording | 3× | 1× |
How their scores compare. Each value is the mean over nights,
adult vs adult-small. Differences marked * are significant at p ≤ 0.05
(paired Wilcoxon over nights); unmarked differences are not.
| Cohort (nights) | Sleep/wake κ | 4-stage κ | Sleep sensitivity | Wake specificity | TST error (min) |
|---|---|---|---|---|---|
| SleepAccel, cross-validation (28) | 0.597 vs 0.583 | 0.435 vs 0.429 | 95.8% vs 95.5% | 74.8% vs 74.4% | −5.6 vs −6.2 |
| Wearanize+, cross-validation (92) | 0.609 vs 0.588* | 0.420 vs 0.410* | 94.5% vs 94.2% | 82.8% vs 80.9%* | −12.1 vs −12.7 |
| SleepAccel-Clinical (32) | 0.583 vs 0.574 | 0.321 vs 0.309 | 94.5% vs 95.7%* | 67.0% vs 62.5%* | +17.1 vs +24.0* |
| AAUWSS (13) | 0.533 vs 0.529 | 0.343 vs 0.357 | 95.3% vs 96.7%* | 62.4% vs 55.7%* | +6.2 vs +15.9* |
| EESM19 (33) | 0.826 vs 0.824 | 0.507 vs 0.498 | 97.8% vs 97.9% | 87.6% vs 86.8% | −0.6 vs +0.7 |
TST error is model − PSG. Neither release was trained on SleepAccel-Clinical, AAUWSS or EESM19.
AAUWSS: 13 healthy adults aged 22–71, one lab night each, Empatica E4.
EESM19 (OpenNeuro ds005185): 33 nights from 16 adults, GENEActiv wrist accelerometer at 100 Hz.
Wake specificity is higher for adult: by 2.0 points on Wearanize+,
4.5 points on SleepAccel-Clinical and 6.7 points on AAUWSS (all p < 0.001).
Total sleep time is overestimated by 17.1 minutes with adult vs 24.0
minutes with adult-small on SleepAccel-Clinical (p < 0.001), and by 6.2
vs 15.9 minutes on AAUWSS (p = 0.001).
No metric differs significantly on SleepAccel (sleep/wake κ difference +0.015, p = 0.093) or EESM19.
Use adult unless model size or compute is a constraint.
The bundle holds three networks of one architecture, trained with different random seeds. Their outputs are averaged, then each 30-s epoch is labeled in two steps:
stage_divisor in config.json; the largest quotient gives the stage.The divisor corrects for two properties of the training: the loss weights rare stages up, and most training recordings are of children, who spend a larger share of sleep in deep sleep than adults (33% of PSG sleep in the pediatric training data). The adult stage proportions in the divisor are those of the adult training recordings, SleepAccel and Wearanize+ (deep sleep 19.7% of PSG sleep).
Output columns:
wake: the averaged probability of wake.light, deep, rem: 1 − wake, split in proportion to the divided
probabilities.stage: the label from steps 1 and 2. This is not always the largest of the
four columns.Not trained on:
is_gap set; leave them out of sleep durations.Per 30-second epoch, one probability per stage, in this order:
| Index | Stage | Meaning |
|---|---|---|
| 0 | wake |
Wake |
| 1 | light |
Light sleep |
| 2 | deep |
Deep sleep |
| 3 | rem |
REM sleep |
is_gap is not a model output: it marks epochs with no accelerometer samples.
3 narrow bi-causal networks (strands) each score every epoch: a convolution bank (kernels 3, 7, 31, 63 epochs, width 112), a bi-causal transformer (4 layers per direction) and a learned gate. A fusion transformer (2 layers, width 128, 4 heads) reads the strands' features across the whole recording and gives the per-epoch output (2.20 M parameters).
The release is 3 models of this architecture, each trained with a different seed (6,590,376 weights in all). Their weights are in model.safetensors under the prefixes member0/ to member2/. The mean of their outputs decides wake or sleep. On the epochs called sleep, the light, deep and REM probabilities are each divided by the stage divisor in config.json (deep 0.00422, light 0.00162, rem 0.00359) before the most probable stage is chosen.
log_psd spectrograms of the mag and jerk channels over 10-s windows every 2 s (60 bins, 0.1–6.0 Hz), averaged to 30-s epochs, plus one row giving the fraction of each epoch with no data. The model input for one pass is (3000, 61, 2). arcasleep.predict builds it from preprocessing.json.
| File | Contents |
|---|---|
model.safetensors |
Weights, as a flat slash-separated tensor map |
config.json |
Architecture settings; rebuilds the network |
preprocessing.json |
Spectrogram settings the inputs must match |
metrics.json |
The scoring protocol behind the evaluation numbers |
provenance.json |
Code, config, split and checkpoint hashes |
checksums.sha256 |
SHA-256 of every file in this release |
assets/adult-architecture.png |
Figure shown on this card |
assets/metrics_grid.png |
Figure shown on this card |
| Field | Value |
|---|---|
| package_version | 0.2.0 |
| git_commit | d47a710 |
| split_manifest_sha256 | d474441e4d5a7b493c0e099341e7d407dab2b9553b6b989d6bd7164f8e78ae34 |
| model_config_sha256 | 61b1bb1c87421126a2b87183b632df8c892bfb3efb0bf2a2592a40c529b9400e |
| processing_config_sha256 | 280f677e714673b6fe6db3cd6b16178e8b4ef52919b0270bbe61976f413529df |
| training_config_sha256 | fb33da993f938d785ed75ea425e77eb25cf2bd9fae68eddc477203f3e3d8e06b |
| member0 | seed 0, epoch 26, checkpoint_sha256 b36883a47f480d43778ac39c58b0cdb7e6f8375a238def0ea8005fa1450c8df9 |
| member1 | seed 1, epoch 18, checkpoint_sha256 b8c8948cfc62bad1b72c97035b3e571e2ee727fb2c4d1c4c3f41dc16279266f8 |
| member2 | seed 2, epoch 35, checkpoint_sha256 6d56883857b79472453388c81a28676c263d608b340a450ca0c37ab9861aa717 |
Check a download with sha256sum -c checksums.sha256.
Generated by python -m arcasleep_bidoze.release card from d47a710.