facebook

Blog

Resta aggiornato

Vediamo come valutare l'efficienza dei modelli di ML e cercare di migliorarla con la tecnica del feature crossing
Feature crossing per migliorare il nostro modello ML
martedì 14 Gennaio 2020

Continuiamo il viaggio nel mondo del Machine Learning iniziato nei precedenti articoli. Siamo partiti da un dataset relativo a partite di calcio giocate nella Serie A Italiana, ma a differenza di quelli preconfezionati per i corsi di ML, non sappiamo se questi dati consentono di creare un modello predittivo o meno.

Nel primo articolo, abbiamo utilizzato il portale cloud Azure Machine Learning per esplorare i dati cercando di ottimizzare le feature disponibili grazie a un po’ di  tecniche classiche. 

Nel secondo articolo, invece, abbiamo creato in Visual Studio una console application che, grazie alla libreria ML.NET, ha generato un modello basato sui dati disponibili. Cosa possiamo aspettarci da questo modello? Qual è l’accuratezza della previsione secondo la quale il calciatore X giocherà n minuti oppure segnerà n goals oppure raccoglierà n cartellini gialli?

L’errore classico nel misurare l’accuratezza della predizione è quello di utilizzare lo stesso dataset di partenza (chiamiamolo training dataset). Ovviamente, il modello sarà accurato nel prevedere i dati che sono stati usati per costruirlo, ma avrà una bassa accuratezza nel momento in cui dovrà valutare un dato nuovo. 

Le performance di un modello vanno valutate su un campione di dati che non sia stato usato per costruirlo. Occorre, quindi, escludere un po’ di dati dal training dataset e, a partire da essi, testare l’accuratezza. Questo sottoinsieme di dati è chiamato validation data.

(fonte https://cdn-media-1.freecodecamp.org/images/augTyKVuV5uvIJKNnqUf3oR1K5n7E8DaqirO)

Come vanno creati i validation data? Rispondere a questa semplice domanda, richiederebbe un articolo a parte, per descrivere tutte le possibili tecniche, la loro validità e fattibilità. L’unica possibilità che abbiamo come absolute beginners è affidarci a dei tool già pronti.

Restiamo nel mondo Microsoft (analoghi strumenti esistono anche per il cloud Amazon e quello Google) con la libreria ML.NET scoperta nel precedente articolo. Stavolta però, piuttosto che lavorare in una console application in Visual Studio, installiamo globalmente la CLI (Command Line Interface) di ML.NET. L’unico prerequisito è avere installato l’SDK di .NET Core sulla propria macchina.

dotnet tool install -g mlnet

La documentazione ci suggerisce di creare in una cartella vuota una console application

e di lanciare in essa il comando mlnet autotrain sul nostro dataset (copiato anch’esso nella stessa cartella). Il comando completo è:

mlnet auto-train --task regression --dataset "data.csv" --label-column-name "Minutes" --max-exploration-time 500

Il parametro —task va scelto tra Binary Classification, Multiclass Classification e Regression. Poiché siamo interessati a predire; un valore numerico (ad esempio Minutes o Goals) scegliamo Regression.

–dataset indica il file contenente il nostro campione di dati mentre  –label-column indica la colonna del file che vogliamo predire.

–max-exploration-time indica il tempo (in secondi) che vogliamo dare a ML.NET per esplorare differenti modelli. Questo parametro (detto anche training time) va scelto proporzionalmente alla dimensione del dataset.

Durante questo intervallo di tempo, la CLI indica quanto tempo è rimasto, l’accuratezza del miglior modello (Best Accuracy), l’algoritmo usato per raggiungerla (Best Algorithm) e l’ultimo algoritmo analizzato (Last Algorithm)

Dopo aver esplorato ben 106 modelli, il risultato finale è il seguente:

Una Best quality del 45% non è un risultato straordinario, ma neppure terribile se consideriamo che siamo partiti da 0.

Notiamo che la CLI ha anche creato un template di codice C# che utilizza il modello generato (MLModel.zip).

Il codice della console application (SampleRegression.ConsoleApp) è molto semplice: dopo aver caricato il modello viene creato un motore di predizione a partire da esso.

MLContext mlContext = new MLContext();

var mlModel = mlContext.Model.Load(GetAbsolutePath(MODEL_FILEPATH), out DataViewSchema inputSchema);

var predEngine = mlContext.Model.CreatePredictionEngine<ModelInput, ModelOutput>(mlModel);

Il motore di predizione offre un metodo, chiamato Predict, che prende in input una riga di nuove feature. Il metodo restituisce la predizione sulla label cercata dal modello (nel nostro caso Minutes).

ModelOutput predictionResult = predEngine.Predict(newData);

A scopo dimostrativo, il template generato prende in input una riga dal file di partenza (data.csv), mostrandone l’output generato e confrontandolo col valore vero.

La CLI di ML.NET è dunque uno strumento molto semplice ma al tempo stesso potente, per automatizzare una serie di operazioni ripetitive e complesse. Il suo utilizzo ci consente di spostare l’attenzione sul problema reale: la validità del nostro dataset e la sua capacità predittiva. Ad esempio, possiamo velocemente testare cosa succede cambiando la Label (Goals invece che Minutes). La best Quality scende al 31%. Altro test è quello di ridurre il numero di feature nel dataset (rimuovendo ad esempio i nomi delle squadre coinvolte e l’identità del giocatore).

La best quality sulla predizione dei Minutes cala ancora di più: dal 45% al 27%.

L’approccio brute-force, consistente nell’affidarsi ciecamente a un software, non sembra quindi portarci ad alcun risultato soddisfacente. Perché? La risposta sta ancora una volta nella costruzione e selezione delle feature.

Partiamo da una considerazione apparentemente slegata dal contesto del machine learning: siamo molto bravi a risolvere problemi lineari.

(fonte: https://developers.google.com/machine-learning/crash-course/feature-crosses/encoding-nonlinearity)

Ad esempio: siamo capaci di trovare una linea che separi i punti blu da quelli arancioni? Beh, si! Non avremo una separazione perfetta, ma sicuramente gran parte dei punti blu si troverà alla destra di questa linea di separazione.
Cosa possiamo dire invece sui punti nell’immagine seguente?

(fonte: https://developers.google.com/machine-learning/crash-course/feature-crosses/encoding-nonlinearity )

Stavolta non riusciamo a trovare un’unica linea di separazione.

(fonte: https://developers.google.com/machine-learning/crash-course/feature-crosses/encoding-nonlinearity )

Si tratta di un problema non lineare che può essere risolto introducendo quella che in gergo si chiama feature cross, ossia una nuova feature artificiale creata a partire da quelle esistenti. Torniamo all’ultima immagine e supponiamo di spostare il sistema di riferimento nella maniera seguente:

(fonte: https://developers.google.com/machine-learning/crash-course/feature-crosses/encoding-nonlinearity )

Se x1 e x2 sono entrambi positivi o entrambi negativi rispetto a questo nuovo sistema di riferimento, abbiamo un punto blu. In caso contrario, abbiamo un punto arancione.
Introduciamo quindi una feature cross, x3, ottenuta moltiplicando x1 ed x2.

x3 = x1 * x2

x3 è in grado di linearizzare il nostro problema, perché il suo segno riesce a separare i punti blu da quelli arancioni!
Se quindi scrivo la più generale relazione lineare in termini di x1,x2 e x3:

y = w1 * x1 + w2 * x2 + w3 * x3 + b

ponendo w1 e w2 uguali a 0 e w3 = 1, ho trovato una linea di separazione anche se il problema non è lineare. 

Possiamo creare una feature cross in tanti modi diversi: moltiplicando ad esempio cinque feature o moltiplicando per se stessa una feature. 

L’introduzione di un nuovo sistema di riferimento è stata decisiva nel nostro esempio.

È stato un trucchetto o c’è un significato più recondito? Ciò che siamo riusciti a fare è discretizzare lo spazio dei nostri punti e dividerlo in quattro quadranti, ciascuno dei quali aveva praticamente abitanti di un solo colore.

Incidentalmente, il numero di abitanti di ciascun settore era molto alto. Per ogni quadrante abbiamo una probabilità molto alta che un punto sia di uno dei due colori.

Quindi, se ho un nuovo punto e scopro che si trova nel primo quadrante (x1 e x2 > 0), ho una probabilità molto alta che il punto sia blu.

Prendiamo un altro esempio, più complesso.

(fonte: https://developers.google.com/machine-learning/crash-course/feature-crosses/encoding-nonlinearity)

Stavolta non bastano quattro quadranti a discretizzare il nostro spazio. Ma possiamo immaginare una griglia di questo tipo

(fonte: https://developers.google.com/machine-learning/crash-course/feature-crosses/encoding-nonlinearity )

e per ogni quadratino avrò un’alta percentuale di punti appartenenti a una sola categoria.

(fonte: https://developers.google.com/machine-learning/crash-course/feature-crosses/encoding-nonlinearity)

La tecnica del features crossing richiede la memorizzazione di come abbiamo discretizzato il nostro spazio di punti. Per ciascuna cella, inoltre, dobbiamo avere un numero sufficiente di punti da rendere statisticamente significativa la sua percentuale di popolazione. Per tale motivo è una tecnica che solo negli ultimi anni di vita del ML ha preso piede: occorrono tanti dati per renderla efficace.

Confusi? Ecco un ultimo esempio che spero vi chiarisca le idee.

Supponiamo di avere una foto di un’automobile scattata in una città. Dalla foto si distingue solo il dettaglio del colore dell’automobile. Ci chiediamo se si tratta o meno di taxi. Il dataset che utilizzeremo per costruire un modello predittivo sarà di questo tipo:

Colore: Rosso, Città: Napoli. Taxi? No
Colore: Bianco, Città: Napoli. Taxi? Si

…………….

Colore: Giallo, Città: New York. Taxi? Si
Colore: Bianco, Città: New York. Taxi? No

Il modello lineare che usi colore e città e ne calcoli i relativi pesi ha un problema.  

Supponiamo di avere una nuova foto in cui vediamo una automobile gialla.

In gran parte delle città del mondo, il colore dei taxi è giallo: quindi avremo un peso molto alto per questo colore e assegneremo la label come Taxi anche se la foto è stata scattata a Napoli.

La feature cross creata dalla combinazione Colore e Città invece linearizza il problema.

x3 = (Rosso e Napoli) Taxi? No
x3 = (Bianco e Napoli) Taxi? Si

…………….

x3 = (Giallo e New York) Taxi? Si
x3 = (Bianco e New York) Taxi? No

Abbiamo discretizzato il nostro spazio e ogni singola combinazione di colore e città (quello che prima abbiamo chiamato quadratino) ha una probabilità molto alta (o molto bassa) della label Taxi. La nuova foto che mostri un’automobile bianca a New York avrà un’alta percentuale che si tratti di un taxi. Perché nel nostro dataset di partenza, avevamo ad esempio 1000 foto di auto bianche scattate a New York e l’80% di esse era un taxi.

Il nostro dataset calcistico è ragionevolmente grande da poter applicare la tecnica del features crossing in maniera tale da linearizzare il nostro spazio e rendere più efficiente il modello generato da ML.NET. Nel prossimo articolo vedremo come.

A presto!