Skip to main content

canary-ml

Drop-in drift and anomaly monitoring for production ML models.

PyPI Python License: MIT Tests

One line wraps your model. Every .predict() call logs drift metrics, detects anomalies, and fires an alert when something shifts. Monitoring runs in a background thread — your inference latency is unaffected. No infrastructure required.

Project page · Guide & manual · Live demo

canary-ml dashboard preview


Install

pip install canary-ml

Requires Python 3.9–3.12. Dependencies: numpy, scipy, scikit-learn, rich.

Keras/TensorFlow model monitoring also requires TensorFlow (Python 3.9–3.12 only):

pip install canary-ml[keras]

Quickstart

from canary_ml import ModelMonitor

monitor = ModelMonitor(
    model=your_model,           # any sklearn-compatible model
    reference_data=X_train,     # baseline distribution
    alert_threshold=0.2,        # PSI threshold for alerts
    log_path="./canary_logs",
    verbose=True,
)

# Drop-in replacement — monitoring runs in the background
predictions = monitor.predict(X_new)
monitor.wait()  # block until background thread finishes

# Inspect the latest report
report = monitor.get_report()
print(report.summary())
# DriftReport | psi=0.41 | features_drifted=3/8 | anomaly_rate=3.2% | ALERT

# Launch the live dashboard
monitor.serve_dashboard(port=8501)
# → http://localhost:8501

What it monitors

  • PSI — global distribution shift. < 0.1 stable · 0.1–0.2 moderate · > 0.2 alert. Requires ≥ 200 samples per batch; use drift_detected (KS-based) for smaller batches.
  • KS test — per-feature Kolmogorov-Smirnov (continuous features). Drift flags are Benjamini-Hochberg corrected across all features in the batch, so the false-positive rate stays controlled at scale instead of compounding per feature.
  • Chi² test — per-feature chi-squared (categorical features, ≤ 20 unique values).
  • Anomaly detection — ensemble of Isolation Forest + z-score (|z| > 3).
  • Confidence estimate — label-free accuracy proxy from predicted probabilities. Accurate when probabilities are well-calibrated; overestimates if the model is overconfident.

Alert callback

def my_alert(report):
    send_slack(f"Drift alert: PSI={report.psi_score:.2f}")

monitor = ModelMonitor(..., on_alert=my_alert)

Dashboard

monitor.serve_dashboard(port=8501)

Stdlib HTTP server, no extra dependencies. Auto-refreshes every 5 seconds. Can also run standalone:

python -m canary_ml.server ./canary_logs 8501

API reference

ModelMonitor

ModelMonitor(
    model,                      # sklearn-compatible model with .predict()
    reference_data,             # np.ndarray or pd.DataFrame, shape (n, features)
    alert_threshold=0.2,        # PSI threshold for drift alert
    performance_threshold=0.05, # accuracy drop (pp) below reference that fires a perf alert
    anomaly_contamination=0.05, # expected fraction of anomalies; alert fires at 4×
    categorical_threshold=20,   # max unique values for a feature to be treated as categorical
    store_samples=True,         # set False to skip storing raw feature rows (recommended in PII-sensitive envs)
    log_path="./canary_logs",
    verbose=True,               # default True — set False to suppress console output
    on_alert=None,              # callable(DriftReport) fired on alert
)
Method Returns Description
.predict(X) same as model Runs model; monitoring queued in background thread
.predict_proba(X) same as model Passthrough to model.predict_proba(); also feeds the confidence estimate
.wait() — Block until background monitoring tasks complete
.get_report() DriftReport | None Latest monitoring report
.get_history(n=50) list[dict] Last n raw log entries
.reset_baseline(new_data) — Replace the reference distribution and refit the anomaly detector
.serve_dashboard(port=8501, host="127.0.0.1") — Starts dashboard server in background thread. Use host="0.0.0.0" to expose beyond localhost

DriftReport

Attribute Type Description
psi_score float Global PSI vs reference
drift_detected bool True if any feature's KS/chi² p < 0.05 (soft warning)
ks_results dict Per-feature {statistic, p_value, drifted}
features_drifted int Count of features with p < 0.05 (computed property)
anomaly_rate float Fraction of samples flagged as anomalies
alert_triggered bool True if PSI > threshold, anomaly rate is high, or performance drops
alert_reasons list[str] Which conditions fired: "drift", "anomaly", "performance"
estimated_accuracy float | None Confidence estimate; None if no predict_proba
reference_accuracy float | None Confidence estimate on reference data
performance_delta float | None estimated_accuracy − reference_accuracy
output_ks dict|None KS test on prediction distribution vs. reference; None if unavailable
performance_alert bool True if delta < −performance_threshold
timestamp str ISO 8601

DriftReport is not directly JSON-serialisable. Use report.to_dict() for logging or json.dumps(report.to_dict()). Dict-style access (report["psi_score"]) is also supported.


License

MIT © Aitor Bazo

Metadata

Release files for canary-ml 1.2.6

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for canary-ml 1.2.6
File Size Uploaded Provenance
canary_ml-1.2.6.tar.gz 33.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for canary-ml 1.2.6
File Interpreter ABI Platform
canary_ml-1.2.6-py3-none-any.whl Python 3 none any Details

Total release size: 62.9 kB

Release files / canary_ml-1.2.6.tar.gz

Download URL canary_ml-1.2.6.tar.gz
Size 33.9 kB
Tags Source
SHA-256 checksum
How to use checksums
8a78a6bba05bb36324a5717e43c23312ee021488eee66191a820b12ec93e7494
BLAKE2b-256 checksum
How to use checksums
35e482a081c9d7cd23c8aaf0824ec1457ac2f12962c754e830e96a5a2b9c11a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / canary_ml-1.2.6-py3-none-any.whl

Download URL canary_ml-1.2.6-py3-none-any.whl
Size 29.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0d2379c3ffa5d19ab7171fa3526cfe01c5ebac5db99fe1c7bb2a67586cabed57
BLAKE2b-256 checksum
How to use checksums
1b62112c2d8dccd1e99d574f799b9ec741e244ad442452831f6c892f0e8df362
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Security for canary-ml 1.2.6

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page