Sei pronto a implementare il tuo algoritmo concepito in modo intelligente, messo a punto da esperti e addestrato con precisione in quell’ultima frontiera chiamata “produzione”. Hai raccolto un set di test di qualità e ti senti soddisfatto delle prestazioni del tuo algoritmo. È ora di spedirlo e di chiamarla una bella giornata di lavoro! Non così in fretta.
Nessuno vuole essere chiamato a riparare un’applicazione ML imbarazzantemente danneggiata. Se i tuoi clienti ti hanno segnalato che qualcosa non va, hai perso la fiducia. Ora è il momento di tentare freneticamente di eseguire il debug e di correggere un sistema il cui funzionamento interno può coinvolgere miliardi di parametri appresi automaticamente.
Se tutto ciò sembra astratto o improbabile, ecco alcuni esempi tratti dalla mia carriera di risultati nel mondo reale ottenuti da modelli che hanno funzionato bene sul set del “test”:
- Un modello per prevedere il risparmio energetico derivante da un audit energetico dell’edificio si è rivelato accurato per la maggior parte degli edifici testati. Tuttavia, sulla base dei dati in tempo reale, si prevedeva che un singolo locale avrebbe risparmiato più energia di quella consumata dall’intero stato. Gli utenti hanno comprensibilmente notato le previsioni anomale più delle buone previsioni.
- Un modello per capire quali apparecchiature determinano il consumo di energia negli edifici ha improvvisamente dato risultati sorprendenti quando un sistema a monte ha riempito i dati mancanti dell’area domestica con zero invece del valore nullo previsto. Ciò ha portato a un lavoro multi-team durato settimane per risolvere il problema e rigenerare i risultati.
Naturalmente, sai che anche se il vero valore è il ML, hai creato un software e si applicano tutte le normali regole. Sono necessari test unitari, controllo sui punti di integrazione e monitoraggio per individuare i numerosi problemi che si presentano nei sistemi reali. Ma come farlo in modo efficace? Ci si aspetta che i risultati cambino man mano che si migliora il modello e le ipotesi addestrate sono alla mercé di un mondo che cambia.
# Not a great use of test code
def test_predict(model_instance, features):
prediction = model_instance.predict(features)
assert prediction == 0.133713371337
Dovrebbe essere ovvio che quanto sopra è un test davvero fragile che non rileva molti potenziali problemi. Verifica solo che il nostro modello produca i risultati che ci aspettavamo quando è stato addestrato per la prima volta. Stack software e hardware diversi tra ambienti locali e di produzione rendono probabile che si rompa man mano che si avanza verso la distribuzione. Man mano che il tuo modello si evolve, ciò creerà più manutenzione di quanto valga. La maggior parte della complessità della pipeline di previsione consiste nella raccolta di dati, nella preelaborazione, nella pulizia, nell’ingegnerizzazione delle funzionalità e nel confezionamento della previsione in un formato di output utile. È qui che test migliori possono rendere il compito molto più semplice.
Ecco cosa dovresti fare invece.
- Testa l’unità in modo approfondito sulla generazione delle funzionalità e sulla post-elaborazione. La progettazione delle funzionalità dovrebbe essere deterministica e probabilmente comporterà la rimozione di più origini dati e alcune trasformazioni non banali. Questa è una grande opportunità per testare l’unità.
- Testa l’unità su tutta la pulizia e sul controllo dei limiti. Hai del codice dedicato alla pulizia dei dati di input e alla garanzia che tutto assomigli ai dati su cui ti sei allenato, giusto? In caso contrario, continua a leggere. Una volta fatto, prova questi controlli. Assicurati che tutte le asserzioni, i ritagli e le sostituzioni mantengano la tua previsione al sicuro dallo scoraggiante mondo dei dati reali. Affermare che le eccezioni accadono quando dovrebbero.
- Credito extra: utilizzare affermazioni approssimative. Nel caso in cui non lo sapessi già, ci sono modi semplici per evitare gli elusivi fallimenti che derivano dall’asserzione su precisi punti mobili. Numpy fornisce una suite di affermazioni approssimative quel test al livello di precisione che conta per la tua applicazione.
Hai mai giocato al gioco del telefono? Ad ogni passaggio la comprensione diminuisce. I sistemi complessi hanno molti passaggi. Quanta fiducia hai nella documentazione approfondita e nella comunicazione della semantica dei dati da parte di ogni membro di un team che cerca di fornire risultati rapidamente? In alternativa, quanto ti fidi di te stesso nel ricordare tutte quelle cose esattamente quando apporti modifiche mesi o anni dopo?
L’impianto idraulico di un software complesso è il luogo in cui sorgono innumerevoli problemi. La soluzione è creare una serie di casi di test black box che testino gli output dell’intera pipeline. Sebbene ciò richieda aggiornamenti regolari se il modello o il codice cambiano frequentemente, copre un’ampia porzione di codice ed è in grado di rilevare rapidamente impatti imprevisti. Il tempo speso ne vale la pena.
def test_pipeline(pipeline_instance):
# Execute the entire pipeline over a set of test configurations that
# exemplify the important cases# complex inputs, file paths, and whatever your pipeline needs
test_configuration = 'some config here'
# Run the entire flow. Data munging, feature engineering, prediction,
# post processing
result = pipline_instance.run(test_configuration)
assert np.testing.assert_almost_equal(result, 0.1337)
Il test di intere pipeline mantiene integre le applicazioni ML.
La fiducia ha un costo
La paranoia è una virtù quando si sviluppano pipeline ML. Più la pipeline e le dipendenze diventano complesse, più è probabile che qualcosa vada storto da cui dipende in modo vitale il tuo algoritmo. Anche se le tue dipendenze a monte sono gestite da team competenti, puoi davvero aspettarti che non commettano mai errori? Non c’è alcuna possibilità che i tuoi input non vengano mai danneggiati? Probabilmente no. Ma la formula per prepararsi affinché gli esseri umani siano esseri umani è semplice.
- Attenersi agli intervalli di input noti.
- Fallisci velocemente.
- Fallisci forte.
Il modo più semplice per farlo è verificare la presenza di intervalli di input noti il prima possibile nella pipeline. Puoi impostarli manualmente o apprenderli insieme all’addestramento del modello.
def check_inputs(frame):
""" In this scenario we're checking areas
for a wide but plausible range. The goal is really just to make sure
nothing has gone completely wrong in the inputs."""conforms = frame('square_footage').apply(lambda x: 1 < x < 1000000)
if not conforms.all():
# Fail loud. We're no longer in the state the pipeline was designed for.
raise ValueError("Some square_footage values are not in plausible range")
L’esempio sopra mostra la formula. Ripeti semplicemente per ogni input. Mettilo al primo posto nella tua pipeline. Le funzioni di convalida rumorose sono veloci da implementare e salvano il tuo team da conseguenze sfortunate. Questo semplice tipo di controllo ci avrebbe salvato da quello sfortunato scambio null-to-zero. Tuttavia, questi test non rilevano tutti gli scenari che coinvolgono interazioni multivariate. È qui che entrano in gioco le tecniche MLOps menzionate in seguito per aumentare significativamente il livello di robustezza.
I test unitari sono un bisturi con controllo a grana fine che esercita percorsi esatti attraverso il codice. I test di integrazione sono ottimi per verificare che i dati scorrano attraverso l’intero sistema come previsto. Tuttavia, ci sono sempre “incognite sconosciute” nei dati reali.
Il controllo pre-distribuzione ideale consiste nell’eseguire la pipeline di machine learning confrontando tutti i dati reali consentiti dai costi e dal tempo. Seguilo con l’analisi dei risultati per individuare valori anomali, errori e casi limite. Come vantaggio collaterale, puoi utilizzare questa esecuzione su larga scala per testare le prestazioni e stimare i costi dell’infrastruttura.
Un’altra ottima strategia è il “lancio graduale” del tuo modello. Distribuiscilo a una piccola parte di utenti prima del lancio generale. Ciò ti consente di individuare eventuali feedback negativi degli utenti e di individuare i guasti reali su piccola scala anziché su larga scala. Questo è un ottimo momento anche per eseguire test A/B rispetto a soluzioni esistenti o alternative.
Creare e mantenere diligentemente gli unit test è solo l’inizio. Non è un segreto che il software live richieda una strategia di gestione delle eccezioni, monitoraggio e avvisi. Ciò è doppiamente vero quando il software si basa su un modello appreso che potrebbe diventare obsoleto rapidamente.
Il campo di MLOps si è evoluto per risolvere esattamente queste sfide. Non fornirò una panoramica approfondita sullo stato di MLOps in questo articolo. Tuttavia, ecco alcune idee rapide sulle cose da monitorare oltre “segnali d’oro” per le applicazioni ML.
- Cerca la deriva del target: la deviazione della distribuzione prevista rispetto a una media a lungo termine o di test. Ad esempio, su un campione sufficientemente ampio le categorie previste dovrebbero essere distribuite in modo simile al tasso di base. Puoi monitorare la divergenza delle tue previsioni più recenti dalla distribuzione prevista per individuare un segnale che qualcosa sta cambiando.
- La deriva delle caratteristiche è altrettanto, se non più importante, da monitorare rispetto alla deriva della previsione. Le funzionalità sono la tua istantanea del mondo. Se le loro relazioni smettono di corrispondere a quelle apprese dal modello, la validità della previsione crolla. Analogamente al monitoraggio delle previsioni, la chiave è monitorare la divergenza delle caratteristiche dalla distribuzione iniziale. Il monitoraggio delle modifiche alle relazioni tra le funzionalità è ancora più potente. Il monitoraggio delle funzionalità avrebbe individuato quel modello di risparmio che prevedeva valori impossibili prima che lo facessero gli utenti.
I grandi strumenti cloud come Azure AI, Vertex AI e SageMaker forniscono tutti funzionalità di rilevamento della deriva integrate. Altre opzioni includono IA del violinista E EvidentementeAI. Per ulteriori riflessioni su come scegliere uno stack ML, vedere Opzioni di scalabilità del machine learning per ogni team.
Mantenere le pipeline ML in ottime condizioni, dalla formazione alla distribuzione e oltre, è una sfida. Fortunatamente, è completamente gestibile con una strategia di test e monitoraggio esperta. Tieni d’occhio alcuni segnali chiave per evitare una catastrofe imminente! Pipeline di test unitari per rilevare rotture su basi di codice di grandi dimensioni. Sfrutta il più possibile i dati di produzione nel processo. Monitora previsioni e funzionalità per assicurarti che i tuoi modelli rimangano pertinenti.
Fonte: towardsdatascience.com