Introduzione
Al giorno d’oggi non passa un giorno senza che sentiamo notizie su quanto avanzati e dirompenti siano i più recenti strumenti basati sull’intelligenza artificiale. Ma come funzionano?
Da veri appassionati della matematica, in queste newsletter andremo a scoprire alcuni dei meccanismi matematici dietro a questi strumenti. Ovviamente, non possiamo partire affrontando modelli super complessi, dato che non sono nemmeno così ben compresi.
Al tempo stesso, non voglio nemmeno partire dal machine learning più classico (ovvero regressione lineare, kernel methods, support vector machines…). Questo non perché questi metodi non siano interessanti ed utili, ma perché voglio partire un po’ più vicino agli strumenti moderni.
Iniziamo quindi dal discutere cosa sia una rete neurale da un punto di vista matematico.
Classificare immagini
Per introdurre questo concetto, ci concentriamo su un problema ben preciso ed intuitivo: classificare delle immagini. Supponiamo per esempio di avere un bel numero di immagini di 10 tipologie di animali differenti, per esempio 5.000 immagini di cani, 5.000 di gatti, 5.000 di scimmie e così via, fino a raggiungere 10 classi.
In questo caso, vogliamo quindi definire una funzione che prenda in pasto un’immagine di una specifica dimensione, per esempio di 32x32 pixel con 3 canali dovuti alla presenza dei colori della scala RGB, e restituisca un vettore di 10 componenti.

Il vettore che ci restituisce ha 10 componenti perché 10 sono le classi nelle quali vogliamo suddividere le nostre immagini. L’idea infatti è che ognuna di queste 10 entrate corrisponda alla probabilità che l’immagine fornita in ingresso appartenga a quella classe.
Vediamo di rendere un po’ più matematico questo ragionamento!
Abbiamo 50.000 immagini di animali, appartenenti a 10 classi, ognuna con 5.000 immagini associate. Queste immagini hanno dimensione 3x32x32, dove 3 sono i canali della scala dei colori RGB. Se non sei familiare con oggetti di queste dimensioni, ovvero i tensori, ne ho parlato in questo video
Il nostro obiettivo è poi di approssimare una funzione
che soddisfa la seguente proprietà:
Vediamo di interpretare un secondo quello che ho scritto qui sopra. Diciamo che l’i-esima immagine x_i appartiene alla k-sima classe se e solo se, applicata la funzione f ad x_i, otteniamo un vettore la cui entrata più grande è la k-sima. Puoi interpretare questo ragionamento pensando che la funzione f, ovvero quell’oracolo che conosce le classi di tute le immagini, dice che è “più probabile” che quest’immagine appartenga alla k-sima classe che alle altre.
Cos’è una rete neurale
Veniamo però alle reti neurali ora! Queste non sono altro che delle funzioni che dipendo da dei parametri, solitamente chiamati pesi, i quali vengono scelti per far sì che la risultante funzione risolva in modo sufficientemente accurato il problema che ci interessa.
Non tutte le funzioni parametriche sono però reti neurali. Queste ultime sono solitamente definite componendo funzioni piuttosto elementari l’una con l’altra. Più precisamente, diciamo rete neurale una funzione della forma
Questa rete neurale qui sopra è formata da L layer (o strati in italiano). Ognuno di questi è definito grazie ad un insieme di parametri
Tutti questi parametri/pesi sono poi raccolti in
che è un vettore dove organizziamo tutti i pesi della rete neurale
Andremo più nei dettagli di alcune tipologie di layer/strati in futuri post dedicati. Però, per non lasciarti con concetti astratti e generici, ecco alcuni esempi di layer/strati che vengono comunemente usati:
Nei casi qui sopra, abbiamo sempre che i pesi
raccolgono matrici e vettori con le opportune dimensioni. Cambiando leggermente notazione, puoi vedere una rappresentazione grafica di una rete con L+2 layer qui sotto, dove il primo e l’ultimo sono mappe lineari definite dalle matrici A e P rispettivamente, anch’esse dei parametri della rete:
Scegliere i pesi della rete
Inizialmente, i pesi della rete sono scelti casualmente. In tal caso, la rete non sarà mai in grado di fare delle previsioni sensate delle classi alle quali le immagini appartengono. Dobbiamo quindi trovare un modo per migliorare queste previsioni, e scegliere dei pesi più validi.
Questo è il compito della funzione di costo/loss function, e dell’algoritmo di ottimizzazione dei pesi. In questo post voglio solo introdurre questi concetti, che verranno poi approfonditi in futuro.
La funzione di costo, non è altro che una funzione che ci quantifica quanto buone sono le previsioni che la rete con i pesi attuali è in grado di fornire. L’esempio più semplice, anche se non il più appropriato per questo problema di classificazione, è quello dell’errore quadratico:
In questo caso, N è il numero di immagini che usiamo per quantificare la qualità delle previsioni. Un’opzione è scegliere N=50.000 in questo caso, ma vedremo che è solitamente meglio lavorare con le cosiddette mini-batch, ovvero con sottoinsiemi dell’intero insieme delle immagini, e quindi con N<50.000. La scelta dell’errore quadratico non è per niente ottimale in questo caso, ma facciamo finta per il momento che sia una scelta opportuna. La cosa importante è che
A questo punto non resta che migliorare i pesi con un algoritmo di ottimizzazione. L’idea è che partiamo con un insieme casuale di pesi, per esempio con pesi estratti in modo indipendente dalla distribuzione Gaussiana
In seguito, andiamo a modificare i pesi iterativamente, cercando di ridurre il valore della funzione di costo dopo l’aggiornamento, ovvero di ottenere
L’algoritmo si ferma quando siamo contenti abbastanza. Ciò può voler dire che ci fermiamo dopo un numero prefissato di iterazioni (epoche), oppure quando vediamo che smettiamo di progredire. Nel caso conoscessi già qualcosina sugli algoritmi di ottimizzazione numerica, puoi pensare che l’algoritmo sia quello più semplice, ovvero la discesa del gradiente:
Nel caso questo algoritmo non ti dica nulla, non preoccuparti! Ne parleremo più dettagliatamente in un articolo dedicato.
Per concludere, supponiamo che dopo 10.000 iterazioni abbiamo ottenuto un insieme di pesi
e che abbiamo deciso di fermarci. A questo punto, possiamo fissare i pesi e usare la funzione
per classificare delle nuove immagini! Con ciò, intendo che posso applicare la rete ad un’immagine di una scimmia, tipo quella nella figura qui sopra, e vedere che vettore mi restituisce. Supponiamo mi restituisca
Questo vuol dire che la rete allenata crede che la classe di cui più probabilmente fa parte quest’immagine sia la prima. Ora, se le classi che abbiamo definito sono
[1: “Scimmia” , 2: “Cane” , 3: “Gatto” , 4: “Topo” , 5: “Zebra” , 6: “Leone” , 7: “Toro” , 8: “Elefante”, 9: “Balena” , 10: “Delfino” ],
vuol dire che la rete ha correttamente identificato che l’immagine da noi fornita è una scimmia.
Conclusione
In questo articolo abbiamo introdotto alcuni concetti fondamentali per andare a parlare in modo relativamente preciso delle reti neurali da un punto di vista matematico. Abbiamo visto che gli elementi fondamentali sono:
l’assemblaggio di un buon dataset di immagini,
la scelta di come parametrizzare i layer/strati della rete,
la scelta della funzione di costo/loss function,
la scelta dell’algoritmo di ottimizzazione.
Negli articoli futuri andremo a concentrarci sui punti 2, 3, e 4. Il primo punto è essenziale, ma non ho intenzione di parlarne in questa serie di articoli.
Fammi sapere cosa ne pensi di questo primo articolo, e se hai domande fatti sentire nei commenti!
Mi piace il tuo stile didattico, formalizzi come la teoria impone ma poi vai al sodo, alla sostanza lasciando al lettore curioso lo sforzo di capire come quella "sostanza" può essere formalizzata in quella "forma"... spero che tu possa continuare a trovare il tempo di continuare questa tua attività didattica qui e su YouTube dove ti seguo assiduamente.