Efficiente Segmentazione delle Immagini Utilizzando PyTorch Parte 3

Efficient Image Segmentation with PyTorch Part 3

Convoluzioni separabili in profondità

In questa serie di 4 parti, implementeremo step by step la segmentazione dell’immagine da zero utilizzando tecniche di deep learning in PyTorch. Questa parte si concentrerà sull’ottimizzazione del nostro modello di base CNN utilizzando le convoluzioni separabili in profondità per ridurre il numero di parametri apprendibili, rendendo il modello utilizzabile su dispositivi mobili e altri dispositivi edge.

In collaborazione con Naresh Singh

Figura 1: Risultati dell'esecuzione della segmentazione dell'immagine utilizzando una CNN con convoluzioni separabili in profondità invece delle normali convoluzioni. Dall'alto in basso, immagini di input, maschere di segmentazione a terra veri e maschere di segmentazione previste. Fonte: Autore(i)

Sommario dell’articolo

In questo articolo, aumenteremo la Convolutional Neural Network (CNN) che abbiamo costruito in precedenza per ridurre il numero di parametri apprendibili nella nostra rete. Il compito di identificare i pixel degli animali domestici (pixel appartenenti a gatti, cani, criceti, ecc …) in un’immagine di input rimane invariato. La nostra rete di scelta rimarrà SegNet e l’unica modifica che apporteremo sarà quella di sostituire i nostri strati convoluzionali con convoluzioni separabili in profondità (DSC). Prima di farlo, approfondiremo la teoria e la pratica delle convoluzioni separabili in profondità e apprezzeremo l’idea alla base della tecnica.

In tutto questo articolo, faremo riferimento al codice e ai risultati di questo notebook per l’addestramento del modello e a questo notebook per una guida introduttiva su DSC. Se desideri riprodurre i risultati, avrai bisogno di una GPU per garantire che il primo notebook completi l’esecuzione in un tempo ragionevole. Il secondo notebook può essere eseguito su una CPU regolare.

Articoli in questa serie

Questa serie è per lettori di tutti i livelli di esperienza con il deep learning. Se vuoi imparare la pratica del deep learning e dell’AI di visione insieme a una solida teoria ed esperienza pratica, sei nel posto giusto! Questa serie dovrebbe essere composta da 4 parti con i seguenti articoli:

  1. Concetti e idee
  2. Un modello basato su CNN
  3. Convoluzioni separabili in profondità (questo articolo)
  4. Un modello basato su Vision Transformer

Introduzione

Iniziamo questa discussione con un’occhiata più da vicino alle convoluzioni dal punto di vista della dimensione del modello e del costo di calcolo. Il numero di parametri apprendibili è un buon indicatore della dimensione di un modello e il numero delle operazioni tensoriali riflette la complessità del modello o il costo di calcolo. Supponiamo di avere uno strato di convoluzione con n filtri di dimensione dₖ x dₖ. Inoltre, assumiamo che questo strato elabori un input con forma m x h x w, dove m è il numero di canali di input, e h e w sono rispettivamente le dimensioni di altezza e larghezza. In questo caso, lo strato di convoluzione produrrà un output con forma n x h x w come mostrato in Figura 2.
Stiamo assumendo che la convoluzione utilizzi stride = 1. Andiamo avanti e valutiamo questa configurazione in termini di parametri apprendibili e costo di calcolo.

Figura 2: Filtri convoluzionali regolari applicati all'input per produrre l'output. Assumere stride = 1 e padding = dₖ-2. Fonte: Efficient Deep Learning Book

Valutazione dei parametri apprendibili: Abbiamo n filtri, ognuno dei quali ha m x dₖ x dₖ parametri apprendibili. Ciò comporta un totale di n x m x dₖ x dₖ parametri apprendibili. I termini di bias sono ignorati per semplificare questa discussione. Guardiamo il codice PyTorch qui sotto per validare la nostra comprensione.

import torchfrom torch import nndef num_parameters(m):return sum([p.numel() for p in m.parameters()])dk, m, n = 3, 16, 32print(f"Expected number of parameters: {m * dk * dk * n}")conv1 = nn.Conv2d(in_channels=m, out_channels=n, kernel_size=dk, bias=False)print(f"Actual number of parameters: {num_parameters(conv1)}")

Stampa quanto segue.

Numero atteso di parametri: 4608Numero attuale di parametri: 4608

Ora, valutiamo i costi di elaborazione della convoluzione.

Valutazione del costo di elaborazione: Un singolo filtro convoluzionale di forma m x dₖ x dₖ quando eseguito con uno stride=1 e un padding=dₖ-2 su un input di dimensioni h x w applicherà il filtro convoluzionale h x w volte, una volta per ogni sezione dell’immagine con dimensioni dₖ x dₖ per un totale di h x w sezioni. Risulta in un costo di m x dₖ x dₖ x h x w per filtro o canale di output. Poiché desideriamo calcolare n canali di output, il costo totale sarà m x dₖ x dₖ x h x n . Procediamo e convalidiamo ciò utilizzando il pacchetto PyTorch torchinfo.

from torchinfo import summaryh, w = 128, 128print(f"Numero atteso di moltiplicazioni totali: {m * dk * dk * h * w * n}")summary(conv1, input_size=(1, m, h, w))

Stamperà quanto segue.

Numero atteso di moltiplicazioni totali: 75497472==========================================================================================Layer (type:depth-idx)                   Output Shape              Param #==========================================================================================Conv2d                                   [1, 32, 128, 128]         4,608==========================================================================================Parametri totali: 4,608Parametri addestrabili: 4,608Parametri non addestrabili: 0Totale moltiplicazioni (M): 75.50==========================================================================================Dimensione input (MB): 1.05Dimensione passaggio in avanti/indietro (MB): 4.19Dimensione parametri (MB): 0.02Dimensione totale stimata (MB): 5.26==========================================================================================

Se ignoriamo i dettagli di implementazione di un livello di convoluzione per un momento, ci renderemmo conto che, su un livello elevato, un livello di convoluzione trasforma semplicemente un input m x h x w in un output n x h x w. La trasformazione è ottenuta attraverso filtri addestrabili che apprendono progressivamente le caratteristiche man mano che vedono gli input. La domanda che segue è: è possibile ottenere questa trasformazione utilizzando meno parametri addestrabili e contemporaneamente garantendo un compromesso minimo nelle capacità di apprendimento del livello? Le convoluzioni separabili in profondità sono state proposte per rispondere a questa esatta domanda. Capiscamo in dettaglio e impariamo come si impilano sulle nostre metriche di valutazione.

Convoluzione separabile in profondità

Il concetto di convoluzioni separabili in profondità (DSC) è stato proposto per la prima volta da Laurent Sifre nella loro tesi di dottorato dal titolo Rigid-Motion Scattering For Image Classification . Da allora, sono state utilizzate con successo in vari popolari network di convoluzione profonda come XceptionNet e MobileNet .

La differenza principale tra una convoluzione regolare e una DSC è che una DSC è composta da 2 convoluzioni come descritto di seguito:

  1. Una convoluzione raggruppata in profondità, dove il numero di canali di input m è uguale al numero di canali di output in modo che ciascun canale di output sia influenzato solo da un singolo canale di input. In PyTorch, questo viene chiamato una convoluzione “raggruppata”. Puoi leggere di più sulle convoluzioni raggruppate in PyTorch qui .
  2. Una convoluzione con punto (dimensione del filtro=1), che funziona come una convoluzione regolare in modo che ciascuno dei n filtri operi su tutti i m canali di input per produrre un singolo valore di output.
Figura 3: filtri di convoluzione separabili in profondità applicati all'input per produrre l'output. Assumiamo stride=1 e padding=dₖ-2 . Fonte: Efficient Deep Learning Book

Eseguiamo lo stesso esercizio che abbiamo fatto per le convoluzioni regolari per le DSC e calcoliamo il numero di parametri addestrabili e le elaborazioni.

Valutazione dei parametri addestrabili: Le convoluzioni “raggruppate” hanno m filtri, ciascuno dei quali ha dₖ x dₖ parametri addestrabili che produce m canali di output. Ciò comporta un totale di m x dₖ x dₖ parametri addestrabili. La convoluzione con punto ha n filtri di dimensione m x 1 x 1 che si sommano a n x m x 1 x 1 parametri addestrabili. Vediamo il codice PyTorch qui sotto per convalidare la nostra comprensione.

class DepthwiseSeparableConv(nn.Sequential):    
    def __init__(self, chin, chout, dk):        
        super().__init__(            
            # Convoluzione Depthwise            
            nn.Conv2d(chin, chin, kernel_size=dk, stride=1, padding=dk-2, bias=False, groups=chin),            
            # Convoluzione Pointwise            
            nn.Conv2d(chin, chout, kernel_size=1, bias=False),        
        )
        
conv2 = DepthwiseSeparableConv(chin=m, chout=n, dk=dk)
print(f"Numero atteso di parametri: {m * dk * dk + m * 1 * 1 * n}")
print(f"Numero effettivo di parametri: {num_parameters(conv2)}")

Ciò che verrà stampato è:

Numero atteso di parametri: 656
Numero effettivo di parametri: 656

Possiamo vedere che la versione DSC ha circa 7 volte meno parametri. Ora, concentriamoci sui costi computazionali per uno strato DSC.

Valutazione del costo computazionale: Supponiamo che il nostro input abbia dimensioni spaziali m x h x w. Nel segmento di convoluzione raggruppata di DSC, abbiamo m filtri, ognuno con dimensioni dₖ x dₖ. Un filtro viene applicato al suo corrispondente canale di input, risultando in un costo di segmento di m x dₖ x dₖ x h x w. Per la convoluzione pointwise, applichiamo n filtri di dimensioni m x 1 x 1 per produrre n canali di output. Ciò porta ad un costo di segmento di n x m x 1 x 1 x h x w. Dobbiamo sommare i costi delle operazioni raggruppate e pointwise per calcolare il costo totale. Verifichiamo ciò utilizzando il pacchetto PyTorch torchinfo.

print(f"Numero totale di moltiplicazioni previste: {m * dk * dk * h * w + m * 1 * 1 * h * w * n}")
s2 = summary(conv2, input_size=(1, m, h, w))
print(f"Moltiplicazioni effettive: {s2.total_mult_adds}")
print(s2)

Ciò che verrà stampato è:

Numero totale di moltiplicazioni previste: 10747904
Moltiplicazioni effettive: 10747904
==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
DepthwiseSeparableConv                   [1, 32, 128, 128]         --
├─Conv2d: 1-1                            [1, 16, 128, 128]         144
├─Conv2d: 1-2                            [1, 32, 128, 128]         512
==========================================================================================
Total params: 656
Trainable params: 656
Non-trainable params: 0
Total mult-adds (M): 10.75
==========================================================================================
Input size (MB): 1.05
Forward/backward pass size (MB): 6.29
Params size (MB): 0.00
Estimated Total Size (MB): 7.34

Confrontiamo le dimensioni e i costi delle due convoluzioni per alcuni esempi per avere un’idea più precisa.

Confronto delle dimensioni e dei costi per convoluzioni regolari e depthwise separabili

Per confrontare le dimensioni e i costi della convoluzione regolare e della convoluzione depthwise separabile, assumiamo una dimensione di input di 128 x 128 per la rete, una dimensione del kernel di 3 x 3 e una rete che dimezza progressivamente le dimensioni spaziali e raddoppia le dimensioni del canale. Supponiamo un singolo layer di convoluzione 2d ad ogni passaggio, ma nella pratica potrebbero esserci di più.

Figura 4: Confronto tra il numero di parametri trainabili (dimensioni) e le moltiplicazioni (costi) delle convoluzioni regolari e delle convoluzioni depthwise separabili. Mostriamo anche il rapporto tra le dimensioni e i costi per i due tipi di convoluzioni. Fonte: Autore(i).

Come si può vedere, in media le dimensioni e i costi computazionali di DSC sono circa il 11% – 12% del costo delle convoluzioni regolari per la configurazione sopra menzionata.

Figura 5: Dimensioni relative e costo di convoluzioni regolari vs DSC. Fonte: Autore/i.

Ora che abbiamo sviluppato una buona comprensione dei tipi di convoluzioni e dei loro costi relativi, ti starai chiedendo se ci sono degli svantaggi nell’utilizzo di DSC. Tutto ciò che abbiamo visto finora sembra suggerire che siano migliori in ogni modo! Beh, non abbiamo ancora considerato un aspetto importante che è l’impatto che hanno sull’accuratezza del nostro modello. Vediamo attraverso un esperimento qui di seguito.

SegNet Utilizzando Convoluzioni Separabili in Profondità

Questo notebook contiene tutto il codice per questa sezione.

Adatteremo il nostro modello SegNet dalla precedente sezione e sostituiremo tutti gli strati di convoluzione regolari con uno strato DSC. Una volta fatto ciò, notiamo che il numero di parametri nel nostro notebook scende da 15,27M a 1,75M di parametri, che è una riduzione dell’88,5%! Ciò è in linea con le nostre stime precedenti di una riduzione del 11% al 12% del numero di parametri addestrabili della rete.

È stata utilizzata una configurazione simile a quella precedente durante l’addestramento e la convalida del modello. La configurazione è specificata di seguito.

  1. Vengono applicate le tecniche di aumento dati di ribaltamento orizzontale casuale e di jitter di colore al set di addestramento per evitare l’overfitting
  2. Le immagini vengono ridimensionate a 128×128 pixel in un’operazione di ridimensionamento non conservante l’aspetto
  3. Nessuna normalizzazione dell’input viene applicata alle immagini – invece, uno strato di normalizzazione batch viene utilizzato come primo strato del modello
  4. Il modello viene addestrato per 20 epoche utilizzando l’ottimizzatore Adam con un LR di 0,001 e nessun programma di riduzione del LR
  5. La funzione di perdita di entropia incrociata viene utilizzata per classificare un pixel come appartenente a un animale domestico, allo sfondo o a un bordo di un animale domestico

Il modello ha raggiunto un’accuratezza di convalida dell’86,96% dopo 20 epoche di addestramento. Questo è inferiore all’accuratezza del 88,28% raggiunta dal modello che utilizza convoluzioni regolari per lo stesso numero di epoche di addestramento. Abbiamo determinato sperimentalmente che l’addestramento per più epoche migliora l’accuratezza di entrambi i modelli, quindi 20 epoche non sono sicuramente la fine del ciclo di addestramento. Ci fermiamo a 20 epoche per scopi dimostrativi in questo articolo.

Abbiamo tracciato un gif che mostra come il modello sta imparando a prevedere le maschere di segmentazione per 21 immagini nel set di convalida.

Figura 6: Un gif che mostra come il modello SegNet con DSC sta imparando a prevedere le maschere di segmentazione per 21 immagini nel set di convalida. Fonte: Autore/i

Ora che abbiamo visto come il modello progredisce attraverso il ciclo di addestramento, confrontiamo i cicli di addestramento dei modelli con convoluzioni regolari e DSC.

Confronti di accuratezza

Troviamo utile guardare ai cicli di addestramento dei modelli con convoluzioni regolari e DSC. La differenza principale che abbiamo notato è nelle prime fasi (epoche) di addestramento, dopo le quali entrambi i modelli si stabilizzano approssimativamente nello stesso flusso di previsione. Infatti, dopo aver addestrato entrambi i modelli per 100 epoche, abbiamo notato che l’accuratezza del modello con DSC è solo circa l’1% in meno rispetto al modello con convoluzioni regolari. Ciò è in linea con le nostre osservazioni da soli 20 epoche di addestramento.

Figura 7: Un gif che mostra la progressione delle maschere di segmentazione previste dal modello SegNet utilizzando convoluzioni regolari vs DSC. Fonte: Autore/i.

Avrai notato che entrambi i modelli ottengono previsioni approssimativamente corrette dopo solo 6 epoche di addestramento, ovvero si può vedere visivamente che i modelli stanno prevedendo qualcosa di utile. La maggior parte del lavoro duro nell’addestrare il modello è quindi sopra, assicurando che i bordi delle maschere previste siano il più stretti possibile e il più vicini possibile agli animali domestici effettivi nell’immagine. Ciò significa che mentre ci si può aspettare una minore aumento assoluto dell’accuratezza nelle epoche di addestramento successive, l’impatto di questo sulla qualità delle previsioni è molto maggiore. Abbiamo notato che un miglioramento di una sola cifra dell’accuratezza a valori di accuratezza assoluti più elevati (passando dall’89% al 90%) comporta miglioramenti qualitativi significativi delle previsioni.

Confronto con un modello UNet

Abbiamo eseguito un esperimento che ha modificato molti iperparametri con l’obiettivo di migliorare la precisione complessiva per avere un’idea di quanto questa configurazione sia lontana dall’essere ottimale. Ecco la configurazione di tale esperimento.

  1. Dimensioni dell’immagine: 128 x 128 — come negli esperimenti finora
  2. Epoca di formazione: 100 — gli esperimenti attuali sono stati formati per 20 epoche
  3. Aumenti: molti più aumenti come la rotazione dell’immagine, la rimozione casuale di canali, la rimozione casuale di blocchi. Abbiamo utilizzato Albumentations invece di torchvision transforms. Albumentations trasforma automaticamente le maschere di segmentazione per noi
  4. LR Scheduler: è stato utilizzato uno scheduler StepLR con un decadimento di 0,8x ogni 25 epoche di formazione
  5. Funzione di perdita: abbiamo provato 4 diverse funzioni di perdita: Cross Entropy, Focal, Dice, Weighted Cross Entropy. Dice si è comportato peggio mentre il resto erano praticamente comparabili tra loro. Infatti, la differenza nella migliore precisione tra il resto dopo 100 epoche era nel 4° decimale dopo la virgola (supponendo che la precisione sia un numero compreso tra 0,0 e 1,0)
  6. Tipo di convoluzione: regolare
  7. Tipo di modello: UNet — gli esperimenti attuali hanno utilizzato un modello SegNet

Abbiamo raggiunto una migliore precisione di convalida del 91,3% per la configurazione sopra. Abbiamo notato che le dimensioni dell’immagine influiscono significativamente sulla migliore precisione di convalida. Ad esempio, quando abbiamo cambiato le dimensioni dell’immagine a 256 x 256, la migliore precisione di convalida è salita al 93,0%. Tuttavia, la formazione ha richiesto molto più tempo e ha utilizzato più memoria, il che ha significato che abbiamo dovuto ridurre la dimensione del batch.

Figura 8: Risultato della formazione di un modello UNet per 100 epoche di formazione con gli iperparametri sopra menzionati. Fonte: autore(i).

Puoi vedere che le previsioni sono molto più lisce e nitide rispetto a quelle che abbiamo visto finora.

Conclusione

Nella parte 3 di questa serie, abbiamo appreso le convoluzioni separabili in profondità (DSC) come tecnica per ridurre la dimensione del modello e il costo di formazione / inferenza senza una significativa perdita di precisione di convalida. Abbiamo appreso il compromesso dimensione / costo da aspettarsi tra regolare e DSC per una determinata configurazione.

Abbiamo mostrato come adattare il modello SegNet per utilizzare DSC in PyTorch. Questa tecnica può essere applicata a qualsiasi CNN profondo. Infatti, possiamo sostituire selettivamente alcune delle layer convoluzionali con DSC, cioè non dobbiamo necessariamente sostituirle tutte. La scelta delle layer da sostituire dipenderà dall’equilibrio che si desidera raggiungere tra dimensione del modello / costo di runtime e precisione di previsione. Questa decisione dipenderà dal tuo caso d’uso specifico e dalla configurazione di distribuzione.

Mentre questo articolo ha formato i modelli per 20 epoche, abbiamo spiegato che questo è insufficiente per i carichi di lavoro di produzione e abbiamo fornito uno sguardo su cosa ci si può aspettare se si addestra il modello per più epoche. Inoltre, abbiamo fornito un’introduzione ad alcuni degli iperparametri che è possibile regolare durante la formazione del modello. Sebbene questa lista non sia esaustiva, dovrebbe consentirti di apprezzare la complessità e le decisioni necessarie per formare un modello di segmentazione delle immagini per i carichi di lavoro di produzione.

Nella prossima parte di questa serie, esamineremo i Vision Transformers e come possiamo utilizzare questa architettura del modello per eseguire la segmentazione delle immagini per il compito di segmentazione degli animali domestici.

Riferimenti e lettura ulteriore

  • Efficient Deep Learning Book Capitolo 04 — Architetture efficienti
  • Un’introduzione di base alle convoluzioni separabili