Articoli

ALGEBRA LINEARE PER TUTTI [Parte 1]

Autore: Paolo Caressa

 

Premessa

Come in ogni altro settore interdisciplinare nel machine learning ed nel deep learning si utilizzano necessariamente nozioni, concetti e formalismi che provengono da diverse fonti e, per molti versi, che richiedono mentalità diverse per essere compresi.

Per questo motivo, si è soliti dire che il data scientist dovrebbe essere un “incrocio” fra un informatico, uno statistico e un matematico ma pochi sono versati in tutte e tre le materie e difficilmente tutte e tre risulteranno egualmente facili, intuitive e belle a una stessa mente.

In particolare, delle varie nozioni matematiche che sono indispensabili ad un data scientist, come per chi è unicamente interessato a capire come funziona un sistema di machine learning per poterlo gestire al meglio, una delle nemesi è l’algebra lineare.

Ciò è sorprendente per i matematici che invece considerano l’algebra lineare una cosa facilissima.

Mi permetto di dire, citando il matematico I.M. Herstein, che l’algebra lineare ha solo tre caratteristiche, è facile, utile e bella!

Lo scopo di questo tutorial è di spiegare in modo semplice ma non privo di rigore le nozioni di base dell’algebra pertanto se già sapete calcolare autovettori ed autovalori di una matrice o magari una decomposizione in valori singolari (SVD) o un’analisi delle componenti principali (PCA) ci salutiamo qua. In caso contrario, buona lettura!

 

Il piano e lo spazio cartesiano

Prendiamola un po’ alla lontana, andando a scavare nei nostri ricordi delle scuole superiori: “la geometria analitica (o cartesiana)”

Inventata da Cartesio e Fermat nel XVII secolo, l’idea di base della geometria cartesiana è di fornire un modello numerico per il piano e lo spazio. In breve, la scoperta consiste nell’identificare l’insieme dei punti del piano (cioè mappato in maniera biunivoca in modo da esserne indistinguibile) con l’insieme delle coppie di numeri (x,y) con x ed y indipendenti.

Per prima cosa ricordiamo che i punti della retta si identificano all’insieme dei numeri reali (cioè razionali ed irrazionali) ordinato dalla solita relazione <.

Fissiamo un punto O sulla retta e corrispondente a 0, si fissa un punto U (diverso da O) e lo si fa corrispondere a 1; tutti gli altri punti sono determinati dalla posizione relativa rispetto a questi:

 

recta

È quindi chiaro cosa voglia dire la distanza fra due punti P e Q sulla retta: se x ed y sono i numeri corrispondenti, la distanza PQ è pari a |x – y| (valore assoluto della differenza):

 

Cattura 1 1

 

 

Quindi su una retta basta fissare lo zero e l’uno, col che si è fissato il verso dei numeri positivi (quelli che stanno tutti da una parte di O e comprendono U) e dei numeri negativi (quelli che stanno tutti da una parte di O e non comprendono U).

In questo modo:

La retta della geometria si identifica completamente nell’insieme R dei numeri reali

 

Ad un punto corrisponde uno e un solo numero, dove ogni numero reale possiamo immaginarlo come un numero decimale avente un numero finito di cifre dopo la virgola, avente un numero finito di cifre dopo la virgola che si ripetono indefinitamente, o avente un numero infinito non periodico di cifre dopo la virgola (a rigore bisogna escludere le sequenze che terminano con un 9 periodico).

Passiamo ora al piano.

Si fissa un punto O nel piano e si prende una retta x che passi per il punto ed una seconda retta ortogonale a x, chiamata y. Su x e y si sceglie una stessa unità di misura (cioè un punto U diverso da O e si stabilisce convenzionalmente che la distanza OU vale 1).

In questo modo si può misurare la distanza fra due punti che stanno su x rispetto all’unità di misura fissata.

La corrispondenza fra un punto P del piano e una coppia (a,b) di numeri avviene come segue:

  1. Si proietta il punto P sull’asse x ottenendo un punto P’ e si pone a = distanza fra P’ e O.
  2. Si proietta il punto P sull’asse y ottenendo un punto P’’ e si pone b = distanza fra P’’ e O.

Questo associa in modo unico a P la coppia (a,b): per passare invece dalle coordinate (a,b) ai punti basterà trovare i punti P’ e P’’ sulle rette x e y che distano per a e b dall’origine O, tracciare le perpendicolare agli assi per questi punti e determinare P come la loro intersezione.

Plano cartesiano

Figura 1. Tre punti del piano cartesiano, le loro coordinate e le loro proiezioni sugli assi, Fonte: wikipedia

 

 

Quindi:

Il piano della geometria si identifica completamente all’insieme R2 delle coppie di numeri reali: a un punto corrisponde una e una sola coppia.

La notazione R2 indica le coppie ordinate di elementi di R. Se X è un insieme Xn è in generale l’insieme delle n-ple di elementi di X.

Che vantaggio c’è nel considerare il piano come l’insieme delle coppie di numeri (a,b)?

  • In primo luogo sappiamo dire cosa sia, un insieme di coppie appunto, non ci servono assiomi o altro.
  • In secondo luogo trasformiamo i problemi geometrici, che normalmente coinvolgono costruzioni complicate e ragionamenti assai lunghi, in calcoli.

La geometria cartesiana è quindi la geometria ideale da fare al computer: possiamo ridurre tutto a numeri e calcoli. Non a caso, le librerie 2D che si usano per disegnare sullo schermo del computer, o su una finestra di una applicazione, rappresentano i punti come coppie di numeri (le coordinate) e un attributo che ne rappresenta il colore.

Per esempio: come si rappresenta una curva nel piano cartesiano?

Ci sono due modi:

  • Tramite una equazione cartesiana, una singola relazione che lega le coordinate di un suo generico punto
  • Tramite una equazione parametrica, che esibisce il generico punto della retta in funzione di un parametro.

Per esempio consideriamo l’equazione x2+y2 = 1 e l’equazione 2x+y = 0. La prima rappresenta una circonferenza di centro l’origine e raggio 1, la seconda una retta passante per l’origine.

Supponiamo di volerne calcolare le intersezioni: utilizzando la geometria classica dovremmo costruire queste intersezioni in qualche modo, mentre con la geometria cartesiana ci stiamo facendo la seguente domanda: quali sono i punti di coordinate (x,y) soggetti simultaneamente alle relazioni  x2+y2 = 1 e 2x+y = 0?

La seconda equazione equivale a dire y = –2x, che sostituita nella prima offre x2+(–2x)2 = 1, cioè x2+4x2 = 1 cioè x2 = 1/5, che ha due soluzioni x = 1/√5 e x = –1/√5, col che troviamo le due intersezioni richieste: i punti (1/√5, –2/√5) e (–1/√5, 2/√5).

A questo punto identifichiamo lo spazio cartesiano in tre dimensioni con l’insieme delle triple (x,y,z) di numeri reali, cioè con l’insieme R3.

Un punto nello spazio è quindi univocamente determinato dalle sue tre coordinate cartesiane, su cui possiamo lavorare per risolvere i problemi geometrici, dopo averli tradotti in problemi algebrici

 

Distanza fra due punti

Abbiamo detto che lungo una retta, identificata con l’insieme dei numeri reali, le distanze si calcolano col valore assoluto della differenza. Come calcoliamo invece le distanze nel piano?

La cosa interessante è che esistono diversi modi di farlo, che costituiscono tutti generalizzazioni della distanza sulla retta, citiamo le tre principali tutte appartenenti alla famiglia delle distanze di Minkonski:

  • la distanza euclidea
  • la distanza di Manhattan
  • la distanza uniforme.

La distanza euclidea fra due punti P = (x1,y1) e Q = (x2,y2) nel piano è data dalla formula seguente:

Cattura 2

Intanto vediamo che se P e Q stanno su una stessa retta, per esempio l’asse delle x, questa distanza si riduce al valore assoluto della differenza delle coordinate: infatti se supponiamo P = (x1,0) e Q = (x2,0) la  formula precedente ci porge :

 

cattura 3

(come al solito quando prendiamo la radice quadrata di un numero consideriamo quella positiva).

La distanza euclidea andrebbe in realtà chiamata pitagorica, in quanto segue dal teorema di Pitagora: supponiamo di avere un triangolo rettangolo OPQ, con un vertice nell’origine, un lato sull’asse delle x e l’altro lato perpendicolare all’asse delle x.

Dunque le coordinate di P saranno del tipo (x,0) e quelle di Q del tipo (x,y): la distanza fra O e P è x e quella fra Q e P è y, col che, per il teorema di Pitagora, d(O,Q)2 = d(O,P)2 + d(P,Q)2 = x2 + y2. Per cui in questo caso, prendendo la radice quadrata,

Cattura 4

e la formula è verificata. Nel caso generale il ragionamento è analogo ma intervengono anche le coordinate di O (che nel nostro caso risultano essere nulle).

Quindi la distanza euclidea si riduce alla distanza fra due punti su una retta e ha un evidente contenuto geometrico.

recta.opq

 

La distanza nello spazio si calcola in modo analogo tenendo conto che i punti hanno una coordinata in più: se P = (x1,y1,z1) e Q = (x2,y2,z2) sono punti dello spazio cartesiano, la loro distanza è:

Cattura 5 1

Per i più curiosi, spiego nel resto di questo paragrafo altri due modi di calcolare la distanza nel piano, che danno luogo a valori diversi della distanza euclidea ma che sono modi comunque validi di misurare quanto due punti sono vicini (un bel teorema che non è il caso di riportare qui dice comunque che, ai fini della relazione di “essere nei pressi di”, tutte queste distanze sono equivalenti).

Un’altra distanza che talvolta si usa in machine learning è la “distanza di Manhattan” anche conosciuta come “distanza dei taxi”:

d_1\left ( P,Q \right )= \left \| X_1-X_2 \right \| + \left \| Y_1-Y_2 \right \|

Di nuovo, se P e Q stanno sull’asse delle x, questa distanza coincide con il valore assoluto della differenza. Il nome distanza dei taxi è data dal fatto che la distanza fra P e Q non si misura col teorema di Pitagora, che cerca una scorciatoia diagonale fra P e Q ma partendo da P e muovendosi lungo l’asse delle x fino a giungere sopra o sotto a Q, per poi spostarsi lungo l’asse delle y e raggiungere Q.

 

 

 

 

 

 

DITANZA EUCLIDEA TRIANGULO

Figura 2. Distanza euclidea (verde) vs. distanza dei taxi (rosso)

È la manovra che deve fare un taxi per andare da un punto di un isolato al punto opposto: non può passare in mezzo all’isolato ma deve costeggiarne i lati.

Un’altra distanza ancora, che talvolta è utilizzata, è la “distanza uniforme”, che è definita comed_0 \left ( P,Q \right )= max \left \{ |x_1-x_2 | \right \}\left \{ |y_1-y_2 | \right \}

Cioè questa si calcola prendendo la lunghezza massima del segmento ottenuto proiettando i due punti sugli assi delle x e delle y: di nuovo è ovvio che se i punti giacciono sull’asse delle x questa si riduce al valore assoluto della differenza fra due punti.

Una notazione di colore: nello spazio, una “palla” si definisce come l’insieme dei punti che hanno distanza minore di un numero fissato, il raggio, da un punto fissato, il centro: cioè se O è il centro e r il raggio, tutti i punti tali che d(P,O) < r costituiscono la palla. Questa terminologia è chiara se usiamo la distanza euclidea.

Ma, usando la distanza dei taxi, che figura geometrica viene fuori considerando tutti i punti P tali che d1(P,O) < r? (suggerimento: si dice che questa distanza abbia le palle quadrate…).

Introduzione a Metodi di riduzioni della Dimensionalità ed elementi di Algebra lineare [Parte 2]

 

Autore: Matteo Alberti

                            

Sommario

Metodi lineari per la riduzione: 2

Identificazione attraverso l’individuazione di sottospazi 2

Approssimazioni Matriciali per la riduzione. 10

Casi di applicazione base: Decomposizione in Valori Singolari (SVD). 11

Norme Matriciali 11

Norme vettoriali 13

Norme indotte. 13

Norme di Schatten. 13

Norma di Frobenius. 13

Casi di applicazione base: Analisi dei Cluster. 16

Definizione di metrica. 16

Distanze di Minkowski (Manhattan, Euclidea, Lagrange). 16

 

 

 

Lo scopo di questo primo tutorial è di introdurre le nozioni base di riduzione della dimensionalità dal punto di vista matematico (spazi, sottospazi, mappe lineari) e di riprendere gli elementi necessari di algebra lineare (norme, isometria, isomorfismo…) per ogni algoritmo di machine learning.

 

Norme Matriciali

 

Abbiamo a questo punto impostato il problema della riduzione della dimensionalità dei dati come un problema di approssimazione tra matrici, dobbiamo a questo punto andar a stabilire valutare e quindi calcolare la distanza fra la matrice dei dati originari e quella approssimante attraverso lo studio delle differenti norme:

Esistono tre principali tipologie di norme:

  • Norme vettoriali
  • Norme indotte
  • Norme di Schatten

Dove nel campo dell’analisi dei dati essenzialmente ci si riconduce, salvo eccezioni, alla norma di Frobenius (distanza euclidea)

 

 

 

 

Elementi di algebra:

Norma

Una norma (comunemente contrassegnata con ) è una funzione dallo spazio vettoriale delle matrici se:

 

Art2 1

 

Norme vettoriali

 

La famiglia delle norme vettoriali trattano la matrice X_n_x_k  come un vettore di nk componenti dove possiamo definire la norma utilizzando una delle qualsiasi norme seguenti:

art2 imagr2

Nota:

Ponendo p=2 ci si ricollega alla norma euclidea

 

Norme indotte

 

Una matrice X_n_x_k  può essere vista come un operatore lineare da   R^k \mapsto R^n .

Misurando in R^k  le lunghezze con una norma fissata e facciamo altrettanto in R^n , con una differente norma, possiamo andare a misurare quanto X allunga o accorcia un vettore , confrontando la norma di v  \in R^k con la relativa norma della sua immagine Xv.

La norma indotta  \parallel X \parallel _k _n  risulta definita come:

 

art2 3

Norme di Schatten

 

La norma di Schatten, di ordine p, di una matrice X è data semplicemente da:

Art2 4

Dove \omega_i  sono i valori singolari

 

 

Norma di Frobenius

 

La norma di Frobenius della nostra matrice  X_n_x_k di partenza è data da:

ART25

 

 

Andando a svolgere i conti, esplicitando il prodotto matriciale si ottiene:

art6.art2

Ne corrisponde che la norma di Frobenius è pari alla radice quadrata della somma del quadrato degli elementi ossia una norma euclidea vista come un vettore che coincide con la norma vettoriale di X di ordine 2.

 

 

 

 

 

Elementi di algebra:

Traccia

L’operatore traccia, indicata con Tr \left ( . \right ), è definita come la somma degli elementi diagonali della matrice argomento

 

 

 

 

 

 

 

 

Casi di applicazione base: Analisi dei Cluster

 

La cluster analysis e’ una tecnica di analisi multivariata attraverso la quale e’ possibile raggruppare le unità statistiche, in modo da minimizzare la “lontananza logica” interna a ciascun gruppo e di massimizzare quella tra i gruppi.

Rientra fra le tecniche di apprendimento non supervisionato.

Nasce quindi spontaneo dover definire che cosa si intende per lontananza logica ed in base a quale metrica.

 

 

 

Definizione di metrica

Sia  X^-\in R^p ed Y^-\in R^p definiamo metrica una funzione tale che   R^p x R^p\mapsto R^+   U\left \{ 0 \right \} 

che goda delle seguenti proprietà:

  •  d \left ( X^-, Y^- \right ) \geq O non negativa
  •  d \left ( X^-, Y^- \right ) = d \left ( Y^-,X^- \right ) simmetria
  •  d \left ( X^-, Y^- \right ) = 0 \leftrightarrow X= Y identità
  •  d \left ( X^-, Y^- \right ) \leq d \left ( X^-, Z^- \right ) + d \left ( Z^-, X^- \right )   diseguaglianza triangolare

 

Distanze di Minkowski (Manhattan, Euclidea, Lagrange)

 

Andiamo a questo punto ad analizzare i casi principali delle distanze appartenenti alla famiglia delle distanze di Minkowski dove:

art27

Evidenziamo i seguenti casi:

  • k=1 Distanza di Manhattan
  • k=2  Distanza Euclidea
  • k\rightarrow \infty Distanza Lagrangiana (Čebyšëv)

In particolare:

 

 

euclidea

Riprendendo dunque con l’esempio della Cluster Analysis, risulta fondamentale quindi definire il tipo di distanza con cui vogliamo affrontare la nostra analisi.

Principalmente nei pacchetti già implementati si trovano le tre varianti delle distanze di Minkowski (per variabili quantitative)

Importando da sklearn:

AgglomerativeClustering(n_clusters=2, affinity=’euclidean’, memory=None, connectivity=None, compute_full_tree=’auto’, linkage=’ward’

 

 

distanze

 

 

Deep Learning Italia – Milano – 19 ottobre 2018

Il Meetup #AperiTech di ottobre di Deep Learning Italia!

• Cosa faremo
“Deep Learning Italia” è lieta di invitarvi al suo Meetup a Milano.

Registrazione obbligatori su eventbrite:

https://www.eventbrite.it/e/biglietti-milano-meetup-aperitech-di-deep-learning-italia-50642063776

Info e prenotazioni a: info@deeplearningitalia.com

Vi aspettiamo!!!

Scaletta Talks:

1) Matteo Testi Founder Deep Learning Italia & Luciano Di Benedetto Head of Big Data at Sferanet

“Introduzione alla piattaforma Deep Learning Italia”
Abstract: Illustrazione della community Deep Learning Italia e degli strumenti oggi sviluppati e a disposizione della community. Introduzione alle features del sito www.deeplearningitalia.com: i tutorials, il question & answer, le references, gli sviluppi futuri.

2) SK Reddy Chief Product Officer AI for Hexagon, located in Silicon Valley

Title: Making sense with 3D Point Clouds using Deep Learning

Abstract: Processing 3D images has many use cases. For example, to improve autonomous car driving, to enable digital conversions of old factories, enable augmented reality solutions for medical surgeries, etc. 3D image processing brings enormous benefits but also amplifies computing cost. The size of the point cloud, the number of points, sparse and irregular point cloud, and the adverse impact of the light reflections, (partial) occlusions, etc., make it difficult for engineers to process point clouds. Moving from using handcrafted features to using deep learning techniques to semantically segment the images, to classify objects, to detect objects, to detect actions in 3D videos, etc., we have come a long way in 3D image processing. 3D Point Cloud image processing is increasingly used to solve Industry 4.0 use cases to help architects, builders and product managers. I will share some of the innovations that are helping the progress of 3D point cloud processing. I will share the practical implementation issues we faced while developing deep learning models to make sense of 3D Point Clouds.

Linkedin: https://www.linkedin.com/in/sk-reddy/

Website: http://hexagon.com

3) Matteo Alberti Techedge & Deep Learning Italia

Applicazione dei principali algoritmi di Deep Learning al mondo Finance:

0) I limiti della modellistica AR, ARIMA,ARMA

1) Applicazione di Reti Ricorrenti (LSTM)

2) Dalle Convoluzioni 2D all’estrazione di Pattern

3) Strumenti di Riduzione della dimensionalità per inglobare indici nella nostra predizione (dalle linearità ad Autoencoder)

4) Cenni al Reinforcement Learning per Automated Stock Trading

Il tutto con alucni esempi pratici con codice in Tensorflow

Programmazione funzionale per il deep learning

Autore: Joyce Xu

Traduttrice: Sabrina Sala

 

Fino a poco tempo fa il concetto di “programmazione funzionale” e “machine learning”(Apprendimento Automatico)  erano attribuiti a due mondi nettamente separati. Il primo è un paradigma di programmazione che ha guadagnato popolarità nel momento in cui si il mondo si è rivolto alla semplicità ed alla componibilità per produrre pplicazioni scalabili complesse; il secondo è uno strumento utilizzato per istruire un computer come un completamento automatico di scarabocchi e a comporre musica. Non vi era quindi dialogo tra questi due elementi.

Ma studiandoli ed approfondendoli con attenzione ci si rende conto che la loro sovrapposizione è sia pratica sia teorica. Innanzitutto, il machine learning non è un elemento a sé stante ma piuttosto, per essere sfruttato, deve essere incorporato in applicazioni scalabili complesse. In secondo luogo, il machine learning, e in particolare il deep learning(apprendimento profondo) , è funzionale nel suo design:

  • I modelli di deep learning (apprendimento profondo) sono componibili: la programmazione funzionale riguarda comporre catene di funzioni di ordine superiore per operare su semplici strutture di dati. Le reti neurali sono disegnate nella stessa maniera, concatenando funzioni di trasformazione da uno strato a quello successivo, per operare su una semplice matrice di dati di input. Infatti l’intero processo di deep learning può essere visto come l’ottimizzazione di un set di funzioni composte. Ciò comporta che i modelli in sé siano intrinsecamente funzionali.

 

  • Le componenti di deep learning (apprendimento profondo) sono immutabili: quando applichiamo le funzioni sui dati di input, i nostri dati non cambiano ma, piuttosto, viene prodotto un nuovo set di valori. In aggiunta, quando i pesi sono aggiornati, non hanno bisogno di essere “mutati” ma rimpiazzi da un nuovo valore. In teoria l’aggiornamento dei pesi può essere applicato in qualsiasi ordine (ovvero non sono dipendenti l’uno dall’altro) e non c’è quindi necessità di tenere traccia in maniera sequenziale del relativo cambiamento.

 

  • La programmazione funzionale offre facilità nella parallelizzazione. Ancor più importante, però, è che le funzioni che sono totalmente componibili sono facili da parallelizzare. Ciò comporta maggiori velocità e potenza computazionale. La programmazione funzionale fornisce concurrency e parallelismo a costi quasi pari a zero, rendendo così più semplice lavorare in apprendimento profondo con modelli larghi e distribuiti.

Ci sono differenti teorie e prospettiva riguardanti la combinazione tra programmazione funzionale e deep learning (apprendimento profondo) , sia dal punto di vista matematico sia da quello pratico, ma tuttavia alcune volte è più semplice vederla in maniera pratica. In questo articolo andremo a introdurre le idee alla base della programmazione funzionale e di come applicarle in un modello Cortex di deep learning per la classificazione dei valori anomali.

Le basi di Clojure

Prima di continuare con il tutorial su Cortex, introduciamo alcune nozioni di base in merito a Clojure. Clojure è un linguaggio di programmazione funzionale ottimo per concurrency e data processing. Per nostra fortuna, questi sono entrambi estremamente utili nel machine learning. Infatti la ragione primaria per cui utilizziamo Clojure per il machine learning è che il lavoro di preparazione dei dataset di allenamento (manipolazione dei dati, processing ecc.) può facilmente compensare il lavoro di implementazione degli algoritmi, specialmente quando si hanno librerie solide come Cortex.  Utilizzare Clojure e .edn (piuttosto che C++ e protobuf) ci da un vantaggio in termini di velocità su progetti di machine learning.

Potete trovare un’introduzione più approfondita sul linguaggio qui.

Partiamo con le basi: il codice di Clojure è formato da un insieme di espressioni. Queste sono racchiuse in parentesi e tipicamente trattate come funzioni di chiamata.

(+ 2 3)          ; => 5
(if false 1 0)   ; => 0

Ci sono 4 strutture di dati base: vettori, liste, hash-map e set. Le virgole sono considerate come spazi bianchi, quindi vengono solitamente omesse.

[1 2 3]            ; vector (ordered)
‘(1 2 3)           ; lists (ordered)
{:a 1 :b 2 :c 3}   ; hashmap or map (unrdered)
#{1 2 3}           ; set (unordered, unique values)

Il virgolettato singolo, che precede la lista, è unicamente uno strumento per far sì che essa non venga rilevata come espressione.

Clojure ha anche molte funzioni integrate per funzionare su queste strutture di dati. Parte del fascino di Clojure sta nel suo design ricco di funzioni per poche tipologie di dati molto ridotti, il che si contrappone alla comune prassi di avere poche funzioni specializzate per il maggior numero possibile di strutture dati. Clojure, essendo un linguaggio di functional programming, supporta funzioni di alto livello, il che significa che le funzioni possono essere importate come argomento su altre funzioni.

(count [a b c])              ; => 3

(range 5)                    ; => (0 1 2 3 4)

(take 2 (drop 5 (range 10))) ; => (5 6)

(:b {:a 1 :b 2 :c 3})        ; use keyword as function => 2

(map inc [1 2 3])            ; map and increment => (2 3 4)

(filter even? (range 5))     ; filter collection based off predicate => (0 2 4)

(reduce + [1 2 3 4])         ; apply + to first two elements, then apply + to that result and the 3rd element, and so forth => 10

Potremmo ovviamente scrivere le nostre funzioni in Clojure utilizzando defn. La definizione delle funzioni di Clojure seguono la forma (defn fn-name [params*] expressions) e inoltre restituiscono il valore dell’ultima espressione nel corpo.

[x]
(+ x 2))(add2 5)     ; => 7

Le espressioni “let” creano e associano le variabili all’interno dello scope lessicale, definito lexical scope, di “let”. Ciò viene fatto nell’espressione (let [a 4] (…)), in cui la variabile “a” presenta un valore di 4 solamente nelle parentesi interne. Queste variabili sono chiamate “locali”.

(defn square-and-add
[a b]
(let [a-squared (* a a)
b-squared (* b b)]
(+ a-squared b-squared)))

(square-and-add 3 4)       ; => 225

Abbiamo, infine, due modi per creare funzioni “anonime”, che possono essere assegnate a una funzionale locale o ad una di ordine superiore.

(fn [x] (* 5 x))          ; anonymous function#(* 5 %)                  ; equivalent anonymous function, where the % represents the function’s argument(map #(* 5 %) [1 2 3])    ; => (5 10 15)

Questo è tutto per le informazione di base. Ora che abbiamo imparato qualche nozione su Clojure, torniamo al machine learning.

Cortex

Cortex è scritta in Clojure, ed è attualmente una delle librerie di machine learning più vaste e in rapida crescita, che utilizza un linguaggio di programmazione funzionale. Il resto dell’articolo si focalizzerà su come costruire un modello di classificazione in Cortex, insieme ai Paradigmi di programmazione funzionale e le tecniche di arricchimento dei dati (data augmentation) richieste.

Data preprocessing

Prendiamo un dataset di frodi legate a carte di credito, fornito da questo sito. Queste dataset è molto sbilanciato, per il fatto che container solo 492 casi di fronde positivi su un totale di 248’807, in pratica lo 0,172%. Ciò ci creerà dei problemi ma, per ora, limitiamoci a guardare i dati e a vedere il funzionamento del modello.

Per assicurare l’anonimità dei dati personali, tutte le caratteristiche originarie, eccetto “time” e “amount”, sono già state trasformate in componenti principali, o PCA (dove ogni entry rappresenta una nuova variabile che contiene le informazioni più rilevanti dei dati grezzi). Una breve occhiata ai dati ci mostra che la prima variabile “time” ha un limitato contenuto informativo, quindi la lasciamo da parte. Di seguito vediamo come appare il nostro gruppo di codici:

 

(ns fraud-detection.core

(:require [clojure.java.io :as io]

[clojure.string :as string] [clojure.data.csv :as csv] [clojure.core.matrix :as mat] [clojure.core.matrix.stats :as matstats]

[cortex.nn.layers :as layers]

[cortex.nn.network :as network]

[cortex.nn.execute :as execute]

[cortex.optimize.adadelta :as adadelta]

[cortex.optimize.adam :as adam]

[cortex.metrics :as metrics]

[cortex.util :as util]

[cortex.experiment.util :as experiment-util]

[cortex.experiment.train :as experiment-train]))

(def orig-data-file “resources/creditcard.csv”)

(def log-file “training.log”)

(def network-file “trained-network.nippy”)

;; Read input csv and create a vector of maps {:data […] :label [..]},

;; where each map represents one training instance in the data

(defonce create-dataset

(memoize

(fn []

(let [credit-data (with-open [infile (io/reader orig-data-file)]

(rest (doall (csv/read-csv infile))))

data (mapv #(mapv read-string %) (map #(drop 1 %) (map drop-last credit-data))) ; drop label and time

labels (mapv #(util/idx->one-hot (read-string %) 2) (map last credit-data))

dataset (mapv (fn [d l] {:data d :label l}) data labels)]

dataset))))

 

Le reti neurali di Cortex utilizzano dati di input in forma di mappe, dove ogni mappa rappresenta un singolo dato con i relativi label associati (per esempio, se ho l’immagine di un cane, il label sarà “cane”). Una classificazione, per esempio, può apparire come [{:data [12 10 38] :label “cat”} {:data [20 39 3] :label “dog“} … ]

Nella nostra funzione per la creazione di dataset ad hoc, vediamo che nel data file di formato comma-separated value, tutte le colonne a parte l’ultima formano i nostri “data” (o caratteristiche), mentre l’ultima colonna rappresenta il label, ovvero l’etichetta. Nel frattempo, trasformiamo i label in one-hot vector (per esempio [0 1 0 0]) basati sulla classe di classificazione. Ciò perché l’ultimo strato soft max nella nostra rete neurale produce un vettore di probabilità di classe, e non il label stesso. Infine, creiamo la mappa da queste due variabili e la salviamo come dataset.

Descrizione del modello

Creare un modello in Cortex è un’operazione piuttosto semplice e diretta. Prima di tutto dobbiamo definire una mappa di parametri superiori che verrà usata successivamente durante l’allenamento. In seguito, per definire il modello, uniamo semplicemente gli strati:

 

(def params

{:test-ds-size      50000 ;; total = 284807, test-ds ~= 17.5%

:optimizer         (adam/adam)   ;; alternately, (adadelta/adadelta)

:batch-size        100

:epoch-count       50

:epoch-size        200000})

(def network-description

[(layers/input (count (:data (first (create-dataset)))) 1 1 :id :data) ;width, height, channels, args

(layers/linear->relu 20) ; num-output & args

(layers/dropout 0.9)

(layers/linear->relu 10)

(layers/linear 2)

(layers/softmax :id :label)])

Dove network-description è un vettore di strati di rete neurale. Il nostro modello consiste in:

  • Uno strato di input
  • Uno strato completamente connesso (e lineare) con la funzione di attivazione ReLu
  • Un layer dropout
  • Un altro strano completamente connesso con ReLu
  • Un strato di output di dimensione 2 , passato attraverso la funzione softmax

Nel primo e ultimo strato, dobbiamo specificare un :id. questo si riferisce alla chiave nella mappa dei dati a cui la nostra rete dovrebbe guardare. Ricordiamo che la mappa risulta come {:data […] :label […]}). Per il nostro strato di input, passiamo in :data id affinché il modello prenda i dati di allenamento nei passaggi successivi. Nello strato finale forniamo, invece, :label come :id, così che possiamo utilizzare il vero label per calcolare il nostro errore.

Allenamento e valutazione

Da qui in poi diventa più complesso. La funzione di allenamento non è in realtà così complicata: Cortex da infatti funzioni preistruite per l’allenamento di alto livello, quindi tutto ciò che dobbiamo fare è settare nostri parametri (la rete, dataset di allenamento e verifica ecc). L’unico avvertimento che vi diamo è che il sistema si aspetta un “infinito” dataset per l’allenamento. tuttavia, Cortex  presenta una funzione infinite-class-balanced-dataset che ci aiuta a trasformarlo.

(defn train)

“Trains network for :epoch-count number of epochs”

[]

(let [network (network/linear-network network-description)

[train-orig test-ds] (get-train-test-dataset)

train-ds (experiment-util/infinite-class-balanced-dataset train-orig

:class-key :label

:epoch-size (:epoch-size params))]

(experiment-train/train-n network train-ds test-ds

:batch-size (:batch-size params)

:epoch-count (:epoch-count params)

:optimizer (:optimizer params)

:test-fn f1-test-fn)))

Quindi arriviamo alla parte complessa: f1-test-fn. Durante l’allenamento, infatti, la funzione train-n si aspetta che le venga fornito un :test-fn che ne verifichi la performance e che determini se debba essere salvata come “best network”. È presente una funzione test di default che individua la perdita cross-entropica (cross-entropy loss)ma il suo valore di perdita non è così semplice da interpretare e, inoltre, non si adatta perfettamente il nostro dataset poco bilanciato. Per risolvere questo problema, andremo a scrivere una nostra personale funzione test.

Ma sorge ora una domanda: come possiamo verificare le performance del nostro modello? La metrica standard nei task di classificazione è solitamente l’accuratezza ma, con il nostro dataset sbilanciato, questa misura è pressoché inutile. Poiché gli esempi positivi contano solo per lo 0,172% del dataset totale, anche un modello che si limiti a prevedere esempi negativi, potrebbe raggiungere il 99.828% di accuratezza. Una percentuale particolarmente elevata, ma nel caso in cui questo modello venisse utilizzato nella realtà, sorgerebbero diversi problemi.

Un migliore gruppo di metriche è quindi: precisione, recupero, e F1 score (o genericamente F-beta).

1 1

1 1

La precisione ci pone quindi di fronte a una domanda: “di tutti gli esempi che ho previsto essere positivi, quale proporzione è di fatto positiva?” Mentre per il recupero ci chiediamo: “di tutti gli esempi  positivi, quale proporzione ho previsto con esattezza essere positiva?”
Visualizzazione di precisione e recupero. Fonte https://en.wikipedia.org/wiki/Precision_and_recall

Il F-beta score (una generalizzazione del tradizionale F1 score) è una media ponderata di precisione e recupero, misurata in una scala da 0 a 1:

2.jpg 2

Quando beta = 1, otteniamo F1 come of 2 * (precisione * recupero) / (precisione + recupero). Solitamente beta rappresenta quante volte recupero debba essere più importante di precisione. Nel nostro modello utilizziamo il F1 score come nostro punteggio da ben approssimare ma registriamo anche i punteggi di precisione e recupero per rilevare il bilanciamento. Questo è il nostro f1-test-fn:

 

(defn f-beta

“F-beta score, default uses F1”

([precision recall] (f-beta precision recall 1))

([precision recall beta]

(let [beta-squared (* beta beta)]

(* (+ 1 beta-squared)

(try                         ;; catch divide by 0 errors

(/ (* precision recall)

(+ (* beta-squared precision) recall))

(catch ArithmeticException e

0))))))

(defn f1-test-fn

“Test function that takes in two map arguments, global info and local epoch info.

Compares F1 score of current network to that of the previous network,

and returns map:

{:best-network? boolean

:network (assoc new-network :evaluation-score-to-compare)}”

[;; global arguments

{:keys [batch-size context]}

;per-epoch arguments

{:keys [new-network old-network test-ds]} ]

(let [batch-size (long batch-size)

test-results (execute/run new-network test-ds

:batch-size batch-size

:loss-outputs? true

:context context)

;;; test metrics

test-actual (mapv #(vec->label [0.0 1.0] %) (map :label test-ds))

test-pred (mapv #(vec->label [0.0 1.0] % [1 0.9]) (map :label test-results))

precision (metrics/precision test-actual test-pred)

recall (metrics/recall test-actual test-pred)

f-beta (f-beta precision recall)

;; if current f-beta higher than the old network’s, current is best network

best-network? (or (nil? (get old-network :cv-score))

(> f-beta (get old-network :cv-score)))

updated-network (assoc new-network :cv-score f-beta)

epoch (get new-network :epoch-count)]

(experiment-train/save-network updated-network network-file)

(log (str “Epoch: ” epoch “\n”

“Precision: ” precision  “\n”

“Recall: ” recall “\n”

“F1: ” f-beta “\n\n”))

{:best-network? best-network?

:network updated-network}))

La funzione esegue la rete sul test set, calcola il F1 score e, infine, aggiorna e salva la rete di conseguenza. Inoltre, stampa ognuna delle nostre metriche di valutazione ad ogni punto. Se ora eseguissimo il REPL, avremmo uno score che sarebbe all’incirca così:

Epoch: 30
Precision: 0.2515923566878981
Recall: 0.9186046511627907
F1: 0.395

Un risultato piuttosto scarso.

Arricchimento dei dati (Data Augmentation)

Eccoci arrivati al problema di cui abbiamo parlato all’inizio di questo articolo, dovuto allo sbilanciamento del dataset. Il modello non presenta ora sufficienti esempi positivi da cui apprendere. Quando richiamiamo experiment-util/infinite-class-balanced-dataset nella nostra funzione di allenamento, stiamo di fatto creando centinaia di copie di ogni istanza di allenamento positiva per bilanciare il nostro dataset. Ne risulta che il modello memorizza quei valori di caratteristiche, piuttosto che apprendere la distinzione tra le classi.

Un modo per ovviare a questo problema è utilizzare l’arricchimento dei dati, con il quale generi amo dati aggiuntivi e artificiale basati sugli esempi che già abbiamo disponibili. Per creare degli esempi di allenamento che siano positivi, dobbiamo aggiungere una qualsiasi quantità di rumore ai delle features vectors (vettori contenenti le caratteristiche) per ogni esempio positivo esistente. La quantità di rumore da noi aggiunta dipenderà dalla varianza di ogni caratteristica nelle classi positive, in modo che le feature con un’ampia varianza siano arricchite con una grande quantità di rumore, e l’opposto per quelle con bassa varianza.

Di seguito il codice per l’arricchimento dei dati:

(defonce get-scaled-variances

(memoize

(fn []

(let [{positives true negatives false} (group-by #(= (:label %) [0.0 1.0]) (create-dataset))

pos-data (mat/matrix (map #(:data %) positives))

variances (mat/matrix (map #(matstats/variance %) (mat/columns pos-data)))

scaled-vars (mat/mul (/ 5000 (mat/length variances)) variances)]

scaled-vars))))

(defn add-rand-variance

“Given vector v, add random vector based off the variance of each feature”

[v scaled-vars]

(let [randv (map #(- (* 2 (rand %)) %) scaled-vars)]

(mapv + v randv)))

(defn augment-train-ds

“Takes train dataset and augments positive examples to reach 50/50 balance”

[orig-train]

(let [{train-pos true train-neg false} (group-by #(= (:label %) [0.0 1.0]) orig-train)

pos-data (map #(:data %) train-pos)

num-augments (- (count train-neg) (count train-pos))

augments-per-sample (int (/ num-augments (count train-pos)))

augmented-data (apply concat (repeatedly augments-per-sample

#(mapv (fn [p] (add-rand-variance p (get-scaled-variances))) pos-data)))

augmented-ds (mapv (fn [d] {:data d :label [0 1]}) augmented-data)]

(shuffle (concat orig-train augmented-ds))))

augment-train-ds prende il nostro dataset di allenamento originario, calcola il numero di arricchimenti necessario per raggiungere un bilanciamento di classe 50/50, e applica poi questi arricchimenti ai nostri esempi esistenti attraverso un qualsiasi vettore di rumore (add-rand-variance) basato sulla varianza consentita (get-scaled-variances). Infine, concateniamo gli esempi arricchiti con il dataset originario ed otteniamo un dataset bilanciato.

Durante l’allenamento, il modello rileva una quantità irrealisticamente ampia di esempi positivi, mentre il set di verifica rimarrà positivo al 0.172%. come risultato, nonostante il modello potrà essere in grado di apprendere in modo migliore la differenza tra le due classi, comunque overfitteremo la nostra classe con di esempi positivi. Per risolvere tale problema, possiamo cambiare le relative soglie in modo da forzare la predizione positiva durante il testing. In altre parole, piuttosto che richiedere al modello almeno il 50% di certezza della positività degli esempi per classificarli come tali, possiamo aumentare la richiesta ad almeno il 70%. Dopo alcuni test, abbiamo notato che la soglia minima dovrebbe essere impostata al 90%. Il codice può essere trovato in  vec->labelfunction nel codice sorgente, ed è richiamato alla linea 31 del f1-test-fn.

Usando il nuovo e arricchito dataset per l’allenamento, i nostri scores si presentano all’incirca così:

Epoch: 25
Precision: 0.8658536585365854
Recall: 0.8255813953488372
F1: 0.8452380952380953

Risultati nettamente migliori rispetto a quelli precedenti.

Conclusioni

Questo modello può ovviamente essere ancora migliorato. Di seguito, alcuni consigli:

  • Tutte le PCA feature sono informative? Osservate la distribuzione dei valori per gli esempi positivi e negativi attraverso le feature e scartate ogni feature che non aiuta a distinguere tra le due classi
  • Vi sono altre architetture di reti neurali, funzioni di attivazione ecc che performano meglio?
  • Vi sono diverse tecniche di arricchimento dei dati che potrebbero performare meglio?
  • Come si rapporta la performance del modello in Cortex rispetto a Keras/Tensorflow/Theano/Caffe?

L’intero codice sorgente per questo progetto può essere trovato qui. Vi incoraggiamo a sperimentare gli step successivi, ad esplorare differenti architetture di reti (qui c’è un ottimo esempio di classificazione di immagini su CNN che potete prendere come riferimento).

 

Deep Learning Italia – Roma – Luglio 2018

1) Francesco Pugliese – Co-Founder Deep Learning Italia | Ricercato ISTAT
“Introduzione divulgativa alle Reti Neurali e al Deep Learning”.
Abstract: Descrizione introduttiva del modello del neurone artificiale e confronto con il neurone biologico, la storia delle reti neurali e come si è arrivati oggi al Deep Learning, detrattori vs sostenitori delle reti neurali e vittoria dei sostenitori (Hinton, LeCunn, Benjo). I successi del Deep Learning e la disfatta del Machine Learning tradizionale di oggi in settori come Computer Vision, Natural Language Processing e Giochi (GO, Chess, ecc.).

2) Matteo Testi- Founder Deep Learning Italia
“Introduzione alla piattaforma Deep Learning Italia”
Abstract: Illustrazione della community Deep Learning Italia e degli strumenti oggi sviluppati e a disposizione della community. Introduzione alle features del sito www.deeplearningitalia.com: i tutorials, il question & answer, le references, gli sviluppi futuri.

3) Ayadi Ala Eddine – Data Scientist at InstaDeep UK – AI researcher intern at Università degli Studi di Padova on deep reinforcement learning and a kaggle expert with more than 3 years of experience in data science, machine learning and statistics by working on real-life problems, a passion holder for deploying predictive models and deep learning techniques.
“Generative Adversarial Networks – Tensorflow to build GAN’s”
Abstract: GANs has been one of the most interesting developments in deep learning and machine learning recently. Through an innovative combination of computational graphs and game theory, we are going to show you how two models fighting against each other would be
able to co-train and generate new samples. Finally, we will end up with a demo where I will show you some cool stuff people have done using GAN and give you links to some of the important resources for getting deeper into these techniques.

 

link iscrizione

Utilizzo di deep learning per il riconoscimento di oggetti

Autrice: Joyce Xu

Traduttrice: Sabrina Sala

 

 

1

 

Con la comparsa di veicoli a guida autonoma, sistemi di videosorveglianza intelligenti e varie applicazioni come quella del conteggio delle persone, la richiesta di sistemi di riconoscimento facciale è ormai in continua crescita. Questi sistemi riguardano non solo il riconoscimento e la classificazione degli oggetti presenti nelle immagini, ma anche la localizzazione di ciascuno di essi, tracciando attorno ad essi un appropriato riquadro di delimitazione. Ciò ha reso il sistema di riconoscimento di oggetti un compito sempre più complesso rispetto al suo predecessore nell’ambito della visione artificiale: la classificazione di immagini.

Fortunatamente gli approcci più appropriati per il riconoscimento di oggetti sono, attualmente, estensioni di modelli per la classificazione di immagini. Qualche mese fa Google ha rilasciato una nuova API (interfaccia di programmazione di un’applicazione) di riconoscimento di oggetti in Tensorflow. In questa release troviamo modelli pre-addestrati con i relativi pesi:

Nello scorso articolo, abbiamo parlato delle tre architetture di reti neurali sopra citate (MobileNets, Inception e ResNet), oggi affronteremo invece i modelli di riconoscimento di oggetti per Tensorflow: Faster R-CNN, R-FCN e SSD. Attraverso questo articolo capiremo come il deep learning è applicato a questi modelli per il riconoscimento di oggetti, come questi ultimi si differenzino tra loro e quali siano i punti in comune.

Faster R-CNN

La faster R-CNN è ormai un modello di riferimento per la rilevazione di oggetti basata sul deep learning  (apprendimento profondo), che ha ispirato molti modelli successivi di rilevazione e segmentazione, inclusi i due che andremo ad esaminare. Sfortunatamente non possiamo comprendere appieno la Faster R-CNN senza analizzare R-CNN e Fast R-CNN, sue predecessori.

R-CNN

Possiamo certamente dire che la R-CNN, Region-based Convolutional Neural Network, è la rete che ha dato il via ai giochi. Consiste in tre fasi:

  1. Scansione dell’immagine di input per la rilevazione di possibili oggetti, utilizzando un algoritmo chiamato Selective Search, che estrae approssimativamente 2000 regioni di questa immagine (Region Proposal)
  2. Esecuzione della rete neurale convoluzionale (CNN) in cima a ciascuna regione.
  3. Estrapolazione dell’output da ogni CNN per immetterlo dentro ad:
    1. una SVM (Support Vector Machine) per classificare la regione
    2. Effettuare una regressione lineare per restringere il riquadro di delimitazione dell’oggetto, se esistente.

Le fasi sono illustrate (dal basso verso l’alto) nella figura sottostante

2

2

In altre parole, prima generiamo le possibili regioni, quindi estraiamo le caratteristiche e infine classifichiamo quelle regioni sulla base delle caratteristiche estratte. In sostanza, abbiamo trasformato la rilevazione di oggetti in un problema di classificazione. La R-CNN risulta molto intuitiva ma, sfortunatamente, anche molto lenta.

Fast R-CNN

Lo sviluppo immediatamente successivo è la Fast R-CNN. Questa ricorda l’originale in molte delle sue caratteristiche ma è migliore in termini di velocità di rilevazione per due aspetti:

  1. L’estrazione di caratteristiche viene effettuata prima di estrarre le regioni di interesse, ma utilizzando solo una CNN per l’intera immagine al posto che 2000 CNN sulle 2000 regioni sovrapposte.
  2. La SVM viene rimpiazzata da una funzione softmax e, inoltre, la rete neurale viene utilizzata anche per le previsioni anziché creare un nuovo modello.

Il modello appare similmente a:

 

3 1

Come possiamo vedere dall’immagine, stiamo ora generando proposte regionali basate non sull’immagine originale, ma piuttosto sull’ultima mappa delle caratteristiche estrapolate dalla rete. Ciò ci permette di allenare una sola CNN per l’intera immagine.

In aggiunta, al posto che allenare differenti SVM per classificare ogni oggetto, vi è un singolo strato softmax che genera direttamente la probabilità per la classe di riferimento. Quindi, abbiamo ora una sola rete neurale da allenare, a differenza di quanto succedeva prima dove invece c’era una rete neurale affiancata a molteplici SVM.

La Fast R-CNN performa, perciò, molto meglio in termini di velocità. Tuttavia, rimane un grosso difetto: l’algoritmo di selective search per proporre le possibili regioni.

Faster R-CNN

Siamo giunti ora all’obiettivo iniziale del nostro articolo: Faster R-CNN. L’intuizione è stata quella di rimpiazzare il lento algoritmo di selective search con una rete neurale veloce. Nello specifico essa ha introdotto la region proposal network (RPN), rete di proposta regionale.

Come funziona la RPN:

  • All’ultimo strato di una CNN iniziale, una finestra scorrevole 3×3 si muove attraverso la mappa delle caratteristiche per mapparla poi in una dimensione inferiore (ad esempio 256-d).
  • Per ogni posizione della finestra scorrevole, la RPN genera molteplici regioni possibili basate su vincoli spaziali di dimensioni fisse chiamati riquadri di ancoraggio (anchor boxes).
  • Ogni proposta regionale consiste in:
    • un punteggio (score) per la presenza dell’oggetto in quella determinata regione
    • 4 coordinate rappresentanti il riquadro di delimitazione della regione.

In altre parole, guardiamo alla nostra regione nell’ultima mappa delle caratteristiche, considerando i differenti k riquadri di ancoraggio attorno ad essa. Per ciascun riquadro viene visualizzata l’eventualità che contenga un oggetto e quali siano le coordinate del riquadro. Nell’immagine è rappresentato come appare dalla posizione di una finestra scorrevole:

 

4 1

4 1

Il punteggio 2k rappresenta la probabilità data da softmax per ciascun riquadro k per la presenza di un oggetto. Da notare è che, nonostante la RPN elabori le coordinate dei riquadri di delimitazione, essa non classifica comunque i possibili oggetti: ha il solo scopo di individuare regioni in cui siano presenti oggetti e quindi comunicare le coordinate dei relativi riquadri. Se un riquadro di ancoraggio ha un punteggio, relativo alla presenza di un oggetto, superiore a una determinata soglia, allora quel dato riquadro verrà selezionato come possibile regione.

Avendo ora le nostre possibili regioni, le introduciamo direttamente nella Fast R-CNN. Aggiungiamo uno strato di Pooling, alcuni strati completamente connessi, infine uno strato di classificazione softmax e un regressore dei riquadri di delimitazione (bounding box regressor). Possiamo dire, in un certo senso, che Faster R-CNN = RPN + Fast R-CNN.

 

5 1

5 1

La Faster R-CNN raggiunge così miglior velocità e accuratezza. Nonostante siano stati molteplici i tentativi successivi di aumentare la velocità di riconoscimento degli oggetti, solo pochi modelli sono stati davvero in grado di superare questa rete. In altre parole, la Faster R-CNN non rappresenta certo il metodo più semplice e veloce per la object detection ma presenta tuttora una delle migliori performance. Quindi, la Faster R-CNN in Tensorflow con la Inception ResNet è il modello più lento ma anche il più accurato.

Nonostante la Faster R-CNN possa sembrare complessa, è possibile notare che il cuore della sua struttura è il medesimo di quello originario della R-CNN: identificare possibili regioni di oggetti e classificarle. Questo è l’approccio dominante della maggior parte degli odierni modelli di rilevazione di oggetti, incluso quello che andremo ad analizzare ora.

R-FCN

Ritorniamo per un momento indietro. Abbiamo detto che la Fast R-CNN ha migliorato di molto la sua velocità di rilevazione condividendo una singola CNN per tutte le regioni. Questo meccanismo di base è lo stesso della R-FCN: aumentare la velocità massimizzando il numero di parametri condivisi.

La Region-based FullyConvolutional Net (R-FCN) condivide la totalità della computazione per ogni singolo output.

Da una parte, quando classifichiamo un oggetto vogliamo che il modello risulti invariante alle traslazioni, in modo da identificarlo ovunque esso appaia. Dall’altra, abbiamo però la necessità di conoscere anche un’eventuale varianza alle traslazioni: se il nostro oggetto si trova nell’angolo in alto a sinistra, il modello deve tracciare un riquadro di delimitazione in quel determinato punto. Perciò, come trovare un compromesso tra i due estremi, varianza e invarianza?

La soluzione proposta dalla R-FCN è rappresentata dalle position-sentitive score maps: mappe dei punteggi (relative alle features, estratte tramite convoluzioni, alla quale è attribuito un punteggio in base alla presenza della data classe) sensibili alla posizione degli oggetti che intendiamo classificare.

Ognuna di queste mappe rappresenta una posizione relativa di una classe di oggetti. Per esempio, una mappa dei punteggi potrebbe attivarsi qualora identifichi la parte in alto a destra di un gatto, mentre un’altra potrebbe attivarsi quando rileva la parte inferiore sinistra di una macchina. Essenzialmente queste score maps sono mappe di caratteristiche convoluzionali che sono state allenate a riconoscere determinate parti di ogni oggetto.

La R-FCN funziona in questo modo:

  1. Eseguire una CNN (in questo caso una ResNet) sull’immagine di input.
  2. Aggiungere uno strato convoluzionale che coinvolga tutte le mappe generate dal passaggio precedente in modo da ottenere un insieme di punteggi complessivi dell’immagine. Ottenendo k²(C+1) mappe di punteggio, dove k² rappresenta il numero di posizioni relative per dividere un oggetto (per esempio 3² per una griglia 3×3), e dove C+1 rappresenta il numero di classi più lo sfondo.
  3. Eseguire una RPN per generare le regioni di interesse (RoI)
  4. Dividere ciascuna RoI nelle medesime k² sottoregioni di cui è composta la mappa dei punteggi
  5. Dobbiamo ora verificare se nell’insieme dei punteggi complessivi, ogni sottoregione combaci con la corrispondente posizione relativa di un oggetto. Per esempio, se vogliamo considerare la sottoregione in alto a sinistra, dobbiamo prendere la mappa dei punteggi che corrisponde all’angolo in alto a sinistra di un oggetto e farne una media all’interno della RoI. Questo processo è ripetuto per ogni classe.
  6. Dopo che ogni k² sottoregione ha un valore di “object match” per ogni classe, si fa una media delle sottoregioni per ottenere un punteggio per ogni classe.
  7. Classificare le RoI con una funzione softmax sui rimanenti C+1 vettori dimensionali.

Una R-FCN, avente una RPN che genera le RoI, apparirà all’incirca così:

6 1

6 1

Capire come funzioni questo modello è più semplice se si può visualizzare concretamente ciò che fa. Qui di seguito abbiamo un esempio del suo funzionamento mentre cerca di individuare un neonato.

 

 

 

 

7Figura 4: visualizzazione di una RoI che non si sovrappone correttamente all’oggetto

In parole semplici: la R-FCN considera ogni regione, suddividendole poi in sottoregioni e chiedendosi per ciascuna di queste se corrispondano o meno alla relativa porzione dell’immagine di input. Ad esempio “assomiglia alla porzione in centro a destra di un bambino?”. Ciò viene ripetuto per ogni classe. Se la maggior parte delle sottoregioni risulta corrispondente, allora la RoI viene classificata come neonato, dopo che la funzione softmax viene eseguita su tutte le classi.

In questo modo, la R-FCN è capace di identificare contemporaneamente la varianza alle traslazioni, proponendo differenti regioni di oggetti, e l’invarianza alle traslazioni attraverso il riferimento di ogni regione alle stesse mappe di punteggio. Queste mappe di punteggio dovrebbero imparare a classificare un gatto come tale, ovunque esso appaia. Inoltre, è completamente convoluzionale: ciò significa che la computazione è condivisa nell’intera rete.

Ciò permette alla R-FCN di essere nettamente più veloce rispetto alla Faster R-CNN, raggiungendo comunque lo stesso grado di accuratezza.

SSD

L’ultimo modello che andremo ad analizzare è la Single-Shot Detector (SDD). Come la R-FCN ha raggiunto una velocità molto maggiore rispetto alla Faster R-CNN ma in modo nettamente diverso.

I primi due modelli eseguono region proposal e region classification in due fasi distinte. Inanzitutto, utilizzano una RPN (region proposal network) per generare le regioni di interesse, successivamente classificano queste regioni attraverso i propri strati interamente connessi o gli strati convoluzionali sensibili alla posizione degli oggetti da classificare. La SSD unisce questi due processi in un singolo passaggio, prevedendo simultaneamente i riquadri di delimitazione e le classi, nel momento in cui esamina l’immagine.

Data un’immagine di input ed un insieme di etichette al dataset, la SSD agisce in questo modo:

  • Passa l’immagine attraverso una serie di strati convoluzionali, producendo mappe delle caratteristiche a scale differenti (per esempio 10×10, poi 6×6 e ancora 3×3 ecc.)
  • Per ogni posizione in ciascuna di queste mappe delle caratteristiche, usa un filtro convoluzionale 3×3 per valutare un piccolo set di riquadri di delimitazione predefiniti. Questi ultimi sono l’equivalente dei riquadri di ancoraggio (anchor boxes) della Faster R-CNN.
  • Per ogni riquadro prevede simultaneamente:
    1. Il riquadro del bounding box
    2. La probabilità per ogni classe.
  • Durante l’allenamento fa corrispondere il riquadro effettivo con quello predetto sulla base del metodo Intersection over Union (IoU), ovvero l’Indice di Jaccard. I riquadri meglio predetti verranno etichettati come “positivi”, come anche tutti gli altri riquadri che abbiano un valore IoU >0.5.

L’allenamento della SSD ha però una difficoltà peculiare rispetto ai precedenti modelli. Nei primi due modelli, la RPN permetteva di prendere in considerazione solo ciò che aveva anche solo la minima possibilità di essere un oggetto. Con la SSD, invece, questo primo filtro viene eliminato: esso classifica e traccia riquadri di delimitazione in ogni singola posizione nell’immagine, usando riquadri di differenti forme e di molteplici scale. Ciò ha come risultato l’avere un numero molto più elevato di riquadri dove, però, la maggior parte di questi è negativo (dal momento che non rileva oggetti).

La SSD corregge questo problema in due modi. Per prima cosa utilizza la non-maximum suppression (NMS) per raggruppare diversi riquadri sovrapposti in un unico riquadro. Quindi se ad esempio quattro riquadri di simile forma e grandezza contengono lo stesso oggetto, la NMS permette di tenere il riquadro migliore, il più accurato, e di scartare i restanti. In secondo luogo, utilizza una tecnica chiamata hard negative mining per bilanciare le classi durante l’allenamento. Con questa tecnica, solo un sottogruppo degli esempi negativi con la più elevata loss in fase di training (i cosiddetti falsi positivi) è utilizzato per ogni iterazione in fase di allenamento. La SSD mantiene un rapporto 3:1 tra negativi e positivi.

La sua architettura appare così:

 

8

Come detto poco sopra, vediamo esserci degli “extra feature layers”. Queste mappe delle caratteristiche dalle misure variabili aiutano a individuare oggetti di diverse dimensioni. Eccone un esempio:

9

In mappe delle caratteristiche di dimensioni più piccole (4×4), ogni riquadro ricopre una regione più ampia dell’immagine, permettendo così di individuare oggetti più grandi. La region proposal e la classificazione sono perciò eseguite nello stesso momento: avendo p classi di oggetti, ogni riquadro di delimitazione è associato a un vettore dimensionale (4+p) che produce 4 riquadri di coordinate e p probabilità di classe. In ultima istanza, viene utilizzata anche qui una funzione sotmax per classificare gli oggetti.

Possiamo perciò dire che la SSD non è poi così diversa rispetto ai due modelli precedenti. Tuttavia omette il passaggio di individuazione delle regioni, considerando ogni riquadro in ogni posizione dell’immagine insieme alla sua classificazione. Eseguendo tutti questi processi simultaneamente, la SSD è di certo il più veloce tra i tre modelli presi in considerazione.

Conclusioni

La Faster R-CNN, la R-FCN, e la SSD sono tre dei migliori e più usati modelli per la rilevazione di oggetti. Tutti fanno affidamento su reti neurali convoluzionali per le prime fasi del processo e seguono, all’incirca, lo stesso metodo di proposta delle regioni e classificazione.

 

White Paper Agid

Business Insider

Google TPU

Andrew Ng 175M