Valutazione di descrittori per il rilevamento automatico di nuclei cellulari in immagini di...

122
Anno Accademico 2011-2012 UNIVERSITÀ DEGLI STUDI DI TRIESTE FACOLTÀ DI INGEGNERIA CORSO DI LAUREA SPECIALISTICA IN INGEGNERIA INFORMATICA Tesi di laurea "VALUTAZIONE DI DESCRITTORI PER IL RILEVAMENTO AUTOMATICO DI NUCLEI CELLULARI IN IMMAGINI DI MICROSCOPIA A FLUORESCENZA" Laureando: Relatore: Paolo Fabris Felice Andrea Pellegrino Correlatore: Walter Vanzella

Transcript of Valutazione di descrittori per il rilevamento automatico di nuclei cellulari in immagini di...

Anno Accademico 2011-2012

UNIVERSITÀ DEGLI STUDI DI TRIESTE

FACOLTÀ DI INGEGNERIA

CORSO DI LAUREA SPECIALISTICA IN INGEGNERIA INFORMATICA

Tesi di laurea

"VALUTAZIONE DI DESCRITTORI PER IL RILEVAMENTO

AUTOMATICO DI NUCLEI CELLULARI IN IMMAGINI DI

MICROSCOPIA A FLUORESCENZA"

Laureando: Relatore:

Paolo Fabris Felice Andrea Pellegrino

Correlatore:

Walter Vanzella

2 Sommario

Ai miei amici,

a tutti coloro che mi vogliono bene

a tutti quelli che mi hanno supportato per tutto questo tempo

ai miei carissimi genitori che mi sono sempre stati vicino

3 Sommario

Sommario SOMMARIO ..................................................................................................................................................... 3

INDICE DELLE FIGURE ....................................................................................................................................... 7

RINGRAZIAMENTI ............................................................................................................................................ 9

1. INTRODUZIONE .................................................................................................................................... 10

1.1. OBBIETTIVI DEL PROGETTO ....................................................................................................................... 10

1.2. L’ALGORITMO ........................................................................................................................................ 11

1.3. MICROSCOPIA A FLUORESCENZA ................................................................................................................ 11

2. REGIONI D’INTERESSE ........................................................................................................................... 14

2.1. INTRODUZIONE....................................................................................................................................... 14

2.2. NORMALIZZAZIONE DELLE IMMAGINI .......................................................................................................... 14

2.3. ESTRAZIONE DEI PUNTI D’INTERESSE ........................................................................................................... 18

2.4. RICERCA DEI PARAMETRI PER IL FILTRO DOG ................................................................................................ 28

2.5. ESTRAZIONE DELLE REGIONI D’INTERESSE ..................................................................................................... 29

2.6. ASSEGNAZIONE DELLE ROI ALLA CLASSE DI APPARTENENZA ............................................................................. 33

3. FEATURE ............................................................................................................................................... 34

3.1. INTRODUZIONE....................................................................................................................................... 34

3.2. PROPRIETÀ DELLE FEATURE ....................................................................................................................... 34

3.3. SHAPEINTENSITY..................................................................................................................................... 37

3.4. ZERNIKE ................................................................................................................................................ 39

3.5. TRASFORMATA DI FOURIER-MELLIN, AFMT, DAFMT E FAFMT .................................................................... 42

3.6. TRASFORMATA DCT................................................................................................................................ 46

4. MACCHINA A VETTORI DI SUPPORTO ................................................................................................... 48

4.1. INTRODUZIONE....................................................................................................................................... 48

4.2. LA MACCHINA ........................................................................................................................................ 48

4.2.1. Classificatore lineare su dati linearmente separabili .................................................................... 50

4.2.2. Classificatore lineare su dati non linearmente separabili ............................................................. 53

4 Sommario

4.2.3. Classificatore non lineare .............................................................................................................. 54

4.2.4. Cross-validation ............................................................................................................................ 55

5. RECEIVER OPERATING CHARACTERISTIC ............................................................................................... 57

5.1. INTRODUZIONE....................................................................................................................................... 57

5.2. SPAZIO ROC .......................................................................................................................................... 57

5.3. GENERAZIONE EFFICIENTE DEI PUNTI DI UNA CURVA ROC ............................................................................... 60

5.4. AUC .................................................................................................................................................... 62

6. NVIDIA CUDA, ARCHITETTURA E MODELLO DI PROGRAMMAZIONE ..................................................... 63

6.1. INTRODUZIONE....................................................................................................................................... 63

6.2. GPU COME COMPUTER PARALLELO ............................................................................................................ 65

6.3. ARCHITETTURA NVIDIA FERMI GF110 ...................................................................................................... 69

6.3.1. Host Interface ............................................................................................................................... 70

6.3.2. Memory Controller ........................................................................................................................ 70

6.3.3. Gerarchia memoria ....................................................................................................................... 71

6.3.4. GDDR5 ........................................................................................................................................... 72

6.3.5. GigaThread Engine ........................................................................................................................ 72

6.3.6. Streaming Multiprocessor ............................................................................................................. 73

6.3.7. Instruction cache ........................................................................................................................... 74

6.3.8. Dual warp scheduler e dispatch unit ............................................................................................. 74

6.3.9. Register file ................................................................................................................................... 76

6.3.10. LD/ST ........................................................................................................................................ 76

6.3.11. SFU ........................................................................................................................................... 76

6.3.12. Texture Unit ............................................................................................................................. 76

6.3.13. CUDA Core ................................................................................................................................ 77

6.4. INTERFACCIA CUDA ................................................................................................................................ 79

6.4.1. Architettura ................................................................................................................................... 79

6.4.2. SIMT .............................................................................................................................................. 82

6.4.3. Organizzazione thread .................................................................................................................. 82

6.4.4. Organizzazione della memoria ..................................................................................................... 84

5 Sommario

6.5. LIBRERIE ............................................................................................................................................... 85

6.6. VELOCITÀ DI ELABORAZIONE...................................................................................................................... 86

7. BENCHMARK ........................................................................................................................................ 87

7.1. INTRODUZIONE....................................................................................................................................... 87

7.2. HARDWARE E SOFTWARE IMPIEGATI ........................................................................................................... 88

7.3. VALUTAZIONE DELLE CLASSIFICAZIONI MANUALI EFFETTUATE DAGLI ESPERTI ........................................................ 90

7.4. VALUTAZIONE DEI PARAMETRI DELLA DOG .................................................................................................. 91

7.5. VALUTAZIONE DELLE PRESTAZIONI IN FASE DI ADDESTRAMENTO ....................................................................... 92

7.6. VALUTAZIONE DELLE PRESTAZIONI IN CLASSIFICAZIONE ................................................................................... 98

7.7. VALUTAZIONE DELLA VELOCITÀ DI ELABORAZIONE .......................................................................................... 99

8. CONCLUSIONI ..................................................................................................................................... 101

BIBLIOGRAFIA .............................................................................................................................................. 104

APPENDICE A ............................................................................................................................................... 105

A.1. DIRECTX 11 SU HARDWARE DIRECTX 10 E DIRECTX 9.0C .................................................................................... 105

A.1. SHADER MODEL 5 ........................................................................................................................................ 105

A.2. VERTEX E INDEX BUFFER ................................................................................................................................ 106

A.3. PRIMITIVE .................................................................................................................................................. 106

A.4. INPUT ASSEMBLER ........................................................................................................................................ 108

A.4. RASTERIZATION ........................................................................................................................................... 108

A.5. PIPELINE GRAFICA DIRECTX 11 ....................................................................................................................... 108

A.5.1. Architettura shader model unificata ............................................................................................... 108

A.5.2. Tessellation ..................................................................................................................................... 109

A.5.3. Schema logico della pipeline grafica DirectX 11 ............................................................................. 112

A.6. SPAZI IN UNA SCENA 3D ................................................................................................................................ 115

A.6.1. OBJECT E WORLD SPACE ............................................................................................................................. 115

A.6.2. VIEW E CLIP SPACE .................................................................................................................................... 116

A.6.3. SCREEN SPACE E HSR ................................................................................................................................ 117

A.7. NVIDIA APPROFONDIMENTI .......................................................................................................................... 118

A.7.1. ROP ................................................................................................................................................. 118

A.7.2. Tessellation ..................................................................................................................................... 118

6 Sommario

A.7.3 CUDA ................................................................................................................................................ 119

APPENDICE B ............................................................................................................................................... 121

B.1. SVILUPPARE MEX IN VISUAL STUDIO 2010 PROFESSIONAL ................................................................................... 121

B.2. SVILUPPARE CUDA KERNEL IN VISUAL STUDIO 2010 PROFESSIONAL ..................................................................... 121

APPENDICE C ............................................................................................................................................... 122

C.1. LIBSVM ...................................................................................................................................................... 122

7 Indice delle figure

Indice delle figure FIGURA 1 IMMAGINE CAMPIONE DI MICROSCOPIA A FLUORESCENZA .................................................................................... 12

FIGURA 2 CLASSIFICAZIONE MANUALE DA PARTE DI UN ESPERTO ......................................................................................... 13

FIGURA 3 ZOOM IN UNA REGIONE CLASSIFICATA MANUALMENTE DA UN ESPERTO ................................................................... 13

FIGURA 4 IMMAGINE NORMALIZZATA ............................................................................................................................ 14

FIGURA 5 RAPPRESENTAZIONE A COLORI ........................................................................................................................ 15

FIGURA 6 VARIAZIONE DI LUMINOSITÀ A COLORI .............................................................................................................. 15

FIGURA 7 IMMAGINE FLATTED ...................................................................................................................................... 16

FIGURA 8 NORMALIZZAZIONE CHE SFRUTTA LA MEDIANA SU IMMAGINE CON LUMINOSITÀ UNIFORME ........................................ 17

FIGURA 9 FUNZIONE GAUSSIANA MONODIMENSIONALE CON MEDIA NULLA ........................................................................... 19

FIGURA 10 FUNZIONE GAUSSIANA BIDIMENSIONALE CENTRATA .......................................................................................... 20

FIGURA 11 FILTRAGGIO DOG ...................................................................................................................................... 21

FIGURA 12 RICERCA DEI MASSIMI LOCALI ....................................................................................................................... 22

FIGURA 13 SOGLIATURA DI OTSU E RIDLER CALVARD........................................................................................................ 25

FIGURA 14 SOGLIATURA DI OTSU E DI RIDLER CALVARD SU DOG ........................................................................................ 26

FIGURA 15 CORREZIONE NELLA GENERAZIONE DEI PUNTI D’INTERESSE IN CONDIZIONI NON OTTIMALI ......................................... 28

FIGURA 16 IMMAGINE BINARIA DALLA DOG ................................................................................................................... 29

FIGURA 17 FILTRAGGIO DOG AL NEGATIVO CON IMPOSTAZIONE DEI PUNTI D'INTERESSE A ZERO ............................................... 30

FIGURA 18 BACINI WATERSHED .................................................................................................................................... 31

FIGURA 19 BLOB GENERATI DAI BACINI WATERSHED ......................................................................................................... 31

FIGURA 20 BLOB CHE CONTENGONO UN PUNTO D’INTERESSE ............................................................................................. 32

FIGURA 21 ESTRAZIONE ROI CON TRASLAZIONE DEL CENTRO DI MASSA ................................................................................ 32

FIGURA 22 FILTRAGGIO DELLA ROI CON FUNZIONE SIGMOIDALE ......................................................................................... 33

FIGURA 23 PIANO CARTESIANO .................................................................................................................................... 36

FIGURA 25 RICOSTRUZIONI DELLA ROI CON DIVERSI GRADI PER ZERNIKE .............................................................................. 41

FIGURA 26 CAMPIONAMENTO CON COORDINATE POLARI .................................................................................................. 44

FIGURA 27 CAMPIONAMENTO CON COORDINATE LOG-POLAR ............................................................................................. 45

FIGURA 28 ENERGIA DELLA DCT .................................................................................................................................. 47

FIGURA 29 RICOSTRUZIONE DI UNA ROI DAI COEFFICIENTI DCT ......................................................................................... 47

FIGURA 30 CLASSIFICATORE LINEARE ............................................................................................................................. 50

FIGURA 31 DIFFERENZA FRA MARGINI SVM ................................................................................................................... 51

FIGURA 32 DATI NON LINEARMENTE SEPARABILI .............................................................................................................. 53

FIGURA 33 SPAIO D’INPUT E DELLE FEATURE ................................................................................................................... 54

FIGURA 34 CUT-OFF .................................................................................................................................................. 58

FIGURA 35 GENERAZIONE ROC ................................................................................................................................... 61

FIGURA 36 GPU VS CPU FLOATING-POINT ..................................................................................................................... 66

FIGURA 37 GPU VS CPU BANDA DI MEMORIA ................................................................................................................ 67

FIGURA 38 ARCHITETTURA GF110 ............................................................................................................................... 69

FIGURA 39 GERARCHIA MEMORIA ................................................................................................................................ 71

FIGURA 40 CACHE L2 UNIFICATA .................................................................................................................................. 72

FIGURA 41 STREAMING PROCESSOR .............................................................................................................................. 73

FIGURA 42 ESECUZIONE KERNEL SU G80/GT200 E GF110 .............................................................................................. 74

FIGURA 43 GESTIONE THREAD NELLE ARCHITETTURE CUDA............................................................................................... 75

8 Indice delle figure

FIGURA 44 OPS PER CLOCK PER LE ISTRUZIONI ESEGUIBILI DA UNO SM ................................................................................. 75

FIGURA 45 DISTRIBUZIONE DELLE ISTRUZIONI ALL'INTERNO DI UNO SM ................................................................................ 76

FIGURA 46 CUDA CORE ............................................................................................................................................. 77

FIGURA 47 FMA VS MAD .......................................................................................................................................... 78

FIGURA 48 ARCHITETTURA MODELLO DI PROGRAMMAZIONE CUDA .................................................................................... 79

FIGURA 49 CAPACITÀ DI CALCOLO CUDA ....................................................................................................................... 81

FIGURA 50 COMPUTE CAPABILITY FEATURE CUDA........................................................................................................... 81

FIGURA 51 BLOCCHI DI THREAD .................................................................................................................................... 83

FIGURA 52 GERARCHIA MEMORIA ................................................................................................................................ 84

FIGURA 53 CALIBRATURA DOG ................................................................................................................................... 92

FIGURA 54 PERCENTUALE DI REGIONI D'INTERESSE SCARTATE NELLA FASE DI ADDESTRAMENTO DELLA MACCHINA A VETTORI DI

SUPPORTO ....................................................................................................................................................... 93

FIGURA 55 NUMERO DI COEFFICIENTI SELEZIONATI PER LA DCT .......................................................................................... 93

FIGURA 56 KERNEL POLINOMIALE ................................................................................................................................. 94

FIGURA 57 CURVA ROC KERNEL POLINOMIALE CON SHAPEINTENSITY .................................................................................. 95

FIGURA 58 KERNEL RBF ............................................................................................................................................. 95

FIGURA 59 CURVA ROC PER KERNEL RBF CON FEATURE FAFMT ....................................................................................... 96

FIGURA 60 KERNEL SIGMOIDALE ................................................................................................................................... 97

FIGURA 61 CURVA ROC PER KERNEL SIGMOIDALE CON SHAPEINTENSITY .............................................................................. 97

FIGURA 62 MIGLIORI FEATURE E KERNEL ........................................................................................................................ 98

FIGURA 63 VALUTAZIONE DEL CONTEGGIO ..................................................................................................................... 98

FIGURA 64 INCREMENTO PRESTAZIONALE SU GPU ......................................................................................................... 100

FIGURA 65 QUADRATO INDICIZZATO ........................................................................................................................... 106

FIGURA 66 VERTEX INDEX BUFFER .............................................................................................................................. 106

FIGURA 67 PRIMITIVE .............................................................................................................................................. 107

FIGURA 68 PRIMITIVA PATCH ..................................................................................................................................... 107

FIGURA 69 PIPELINE GRAFICA DIRECTX 9.0C ................................................................................................................ 108

FIGURA 70 WORKLOAD DEGLI SHADER DEDICATI ............................................................................................................ 108

FIGURA 71 PIPELINE GRAFICA DIRECTX 10 ................................................................................................................... 109

FIGURA 72 PATCH PER LA TESSELLATOR UNIT ................................................................................................................ 110

FIGURA 73 TESSELLATION REGOLARE ........................................................................................................................... 111

FIGURA 74 TESSELLATION SEMI-REGOLARE ................................................................................................................... 111

FIGURA 75 FIGURA INIZIALE PER L'EDGE FACTOR DELLA TESSELLATION ................................................................................ 111

FIGURA 76 RISULTATO DELL'EDGE FACTOR PER LA TESSELLATION ....................................................................................... 111

FIGURA 77 PIPELINE GRAFICA DIRECTX 11 ................................................................................................................... 112

FIGURA 78 SCHEMA A BLOCCHI INPUT ASSEMBLER, VERTEX SHADER, HULL SHADER, TESSELLATOR ......................................... 113

FIGURA 79 SECONDO PARTE DELLA PIPELINE GPU CON TESSELLATOR ................................................................................. 114

FIGURA 80 SPAZI IN UNA SCENA 3D ............................................................................................................................ 115

FIGURA 81 COORDINATE NEL WORLD SPACE ................................................................................................................. 116

FIGURA 82 VIEW FRUSTRUM ..................................................................................................................................... 116

FIGURA 83 PROIEZIONE DEGLI OGGETTI DAL CLIPPING SPACE AL CUBO ................................................................................ 117

FIGURA 84 POLYMORPH ENGINE ............................................................................................................................... 118

FIGURA 85 RASTER ENGINE ....................................................................................................................................... 119

9 Ringraziamenti

Ringraziamenti Uno speciale ringraziamento ad Felice Andrea Pellegrino e Walter Vanzella che mi hanno

consigliato e guidato durante il periodo di tirocinio e tesi presso la Glance Vision

Technologies Srl; mi hanno fatto apprezzare il ramo informatico dedicato all’image

processing.

Un grande grazie a Jack.

Ultimo, ma non per questo meno importante, un sentito ringraziamento agli amici e ai

parenti che mi hanno dato sostegno quando ne ho avuto bisogno.

10 Introduzione

1. Introduzione

1.1. Obbiettivi del progetto

Il progetto di questa tesi è stato sviluppato presso la Glance Vision Technologies Srl

http://www.gvt.it/; questo lavoro deriva dall’osservazione che presso la SISSA (Scuola

Internazionale Superiore Di Studi Avanzati di Trieste) gli esperti di classificazione cellulare

svolgevano in modo manuale la ricerca dei nuclei di neuroni in immagini di microscopia a

fluorescenza. L’obbiettivo che ci si prefigge è quello di automatizzare tale analisi con

conseguente raggiungimento dei seguenti benefici:

Riduzione del tempo richiesto per portare a termine le indagini;

L’esperto può concentrarsi esclusivamente sull’analisi dei risultati forniti

dall’algoritmo senza dover selezionare manualmente le regioni d’interesse valide (i

set d’immagini possono avere da 500 a 5000 regioni d’interesse valide);

L’algoritmo genera automaticamente le regioni d’interesse classificate che possono

essere usate successivamente per eseguire altre analisi (tipicamente in ambito

statistico);

Oggettività dei criteri e la conseguente ripetibilità dei risultati che non dipende da chi

svolge l’analisi.

Tutte le immagini da esaminare sono ottenute tramite la microscopia a fluorescenza che

riveste un ruolo fondamentale nell’analisi di culture cellulari. Infatti, è in grado di mettere in

risalto aspetti salienti delle cellule come la localizzazione di DNA, RNA, mitocondri e nuclei.

Le analisi di questo tipo d’immagini sono fondamentali per studiare patologie, verificare

l’evoluzione nel tempo di una malattia, analisi statistiche sulla popolazione cellulare ecc.

La strategia di fondo seguita nell’algoritmo è:

Eseguire un’analisi preliminare delle immagini per eliminare l’illuminazione non

uniforme;

Individuare le regioni d’interesse (ROI);

Rappresentare ogni ROI con opportuni descrittori (detti feature);

Usare un algoritmo d’apprendimento per affrontare il problema di

addestramento/classificazione delle ROI (rappresentate dalle corrispondenti

feature).

Nei seguenti capitoli si affrontano diverse tematiche che riguardano la classificazione binaria

delle ROI, in particolare:

Nel secondo capitolo si descrive la procedura seguita per rendere le immagini più

robuste alla luminosità non uniforme la quale può compromettere le prestazioni

11 Introduzione

dell’algoritmo in addestramento/classificazione. Successivamente si descrive

l’approccio seguito per l’estrazione delle regioni d’interesse;

Il terzo è dedicato alla rappresentazione delle ROI tramite opportuni descrittori detti

feature e si descrivono le tecniche per garantire l’invarianza per rotazione, invarianza

per traslazione e varianza per scala;

Il quarto descrive l’algoritmo d’apprendimento ossia la macchina a vettori di

supporto;

Nel quinto capitolo si presenta la descrizione delle curve ROC (Receiver Operating

Characteristic) per la caratterizzazione statistica dei risultati in classificazione binaria.

La scelta dei parametri dell’algoritmo e la valutazione delle prestazioni del medesimo

sono effettuate in base all’analisi delle curve ROC;

Il sesto tratta l’architettura NVIDIA CUDA impiegata per accelerare alcune

elaborazioni su GPU;

Il settimo presenta i risultati ottenuti;

L’ottavo riguarda le conclusioni;

Infine, l’appendice A descrive argomenti supplementari riguardanti l’elaborazione su

GPU, B illustra quali sono i passi da seguire per sviluppare in Visual Studio 2010 le

mex e i CUDA Kernel, C descrive i parametri della libreria libsvm.

1.2. L’algoritmo

Per sviluppare l’algoritmo si è scelto di usare l’ambiente MATLAB dato che mette a

disposizione una serie di strumenti che semplificano l’implementazione e quindi riducono il

tempo di sviluppo; il linguaggio MATLAB è interpretato e questo comporta lo svantaggio che

la velocità di elaborazione non è elevata. Per superare parzialmente questo inconveniente,

che influenza notevolmente il tempo totale di elaborazione, si è deciso di riscrivere una

parte della macchina a vettori di supporto con OpenMP in C/C++ (accelera l’elaborazione su

CPU multicore) e una parte degli script MATLAB in CUDA C sfruttando la programmazione

ibrida (CPU/GPU). E’ importante osservare che il wrapping fatto tramite le mex per eseguire

l’elaborazione in CUDA introduce overhead non eliminabile; in particolare la velocità di

trasferimento dei dati tra CPU e GPU è dimezzata rispetto a quanto sarebbe stato possibile

ottenere dato che le variabili nello spazio di lavoro MATLAB non sono memorizzate nella

pinned memory. Le mex sono funzioni richiamabile dall’ambiente MATLAB sviluppate in

linguaggio C/C++.

L’intero algoritmo è strutturato in modo che l’utente debba inserire solo un numero ridotto

di parametri.

1.3. Microscopia a fluorescenza

L’intero lavoro si basa sull’elaborazione d’immagini di microscopia a fluorescenza; queste

sono ottenute impiegando un microscopio a fluorescenza tipicamente usato nei laboratori

di biologia per analizzare campioni organici sfruttando i fenomeni della fluorescenza e

12 Introduzione

fosforescenza. D’ora in poi si considera soltanto il caso in cui si vogliono evidenziare i nuclei

cellulari di neuroni che è la situazione trattata in questo progetto.

Le procedure per ottenere le immagini consistono nel marcare i campioni d’interesse con

molecole fluorescenti, ossia il fluorocromo, e successivamente il tutto è illuminato con un

fascio di luce a una specifica lunghezza d’onda; il fascio luminoso è assorbito dal

fluorocromo che provoca l’emissione di luce a lunghezza d’onda maggiore e questo

permette di generare un colore diverso da quello della luce assorbita. Tramite un filtro si

separano i due tipi di luce e si considera soltanto quella generata dal fluorocromo; una tipica

immagine ottenuta con questa tecnica è riportata di seguito.

Figura 1 Immagine campione di microscopia a fluorescenza

Su immagini come quella di sopra, gli esperti di classificazione eseguono delle analisi per

separare i nuclei delle cellule da altri corpi estranei; di seguito si riporta una tipica

classificazione manuale.

13 Introduzione

Figura 2 Classificazione manuale da parte di un esperto

Figura 3 Zoom in una regione classificata manualmente da un esperto

I punti d’interesse inseriti dall’esperto marcano le regioni d’interesse valide, le ROI non

segnate sono da considerarsi come non valide.

14 Regioni d’interesse

2. Regioni d’interesse

2.1. Introduzione

L’estrazione delle regioni d’interesse presenti in un’immagine è il primo problema da

affrontare; le regioni d’interesse (ROI) sono porzioni rilevanti dell’immagine che possono

contenere i nuclei cellulari da identificare. Lo scopo è di generare una ROI per ogni oggetto

che può rappresentare un nucleo cellulare.

2.2. Normalizzazione delle immagini

Prima di poter elaborare un’immagine di microscopia a fluorescenza è necessario eseguire

una normalizzazione della stessa per renderla visibile a un operatore umano e al tempo

stesso ridurre l’influenza della variazione di luminosità che può compromettere l’estrazione

delle regioni d’interesse.

La luminosità non uniforme ha i seguenti effetti indesiderati:

C’è la possibilità che una porzione dello sfondo sia estratta come ROI quando in

realtà questa non dà alcun contributo informativo per individuare i nuclei delle

cellule;

Compromette la reale distribuzione dell’intensità del potenziale nucleo.

Il primo passo quindi consiste nell’eseguire la normalizzazione dell’immagine da elaborare

tra zero e uno. Il risultato è riportato in figura.

Figura 4 Immagine normalizzata

Dall’immagine in tonalità di grigio non si riesce ad apprezzare completamente la variazione

di luminosità; se si usa una rappresentazione in cui l’intensità segue il seguente schema di

colori (dove l’intensità più bassa è posta a sinistra e quella più alta a destra)

15 Regioni d’interesse

Figura 5 Rappresentazione a colori

si ottiene

Figura 6 Variazione di luminosità a colori

Da questa è possibile notare che la luminosità non è uniforme nell’immagine ed ha la

tendenza a essere più intensa nell’angolo in basso a destra. Per rendere l’immagine a

luminosità uniforme si dovrebbe avere a disposizione un’immagine con solo sfondo

(ottenuta nelle stesse condizioni di quella da analizzare) e combinarla con quella avente le

cellule tramite la seguente formula

dove è l’immagine con le cellule, è l’immagine con solo sfondo (chiamata

anche immagine flatted) e è l’immagine con luminosità uniforme. Il problema è che

non è disponibile direttamente e quindi è necessario ricavarla dall’immagine iniziale

estraendo solo lo sfondo; per fare questo si è deciso di sfruttare un filtro che fa la media

dato che è semplice da implementare e se la finestra di applicazione del filtro non è troppo

ampia si eseguono i calcoli velocemente. Si è scelta come dimensione della finestra di

filtraggio una abbastanza ampia da cancellare le cellule dall’immagine e allo stesso tempo

abbastanza ridotta da fare i calcoli velocemente; il risultato dell’estrazione dell’immagine

da nell’esempio considerato è

16 Regioni d’interesse

Figura 7 Immagine flatted

Da questa si nota in dettaglio la distribuzione della luminosità. Da osservare che prima

dell’applicazione del filtro si applica del padding verticale e orizzontale in modo da evitare in

prossimità dei bordi dell’immagine che la media sia fatta con dei pixel zero (che stanno fuori

dai bordi); successivamente si esegue un ritaglio in modo da estrarre la parte senza padding.

A questo punto si ha a disposizione un’immagine con distribuzione uniforme della

luminosità; si può inoltre notare che in tutte le immagini a disposizione, il 50% + 1 dei pixel è

sfondo, quindi è possibile sfruttare la mediana per cancellare quasi completamente il

rumore presente sullo sfondo con le seguenti operazioni eseguite in sequenza:

dove è la mediana di e è l’immagine normalizzata a luminosità

uniforme dopo la sottrazione con la mediana.

Il risultato finale è riportato di seguito, da cui si può notare che l’effetto della luminosità è

stato completamente cancellato.

17 Regioni d’interesse

Figura 8 Normalizzazione che sfrutta la mediana su immagine con luminosità uniforme

Con questa procedura si ha che le immagini sono sempre rappresentate tra zero e uno e i

pixel risentono meno l’influenza della luminosità non uniforme che può essere diversa tra le

immagini; in questo modo le ROI e quindi le feature possono essere calcolate in condizioni

pressoché identiche tra un’immagine e l’altra.

Altra osservazione da fare è che nelle immagini spesso si presenta la situazione in cui alcuni

blob, gli agglomerati di pixel che formano un oggetto da analizzare, sono a contatto con i

bordi dell’immagine e risultano “tagliati”; per evitare di compromettere il comportamento

dell’algoritmo d’apprendimento si è deciso di non considerare i blob vicini ai bordi, il che è

anche una strategia tipica utilizzata nella classificazione manuale delle cellule.

18 Regioni d’interesse

2.3. Estrazione dei punti d’interesse

Dopo aver normalizzato l’immagine e aver eliminato gli effetti della luminosità non uniforme

è necessario procedere all’individuazione delle regioni d’interesse; si può notare che gli

oggetti presenti nelle immagini sono per lo più ovali e tipicamente l’intensità è concentrata

al centro dei medesimi, per questo motivo si è fatta la scelta di sfruttare una tecnica basata

sul Laplaciano per individuare i punti in cui si hanno le maggiori variazioni d’intensità. Da

notare che in questo modo, oltre a mettere in risalto i centri dei potenziali nuclei, si

mettono in risalto anche i bordi degli oggetti che devono essere cancellati. Una volta che i

punti d’interesse sono a disposizione, l’algoritmo li sfrutta come seme per costruire le

regioni d’interesse.

Di solito nell’ambito dell’image processing, per applicare il Laplaciano a un’immagine, si usa

una delle due seguenti tecniche:

LOG (Laplacian of Gaussian);

DOG (Difference of Gaussian).

La tecnica impiegata per applicare il laplaciano in questo lavoro si basa sulla DOG dato che

dal punto di vista computazionale è più veloce e semplice da implementare rispetto alla LOG

di cui è una buona approssimazione. Come si vedrà successivamente, entrambe le tecniche

richiedono l’uso di filtri gaussiani; prima di procedere con la trattazione è necessario

descrivere quest’ultimo filtro.

Un filtro gaussiano monodimensionale con deviazione standard e media nulla si ottiene

dalla seguente funzione

Siccome questa non si annulla con in , il supporto del filtro è teoricamente

infinito. Però per valori di fuori da , la funzione può essere considerata nulla

dato che il 99.7% dell’area sottesa della gaussiana risiede nell’intervallo suddetto.

Di seguito si riporta il profilo del filtro con .

19 Regioni d’interesse

Figura 9 Funzione gaussiana monodimensionale con media nulla

Nel caso bidimensionale si ha che il kernel del filtro con deviazione standard è

dove e rappresentano le coordinate; come nel caso precedente si ha che il 99.7% del

contributo è dato per e nell’intervallo . La finestra del kernel gaussiano

bidimensionale può quindi essere approssimata tramite una finestra quadrata di dimensioni

x ; questo filtro è di tipo passa basso.

Di seguito si rappresenta la distribuzione nello spazio con e media nulla:

20 Regioni d’interesse

Figura 10 Funzione gaussiana bidimensionale centrata

Tornando al filtro LOG si ha che

dove con s’indica la funzione che rappresenta un’immagine continua, il laplaciano

e il risultato del filtraggio che si può calcolare tramite la convoluzione; poiché

l’immagine è rappresentata da un insieme discreto di pixel, è necessario individuare un

kernel che approssimi la derivata seconda nella definizione del laplaciano. Due tipici kernel

approssimati sono riportati di seguito (il primo per intorni 4-connessi e il secondo per 8-

connessi):

L’inconveniente nell’usare la convoluzione dell’immagine con uno di questi due filtri

approssimati consiste nel fatto che sono molto sensibili al rumore (alte frequenze); per

attenuarlo, si filtra l’immagine con un filtro gaussiano. L’operazione di convoluzione è

associativa, quindi è possibile costruire prima un filtro ibrido dato dalla combinazione di

quello gaussiano con quello laplaciano e successivamente convolvere questo con

l’immagine. Tutto ciò porta a due vantaggi:

Siccome i kernel del filtro gaussiano e laplaciano sono molto più piccoli

dell’immagine da considerare, questo metodo richiede poche operazioni

aritmetiche;

Si può precalcolare il kernel e quindi fare solo la convoluzione durante

l’elaborazione.

La funzione 2-D LOG centrata nello zero con deviazione standard della gaussiana è data da

Il secondo filtro che si presenta sfrutta il kernel della DOG che è dato da

21 Regioni d’interesse

dove < sono rispettivamente le deviazioni standard della prima e seconda gaussiana.

La DOG quindi consiste nel fare la differenza tra due immagini ottenute dal filtraggio

gaussiano delle medesima ma con deviazioni standard differenti; il filtro gaussiano con

deviazione standard maggiore ha un effetto di filtraggio più accentuato.

I vantaggi del filtraggio DOG su quello di tipo LOG sono:

Semplicità d’implementazione;

Velocità di computazione maggiore (il kernel del filtro gaussiano 2D è separabile,

quindi il kernel della DOG può essere calcolato come il contributo di due kernel

gaussiani separabili);

Buona approssimazione della LOG con

.

Per i vantaggi elencati, si è deciso di impiegare il filtro DOG in luogo di LOG.

L’algoritmo, una volta a disposizione l’immagine normalizzata con luminosità non uniforme

cancellata, applica la DOG; a questo punto si passa alla ricerca dei massimi locali. Si

riportano il risultato del filtraggio e relativa ricerca dei massimi.

Figura 11 Filtraggio DOG

22 Regioni d’interesse

Figura 12 Ricerca dei massimi locali

Si può notare che in questo caso ci sono tanti punti d’interesse vicini generati in

corrispondenza delle zone poche “stabili”, cioè lì dove ci sono delle continue variazioni

d’intensità (anche se d’entità molto ridotta) causa rumore residuo. Siccome ci sono delle

zone in cui i punti d’interesse sono molto vicini fra loro (le aree nere), queste vanno a

compromettere l’estrazione delle ROI (si rischia di generare tantissime ROI vuote causa il

filtraggio circolare che sarà descritto durante la fase di estrazione delle medesime) oltre che

a ridurre di molto la velocità di elaborazione complessiva delle successive fasi. Per evitare

questi effetti indesiderati si può quindi applicare all’immagine filtrata con la DOG una

sogliatura globale in modo da cancellare queste zone. Per sogliatura globale s’intende

l’individuazione di un valore d’intensità in modo tale che tutti i pixel sotto a questo siano

considerati sfondo (e quindi è possibile porli a zero). Esistono diverse tecniche di sogliatura

in letteratura, molte delle quali si basano sull’analisi dell’istogramma di un’immagine; i

vantaggi principali di questi approcci consistono nella semplicità d’implementazione

dell’algoritmo ed efficienza computazionale. Ci sono però degli svantaggi da tenere in

considerazione che sono dovuti al fatto che il valore di soglia dipende da:

Distanza tra i picchi nell’istogramma;

Rumore nell’immagine;

Dimensione dei blob rispetto allo sfondo;

Luminosità nell’immagine.

Da notare che queste dipendenze sono notevolmente ridotte in questa fase di ricerca dei

massimi locali, infatti:

Il rumore è ridotto notevolmente grazie all’impiego del filtraggio DOG (che funge da

filtro passa banda);

23 Regioni d’interesse

Gli effetti della luminosità non uniforme sono stati eliminati durante la

normalizzazione dell’immagine;

Il 50% + 1 dei pixel sono sfondo quindi nell’istogramma è garantito che ci siano due

picchi distanti (uno relativo allo sfondo e uno all’intensità delle cellule che in questa

fase, dopo il filtraggio con DOG, hanno intensità pressoché identica e uniforme).

Da tutto ciò si deduce che la sogliatura globale in questo contesto è un buon approccio per

ridurre la generazione di punti d’interesse indesiderati.

Ci sono molti ricercatori nell’ambito dell’elaborazione digitale d’immagini ad aver proposto

diverse procedure per eseguire la sogliatura, una delle più usate prende il nome di

sogliatura di Otsu.

La sogliatura di Otsu si basa sul metodo del discriminante; i pixel dell’immagine sono

associati a due classi differenti: e ; dove

rappresenta il livello di sogliatura, valore in tonalità di grigio e il numero di livelli di grigio

nell’immagine considerata. L’algoritmo valuta le varianze delle due classi e quella totale, la

soglia ottima è scelta massimizzando la varianza inter-classe. Per utilizzare questa tecnica in

modo efficiente è necessario che sia soddisfatta l’ipotesi in cui l’istogramma contiene due

mode dominanti; in questo caso il valore di soglia è quello che separa le due mode.

Si consideri un’immagine di dimensioni con livelli d’intensità in tonalità di grigio e

con il numero totale di pixel di livello i-esimo, allora l’istogramma normalizzato ha come

componenti

Si seleziona una soglia con e si definiscono due classi:

con tutti i pixel d’intensità tra e ;

con tutti i pixel d’intensità tra e .

La probabilità di assegnamento di un pixel alla classe è pari a

mentre per la classe

Il valore medio d’intensità dei pixel che appartengono a è

24 Regioni d’interesse

invece per la classe

La media cumulativa di livello k è pari a

mentre la media sull’immagine è

Per valutare la bontà della soglia si sfrutta la seguente formula

dove rappresenta la varianza globale dei pixel dell’immagine

e la varianza inter-classe

Più distanti sono le due medie e più la varianza inter-classe è elevata, la soglia è quella

che massimizza questa varianza; si ha

L’inconveniente di questo sogliatura è che ha la tendenza a generare una soglia troppo

aggressiva, nel senso che la soglia è in genere troppo alta in questo contesto e ciò comporta

la cancellazione di pixel che invece potrebbero dare un contributo informativo per la

generazione di punti d’interesse in prossimità di oggetti che potrebbero essere nuclei

cellulari. Per risolvere questo inconveniente è possibile usare un’altra sogliatura globale

ossia quella proposta da Ridler e Calvard che permette di calcolare un valore di soglia più

25 Regioni d’interesse

conservativo e quindi di considerare più blob. Questa procedura sfrutta il metodo di Otsu

per calcolare una soglia iniziale e successivamente in modo iterativo individua la media

sopra e sotto tale soglia; la nuova soglia è individuata come la media delle due medie

calcolate precedentemente. Il procedimento continua fino a quando la differenza tra la

nuova soglia e quella al passo precedente è inferiore a un valore prestabilito.

Di seguito si riporta il confronto tra i risultati della ricerca dei massimi locali dopo

l’applicazione della soglia di Otsu e Ridler Calvard.

Figura 13 Sogliatura di Otsu e Ridler Calvard

26 Regioni d’interesse

Figura 14 Sogliatura di Otsu e di Ridler Calvard su DOG

Da sopra si nota che conviene sfruttare la procedura di Ridler Calvard che garantisce una

soglia più conservativa rispetto a quella di Otsu e ciò comporta in genere risultati più

accurati, anche se questo ha l’inconveniente di non cancellare tutte le regioni indesiderate

afflitte da rumore. Da notare comunque che le zone affette da rumore non cancellate dopo

la sogliatura di Ridler Calvard sono in genere molto poche e quindi non compromettono la

ricerca dei nuclei cellulari infatti:

Molto probabilmente le regioni indesiderate saranno cancellate dall’algoritmo

durante la fase di estrazione delle ROI per garantire l’invarianza per rotazione (come

sarà chiarito in seguito);

27 Regioni d’interesse

Nel caso in cui le regioni indesiderate non fossero scartate dopo l’estrazione delle

ROI, queste sarebbero comunque marcate come non valide durante l’addestramento

della macchina a vettori di supporto senza compromettere la ricerca dei nuclei

cellulari.

Per ottenere i punti d’interesse correttamente è necessario impostare opportunamente i

parametri della DOG; questi parametri sono fissi per ogni immagine, quello che può

accadere è che questi non vanno bene in certe situazioni e si può avere uno dei seguenti

scenari:

I punti d’interesse generati sono troppo pochi;

I punti d’interesse generati sono molti e sono troppo vicini fra loro (se sono troppo

vicini, allora questo può compromettere l’estrazione delle ROI perché rischiano di

essere vuote).

Per il primo caso, l’unico modo per risolvere il problema è di impostare altri valori per i

parametri della DOG in modo da aumentare il numero di punti d’interesse; questo non è

attuabile perché non è possibile sapere a priori quali siano i parametri ottimali senza aver a

disposizione la classificazione fatta da un esperto (non si può sfruttare una procedura

automatizzata). Per il secondo problema si è scelto di usare un algoritmo in grado di

localizzare le situazioni in cui i punti d’interesse sono troppo vicini; i parametri da impostare

sono raggio massimo e minimo che un intorno associato a un punto d’interesse può avere:

1) Si associa a ogni punto d’interesse un intorno il cui raggio è la metà della distanza dal

punto d’interesse più vicino, se viene superato il raggio massima allora è impostato a

quest’ultimo valore;

2) Per tutti gli intorni con raggio inferiore a quello minimo consentito, si procede come

di seguito:

a. Si seleziona l’intorno con raggio più piccolo e lo si marca come analizzato;

b. I punti d’interesse che distano dal centro dell’intorno selezionato di un valore

inferiore al doppio del raggio minimo consentito sono cancellati assieme ai

relativi intorni associati;

c. Si riparte da a. fino a quando tutti gli intorni sono stati analizzati.

Il raggio dell’intorno associato a ogni punto d’interesse è impiegato per rilevare la situazione

in cui i seed sono troppo vicini. Da notare che questa situazione indesiderata si verifica di

rado; questa procedura è in grado di migliorare un po’ l’estrazione delle ROI nella

condizione suddetta. Ad esempio, forzando l’algoritmo a operare con parametri che si

scostano da quelli ottimali (per simulare la situazione descritta sopra), si ottiene (a sinistra

senza l’ottimizzazione e a destra con l’algoritmo descritto):

28 Regioni d’interesse

Figura 15 Correzione nella generazione dei punti d’interesse in condizioni non ottimali

2.4. Ricerca dei parametri per il filtro DOG

Uno degli aspetti più importanti per usare correttamente la DOG riguarda l’impostazione dei

parametri del filtro DOG ossia le deviazioni standard delle due gaussiane

un’impostazione errata può compromettere drasticamente l’estrazione delle regioni

d’interesse. La procedura seguita fa riferimento a com’è stata fatta la classificazione

manuale da parte di un esperto:

1) Imposta una coppia di deviazioni standard da un insieme prestabilito in modo che

;

2) Genera i punti d’interesse per tutte le immagini classificate manualmente

dall’esperto;

3) In ogni immagine classificata manualmente dall’esperto ci sono dei marcatori che

rappresentano i centri dei nuclei, questi sono usati per costruire un intorno in modo

che il diametro massimo sia pari a quello impostato dall’utente (scelto a priori). Nel

caso di sovrapposizioni tra intorni si ha che il diametro di questi è pari alla distanza

dal centro dell’intorno più vicino (si può osservare che i nuclei sono ovali, quindi

risulta ragionevole considerare intorni di forma circolare);

4) Per ogni intorno costruito si verifica quanti punti d’interesse generati dalla DOG sono

situati all’interno di questo. Si calcolano tre quantità che saranno usate

successivamente per stabilire quali sono i parametri migliori:

a. Validi. Numero di marcatori che hanno nell’intorno un solo punto d’interesse

generato dalla DOG;

b. Sovrannumero. Numero di marcatori che hanno nell’intorno più di un punto

d’interesse;

c. Sovra raggio. Numero di marcatori che inizialmente avevano un intorno senza

punti d’interesse ma aumentando il raggio del doppio c’è almeno un punto

d’interesse nell’intorno (è ragionevole procedere in questo modo perché i

marcatori inseriti dall’esperto possono essere posizionati anche sui bordi dei

nuclei e quindi la distanza tra centro dell’intorno e punto d’interesse può

essere maggiore del raggio dell’intorno iniziale);

29 Regioni d’interesse

5) Si riparte dal passo uno fino a esaurire tutte le coppie di deviazioni standard a

disposizione.

La coppia di deviazioni standard ottima è quella che massimizza la quantità data dalla

somma dei marcatori validi con quelli in sovra raggio, questa è un indice che descrive

quanto l’algoritmo si “avvicina” nella generazione dei punti d’interesse ai marcatori

dell’esperto. Non si prende in considerazione il sovrannumero nella ricerca dei parametri

migliori perché se la DOG generasse molti punti d’interesse, allora ci sarebbero tanti

marcatori individuati per sovrannumero (quindi non è un valore discriminante nella scelta

dei parametri).

2.5. Estrazione delle regioni d’interesse

I punti d’interesse generati servono come seme per la costruzione delle regioni d’interesse

(dette ROI, Region of Interest); queste sono tutte quelle porzioni dell’immagine in analisi che

potrebbero contenere uno o più nuclei cellulari. Lo scopo è quindi di creare delle regioni che

descrivono i dettagli degli oggetti senza compromettere il contenuto informativo (bordi,

distribuzione d’intensità ecc.).

La soluzione proposta si basa sulla segmentazione dell’immagine sfruttando i punti

d’interesse generati dalla DOG e successivamente si applica un filtraggio per cancellare gli

oggetti indesiderati all’interno delle ROI; si è fatta questa scelta perché porta il notevole

vantaggio di non compromettere il contenuto informativo e di sfruttare delle tecniche

ampiamente usate e testate nell’ambito dell’image processing.

Si converte l’immagine filtrata dalla DOG in binario.

Figura 16 Immagine binaria dalla DOG

Ora è necessario calcolare il negativo dell’immagine filtrata mediante la DOG e ogni pixel

associato a un punto d’interesse si pone a valore zero. La conversione al negativo serve per

30 Regioni d’interesse

applicare la procedura watershed (descritta successivamente) e l’impostazione dei pixel a

zero in corrispondenza dei punti d’interesse serve invece a garantire che i blob che saranno

generati saranno strettamente legati ai punti d’interesse.

Figura 17 Filtraggio DOG al negativo con impostazione dei punti d'interesse a zero

A questo punto è possibile applicare la procedura watershed sull’immagine generata dal

passo precedente che è basata sul digital elevation model: i valori di un blocco di dati sono

interpretati come altitudini. Ai minimi locali si associano gli elementi dell’intorno che sono

collegati a essi da un percorso in discesa; s’individuano così i catchment basin separati da

linee chiamate watershed. Si simula il riempimento con acqua dei bacini catchment; la

crescita delle regioni nelle varie direzioni è arrestata quando più bacini si fondono. Per dare

una forma ai blob che seguono il profilo degli oggetti, è necessario moltiplicare il risultato

che si ottiene da questa procedura con l’immagine binaria calcolata in precedenza; a questo

punto si procede con l’assegnamento delle etichette ai blob ottenuti, si cancellano i blob in

prossimità dei bordi dell’immagine (dato che non devono essere considerati

nell’elaborazione) e quelli che non contengono nessun punto d’interesse.

Da notare che a ogni punto d’interesse è associato un blob grazie all’impostazione dei

relativi pixel a zero nell’immagine al negativo.

31 Regioni d’interesse

Figura 18 Bacini watershed

Figura 19 Blob generati dai bacini watershed

32 Regioni d’interesse

Figura 20 Blob che contengono un punto d’interesse

L’utente deve impostare come parametro d’ingresso dell’algoritmo il diametro massimo che

una cellula può avere; questo è usato per estrarre regioni d’interesse quadrate centrate nei

relativi punti d’interesse, la ROI ha come lunghezza dei propri lati il diametro impostato. I

blob calcolati in precedenza servono per individuare i relativi centri di massa che sono

sfruttati per traslare il blob da analizzare nel centro della ROI. Questo passo serve per

rafforzare l’invarianza per traslazione durante il calcolo delle feature che è una delle

condizioni fondamentali da garantire per rappresentare opportunamente una ROI (il

discorso è ripreso nel capitolo relativo ai descrittori delle ROI).

Figura 21 Estrazione ROI con traslazione del centro di massa

Ora si cancellano eventuali oggetti indesiderati all’interno della ROI che possono

compromettere la fase di addestramento della macchina a vettori di supporto dato che si è

interessati ad analizzare un oggetto per volta; questa situazione si può presentare quando ci

sono oggetti vicini che hanno blob di diametro inferiore a quello impostato dall’utente. La

strategia impiegata consiste nel calcolare una matrice che ha le medesime dimensioni della

ROI che deve essere moltiplicata elemento per elemento con quest’ultima; questa matrice si

ottiene sfruttando la funzione sigmoidale come riportato di seguito:

33 Regioni d’interesse

Dove è la matrice che deve essere moltiplicata elemento per elemento con i pixel

della ROI, è il raggio del blob associato alla ROI (si calcola come la metà dell’asse maggiore

dell’elisse che contiene il blob) e è la distanza dal centro della ROI.

Figura 22 Filtraggio della ROI con funzione sigmoidale

E’ importante notare che in questo modo gran parte degli oggetti indesiderati all’interno

della ROI sono cancellati; non conviene sfruttare direttamente i blob individuati

precedentemente perché si rischia di compromettere la forma degli oggetti da analizzare. Il

principale svantaggio però è legato al fatto che in questo modo non sempre è possibile

cancellare con accuratezza i blob indesiderati, quindi la macchina a vettori di supporto dovrà

gestire le situazioni in cui le ROI contengono anche parti di oggetti indesiderati e non solo

quello effettivamente da analizzare.

2.6. Assegnazione delle ROI alla classe di appartenenza

Per l’addestramento della macchina a vettori di supporto è necessario stabilire quali ROI

devono essere considerate come positive e quali negative; è indispensabile avere a

disposizione il risultato di classificazione manuale di un esperto. Per stabilire la classe di

appartenenza di una ROI si sfruttano i blob associati a ogni regione e si verifica se il blob

contiene almeno un marcatore inserito dall’esperto di classificazione; nel caso sia presente

un marcatore, allora la ROI dovrà essere considerata come positiva, altrimenti negativa.

L’approccio considerato è migliore rispetto a quello basato sulla ricerca di marcatori

all’interno di un intorno centrato nei punti d’interesse perché ci sono varie situazioni in cui

questi punti sono molto distanti dai marcatori inseriti dagli esperti (ciò andrebbe a

compromettere l’associazione della ROI alla corretta classe di appartenenza). Invece, con

l’approccio basato sui blob, si prende in considerazione la forma degli oggetti e quindi si

aumenta la probabilità di individuare i marcatori inseriti dall’esperto; lo svantaggio è che se

l’esperto ha inserito i marcatori in prossimità dei bordi delle cellule allora questa soluzione

potrebbe non rilevare tali marcatori (di solito i marcatori sono posti nel centro delle cellule,

quindi il problema è quasi sempre trascurabile).

34 Feature

3. Feature

3.1. Introduzione

Dopo aver descritto come si estraggono le regioni d’interesse, ora è necessario stabilire

come rappresentarle prima di inoltrarle all’algoritmo d’apprendimento Support Vector

Machine (SVM); la rappresentazione fa riferimento a dei descrittori che prendono il nome di

feature. Il problema da affrontare consiste quindi nell’individuare delle feature in grado di

descrivere in modo efficiente le regioni d’interesse; per efficienza s’intende che con un

numero ridotto di descrittori si è in grado di rappresentare le caratteristiche salienti degli

oggetti. Si può osservare che spesso gli oggetti che rappresentano nuclei cellulari sono di

forma ovale oppure hanno forme meno regolari e le texture degli oggetti non validi sono

abbastanza simili fra loro (dato che spesso rappresentano rumore o porzioni di cellule a

intensità pressoché uniforme); quindi, conviene usare dei descrittori in grado di mettere in

risalto le forme degli oggetti ma anche la loro texture interna.

Per costruire della feature con alto contenuto informativo per la SVM, cioè affinché questa

sia in grado di discriminare correttamente gli oggetti presenti nelle immagini, è necessario

garantire tre proprietà:

Invarianza per traslazione, ossia la posizione dell’oggetto da analizzare all’interno di

un’immagine non deve influenzare il calcolo delle feature;

Invarianza per rotazione, cioè due oggetti uguali ma ruotati devono generare le

medesime feature;

Varianza per scala, le feature devono essere strettamente legate alla scala

dell’oggetto.

Garantire le caratteristiche suddette è uno dei principali problemi da affrontare prima del

calcolo delle feature e dell’addestramento dell’algoritmo di apprendimento.

In questo lavoro si presentano come tipologie di feature ShapeIntensity, Zernike, DCT, FMT

(distinte in FAFMT e DAFMT).

3.2. Proprietà delle feature

L’invarianza per traslazione è garantita dalla fase di traslazione del centro di massa del blob

d’interesse nel centro della ROI come descritto nel capitolo precedente.

La varianza per scala dipende unicamente dal tipo di feature, quindi queste devono essere

scelte in modo da renderle dipendenti dalla scala degli oggetti da analizzare.

L’invarianza per rotazione la si può ottenere in quattro modi diversi:

Ruotare le ROI e per ogni rotazione calcolare le feature da passare alla SVM;

Agire direttamente sulle feature in modo che sia garantita questa proprietà;

35 Feature

Ruotare i vettori di supporto della SVM;

Rendere direttamente le ROI invarianti per rotazione.

La prima soluzione richiede di ruotare (per un numero finito di volte) tutte le ROI, calcolare

per ogni rotazione le relative feature e passarle alla SVM; l’inconveniente è che deve essere

la SVM ad “apprendere” che le ROI sono ruotate in base a quanto descritto dalle feature, ciò

non garantisce l’invarianza per rotazione in tutti le possibili situazioni (la macchina a vettori

di supporto può sbagliare nella classificazione). Altro inconveniente è che il tempo di

elaborazione richiesto è elevato dato che sono coinvolte molte operazioni.

La seconda soluzione non sempre è attuabile dato che dipende dalle formule impiegate per

calcolare le feature.

La soluzione basata sulla rotazione dei vettori di supporto ha l’inconveniente di complicare

l’elaborazione perché è necessario mantenere l’associazione tra vettori di supporto e

corrispondenti regioni d’interesse; altro svantaggio sta nel fatto che è necessario ruotare le

ROI e poi ricalcolare le feature, ma le rotazioni non possono essere continue (altrimenti si

avrebbero infiniti vettori di supporto che su calcolatore non è possibile rappresentare). Altro

svantaggio è che è necessario stabilire in modo empirico il numero di rotazioni da

impiegare.

La quarta soluzione è migliore rispetto alle altre perché rende direttamente le ROI invarianti

per rotazione; la soluzione che si propone si basa su una tecnica che sfrutta il gradiente sulle

regioni d’interesse da analizzare. In questo caso, prima di procedere al calcolo

dell’orientazione delle ROI, si applica un filtro gaussiano sulle ROI per ridurre il rumore. Sulle

ROI così ottenute si procede con il calcolo del gradiente

dove è il gradiente della ROI , è il versore lungo l’asse , è il versore

lungo l’asse , è la componente del gradiente lungo la direzione e lungo

l’asse .

Per risalire all’orientazione della ROI si calcola il gradiente in corrispondenza del centro

dell’oggetto in analisi; per fare questo, s’individuano i valori dei centri di e .

36 Feature

dove sono le coordinate del centro della ROI e quindi anche delle matrici e

. Sfruttando la funzione arcotangente si risale all’orientazione del centro della ROI e

quindi della ROI medesima

Ora facendo riferimento al piano cartesiano

Figura 23 Piano cartesiano

e ai segni di è possibile risalire alla posizione del vettore in uno dei quattro

quadranti; le possibili situazioni sono (gli angoli sono in gradi):

e allora ;

e allora ;

e allora ;

e allora ;

e allora ;

e allora .

Nella fase di classificazione basta calcolare l’orientazione come descritto in precedenza e

ruotare la ROI in modo che l’angolo di rotazione sia

37 Feature

La condizione di sopra garantisce che tutte le ROI abbiano orientazione zero; calcolando le

feature sulle ROI così ottenute, si ha che queste sono invarianti per rotazione dato che le

ROI sono sempre a orientazione zero (due ROI iniziali uguali ma con orientazioni diverse

assumono la medesima orientazione dopo l’applicazione della procedura descritta sopra,

quindi le feature calcolate sono uguali).

Nel caso in cui le ROI debbano essere impiegate nella fase di addestramento della macchina

a vettori di supporto, conviene procedere in un altro modo ossia ridurre le ROI sulle quali

calcolare le feature. Infatti alcune feature non portano contenuto informativo che permetta

di definire al meglio il modello della SVM; queste ROI sono poco robuste alla rotazione causa

rumore o forme non regolari (oggetti piccoli dello sfondo), quindi si possono non

considerare nella definizione del modello della SVM (in fase di addestramento) e ciò porta ai

seguenti vantaggi:

Migliore definizione del modello della macchina a vettori di supporto dato che si

considerano esclusivamente feature molto robuste all’invarianza per rotazione;

Si aumenta la velocità di addestramento della SVM dato che si elaborano meno ROI

e quindi meno feature.

Una ROI poco robusta è individuata ruotandola di trentacinque volte di dieci gradi, per ogni

rotazione si verifica lo scostamento dell’orientazione da quella attesa; se lo scostamento

supera i cinque gradi allora la ROI viene scartata. Si è deciso di rendere molto ridotto il

margine per garantire una definizione accurata del modello della macchina a vettori di

supporto. Se la ROI risulta robusta allora si procede come descritto in precedenza, ossia si

esegue una rotazione della regione d’interesse in modo che l’orientazione sia di zero gradi

prima di calcolare le feature.

3.3. ShapeIntensity

La prima tipologia di feature che si presenta in questo lavoro serve per descrivere la forma

dei blob, la distribuzione dell’intensità e le informazioni sul profilo dell’istogramma; questi

descrittori non possono essere impiegati per ricostruire gli oggetti analizzati. La scelta di

testare questa tipologia di descrittore deriva dal fatto che permette di descrivere in modo

naturale le caratteristiche degli oggetti da analizzare.

Le feature che si calcolano per ogni oggetto da analizzare sono: area, asse maggiore, asse

minore, rapporto tra gli assi, intensità massima, intensità media, varianza, entropia, energia,

contrasto, correlazione, omogeneità, skewness e curtosi; quasi tutte le feature menzionate

appartengono ai descrittori di forma dell’istogramma del primo e secondo ordine. Oltre a

queste se ne sono aggiunte altre per migliorare le informazioni relative alla forma degli

oggetti (area, asse maggiore, asse minore, rapporto tra gli assi).

La distribuzione di probabilità del primo ordine di un’immagine quantizzata può essere

descritta da

38 Feature

dove rappresenta la quantizzazione del livello d’intensità e è il

pixel considerato nell’immagine F di coordinate . La stima di dell’istogramma del

primo ordine è

dove rappresenta il numero totale di pixel nella finestra centrata nel punto d’interesse e

il numero di pixel d’ampiezza .

Occorre osservare che la forma dell’istogramma permette di descrivere molte

caratteristiche e in questo caso le feature prendono il nome di descrittori quantitativi di

forma dell’istogramma del primo ordine:

Le feature dell’istogramma del secondo ordine sono basate sulla definizione della

distribuzione di probabilità congiunta di una coppia di pixel. Si considerano due pixel

e di coordinate rispettivamente e posti a distanza con angolo

rispetto all’asse orizzontale; quindi la distribuzione congiunta è data da

dove sono le ampiezze quantizzate. La stima della distribuzione del secondo ordine

dell’istogramma è data da

39 Feature

dove rappresenta il numero totale dei pixel nella finestra di misura e il numero di

occorrenze per = e = . I descrittori di forma dell’istogramma del

secondo ordine sono:

Dove

Oltre a queste se ne sono aggiunte altre per migliorare le prestazioni di riconoscimento dei

nuclei cellulari, ossia il valore massimo d’intensità della cellula, asse maggiore e minore

dell’ellisse che contiene il blob considerato e il loro rapporto, area del blob ottenuta tramite

la segmentazione basata sulla sogliatura di Otsu.

3.4. Zernike

La trasformata di Zernike tipicamente si usa per l’analisi di oggetti di forma circolare di un

certo raggio, quindi in questo lavoro si presta bene alla generazione di descrittori.

L’inconveniente principale è che è necessario usare un numero molto elevato di feature

(molti coefficienti) per non perdere troppe informazioni riguardanti l’oggetto da descrivere;

ciò significa che è necessario presentare alla macchina a vettori di supporto vettori con

molti elementi (le feature) ma questo non implica necessariamente una migliore definizione

del modello della SVM.

40 Feature

Le funzioni di Zernike sono calcolate come il prodotto tra i polinomi di Zernike e le funzioni

trigonometriche coseno e seno:

Dove rappresenta il raggio e ө l’angolo, l’indice è chiamato grado della

funzione o del polinomio di Zernike, mentre con pari ed è chiamato

ordine di Zernike. I polinomi sono espressi come:

Di seguito si riportano le prime dieci funzioni di Zernike tipiche che si utilizzano nelle

applicazioni pratiche:

Queste funzioni sono un’utile base per la decomposizione di funzioni complesse perché

sono ortogonali sul cerchio di raggio unitario. Utilizzando tale ortogonalità, una qualsiasi

funzione definita sul cerchio, può essere espressa come somma delle mode di

Zernike (come nel caso delle funzioni coseno e seno nella trasformata di Fourier)

Se si rappresentano i dati in questo modo, è possibile descrivere deformazioni complesse in

termini di un numero ridotto di coefficienti associati alle mode dominanti di Zernike.

41 Feature

I coefficienti (detti momenti di Zernike) possono essere calcolati dall’inversione

dell’equazione precedente se è nota la funzione :

Il numero di coefficienti dipende dal grado del polinomio di Zernike e più questo è elevato

migliore è la rappresentazione dell’oggetto in analisi. Da notare che Zernike si può calcolare

solo all’interno di un cerchio, quindi l’oggetto da analizzare deve risiedere completamente

nel cerchio inscritto nella ROI di diametro pari alla lunghezza di un lato della ROI. Occorre

osservare che non si può aumentare il grado a un valore arbitrario dato che la velocità di

calcolo diminuisce notevolmente già da grado dieci in poi.

Di seguito si riporta un esempio di oggetto sul quale si calcola un certo numero di

coefficienti di Zernike e poi la relativa ricostruzione; rispettivamente i gradi del polinomio

sono dodici (novantuno feature), venti (duecento trentuno feature) e poi trenta

(quattrocento novantasei feature).

Figura 24 Ricostruzioni della ROI con diversi gradi per Zernike

Dalle immagini di sopra si può immediatamente notare che per rappresentare con dettaglio

elevato le caratteristiche dell’oggetto in questione sono necessari molti coefficienti; il

passaggio da grado dodici a venti non produce un miglioramento descrittivo significativo,

mentre con grado trenta si ha una buona descrizione ma il problema è che il tempo di

42 Feature

elaborazione richiesto è eccessivo dato che ci sono tantissime feature da calcolare

(quattrocentonovantasei).

3.5. Trasformata di Fourier-Mellin, AFMT, DAFMT e FAFMT

Un altro tipo di feature considerato in questo lavoro di tesi si basa sulla trasformata di

Fourier-Mellin (FMT); i principali problemi della FMT classica sono legati nell’accuratezza ed

efficienza della sua approssimazione numerica, il vantaggio è che è possibile avere una

rappresentazione accurata dell’oggetto anche con pochi coefficienti.

La trasformata di Fourier–Mellin di una funzione continua è data da

e deve valere

dove è la rappresentazione dell’immagine nel piano polare ( è il raggio e

l’angolo); questa è una trasformata globale che si applica su ogni pixel dell’immagine. Per

poterla calcolare è necessario definire il centro delle coordinate; l’inconveniente principale è

legato al calcolo dell’integrale nell’espressione di cui sopra, la FMT esiste per funzioni che

sono equivalenti a nelle vicinanze dell’origine per costante e . Occorre

osservare che la funzione di rappresentazione dell’immagine non necessariamente soddisfa

tale condizione dato che nelle vicinanze del centro dell’immagine (tipicamente corrisponde

al centro di “massa” dell’oggetto considerato) non assume valore zero; come conseguenza

non è sommabile e l’integrale per il calcolo di diverge. Altra osservazione da fare

è che la FMT è invariante per rotazione e scala di (cioè scala di ROI no dell’oggetto da

analizzare).

A causa della singolarità nell’origine delle coordinate, Ghorbel [17] ha proposto di calcolare

la FMT classica sulla funzione in luogo di dove è fissato e

deve essere un numero reale strettamente positivo; in questo caso esiste sempre la

trasformata FMT e prende il nome di trasformata di Fourier–Mellin Analitica (AFMT) di . Di

seguito si riporta l’AFMT

dove . L’anti trasformata IAFMT è data da:

43 Feature

Per , dove è l’angolo di rotazione e il fattore di scala rispetto a

, si ha che i due oggetti e hanno la stessa forma quindi sono simili. L’AFMT di g è data

da

che si può anche riscrivere come

Si può osservare che l’AFMT può essere utilizzata per calcolare feature invarianti per

rotazione (basta considerare il modulo dell’AFMT); da notare che in questo lavoro è

costante dato che le feature sono calcolate sempre su finestre (ROI) della stessa

dimensione (nel caso in cui la finestra cambiasse dimensione allora la trasformata

dipenderebbe anche dal fattore ).

Ora che si è definita l’AFMT e IAFMT per funzioni reali è necessario passare alla

rappresentazione discreta. Questa, però, non esiste direttamente e per ricavarla è

necessario stimare la trasformata diretta e inversa. L’invarianza in rotazione degli oggetti è

già gestita mediante la tecnica basata sul gradiente descritta all’inizio di questo capitolo, ma

è possibile rafforzare questa condizione considerando il modulo della trasformata;

l’inconveniente è che in questo modo si perde l’informazione sulla fase e di conseguenza

non è più possibile ricostruire l’oggetto iniziale a partire dalle feature (questo non è un

problema perché non è necessario fare la ricostruzione).

Per l’approssimazione discreta della trasformata AFMT si considera con

un’immagine discreta definita su una griglia rettangolare finita; non esiste fuori dal piano

2D, la sua AFMT non è a banda limitata e richiede un numero infinito di armoniche per

descrivere l’oggetto in questione. Su calcolatore è possibile rappresentare un numero finito

di armoniche e quindi si perde una parte dell’informazione iniziale. L’AFMT discreta a

estensione finita è calcolata per e ; nel lavoro di Goh

[18] si suggerisce di utilizzare . Per funzioni reali l’AFMT è simmetrica, quindi

indicando con la linea il complesso coniugato si ha:

D’ora in poi con si denota la ricostruzione di da un numero finito di

armoniche Fourier–Mellin; per la scelta di e non ci sono delle regole predefinite,

44 Feature

tipicamente si procede in modo empirico. Di seguito si descrivono le due approssimazioni

possibili considerate.

La prima approssimazione che si considera è quella diretta di AFMT (DAFMT) e consiste nel

campionare nel piano discreto polare e stimare gli integrali di Fourier–Mellin. La

griglia polare di campionamento si costruisce dalle intersezioni tra cerchi concentrici di

raggi incrementati di un valore fissato e linee radiali generate dal centro dell’immagine. I

passi di campionamento angolari e radiali sono rispettivamente

dove rappresenta il raggio minimo del disco che è in grado di contenere l’oggetto. I punti

di campionamento quando non corrispondono alla griglia dei pixel dell’immagine sono

calcolati per interpolazione; la rappresentazione polare dell’immagine è una matrice i

cui valori corrispondono a

dove e sono rispettivamente il raggio d’indice e cerchio d’indice .

Un esempio di campionamento in coordinate polari è riportato di seguito.

Figura 25 Campionamento con coordinate polari

La trasformata diretta DAFMT è

con

La trasformata inversa della DAFMT è data da

45 Feature

con

La seconda approssimazione possibile consiste nel cambiare la variabile d’integrazione da r a

q = ln(r), quindi si può riscrivere il tutto come la trasformata di Fourier dell’oggetto

deformato . Questa trasformata prende il nome di trasformata veloce FMT

(FAFMT) ed è data da

con

La FAFMT consiste nel campionare la nel piano log-polar e stimare Fourier-Mellin; la

conversione numerica da coordinate cartesiane in log-polar avviene come nel caso

precedente eccetto che i cerchi in questo caso sono separati esponenzialmente.

Un esempio di campionamento con log-polar è riportato di seguito.

Figura 26 Campionamento con coordinate log-polar

Per calcolare l’AFMT con questo tipo d’approssimazione si utilizza la trasformata discreta 2D

con coordinate log–polar :

46 Feature

La trasformata inversa è data da

3.6. Trasformata DCT

La trasformata DCT (Discrete Cosine Transform) è tipicamente utilizzata nelle elaborazioni

delle immagini e video; la procedura di calcolo delle feature basata sulla DCT consiste nel

calcolare la DCT direttamente sulla ROI da analizzare e poi selezionare i coefficienti (le

feature) da considerare.

Se con s’indica il valore in posizione del pixel nell’immagine di dimensione

e con il coefficiente DCT della matrice delle frequenze allora sia ha:

Per l’anti trasformata:

La DCT permette di passare da una rappresentazione nel dominio spaziale a quello della

frequenza. L’elemento è il valore massimo presente nel blocco trasformato (è la

componente continua), gli altri elementi dicono quanto potere spettrale è presente. Le

componenti a bassa frequenza rendono conto dell’andamento generale della luminosità

nell’immagine, mentre quelle ad alta frequenza codificano i dettagli e il rumore.

Per stabilire il numero di coefficienti da usare come feature è conveniente fare un’analisi

preliminare di tutte le ROI in cui si calcolano le energie dei singoli coefficienti della DCT; a

questo punto è possibile individuare l’energia media complessiva delle ROI e selezionare il

numero di coefficienti in modo che la somma delle energie di questi dia come valore quello

più vicino (per eccesso) a una soglia prestabilita dall’utente.

Di seguito si riporta un esempio dell’andamento dell’energia di una ROI, si può notare che la

DCT ha la tendenza a concentrare l’energia nei coefficienti in alto a sinistra.

47 Feature

Figura 27 Energia della DCT

Si riporta un esempio di ricostruzione della ROI con una finestra dodici

(centoquarantaquattro feature), quindici (duecentoventi cinque feature), venti

(quattrocento feature) e trenta (novecento feature). Si può notare che dopo una finestra

quindici, il miglioramento nella ricostruzione della ROI è minimo.

Figura 28 Ricostruzione di una ROI dai coefficienti DCT

48 Macchina a vettori di supporto

4. Macchina a vettori di supporto

4.1. Introduzione

Dopo aver rappresentato opportunamente le ROI tramite le feature, è necessario procede

con la classificazione delle medesime; per far questo si usa un opportuno algoritmo

d’apprendimento che dopo l’addestramento sia in grado di eseguire nel miglior modo

possibile tale classificazione. Gli algoritmi d’apprendimento stanno rivestendo un ruolo

sempre più importante in tutti quei campi in cui è necessario risolvere un problema di

classificazione:

Binario, ossia ci sono solo due possibili risposte;

Multi-classe cioè l’algoritmo è in grado di fornire più di due risposte.

Allo stato attuale esistono vari classificatori binari ma si è deciso di impiegare la macchina a

vettori di supporto (questa è implementata dalla libreria open source libsvm); si è deciso di

sfruttare la SVM (Support Vector Machine) per i seguenti motivi:

Possibilità di risolvere problemi di classificazione generali con tecniche di

programmazione quadratica o lineare ben note;

Costo computazionale ridotto e nessun problema di convergenza. Le reti neurali a

singolo strato sono molto efficienti ma si possono impiegare nel caso in cui i dati

sono linearmente separabili. Le reti multistrato possono rappresentare funzioni non

lineari ma l’addestramento è complesso, inoltre le tecniche più diffuse permettono

di ottenere i pesi della rete tramite la risoluzione a un problema di ottimizzazione

che però presenta un numero indeterminato di minimi locali;

Compatta l’informazione contenuta nel data set d’input tramite i vettori di supporto;

Gestisce dati con molte caratteristiche descrittive;

La complessità del classificatore è legata ai vettori di supporto e non alla dimensione

dello spazio delle feature. Questo comporta ridotto overfitting, ossia dopo che la

macchina è stata addestrata sul training set e l’errore minimizzato, questa tende ad

associare ai nuovi dati in ingresso un errore ridotto ossia è addestrata anche per

generalizzare le nuove situazioni che a essa si presentano.

Ultima osservazione è che la SVM è adatta per risolvere problemi binari, quindi in un

problema di classificazione multi-classe è necessario costruire una rete di macchine che

richiede una gestione dell’intera struttura; nel problema che questo lavoro si prefigge di

risolvere è possibile impiegare una singola macchina dato che la classificazione cellulare in

questo caso è binaria.

4.2. La macchina

L’algoritmo della SVM fa riferimento alla teoria di apprendimento statistico di Vapnik-

Chervonenkis (VC); questa teoria caratterizza le proprietà degli algoritmi di apprendimento

49 Macchina a vettori di supporto

che dopo l’addestramento sono in grado di generalizzare. Una SVM è un classificatore

binario che apprende il confine tra esempi appartenenti a due classi diverse. Gli esempi

d’input sono proiettati in uno spazio multidimensionale e l’algoritmo individua un iperpiano

di separazione in questo spazio in modo tale da massimizzare la distanza dagli esempi di

training più vicini (questa distanza prende il nome di margine).

Per descrivere il processo d’apprendimento è necessario introdurre un insieme di funzioni di

soglia

dove è un insieme di parametri reali che definiscono la macchina, le funzioni si

chiamano ipotesi e l’insieme è lo spazio delle ipotesi . Ora si considera un

insieme di esempi già classificati presi da una distribuzione sconosciuta :

La macchina deve trovare un’ipotesi che minimizzi il rischio, questo è in funzione di

:

L’errore teorico rappresenta la misura della bontà dell’ipotesi nel predire la classe del

punto . L’insieme genera una SVM in grado di risolvere un particolare problema di

classificazione binaria; la distribuzione di probabilità non è nota quindi non è possibile

calcolare direttamente l’errore teorico ma è necessario procedere in modo diverso per

individuare .

L’errore empirico è dato da

dove è il numero delle osservazioni a disposizione; per si ha che l’errore empirico

converge in probabilità all’errore teorico.

Prima di procedere con la descrizione della classificazione mediante macchina a vettori di

supporto è necessario introdurre il concetto di dimensione VC dello spazio delle ipotesi ;

questo è un numero naturale che rappresenta il più grande numero di punti che possono

essere separati in tutti i modi possibili dall’insieme delle ipotesi . La dimensione VC è una

misura della complessità dell’insieme e in generale per un insieme d’iperpiani separatori

di dimensione è .

50 Macchina a vettori di supporto

La teoria della convergenza uniforme in probabilità sviluppata da Vapnik e Chervonenkis

fornisce un limite alla deviazione dell’errore empirico da quello teorico; fissato con

si ha:

Dove è la dimensione VC di ; da questa espressione si ha che per ottenere l’errore

teorico minimo è necessario minimizzare la somma dell’errore empirico e della confidenza.

L’algoritmo SVM risolve efficientemente il problema di classificazione binaria minimizzando

contemporaneamente sia la dimensione VC sia il numero di errori sul training set.

4.2.1. Classificatore lineare su dati linearmente separabili

In questo caso specifico si ha che l’insieme dei dati d’ingresso, quindi le osservazioni, sono

linearmente separabili. La macchina d’apprendimento deve individuare il miglior iperpiano

che li separa in questa situazione.

Un insieme di osservazioni è linearmente separabile se esiste una coppia tale che

con

con

Le seguenti funzioni quindi rappresentano lo spazio delle ipotesi

con s’indica il discriminatore binario.

Un esempio di separazione lineare è riportato di seguito:

Figura 29 Classificatore lineare

Per quanto riguarda la notazione che sarà utilizzata d’ora in poi, si ha che: lo spazio d’input è

indicato con , lo spazio d’output , ipotesi o , training set

ed errore su un dato di test .

La distanza dell’iperpiano associato alla coppia dal generico punto è

51 Macchina a vettori di supporto

cioè è funzione di

; se s’impone che allora la distanza dell’iperpiano dal punto

più vicino deve essere maggiore di

. Per ridurre il numero d’iperpiani, e quindi migliorare la

velocità di ricerca del piano ottimale, si considerano soltanto gli iperpiani che non

intersecano nessuna delle sfere di raggio

centrate nei punti dell’insieme delle osservazioni.

L’iperpiano ottimale è quello che permette di classificare correttamente il training set e ha

minima cioè massimizza il margine alle osservazioni del training set; la norma piccola

ha come conseguenza quella di tenere la dimensione VC piccola.

Di seguito si riportano due soluzioni al medesimo problema binario, però la seconda

garantisce un minor rischio di overfitting ossia ha una migliore generalizzazione (margine più

elevato):

Figura 30 Differenza fra margini SVM

Il problema della ricerca dell’iperpiano ottimo si può descrivere tramite la

con legati al vincolo

52 Macchina a vettori di supporto

e con . Questo problema si può risolvere con la tecnica dei moltiplicatori di

Lagrange in cui s’introduce un moltiplicatore per ogni vincolo

dove rappresenta il vettore dei moltiplicatori di Lagrange positivi che fanno

riferimento ai vincoli ; deve essere minimizzata rispetto a e

massimizzata rispetto a per ottenere la soluzione ottimale. Il problema può essere

riscritto come di seguito:

Dalla prima si ha che l’iperpiano è dato da

e quindi

La funzione da ottimizzare è quadratica in cui i dati appaiono all’interno di prodotti

vettoriali; a questo punto è possibile riformulare il problema in modo più semplice

In quest’ultima formulazione si ha che i vincoli ora sono rappresentati da

vincoli sui moltiplicatori e i vettori del training set appaiono come prodotti tra vettori. La

soluzione al problema riformulato permette di individuare i moltiplicatori e il classificatore

è dato da

53 Macchina a vettori di supporto

Tutti i punti per i quali il relativo moltiplicatore è sono detti vettori di supporto (e

stanno su uno dei due iperpiani ), invece gli altri hanno il relativo moltiplicatore a zero

e quindi non hanno alcuna influenza sul classificatore. I vettori di supporto sono quelli

fondamentali che stabiliscono il comportamento della macchina e sono i punti critici del

training set (cioè quelli più vicini all’iperpiano di separazione).

4.2.2. Classificatore lineare su dati non linearmente separabili

Ora si considera la situazione in cui i dati non sono linearmente separabili come

nell’esempio seguente

Figura 31 Dati non linearmente separabili

Il piano dista dall’origine

e il punto “anomalo” dista dalla sua classe

. Nei casi in

cui i dati non siano linearmente separabili, si ha che alcune osservazioni sono in posizioni

anomale rispetto alle altre della medesima classe; si prende in considerazione una costante

di scarto (variabile di slack) che assume valori tanto più grandi quanto più lontani sono gli

elementi anomali. La coppia che soddisfa il vincolo diventa

con e . In questo modo il vincolo ammette una certa

tolleranza agli errori e un’osservazione è mal classificata se il corrispondente supera

l’unità. La sommatoria è un limite superiore al numero massimo di errori possibili sul

training set. Il problema in questo caso può essere riformulato come la minimizzazione di

con insieme degli scarti e che soddisfano i vincoli

con

La costante è il soft margin che deve essere impostata a priori. Con l’introduzione di , la

macchina cerca di minimizzare e allo stesso tempo separa le osservazioni minimizzando

54 Macchina a vettori di supporto

il numero di errori. Per la soluzione al problema di ottimizzazione si procede come visto in

precedenza, quindi tramite i moltiplicatori lagrangiani

in cui i moltiplicatori e sono associati ai vincoli

; deve essere minimizzata rispetto a e massimizzata rispetto a e

.

Con si ha che si deve massimizzare

con vincoli . La soluzione è identica al caso di dati d’input separabili

linearmente con la differenza sul vincolo sui moltiplicatori che adesso sono limitati

superiormente da ; il classificatore è

4.2.3. Classificatore non lineare

Se nello spazio d’input le osservazioni non sono linearmente separabili, in questo caso è

possibile sfruttare una funzione che mappa lo spazio d’input in quello delle feature dove

le osservazioni diventano linearmente separabili

Figura 32 Spaio d’input e delle feature

Se si mappano le osservazioni non linearmente separabili dallo spazio d’input in quello delle

feature (di dimensione maggiore rispetto al primo) per rendere i dati linearmente separabili

sfruttando la funzione di mappatura , allora l’algoritmo dipende dai dati e quindi

dal prodotto delle loro immagini da in (funzioni del tipo ). La dimensione

dello spazio delle feature influenza la velocità di calcolo; maggiore è la dimensione maggiore

è il tempo di calcolo dato che la macchina deve operare con vettori di grandi dimensioni.

55 Macchina a vettori di supporto

Per risolvere il problema descritto sopra, la SVM sfrutta una funzione kernel che restituisce il

valore del prodotto interno fra le immagini ; a questo punto è

possibile usare nell’algoritmo per ignorare la forma diretta di In questo caso si sfrutta

una rappresentazione matriciale della funzione di kernel i cui argomenti ovviamente sono i

vettori di apprendimento. Tramite la tecnica basata sul kernel, si genera una macchina che

opera in ed esegue le elaborazioni nella stessa quantità di tempo che impiegherebbe se

lavorasse con i dati originali non mappati; quello che accade è che si costruisce un

classificatore lineare ma in uno spazio differente. In dettaglio si ha che un punto d’ingresso

generico è mappato in un vettore nello spazio delle feature tramite la funzione

, dove gli sono numeri reali e le sono funzioni reali. Ora

si procede come nel caso di osservazioni non linearmente separabili, però si sostituisce la

variabile con il vettore quindi si ha che la funzione di decisione è data da

Si sostituiscono i prodotti con il kernel

Esistono vari tipi di kernel, quelli comunemente utilizzati sono:

Lineare ;

Polinomiale ;

Radial Basis Function ;

Sigmoidale .

Da osservare che i dati d’ingresso devono essere normalizzati (ad esempio tra zero e uno )

prima di essere passati alla macchina; quindi è necessario salvare i coefficienti di

normalizzazione prima dell’addestramento (uno per ogni feature) per impiegarli

successivamente nella fase di classificazione per normalizzare le osservazioni.

4.2.4. Cross-validation

Questa è una tecnica statistica che è utilizzata per addestrare opportunamente la macchina

e permette di verificare l’overfitting ossia la bontà della generalizzazione in base ai

parametri impostati (uno per il kernel e uno che rappresenta il soft margin). L’insieme delle

osservazioni è suddiviso in porzioni e a ogni passo la parte rappresenta

l’insieme di validazione ossia il sottoinsieme delle osservazioni su cui si testa la macchina

addestrata; le parti restanti rappresentano il training set su cui si addestra la

macchina. Su ogni insieme di validazione si calcola l’AUC, cioè l’area sottesa alla curva ROC

(queste curve sono descritte in dettaglio nel prossimo capitolo) e si fa la media delle curve

ROC ottenute per ricavare la ROC e quindi l’AUC finale. A questo punto si salvano i

56 Macchina a vettori di supporto

parametri della macchina e si procede nuovamente dall’inizio con dei nuovi; quando i valori

prefissati dei parametri sono stati tutti considerati, allora si scelgono come parametri ottimi

quelli che massimizzano l’AUC e con questi parametri si procede all’addestramento della

macchina su tutto il training set a disposizione. Tale procedura permette di verificare

l’overfitting e allevia il problema del campionamento asimmetrico tipico della suddivisione

degli esempi a disposizione in due sole parti (ossia training set e validation set).

57 Receiver Operating Characteristic

5. Receiver Operating Characteristic

5.1. Introduzione

Dopo aver descritto il classificatore binario, è necessario considerare il criterio per la

valutazione delle prestazioni. In questo progetto si considera esclusivamente la

classificazione binaria dato che lo scopo è di stabilire se una ROI rappresenta un nucleo di un

neurone (ROI positiva) o meno (ROI negativa); in letteratura esistono varie tecniche per

valutare le prestazioni di un classificatore binario ma in questo lavoro si considera

unicamente quella basata sulle curve ROC (Receiver Operating Characteristic). Questa scelta

deriva dal fatto che le curve ROC hanno una proprietà molto importante ossia sono

indipendenti alle variazioni delle distribuzioni delle due classi (positivi e negativi); ciò

significa che se le proporzioni tra positivi e negativi nel test cambiano ma le prestazioni

effettive del classificatore sono le medesime (veri positivi e falsi positivi non sono cambiati

in numero) allora le curve ROC non subiscono modifiche. Quest’aspetto è molto rilevante,

infatti, garantisce che a classificatori con prestazioni uguali corrispondono curve ROC

identiche indipendentemente dalle proporzioni tra positivi e negativi. Tale proprietà non

vale per tecniche che usano metriche quali accuratezza, precisione (Precision and Recall) e

funzioni di F score cioè le curve cambiano al variare delle proporzioni tra positivi e negativi

anche se le prestazioni effettive non cambiano; da ciò si evince che la tecnica di valutazione

delle prestazioni di un classificatore binario basata su curve ROC descrive al meglio le

prestazioni del medesimo. Questa particolarità delle curve ROC deriva dal fatto che lo spazio

ROC fa riferimento esclusivamente al false positive rate e true positive rate che sono

indipendenti dalle distribuzioni delle classi.

5.2. Spazio ROC

Per verificare un’ipotesi esistono molte procedure della più svariata natura che prendono il

nome di test. I test sono classificati in due categorie in base al tipo di output:

Test qualitativi, restituiscono una risposta dicotomica ossia risultato

positivo/negativo, vero/falso ecc.;

Test quantitativi, forniscono risultati in forma di variabili numeriche discrete o

continue.

Nei test quantitativi è necessario individuare un valore di soglia detto cut-off che discrimini

al meglio le due classi di positivi e negativi; i problemi principali nell’interpretazione di un

test risiedono nel fatto che esiste spesso una sovrapposizione fra i risultati ottenuti, cioè il

test non è in grado di separare correttamente le due classi da discriminare e quindi i risultati

si discostano da quelli veri. Nel caso in cui non ci fosse tale sovrapposizione, allora il cut-off

sarebbe in grado di discriminare con precisione assoluta le due popolazioni di positivi e

negativi; in pratica quello che accade è che quasi sempre esistono queste sovrapposizioni

tra le distribuzioni.

58 Receiver Operating Characteristic

Di seguito si riportano le due situazioni ossia di classificazione perfetta e con

sovrapposizione delle distribuzioni di due classi; la classe uno descrive unicamente le ROI

positive (nuclei dei neuroni) e la classe due le ROI negative (tutto ciò che non rappresenta

nuclei dei neuroni).

Figura 33 Cut-off

Per stimare le prestazioni di un test a un determinato valore di cut-off è necessario valutare

la capacità del test di condurre a risultati positivi per gli elementi della classe uno e a

risultati negativi per quelli della classe due; per fare questo si confrontano i test con il

golden test, ossia quello che fornisce risultati perfettamente corrispondenti alla realtà e in

questo lavoro è dato dagli esperti di classificazione.

Di seguito si riporta la matrice di confusione.

Golden test

Test Classe 1 (ROI positiva p) Classe 2 (ROI negativa n)

Y TP FP

N FN TN

Dove Y sta per predizione positiva del classificatore (yes), N per predizione negativa

(negative), TP vero positivo (true positive), FN falso negativo (false negative), FP falso

positivo (false positive) e TN vero negativo (true negative).

La rappresentazione delle curve ROC in un grafico permette la visualizzazione,

organizzazione e selezione dei classificatori in base alle loro prestazioni. Ogni istanza di una

delle due classi si denota con il simbolo ed è mappata a un elemento dell’insieme

che rappresenta l’etichetta delle classi del golden test. Il classificatore mappa ogni istanza

alla classe predetta (si fa riferimento al test da valutare). Alcuni modelli di classificazione

59 Receiver Operating Characteristic

generano un’uscita continua e tramite determinati valori di soglia è possibile stabilire

l’appartenenza a una classe, altri modelli producono uscite discrete ossia le etichette di

appartenenza a una specifica classe; le label predette dal classificatore binario s’indicano

con . A questo punto, dato un classificatore e un’istanza , ci sono quattro possibili

casi:

L’istanza è positiva ed è classificata come positiva, corrisponde a un TP;

L’istanza è positiva ma è classificata come negativa, quindi si è nel caso di FN;

L’istanza è negativa ed è classificata negativa, allora si ha un TN;

L’istanza è negativa ma è classificata positiva, quindi FP.

Dato un classificatore e un insieme d’istanze, si ottiene la matrice di confusione riportata

sopra; molte tecniche di valutazione delle prestazioni di un classificatore binario fanno

riferimento a questa che rappresenta la base per la costruzione di varie metriche comuni

quali:

;

;

;

.

Alle curve ROC sono associati i termini , ma anche sensitività che è la recall,

specificità che è data da

e valore predittivo positivo che è la precision.

I grafici ROC si rappresentano in un grafico a due assi, l’asse delle ascisse fa riferimento ai

e quello delle ordinate ai ; le curve ROC descrivono il compromesso tra

benefici (TP) e costi (FP).

Un classificatore discreto genera come uscite delle etichette associate alle due classi di

appartenenza, quindi a ogni classificatore corrisponde una coppia che

individua un punto nello spazio ROC. Nello spazio ROC ci sono tre punti rilevanti di

coordinate:

descrive la situazione in cui non ci sono elementi classificati come positivi,

quindi il classificatore non genera falsi positivi ma neanche veri positivi;

descrive la situazione di classificazione perfetta ossia non sono generati falsi

positivi ma soltanto i veri positivi;

si è nella situazione in cui ogni esempio è classificato come positivo.

60 Receiver Operating Characteristic

I punti sulla diagonale nello spazio ROC descrivono la situazione in cui la classificazione è

casuale; ad esempio per il punto ci si attende un 70% di veri positivi ma anche

un 70% di falsi positivi, quindi la probabilità che un elemento classificato positivo sia

effettivamente corretto è 0.5 (come nel lancio casuale di una moneta). Lo stesso discorso

vale anche per tutti gli altri punti della diagonale. Ciò implica che la regione dello spazio ROC

da considerare è data dal triangolo equilatero di coordinate e la regione

sotto questo triangolo usualmente è vuota. Se si nega il risultato fornito da un classificatore,

allora i veri positivi diventano falsi negativi (errori) e i falsi positivi diventano veri negativi;

ciò significa che se si ha un punto nel triangolo in basso a destra, questo può essere negato

per ottenere un punto nel triangolo in alto a sinistra (ad esempio la negazione di è ). Da

queste osservazioni si deduce che i punti sulla diagonale non portano informazione utile

sulla classe di appartenenza e quelli nel triangolo in basso a destra hanno informazione utile

grazie alla negazione ma risulta applicata in modo incorretto.

5.3. Generazione efficiente dei punti di una curva ROC

I classificatori si possono distinguere in due categorie:

Classificatori discreti, cioè stabiliscono l’appartenenza a una specifica classe (ad

esempio nel caso di classificatori binari associano a ogni istanza o l’etichetta o );

Classificatori probabilistici, ossia quelli che generano un numero per ogni istanza

che descrive il grado di appartenenza di un’istanza a una classe. In questo caso i

numeri generati possono essere direttamente le probabilità di appartenenza a una

classe o fanno riferimento a una funzione di score che ha la proprietà che a valori

elevati corrisponde probabilità elevate (i numeri non sono direttamente i valori della

probabilità).

Se il classificatore usa una funzione di score, è possibile sfruttare un valore di soglia per

generare una classificazione discreta binaria; cioè se l’uscita del classificatore è sopra la

61 Receiver Operating Characteristic

soglia, allora produce etichetta altrimenti . A ogni valore di soglia corrisponde un punto

nello spazio; concettualmente, si può immaginare di variare la soglia da a e

tracciare in questo modo una curva nello spazio ROC. Quest’ultima tecnica è poco efficiente

dal punto di vista della velocità di calcolo, successivamente sarà presentato un algoritmo

molto più efficiente.

Una curva ROC generata da un insieme finito d’istanze è rappresentata da una funzione a

gradini; per ottenere effettivamente una curva sarebbe necessario considerare un’infinità

d’istanze. Prima di procedere a tracciare una curva ROC è necessario avere a disposizione

una funzione di score usata dal modello del classificatore; nel caso della macchina a vettori

di supporto implementata nella libreria libsvm, si ha a disposizione direttamente questa

funzione. I valori di questa funzione fanno riferimento unicamente ai risultati positivi del

golden test, rappresentano la probabilità assegnata dalla macchina che gli esempi classificati

dalla SVM siano positivi.

Di seguito si riporta l’algoritmo adottato per tracciare una curva ROC.

Figura 34 Generazione ROC

L’input dell’algoritmo è cioè l’insieme degli esempi positivi del golden test classificati dalla

SVM, l’output è ossia l’insieme dei punti della curva ROC. Tramite la funzione di score si

ordina in modo decrescente e si ottiene ; poi s’inizializzano le variabili:

62 Receiver Operating Characteristic

a zero che rappresenta i veri positivi;

a zero che è il descrittore dei falsi positivi;

a che indica il valore di score associato all’esempio precedente

analizzato;

a 1 che indica l’indice dell’esempio da analizzare.

Fino a quando non ha raggiunto il numero di esempi presenti in si verifica se il valore di

score associato all’esempio di indice è diverso da quello di indice precedente; in caso

affermativo si genera il punto della curva ROC di coordinate

e si salva il risultato in

e si imposta , in caso contrario non si genera alcun punto. Ora si verifica se

l’esempio all’indice corrente è positivo, in caso affermativo si aggiorna

altrimenti si aggiorna . Alla fine s’incrementa l’indice di uno per analizzare il

successivo esempio e si riparte dall’inizio; se l’indice ha raggiunto il limite massimo (numero

di esempi in ) allora si genera il punto

e lo si salva in .

5.4. AUC

Una curva ROC fa riferimento a un sistema cartesiano a due assi; per confrontare le

prestazioni descritte dalle curve ROC di vari classificatori, è possibile sfruttare un singolo

valore scalare associato a ogni curva che prende il nome di AUC (Area Under the ROC Curve).

Poiché l’AUC è una porzione dell’area del quadrato nello spazio ROC (ogni lato ha lunghezza

unitaria) allora può assumere valori tra zero e uno; tuttavia, è necessario osservare che un

classificatore realistico non ha una curva ROC sotto la diagonale dello spazio ROC, quindi

l’area non sarà mai inferiore a 0.5.

L’AUC ha un’importante proprietà statistica: l’AUC di un classificatore è equivalente alla

probabilità che il risultato di un’istanza su un elemento estratto a caso dalla classe uno (dei

positivi) sia superiore a quello di un estratto a caso dalla classe due (dei negativi). Per

calcolare l’AUC si può usare la tecnica dei trapezoidi.

Per l’interpretazione dell’AUC si può tenere presente la classificazione della capacità

discriminante di un test proposta da Swets nel 1998 [15]:

test non informativo;

test poco accurato;

test moderatamente accurato;

test altamente accurato;

test perfetto.

63 NVIDIA CUDA, architettura e modello di programmazione

6. NVIDIA CUDA, architettura e modello di programmazione

6.1. Introduzione

L’inconveniente di sviluppare in linguaggio MATLAB consiste che questo è interpretato e

quindi la velocità di elaborazione non è elevata; per ridurre i tempi di test dell’algoritmo,

soprattutto nella fase di addestramento, si è reso necessario fare delle ottimizzazioni per

velocizzare i calcoli. Da osservare che dalla fase di caricamento delle immagini

all’addestramento della macchina a vettori di supporto sulle ROI ricavate sono richieste

diverse ore di elaborazione (per testare solo una feature); questo comporta che se si fa una

modifica a una o più fasi che precedono l’addestramento è necessario rifare tutti i calcoli da

capo e quindi ciò rende impraticabile la possibilità di verificare velocemente eventuali

aggiunte per migliorare il comportamento dell’algoritmo. Come conseguenza si hanno tempi

elevati di sviluppo del software (ogni modifica deve essere testata e richiede ore per la

verifica) e tempi lunghi per la correzione di bug; per risolvere questo inconveniente, che

compromette lo sviluppo veloce del software, una parte del codice degli script MATLAB è

stata riscritta tramite delle mex. Una mex non è altro che una funzione richiamabile dal

MATLAB ma sviluppata in C/C++; questo permette alla mex di sfruttare qualunque

tecnologia compatibile con i linguaggi C/C++. Le unità di elaborazione disponibili in un

moderno calcolatore sono le CPU e GPU; per la SVM si è deciso di sfruttare le mex della

libreria libsvm e di riscrivere alcune parti di codice degli script MATLAB (che tipicamente non

subiscono modifiche durante eventuali tentativi di miglioramento) sfruttando la tecnologia

CUDA su GPU. L’inconveniente della libreria libsvm è che è in grado di sfruttare un solo core

della CPU, per questo motivo si è deciso di riscrivere alcuni loop for delle mex tramite

OpenMP e ciò permette di sfruttare tutti i core durante la fase di addestramento e

classificazione della macchina. Le mex che sfruttano la tecnologia CUDA, lo possono fare

perché CUDA C è un’estensione del linguaggio C; lo svantaggio è che il MATLAB non

permette di rappresentare le variabili passate alle mex nella pinned memory e ciò comporta

un dimezzamento della velocità di scambio dei dati tra CPU e GPU. Per ridurre il più

quest’ultimo inconveniente, sono stati ridotti il più possibile le allocazioni in memoria di

variabili e trasferimento dei dati tra CPU e GPU. Altro inconveniente causato

dall’impossibilità di sfruttare la pinned memory (detta anche free page locked memory) è

che non si può sfruttare nemmeno l’overlap cioè trasferire dati tra host e device e

contemporaneamente eseguire l’elaborazione del kernel.

Si è scelto di sfruttare l’elaborazione su GPU perché questa è estremamente più

performante di una qualunque CPU di ultima generazione quando è necessario elaborare

migliaia di thread (com’è possibile fare in questo lavoro di tesi).

64 NVIDIA CUDA, architettura e modello di programmazione

Sul mercato esistono delle alternative a CUDA dal punto di vista architetturale e modello di

programmazione per quanto riguarda l’elaborazione lato GPU:

ATI Stream è una tecnologia introdotta da AMD / ATI per l’elaborazione di tipo

GPGPU, al momento attuale le feature implementate e le prestazioni sono inferiori

rispetto a CUDA, inoltre la programmazione è più complessa rispetto al modello

utilizzato in CUDA C;

OpenCL è uno standard per l’elaborazione generica su GPU alla cui definizione

partecipa la stessa NVIDIA, esistono molte analogie con CUDA ma allo stato attuale

la programmazione è più complessa, le prestazioni sono nettamente inferiori a

un’applicazione CUDA e le feature limitate (non è possibile accedere a determinate

caratteristiche dell’hardware come ad esempio la cache dedicata partizionabile in

cache condivisa e di livello uno);

DirectXCompute è l’API DirectX undici dedicata per il GPGPU, allo stato attuale ha le

medesime limitazioni di OpenCL (programmazione complessa, prestazioni inferiori a

un’applicazione CUDA, feature limitate) e inoltre può essere impiegata

esclusivamente su sistemi operativi Microsoft.

Se si vuole realizzare un’applicazione di calcolo intensivo in grado di sfruttare al massimo la

potenza di elaborazione delle GPU è quindi necessario impiegare la tecnologia CUDA; se

invece si vuole la piena compatibilità con tutte le GPU pur accettando di perdere efficienza

di calcolo dal punto di vista velocistico allora è necessario utilizzare OpenCL

(DirectXCompute se si vuole eseguire l’applicazione solo su sistemi operativi Windows).

E’ necessario fare altre osservazioni:

CUDA fa riferimento al mercato delle workstation professionali di cui quasi il 93%

(nel 2010) appartiene a NVIDIA, quindi non ci sono problemi di diffusione di

applicazioni CUDA (tutte le schede video NVIDIA professionali dal 2007 supportano

CUDA);

Più del 50% del fatturato di NVIDIA deriva dal mercato delle workstation

professionali, per questo motivo l’azienda sta investendo molto di più in ambito

professionale anziché consumer (AMD / ATI sta facendo l’opposto). Il risultato è che

l’architettura da generazione a generazione diventa sempre più efficiente per i

calcoli generici e tutto ciò ha comportato la diffusione di applicazioni professionali

che sfruttano CUDA come ad esempio Autodesk 3ds Max 2011 (con NVIDIA PhysX),

AutoCAD, ambito militare;

NVIDIA non ha una licenza per progettare e distribuire processori x86, quindi non è

in grado di contrastare direttamente le soluzioni dell’Intel e AMD correnti con GPU

sullo stesso die della CPU. Questo significa che l’unica strada percorribile da NVIDIA

per rimanere nel mercato delle GPU è di introdurre alternative valide per

l’elaborazione di tipo general purpose;

65 NVIDIA CUDA, architettura e modello di programmazione

Occorre osservare che esiste anche un compilatore CUDA x86, in questo modo è

possibile utilizzare lo stesso modello di programmazione CUDA non solo su GPU ma

anche su CPU x86. Questo significa che se la macchina sulla quale è necessario

eseguire l’elaborazione mediante CUDA non è dotata di una GPU NVIDIA, allora è

possibile eseguire il medesimo codice su CPU ovviamente con una riduzione di

prestazioni dato che il numero di core è ridotto rispetto alle GPU.

In questo lavoro si presenterà l’architettura delle GPU NVIDIA e il modello di

programmazione CUDA. In appendice A e B sono riportati i concetti fondamentali

dell’elaborazione grafica che fanno riferimento alle specifiche DirectX undici, questi sono di

fondamentale importanza per capire le elaborazioni eseguite dalle unità presenti

nell’architettura della GPU in questione (e in generale per tutte le GPU).

6.2. GPU come computer parallelo

Fino al 2003 i microprocessori erano basati su una singola unità centrale di elaborazione

(CPU) come ad esempio i prodotti dell’Intel Pentium e AMD Opteron; da una generazione

all'altra c’era un incremento prestazionale che seguiva la legge di Moore. Le prestazioni in

ambito desktop erano arrivate fino a qualche giga di operazioni in floating-point per

secondo (GFLOPS) e per i cluster di server fino a centinaia di GFLOPS. Grazie al

miglioramento delle prestazioni delle CPU da una generazione all’altra, gli sviluppatori

software erano stati in grado di aggiungere nuove funzionalità alle proprie applicazioni

(miglioramento della GUI, implementazione di algoritmi complessi in ambito scientifico per

simulazioni ecc.) e queste potevano beneficiare di un incremento prestazionale dal punto di

vista della velocità di elaborazione con il passaggio da una generazione di CPU a un’altra.

Gran parte del software in commercio era sviluppato secondo la logica sequenziale descritta

da Von Neumann 1945, solo poche applicazioni erano sviluppate specificatamente per

l’elaborazione parallela (tipicamente in ambito scientifico); dal 2003 i produttori di CPU non

potevano più aumentare le prestazioni delle proprie architetture semplicemente

incrementando la frequenza di clock a causa del consumo energetico e dissipazione

eccessiva, l’unico modo per migliorare la velocità di calcolo era di aumentare il numero di

unità di elaborazione (oltre che rendere più ottimizzate le architetture e aumentare la

cache). Da allora i produttori software sono migrati dalla programmazione sequenziale a

quella parallela, attualmente esistono molti applicativi che sono sviluppati per le nuove

architetture multicore delle CPU e quindi che sono in grado di beneficiare della potenza di

calcolo a disposizione. Oltre alle CPU, nelle workstation moderne, esistono altre unità di

elaborazioni sofisticate ossia le GPU che sono nettamente superiori nell’ambito

dell’elaborazioni multithreading intensive nel calcolo numerico rispetto alle CPU.

Le CPU attuali hanno diversi core per eseguire le computazioni (ad esempio dodici per gli

ultimi AMD Opteron), oltre a queste architetture ne esistono altre che hanno molte più

unità di elaborazione ossia le GPU (Graphics Processing Unit); nell’architettura Fermi si ha

un massimo di 512 CUDA core. Oltre alla notevole differenza nel numero di unità di

66 NVIDIA CUDA, architettura e modello di programmazione

elaborazione tra CPU e GPU è necessario osservare che esiste anche un notevole divario

prestazionale nell’elaborazione in floating-point che si assesta a cento GFLOPS e un TFLOPS

rispettivamente per CPU e GPU. Di seguito si riporta l’evoluzione prestazionale

nell’elaborazione in floating-point negli anni:

Figura 35 GPU vs CPU floating-point

L’architettura tra questi due dispositivi di elaborazione è notevolmente differente:

I core delle CPU sono progettati per eseguire una serie di operazioni su uno stream di

dati (in modo sequenziale);

I core delle GPU sono ottimizzati per eseguire elaborazioni in parallelo su molti flussi

di dati e no su uno solo;

Nelle CPU i transistor sono utilizzati per le feature hardware come predizione delle

ramificazioni nell’esecuzione d’istruzioni di un applicativo, cache e inoltre il singolo

core è ottimizzato per l’esecuzione di un solo thread nel caso di AMD invece per Intel

due o quattro thread (dipende dal modello di CPU, in questo caso si parla di

processori virtuali che sfruttano la tecnologia Hyperthreading);

I transistor nelle GPU sono utilizzati per realizzare gli array di processori, gestire via

hardware decine di migliaia di thread in modo concorrente, FPU (Floating Point

Unit), memoria condivisa e controller di memoria;

La latenza della memoria di sistema è mascherata da CPU mediante una cache

grande e hardware di branch prediction;

La latenza della memoria nelle GPU è mascherata con il fatto che è possibile eseguire

in modo concorrente molti thread e se i thread sono in attesa per l’accesso alla

memoria, allora la GPU può eseguire lo switch verso un altro insieme di thread senza

penalità (nel caso della CPU sono necessari diversi cicli di clock). Soltanto quando la

strategia descritta non si può usare allora la GPU sfrutta la cache per mascherare la

latenza;

67 NVIDIA CUDA, architettura e modello di programmazione

SIMD vs SIMT. Le CPU moderne sfruttano anche unità SIMD (Single Instruction

Stream, Multiple Data Stream) per vector processing; le GPU impiegano SIMT (Single

Instruction Stream, Multiple Thread Stream) per scalar thread processing, SIMT non

richiede l’organizzazione dei dati in vettori come invece SIMD impone;

La banda di memoria della GPU è dieci volte superiore a quella della CPU dato che i

memory controller stanno sul die e anche per il fatto che per le CPU c’è il vincolo di

compatibilità con sistemi operativi e applicazioni legacy e accesso da parte dei

dispositivi di I/O;

Figura 36 GPU vs CPU banda di memoria

L’architettura delle GPU è modellata in base alle esigenze dell’industria dei video

giochi che richiede di eseguire un numero elevatissimo di operazioni in floating-point

per frame, questo ha contribuito a massimizzare l’area del chip dedicata alla FPU

(Floating Point Unit). Gran parte delle GPU utilizzano il formato in virgola mobile in

singola precisione, questo è un problema per le applicazioni che richiedono la doppia

precisione per l’elaborazione, solo di recente le GPU sono passate all’elaborazione in

double-precision;

Le GPU sono altamente ottimizzate per l’esecuzione in parallelo di molti thread (a

differenza delle CPU che sono in grado di gestire un thread per core per AMD o 2 – 4

thread nel caso di Intel mediante la tecnologia Hyperthreading). La logica di controllo

dei thread è molto più semplice che quella impiegata nella CPU e ciò permette di

eseguire in modo concorrente tanti thread e fare il context switch senza costo, si ha

anche a diposizione un piccolo quantitativo di cache per ogni multiprocessore in

modo tale che i thread non debbano necessariamente accedere alla GDDR DRAM.

Le applicazioni attuali, per sfruttare a pieno le potenzialità delle unità di elaborazione

presenti sul mercato, devono essere sviluppate in modo tale che la parte sequenziale di

68 NVIDIA CUDA, architettura e modello di programmazione

elaborazione sia eseguita su CPU e il calcolo numerico intensivo parallelo su GPU; da queste

osservazioni sono nati il modello di programmazione CUDA e la relativa architettura

hardware (Compute Unified Device Architecture) che permette di eseguire un’applicazione

su CPU e GPU (questo modo di eseguire elaborazioni prende il nome di elaborazione

eterogenea e riguarda l’esecuzione delle varie operazioni sul processore più adatto). In

passato, il GPGPU (General Purpose Graphics Processor Unit) richiedeva l’utilizzo di apposite

API (OpenGL o Direct3D) per accedere alle funzionalità delle GPU ma questo era un notevole

limite dato che si era legati esclusivamente alle API. L’API grafica richiede di salvare i dati

come texture, di usare specifici indirizzi dei registri, non permette di accedere a funzionalità

specifiche dell’hardware, richiede una conoscenza ampia dell’API. Con CUDA l’approccio

cambia completamente, i programmatori possono sviluppare le applicazioni direttamente in

CUDA C (estensione del C) per GPU e usare qualsiasi linguaggio lato CPU, quindi senza dover

usare apposite API grafiche. Il principale vantaggio è che tramite CUDA è possibile accedere

a delle feature hardware che tramite le API grafiche non sono accessibili, in particolare, la

cache condivisa tra i thread per ogni Streaming Multiprocessor (che permette di salvare dati

che sono usati spesso dai thread del medesimo warp), salvare i dati in qualsiasi indirizzo e

non serve tradurre il problema da risolvere in termini di concetti di elaborazione grafica

(come texture). Tutto ciò è possibile perché sul chip di silicio c’è un’apposita area dedicata

all’interfacciamento con applicazioni sviluppate tramite CUDA C.

CUDA è un modello di programmazione e architettura hardware che permette di usare molti

core della GPU per calcoli matematici general purpose. Attualmente esiste anche il

compilatore della PGI che permette di usare il medesimo modello di programmazione CUDA

anche su CPU X86; quindi è possibile eseguire codice CUDA su CPU multicore ad esempio

quando la macchina non ha a disposizione una GPU NVIDIA.

Per quanto riguarda la programmazione parallela nell’ambito delle CPU, il principale

problema è legato alla gestione dei cluster di CPU da parte dell’applicazione che deve essere

divisa in più thread da eseguire in modo concorrente sui core a disposizione; dato che le CPU

sono essenzialmente dei processori per eseguire calcoli in modo sequenziale, avere più

processori richiede la scrittura di codice in modo piuttosto complesso. Con CUDA la

programmazione è molto più semplice da gestire, questo modello prevede

l’implementazione di un algoritmo sequenziale (chiamato kernel) il quale è caricato dalla

GPU che esegue migliaia d’istanze del medesimo (ogni istanza è un thread che opera su dati

indipendenti). CUDA C è un’estensione del linguaggio di programmazione C, questo

semplifica notevolmente il porting delle applicazioni attuali C su questo tipo di architettura.

Per realizzare un’applicazione in CUDA tipicamente si seguono i seguenti passi:

S’individuano i colli di bottiglia del programma e relative porzioni di codice su CPU

che possono essere parallelizzate (sfruttando il paradigma data parallelism, ossia

ogni dato può essere elaborato in modo indipendente);

Per ogni porzione parallelizzabile s’implementa il kernel;

69 NVIDIA CUDA, architettura e modello di programmazione

Il kernel è caricato dalla GPU ed è applicato a uno specifico data set;

Per ogni elemento del data set è istanziato il kernel, ogni istanza prende il nome di

thread (formato dal program counter, registri e stato)

6.3. Architettura NVIDIA Fermi GF110

In questo paragrafo si analizzano in dettaglio gli aspetti salienti dell’architettura CUDA

GF110 (Graphics Fermi). Dall’analisi della pipeline grafica descritta in appendice A e dalle

soluzioni architetturali della NVIDIA, sarà subito chiaro che l’azienda di Santa Clara ha deciso

di introdurre dove possibile unità general purpose per rendere la GPU sempre più simile alla

CPU in contrapposizione all’AMD / ATI che invece utilizza in modo massiccio unità dedicate

soprattutto per applicare la tecnica di tessellation. La NVIDIA ha assegnato a

quest’architettura il nome di CUDA per specificare che la GPU oltre ad essere in grado si

eseguire elaborazioni grafiche è anche capace di fare calcoli intensivi generici per

applicazioni generiche.

Di seguito si riporta la figura relativa all’architettura completa di una GPU CUDA Fermi

GF110 costituita da tre miliardi di transistor con processo produttivo a quaranta nm:

Figura 37 Architettura GF110

La differenza da un modello all’altro in questa generazione di GPU sta nel numero di GPC

(Graphics Processing Clusters che rappresenta un gruppo di calcolo), di memory controller,

ROP, frequenze di clock e il numero di SM (alcuni di questi sono disattivati per motivi di resa

produttiva, quindi se ci sono degli SM non funzionanti si può comunque procedere alla

certificazione della GPU per un’altra classe).

70 NVIDIA CUDA, architettura e modello di programmazione

Di seguito si riporta la descrizione di ogni componente di quest’architettura:

Host interface. Rappresenta l’interfaccia tramite la quale l’host e device sono in

grado di comunicare fra loro (per host s’intende la CPU e per device GPU);

GigaThread Engine. E’ una nuova tecnologia introdotta dalla NVIDIA che permette di

gestire migliaia di thread da eseguire in parallelo sulla GPU (assegna i thread agli SM)

e accedere al frame buffer;

Memory controller. Sono i controller per gestire l’accesso alla memoria video;

L2 Cache. E’ la cache di secondo livello, ci sono 128 KB assegnati a ogni specifico

memory controller per un totale di 768 KB;

ROP. Render output unit o più propriamente detta raster operations pipeline è l’unità

utilizzata per eseguire uno degli ultimi passi del rendering, in GF110 ci sono 48 ROP

(riguarda unicamente l’elaborazione grafica, per dettagli vedere l’appendice A);

GPC. Graphics processing cluster è l’unità grafica di elaborazione costituita dagli SM

(4) e Raster Engine (1);

Raster Engine e Polymorph Engine. Sono le unità per gestire la tessellation (fare

riferimento all’appendice A per dettagli).

SM. Uno streaming multiprocessor è il processore utilizzato per elaborare in parallelo

molti flussi di dati (32 SM);

SP. Streaming processor, detto anche CUDA core, è l’unità di elaborazione generica

per il singolo flusso di dati (32 per ogni SM per un totale di 512 CUDA core);

Nei successivi paragrafi si andrà a descrivere in dettaglio ogni singolo componente di

quest’architettura (eccetto quelli che sono impiegati esclusivamente per l’elaborazione

grafica, in questo caso è necessario per ulteriori dettagli fare riferimento all’appendice A)

6.3.1. Host Interface

L’host interface è utilizzato per leggere i comandi inviati dalla CPU alla GPU; per ogni

comando grafico restituisce lo stato d’esecuzione ed eventuali dati di ritorno alla CPU

(quindi otre a leggere dalla memoria centrale è in grado anche di scrivere nella memoria

centrale). Si sfrutta anche durante l’elaborazione in CUDA per gestire le interazioni tra host

e device.

6.3.2. Memory Controller

Ci sono sei memory controller per l’accesso alla memoria video di tipo GDDR5 (Graphics

Double Date Rate) DRAM detta frame buffer e ognuno sfrutta un’interfaccia a 64 bit per un

totale di 384 bit di bus per l’accesso al frame buffer. La differenza tra GDDR DRAM e DDR

DRAM di sistema sta nel fatto che la prima è utilizzata come memoria per memorizzare dati

grafici o dati generici per un’applicazione CUDA, invece la seconda tipologia è utilizzata per

memorizzare dati generici non legati alla grafica. Per le applicazioni grafiche, nella GDDR

sono memorizzate le immagini video, informazioni sulle texture per il rendering 3D; invece

per CUDA è utilizzata come memoria generica con elevata banda (5 – 10 volte maggiore a

quella della DRAM di sistema utilizzata dalla CPU).

71 NVIDIA CUDA, architettura e modello di programmazione

6.3.3. Gerarchia memoria

Di seguito si descrive la gerarchia della memoria utilizzata all’interno di GF110:

Figura 38 Gerarchia memoria

La cache L1 è dedicata alle operazioni di load e store, non era presente fino all’architettura

GT200; in GF110 permette di incrementare le prestazioni soprattutto in simulazioni di fisica

e di ray tracing. La cache condivisa è invece presente in quantitativo di 16 KB dalle soluzioni

GT200. Quest’ultima è impiegata per condividere dati tra thread del medesimo warp.

In GF110 la cache dedicata è di 64 KB ed è di tipo partizionabile; le proporzioni possono

essere di 3:1 (48 KB / 16 KB) o 1:3 (16 KB / 48 KB) per memoria condivisa e cache L1.

Le unità di texture (4) hanno una cache dedicata all’interno di ogni SM in quantitativo pari a

12 KB: in questo caso il valore è rimasto invariato rispetto a quanto implementato nelle GPU

GT200.

A completare la gerarchia della cache c’è la cache L2 integrata nella GPU e condivisa tra i

vari SM; la quantità di memoria è di 768 KB cioè 128 KB dedicato a ogni memory controller.

La gerarchia della memoria segue il medesimo approccio impiegato nelle CPU multicore di

ultima generazione, ove, le strutture di cache dedicate al singolo core sono tutte raccordate

da una più ampia (solitamente di terzo livello).

72 NVIDIA CUDA, architettura e modello di programmazione

Figura 39 Cache L2 unificata

6.3.4. GDDR5

Nell’architettura Fermi il tipo di memoria che si utilizza per il frame buffer è la

GDDR5 (Graphics Double Data Rate), questa è basata sulla tecnologia double date rate

specifica per le schede video in sostituzione all’obsoleta VRAM (Video RAM). Il frame buffer

è utilizzato dalla GPU per memorizzare informazioni relative al rendering o per i dati per il

kernel sviluppato tramite CUDA C; GDDR5 è utilizzata in luogo della memoria DDR DRAM di

sistema dato che quest’ultima è più lenta di quella utilizzata nelle GPU (il requisito

fondamentale per la memoria video è un’elevata velocità in lettura e scrittura). Il bus,

nell’architettura Fermi, è di 384 bit dato che ci sono sei controller di memoria a 64 bit.

L'obiettivo delle memorie GDDR5 è di garantire un transfer rate elevatissimo, attualmente

con i chip Samsung si è raggiunto 24 GBit/s (DDR 3 arriva a 1.5 GBit/s),

contemporaneamente a un risparmio energetico maggiore del 20% rispetto alla generazione

precedente ossi alla GDDR4 grazie anche alla riduzione della tensione operativa a 1.5 V. Le

GDDR5 usano un prefetch buffer a 8 bit (il prefetch buffer serve per raccogliere i dati da

inviare alla successiva interfaccia più veloce) come le GDDR4 ma offrono alcune innovazioni:

le GDDR5 hanno due frequenze di clock ossia CK e WCK (la seconda lavora a frequenza

doppia rispetto alla prima). I comandi sono trasferiti in modalità single data rate (SDR) alla

frequenza CK quindi con trasferimento sul solo fronte di salita del clock, gli indirizzi sono

trasferiti in double data rate (DDR) alla frequenza CK, i dati invece sono trasferiti in DDR alla

frequenza WCK. Tale approccio permette di ridurre i problemi legati alla qualità del segnale

durante la trasmissione dei comandi e degli indirizzi, mentre accede a una frequenza

superiore per la trasmissione dati. Siccome a frequenze maggiori si ha una maggiore

probabilità di errore, in questo tipo di memoria è implementato anche un meccanismo di

rivelazione di tali errori al fine di garantire l'integrità dei dati trasmessi.

6.3.5. GigaThread Engine

Il GigaThread engine raccoglie i dati necessari dalla memoria di sistema e li copia nel frame

buffer passando attraverso i memory controller; a questo punto, crea blocchi di thread

chiamati warp e li invia agli SM. Il GigaThread entra in funzione anche per redistribuire i

compiti alle singole unità di elaborazione.

73 NVIDIA CUDA, architettura e modello di programmazione

Una delle caratteristiche più rilevanti del GigaThread engine di GF110 è che è in grado di

inviare kernel in parallelo anziché sfruttare l’approccio “un kernel alla volta” tipico

dell’architettura Tesla precedente; il numero massimo di kernel gestibili è pari a sedici. Tale

tecnologia ottimizza la schedulazione dei thread da gestire al fine di sfruttare al meglio le

unità d'elaborazione a disposizione. Il processore è in grado di processare fino a 24576

thread e può far eseguire più thread in parallelo all'interno di ogni SM al fine di ottimizzare

l'utilizzo dei CUDA core.

6.3.6. Streaming Multiprocessor

Lo stream processing è un paradigma di programmazione parallela che prevede l’esecuzione

di una serie di operazioni su dati organizzati in gruppi detti stream. Uno streaming

multiprocessor è un’unità in grado di elaborare contemporaneamente flussi multipli di dati

(in parallelo), uno streaming processor invece esegue l’elaborazione su un singolo stream di

dati.

Di seguito si riporta in dettaglio l’architettura di uno Streaming Multiprocessor:

Figura 40 Streaming Processor

Uno SM ha trentadue CUDA core:

A gruppi di quattro sono associati a due unità di load e store (LD/ST);

A gruppi di otto sono abbinati a un’unità di tipo special function (SFU), la quale

esegue elaborazioni in floating point con le funzioni trascendenti (tutte le funzioni di

tipo non algebrico che non utilizzano le quattro operazioni elementari dell’aritmetica

e le potenze e radici come seno, coseno, seccante, tangente ecc).

74 NVIDIA CUDA, architettura e modello di programmazione

A monte dello SM c’è la cache per le istruzioni, seguita da due warp scheduler, da due unità

per le operazioni di dispatch le quali sono collegate al registro dei file capace di gestire un

massimo di 32.768 entry a 32bit.

Per ogni streaming multiprocessor si ha una cache dedicata a 64 KB partizionabile come

memoria condivisa e come cache L1: i rapporti sono 1:3 oppure 3:1. Il rapporto è funzione

del tipo di applicazione che deve essere eseguita, nell’architettura precedente GT200 si

aveva una memoria cache da 16 KB non partizionabile.

Ogni SM integra al proprio interno quattro texture unit, per un totale quindi di 64 unità di

questo tipo; le texture unit sono dotate di una propria cache dedicata integrata all'interno

dello specifico SM che serve per accelerare le operazioni di gestione delle texture.

6.3.7. Instruction cache

La cache istruzioni è di 12 KB, serve per accelerare il prelievo delle istruzioni da eseguire;

occorre osservare che ogni warp è formato da thread che devono eseguire le medesime

operazioni però su dati differenti.

6.3.8. Dual warp scheduler e dispatch unit

Il G80 era la prima GPU in grado di supportare la tecnologia CUDA (2007), tutte le

architetture prima dell’evento del GF100/GF110 richiedono che gli SM lavorino sullo stesso

kernel (funzione/programma/loop) allo stesso istante; nelle generazioni precedenti, se il

kernel non era abbastanza grande da occupare l’esecuzione di tutto l’hardware, allora

alcune unità potevano restavano in idle con conseguente riduzione dell’efficienza

nell’utilizzo della GPU. Occorre osservare che l’architettura delle GPU permette di ottenere

notevoli vantaggi dal punto di vista della velocità d’elaborazione solo se l’utilizzo

dell’hardware è vicino al 100%.

In GF110 è possibile eseguire kernel multipli in parallelo, ciò permette alla GPU di scalare il

numero di core nel chip senza decrementare l’efficienza. Di seguito si riporta un esempio di

elaborazione prima dell'introduzione dell'architettura in GF110 (a sinistra) e quella attuale

(a destra):

Figura 41 Esecuzione kernel su G80/GT200 e GF110

75 NVIDIA CUDA, architettura e modello di programmazione

L’architettura Fermi è migliorata anche nello switch tra modalità grafica e CUDA di un fattore dieci; ora è possibile fare lo switch più volte in un frame e questo permette di sfruttare meglio la GPU ad esempio per l’accelerazione della fisica nei video giochi.

L’architettura Tesla GT200 riesce a gestire un numero enorme di thread, oltre 30000 thread al volo; con GF110, il numero è sceso a circa 24000 per ridurre la complessità dell’hardware di gestione dei thread e aumentare la memora condivisa negli SM.

Figura 42 Gestione thread nelle architetture CUDA

Ogni SM ha due warp scheduler e due unità di dispatch. I due schedulatori del GF110

selezionano due warp che sono distribuiti su trentadue CUDA core. Nel GT200 e G80, la

metà di ogni warp è distribuita su un singolo SM ed eseguita in un singolo ciclo di clock, cioè

richiede due cicli di clock per completare un warp (senza branch condition), inoltre la logica

di dispatch per la SM è strettamente legata all’hardware di esecuzione. Se un thread

richiede l’elaborazione con una SFU, allora sull’intero SM non può essere distribuita una

nuova istruzione fino a quando l’istruzione che occupa la SFU non è stata eseguita

completamente. Questo porta a una notevole riduzione d’efficienza nell’utilizzo della GPU;

questo problema è superato nell’architettura Fermi con due unità di dispatch indipendenti

in ogni SM e queste sono completamente disaccoppiate dal resto dello SM. Ogni unità di

dispatch può selezionare e distribuire metà del warp per ciclo di clock, i thread possono

provenire da differenti warp in modo da ottimizzare la possibilità di individuare operazioni

indipendenti.

L’inflessibilità della gestione dei thread nell’architettura NVIDIA consiste nel fatto che ogni

thread nel warp deve eseguire la stessa istruzione contemporaneamente, se ciò accade, si

ha il pieno utilizzo delle risorse a disposizione altrimenti alcune unità resteranno in idle

(path d’esecuzione diversi sono eseguiti in modo seriale e quindi alcuni CUDA core non sono

sfruttati).

Di seguito si riporta il numero di operazioni per clock che uno SM è in grado di eseguire:

Figura 43 Ops per clock per le istruzioni eseguibili da uno SM

Nel GF110 le SFU non bloccano l’intero SM, questo significa che se una o più SFU sono

utilizzate da mezzo warp si hanno comunque altri sedici CUDA core liberi per l’elaborazione.

Nelle architetture precedenti l’intero SM restava bloccato per otto cicli di clock per eseguire

76 NVIDIA CUDA, architettura e modello di programmazione

le istruzioni tramite le SFU (se tutte e quattro le SFU erano utilizzate). Con il nuovo

approccio è possibile eseguire molte istruzioni in modo concorrente: due istruzioni su interi,

due istruzioni su floating point o un mix d’istruzioni per interi, floating point, load, store e

SFU.

Figura 44 Distribuzione delle istruzioni all'interno di uno SM

6.3.9. Register file

Un register file è un array di registri del processore (SM) implementato tramite memoria

RAM statica con porte multiple e ogni porta è di lettura e scrittura; questi registri

organizzano i dati tra memoria e unità funzionali del chip. Il register file è visibile in fase di

programmazione.

6.3.10. LD/ST

Siccome CUDA C è un’estensione del C/C++, per utilizzare questo linguaggio di

programmazione la NVIDIA ha deciso di aggiungere delle unità per gestire le istruzioni di

load e store.

Ogni SM ha sedici unità di load/store che supportano il load e store a qualsiasi indirizzo di

cache e DRAM.

6.3.11. SFU

Ogni SM ha quattro special function unit (SFU), ogni SFU è in grado di eseguire istruzioni

trascendenti come sin, cos, esponenziale, logaritmo, reciproco, radice quadrata e anche i

calcoli d’interpolazione grafica; la pipeline SFU è disaccoppiata dal dispatch unit in modo tale

che sia possibile eseguire altre elaborazioni con i CUDA core quando la SFU è occupata. A

trarre particolare beneficio dall’hardware dedicato alle special function è l’elaborazione

intensiva attraverso shader.

6.3.12. Texture Unit

Ogni SM ha quattro unità per la gestione delle texture, ogni unità di texture calcola

l’indirizzo della texture ed esegue la fase di fetch della medesima per clock (quindi sono

gestite quattro texture per ogni ciclo clock in ogni SM). Il risultato restituito può essere

filtrato: bilineare, trilineare e anisotropico o niente.

77 NVIDIA CUDA, architettura e modello di programmazione

Il vantaggio in GF110 delle texture unit rispetto alla generazione precedente consiste nel

fatto che le texture sono gestite più velocemente perché è stata migliorata l’efficienza di

queste unità; infatti, ora, le unità di texture sono raggruppate all’interno degli SM, si ha

cache dedicata esclusivamente per la gestione delle texture e il clock delle texture unit /

texture cache è maggiore rispetto alla generazione precedente.

Inoltre è supportato il nuovo formato di compressione delle texture DirectX 11 BC6H e BC7

che permette di ridurre la memoria occupata dalle texture per la gestione HDR (High

Dynamic Range) e per il target da renderizzare.

6.3.13. CUDA Core

Di seguito si riporta la struttura completa di uno streaming processor detto anche CUDA

core:

Figura 45 CUDA Core

Uno SM ha trentadue SP, quindi in totale ci sono 512 CUDA core nell’architettura GF110.

Un CUDA core è un’unità di elaborazione in grado di eseguire una serie di operazioni su

flussi di dati multipli in modo efficiente e performante; ogni singolo CUDA core integra al

proprio interno una Dispatch Port, un’unità per la raccolta degli operandi, una FPU, un’ALU

e in fine una Result Queue.

6.3.13.1. Operand collector

L’Operand Collector è un’unità hardware che legge molti valori dai registri e li bufferizza per

un utilizzo successivo, è una sorta di cache per registri temporanei per le unità funzionali;

quindi l’Operand Collector legge gli operandi necessari per le operazioni da eseguire (ad

esempio per le SFU). Quest’unità è strettamente legata al Register File ma è anche in grado

di prelevare gli operandi da altre sorgenti ossia memoria condivisa, cache L1 e texture

cache.

6.3.13.2. FPU

In GF110 l’elaborazione in floating-point supporta i numeri subnormali via hardware e lo

standard IEEE 754-2008 con le quattro approssimazioni: nearest, zero, positive infinity e

negative infinity. I numeri subnormali sono quelli tra lo zero e il più piccolo numero

78 NVIDIA CUDA, architettura e modello di programmazione

normalizzato dato un sistema numerico floating-point. Nelle generazioni precedenti di GPU

questi numeri sono posti direttamente a zero con perdita di precisione. Tipicamente nelle

CPU il calcolo dei numeri subnormali è gestito via software e richiede migliaia di cicli di

clock, in Fermi le FPU gestiscono questi numeri via hardware senza penalità in termini di

prestazioni.

In computer grafica, algebra lineare e applicazioni scientifiche spesso si ha l’esigenza di

moltiplicare due numeri e poi sommare il risultato a un altro numero per esempio D = A x B

+ C. Prima di GF110, questa funzione era accelerata mediante l’istruzione multiply-add

(MAD) che permette di eseguire entrambe le operazioni in un singolo ciclo di clock; la MAD

esegue un’approssimazione dopo la moltiplicazione e subito dopo esegue la somma con

approssimazione nearest. Nell’architettura Fermi, si sfrutta invece l’istruzione fused

multiply-add (FMA) sia a 32 bit (single precision) sia a 64 bit (double precision) e questo

migliora l’operazione di moltiplicazione e somma dato che non c’è l’approssimazione nel

passo intermedio di moltiplicazione. Tutto ciò garantisce notevoli benefici in termini di

precisione per molti algoritmi come ad esempio: minimizza l’errore di rendering di triangoli

vicini sovrapposti, migliore precisione nel calcolo matematico iterativo, migliore

approssimazione della divisione e operazioni di radice quadrata.

Figura 46 FMA vs MAD

6.3.13.3. ALU

In Fermi si utilizza una nuova ALU con supporto completo alla precisione a 32 bit per tutte le

istruzioni ed è consistente con i requisisti dei linguaggi di programmazione standard C/C++;

inoltre l’ALU è ottimizzata anche per operazioni a 64 bit.

Le istruzioni che sono supportate sono elencate di seguito: boolean, shift, convert, bit-field

extract, bit-reverse insert e conteggio.

6.3.13.4. Result queue

Il duale dell’Operand Collector è il Result Queue, questo bufferizza l’output delle unità

funzionali prima di eseguire la scrittura nel Register File; per essere efficace è necessario che

la dimensione sia almeno pari alla dimensione di un warp cioè trentadue operandi. Occorre

osservare che non tutti i risultati calcolati richiedono di essere scritti nel Register File, alcune

operazioni richiedono esclusivamente un risultato intermedio che successivamente sarà

79 NVIDIA CUDA, architettura e modello di programmazione

utilizzato in un’altra operazione; con quest’unità si garantiscono migliori performance senza

dover ogni volta andare a prelevare i risultati dal Register File.

6.4. Interfaccia CUDA

In questo paragrafo si andrà ad analizzare in dettaglio l’interfaccia CUDA, l’organizzazione

dei thread e in fine l’organizzazione della memoria dal punto di vista del modello di

programmazione CUDA.

6.4.1. Architettura

Di seguito si riporta l’architettura completa dell’interfaccia CUDA per la programmazione

GPGPU che permette la comunicazione tra host e device:

Figura 47 Architettura modello di programmazione CUDA

Per quanto riguarda la programmazione della GPU per elaborazioni generiche sono possibili

i seguenti casi:

Nell’API DirectX undici esiste la DirectXCompute. In questo caso si utilizza come

linguaggio di programmazione HLSL compute shader (che fa parte degli shader model

cinque), il compilato è inviato all’API DirectXCompute che si occupa della

comunicazione con GPU CUDA tramite il kernel del sistema operativo;

Con le OpenGL invece è necessario utilizzare OpenCL C come linguaggio di

programmazione e inviare il kernel al driver OpenCL. Quest’approccio richiede di

comunicare con un’API chiamata CUDA driver;

Applicazione CUDA che sfrutta direttamente l’API di basso livello CUDA driver per

comunicare con la GPU;

Applicazione CUDA che sfrutta l’API C runtime for CUDA per la comunicazione con la

GPU.

Nel seguito ci si concentrerà esclusivamente su CUDA e no su OpenCL e DirectXCompute.

80 NVIDIA CUDA, architettura e modello di programmazione

Quando si sfrutta il modello di programmazione CUDA, è necessario utilizzare una o

entrambe le API seguenti (tipicamente si utilizza una sola):

API di basso livello che prende il nome di CUDA driver;

API di alto livello chiamata C runtime for CUDA che è costruita sopra l’API

precedente.

C runtime for CUDA è la più utilizzata perché semplifica notevolmente la programmazione e

riduce il numero di righe di codice da scrivere dato che la gestione del device avviene

mediante inizializzazione implicita come pure la gestione del context e dei moduli. CUDA

driver API invece richiede molto più codice, aumenta la complessità della programmazione e

debugging ma offre un miglior livello di controllo; da osservare che queste due API sono

riferite all’host quindi il kernel in esecuzione sulla GPU sarà il medesimo indipendentemente

dall’API utilizzata.

Le due API sono facilmente distinguibili dato che CUDA driver è fornita dalla libreria

dinamica nvcuda.dll e le varie istruzioni hanno tutte il prefisso cu; mentre C runtime for

CUDA è fornita dalla libreria dinamica cudart.dll e tutte le istruzioni iniziano con suffisso

cuda. Da osservare che CUDA driver mette a disposizione le stesse funzionalità del C runtime

con l’aggiunta però di altre più di basso livello. D’ora in poi si farà riferimento

esclusivamente al C runtime for CUDA salvo dove indicato diversamente.

Nel CUDA driver è incluso anche il PTX ISA ossia il parallel thread execution virtual machine

instruction set architecture; PTX definisce la CUDA virtual machine e l’ISA virtuale per

l’elaborazione generica parallela tramite thread. Il compilatore CUDA genera un binario PTX

che rappresenta l’ISA virtuale per le GPU NVIDIA (codice assembler); un traslatore, che può

essere il compilatore o la macchina virtuale al runtime, esegue la traduzione da codice PTX

in codice binario per l’architettura fisica target. Nel caso in cui si sfrutti la virtual machine, il

vantaggio consiste nel fatto che al runtime è invocato il compilatore jit (just in time detto

anche jitter) per compilare e ottimizzare il codice per l’architettura della GPU che

l’applicazione CUDA utilizzerà (rende il codice PTX portabile fra GPU diverse); lo svantaggio è

che il caricamento dell’applicazione è più lento rispetto a un approccio completamente

compilato.

Ogni GPU ha un proprio compute capability che specifica le caratteristiche CUDA

supportate, il tutto è fornito con un major e minor number; le pipeline grafiche con lo stesso

major number utilizzano la medesima architettura mentre il minor number specifica

l’aggiunta di nuove feature. Di seguito si riporta la tabella del compute capability delle varie

pipeline grafiche:

81 NVIDIA CUDA, architettura e modello di programmazione

Figura 48 Capacità di calcolo CUDA

Di seguito invece si riportano le feature supportate per ogni compute capability.

Figura 49 Compute capability feature CUDA

Per sfruttare a pieno l’architettura CUDA è necessario che l’applicazione presenti un elevato

grado di data parallelism, questo significa che l’algoritmo è in grado di eseguire molte

operazioni aritmetiche in modo indipendente su ogni dato del data set. Come esempio si più

considerare il prodotto tra due matrici, la matrice prodotta è costituta da un insieme di

elementi ognuno dei quali è calcolato come prodotto tra colonna e riga della prima e

seconda matrice rispettivamente e relativa somma; ogni elemento può essere calcolato in

modo indipendente dagli altri, questo permette d’implementare un algoritmo in CUDA C

altamente ottimizzato per l’esecuzione su GPU.

82 NVIDIA CUDA, architettura e modello di programmazione

6.4.2. SIMT

L’architettura CUDA è costruita su un array scalabile di Streaming Multiprocessor; i thread

sono organizzati in blocchi e questi ultimi enumerati e distribuiti sui multiprocessori liberi. I

thread di un blocco di thread sono eseguiti in modo concorrente sul medesimo SM; quando

l’esecuzione dei blocchi su uno SM è finita, allora nuovi blocchi possono essere lanciati sullo

SM libero.

Un multiprocessore è progettato per eseguire migliaia di thread in modo concorrente; per

gestire un numero così elevato di thread, l’architettura impiegata è la SIMT (Single-

Instruction e Multiple-Thread).

I thread sono organizzati in warp, i warp a loro volta sono organizzati in blocchi di warp, ogni

warp è costituito da trentadue thread. I thread che fanno parte del medesimo warp iniziano

tutti assieme dallo stesso program address, ma ognuno ha il proprio instruction address

counter e register state e quindi sono liberi di eseguire ramificazioni di esecuzione diverse.

Metà warp può essere la prima o seconda metà di un warp, un quarte-warp può essere il

primo, secondo, terzo o quarto quarte di un warp.

Quando un multiprocessore deve eseguire blocchi di thread, i warp sono schedulati dal

warp scheduler; per la massima efficienza è necessario che i trentadue thread seguano il

medesimo path d’esecuzione. Se i thread di un medesimo warp divergono verso rami diversi

d’esecuzione, allora i vari rami sono eseguiti in modo seriale e i thread che appartengono al

medesimo ramo in parallelo; dopo aver terminato tutti i rami d’esecuzione, l’elaborazione

ricomincia di nuovo in parallelo per tutti i thread del medesimo warp. Questa divergenza si

può manifestare esclusivamente all’interno del medesimo warp dato che ognuno è

indipendente nell’esecuzione rispetto agli altri.

L’architettura SIMT è simile alla SIMD (Single-Instruction Stream Multiple-Data Stream) in

cui una singola istruzione controlla l’elaborazione su più elementi (i dati); la differenza tra le

due architetture consiste nel fatto che un’istruzione SIMD ha una dimensione massima per i

dati gestibili (pari a quattro), invece un’istruzione SIMT specifica l’esecuzione e il branching

behavior del singolo thread (non c’è un vincolo sul numero di dati).

Il contesto d’esecuzione (program counter, register, ecc.) per ogni warp elaborato dal

multiprocessore è mantenuto sul chip per tutto il ciclo di vita del warp; lo switching da un

execution context a un altro non ha alcun costo e a ogni instante d’esecuzione di

un’istruzione il warp scheduler seleziona un warp in cui i thread sono pronti per l’esecuzione

(thread attivi) e li distribuisce per la successiva istruzione da eseguire.

6.4.3. Organizzazione thread

CUDA C estende il linguaggio C permettendo al programmatore di definire delle funzioni che

prendono il nome di kernel e le quali sono eseguite su GPU; da codice il kernel è definito

come una funzione con qualificatore __global__; per istanziare il kernel, è necessario da

host utilizzare la sintassi <<<numero blocchi, numero thread per blocco, cache condivisa,

83 NVIDIA CUDA, architettura e modello di programmazione

cuda stream>>> che specifica come organizzare i thread. Le funzioni possono essere definite

anche con __device__ e __host__ che rappresentano rispettivamente funzioni eseguite e

invocate sul e dal device e host; __host__ è applicato implicitamente a tutte le funzioni

senza qualificatore. Ogni thread che esegue il kernel ha un identificatore univoco dato dalla

variabile threadIdx, questa è un vettore di tre dimensioni che permette l’identificazione

univoca del thread all’interno del blocco; ciò permette di eseguire l’elaborazione di elementi

di un data set in modo naturale ad esempio per il calcolo con vettori, matrici o volumi.

I thread sono organizzati in blocchi, questi sono ordinati in una griglia monodimensionale o

bidimensionale; il numero di thread per blocco in una griglia è individuato tipicamente dalla

dimensione dei dati da elaborare o dal numero di CUDA core nel sistema. Nell’invocazione

del kernel è possibile passare come primo parametro o int (per griglia monodimensionale) o

dim3 (per griglia bidimensionale); ogni blocco è identificato univocamente dalla variabile

blockIdx (mono o bidimensionale) e mette a disposizione la dimensione tramite blockDim

(mono o bidimensionale). I blocchi sono eseguiti in modo indipendente, questo permette di

scalare su un qualsiasi numero di processori.

Figura 50 Blocchi di thread

I CUDA thread possono accedere ai dati memorizzati in diversi spazi di memoria durante

l’esecuzione; ogni thread ha una memoria locale privata, i thread del medesimo blocco

possono salvare i dati nella memoria condivisa la quale è visibile a ogni thread dello stesso

blocco, tutti i thread possono accedere alla memoria globale (quella del device). Ci sono

ancora due spazi di memoria accessibili dai thread ma solo in lettura ossia la constant e

texture memory, questi sono ottimizzati per differenti tipi d’utilizzo e inoltre la texture

84 NVIDIA CUDA, architettura e modello di programmazione

memory permette differenti modalità d’indirizzamento come pure il filtraggio dei dati. La

global, constant e texture memory sono inoltre persistenti per tutti i lanci del kernel per la

medesima applicazione.

Figura 51 Gerarchia memoria

Occorre osservare che la memoria di sistema (quella dell’host) è separata da quella della

GPU, questo significa che è necessario un trasferimento dei dati tra memoria dell’host e

memoria del device; in CUDA C i puntatori alla memoria dell’host possono accedere

esclusivamente alle locazioni di memoria che stanno sull’host, i puntatori alla memoria del

device possono accedere esclusivamente alle locazioni che stanno sul device. Per eseguire la

comunicazione tra host e device si utilizzano opportune chiamate al C Runtime for CUDA

(tramite cudaMemcpy e simili).

6.4.4. Organizzazione della memoria

In questo paragrafo si andrà ad analizzare l’organizzazione della memoria a cui fa

riferimento un’applicazione CUDA sia per host sia per device:

Linear device memory. La linear memory è presente su device nella global memory e

utilizza uno spazio d’indirizzamento di trentadue e quaranta bit rispettivamente per

compute capability 1.x e 2.x; per l’allocamento e liberare le risorse si utilizzano le

chiamate cudaMalloc e cudaFree, per il trasferimento dei dati si utilizza

cudaMemcpy. C’è la possibilità di eseguire l’allocazione anche con altre due

chiamate al C runtime ossia cudaMallocPitch e cudaMalloc3D, queste permettono

rispettivamente di allocare vettori 2D e 3D in modo efficiente impiegando

l’allineamento in memoria. Le operazioni di copia sono eseguite in questo caso da

cudaMemcpy2D e cudaMemcpy3D;

Shared device memory. La memoria condivisa all’interno di ogni SM è molto più

veloce della memoria globale del device; la dimensione è ridotta, quindi è necessario

salvare in questa porzione di memoria i dati a cui i thread accedono più

frequentemente. L’allocazione avviene mediante __shared__;

Texture device memory. In ogni SM c’è una cache dedicata per la gestione delle

texture, questa memoria è molto più performante della memoria globale. Il kernel è

in grado di accedere a questa in lettura; l’operazione di fetch della texture avviene

mediante le funzioni che prendono il nome di texture fetch function device, il primo

85 NVIDIA CUDA, architettura e modello di programmazione

parametro di queste funzioni è un oggetto chiamato texture reference che specifica

quale parte della texture memory deve essere prelevata. Una texture reference ha

diversi attributi, in particolare si può specificare che l’accesso alla texture elemento

per elemento (ogni elemento è chiamato texel) può avvenire tramite un array a 1,2 o

3 dimensioni, il tipo di dati d’input e output della texture, interpretazione delle

coordinate e il tipo di filtraggio;

Surface device memory. La texture cache è in sola lettura, la surface cache memory è

un CUDA array in lettura e scrittura; il compute capability specifica la massima

altezza, larghezza e profondità. La funzione per allocare la surface memory è

cudaArraySrufaceLoadStore;

Pinned host memory. Pinned memory (free page-locked) sta sull’host, per allocare

questa memoria è necessario utilizzare cudaHostAlloc e cudaFreeHost. Occorre

osservare però che la quantità di memoria a disposizione è limitata e togliendo

memoria disponibile al sistema operativo per la paginazione ciò può comportare a

una riduzione delle prestazioni dell’intero sistema. Se si utilizza la chiamata al C

runtime cudaHostAlloc, la pinned memory è cacheable lato host ma si può disattivare

questa modalità tramite la chiamata a cudaHostAllocWriteCombined. In quest’ultimo

caso non si utilizzano le cache L1 e L2, le quali potranno essere utilizzate dalla CPU

per altri scopi, inoltre l’accesso diventa piuttosto lento lato host e conviene utilizzare

questa tecnica solo quando l’host deve scrive dati nella memoria e il device accede a

questa soltanto in lettura. Nel caso in cui la memoria è mappata tra host e device

allora questa è condivisa ed è necessaria la sincronizzazione per l’accesso ai dati. I

vantaggi nell’utilizzo di questa memoria sono:

o E’ possibile eseguire la copia dei dati tra pinned host memory e device in

modo concorrente con il kernel in esecuzione;

o C’è la possibilità di eseguire il mapping dello spazio d’indirizzamento della

pinned host in device memory quindi non serve eseguire la copia dei dati con

cudaMemcpy;

o Il trasferimento dei dati tra host e device è molto efficiente dato che la

memoria allocata non è paginabile (non può essere salvata dal sistema

operativo su disco) e in particolare per il fatto che si sfrutta il DMA (Direct

Memory Access) per sollevare la CPU dalla gestione del trasferimento.

6.5. Librerie

Il CUDA SDK mette a disposizione svariate librerie per facilitare la programmazione in CUDA

C:

CUBLAS è l’implementazione di BLAS (Basic Linear Algebra Subprograms) in CUDA,

permette di eseguire le classiche operazioni su matrici;

CUFFT è una libreria per eseguire la Fast Fourier Transform (FFT) su GPU;

CURAND mette a disposizione una libreria per la creazione di numeri casuali tramite

CPU o GPU;

86 NVIDIA CUDA, architettura e modello di programmazione

CUSPARSE per le tipiche operazioni su matrici sparse;

NPP è la libreria dedicata all’image e digital signal processing.

6.6. Velocità di elaborazione

La legge di Amdahl specifica qual è il massimo aumento in velocità di elaborazione che si

può ottenere mediante la parallelizzazione di una porzione di un programma seriale

dove S è l’aumento di velocità, P la frazione del tempo totale di esecuzione seriale della

porzione di codice che può essere parallelizzata e N il numero di processori per eseguire la

porzione di codice parallelizzata. Più grande è N più piccolo è il rapporto P/N, nel caso di

GPU N è molto grande e quindi il termine P/N può essere trascurato; per ottenere un

elevato incremento prestazionale dalla parallelizzazione è necessario rendere P il più grande

possibile. Da questo si deduce che per eseguire il più velocemente possibile un’applicazione

con CUDA è necessario parallelizzare la maggior parte del codice, quindi la fase di analisi e

successiva programmazione è di fondamentale importanza per ottenere il massimo del

beneficio prestazionale dall’architettura CUDA.

87 Benchmark

7. Benchmark

7.1. Introduzione

In questo capitolo si presentano i risultati ottenuti con l’algoritmo descritto; i benchmark

riguardano le prestazioni sia dal punto di vista del riconoscimento dei nuclei cellulari sia in

termini di velocità di calcolo.

Per fare i test di calibrazione del filtro DOG e addestramento dell’algoritmo si è usato un

insieme di centotrentadue immagini classificate manualmente da due esperti; dato che non

è possibile stabilire chi dei due esperti ha eseguito la migliore classificazione, si è deciso di

usare l’insieme classificato del secondo esperto come riferimento. La scelta deriva dal fatto

che il secondo esperto ha la tendenza di fornire un conteggio maggiore rispetto al primo, ciò

permette di presentare più esempi positivi all’algoritmo che “simulerà” questa tendenza. Sì

è notato che l’algoritmo ha la propensione di generare un conteggio molto inferiore rispetto

a quello dell’esperto in certi data set (a queste situazioni corrispondono i casi in cui

l’algoritmo si comporta peggio), quindi il vantaggio consiste nel fatto che in questi casi si ha

un aumento nel conteggio senza compromettere la classificazione in cui l’algoritmo non

presenta questo problema. Da notare che si poteva procedere anche con un’altra strategia

ossia considerare i soli oggetti classificati allo stesso modo dai due esperti. In quest’ultimo

caso si hanno dei notevoli svantaggi, prima di elencarli è necessario stabilire cosa s’intende

per oggetti classificati allo stesso modo; è necessario distinguere due situazioni:

Nel caso della calibrazione dei parametri per la DOG (fare riferimento al paragrafo

2.4.), un oggetto è classificato allo stesso modo dai due esperti quando l’intorno

(centrato ad esempio nel marcatore del secondo esperto) contiene un solo

marcatore dell’altro esperto. Si ha ambiguità quando l’intorno contiene più

marcatori dell’altro esperto o nessuno;

Per la procedura di assegnazione della classe di appartenenza della ROI (fare

riferimento al paragrafo 2.6.), l’oggetto è classificato allo stesso modo quando il blob

associato contiene un marcatore di entrambi gli esperti. Si ha ambiguità quando il

blob contiene due marcatori dello stesso esperto, ha un solo marcatore o ha più di

due marcatori.

Per tutte le situazioni ambigue non si definisce il comportamento dell’algoritmo dato che si

prendono in considerazione soltanto gli oggetti classificati allo stesso modo, ciò ha dei

notevoli svantaggi che compromettono irrimediabilmente il comportamento dell’intero

algoritmo visto che tali situazioni determinano circa il 10% (fare riferimento al paragrafo

7.3.) di scostamento nella classificazione fatta dai due esperti:

Non sarebbe possibile calibrare accuratamente i parametri della DOG dato che non si

stabilisce (e non si verifica) la generazione dei punti d’interesse nelle situazioni

ambigue, quindi si rischia di compromettere tutti i passi successivi di elaborazione

88 Benchmark

che determinano il comportamento dell’algoritmo (generazione ROI, calcolo feature

e conseguente comportamento della SVM);

Come già detto, si è notato che l’algoritmo ha la tendenza di generare un conteggio

molto inferiore rispetto a quello dell’esperto in certi data set (causato per parametri

DOG non ottimi e quindi aumenta la possibilità di classificazione errata), con la

tecnica descritta si passerebbero meno esempi positivi rispetto alla soluzione finale

addotta con conseguente possibile tendenza ad accentuare questo tipo di

comportamento non desiderato;

Siccome non si prenderebbero in considerazione gli oggetti ambigui, non si definisce

il modello della SVM in queste situazioni e la classificazione finale potrebbe essere

completamente diversa da quell’attesa (poiché lo scostamento è di circa 10% nella

classificazione tra i due esperti).

Da tutto ciò si deduce che non stabilire il comportamento dell’algoritmo nelle situazioni

ambigue può compromettere notevolmente la classificazione finale, è meglio definire

accuratamente i parametri della DOG e il modello della SVM facendo riferimento al secondo

esperto piuttosto che rischiare di avere comportamenti non previsti dell’algoritmo. D’ora in

poi si farà riferimento unicamente alla soluzione che impiega il secondo esperto.

Dopo la calibrazione della DOG, la scelta del miglior kernel e feature per le centotrentadue

immagini, si sono fatte le valutazioni di conteggio su dieci insiemi d’immagini per le quali si

hanno a disposizione esclusivamente i conteggi finali cioè il numero di cellule classificate

come positive senza le posizioni delle medesime (eccetto che per due insiemi che sono stati

usati anche nella fase di addestramento ossia Data1 e Data2): ctrl 30 aprile 2010, ctrl2 30

aprile 2010, Data1, Data2, dot 400 4, Dot100, dots 200nm 1, Pillar100, t9_12 DAPI 400nm e

t9_12 DAPI ctrl.

7.2. Hardware e software impiegati

La macchina utilizzata per fare i benchmark ha le seguenti caratteristiche hardware:

CPU:

o Intel Core 2 Duo T5550;

o Processo produttivo a 65 nm;

o Frequenza core 1.83 GHz;

o Frequenza bus 167 MHz;

o FSB 667 MHz ;

o L1 Cache 32 KBytes x2;

o L2 Cache 2048 KBytes

o Numero di core 2;

GPU:

o GeForce 8600m GT;

o Compute capability 1.1;

89 Benchmark

o Frequenza streaming processor 950 MHz;

o Numero di SM 4;

o Dimensione warp di 32 thread;

o Regs per blocco 8192;

o Thread per blocco 512;

o Dimensioni massime dei thread 512x512x64;

o Dimensioni massime della griglia 655535x65535x1;

o Clock della memoria a 400 MHz;

o Memoria globale di 466.625 MB;

o Cache condivisa per blocco di 16 KB;

o Pitch 2.09715 GB;

o Memoria costante di 64 KB;

o Allineamento texture di 256 bytes;

o Overlap è supportato;

o Transfer rate da host a device con pinned 1750 MB/s;

o Transfer rate da host a device pageable 1000 MB/s;

o Transfer rate da device a host pinned 1750 MB/s;

o Transfer rate da device a host pageable 1000 MB/s;

o Transfer rate da device a device 5200 MB/s;

o 32-bit floating-point 60500 Mflop/s;

o 32 –bit integer 12150 Miop/s;

o 24-bit integer 60500 Miop/s;

o Processo produttivo 80 nm;

o Dimensione bus di memoria di 128 bits.

Memoria principale:

o DDR2;

o 3072 MB;

o Dual channels;

o DC in modalità simmetrica;

o Frequenza DRAM 333 MHz.

Memoria di massa:

o SSD Corsair F60;

o Capacità di 60 GB;

o Massimo transfer rate sequenziale in lettura e scrittura 285 MB/s 275 MB/s;

o Numero di IOPS con blocchi casuali di 4 KB 50000 IOPS.

I software impiegati sono:

Windows 7 Professional x64;

Visual Studio 2010 Ultimate;

NVIDIA Parallel Nsight 2.0, NVIDIA CUDA SDK 4.0, NVIDIA Compute Visual Profile 4.0;

MATLAB 2011a.

90 Benchmark

Per eseguire il debugging del codice CUDA C si è impiegata una macchina remota con GPU

NVIDIA G82.

7.3. Valutazione delle classificazioni manuali effettuate dagli esperti

Prima di poter valutare le prestazioni dell’algoritmo è necessario avere un termine di

paragone, ossia il golden test che è dato dalla classificazione manuale degli esperti. Le

immagini classificate sono organizzate in due gruppi (Data1 e Data2) per un totale di

centotrentadue; nella fase di confronto delle classificazioni manuali, calibratura dei

parametri della DOG e valutazione delle prestazioni in addestramento si raggruppano

queste immagini in un unico gruppo. Ciò ha i seguenti vantaggi:

Avere più esempi a disposizione in addestramento significa costruire un modello

della SVM più accurato;

Avere molti esempi permette in fase di cross-validation verificare meglio la

generalizzazione dell’algoritmo d’apprendimento;

Con molti esempi è possibile valutare meglio l’errore in classificazione tra i due

esperti.

Gli esperti a disposizione (per Data1 e Data2) sono due e di seguito si riporta la tabella

riassuntiva relativa alle classificazioni manuali.

Esperto Conteggio

1 5208

2 5280

La differenza fra il numero totale di cellule è 72 mentre in percentuale è 4.6083%; da notare

che questo modo di confrontare la classificazione non è molto accurato dato che non si è in

grado di stabilire effettivamente se un oggetto è stato classificato nello stesso modo da

entrambi gli esperti. Per tale motivo si è deciso di procedere in modo diverso per

confrontare le due classificazioni, da notare che si hanno a disposizione le posizioni dei

marcatori sui nuclei delle cellule. La strategia consiste nel prendere come riferimento la

classificazione del secondo esperto e costruire un intorno riferito a ogni marcatore inserito

(gli intorni sono costruiti con la medesima logica in 2.4); all’interno di ogni intorno si verifica

se c’è un solo marcatore dell’esperto uno, in caso affermativo significa che il nucleo è

classificato nello stesso modo. L’errore finale è calcolato come

è il numero di nuclei classificati dal secondo esperto in modo diverso dal primo, è il

numero di nuclei del primo esperto che non sono stati coinvolti nella ricerca all’interno degli

intorni e è il numero totale di nuclei classificati dal secondo esperto.

D S N D + S e%

200 340 5280 540 10.2273

91 Benchmark

L’effettivo errore di scostamento è del 10.2273%, quindi per avere delle prestazioni

confrontabili con quelle degli esperti l’algoritmo non deve scostarsi troppo nei test da

questa soglia.

7.4. Valutazione dei parametri della DOG

La calibrazione dei parametri del filtro DOG è di fondamentale importanza, una calibratura

errata compromette l’intero funzionamento dell’algoritmo; per questo motivo si sfrutta una

procedura che testa varie coppie di deviazioni standard e tutto il processo richiede ore di

elaborazione prima di individuare la coppia ottima. L’utente deve inserire soltanto il

diametro massimo di una cellula; l’algoritmo segue la logica descritta in 2.4 per stabilire

quali sono i parametri ottimali.

Indice Sigma1 Sigma2 Validi% Sovrannumero% Sovra raggio%

Non individuati%

Validi% + Sovra raggio%

1 10 11 78.1277 9.6238 11.6360 0.6124 89.7637

2 11 12 79.3991 6.7382 12.1459 1.7167 91.545

3 11 13 78.8627 5.8155 12.9399 2.3820 91.8026

4 11 14 77.9614 5.1502 14.3133 2.5751 92.2747

5 11 15 76.9528 4.8069 15.0429 3.1974 91.9957

6 11 16 75.4077 4.4850 16.6953 3.4120 92.103

7 11 17 73.6052 4.1416 18.0043 4.2489 91.6095

8 11 18 65.6315 3.5197 24.2236 6.6253 89.8551

9 12 13 77.6180 5.1073 14.5279 2.7468 92.1459

10 12 14 76.3519 4.6352 15.8155 3.1974 92.1674

11 12 15 74.0773 4.3348 17.8326 3.7554 91.9099

12 12 16 71.9957 3.9914 19.1631 4.8498 91.1588

13 12 17 64.6998 3.7267 24.6377 6.9358 89.3375

92 Benchmark

Figura 52 Calibratura DOG

Indice indica il passo di ricerca dell’algoritmo, Sigma1 è la deviazione standard della prima

gaussiana, Sigma2 è la deviazione standard della seconda gaussiana, Validi% indica la

percentuale di marcatori validi, Sovrannumero% percentuale di marcatori individuati per

sovrannumero, Sovra raggio% percentuale di marcatori individuati per aumento del raggio,

No individuati% è la percentuale di marcatori non individuati dall’algoritmo (cioè non ci

sono punti d’interesse generati dalla DOG negli intorni centrati nei marcatori inseriti dagli

esperti). La combinazione migliore è quella che massimizza la somma di Validi% con Sovra

raggio% (fare riferimento al paragrafo 2.4.) che è data per indice quattro.

7.5. Valutazione delle prestazioni in fase di addestramento

Nel capitolo tre si è descritto in dettaglio come si garantisce l’invarianza per rotazione delle

regioni d’interesse; come già detto, per ridurre il numero di ROI poco significative da fornire

alla macchina a vettori di supporto nella fase di addestramento e quindi definire meglio il

modello della macchina SVM, si scartano nell’elaborazione le ROI poco robuste

nell’invarianza per rotazione (fare riferimento a 3.2). L’errore di scostamento massimo in

gradi è pari a cinque e il numero di rotazioni da verificare sono trentacinque (con incrementi

di dieci gradi). Di seguito si riporta il risultato delle ROI scartate.

89.7637

91.545

91.8026

92.2747

91.9957

92.103

91.6095

89.8551

92.1459

92.1674

91.9099

91.1588

89.3375

87 88 89 90 91 92 93

1

2

3

4

5

6

7

8

9

10

11

12

13

%

Validi% + Sovra raggio%

Validi% + Sovra raggio%

93 Benchmark

Figura 53 Percentuale di regioni d'interesse scartate nella fase di addestramento della macchina a vettori di supporto

Dopo aver scartato le ROI poco robuste all’invarianza per rotazione, è necessario stabilire il

numero di coefficienti per le varie tipologie di feature.

Il numero di coefficienti per le feature di tipo DCT è legato all’energia media minima

impostata che in questo caso è del 90% a cui corrisponde una finestra DCT 7x7 e quindi

s’impiegano quarantanove coefficienti.

Figura 54 Numero di coefficienti selezionati per la DCT

In tutti gli altri casi si procede considerando un buon compromesso tra velocità di

elaborazione e descrizione degli oggetti; per Zernike s’impiegano duecentotrentuno feature

(cioè il grado del polinomio di Zernike è impostato a venti), per FAFMT e DAFMT si sfrutta

50.3860

52.0607

49.5000 50.0000 50.5000 51.0000 51.5000 52.0000 52.5000

Esprto 2

%

Percentuale di regioni d'interesse scartate

Positivi scartati

Negativi scartati

0 10 20 30 40 50 60 70 80 90 1000

0.1

0.2

0.3

0.4

0.5

0.6

0.7

0.8

0.9

1

Size DCT

Energ

y (

energ

y:

0.9

2366 w

indow

: 7 )

94 Benchmark

una finestra 15x15 quindi s’impiegano duecentoventicinque feature, per ShapeIntensity si

hanno quattordici descrittori.

Per la macchina a vettori di supporto si testa il kernel polinomiale, RBF e sigmoidale con le

feature descritte nel capitolo tre; per i concetti relativi alle curve ROC fare riferimento al

capitolo cinque.

Di seguito si riporta per ogni kernel della macchina a vettori di supporto il valore , il

parametro del kernel (nel caso di kernel polinomiale corrisponde al grado, per RBF a

gamma e per sigmoidale a gamma) e ossia il soft margin. Questi parametri fanno

riferimento alla miglior macchina per feature con uno specifico kernel.

Kernel polinomiale con feature

AUC dg C

ShapeIntensity 0.9467 2 10000

Zernike 0.9165 2 10000

FAFMT 0.9325 2 10000

DAFMT 0.9295 2 10000

DCT 0.9375 3 10000

Figura 55 Kernel polinomiale

In questo caso le migliori feature con kernel polinomiale sono ShapeIntensity. Si riporta la

relativa curva ROC.

0.9467

0.9165

0.9325

0.9295

0.9375

0.9 0.91 0.92 0.93 0.94 0.95

ShapeIntensity

Zernike

FAFMT

DAFMT

DCT

AUC

Kernel polinomiale

AUC

95 Benchmark

Figura 56 Curva ROC kernel polinomiale con ShapeIntensity

Kernel RBF con feature

AUC dg C

ShapeIntensity 0.9496 0.25 10000

Zernike 0.9404 0.25 10000

FAFMT 0.95862 0.5 10

DAFMT 0.9564 0.25 10

DCT 0.9475 0.5 100

Figura 57 Kernel RBF

0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 10

0.1

0.2

0.3

0.4

0.5

0.6

0.7

0.8

0.9

1

False Positive Rate

Tru

e P

ositiv

e R

ate

ROC curve of ( AUC = 0.9467 )

0.9496

0.9404

0.9586

0.9564

0.9475

0.93 0.935 0.94 0.945 0.95 0.955 0.96

ShapeIntensity

Zernike

FAFMT

DAFMT

DCT

AUC

Kernel RBF

AUC

96 Benchmark

In questo caso le feature migliori da usare con kernel RBF sono le FAFMT.

Figura 58 Curva ROC per kernel RBF con feature FAFMT

Kernel Sigmoidale con feature

AUC dg C

ShapeIntensity 0.9416 0.0078 10000

Zernike 0.9109 9.76E-04 10000

FAFMT 0.9245 9.76E-04 100

DAFMT 0.9385 9.76E-04 1000

DCT 0.9136 0.002 10000

0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 10

0.1

0.2

0.3

0.4

0.5

0.6

0.7

0.8

0.9

1

False Positive Rate

Tru

e P

ositiv

e R

ate

ROC curve of ( AUC = 0.95862 )

97 Benchmark

Figura 59 Kernel sigmoidale

In questo caso conviene impiegare come feature le ShapeIntensity.

Figura 60 Curva ROC per kernel sigmoidale con ShapeIntensity

Dai dati precedenti si nota che la migliore soluzione si ottiene con kernel RBF e feature

FAFMT. Di seguito si riporta il sommario dei risultati ottenuti.

Kernel Feature AUC dg C

Polinomiale ShapeIntensity 0.9467 2 10000

RBF FAFMT 0.9586 0.5 10

Sigmoidale ShapeIntensity 0.9416 0.0078 10000

0.9416

0.9109

0.9245

0.9385

0.9136

0.89 0.9 0.91 0.92 0.93 0.94 0.95

ShapeIntensity

Zernike

FAFMT

DAFMT

DCT

AUC

Kernel sigmoidale

AUC

0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 10

0.1

0.2

0.3

0.4

0.5

0.6

0.7

0.8

0.9

1

False Positive Rate

Tru

e P

ositiv

e R

ate

ROC curve of ( AUC = 0.9416 )

98 Benchmark

Figura 61 Migliori feature e kernel

7.6. Valutazione delle prestazioni in classificazione

A questo punto è necessario valutare le prestazioni dell’algoritmo in classificazione con

kernel RBF e feature FAFMT; per tutti gli insiemi d’immagini (eccetto Data1 e Data2) si

hanno a disposizione esclusivamente i conteggi fatti dagli esperti , quindi, non c’è modo per

risalire alle posizioni reali dei marcatori inseriti manualmente.

Figura 62 Valutazione del conteggio

Il valore medio dell’errore (prendendo in esame gli errori in valore assoluto) è 4.1834% con

deviazione standard 2.2972%.

0.9467

0.9586

0.9416

0.93 0.935 0.94 0.945 0.95 0.955 0.96

ShapeIntensity

FAFMT

ShapeIntensity

Po

lino

mi

ale

RB

F Si

gmo

idal

e

AUC

Migliori feature e kernel

AUC

3.4142

-7.0646

1.3793

3.9033

0.6775

2.931

6.2937

3.5326

-7.5026

-5.1351

-10 -8 -6 -4 -2 0 2 4 6 8

Data1 (3544)

dot 400 4 (821)

Dot100 (1450)

dots 200nm 1 (538)

t9_12 DAPI ctrl (738)

Data2 (1160)

ctrl 30 aprile 2010 (715)

ctrl2 30 aprile 2010 (736)

t9_12 DAPI 400nm (973)

Pillar100 (2220)

%

Valutazione del conteggio

Errore nel conteggio

99 Benchmark

7.7. Valutazione della velocità di elaborazione

Per valutare la velocità di elaborazione dell’algoritmo si sono fatti cinque test per ogni

routine da testare e il tempo riportato è la media di questi; nella valutazione si considera

l’incremento della velocità di elaborazione quando s’impiega la GPU in luogo della CPU. Da

ricordare che solo una parte dell’algoritmo è implementata in CUDA C, in particolare due

funzioni sono implementate completamente in CUDA C:

mexBlob restituisce le coordinate dei punti d’interesse presenti in un blob;

mexFind restituisce le coordinate di un solo punto d’interesse specificando

l’etichetta associa.

Queste due routine sono ampiamente usate in varie porzioni di codice dell’algoritmo ed

eseguono compiti tipici riguardanti la gestione dei punti d’interesse. Si è scelto

d’implementare queste due funzionalità perché sono molto generiche e quindi non

subiscono modifiche se s’implementano nuove procedure di elaborazione dell’algoritmo

quali nuove tecniche di confronto tra le classificazioni manuali dei due esperti, filtraggi,

ricerca dei parametri della DOG, estrazione delle ROI, nuove feature, nuovi kernel per la

SVM e l’impiego di altri algoritmi d’apprendimento. Tutti i test sono effettuati sul training

set (centotrentadue immagini date da Data1 e Data2); per tenere traccia delle tempistiche

delle funzioni si sfrutta il profile del MATLAB.

Routine CPU (s) GPU (s) Incremento prestazionale su

GPU

ExtractCircularBlob 74.059 32.737 2.2622415

ExtractDOGError 1985.363 162.614 12.20905334

GetCircularSeed 56.442 18.052 3.126634168

BenchmarkUserSeeds 182.877 98.796 1.851056723

GetSeeds 283.704 154.004 1.842185917

AutomaticDOG 4975.376 2414.042 2.06101468

AutomaticDOGImproved 1054.537 629.794 1.674415761

100 Benchmark

Figura 63 Incremento prestazionale su GPU

L’incremento medio delle prestazioni su GPU è di 3.57 volte con deviazione standard 3.84.

2.26

12.21

3.13

1.85

1.84

2.06

1.67

0 2 4 6 8 10 12 14

ExtractCircularBlob

ExtractDOGError

GetCircularSeed

BenchmarkUserSeeds

GetSeeds

AutomaticDOG

AutomaticDOGImproved

Incremento

Incremento prestazionale su GPU

Incremento prestazionale su GPU

101 Conclusioni

8. Conclusioni In questo lavoro si è presentato un algoritmo efficace dal punto di vista del riconoscimento

dei nuclei cellulari e velocità di elaborazione grazie alla GPU.

Nella calibratura del filtro DOG si osserva che conviene usare la coppia di deviazioni

standard che garantisce un numero di marcatori dell’esperto

non rilevati pari a 2.5751% che è un valore abbastanza piccolo (se paragonato al 10.2273%

di differenza in classificazione manuale tra i due esperti). Questo scostamento influenza il

risultato finale di conteggio dell’algoritmo però in lieve entità.

Nella valutazione dei kernel per la SVM si nota che le feature di tipo ShpaeIntensity sono

quelle che garantiscono un miglior comportamento dell’algoritmo con kernel polinomiale e

sigmoidale; per kernel RBF conviene usare le feature di tipo FAFMT che sono migliori

rispetto alle altre. La migliore AUC si ottiene con kernel RBF e feature FAFMT che assume il

valore di 0.9586 e in base alla capacità discriminante dell’AUC proposta da Swets [15] risulta

che il test è altamente accurato. Da questi risultati si deduce che il kernel RBF con vettori di

supporto che sfruttano le feature FAFMT discrimina al meglio le osservazioni. Si può notare

che per feature FAFMT e DAFMT i risultati che si ottengono nella valutazione dei kernel sono

molto simili a dimostrazione del fatto che sono due approssimazioni della medesima

trasformata; le feature di Zernike sono poco accurate come previsto (fare riferimento a 3.3)

e sono le peggiori in tutti i casi considerati dato che nonostante un numero elevato di

coefficienti (le feature) non sono in grado di rappresentare efficacemente i dettagli degli

oggetti. Le feature di tipo ShapeIntensity garantiscono un buon comportamento, da ciò si

deduce che i descrittori scelti (quattordici) permettono una descrizione molto accurata della

forma e della distribuzione dell’intensità degli oggetti.

Si è notato che la differenza in classificazione tra i due esperti è del 10.2273% e lo scopo

dell’algoritmo è fornire un conteggio che ha un errore di scostamento non superiore a

questo valore; dalla differenza in classificazione tra i due esperti si nota che c’è un fattore

soggettivo non trascurabile che influenza la classificazione. Lo scostamento massimo che si è

ottenuto nei dieci insiemi d’immagini a disposizione è di -7.5026% (set “t9_12 DAPI ctrl” che

ha 738 nuclei cellulari classificati manualmente dall’esperto), quindi il risultato è notevole a

fronte dell’elevata soggettività in classificazione. Da osservare che ci sono molti insiemi

d’immagini per i quali l’algoritmo fornisce un errore di scostamento molto ridotto, inferiore

al 4%, questo a dimostrazione del buon comportamento dell’algoritmo. I casi peggiori hanno

un errore (in valore assoluto) di scostamento tra il 5% e 7.5%; i principali motivi che possono

portare a questi risultati sono:

Parametri del filtro DOG non sempre adatti poiché le immagini sono prelevate in

condizioni diverse (la luminosità può variare molto da un’immagine all’altra e se

102 Conclusioni

questa è particolarmente intensa in certe zone dello sfondo, allora potrebbe

accadere che in corrispondenza di queste l’algoritmo generi delle ROI indesiderate);

Modello della macchina a vettori di supporto non ben definito. Alcuni esempi

classificati positivi da un esperto potrebbero essere passati alla SVM nella fase di

addestramento come esempi negativi perché l’esperto ha inserito alcuni marcatori

sui bordi dei nuclei anziché vicino ai centri degli oggetti da analizzare. Ciò significa

che l’algoritmo potrebbe non individuare questi marcatori e impostare l’esempio

come negativo quando in realtà è positivo;

L’AUC migliore durante i test di addestramento è pari a 0.9586 (kernel RBF e feature

FAFMT) e questo significa che l’algoritmo commette degli errori, questi potrebbero

aumentare se gli esempi da analizzare sono molto diversi da quelli usati nella fase di

addestramento della macchina;

L’ipotesi di non considerare i blob a una certa distanza dai bordi dell’immagine non

sempre funziona correttamente dato che dipende dalla distanza impostata. Questa

distanza, che è fissa, potrebbe non essere efficace in alcuni casi poiché potrebbe

accadere che ci siano immagini con un elevato numero di nuclei cellulari di diametro

inferiore alla distanza limite vicini ai bordi. Questo è il principale motivo per il quale

si hanno scostamenti negativi, cioè conteggi che in numero sono inferiori a quelli

effettuati da un esperto. Infatti, in tutti questi casi, diminuendo questa distanza si ha

un notevole miglioramento nel conteggio ma un peggioramento negli altri esempi

perché i blob risultano tagliati e quindi non riconoscibili correttamente dalla SVM (da

notare che i blob tagliati non sono impiegati nel conteggio e quindi l’errore aumenta

sia perché la SVM li classifica positivi sbagliando sia perché non sono presi in

considerazione nel conteggio da parte degli esperti);

Il filtro basato sulla funzione sigmoidale per l’estrazione dell’oggetto della ROI può

non essere efficace in alcuni casi, specialmente se gli oggetti indesiderati sono molto

vicini a quello da analizzare (in questa situazione la funzione sigmoidale non è in

grado di cancellare completamente gli oggetti da non analizzare).

Per quanto riguarda le prestazioni si ha che le routine che sfruttano la tecnologia CUDA

hanno un incremento da 1.6 a 12.2 volte rispetto al medesimo algoritmo elaborato però

esclusivamente su CPU; le funzioni con incremento prestazionale massimo di circa due

eseguono poche chiamate alle routine CUDA mexBlob e mexFind, invece le altre le usano in

modo più intensivo (ExtractDOGError impiega quasi esclusivamente funzioni CUDA e ciò

permette un incremento prestazionale superiore a dodici volte) . Per migliorare le

prestazioni lato CUDA sarebbe opportuno impiegare una GPU di fascia alta, invece, nei test

effettuati si è usata una GPU di fascia bassa con varie restrizioni poiché ha compute

capability di solo 1.1.

Possibili sviluppi futuri per migliorare l’algoritmo sono:

103 Conclusioni

Usare nuove feature che permettano di migliorare ulteriormente la descrizione della

forma e texture degli oggetti da analizzare (una possibile idea sarebbe di impiegare

feature basate sui filtri di Gabor per mettere in risalto le texture);

Impiegare la libreria MKLAB libsvm per la macchina a vettori di supporto che sfrutta

la tecnologia CUDA per gestire il kernel RBF (non ha il supporto al kernel polinomiale

e sigmoideo). In questo caso è necessario implementare una mex per interagire con

il MATLAB;

Impiegare una tecnica più efficace della funzione sigmoidale per escludere gli oggetti

da non analizzare presenti nella ROI;

Eventualmente per rendere il codice per l’elaborazione su GPU indipendente dal

produttore hardware si potrebbe eseguire un’implementazione in OpenCL anziché

CUDA C.

104 Bibliografia

Bibliografia [1] Programming Massively Parallel Processors-David B. Kirk, Wen-mei W. Hwu 2010.

[2] CUDA by example An Introduction to General-Purpose GPU Programming Jason Sanders,

Edward Kandrot 2010.

[3] White Paper NVIDIA GF110 2010.

[4] White Paper NVIDIA Fermi Compute Architecture 2010.

[5] NVIDIA CUDA Architecture Introduction & Overview 2010

[6] NVIDIA CUDA C Best Practices Guide 2010.

[7] NVIDIA CUDA C Programming Guide 2010.

[8] NVIDIA PTX: Parallel Thread Execution ISA version 2.1 2010

[9] NVIDIA Fermi Tuning Guide 2010.

[10] F. Ghorbel. A complete invariant description for gray-level images by the harmonic

analysis approach. Pattern Recognition Letters, October 1994.

[11] Milan Sonka, Vaclav Hlavac, and Roger Boyle Image Processing, Analysis and Machine

Vision 2 Ed.

[12] Digital Image Processing: PIKS Inside, Third Edition. William K. Prat.

[13] Chris Stauffer, "Automatic hierarchical classification using time-based co-

occurrences", IEEE Conference on Computer Vision and Pattern Recognition (CVPR1999), pp.

333-339, June 23-25, 1999.

[14] Chih-Chung Chang and Chih-Jen Lin, LIBSVM : a library for support vector machines.

ACM Transactions on Intelligent Systems and Technology, 2:27:1--27:27, 2011. Software

available at http://www.csie.ntu.edu.tw/~cjlin/libsvm.

[15] Swets J.A. (1998) Measuring the accuracy of diagnostic systems. Science, 240, 1285-93.

[16] Schäfer H. (1989). Constructing a cut-off point for a quantitative diagnostic test.

[17] F. Ghorbel, A complete invariant description for gray-level images by the harmonic

analysis approach 1994.

[18] S. Goh. The Mellin transformation: Theory and digital filter implementation 1985.

105 Appendice A

Appendice A

A.1. DirectX 11 su hardware DirectX 10 e DirectX 9.0c

E’ possibile utilizzare l’API DirectX 11 su hardware DirectX 10 o 9.0c con il vantaggio di

sfruttare i miglioramenti prestazionali introdotti nell’API; però per utilizzare le nuove feature

è necessario sfruttare hardware DirectX 11 compatibile (tessellation, compute shader).

A.1. Shader model 5

Gli shader model servono per applicare effetti visivi ai modelli 3D in base al tipo di oggetto,

ad esempio se l’oggetto è metallico, allora è necessario utilizzare gli shader relativi alla

gestione dei metalli. Gli shader model sono suddivisi nelle seguenti categorie:

Vertex Shader (VS), descrivono la forma del modello 3D e a ogni vertex d’input

corrisponde un vertex d’output cioè è in grado di alterare la posizione e orientazione

dei vertici di un oggetto;

Geometry Shader (PolyMorph, GS), esegue operazioni di amplificazione o

deamplificazione delle geometrie permettendo l’aumento o riduzione del numero di

vertici per creare un modello finale più complesso di quello iniziale;

Pixel Shader, descrivono il valore del singolo pixel per applicare texture o effetti

come bump mapping o nebbia;

Gli Hull Shader (HS) elaborano da uno a trentadue control point del patch generato

dai vertex shader, da questi e dalle caratteristiche che definiscono la mesh, ricavano

un nuovo insieme di control point (sempre in numero massimo pari a trentadue). Nel

fare quest’operazione, gli HS possono decidere se variare il numero dei control point,

aumentandolo o diminuendolo;

Domain Shader (DS). Gli ingressi dei DS sono dati dai control point generati dagli hull

shader, tessellation factor e il patch generato dal tessellator; in questa fase si sta

operando a livello di view space. Questi shader svolgono i seguenti compiti:

o Si occupano di confrontare il risultato della tessellation con le indicazioni

fornite dai control point generati dagli HS;

o Trasformano, in base ai dati degli HS le serie di linee, triangoli e altri poligoni

generati in fase di tessellation in nuovi vertici da renderizzare;

o Controllano che i risultati ottenuti siano congruenti con il valore di LoD (Level

of Detail) impostato;

o Procedono, se necessario, a eseguire altre operazioni come ad esempio

l’applicazione del displaced mapping;

Compute Shader. E’ un nuovo tipo di shader introdotto in DirectX 11 per eseguire

calcoli di tipo generico su GPU.

106 Appendice A

A.2. Vertex e Index buffer

Nelle DirectX è possibile indicizzare i vertici ossia a ogni vertex è possibile assegnare un

indice che lo identifica univocamente; i vertex sono salvati nel vertex buffer mentre gli indici

nell’index buffer, la CPU riempie questi buffer.

Se ad esempio si vuole disegnare un quadrato di questo tipo

Figura 64 Quadrato indicizzato

e se si utilizza la primitiva triangle list, allora la situazione è descritta come di seguito

Figura 65 Vertex Index buffer

A.3. Primitive

Una primitiva è la più semplice delle figure geometriche gestibile dalla GPU, tutte le forme

complesse sono ricavate combinando assieme le primitive. Di seguito si riportano tutte le

primitive supportate dalle schede video di ultima generazione DirectX 10 e DirectX 11.

107 Appendice A

Figura 66 Primitive

Occorre osserva che le informazioni relative alle adiacenze riguardano esclusivamente i

geometry shader.

Oltre alle nove primitive di sopra, nelle DirectX 11 è stata introdotta una nuova chiamata

patch:

Figura 67 Primitiva patch

I vari punti rappresentano i control point da inviare al tessellator, quindi questa primitiva si

utilizza esclusivamente con i tessellator e no per altri compiti.

108 Appendice A

A.4. Input assembler

Lo input assembler preleva i dati per le primitive dai vertex e index buffer con lo scopo di

assemblare le primitive che saranno utilizzate dagli stadi successivi della pipeline grafica.

A.4. Rasterization

Consiste nella conversione della scena 3D in immagine raster o bitmap cioè formata da

pixel; ciò server per ottenere un'immagine proiettabile sul monitor. Questo significa che è

necessario passare da una descrizione lineare a una discreta, ossia i pixel dell'immagine

raster. Questo ha comportato l’implementazione di vari algoritmi di rastering, sia per

oggetti semplici come le linee sia per più complessi come i poligoni.

A.5. Pipeline grafica DirectX 11

Per comprendere in dettagli l’architettura NVIDIA Fermi è necessario descrivere la piepeline

grafica dal punto di vista logico.

A.5.1. Architettura shader model unificata

Prima dell’evento delle DirectX 10, le unità di gestione degli shader erano dedicate e si

utilizzava una pipeline come riportata di seguito (sia per ATI sia per NVIDIA):

Figura 68 Pipeline grafica DirectX 9.0c

In uno schema di questo tipo ogni unità di calcolo è dedicata a un compito ben specifico da

eseguire e ogni blocco funzionale rimane in attesa dei dati dell’unità precedente (senza

poter eseguire elaborazioni). Con un’architettura di questo tipo non è possibile avere la

piena occupazione di tutte le unità funzionali a pieno carico, quello che tipicamente accade

è riportato di seguito:

Figura 69 Workload degli shader dedicati

109 Appendice A

Ossia quando un’unità è occupata, tutte le successive sono in idle; per sfruttare al meglio il

silicio (quindi i transistor) i progettisti hanno seguito la filosofia degli shader unificati: unità

generica per eseguire compiti differenti (per le varie tipologie di shader).

Gli shader unificati sono stati introdotti nelle DirectX 10 e comprendono vertex, geometry e

pixel shader; con le DirectX 11 sono stati aggiunti altri tre shader ossia hull, domain e

compute shader.

Il modello degli shader model unificati utilizza il medesimo instruction set per gestire i vari

tipi di shader; questo ha portato notevoli vantaggi:

Ottimizzazione del lavoro dell’intero chip e non nella maggior efficienza della singola

operazione (si sfrutta meglio l’intera architettura del chip);

Miglioramento del workload e conseguente risparmio di transistor dato che non ci

sono più unità dedicate in idle;

Programmazione più semplice dato che si sfrutta il medesimo ISA (Instruction Set

Architecture) unificato che ne semplifica la gestione;

Flessibilità nell’utilizzo dell’hardware di elaborazione, in quanto a ogni unità di

shading può essere affidata una delle tipologie di shader a disposizione; ad esempio

se un’applicazione richiede calcoli intensivi di tipo geometry shader, piuttosto che di

vertex e pixel, allora un numero maggiore di unità può essere dedicato al tipo di

elaborazione prevalente aumentando la velocità d’esecuzione complessiva.

Di seguito si riporta la pipeline grafica DirectX 10 con shader model unificati.

Figura 70 Pipeline grafica DirectX 10

A.5.2. Tessellation

Una delle principali novità nelle DirectX 11 è la tecnica di tessellation; occorre osservare che

durante l’introduzione delle DirectX 9.0c nel mercato delle GPU c’era già stato un primo

tentativo di tessellation ma successivamente abbandonato dato che era molto primitiva

come tecnica e non permetteva d’ottenere benefici consistenti nel miglioramento

dell’immagine finale. Il primo tentativo fu fatto da ATI con R200 e successivamente con la

GPU Xenos per XBOX 360, da allora fino all’evento delle DirectX 11 nessun produttore

hardware ha introdotto soluzioni significative in quest’ambito. Solo con la nuova API grafica,

la Microsoft ha introdotto tecniche di tessellation sofisticate e ha reso l’implementazione

hardware obbligatoria.

110 Appendice A

La tessellation consiste nel ripetere una figura geometrica (o un gruppo di figure) chiusa fino

a riempire un’intera superficie senza soluzione di continuità (nel caso di utilizzo di una sola

forma, si parla di tessellation pura). Prima dell’introduzione della tessellation, un

modellatore 3D creava il modello dell’oggetto d’interesse con un certo numero di poligoni,

maggiore era il numero di poligoni e maggiore era il dettaglio dell’oggetto ma questo

comportava un aumento della memoria occupata e diminuzione del frame rate. Invece con

la tessellation, che è un approccio hardware, da un modello iniziale opportunamente

elaborato è generato un finale cha ha un numero di poligoni maggiore rispetto all’originale.

Vantaggi:

Risparmio di memoria a parità di complessità poligonale;

Riduzione dei dati che la CPU deve inviare alla GPU quindi miglioramento nel

sfruttare la banda a disposizione;

Aumenta il dettaglio dell’oggetto rendendolo molto realistico;

Può genera lo skeletal animation in modo da rendere più fluide le animazioni;

Possibilità di replicazione del medesimo oggetto con notevole risparmio di memoria

(in memoria è presente un singolo oggetto e non tutte le repliche).

Svantaggi:

La tessellator unit si occupa esclusivamente della generazione dei poligoni, quindi se

si aumenta la complessità poligonale, allora si aumenta anche quella del rendering e

questo comporta a una riduzione del frame rate. Per risolvere questo problema,

almeno parzialmente, si sfrutta la tessellation adattativa;

La tessellator unit richiede come input un patch come quello riportato di seguito

Figura 71 Patch per la tessellator unit

dove sono indicati i control point i cui valori rappresentano gli input della fase di tessellation,

a ogni control point è associato un dominio; a questo punto si calcola in quante parti il

dominio dovrà essere suddiviso. Esistono due tecniche per eseguire l’operazione descritta:

tessellation regolare (poligoni regolari e congruenti) oppure semi-regolare (poligoni regolari

ma di tipo differente).

111 Appendice A

Figura 72 Tessellation regolare

Figura 73 Tessellation semi-regolare

Quello al centro è il control point, i numeri indicano il numero di lati per ogni poligono

generato.

Oltre a dover specificare il numero di suddivisioni, la tessellator unit tiene in considerazione

anche del tessellation edge factor, ossia il numero di segmenti di cui è composto un lato. Se

ad esempio la figura iniziale fosse la seguente

Figura 74 Figura iniziale per l'edge factor della tessellation

e se il risultato della tessellation fosse questo

Figura 75 Risultato dell'edge factor per la tessellation

l’edge factor per il lato superiore sarebbe uno, mentre per gli altri quattro. E’ di

fondamentale importanza osservare che i patch contigui devono avere il medesimo edge

factor sulle superfici a contatto altrimenti sarebbero generati degli artefatti.

Oltre alla scelta dei poligoni da utilizzare, è necessario stabilire come la tessellation debba

essere applicata: continua o adattativa. Nel caso di modalità continua, si usa un unico livello

di tessellation per ciascuna mesh o gruppo quindi si ha una tessellation omogenea (permette

di ottenere il miglior risultato dal punto di vista della qualità dell’immagine); al variare del

LoD (Level Of Detail) varia il livello di tessellation in modo proporzionale. Nella modalità

adattativa si hanno differenti livelli di tessellation per ogni edge o spigolo della mesh (la

tessellation non necessariamente è uniforme); in questo modo è possibile adattare il livello

di tessellation al LoD e alle superfici che risultano più visibili. Siccome l’adaptive mode

112 Appendice A

richiede un’analisi dinamica, è necessario calcolare l’edge factor per ogni frame, inoltre è

necessario stabilire un valore minimo e massimo di tessellation.

La tecnica continua ha il vantaggio di generare un modello geometrico altamente dettagliato

ma ha lo svantaggio di rendere molto lento il rendering a causa dell’elevata complessità

poligonale uniforme su tutti gli oggetti. L’adattativa ha il vantaggio di generare un modello

poligonale che dal punto di vista del dettagliato visivo è quasi come quello della tecnica

continua (leggermente inferiore) che richiede però meno tempo per eseguire il rendering (le

superfici meno visibili, lontane dall’osservatore e/o oscurate hanno una tessellation molto

ridotta); lo svantaggio è che per ogni frame è necessario riapplicare la tessellation.

A.5.3. Schema logico della pipeline grafica DirectX 11

Fare riferimento all’appendice B per approfondire i concetti di object, world, view, clip,

screen space e HSR (Hidden Surface Removal).

Dal punto di vista logico una pipeline grafica DirectX 11 è rappresentata come di seguito:

Figura 76 Pipeline grafica DirectX 11

Di seguito si descrivono in dettaglio le varie parti della pipeline grafica nel caso in cui si

sfrutta la tecnica di tessellation (se non si utilizza tale tecnica, allora l’output dei vertex

shader è inviata direttamente agli stadi dopo i domain shader). Sotto si riporta in dettaglio lo

schema a blocchi dall’Input Assembler al Tessellator:

113 Appendice A

Figura 77 Schema a blocchi Input Assembler, Vertex Shader, Hull Shader, Tessellator

Lo input assembler riceve i dati dai vertex e index buffer che sono stati riempiti dalla CPU,

questi contengono le informazioni relative alla creazione della geometria del frame. Il suo

output è costituito da primitive che possono contenere un numero di vertici variabile tra

uno e trentadue; tutta l’elaborazione avviene a livello dell’object space. Le mesh così

ottenute sono inviate ai vertex shader (VS), che possono compiere una serie di operazioni,

come cambiare le coordinate, effettuare operazioni di trasformazione sui control point per

ottenere effetti tipo skeletal animation. In questa fase avviene anche il passaggio da object a

world space; l’output dei VS, costituito dai control point del patch elaborato, diventano lo

input per il successivo stadio che, nelle DX11, è costituto dagli hull shader. Si può notare che

l’hull shader è formato da due parti ossia dalla constant function (CF) e dalla parte

programmabile; se si sfrutta la tessellation continua, allora la CF esegue una sola volta per

l’intero patch la definizione dei valori comuni a tutti i control point ossia il tessellation factor

da inviare al tessellator altrimenti con la tecnica adattativa il tessellation factor è calcolato

per ogni control point. Il tessellation factor si ricava dai valori dei control point in ingresso,

caratteristiche della mesh (superficie nascoste nell’ombra e poco visibili) e dall’algoritmo di

tessellation. Lo stadio programmabile, in base alla posizione dei control point del patch

forniti dai VS e dalla funzione di tessellation scelta, definisce un insieme di nuovi control

point.

I dati relativi ai nuovi control point (generati dagli HS) sono inviati ai domain shader, mentre

il tessellation factor (generato dalla CF) che fornisce indicazioni su quanti sono i poligoni in

cui ciascuna figura geometrica formante la mesh deve essere scomposta, diventa lo input

del tessellator vero e proprio e dei domain shader (DS).

114 Appendice A

Figura 78 Secondo parte della pipeline GPU con tessellator

Il tessellator opera su patch formato da più domini (a ogni control point corrisponde un

dominio) e il cui input è il tessellation factor e il cui output è un patch in cui ciascuno dei

domini è stato suddiviso in un determinato numero di poligoni. L’interno di un tessellator è

formato da due stadi consecutivi:

Elaborazione in floating-point a 32 bit e si occupa di gestire le approssimazioni,

decodificare e ottimizzare lo input per il successivo stadio della tessellator unit;

Calcoli in fixed-point a 16 bit per eseguire l’operazione di tessellation vera e propria,

quindi stabilire la topologia del partizionamento. L’utilizzo della notazione in virgola

fissa a 16 bit deriva dal dover soddisfare esigenze di velocità di esecuzione senza

penalizzare eccessivamente la qualità delle operazioni svolte.

L’output dei DS è dato dai nuovi vertici e primitive definite dall’operazione di tessellation ed

è inviato ai GS, tutta l’elaborazione è fatta nel view space; l’output dei GS è inviato al

Rasterizer che esegue l’elaborazione nel canonical view volume e individua i pixel da

rappresentare su schermo, i pixel così ottenuti sono inviati ai pixel shader (PS). L’output dei

GS può essere anche inviato allo stream output per salvare i dati correnti e utilizzarli

successivamente per altre elaborazioni. L’ultima parte della pipeline è formata dall’output

merger che si occupa di raccogliere tutte i dati elaborati e combinarli assieme per ottenere

specifici effetti come le ombre, in questo modo sono impostati i pixel da visualizzare su

schermo sfruttando la combinazione del z test e stencil buffer (funge da maschera per i

pixel, questi possono essere cancellati oppure cambiati di valore ad esempio per dare

l’effetto di ombra).

115 Appendice A

A.6. Spazi in una scena 3D

Un oggetto prima di essere visualizzato su schermo deve essere riportato in diversi spazi,

ognuno di questi serve per definire le caratteristiche di posizione, colore, forma,

orientazione e consistenza; questi spazi convertono le varie caratteristiche degli oggetti in

coordinate e mettono in relazione le coordinate dell’oggetto considerato con gli altri in

modo tale che possano interagire fra loro.

Di seguito si riporta lo schema completo degli spazi che si utilizzano per rappresentare gli

oggetti e relative caratteristiche:

Figura 79 Spazi in una scena 3D

A.6.1. Object e world space

Il primo passo è quello di definire l’oggetto nell’object space (talvolta detto anche model

space), in cui ogni oggetto è rappresentato con un proprio sistema di coordinate; si sceglie

un punto che rappresenta l’origine degli assi (detto pivot point o object orgigin), tipicamente

un vertice della mesh o il suo baricentro, si utilizza tale origine per definire la posizione e le

dimensioni dell’oggetto nello spazio definito. Per ogni oggetto aggiunto alla scena, si

procede come descritto precedentemente per la scelta del pivot point. A questo punto ogni

oggetto ha un proprio sistema di coordinate e un pivot assegnato tramite il quale, l’oggetto

in questione, può essere traslato, ruotato e scalato (si comporterà come un corpo rigido);

quindi si utilizzano coordinate locali e si ha una certa facilità nella modellazione 3D. In

questo spazio gli oggetti possono non essere in relazione fra loro e sono rappresentati in

forma di vettori in coordinate omogenee con le relative normali, la quaterna è data da (x, y,

z, w); in questo modo a ogni terna x, y, z corrisponderà un’infinità di elementi al variare di

w.

Gli oggetti poi devono essere posti in uno spazio comune chiamato world space in modo tale

che essi siano messi in reciproca relazione spaziale.

116 Appendice A

Figura 80 Coordinate nel World space

A questo punto sono definite le proprietà dei singoli oggetti ossia di superficie, animazione

(skeletal) e illuminazione; il vantaggio di utilizzare coordinate omogenee consiste

nell’effettuare trasformazioni di coordinata, traslazione e scala ecc. sfruttando la

moltiplicazione tra vettori e matrici.

A.6.2. View e clip space

Per definire il view space è necessario stabilire la posizione dell’osservatore, che non deve

per forza coincidere con l’origine del world space, quindi il sistema di coordinate

(tipicamente terna sinistra) è orientato in modo tale che x, y e z coincidono rispettivamente

con l’asse orizzontale, verticale e quello normale al piano xy nella sua origine; tutto ciò serve

per definire la direzione e il verso in cui l’osservatore guarda. Il campo visivo non è illimitato,

per definire i limiti s’imposta un angolo solido con vertice nella posizione dell’osservatore

inserito nel view space che si apre nella direzione e verso in cui guarda; altri limiti sono

impostati mediante due piani perpendicolari all’asse z, direzione in cui si guarda, chiamati

far clipping plane (che limita il fondo del campo visivo) e near clipping plane (che limita il

campo visivo in prossimità del punto dell’osservatore). Tutto ciò serve per limitare il campo

visivo tramite sei piani (i clipping plane) che formano un tronco di piramide di nome view

frustrum.

Figura 81 View Frustrum

Tutto ciò che risiede nel view frustrum è renderizzato per lo specifico frame. Esistono vari

algoritmi per gestire il view frustrum culling (fase di clipping culling), tipicamente si procede

tramite delle celle che contengono dei poligoni (non si esaminano direttamente i poligoni);

da un punto di vista logico l’algoritmo funziona come descritto di seguito:

Cella fuori dal view frustrum allora è culled (cella scartata);

Cella inclusa nel view frustrum allora è rendered (cella renderizzata);

Cella parzialmente nel view frustrum. Si divide la cella fino eventualmente al singolo

poligono per stabilire cosa sta all’interno del view frustrum (tutto ciò che sta

all’interno del view frustrum è renderizzato).

117 Appendice A

Ora si procede con la fase di backface culling ossia si rimuovono le superfici di un oggetto

solido coperte alla vista in quanto nascoste da altre superfici visibili dallo stesso oggetto.

Quello che si ottiene va sotto il nome di clip space, le operazioni descritte precedentemente

servono per ottimizzare il rendering.

Il monitor è rettangolare e non è adatto a uno spazio a forma di tronco piramidale, il passo

successivo consiste nel proiettare l’immagine del clip space all’interno di un altro spazio a

forma di cubo dove le coordinate x, y variano tra -1, +1 e per z da 0 (che rappresenta il near

clipping plane) a 1 (far clipping plane) per DirectX 11 e -1, 1 per OpenGL.

Figura 82 Proiezione degli oggetti dal clipping space al cubo

Lo spazio così ottenuto prende il nome di canonical view volume, la visione in prospettiva è

un’illusione che si ottiene dalla deformazione degli oggetti proiettati in questo spazio.

A.6.3. Screen space e HSR

Lo schermo è a due dimensioni e di forma rettangolare quindi è necessario creare l’illusione

che gli oggetti si sviluppino lungo un’inesistente terza dimensione; per far ciò si sfrutta lo

screen space:

Dalle quattro dimensioni dello spazio omogeneo (x, y, z, w) si passa a uno di due (x,

y);

Lo spazio tridimensionale delle figure geometriche è sostituto da uno spazio

bidimensionale in cui si opera in termini di pixel.

Si taglia il canonical view volume in una serie di piani ideali perpendicolari a z, ogni piano è

individuato da mxn punti (x, y) e a ogni punto corrisponde un valore z comune a tutto il

piano; quindi gli oggetti presenti nel canonical view volume sono rappresentati da una serie

di piani. Per ogni frame si ha che per ogni punto di un poligono si associa una coppia di

coordinate (x, y) che ne individuano la posizione nello screen space z che ne definisce la

distanza dall’osservatore.

Prima di poter eseguire il rendering in modo efficiente, le GPU attuali devono individuare le

superfici nascoste dietro superfici facenti parte di altri oggetti (fino a questo punto sono

stati rimossi gli oggetti fuori dal view frustrum e le superfici nascoste da quelle dell’oggetto

medesimo). Quest’ultima fase prima del rendering è elaborata mediante algoritmi di nome

hidden surface removal (HSR), tipicamente fanno uso di uno o più z-buffer che contengono i

valori recenti di z dei vari piani dei poligoni; la scansione può essere front to back (quando si

parte dal piano dell’osservatore) e back to front (quando si parte dal piano più lontano

dall’osservatore).

118 Appendice A

A.7. NVIDIA approfondimenti

A.7.1. ROP

La raster operation pipeline esegue una delle ultime fasi del rendering; l’unità in questione,

preleva le informazioni relative ai pixel e texel (singoli elementi di una texture) ed esegue le

elaborazioni mediante operazioni matriciali e vettoriali per ottenere il valore finale del pixel

o di profondità. Richiede l’accesso alla memoria GDDR in lettura e scrittura.

Il back-end di GF110 è organizzato in sei blocchi ROP, ognuno dei quali contiene 8 unità per

un totale di 48 ROP; ogni partizione è in grado di gestire otto pixel di tipo intero a 32 bit per

ogni ciclo di clock. Questo dato è superiore agli otto blocchi GT200 capaci di quattro pixel

per clock. In quest’architettura si mantiene un controller di memoria a 64 bit per blocco, ma

realizza un incremento generale da 32 a 48 pixel per clock.

Questa GPU è migliore rispetto all’architettura Tesla anche dal punto di vista della gestione

dell’anti-aliasing eseguita dalle ROP; esiste una nuova modalità chiamata coverage sampling

anti-aliasing 32x (CSAA). Il risultato di queste ottimizzazioni è che NVIDIA afferma di avere

un calo prestazionale inferiore al 10% passando dall'anti-aliasing multi-sampling 8x al CSAA

a 32x (quindi si ha una lieve riduzione delle prestazioni a fronte di un notevole

miglioramento dell’anti-aliasing).

A.7.2. Tessellation

La NVIDIA ha implementato nell'architettura Fermi due componenti hardware per la

gestione della tessellation cioè PolyMorph engine e Raster engine (quest’ultima può essere

utilizzata anche per rasterizzare le mesh generate dai GS senza la tessellation); non ci sono

unità dedicate di hull e domain shader in NVIDIA Fermi, queste sono emulate via software

tramite gli shader core a differenza di quanto fatto da AMD / ATI .

Ogni SM ha un PolyMorph engine dotato al proprio interno di un'unità dedicata alla

tessellation e di altre unità specifiche per l’elaborazione della geometria degli oggetti 3D. La

presenza di cache L1 e L2 integrata nel chip consente un veloce passaggio dei dati tra SP e

PolyMorph engine, oltre che tra i vari SM presenti nella GPU, velocizzando tutte le

operazioni legate alla tessellation.

Figura 83 PolyMorph Engine

Quest’unità ha cinque stadi: Vertex Fetch, Tessellator, Viewport Transform, Attribute Setup

e Stream Output; il primo passo consiste nel fare il fetch (prelievo) dei vertex dal vertex

buffer globale, questi vertici sono inviati allo SM per il vertex shading e hull shading (eseguiti

119 Appendice A

dai CUDA core). Dopo queste elaborazioni si procede con il calcolo dei tessellation factor e

sono inviati al Tessellator; l’elaborazione dei domain shader e geometry shader avviene

nuovamente tramite i CUDA core. Il terzo stadio esegue la trasformazione di viewport

(divide il canonical view volume con dei piani paralleli tra loro e normali a z) e correzione

della prospettiva; l’Attribute Setup trasforma gli attributi dei vertici calcolati nella fase di

post-processing in equazioni di piano per rendere efficiente l’elaborazione di tipo shader.

L’ultimo stadio è opzionale, serve per mettere i vertici calcolati in uno stream verso la

memoria per eventuali elaborazioni successive.

C’è un Raster Engine per ogni GPC quindi per un totale di quattro unità, la pipeline è ha tre

stadi:

Figura 84 Raster Engine

L’Edge Setup esegue il fetch dei vertici e calcola le equazioni di edge del triangolo (le

equazioni delle rette sulle quali giacciono i segmenti del triangolo); i triangoli non visibili

sono rimossi mediante la tecnica del back face cull (vedere appendice). Ogni Edge Setup è in

grado di gestire una linea, punto o triangolo per clock; questo significa che nell’architettura

GF110 è possibile processare al massimo quattro triangoli per ogni ciclo di clock. L’unità

Rasterizer preleva le equazioni calcolate dal passo precedente e calcola la copertura dei

vertici; per ogni ciclo di clock la Rasterizer è in grado di generare otto pixel quindi un totale

di trentadue pixel per clock. Z-Cull individua le superfici nascoste e le elimina in modo tale

che queste non siano renderizzate, tutto ciò per migliorare l’utilizzo della banda a

disposizione.

A.7.3 CUDA

Il numero totale di warp in un blocco è dato da:

è il numero di thread per blocco, dimensione del warp che per tutte le architetture

fino ad ora è di trentadue thread, è uguale a arrotondato al multiplo più vicino a

.

Il numero totale di registri allocati per blocco sono dati per GPU con compute capability 1.x:

.

Invece per compute capability pari a 2.x:

120 Appendice A

è la granularità di allocazione dei warp che per compute capability 1.x è pari a due dato

che ogni SM ha soltanto sedici CUDA core, è il numero di registri utilizzati dal kernel, è

la granularità d’allocazione dei thread che per compute capability 1.0 e 1.1 è pari a 256 per

1.3 e 1.4 512 e per 2.x 64.

Il totale della memoria condivisa allocata in byte per blocco è pari a:

Dove è l’ammontare della memoria condivisa in byte occupata dal kernel, è la

granularità della memoria condivisa allocata che è pari a 512 nel caso di compute capability

1.x e 256 per compute capability 2.x.

121 Appendice B

Appendice B

B.1. Sviluppare mex in Visual Studio 2010 Professional

Per compilare le librerie mex, da usare in MATLAB, direttamente in ambiente Visual Studio

2010 Professional o superiore è necessario seguire i seguenti passi:

Creare un progetto di tipo C++ class library (dll);

In Configuration Properties->General->Target Extension aggiungere mexw64;

Creare un file def nel progetto che deve contenere l’indicazione LIBRARY

“name.mexw64” ed EXPORTS mexFunction;

In C/C++->General->AdditionalIncludeDirectories aggiungere

matlabroot\extern\include come folder addizionale dove matlabroot è la directory in

cui è installato il MATLAB;

In General cambiare l’estensione del file Target Extension da .dll a .mexw64;

In Linker->General->AdditionalLibraryDirectories aggiungere

matlabroot\extern\lib\microsoft;

In Linker->Input->AdditionalDependencies aggiungere libmx.lib, libmex.lib e

libmat.lib come dipendenze addizionali;

In Linker Input properties aggiungere il modulo .def.

B.2. Sviluppare CUDA Kernel in Visual Studio 2010 Professional

E’ necessario installare il software NVIDIA Parallel Nsight 2.0, questo aggiungerà in

automatico le variabili d’ambiente e le regole di compilazione per Visual Studio 2010

Professional o superiore.

Installare il software NVIDIA Parallel Nsight Monitor 2.0 sulla macchina su cui s’intende

eseguire il debugging; occorre osservare che sono sempre necessarie due GPU, una per il

rendering e l’altra su cui fare il debugging. Se la macchina utilizzata non ha due GPU, è

possibile utilizzare tale software per fare il debugging da remoto su una macchina con GPU

NVIDIA.

Creare un progetto C++ e utilizzare la regola di compilazione CUDA dal menu Build

Customization:

In C/C++->General->AdditionalIncludeDirectories aggiungere $(CUDA_INC_PATH);

In Linker->General->AdditionalLibraryDirectories aggiungere $(CUDA_LIB_PATH);

In Linker->Input->AdditionalDependencies aggiungere cudart.lib.

122 Appendice C

Appendice C

C.1. Libsvm

Per la Support Vector Machine si è utilizzata la libreria libsvm.

Utilizzo:

svm-train [options] training_set_file [model_file].

Opzioni (precedute dal simbolo -):

s svm_type : imposta il tipo di SVM (default 0)

0 -- C-SVC

1 -- nu-SVC

2 -- one-class SVM

3 -- epsilon-SVR

4 -- nu-SVR

t kernel_type : imposta il tipo di kernel (default 2)

0 -- linear: u'*v

1 -- polynomial: (gamma*u'*v + coef0)^degree

2 -- radial basis function: exp(-gamma*|u-v|^2)

3 -- sigmoid: tanh(gamma*u'*v + coef0)

4 -- precomputed kernel (kernel caricato da file)

- d degree: imposta il grado della kernel function (default 3)

- g gamma: imposta gamma nella kernel function (default 1/num_features)

- r coef0: imposta coef0 in kernel function (default 0)

- c cost: imposta il parametro C di C-SVC, epsilon-SVR, e nu-SVR (default 1)

- n nu: imposta il parametro di nu-SVC, one-class SVM, and nu-SVR (default 0.5)

- p epsilon: imposta epsilon in loss function di epsilon-SVR (default 0.1)

- m cachesize: imposta cache memory size in MB (default 100)

- e epsilon: imposta tolleranza del criterio di stop (default 0.001)

- h shrinking: usa shrinking heuristics, 0 o 1 (default 1)

- b probability_estimates: train di una SVC o SVR model per la stima di probabilità, 0 o 1

(default 0)

- wi weight: imposta il parametro C della classe i a weight*C, for C-SVC (default 1)

- v n: n-fold cross validation mode

- q: quiet mode (no outputs)

k in -g significa numero di attributi in input.