XGBoost multi-class classifier Β· MLflow experiment tracking Β· DVC data versioning Β· FastAPI serving Β· Evidently AI monitoring Β· Docker orchestration
Data β Train β Serve β Monitor β Retrain End-to-end MLOps pipeline with environment parity, type-safe APIs, and automated drift detection.
- Overview
- Features
- System Architecture
- Tech Stack
- Project Structure
- Quick Start
- Dataset
- API Reference
- Troubleshooting
- Contributing
- License
NetSentinel is a production-grade MLOps pipeline for network intrusion detection. It trains an XGBoost multi-class classifier on the NSL-KDD dataset, tracks experiments via MLflow, versions data with DVC, serves predictions through a FastAPI REST API, and visualizes data drift using Evidently AI β all orchestrated in Docker Compose.
The project is intentionally designed to reflect real SDE and MLOps practices: reproducible pipelines, type-safe APIs, containerized environments, and monitoring-driven retraining decisions.
Classification targets:
| Label | Description |
|---|---|
Normal |
Legitimate network traffic |
DoS |
Denial of Service attacks |
Probe |
Surveillance and port scanning |
R2L |
Remote-to-Local unauthorized access |
U2R |
User-to-Root privilege escalation |
NSL-KDD's test set contains novel attack subtypes not present in training β so the model is evaluated on Macro F1-Score and Recall for minority classes (U2R, R2L), not just accuracy.
[ KDDTrain+.txt / KDDTest+.txt ]
β
βΌ (DVC versioned)
[ Preprocessing Layer ]
Feature engineering
β
βΌ (MLflow tracked)
[ Training Layer ]
XGBoost classifier
Params + Metrics + Artifacts logged
β
βΌ (Dynamic model load via glob)
[ FastAPI Serving Layer ]
POST /predict Β· Pydantic validated
β
βΌ (Docker internal network)
[ Streamlit Dashboard ]
Predictions + Evidently AI drift report
| Feature | Description |
|---|---|
| π§ XGBoost Multi-Class Classifier | Trained on NSL-KDD with Macro F1 optimization; handles class imbalance across Normal, DoS, Probe, R2L, U2R |
| π¦ DVC Data Versioning | Dataset and artifacts tracked with DVC β full reproducibility across environments |
| π MLflow Experiment Tracking | Every run logs hyperparameters, metrics, and model artifacts to the MLflow registry |
| β‘ FastAPI REST API | Type-safe prediction endpoint with Pydantic schema validation and NumPy-safe JSON serialization |
| π Evidently AI Drift Monitoring | Detects data drift between train and test distributions; triggers retraining decisions automatically |
| π₯οΈ Streamlit Dashboard | Renders live predictions and Evidently HTML drift reports via st.components.html |
| π³ Docker Compose Orchestration | Single command spins up API + Dashboard with full environment parity across Mac, Linux, and Cloud |
| π Type Safety Throughout | Pydantic validates every incoming network feature payload before it reaches the model |
NetSentinel is organized into five clearly separated layers:
ββββββββββββββββββββ
β DATA LAYER β KDDTrain+.txt Β· KDDTest+.txt
β (DVC) β Versioned, reproducible, shareable
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β TRAINING LAYER β src/models/train.py
β (MLflow) β XGBoost Β· Params Β· Metrics Β· Artifacts
ββββββββββ¬ββββββββββ
β model.pkl (loaded dynamically via glob)
βΌ
ββββββββββββββββββββ
β SERVING LAYER β api/main.py
β (FastAPI) β POST /predict Β· Pydantic Β· NumPy-safe JSON
ββββββββββ¬ββββββββββ
β Docker internal network
βΌ
ββββββββββββββββββββ ββββββββββββββββββββββββββββ
β MONITORING ββββββΆβ UI LAYER β
β (Evidently AI) β β (Streamlit) β
β Drift reports β β Dashboard + drift reportβ
ββββββββββββββββββββ ββββββββββββββββββββββββββββ
Example prediction request / response:
// POST /predict
{
"duration": 0,
"protocol_type": "tcp",
"service": "http",
"flag": "SF",
"src_bytes": 215,
"dst_bytes": 45076
}
// Response
{
"prediction": "Normal",
"confidence": 0.97
}| Layer | Technology |
|---|---|
| ML / Training | XGBoost, LightGBM, Scikit-Learn, Pandas, NumPy < 2.0 |
| MLOps | MLflow (experiment tracking + model registry), DVC (data versioning) |
| API | FastAPI, Uvicorn, Pydantic |
| Monitoring | Evidently AI β₯ 0.7.0 (data drift + model monitoring) |
| Frontend | Streamlit (st.components.html for Evidently reports) |
| DevOps | Docker, Docker Compose |
| Utilities | Loguru, Pytest, HTTPx, Joblib |
| Dataset | NSL-KDD (KDDTrain+.txt Β· KDDTest+.txt) |
NetSentinel/
β
βββ api/
β βββ main.py # FastAPI app + dynamic model loader (glob)
β βββ schemas.py # Pydantic request/response models
β
βββ dashboard/
β βββ app.py # Streamlit dashboard
β βββ Dockerfile # UI container
β
βββ src/
β βββ data/
β β βββ preprocessing.py # Feature engineering for NSL-KDD
β βββ models/
β β βββ train.py # XGBoost training + MLflow logging
β βββ monitoring/
β βββ drift.py # Evidently AI drift report generation
β
βββ data/ # DVC-tracked (KDDTrain+.txt, KDDTest+.txt)
βββ mlruns/ # MLflow experiment store
βββ docker-compose.yml # Service orchestrator (API + Dashboard)
βββ Dockerfile # API container
βββ requirements.txt
βββ README.md
This is a 3-command setup. Docker handles all dependencies β no virtual environments, no manual installs.
git clone https://github.com/sosush/NetSentinel.git
cd NetSentineldvc pullOr manually place
KDDTrain+.txtandKDDTest+.txtin thedata/directory.
docker-compose up --build| Service | URL |
|---|---|
| Streamlit Dashboard | http://localhost:8501 |
| FastAPI Swagger Docs | http://localhost:8000/docs |
| MLflow UI | http://localhost:5000 |
That's it. The API, dashboard, and monitoring stack all come up together.
If you want to retrain the model manually:
# Inside the container or local venv
python src/models/train.pyMLflow logs the run automatically. The API reloads the latest model artifact on the next request via glob.
NSL-KDD is the standard benchmark for network intrusion detection research, addressing key shortcomings of the original KDD Cup 1999 dataset.
Files:
| File | Purpose |
|---|---|
KDDTrain+.txt |
Training set β 41 features + attack label |
KDDTest+.txt |
Test set β contains novel attack subtypes not in training |
Why Macro F1 over Accuracy? The test set is intentionally skewed toward rare attack classes (U2R, R2L). A model that predicts "Normal" for everything achieves high accuracy but fails in practice. NetSentinel optimizes for Macro F1-Score and per-class Recall to ensure minority attack types are actually detected.
Download the dataset from the GitHub Releases page and place files under data/.
Accepts a JSON payload of network flow features, returns a predicted class and confidence score.
curl -X POST http://localhost:8000/predict \
-H "Content-Type: application/json" \
-d '{
"duration": 0,
"protocol_type": "tcp",
"service": "http",
"flag": "SF",
"src_bytes": 215,
"dst_bytes": 45076
}'All fields are validated by Pydantic before reaching the model. NumPy types (int64, float32) are cast to standard Python types before serialization β avoiding the TypeError: Object of type int64 is not JSON serializable error that plagues most ML APIs.
curl http://localhost:8000/health
# {"status": "ok", "model_loaded": true}These are real issues encountered during development, not hypotheticals.
| Issue | Root Cause | Fix |
|---|---|---|
TypeError: Object of type int64 is not JSON serializable |
NumPy types don't serialize to JSON natively | Cast outputs to int(x) or str(x) in api/main.py before returning the response |
ValueError: numpy.dtype size changed |
NumPy 2.0 broke binary compatibility with compiled extensions (XGBoost, Evidently) | Pin numpy<2.0.0 in requirements.txt or upgrade to evidently>=0.7.0 |
| MLflow loads wrong model / path not found | Hardcoded absolute host paths baked into MLflow artifact URIs don't resolve inside Docker containers | Use glob("mlruns/**/model.pkl", recursive=True) to dynamically resolve the latest artifact at runtime |
| Streamlit can't reach API | Services on different Docker networks | Ensure both services are under the same network in docker-compose.yml; use the service name (e.g. http://api:8000) not localhost |
| Drift report not rendering | Evidently HTML uses inline JS that Streamlit sandboxes | Use st.components.v1.html(report_html, height=800) instead of st.markdown |
Pull requests are welcome.
# 1. Fork the repository
# 2. Create a feature branch
git checkout -b feature/my-feature
# 3. Commit your changes
git commit -m "feat: describe your change"
# 4. Push and open a Pull Request
git push origin feature/my-featureThis project is released under the MIT License β free to modify and distribute with attribution.
See LICENSE for full details.
Made by sosush