Sleep-state scoring for mouse EEG/EMG (+ video)
Somnus assigns Wake / NREM / REM to every 4-second epoch of a mouse polysomnography recording, using EEG, EMG, and — when available — video-derived locomotion. It includes a trained logistic model, a batch scorer, a review interface for correcting the model's output, and a fine-tuning step that adapts the model to your dataset.
The design goal is not maximum accuracy on one rig. It is a system that runs on whatever data you have, and that can be readily adapted to disease models with degraded sleep architecture where heavier commercial scorers may fail altogether.
Features are computed in frequency tiers gated by each recording's measured bandwidth. The temporal structure of sleep comes from an HMM/Viterbi model with a "transition resistance" knob which allows you to adjust the frequency of state transitions. This can also be retrained on data from your model organism.
Install
Install somnus in a virtual environment using conda, with a python version > 3.12:
conda create -n somnus-eeg python=3.13 -y
conda activate somnus-eeg
pip install somnus-eeg
The desktop GUI
To start the GUI, use:
somnus-gui
The GUI includes a five-tab workflow: Project (point it at a folder of recordings) → Score (batch scoring with smoothing controls) → Review & Relabel (whole-recording hypnogram with a confidence trace, plus a signal/video scorer pre-loaded with the model's labels, so you correct rather than score from scratch) → Fine-tune (adapt the model to your corrections) → Evaluate (compare against the base model; export sleep-architecture statistics).
Two notes: source data is never written to, and the model never trains on its own output — every epoch records where its label came from, and only manually sourced labels can become training targets.
Alternative -- Score a recording in Python
from somnus import load_model
from somnus.predict import predict
from somnus.data.datasets import featurize
art = load_model() # the packaged v1.0 model
df = featurize({"recording": "myrec", "edf": "path/to/myrec.edf",
"dataset": "user", "group": "user", "subject": "m1",
"scored": None, "pkl": None},
eeg_chan=[1, 2, 3], emg_chan=4)
labels, proba = predict(art, df) # per-epoch states + probabilities
eeg_chan and emg_chan set which channels are which, by number (counted
from 1) or by name. When several EEG channels are named, the best snr is used.
predict(..., stickiness=...) controls the temporal decode: 0 disables
smoothing, 1 uses the transition matrix as estimated, >1 enforces longer
bouts.
Video tracking (optional)
If a recording has video with the animal's position tracked, Somnus adds a
locomotion feature. Pass the tracking file as "pkl" in the featurize()
entry, or put it beside the EDF and the GUI will find it.
One row per video frame, in frame order. Accepted formats:
| File | Contents |
|---|---|
.csv |
A DeepLabCut export, or any table with x and y columns |
.h5 |
A DeepLabCut export (needs pip install tables) |
.pkl |
An (n_frames, 2) array of x/y, or a dict with a coordinates key |
A DeepLabCut file usually tracks many bodyparts. Somnus uses the one named
mouse_center; if the file tracks exactly one bodypart, it uses that.
Otherwise it stops rather than guess which point represents the animal — export
a mouse_center bodypart, or hand it a plain two-column x,y table instead.
Filter low-confidence points yourself. Somnus does not drop them, so a badly
tracked frame reads as real movement. Replace rejected points with NaN before
passing the file.
Frame times are strongly suggested. Somnus looks for a
*_timestamps.npy beside the tracking file with exactly one timestamp per row.
Cameras drop frames, so assuming a constant frame rate can misplace positions by
minutes; if no timestamps file is found, Somnus requires confirmation.
Fine-tuning
The performance loss on labeled epochs is minimized with a penalty that pulls the weights toward the existing model. We use a parameter λ, where "keep the shipped model" (λ→∞), and "train on my data alone" (λ→0). The default λ value is chosen by cross-validation on your recordings, so fine-tune versus retrain is decided by evidence.
Performance
Tested on held-out mice from a public multi-lab validation corpus — 74 subjects, ~1.52 million labeled epochs — after training on 61,164 epochs from six labs:
| metric | value |
|---|---|
| accuracy | 0.914 |
| balanced accuracy | 0.858 |
| Cohen's κ | 0.845 |
On in-house 5 kHz recordings (leave-one-recording-out): accuracy 0.975.
Limitations to keep in mind
- REM scoring criteria differ between labs so a general model necessarily compromises; (F1 REM 0.728 vs >0.90 for Wake/NREM). Fine-tuning to your own data is the intended remedy!
- Every recording must contain both sleep and wake. The model depends on z-scoring within each recording to accept a wide range of recording conditions, so on a recording containing only one sleep/wake state — for example a short session where the animal never sleeps — it fails completely.
A full write-up of the evaluation, caveats, and design rationale will accompany the forthcoming preprint.
See docs/DEVELOPMENT.md for the module reference.
License
BSD 3-Clause. The trained model was fitted in part on a publicly available multi-lab mouse polysomnography dataset. PSD estimation uses openseize.
Citation
A preprint is in preparation; until then, please cite this repository.
Metadata
Release files for somnus-eeg 1.0.5
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| somnus_eeg-1.0.5.tar.gz | 83.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| somnus_eeg-1.0.5-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 168.6 kB
Release files / somnus_eeg-1.0.5.tar.gz
| Download URL | somnus_eeg-1.0.5.tar.gz |
|---|---|
| Size | 83.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ac42d9c7a8e56e775d653ea417dd01e21a3e7b8f80ba7906160479bf14831fbe
|
|
BLAKE2b-256 checksum How to use checksums |
68a43d5fa5562f085387afdd8bc752d89fee498c57e2ca5ffe13ec3807cd220a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / somnus_eeg-1.0.5-py3-none-any.whl
| Download URL | somnus_eeg-1.0.5-py3-none-any.whl |
|---|---|
| Size | 85.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
38881ff1e3c8b9058230485e75e365d705173a8e6b5dcf462d1fe0b6c8280233
|
|
BLAKE2b-256 checksum How to use checksums |
9debece515657fb4585bf289e400887e077ec7fb2feaf66bb95ecaf52563ba89
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|