anomaly-detection / README.md
zeetay's picture
add favicon
1cd4171 verified
|
Raw
History Blame Contribute Delete
4.53 kB
---
title: Real-Time Anomaly Detection
emoji: 📡
colorFrom: blue
colorTo: indigo
sdk: docker
app_port: 7860
pinned: false
---
# Real-Time Anomaly Detection on Time-Series Streams
**Live demo: [anomaly.zeetay.dev](https://anomaly.zeetay.dev)**
Online anomaly detection on a multivariate sensor stream with concept drift handling. Each observation is scored once as it arrives. No batch retraining.
## Problem
Sensor distributions shift over time. A static model will either miss anomalies in the new regime or start flagging normal post-drift readings as anomalous. This project fits a baseline during a stable warmup window, then scores every subsequent observation against it while monitoring for distribution shifts.
## Approach
- **Synthetic stream**: Three-phase generator (normal baseline, gradual drift, injected anomalies) with configurable rates and ground truth labels.
- **Online scorer**: Mahalanobis distance from a frozen Phase A baseline. Uses the full sensor covariance matrix, so it catches contextual anomalies (anti-correlated sensor readings) that per-feature z-score methods miss entirely.
- **Drift detection**: ADWIN watches a normalized composite sensor signal. When the distribution shifts (Phase B), ADWIN fires. The anomaly baseline is kept since it was calibrated before drift started.
- **Running metrics**: Precision, recall, and F1 are updated after every observation against ground truth labels.
- **Real-time UI**: FastAPI + WebSocket streams each scored observation to a dashboard with rolling charts, anomaly/drift markers, and live counters. New visitors get a replay of the last 200 points.
## Results (offline benchmark)
Evaluated on Phase C (300 obs, 10% anomaly rate, seed=42):
| Method | Precision | Recall | F1 | Mode |
|--------|-----------|--------|-----|------|
| Mahalanobis + ADWIN | 0.833 | 1.000 | **0.909** | online |
| Isolation Forest | 0.476 | 1.000 | 0.645 | batch |
| Z-Score (max \|z\|>2.5) | 0.450 | 0.600 | 0.514 | batch |
Z-Score's recall is limited by contextual anomalies where no single sensor exceeds the 2.5σ threshold. Mahalanobis catches these via the covariance term.
## Tech stack
- **Python 3.10+**
- **River** - online drift detection (ADWIN)
- **numpy / scikit-learn** - Mahalanobis scoring, Isolation Forest baseline
- **FastAPI** - REST + WebSocket, static dashboard
- **asyncio** - async stream and pipeline
- **pytest** - tests for stream, detector, pipeline, and server
## Setup and run
```bash
python -m venv .venv
.venv\Scripts\activate # Windows
# source .venv/bin/activate # Linux/macOS
pip install -r requirements.txt
python run.py
```
Open **http://localhost:8000/**. The pipeline starts on first connection and loops automatically.
## Deploy
- **Frontend**: [anomaly.zeetay.dev](https://anomaly.zeetay.dev) — Netlify, auto-deploys from `main`
- **Backend**: [huggingface.co/spaces/zeetay/anomaly-detection](https://huggingface.co/spaces/zeetay/anomaly-detection) — HF Spaces (Docker)
The frontend is static files served by Netlify. The backend is a FastAPI + WebSocket server running in a Docker container on HF Spaces. `dashboard.js` connects directly to the HF Space WebSocket from any non-HF host.
**Docker locally:** `docker build -t anomaly . && docker run -p 7860:7860 anomaly`
## Tests
```bash
pytest
```
All tests use the synthetic stream and need no external services.
## Project layout
| Path | Role |
|------|------|
| `src/stream/` | Observation model, async synthetic generator (phases A/B/C) |
| `src/detector/` | Anomaly scorer (Mahalanobis), drift detector (ADWIN), running metrics |
| `src/pipeline/` | Async pipeline: stream, score, broadcast, replay buffer |
| `src/server/` | FastAPI app, WebSocket, `/stats`, `/metrics` (Prometheus), static dashboard |
| `tests/` | Pytest for stream, detector, pipeline, dashboard |
## Design notes
- **Mahalanobis over Z-Score**: Z-Score tests each sensor independently. Mahalanobis uses the covariance matrix, so readings that look moderate in isolation but are unusual as a combination (e.g., temp up + pressure down when they normally move together) score high.
- **ADWIN on sensor signal, not anomaly scores**: Watching the normalized sensor deviation catches sustained distribution shifts without false-firing on isolated anomaly spikes.
- **Replay on connect**: New clients get the last 200 messages immediately, then live updates.
- **Start on first connect**: The pipeline only runs while at least one client is connected. Counters reset each cycle.