Skip to content

On device adaptation - #3

Merged
Trexz14 merged 6 commits into
mainfrom
on-device-adaptation
Jun 15, 2026
Merged

Trexz14 merged 6 commits into
mainfrom
on-device-adaptation

Conversation

@Trexz14

@Trexz14 Trexz14 commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

Copilot AI review requested due to automatic review settings June 15, 2026 12:32
@Trexz14
Trexz14 merged commit 73260a6 into main Jun 15, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an “on-device adaptation” demo and supporting tooling for CAP detection/classification, including a NumPy reference model, offline model comparisons (linear/RF/CNN + ensemble), a raw-stream replay script for training/eval on the Arduino, and a C++ parity harness to validate the on-device training core against Python.

Changes:

  • Introduces a shared dataset cache builder + deterministic within-rat temporal split utilities for comparable model evaluation.
  • Adds an on-device streaming/adaptation workflow (host replay + Arduino sketch + C++ model core + host parity test).
  • Adds documentation for running the demos and (separately) includes an article markdown export.

Reviewed changes

Copilot reviewed 19 out of 21 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
scripts/cap_pipeline/ondevice/task_data.py Shared task definition, deterministic splits, and prediction save/load helpers for model comparisons
scripts/cap_pipeline/ondevice/stream_raw.py Host-side raw replay streamer + offline self-test for on-device training/adaptation demo
scripts/cap_pipeline/ondevice/showcase.py Offline demos of online learning, cross-rat adaptation, and channel dropout using the NumPy model
scripts/cap_pipeline/ondevice/README.md Usage docs for the on-device pipeline
scripts/cap_pipeline/ondevice/model.py NumPy reference feature extractor, running standardizer, and SGD logistic regression
scripts/cap_pipeline/ondevice/model_linear.py sklearn logistic regression baseline using shared split/task
scripts/cap_pipeline/ondevice/model_random_forest.py sklearn random forest baseline using shared split/task
scripts/cap_pipeline/ondevice/model_cnn.py PyTorch two-stream CNN baseline using shared split/task
scripts/cap_pipeline/ondevice/model_ensemble.py Soft-voting ensemble over saved per-sample probabilities
scripts/cap_pipeline/ondevice/build_dataset.py Cache builder: reads .rhd, detects CAPs, saves 56×100 windows
scripts/Arduino/ondevice_train/test_host.cpp Host-side C++ parity runner for the on-device model core
scripts/Arduino/ondevice_train/README.md Instructions for generating parity data and running the host test
scripts/Arduino/ondevice_train/make_parity.py Exports parity fixtures + Python reference outputs for the C++ test
scripts/Arduino/ondevice_train/.gitignore Ignores generated parity artifacts/binaries
scripts/Arduino/ArduinoOnDeviceTrain/README.md Arduino sketch usage documentation
scripts/Arduino/ArduinoOnDeviceTrain/ondevice_model.h Arduino/host-shared model API (features, standardizer, SGD logreg)
scripts/Arduino/ArduinoOnDeviceTrain/ondevice_model.cpp Arduino/host-shared model implementation
scripts/Arduino/ArduinoOnDeviceTrain/ArduinoOnDeviceTrain.ino Full Arduino sketch: detection + feature extraction + online training + eval-only mode
articles/2022_Resource_efficient_Neural_Network_Architectures_for_Classifying_Nerve_Cuff_Recordings.md Adds a markdown version of an external paper
.gitignore Ignores generated caches and Torch weight files

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

float feat[OD_N_FEAT];
double z[OD_N_FEAT];
od_extract_features(od_window, feat);
if (!eval) od_std.update(feat);
trigs, _ = detect(raw, warmup=int(0.5 * FS))
for t in trigs:
if t - LEAD >= 0 and t + TRAIL <= N:
events.append((raw[t - LEAD: t + TRAIL], cls))
Comment on lines +20 to +23
HERE = pathlib.Path(__file__).resolve().parent
OND = HERE.parents[1] / "cap_pipeline" / "ondevice"
CACHE = HERE.parents[1] / "cap_pipeline" / "caches" / "cap_windows_rich.npz"
sys.path.insert(0, str(OND))
Checks the C++ training core (ondevice_model.*) against the Python reference.
Run make_parity.py first to produce the data files, then:

g++ -O2 -std=c++17 test_host.cpp ondevice_model.cpp -o test_host && ./test_host
g++ -O2 -std=c++17 test_host.cpp ../ArduinoOnDeviceTrain/ondevice_model.cpp -o test_host
./test_host
```
Should print all PASS (predictions identical, weights match to ~1e-15).
Comment on lines +7 to +9
We use this task because dorsi vs plantar basically can't be told apart in this
data (~50%, see `docs/replication_investigation_2026-06.md`), but pricking vs
movement works ok — around 70% when we stay within one rat.
Comment on lines +1 to +4
# Content from 2022.10.05.510983v1.full.pdf

bioRxiv preprint doi: https://doi.org/10.1101/2022.10.05.510983; this version posted October 7, 2022. The copyright holder for this preprint (which was not certified by peer review) is the author/funder. All rights reserved. No reuse allowed without permission.

Comment on lines +28 to +30
def load():
d = np.load(CACHE)
X, y3, rat = d["X"].astype(np.float32), d["y"], d["rat"]
Comment on lines +16 to +17
## How to run
Build the window cache once (takes a couple of minutes):
DATA_DIR = HERE.parents[2] / "data" # <repo>/data
CACHE = HERE.parent / "caches" / "cap_windows_rich.npz"

# Each recording folder and its class label. (RAT7 uses a 64-ch cuff -> skipped.)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants