Machine Learning Academy · Lezione

Monitorare le previsioni: registrare input e output

Imparerete ad aggiungere la registrazione delle previsioni all’API, discutere di data drift e obsolescenza del modello e delineare il trigger di riaddestramento e la pipeline di deployment.

Lezione 4 di 413 passaggi

Monitorare le previsioni: registrare input e output è una lezione Machine Learning Academy gratuita su CoddyKit. Questa è la lezione 4 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Machine Learning Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Machine Learning Academy include 4 lezioni in totale.

Perché monitorare un modello distribuito

Un modello che ha fornito prestazioni eccellenti al momento della distribuzione può degradarsi silenziosamente quando il mondo reale cambia. Il comportamento dei clienti si modifica, compaiono nuove categorie di prodotti, i sensori subiscono variazioni, cambiano le condizioni economiche: tutti questi fattori fanno divergere la distribuzione degli input dai dati di addestramento. Senza monitoraggio, ci si accorge del malfunzionamento del modello solo quando gli utenti si lamentano o gli indicatori aziendali peggiorano. Il monitoraggio delle predizioni rileva per tempo il degrado, prima che abbia conseguenze sugli utenti.

Cosa registrare: le tre W

Ogni evento di predizione dovrebbe registrare: When (il timestamp), What (le feature di input e l’output/la predizione/la probabilità del modello) e, idealmente, Whether (l’etichetta reale finale, quando sarà disponibile). Le feature di input servono a rilevare il data drift; gli output consentono di monitorare la confidenza; i valori reali permettono di monitorare l’accuratezza nel tempo.

Aggiungere la registrazione all’endpoint FastAPI

Estenda la route di predizione FastAPI per registrare ogni richiesta in un file JSONL strutturato (JSON Lines: un oggetto JSON per riga). JSONL è facile da aggiornare in modalità append, da analizzare e si integra bene con strumenti come pandas, Spark e gli aggregatori di log cloud. Ogni riga del log rappresenta un evento di predizione.

import json
from datetime import datetime
from fastapi import FastAPI
from pydantic import BaseModel
import numpy as np

app = FastAPI()
LOG_FILE = '/tmp/prediction_log.jsonl'

def log_prediction(features: dict, prediction: int, confidence: float):
    entry = {
        'timestamp': datetime.utcnow().isoformat(),
        'features': features,
        'predicted_class': prediction,
        'confidence': confidence
    }
    with open(LOG_FILE, 'a') as f:
        f.write(json.dumps(entry) + '\n')

# Call inside the predict route:
# log_prediction(features.dict(), pred, confidence)
print('Logging enabled — entries written to', LOG_FILE)

Simulare e leggere il log

Dopo aver accumulato le predizioni, legga il file JSONL in un DataFrame di pandas per analizzarlo. Ogni riga rappresenta un evento di predizione. Può calcolare statistiche per qualsiasi intervallo temporale: la confidenza media mobile, le variazioni nella distribuzione delle feature e la frequenza delle classi predette.

import json
import pandas as pd
from datetime import datetime
import random

# Simulate log entries
LOG_FILE = '/tmp/prediction_log.jsonl'
with open(LOG_FILE, 'w') as f:
    for i in range(100):
        entry = {
            'timestamp': datetime.utcnow().isoformat(),
            'features': {'sepal_length': round(4.5 + random.gauss(1, 0.5), 2),
                         'sepal_width': round(3.0 + random.gauss(0, 0.3), 2),
                         'petal_length': round(1.0 + random.gauss(2, 1), 2),
                         'petal_width': round(0.2 + random.gauss(0.5, 0.2), 2)},
            'predicted_class': random.choice([0, 1, 2]),
            'confidence': round(random.uniform(0.6, 1.0), 4)
        }
        f.write(json.dumps(entry) + '\n')

# Read back as DataFrame
rows = [json.loads(line) for line in open(LOG_FILE)]
df = pd.json_normalize(rows)
print(df.shape)
print(df[['confidence', 'predicted_class']].describe())

Monitorare la confidenza nel tempo

Tracci la confidenza media mobile nel tempo. Una tendenza al ribasso indica che il modello sta diventando meno sicuro delle proprie predizioni: è un classico segnale precoce di data drift. Imposti una soglia, ad esempio una confidenza mobile inferiore a 0.7, e attivi un avviso. In questo modo riceverà un avvertimento prima che l’accuratezza diminuisca effettivamente.

import pandas as pd
import matplotlib.pyplot as plt
import json

df = pd.json_normalize([json.loads(l) for l in open('/tmp/prediction_log.jsonl')])
df['timestamp'] = pd.to_datetime(df['timestamp'])
df = df.sort_values('timestamp').reset_index(drop=True)

# Rolling window of 20 predictions
df['rolling_confidence'] = df['confidence'].rolling(20).mean()

plt.figure(figsize=(10, 4))
plt.plot(df.index, df['confidence'], alpha=0.3, label='Per-prediction')
plt.plot(df.index, df['rolling_confidence'], linewidth=2, label='Rolling mean (n=20)')
plt.axhline(0.7, color='red', linestyle='--', label='Alert threshold')
plt.xlabel('Prediction number')
plt.ylabel('Confidence')
plt.title('Prediction Confidence Over Time')
plt.legend()
plt.show()

Rilevare le variazioni nella distribuzione delle feature

Confronti la distribuzione di ogni feature di input nelle predizioni recenti con la distribuzione dei dati di addestramento. Il Population Stability Index (PSI) è una metrica comune: PSI < 0.1 indica l’assenza di variazioni significative; 0.1–0.2 indica un drift moderato; >0.2 indica un drift grave che richiede il riaddestramento. In alternativa, il test di Kolmogorov-Smirnov verifica se due campioni provengono dalla stessa distribuzione.

import numpy as np
from scipy import stats
import pandas as pd
import json

df = pd.json_normalize([json.loads(l) for l in open('/tmp/prediction_log.jsonl')])

# Simulated training distribution for sepal_length
train_sepal = np.random.normal(5.8, 0.8, 500)  # reference
recent_sepal = df['features.sepal_length'].values

# KS test: tests if two samples come from same distribution
stat, p_value = stats.ks_2samp(train_sepal, recent_sepal)
print(f'KS statistic: {stat:.4f}  p-value: {p_value:.4f}')
if p_value < 0.05:
    print('WARNING: sepal_length distribution has drifted!')
else:
    print('No significant drift detected in sepal_length')

Monitorare la frequenza delle classi predette

Tracci la frequenza mobile di ogni classe predetta. Se la classe 0 veniva predetta nel 60% dei casi durante la valutazione sul periodo di addestramento, ma ora viene predetta solo nel 10% dei casi, significa che qualcosa nei dati di input è cambiato. Le variazioni nella distribuzione delle classi sono spesso più facili da rilevare rispetto ai cambiamenti più sottili nella distribuzione delle feature e possono fungere da primo avviso rapido.

import pandas as pd
import json

df = pd.json_normalize([json.loads(l) for l in open('/tmp/prediction_log.jsonl')])

# Compute rolling class frequencies in windows of 20
window = 20
rolling_freq = pd.get_dummies(df['predicted_class']).rolling(window).mean()
rolling_freq.columns = [f'class_{c}' for c in rolling_freq.columns]

print('Recent class frequencies (last 20 predictions):')
print(rolling_freq.tail(1).to_string())

print('\nTraining class frequency (expected):')
print('class_0: 0.33  class_1: 0.33  class_2: 0.33')

Registrazione strutturata in produzione

In produzione, scriva i log in un sistema di registrazione strutturato anziché in un file semplice. Le opzioni includono: il modulo Python logging con un formattatore JSON, i servizi di logging cloud (AWS CloudWatch, GCP Cloud Logging, Datadog) oppure un database. I log strutturati possono essere interrogati, sono scalabili e si integrano con dashboard come Grafana per il monitoraggio in tempo reale.

import logging
import json
from datetime import datetime

# Configure structured JSON logging
class JSONFormatter(logging.Formatter):
    def format(self, record):
        log_data = {
            'time': datetime.utcnow().isoformat(),
            'level': record.levelname,
            'message': record.getMessage()
        }
        if hasattr(record, 'prediction_data'):
            log_data.update(record.prediction_data)
        return json.dumps(log_data)

logger = logging.getLogger('ml_predictor')
handler = logging.StreamHandler()
handler.setFormatter(JSONFormatter())
logger.addHandler(handler)
logger.setLevel(logging.INFO)

# Usage in prediction route:
extra = {'prediction_data': {'features': {'x': 1.5}, 'pred': 0, 'conf': 0.95}}
logger.info('prediction', extra=extra)

Data drift e concept drift

Esistono due modalità di malfunzionamento distinte: Data drift: cambia la distribuzione delle feature di input, ad esempio perché un sensore viene ricalibrato o emergono nuovi dati demografici sui clienti. Concept drift: cambia la relazione tra gli input e il target, ad esempio perché ciò che costituisce una «frode» si evolve quando i truffatori si adattano. Il data drift può talvolta essere gestito riaddestrando il modello su dati recenti; il concept drift richiede di ripensare le feature o l’approccio di modellazione.

Criteri per il riaddestramento

Definisca criteri chiari per il riaddestramento prima della distribuzione. Tra i criteri comuni vi sono: programmato (riaddestrare ogni 30 giorni indipendentemente da tutto), basato sulle prestazioni (riaddestrare se l’AUC su un holdout etichettato scende sotto una soglia) oppure basato sul drift (riaddestrare quando il PSI supera 0.2 per una feature importante). Automatizzare il criterio e la pipeline di riaddestramento impedisce al modello di degradarsi silenziosamente.

from datetime import datetime, timedelta

class RetrainingPolicy:
    def __init__(self, last_trained: datetime, max_age_days=30,
                 min_auc=0.85, max_drift_psi=0.2):
        self.last_trained = last_trained
        self.max_age_days = max_age_days
        self.min_auc = min_auc
        self.max_drift_psi = max_drift_psi

    def should_retrain(self, current_auc=None, max_psi=None):
        age = (datetime.utcnow() - self.last_trained).days
        if age >= self.max_age_days:
            return True, f'Model is {age} days old (max {self.max_age_days})'
        if current_auc and current_auc < self.min_auc:
            return True, f'AUC {current_auc:.3f} below threshold {self.min_auc}'
        if max_psi and max_psi > self.max_drift_psi:
            return True, f'PSI {max_psi:.3f} above threshold {self.max_drift_psi}'
        return False, 'No trigger met — model healthy'

policy = RetrainingPolicy(last_trained=datetime.utcnow() - timedelta(days=35))
print(policy.should_retrain(current_auc=0.90))

Schema della dashboard di monitoraggio

Una dashboard di monitoraggio ML in produzione mostra in genere: la confidenza mobile delle predizioni nel tempo, la distribuzione delle classi nel tempo, gli istogrammi della distribuzione delle feature che confrontano i dati di addestramento con le predizioni recenti e, quando le etichette sono disponibili, l’accuratezza mobile o l’AUC. Strumenti come Grafana + Prometheus, Evidently AI o WhyLogs forniscono componenti predefiniti per il monitoraggio ML, senza doverli creare da zero.

# Evidently AI example (pip install evidently)
from evidently.report import Report
from evidently.metric_preset import DataDriftPreset
import pandas as pd
import numpy as np

# Reference: training feature distributions
reference = pd.DataFrame({
    'sepal_length': np.random.normal(5.8, 0.8, 300),
    'petal_length': np.random.normal(3.7, 1.7, 300)
})

# Current: recent predictions features
current = pd.DataFrame({
    'sepal_length': np.random.normal(6.5, 1.2, 100),  # drifted!
    'petal_length': np.random.normal(3.7, 1.7, 100)
})

report = Report(metrics=[DataDriftPreset()])
report.run(reference_data=reference, current_data=current)
report.save_html('/tmp/drift_report.html')
print('Drift report saved to /tmp/drift_report.html')

Verifica rapida

Verifichi la sua comprensione del monitoraggio e della registrazione delle predizioni trattati in questa lezione.

Riepilogo della lezione

In questa lezione ha imparato a: registrare ogni evento di predizione con timestamp, feature di input, classe predetta e confidenza, così da poter rilevare il drift; monitorare la confidenza mobile e le distribuzioni delle feature per individuare il degrado prima che abbia conseguenze sugli utenti; e definire criteri automatici per il riaddestramento (pianificazione, soglia delle prestazioni o soglia di drift) per mantenere il modello efficiente in produzione. Con questa lezione si conclude il corso Nozioni di base sulla persistenza e la distribuzione dei modelli.

Gratis per iniziare

Impara Python con un tutor IA — gratis

Scrivi ed esegui vero codice nel tuo browser, ricevi aiuto istantaneo da un tutor IA disponibile 24/7, e riprendi da dove hai lasciato sul web o nell'app.

Corsi
30
Lezioni
120

Domande Frequenti

La lezione «Monitorare le previsioni: registrare input e output» è gratuita?

Sì — il testo completo di «Monitorare le previsioni: registrare input e output» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Machine Learning Academy, passa a CoddyKit PRO. Il corso Machine Learning Academy include 4 lezioni in totale.

Cosa imparerò in «Monitorare le previsioni: registrare input e output»?

Imparerete ad aggiungere la registrazione delle previsioni all’API, discutere di data drift e obsolescenza del modello e delineare il trigger di riaddestramento e la pipeline di deployment. Eserciti Machine Learning Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Machine Learning Academy?

Non è richiesta alcuna esperienza precedente. Machine Learning Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 4 di 4.

Quanto tempo richiede la lezione «Monitorare le previsioni: registrare input e output»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Machine Learning Academy?

Sì. Ogni lezione Machine Learning Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Salvare i modelli con joblib e pickle
  2. Versionare i modelli: perché nomi dei file e metadati sono importanti
  3. Servire previsioni con un endpoint FastAPI
  4. Monitorare le previsioni: registrare input e output
← Torna a Machine Learning Academy