المراقبة بعد النشر
النشر مش النهاية. ده بداية حياة الموديل.
ليه الموديل «بيبوظ»؟
الكود مابيتغيرش، بس الدنيا بتتغير. الموديل اتدرب على أسعار السنة اللي فاتت، والأسعار زادت. أو شركة فتحت كمبوند جديد والشقق كلها بقت أكبر. الموديل هيفضل يرد بثقة، بس ردوده هتبقى أغلط وأغلط. ده اسمه Data Drift، ومش هيطلع error ولا حاجة، فلازم انت تدور عليه.
سجّل كل توقع
import json import logging import time pred_log = logging.getLogger("predictions") pred_log.addHandler(logging.FileHandler("predictions.jsonl")) pred_log.setLevel(logging.INFO) def log_prediction(features: dict, price_k: float, started: float, version: str): pred_log.info(json.dumps({ "time": time.time(), "latency_ms": round((time.time() - started) * 1000, 1), "model_version": version, "input": features, "output": price_k, })) # inside your /predict endpoint: # started = time.time() # ... predict ... # log_prediction(apt.model_dump(), price, started, MODEL_VERSION)
كل سطر في الملف ده توقع كامل: إمتى، وخد قد إيه، وأنهي نسخة موديل، وإيه المدخلات والمخرجات. من غيره، لما حد يشتكي إن الأسعار غلط، مش هتعرف تبدأ تدور منين.
اكتشف الـ Drift
هنقارن توزيع المساحات في داتا التدريب بتوزيعها في الطلبات اللي جت الشهر ده. واختبار إحصائي اسمه Kolmogorov–Smirnov بيقولك هل التوزيعين مختلفين فعلاً ولا الفرق صدفة:
import numpy as np import pandas as pd import matplotlib.pyplot as plt from scipy.stats import ks_2samp train_area = pd.read_csv("apartments.csv")["area"] rng = np.random.default_rng(3) # Simulated production requests: a new compound with bigger flats opened live_area = np.concatenate([rng.integers(60, 221, 300), rng.integers(200, 320, 150)]) stat, p_value = ks_2samp(train_area, live_area) print(f"train mean area: {train_area.mean():.0f} m2") print(f"live mean area: {live_area.mean():.0f} m2") print(f"KS p-value: {p_value:.2e}") print("DRIFT DETECTED" if p_value < 0.01 else "no significant drift") print(f"requests outside training range: {(live_area > train_area.max()).mean():.0%}") plt.figure(figsize=(7, 3.4)) plt.hist(train_area, bins=30, alpha=0.6, density=True, label="training data", color="#3776AB") plt.hist(live_area, bins=30, alpha=0.6, density=True, label="this month", color="#E0A800") plt.xlabel("area (m²)"); plt.title("Input drift: area") plt.legend() plt.show()
الاختبار أكد إن فيه drift، والأخطر إن جزء كبير من الطلبات فيه مساحات أكبر من أي شقة الموديل شافها. الموديل هنا بيخمّن برا المنطقة اللي اتعلمها، زي الـ LSTM في المرحلة ٦ بالظبط. ده وقت إنك تجمع داتا جديدة وتدرّب نسخة جديدة.
تراقب إيه؟
| المؤشر | بيقولك إيه |
|---|---|
| latency وعدد الطلبات والـ errors | الـ API نفسه صحته كويسة؟ |
| توزيع المدخلات | الداتا الجديدة شبه داتا التدريب؟ |
| توزيع التوقعات | الموديل فجأة بقى يطلع أرقام غريبة؟ |
| الأداء الحقيقي | لما السعر الحقيقي يبان بعدين، التوقع كان قريب؟ |