Schiro commited on
Commit
a97c8f9
·
verified ·
1 Parent(s): 83dcb6d

Upload folder using huggingface_hub

Browse files
Files changed (1) hide show
  1. monitoring.py +88 -19
monitoring.py CHANGED
@@ -1,26 +1,95 @@
1
- import numpy as np
2
- import random
3
  from datasets import load_dataset
4
- from model_setup import predict
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
- dataset = load_dataset("cardiffnlp/tweet_eval", "sentiment")
7
 
8
- # Take a sample of random tweets to monitor
9
- test_dataset = dataset["test"]
10
- sample_size = 100
11
- indices = random.sample(range(len(test_dataset["text"])), sample_size)
12
- texts = [test_dataset["text"][i] for i in indices]
13
 
 
 
14
 
15
- # Predict sentiment for each tweet
16
- print("Predicting sentiment on sample...")
17
- pred_labels = [predict(text) for text in texts]
18
 
19
- # Count sentiment distribution
20
- # 0=Negative, 1=Neutral, 2=Positive
21
- distribution = np.bincount(pred_labels, minlength=3) / sample_size
22
 
23
- print(f"\n--- Sentiment Distribution ---")
24
- print(f"Negative: {distribution[0]:.2%}")
25
- print(f"Neutral: {distribution[1]:.2%}")
26
- print(f"Positive: {distribution[2]:.2%}")
 
 
 
1
  from datasets import load_dataset
2
+ from model_setup import predict_batch
3
+ import numpy as np
4
+ import json
5
+ from pathlib import Path
6
+ import mlflow
7
+ import sys
8
+
9
+ WINDOW_SIZE = 500 # tweets per monitoring window, one "day" of traffic
10
+ DRIFT_THRESHOLD = 0.10 # alert when the negative share grows by more than 10 points
11
+ BASELINE_PATH = Path("baseline.json")
12
+ BASELINE_WINDOWS = 4 # first windows of the stream define normal behaviour
13
+ MLFLOW_URI = "sqlite:///mlflow.db"
14
+
15
+
16
+
17
+ def get_window(index, size=WINDOW_SIZE):
18
+ """Return one window of incoming texts. Swap this to read from a live source."""
19
+ test = load_dataset("cardiffnlp/tweet_eval", "sentiment")["test"]
20
+ start = index * size
21
+ return test["text"][start:start + size]
22
+
23
+
24
+ def sentiment_distribution(texts):
25
+ """Share of negative, neutral and positive predictions over a list of texts."""
26
+ predictions = predict_batch(texts)
27
+ counts = np.bincount(predictions, minlength=3)
28
+ return (counts / len(predictions)).tolist()
29
+
30
+ def build_baseline():
31
+ """Compute the reference distribution on the first windows of the stream and store it."""
32
+ texts = []
33
+ for index in range(BASELINE_WINDOWS):
34
+ texts += get_window(index)
35
+
36
+ distribution = sentiment_distribution(texts)
37
+ BASELINE_PATH.write_text(json.dumps(distribution))
38
+ return distribution
39
+
40
+ def load_baseline():
41
+ """Read the stored baseline, building it the first time."""
42
+ if BASELINE_PATH.exists():
43
+ return json.loads(BASELINE_PATH.read_text())
44
+ return build_baseline()
45
+
46
+
47
+ def check_drift(current, baseline, threshold=DRIFT_THRESHOLD):
48
+ """Compare the negative share against the baseline; return the shift and whether it alerts."""
49
+ shift = current[0] - baseline[0] # index 0 is the negative class
50
+ return shift, shift > threshold
51
+
52
+
53
+ def monitor(n_windows):
54
+ """Run the monitoring loop over consecutive windows; return the alerting ones."""
55
+ baseline = load_baseline()
56
+ print(f"{'baseline negative share:':<26}{baseline[0]:>8.2%}\n")
57
+
58
+ header = f"{'window':<10}{'negative':>10}{'neutral':>10}{'positive':>10}{'shift':>10}"
59
+ print(header)
60
+ print("-" * len(header))
61
+
62
+ alerts = []
63
+ for index in range(BASELINE_WINDOWS, BASELINE_WINDOWS + n_windows):
64
+ distribution = sentiment_distribution(get_window(index))
65
+ shift, alerting = check_drift(distribution, baseline)
66
+
67
+ mlflow.log_metrics({
68
+ "negative": distribution[0],
69
+ "neutral": distribution[1],
70
+ "positive": distribution[2],
71
+ "negative_shift": shift,
72
+ "alert": int(alerting),
73
+ }, step=index)
74
+
75
+ flag = " ALERT" if alerting else ""
76
+ print(f"{index:<10}{distribution[0]:>10.2%}{distribution[1]:>10.2%}"
77
+ f"{distribution[2]:>10.2%}{shift:>+10.2%}{flag}")
78
+ if alerting:
79
+ alerts.append(index)
80
 
81
+ return alerts
82
 
 
 
 
 
 
83
 
84
+ if __name__ == "__main__":
85
+ mlflow.set_tracking_uri(MLFLOW_URI)
86
 
87
+ with mlflow.start_run():
88
+ mlflow.log_params({"window_size": WINDOW_SIZE, "threshold": DRIFT_THRESHOLD})
89
+ alerts = monitor(n_windows=5)
90
 
91
+ if alerts:
92
+ print(f"\nDrift detected on windows: {alerts}")
93
+ sys.exit(1) # non-zero exit fails the job and notifies
94
 
95
+ print("\nNo drift detected.")