Behavioral-biometric identity verification from keystroke dynamics — neural networks built from scratch in pure NumPy.
KeyGuardian decides whether the person at the keyboard is the legitimate owner or an intruder, based purely on how they type (rhythm, hold times, key-to-key latencies) rather than what they type. Every neural network here is implemented from first principles with only numpy and math — no TensorFlow, PyTorch, or scikit-learn.
Academic project for the course Wstęp do algorytmów genetycznych i sztucznych sieci neuronowych (Introduction to Genetic Algorithms and Artificial Neural Networks).
- From-scratch deep learning — MLP and autoencoder with manual forward/backprop, He initialization, mini-batch gradient descent, numerically stable sigmoid, weighted binary cross-entropy and MSE losses.
- Two complementary approaches to the same problem (fixed-phrase classification vs. free-text novelty detection).
- Privacy by design — the free-text logger records only key timings and a category (
char/space/backspace). It never stores the characters you type, your passwords, or any text content. - Scientific validation — the methods are benchmarked on the public CMU Keystroke Dynamics dataset (Killourhy & Maxion, DSN 2009) with standard biometric metrics (FAR, FRR, EER, ROC/AUC).
- Live demo — a background detector raises a full-screen alert the moment an unfamiliar typing rhythm is detected.
A supervised Multi-Layer Perceptron trained to distinguish the owner (class 1) from impostors (class 0) on the fixed password .tie5Roanl.
- Owner samples are recorded with a small tkinter tool; impostors come from the 51 users of the CMU benchmark.
- 31 timing features per sample: hold time (
H.*), key-down-to-key-down (DD.*), and key-up-to-key-down (UD.*). - Class imbalance handled with inverse-frequency class weights inside the loss.
- Reported metrics: Accuracy, FAR, FRR, EER, ROC/AUC, plus convergence and confusion-matrix plots.
A one-class autoencoder trained to reconstruct only the owner's natural typing style. Text you type is windowed into fixed-length feature vectors (aggregate statistics of hold/DD/UD times, typing speed, backspace ratio, overlap ratio). A familiar rhythm reconstructs with low error; an unfamiliar one produces high reconstruction error → intruder.
- Works on any text — features are independent of what is typed.
- Decisions are smoothed over several consecutive windows to suppress false alarms.
- A live background detector (
pynput) monitors typing and pops a full-screen alert on a sustained mismatch.
KeyGuardian/
├── data/ # datasets (see data/README.md)
│ ├── DSL-StrongPasswordData.csv # CMU benchmark (impostors)
│ ├── owner_samples.csv # your fixed-phrase samples (from collect.py)
│ └── owner_freetext.csv # your free-text profile (from collect_freetext.py)
├── src/ # Phase 1 — fixed-phrase MLP
│ ├── collect.py # record your own fixed-phrase samples (tkinter)
│ ├── data.py # load, normalize (z-score), stratified split, class weights
│ ├── mlp.py # MLP: forward, backprop, training (from scratch)
│ ├── eval.py # metrics (Accuracy, FAR, FRR, EER, ROC/AUC) + plots
│ └── experiments.py # compare 3 configs, averaged over random seeds
├── live/ # Phase 2 — free-text autoencoder
│ ├── collect_freetext.py # privacy-preserving background logger (timings only)
│ ├── features.py # sliding-window free-text feature extractor
│ ├── autoencoder.py # one-class autoencoder (from scratch) + save/load
│ ├── train.py # train owner model, pick threshold, save owner_model.npz
│ ├── detector.py # LIVE detector with full-screen intruder alert
│ ├── eval_cmu.py # validate the one-class method on the CMU benchmark
│ └── eval_intruder.py # record/evaluate a test session (genuine vs intruder)
├── results/ # generated plots and comparison tables
├── DOKUMENTACJA.ipynb # final report / documentation (Jupyter)
├── requirements.txt
└── README.md
pip install -r requirements.txtCore dependencies are numpy and matplotlib. The live free-text tools (live/collect_freetext.py, live/detector.py) additionally need pynput for global keyboard listening:
pip install pynputDownload the CMU Keystroke Dynamics benchmark (DSL-StrongPasswordData.csv) and place it in data/. See data/README.md for the exact steps.
# (optional) record your own samples of ".tie5Roanl"
python src/collect.py
# inspect the prepared dataset
python src/data.py
# quick training sanity check
python src/mlp.py
# train + full evaluation (writes plots to results/)
python src/eval.py
# run the 3-configuration comparison
python src/experiments.py# 1) build your typing profile (records only timings + key category)
python live/collect_freetext.py # repeat over several sessions for a better profile
# 2) train the one-class autoencoder on your profile
python live/train.py
# 3) run the live detector
python live/detector.py
# 4) (optional) benchmark the method on CMU / test against a recorded session
python live/eval_cmu.py
python live/eval_intruder.py collect intruder # record a test session
python live/eval_intruder.py eval data/test_intruder.csv --label intruder| Metric | Meaning |
|---|---|
| Binary Cross-Entropy / MSE | Training loss (classifier / autoencoder) |
| Accuracy | Overall classification accuracy |
| FAR (False Acceptance Rate) | Fraction of impostors wrongly accepted |
| FRR (False Rejection Rate) | Fraction of owners wrongly rejected |
| EER (Equal Error Rate) | Operating point where FAR = FRR |
| ROC / AUC | Trade-off curve and area under it |
Averaged over 5 random seeds (results/comparison.csv):
| Config | Hidden layers | LR | Accuracy | FAR | FRR | EER |
|---|---|---|---|---|---|---|
| C1_base | [16] | 0.01 | 0.956 | 0.040 | 0.067 | 0.044 |
| C2_deep | [32, 16] | 0.01 | 0.969 | 0.024 | 0.067 | 0.066 |
| C3_slowLR | [16] | 0.001 | 0.793 | 0.224 | 0.120 | 0.097 |
The comparison highlights how a too-small learning rate (C3) fails to converge within the training budget, while a deeper network (C2) trades a little EER stability for higher accuracy.
The free-text tools are built to be safe to run during normal computer use:
- Only timestamps (key-down / key-up) and a category (
char/space/backspace) are recorded. - The actual characters, words, and passwords are never captured or stored.
- Live detection processes keystrokes in memory only — nothing is written to disk.
CMU Keystroke Dynamics Benchmark — https://www.cs.cmu.edu/~keystroke/
K. S. Killourhy and R. A. Maxion, "Comparing Anomaly-Detection Algorithms for Keystroke Dynamics," IEEE/IFIP International Conference on Dependable Systems and Networks (DSN), 2009.
Released under the MIT License.
Luiza Łukasik — MSc studies, semester 1.