Print
Deep Learning
Hits: 1008

Introduzione

Ho deciso di raccogliere sul mio sito una serie di note che ho sviluppato durante lo studio dei corsi della specializzazione "Tensorflow in Practice" di Coursera. 

Tensorflow 2.0

Oramai la versione 2 di Tensorflow è disponibile ed è uscita dalla fase beta. Ho deciso pertanto di utilizzare soltanto la versione 2 e di portare tutto il codice scritto prima in vers. 2. Uno dei grandi vantaggi di TF 2 è che ha adottato ufficialmente Keras come API di alto livello. Io ho sempre adorato Keras da quando ho cominciato a leggere il libro di F. Chollet (che è sempre uno dei libri pronto per essere consultato sulla mia scrivania).

Reti Convolutive e Image Recognition.

Le reti convolutive (CNN: Convolutional Neural Networks) sono state utilizzate e sono utilizzate oggi in tutti i casi di maggior successo del Deep Learning. Sono state introdotte alla fine degli anni 90 (Y Le Cunn, LeNet 5) per riconoscere le cifre scritte a mano sugli assegni (handwritten recognition), ma l'enorme e rapido progresso è avvenuto dal 2012 in poi, sopratutto sotto lo stimolo prodotto dalle sfide ILSVRC (ImageNet Large Scale Visual Recognition Challenge).

Grazie alle CNN oggi il problema della Image Recognition è sostanzialmente un problema risolto ed è possibile usare reti pre-trained CNN per ottenere facilmente accuratezze superiori al 95%.

I building block delle CNN sono:

Architettura di una semplice CNN

Una "semplice CNN" è tipicamente fatta da

Questo è un esempio di codice TF:

model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(32, (3,3), activation='relu', input_shape=(150, 150, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dense(1, activation='sigmoid')
])

Nell'esempio si tratta di classificazione binaria (N = 2) e l'ultimo layer utilizza come funzione di attivazione una sigmoide.

Per definire un layer convolutivo (Conv2D) si devono, nell'ordine, specificare:

  1. Il numero di filtri del layer
  2. La shape del filtro (es: (3,3))
  3. La funzione di attivazione (ad es: relu)

Soltanto per il primo layer si deve specificare, con il parametro input_shape, la shape delle immagini in input (nel nostro esempio (150,150,3).

Per un layer MaxPooling si deve specificare solo la shape della finestra usata per il pooling.

In realtà le reti CNN "state of the art" sono molto più complesse. Si vedano ad esempio le architetture di ResNet ed Inception.

Le ResNet ad esempio usano residual block.

La funzione di attivazione ReLU

Nel grafico seguente è rappresentata la funzione di attivazione relu, utilizzata nel modello precedente

 

relu(x) = max(0, x)

 

Classificazione multi-classe.

Trattiamo un problema di classificazione e le classi in cui suddividiamo i nostri campioni sono N (N > 2).

Le seguenti sono le modifiche al codice utilizzato per una classificazione binaria che devono essere apportate se si deve passare ad una classificazione multi-classe:

  1. Per poter utilizzare ImageDataGenerator si devono prevedere, al di sotto delle directory training e validation, tante sotto-directory N quante sono le classi al cui interno classifichiamo le nostre immagini
  2. Nell'invocazione del metodo flow_from_directory si deve specificare class="categorical" (e non più binary)
  3. Nella costruzione del modello TF l'ultimo layer deve avere N neuroni (tanti quanto le classi) e deve utilizzare come funzione di attivazione softmax (e non sigmoid)
  4. Nella compilazione (compile) si deve utilizzare come loss function categorical_crossentropy (e non più binary_crossentropy)

Transfer Learning.

Il Transfer Learning è sicuramente uno dei concetti più affascinanti che si incontrano nel campo delle Deep Neural Networks e sicuramente funziona molto bene con le CNN.

Lo spiego prima da un punto di vista concettuale, utilizzando un esempio concreto. Vi sono numerose CNN che sono state sviluppate nell'ambito della sfida ILSVRC, quali ResNet, Inception etc. Queste reti sono state addestrate su dataset che contengono milioni di immagini (very large dataset) e prevedono alcune migliaia di classi. I ricercatori che hanno sviluppato ed addestrato queste CNN hanno messo a disposizione, in formato Open Source, tutto quanto è necessario per riprodurre la CNN:

Se vogliamo addestrare una nostra rete per riconoscere delle immagini non strettamente previste in ImageNet (ad esempio: oggetti di arredamento) possiamo pensare di utilizzare la conoscenza accumulata in una delle CNN sopra menzionate e di costruire la nostra CNN specializzata riutilizzando la base convolutiva.

In sintesi, si riusano gli strati bassi (la rete è rappresentata ipotizzando l'input, le immagini, in basso) perché sopratutto i primi layer della base convolutiva fungono da "local features detector" identificando caratteristiche quali: linee verticali, orizzontali, spigoli, curve, etc.

Ovviamente, la parte DNN che funge da classificatore sulle feature estratte dalla base convolutiva deve essere addestrata sul nostro dataset.

Entrando nei dettagli, i passi da compiere sono:

  1. Si seleziona una CNN pre-addestrata (es: Inception V3);
  2. Si scaricano i pesi della CNN pre-addestrata; Keras, ad esempio, contiene sia la definizione di alcune di queste reti sia i pesi ottenuti dal training su ImageNet;
  3. Si selezione solo la "convolutional base include_op = False)
  4. Si costruisce il modello aggiungendo alla Convolutional Base il nostro classificatore DNN
  5. Si effettua il "freeze" dei pesi della Convolutional Base
  6. Si effettua il training sul nostro Dataset, eventualmente utilizzando la Data Augmentation

Ecco i passi principali in un esempio di codice:

from tensorflow.keras.applications.inception_v3 import InceptionV3

pretrained_model = InceptionV3(input_shape = (150, 150, 3), 
                                include_top = False, 
                                weights = "imagenet")
pretrained_model.summary()
# per il freeze dei pesi
for layer in pretrained_model.layers:
  layer.trainable = False
 
xxxx
 
Dopo aver effettuato un primo training, si può effettuare un fine tuning. In questo caso, si provvede a "sbloccare" alcuni dei layer più alti della convolutional base e si rieffettua il training, sempre utilizzando la Data Augmnentation, utilizzando però (è un aspetto importante) un learning rate più piccolo.
Il learning rate più piccolo serve per evitare che, nelle epochs iniziali, si producano grandi gradienti che alterino radicalmente i pesi dei layer convolutivi sbloccati. 

Ovviamente:

sono aspetti che devono essere definiti nel problema concreto, facendo ottimizzazione. Dipendono ad esempio da quanto le immagini del nostro dataset "sono simili" alle immagini del dataset su cui il modello pre-trained è stato addestrato. Se le immagini sono tanto differenti solo i layer più bassi, che identificano feature low-level, molto generali, possono essere riusati con i loro pesi.

Overfitting: cos'è e come affrontarlo

Breve descrizione dell'overfitting. Inserire un grafico che mostri evidenze di overfitting.

 

Overfitting e Data Augmentation

Si può fare Data Augmentation specificando una serie di parametri all'interno della creazione del ImageDataGenerator. Ecco un esempio di codice:

train_datagen = ImageDataGenerator(
      rescale=1./255,
      rotation_range=40,
      width_shift_range=0.2,
      height_shift_range=0.2,
      shear_range=0.2,
      zoom_range=0.2,
      horizontal_flip=True,
      fill_mode='nearest')

Libri.

Riporto la lista dei miei libri preferiti. Per ciascun libro il link su Amazon.it, non per spingere ad acquistare su Amazon ma per non dover fornire troppe altre informazioni