Parte IV — Localizzazione e deep learning · Capitolo 13

Deep learning per la semantic segmentation

~40 min di lettura3 widget interattivi4 tavole

In questo capitolo

  1. Dalla detection alla segmentazione
  2. Ambiti applicativi
  3. Valutare le prestazioni: accuratezza e classi sbilanciate
  4. Confusion matrix, IoU e Dice index
  5. Dal patch-per-pixel alla rete pienamente convoluzionale
  6. La struttura encoder-decoder
  7. Unpooling
  8. Transposed convolution
  9. Skip connection: recuperare i dettagli
  10. FCN, DeconvNet e U-Net
  11. Mask R-CNN: instance segmentation
  12. Dataset e modelli recenti
  13. Verifica le tue conoscenze

1. Dalla detection alla segmentazione

Con il termine segmentation ci si riferisce a un insieme di metodi il cui obiettivo è partizionare un'immagine di input in regioni con proprietà comuni (es. colore, edge) — lo stesso obiettivo del capitolo 3. Due varianti profonde:

È il passo successivo alla object detection: invece di una bounding box per oggetto, si produce una maschera densa a livello di pixel.

input semantic classe per pixel (senza istanze) instance ogni istanza è distinta semantic segmentation: classificazione per pixel · instance segmentation: istanze distinte per classe
Tavola 13.1 — Semantic vs instance segmentation: la prima classifica ogni pixel per classe, la seconda distingue anche le singole istanze della stessa classe (le due figure blu sono due istanze diverse).

2. Ambiti applicativi

Numerosi ambiti applicativi traggono beneficio dalla semantic segmentation: le immagini medicali (segmentazione di organi e lesioni), le auto a guida autonoma (separazione di strada, veicoli, pedoni a livello di pixel) e l'analisi di immagini satellitari (classificazione del suolo e delle aree urbane).

3. Valutare le prestazioni: accuratezza e classi sbilanciate

In letteratura esistono vari indicatori per misurare le prestazioni di un sistema di segmentazione. I più semplici: l'accuratezza di classificazione (la percentuale di pixel correttamente classificati) e l'errore di classificazione (il complemento dell'accuratezza). Attenzione ai problemi con cardinalità delle classi molto sbilanciata: se una classe copre il 95% dei pixel (es. lo sfondo), classificare tutto come quella classe dà un'accuratezza del 95% pur essendo un sistema inutile — l'accuratezza grezza è fuorviante.

Il problema delle classi sbilanciate

Un'immagine con 1000 pixel: regola la dimensione dello sfondo (in %) e l'accuratezza del classificatore sui pixel di primo piano. Un sistema che classifica tutto come sfondo può avere un'accuratezza altissima senza riconoscere nulla.

4. Confusion matrix, IoU e Dice index

Confusion matrix — ogni cella (i, j) riporta la percentuale di casi in cui il sistema ha assegnato la classe j a un pixel la cui classe reale è i. Le slide mostrano l'esempio con 5 classi (gatto, cane, coniglio, capra, maiale): il gatto è classificato correttamente al 71% (il 29% come cane), il cane al 38%, il coniglio al 92%, la capra all'83% e il maiale al 54%. La matrice evidenzia le confusioni sistematiche tra classi simili.

Due indici basati sull'overlap tra la maschera restituita dal sistema e quella attesa:

IoU (Jaccard index)  = area(A_t ∩ R_e) / area(A_t ∪ R_e)
Dice index (DSC/F1)  = 2 · area(A_t ∩ R_e) / (area(A_t) + area(R_e))

Il Dice index misura il rapporto tra i pixel in comune e il numero di pixel presente in ogni maschera; è una misura molto usata nelle applicazioni mediche.

IoU e Dice a confronto

La maschera attesa (verde) e quella restituita (cobalto) si sovrappongono parzialmente. Regola l'overlap per vedere come si comportano i due indici: il Dice è sempre ≥ IoU (a parità di overlap).

5. Dal patch-per-pixel alla rete pienamente convoluzionale

Il primo approccio «naïve» alla semantic segmentation con CNN: per ogni pixel, si estrae una patch centrata sul pixel, la si dà in input a una CNN di classificazione, e la classe assegnata al pixel centrale della patch diventa la classe del pixel. La procedura viene ripetuta per ogni pixel dell'immagine. Problemi: molto inefficiente (una forward per pixel!) e si usano solo le informazioni contenute nell'intorno del pixel (contesto limitato).

L'evoluzione: una rete senza livelli fully-connected (pienamente convoluzionale) che produce direttamente una mappa di classi. Il problema: l'output è più piccolo dell'input a causa della riduzione delle dimensioni spaziali (convoluzioni e pooling). Serve quindi una parte che riporti l'output alle dimensioni originali: nasce la struttura encoder-decoder.

approccio naïve: patch per pixel patch CNN per ogni pixel: inefficiente! CNN CLASSE rete pienamente convoluzionale input (alta risoluzione) CNN (no FC) output piccolo serve il decoder! output < input a causa di convoluzioni e pooling → struttura encoder-decoder
Tavola 13.2 — Dal patch-per-pixel (una CNN per ogni pixel, inefficiente e con contesto limitato) alla rete pienamente convoluzionale, il cui output è però più piccolo dell'input: il decoder deve riportarlo alla risoluzione originale.

6. La struttura encoder-decoder

La maggior parte delle reti per la semantic segmentation condivide la medesima struttura generale: una rete di codifica (encoder) seguita da una rete di decodifica (decoder).

Per ottenere un output delle stesse dimensioni dell'immagine di input, il decoder deve «invertire» le operazioni di convoluzione e pooling dell'encoder, avvalendosi di due nuove operazioni: unpooling e transposed convolution.

input conv+pool conv+pool basso livello unpool+ tconv unpool+ tconv output (denso) ENCODER DECODER encoder: mapping a bassa risoluzione con feature discriminanti · decoder: proiezione «densa» sui pixel
Tavola 13.3 — La struttura encoder-decoder: l'encoder riduce la risoluzione aggregando feature discriminanti, il decoder la riporta alla risoluzione originale con unpooling e transposed convolution, producendo la classificazione densa.

7. Unpooling

L'obiettivo dell'unpooling è invertire una precedente operazione di pooling aumentando le dimensioni della feature map di input. Mentre il pooling riduce la risoluzione condensando una sotto-finestra in un singolo valore, l'unpooling amplia la risoluzione distribuendo un singolo valore su una sotto-finestra. Nel caso del max pooling si ricordano le posizioni dei massimi: l'unpooling riposiziona ogni valore nella posizione in cui era stato selezionato il massimo, riempiendo di zeri le altre celle. Nel caso dell'average pooling, il valore viene replicato su tutta la sotto-finestra (es. 3.25 → 3.25 3.25 su due celle). L'esempio delle slide: max pooling 2 × 2 stride 2 su una 4 × 4 (valori 1 1 2 4 / 5 6 7 8 / 3 2 1 0 / 1 2 3 4) → 2 × 2 (6, 8, 3, 4); l'unpooling con le posizioni dei massimi rimette 6, 8, 3, 4 nelle celle giuste e zeri altrove.

Max pooling e unpooling con le posizioni dei massimi

Input 4×4 (i valori delle slide). Il max pooling 2×2 stride 2 seleziona il massimo di ogni finestra; l'unpooling usa le posizioni ricordate per rimettersi al posto giusto (il resto è zero).

8. Transposed convolution

Data una feature map M, ottenuta applicando una convoluzione a una feature map iniziale I, la transposed convolution è l'operazione che, applicata a M, consente di ottenere una feature map I′ con le stesse dimensioni di I. Mentre nella convoluzione «diretta» l'input definisce la posizione in cui applicare il filtro, nella transposed convolution l'input definisce il peso del filtro e i contributi dei filtri si sommano tra loro (scatter-add). Per una convoluzione con kernel F, stride S e padding P:

convoluzione:      W_out = (W_in − F + 2·P)/S + 1
transposed conv:   W_out = (W_in − 1)·S + F − 2·P

L'esempio delle slide: input 2 × 2 (0 1 / 2 3), kernel 3 × 3 (0 1 2 / 3 4 5 / 6 7 8), stride 1, padding 0 → output 4 × 4. Ogni valore dell'input viene «spalmato» sul kernel pesato e i contributi si sommano: per l'input 2×2, output = [[0, 0, 1, 2], [0, 6, 11, 11]…] secondo lo schema delle slide. Con stride 2 l'output diventa 5 × 5 e i kernel pesati sono distanziati di 2 celle, con overlap che si sommano; con padding 1 l'output torna 3 × 3. L'esempio di decoder completo nelle slide: 224 × 224 → (encoder) 14 × 14 → unpooling 28 × 28 → transposed conv 28 × 28 → unpooling 56 × 56 → transposed conv 56 × 56 → unpooling 112 × 112 → transposed conv 112 × 112 → unpooling 224 × 224 → transposed conv 224 × 224.

9. Skip connection: recuperare i dettagli

Se l'encoder e il decoder venissero messi semplicemente in sequenza, si correrebbe il rischio di perdere informazioni di basso livello (dettagli): il decoder produrrebbe un output piuttosto impreciso, soprattutto nelle zone di confine tra classi diverse. Per ovviare a questa perdita, si può dare al decoder la possibilità di accedere alle feature di basso livello prodotte dagli strati dell'encoder. Ciò si ottiene tramite le skip connection: gli output intermedi dell'encoder vengono aggiunti/concatenati (in posizioni opportune) agli input dei livelli intermedi del decoder. Il risultato è una segmentazione molto più precisa ai bordi (come mostrato dal confronto «senza skip / con skip connections» delle slide).

input output encoder decoder skip connection: concatena le feature dell'encoder agli input dei livelli intermedi del decoder (struttura a U)
Tavola 13.4 — Le skip connection: gli output intermedi dell'encoder vengono concatenati agli input dei livelli intermedi del decoder, recuperando i dettagli di basso livello persi dalla compressione e migliorando i confini tra classi.

10. FCN, DeconvNet e U-Net

Fully Convolutional Network (FCN) — Long, Shelhamer e Darrell sono stati i primi (2015) a proporre una FCN per la segmentazione di immagini. Non essendoci livelli fully-connected, può essere usata con immagini di qualsiasi dimensione; è utilizzabile con diverse architetture (backbone) allo stato dell'arte: VGG, AlexNet, GoogLeNet; l'addestramento è effettuato tramite fine-tuning.

DeconvNet — Noh, Hong e Han (2015) proposero un modello composto da due parti connesse tra loro: encoder e decoder. L'encoder è l'architettura VGG16 (adattabile ad altre); il decoder è speculare all'encoder; presenza di due livelli fully-connected; batch normalization dopo ogni livello di convoluzione per aumentare la velocità di apprendimento; addestramento tramite fine-tuning.

U-Net — proposta da Ronneberger, Fischer e Brox (2015) per segmentare immagini medicali; combina informazioni locali (encoder) e contestuali (decoder) grazie alle skip connections (la struttura a U del nome); non avendo livelli FC può usare immagini di qualsiasi dimensione; è efficiente e non necessita di grandi quantità di dati; nata per la medicina, è facilmente utilizzabile anche in altri contesti; addestramento end-to-end.

11. Mask R-CNN: instance segmentation

Nel 2017, He, Gkioxari, Dollar e Girshick proposero Mask R-CNN per risolvere problemi di instance segmentation. È composta da: una Faster R-CNN, un RoI align layer e una Mask head. La Faster R-CNN restituisce una bounding box e una label per ogni oggetto; il RoI pooling della Faster R-CNN è sostituito da un RoI align layer per meglio preservare le informazioni spaziali; l'output del RoI align è dato in input alla Mask head, che genera una maschera binaria per ogni RoI. La multi-task loss per ogni RoI:

L = L_cls + L_box + L_mask

Le componenti Lcls e Lbox sono identiche a quelle della Faster R-CNN; Lmask è la media della binary cross-entropy calcolata sull'intera maschera. Mask R-CNN è facile da addestrare, efficiente, con performance elevate e molto flessibile: facilmente adattabile ad altri task.

RoI align layer

Il RoI pooling restituisce un volume di output di dimensione prefissata indipendentemente dalla dimensione della regione di interesse, ma soffre del problema del disallineamento (poco influente per l'object detection) causato da due arrotondamenti: l'arrotondamento di x, y, w e h della regione e l'arrotondamento della divisione in celle. Per la segmentazione il disallineamento è estremamente dannoso: il RoI align evita i due arrotondamenti usando l'interpolazione bilineare.

Mask head

La Mask head è composta da due layer: transposed convolution e convoluzione. Restituisce una maschera binaria che si riferisce alla classe restituita dalla Faster R-CNN.

immagine Faster R-CNN bounding box + label RoI align interpolazione bilineare (niente arrotondamenti) Mask head transposed conv + conv maschera binaria per RoI L = L_cls + L_box + L_mask
Tavola 13.5 — Mask R-CNN: la Faster R-CNN produce bounding box e label, il RoI align preserva le informazioni spaziali senza arrotondamenti, la Mask head genera la maschera binaria per ogni regione; la loss combina classificazione, box e maschera.

12. Dataset e modelli recenti

I dataset di riferimento per la segmentazione:

Dataset# immagini# classiCaratteristiche
PASCAL VOC~20K20Dataset storico, semplice, ideale per training rapido e sperimentazioni didattiche
Cityscapes5K30Scene urbane, standard per la guida autonoma
ADE20K~27K~150Scene indoor/outdoor
COCO-Stuff164K~170Molto complesso
Mapillary Vistas25K124Scene stradali

Modelli recenti: DeepLabV3+ (ottimo per multi-scale context e contorni precisi, ma computazionalmente pesante per il real-time); SegFormer (alta accuratezza e generalizzazione eccellente, richiede GPU potenti per il training); SAM (Segment Anything Model: non richiede retraining e segmenta qualsiasi oggetto, ma non è ottimizzato sui dataset classici — è progettato per la versatilità); PointRend (ottimo per immagini ad alta risoluzione e video, più complesso da integrare).

Verifica le tue conoscenze

Che cos'è la semantic segmentation e in cosa differisce dall'instance segmentation?

La semantic segmentation classifica ogni pixel di un'immagine sulla base di un insieme predefinito di classi (senza distinguere le istanze). L'instance segmentation classifica ogni pixel identificando le diverse istanze delle varie classi (es. «persona 1», «persona 2», …).

Perché l'accuratezza grezza può essere fuorviante nella segmentazione?

Con cardinalità delle classi molto sbilanciata, se una classe copre il 95% dei pixel un sistema che classifica tutto come quella classe ottiene un'accuratezza del 95% pur essendo inutile. Servono indicatori che tengano conto delle singole classi (confusion matrix, IoU, Dice).

Che cos'è la confusion matrix e cosa mostra?

Ogni cella (i, j) riporta la percentuale di casi in cui il sistema ha assegnato la classe j a un pixel la cui classe reale è i. Evidenzia le confusioni sistematiche tra classi simili (es. nel caso delle slide il gatto è confuso col cane nel 29% dei casi).

Scrivete le formule di IoU e Dice index.

IoU = area(A_t ∩ R_e) / area(A_t ∪ R_e) (Jaccard index) e DSC = 2·area(A_t ∩ R_e) / (area(A_t) + area(R_e)) (Dice/F1): misurano l'overlap tra la maschera restituita e quella attesa. Il Dice è sempre ≥ IoU a parità di overlap.

Quali sono i problemi dell'approccio patch-per-pixel?

È molto inefficiente (una forward della CNN per ogni pixel) e usa solo le informazioni contenute nell'intorno del pixel (contesto limitato).

Perché una rete pienamente convoluzionale produce un output più piccolo dell'input?

Per la riduzione delle dimensioni spaziali causata dalle operazioni di convoluzione e pooling. Il problema è risolto dal decoder, che riporta l'output alla risoluzione originale.

Descrivete la struttura encoder-decoder.

L'encoder effettua un mapping a bassa risoluzione dell'immagine aggregando feature altamente discriminanti; il decoder proietta le feature a bassa risoluzione sullo spazio originale dei pixel per ottenere una classificazione densa, invertendo convoluzioni e pooling con unpooling e transposed convolution.

Come funziona l'unpooling?

Amplia la risoluzione distribuendo un singolo valore su una sotto-finestra, invertendo il pooling. Nel max pooling si ricordano le posizioni dei massimi: l'unpooling riposiziona ogni valore nella posizione del massimo e mette zeri altrove; nell'average pooling il valore è replicato su tutta la sotto-finestra.

Che cos'è la transposed convolution e qual è la sua formula di output?

L'operazione che, applicata a una feature map M ottenuta da una convoluzione di I, produce una feature map I′ con le stesse dimensioni di I. L'input definisce il peso del filtro e i contributi si sommano tra loro (scatter-add). Formula: W_out = (W_in − 1)·Stride + F − 2·Padding.

Perché servono le skip connection nella segmentazione?

Senza skip, il decoder perderebbe le informazioni di basso livello (dettagli) e produrrebbe output imprecisi soprattutto ai confini tra classi. Le skip connection aggiungono/concatenano gli output intermedi dell'encoder agli input dei livelli intermedi del decoder, recuperando i dettagli.

Confrontate FCN, DeconvNet e U-Net.

FCN (2015): prima rete pienamente convoluzionale, qualsiasi dimensione di input, backbone VGG/AlexNet/GoogLeNet, fine-tuning. DeconvNet (2015): encoder VGG16 + decoder speculare, due FC, batch normalization. U-Net (2015): encoder+decoder con skip connections (struttura a U), efficiente, pochi dati necessari, nata per le immagini medicali, end-to-end.

Descrivete l'architettura di Mask R-CNN.

Una Faster R-CNN (bounding box + label), un RoI align layer al posto del RoI pooling e una Mask head (transposed convolution + convoluzione) che genera una maschera binaria per ogni RoI. Loss: L = L_cls + L_box + L_mask con L_mask media della binary cross-entropy sull'intera maschera.

Che cos'è il problema del disallineamento del RoI pooling e come lo risolve il RoI align?

Il RoI pooling introduce due arrotondamenti (di x, y, w, h e della divisione in celle) che causano disallineamento: poco influente per la detection, estremamente dannoso per la segmentazione. Il RoI align evita gli arrotondamenti usando l'interpolazione bilineare.

Quali sono i principali dataset per la semantic segmentation?

PASCAL VOC (~20K, 20 classi, storico e didattico), Cityscapes (5K, 30 classi, scene urbane per la guida autonoma), ADE20K (~27K, ~150 classi, scene indoor/outdoor), COCO-Stuff (164K, ~170 classi, molto complesso), Mapillary Vistas (25K, 124 classi, scene stradali).

Cosa sono DeepLabV3+, SegFormer, SAM e PointRend?

DeepLabV3+: ottimo per multi-scale context e contorni precisi, pesante per il real-time. SegFormer: alta accuratezza e generalizzazione, richiede GPU potenti. SAM: segmenta qualsiasi oggetto senza retraining, non ottimizzato sui dataset classici (versatilità). PointRend: ottimo per immagini ad alta risoluzione e video, più complesso da integrare.