Skip to content

Latest commit

 

History

9 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Wearable Sensor Activity Classification

A deep learning project classifying human activity (walking, walking upstairs, walking downstairs, sitting, standing, laying) from raw wearable accelerometer and gyroscope data, using the UCI Human Activity Recognition (HAR) dataset.

I built this to get hands-on experience with the kind of deep learning and signal-processing work I do professionally in a research context — my background is in biomechanical sensor data (multi-sensor IMU synchronization, signal processing) from two years as a research assistant at Beth Israel Deaconess Medical Center, and this project applies that same domain to a public benchmark dataset with a full deep learning pipeline: EDA, a baseline model, and a CNN + self-attention architecture trained from raw signal data.

Results at a glance: a logistic regression baseline (76.5% accuracy) and a CNN + self-attention model (90.5% accuracy) that specifically closes the gap the baseline couldn't — distinguishing between different types of movement, not just movement from stillness. Full analysis below.

Setup

pip install -r requirements.txt

Optional — GPU acceleration: if you have an NVIDIA GPU, install a CUDA-matched PyTorch build instead of the default CPU version. Check your driver's supported CUDA version with nvidia-smi, then get the exact install command from pytorch.org/get-started/locally.

Exploratory Data Analysis

Before building a model, I plotted one example window of body acceleration (x, y, z) for each of the six activity classes to understand what separates them at the raw signal level.

Signals by activity

Key observations:

  • Dynamic activities (walking, walking upstairs, walking downstairs) show periodic, high-amplitude oscillation — consistent with a repeating gait cycle. Walking downstairs shows the sharpest peaks of the three (nearing 0.8g on the x-axis), likely reflecting the more abrupt deceleration events involved in descending steps.

  • Static activities (sitting, standing, laying) show dramatically lower amplitude and variance — the body isn't generating repeated acceleration, so the signal stays close to a flat baseline.

  • Standing is the flattest of all six — the most physically static posture, and the signal reflects that almost perfectly.

  • Sitting shows an interesting transient at the start of the window — acceleration begins around 0.3-0.4g and decays toward zero over the first ~60 timesteps. This likely captures the sensor settling as the subject completes the act of sitting down, rather than steady-state stillness from the start.

Implication for modeling: separating static from dynamic activities looks like it should be straightforward from amplitude/variance alone. The harder problem is distinguishing between the three dynamic activities (walking, upstairs, downstairs), since they look visually similar to each other and differ more subtly in frequency and peak shape — this is where a model needs to do real work, not just amplitude thresholding.

Baseline Model

Before building a deep learning model, I established a simple baseline: a logistic regression classifier trained on hand-crafted features (mean and standard deviation of each of the 9 sensor channels per window).

Result: 76.5% accuracy

Baseline confusion matrix

This confirms the hypothesis from the EDA step, precisely: every misclassification among the three walking activities (WALKING, WALKING_UPSTAIRS, WALKING_DOWNSTAIRS) stays within that group — zero walking samples were predicted as sitting, standing, or laying. Mean and standard deviation cleanly separate movement from stillness, but can't distinguish different types of movement from each other, exactly as the raw signal plots suggested they wouldn't.

One honest anomaly: 27 LAYING samples were misclassified as WALKING_UPSTAIRS, which doesn't fit the otherwise clean "static vs. dynamic" story. I don't have a confirmed explanation for this yet — it's a specific thing to investigate if I extend this project further, rather than something the current approach explains.

This sets a concrete target for the next step: a model using the full temporal structure of the signal, not just summary statistics, should specifically improve on the three walking classes without needing to work harder on sitting/standing/laying, which are already well separated.

Deep Learning Model (CNN + Self-Attention)

A CNN with a self-attention layer, trained on the full raw 128-timestep signal rather than summary statistics.

Result: 90.5% accuracy (+14 points over the baseline)

Model confusion matrix

Activity Precision Recall F1
Walking 0.97 0.89 0.93
Walking Upstairs 0.87 0.99 0.92
Walking Downstairs 0.94 1.00 0.97
Sitting 0.79 0.82 0.81
Standing 0.87 0.78 0.83
Laying 1.00 0.98 0.99

This confirms what the EDA predicted: static activities would separate cleanly on amplitude/variance, while the three walking variants would need the model to use temporal shape, not just intensity. The baseline confirmed this, with walking variants scoring lowest. The deep model, given access to the full 128-timestep signal instead of just mean/std, improved walking-variant F1 scores by 0.24-0.30 each, while sitting/standing/laying performance stayed essentially unchanged.

Iteration: Batch Normalization + Data Augmentation

Starting from the CNN + self-attention model above, I added two specific improvements: batch normalization after each convolutional layer (for training stability) and on-the-fly data augmentation — random jitter and scaling applied fresh each epoch to reduce overfitting to the exact training signals.

Result: 93.5% accuracy (+3 points over the previous 90.5%)

Model confusion matrix

Activity Precision Recall F1
Walking 0.97 0.95 0.96
Walking Upstairs 0.94 0.93 0.93
Walking Downstairs 0.91 0.99 0.95
Sitting 0.92 0.82 0.86
Standing 0.88 0.93 0.90
Laying 1.00 1.00 1.00

What changed: unlike the previous jump (which was concentrated in the walking variants specifically, as predicted), this improvement is spread across nearly every class — Standing's F1 improved from 0.83 to 0.90 and Sitting's from 0.81 to 0.86, with Laying reaching a perfect score. That pattern suggests these two changes improved the model's general ability to generalize, rather than fixing one specific weakness the way the first architecture change did.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages