Skip to content
All projects
Applied ML

SleepSense AI

I built an end-to-end pipeline that turns raw overnight sleep recordings into labelled 30-second windows and trains two deep models to separate normal breathing, hypopnea and obstructive apnea.

Pipeline06 stages
  1. 01
    Overnight signal export
  2. 02
    Butterworth 0.17-0.4 Hz
  3. 03
    30 s windows, 50% overlap
  4. 04
    Event-based labelling
  5. 05
    1D CNN / Conv-LSTM
  6. 06
    Leave-one-participant-out CV
Schematic, not a screenshot

01Problem

Scoring overnight breathing events by hand is slow specialist work, and the events that matter are rare: in this recording set obstructive apnea accounts for 36 of 1318 windows.

02Implementation

  • Parsed the raw signal exports and clinical event annotations, aligning nasal airflow, thoracic movement and SpO2 on their timestamps.
  • Applied a Butterworth bandpass at 0.17 to 0.4 Hz with SciPy to isolate the breathing band before segmentation.
  • Segmented the recordings into 30-second windows at 50% overlap and labelled each one from the annotated event intervals.
  • Trained a 1D CNN, three Conv1d and BatchNorm blocks into adaptive average pooling with dropout, on 3-channel 960-sample windows in PyTorch.
  • Trained a Conv-LSTM alternative, two convolutional blocks feeding a single-layer LSTM, on the same windows.
  • Evaluated with leave-one-participant-out cross-validation so that no participant appears in both training and test folds.

03Models

1D CNN
Three Conv1d and BatchNorm blocks, adaptive average pooling, dropout, then a linear classifier.
Conv-LSTM
Two convolutional blocks feeding a single-layer LSTM, classified from the final timestep.
Butterworth bandpass filter
Isolates the 0.17 to 0.4 Hz breathing band before windowing.

04Input data

Overnight recordings from 5 participants: nasal airflow, thoracic movement and SpO2. The processed set is 1318 windows, split 886 normal, 396 hypopnea and 36 obstructive apnea.

05Results

Both models land near 0.53 accuracy under leave-one-participant-out validation. With 5 participants and 36 apnea examples that is the honest result, and the value of the project is the pipeline and the evaluation protocol rather than the classifier.

  • 1D CNN, leave-one-participant-out: accuracy 0.53, precision 0.30, recall 0.33
  • Conv-LSTM, leave-one-participant-out: accuracy 0.53, precision 0.33, recall 0.31
  • Dataset: 1318 windows from 5 participants (886 / 396 / 36 per class)

These numbers come from held-out-participant validation, which is deliberately harder than a random window split. A random split would leak windows from the same night into both sides and report a much better number that would not survive a new participant.

06Decisions

  • Evaluated leave-one-participant-out rather than with a random split, because a random split leaks windows from the same participant into training and test and inflates the score.
  • Filtered to 0.17 to 0.4 Hz before windowing to keep the breathing band and drop baseline drift and higher-frequency noise.

07Stack

PythonPyTorchSciPyScikit-learnpandasNumPy

08Visuals

RAW SIGNALBANDPASS 0.17–0.4 HZ30 S WINDOW · 50% OVERLAPCONV1DCONV1DCONV1DLSTMNORMALHYPOPNEAOBSTRUCTIVE APNEA
Illustrative visualization — a diagram of the technique, not a screenshot or a real output

Screenshots of the running project will replace this once they are available.