Face Recognition with Eigenfaces

Il riconoscimento dei volti è onnipresente nella fantascienza: il protagonista guarda una telecamera, e la telecamera scansiona il suo volto per riconoscere la persona. Più formalmente, possiamo formulare il riconoscimento dei volti come un compito di classificazione, dove gli input sono immagini e gli output sono i nomi delle persone. Discuteremo una tecnica popolare per il riconoscimento dei volti chiamata eigenfaces. Il cuore di eigenfaces è una tecnica non supervisionata di riduzione della dimensionalità chiamata analisi delle componenti principali (PCA), e vedremo come possiamo applicare questa tecnica generale al nostro compito specifico di riconoscimento dei volti. Scarica il codice completo qui.

Non mancare! L’offerta termina tra
  • Accedi a tutti gli oltre 200 corsi
  • Nuovi corsi aggiunti mensilmente
  • Annulla in qualsiasi momento
  • Certificati di completamento

Riconoscimento dei volti

Prima di parlare dell’analisi delle componenti principali, dobbiamo definire il nostro problema. Il riconoscimento dei volti è la sfida di classificare di chi è il volto in un’immagine di input. Questo è diverso dal rilevamento dei volti, dove la sfida è determinare se c’è un volto nell’immagine di input. Con il riconoscimento dei volti, abbiamo bisogno di un database esistente di volti. Data una nuova immagine di un volto, abbiamo bisogno di riportare il nome della persona.

Un modo ingenuo di realizzare questo è prendere la nuova immagine, appiattirla in un vettore, e calcolare la distanza euclidea tra essa e tutte le altre immagini appiattite nel nostro database.

Ci sono diversi lati negativi in questo approccio. Prima di tutto, se abbiamo un grande database di facce, allora fare questo confronto per ogni faccia richiederà un po’ di tempo! Immaginate che stiamo costruendo un sistema di riconoscimento facciale per un uso in tempo reale! Più grande è il nostro set di dati, più lento sarà il nostro algoritmo. Ma più facce produrranno anche risultati migliori! Vogliamo un sistema che sia allo stesso tempo veloce e accurato. Per questo, useremo una rete neurale! Possiamo addestrare la nostra rete sul nostro set di dati e usarla per il nostro compito di riconoscimento dei volti.

C’è un problema nell’usare direttamente una rete neurale: le immagini possono essere grandi! Se avessimo una singola immagine metà n

, dovremmo appiattirla in un singolo vettoremetà netà 1da dare in input alla nostra rete neurale. Per immagini di grandi dimensioni, questo potrebbe danneggiare la velocità! Questo è legato al secondo problema dell’uso delle immagini così come sono nel nostro approccio ingenuo: sono altamente dimensionali! (Un’immagine

multipla di nè in realtà unmultiplo di 1vettore) Un nuovo input potrebbe avere una tonnellata di rumore e confrontare ogni singolo pixel usando la sottrazione della matrice e la distanza euclidea potrebbe darci un errore elevato e delle classificazioni errate!

Questi problemi sono il motivo per cui non usiamo il metodo ingenuo. Invece, vorremmo prendere le nostre immagini ad alta densità e ridurle ad una dimensione più piccola mantenendo l’essenza o le parti importanti dell’immagine.

Riduzione della dimensionalità

La sezione precedente motiva la nostra ragione per usare una tecnica di riduzione della dimensionalità. La riduzione della dimensionalità è un tipo di apprendimento non supervisionato in cui vogliamo prendere dati di dimensioni superiori, come le immagini, e rappresentarli in uno spazio di dimensioni inferiori. Usiamo la seguente immagine come esempio.

Questi grafici mostrano gli stessi dati, tranne il grafico in basso che li azzera. Notate che i nostri dati non hanno alcuna etichetta associata ad essi perché questo è un apprendimento non supervisionato! Nel nostro semplice caso, la riduzione della dimensionalità ridurrà questi dati da un piano 2D a una linea 1D. Se avessimo dati 3D, potremmo ridurli a un piano 2D o anche a una linea 1D.

Tutte le tecniche di riduzione della dimensionalità mirano a trovare un iperpiano, una linea di dimensioni superiori, su cui proiettare i punti. Possiamo immaginare una proiezione come se prendessimo una torcia perpendicolare all’iperpiano su cui stiamo proiettando e tracciassimo dove cadono le ombre su quell’iperpiano. Per esempio, nei nostri dati di cui sopra, se volessimo proiettare i nostri punti sull’asse x, allora facciamo finta che ogni punto sia una palla e la nostra torcia punterebbe direttamente in basso o in alto (perpendicolare all’asse x) e le ombre dei punti cadrebbero sull’asse x. Questa è una proiezione. Non ci preoccuperemo dell’esatta matematica che c’è dietro, poiché scikit-learn può applicare questa proiezione per noi.

Nel nostro semplice caso 2D, vogliamo trovare una linea su cui proiettare i nostri punti. Dopo aver proiettato i punti, allora abbiamo dati in 1D invece che in 2D! Allo stesso modo, se avessimo dati in 3D, vorremmo trovare un piano su cui proiettare i punti per ridurre la dimensionalità dei nostri dati da 3D a 2D. I diversi tipi di riduzione della dimensionalità consistono nel capire quale di questi iperpiani selezionare: ce ne sono un numero infinito!

Analisi delle componenti principali

Una tecnica di riduzione della dimensionalità è chiamata analisi delle componenti principali (PCA). L’idea alla base della PCA è che vogliamo selezionare l’iperpiano tale che quando tutti i punti sono proiettati su di esso, sono distribuiti al massimo. In altre parole, vogliamo l’asse della massima varianza! Consideriamo il nostro esempio di grafico qui sopra. Un asse potenziale è l’asse x o l’asse y, ma, in entrambi i casi, non è l’asse migliore. Tuttavia, se scegliamo una linea che taglia i nostri dati in diagonale, quello è l’asse dove i dati sarebbero più diffusi!

L’asse blu più lungo è l’asse corretto! Se proiettassimo i nostri punti su questo asse, sarebbero massimamente diffusi! Ma come facciamo a capire questo asse? Possiamo prendere in prestito un termine dall’algebra lineare chiamato autovettori! È da qui che deriva il nome di eigenfaces! Essenzialmente, calcoliamo la matrice di covarianza dei nostri dati e consideriamo i più grandi autovettori della matrice di covarianza. Questi sono i nostri assi principali e gli assi su cui proiettiamo i nostri dati per ridurre le dimensioni. Usando questo approccio, possiamo prendere dati ad alta dimensione e ridurli ad una dimensione inferiore selezionando gli autovettori più grandi della matrice di covarianza e proiettandoli su quegli autovettori.

Siccome stiamo calcolando gli assi di massima diffusione, stiamo mantenendo gli aspetti più importanti dei nostri dati. È più facile per il nostro classificatore separare i volti quando i nostri dati sono sparsi invece che raggruppati insieme.

(Ci sono altre tecniche di dimensionalità, come l’Analisi Discriminante Lineare, che usano l’apprendimento supervisionato e sono anche usate nel riconoscimento dei volti, ma la PCA funziona davvero bene!)

Come si collega questo alla nostra sfida del riconoscimento dei volti? Possiamo concettualizzare le nostre multipli n

immagini come punti inmultipli nspazio dimensionale. Poi, possiamo usare la PCA per ridurre il nostro spazio dam\punto na qualcosa di molto più piccolo. Questo ci aiuterà a velocizzare i nostri calcoli e sarà robusto al rumore e alle variazioni.

A parte il Face Detection

Finora, abbiamo assunto che l’immagine di input sia solo quella di un volto, ma, in pratica, non dovremmo richiedere che le immagini della telecamera abbiano un volto perfettamente centrato. Questo è il motivo per cui eseguiamo un algoritmo di rilevamento facciale out-of-the-box, come un classificatore a cascata addestrato sui volti, per capire quale porzione dell’immagine di input contiene un volto. Quando abbiamo quel riquadro di delimitazione, possiamo facilmente tagliare quella porzione dell’immagine di input e usare gli autodefiniti su quella fetta. (Di solito, smussiamo quella slice ed eseguiamo una trasformazione affine per de-warpare la faccia se appare in un angolo). Per i nostri scopi, daremo per scontato che abbiamo già delle immagini di volti.

Codice degli autovalori

Ora che abbiamo discusso di PCA ed autovalori, codifichiamo un algoritmo di riconoscimento dei volti usando scikit-learn! Per prima cosa, abbiamo bisogno di un set di dati. Per i nostri scopi, useremo un set di dati dell’Università del Massachusetts chiamato Labeled Faces in the Wild (LFW).

Siate liberi di sostituire il vostro set di dati! Se volete creare il vostro dataset di volti, avrete bisogno di diverse immagini del volto di ogni persona (con diverse angolazioni e illuminazione), insieme alle etichette di verità a terra. Più ampia è la varietà di volti che usi, migliore sarà il risultato del riconoscitore. Il modo più semplice per creare un dataset per il riconoscimento dei volti è quello di creare una cartella per ogni persona e metterci le immagini dei volti. Assicurati che ognuna sia della stessa dimensione e ridimensionale in modo che non siano immagini grandi! Ricorda che la PCA ridurrà comunque la dimensionalità dell’immagine quando proietteremo su quello spazio, quindi usare immagini grandi e ad alta definizione non aiuterà e rallenterà il nostro algoritmo. Una buona dimensione è ~512×512 per ogni immagine. Le immagini dovrebbero essere tutte della stessa dimensione in modo da poterle memorizzare in un array numpy con dimensioni (num_esempi, altezza, larghezza). (Stiamo assumendo immagini in scala di grigi). Quindi utilizzare i nomi delle cartelle per disambiguare le classi. Usando questo approccio, potete usare le vostre immagini.

Tuttavia, noi useremo il dataset LFW. Fortunatamente, scikit-learn può caricare automaticamente il nostro dataset nel formato corretto. Possiamo chiamare una funzione per caricare i nostri dati. Se i dati non sono disponibili su disco, scikit-learn li scaricherà automaticamente per noi dal sito dell’Università del Massachusetts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_lfw_people
from sklearn.metrics import classification_report
from sklearn.decomposition import PCA
from sklearn.neural_network import MLPClassifier
# Load data
lfw_dataset = fetch_lfw_people(min_faces_per_person=100)
_, h, w = lfw_dataset.images.shape
X = lfw_dataset.data
y = lfw_dataset.target
target_names = lfw_dataset.target_names
# dividere in un training e un testing set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

L’argomento della nostra funzione si limita a potare tutte le persone senza almeno 100 volti, riducendo così il numero di classi. Poi possiamo estrarre il nostro dataset e altre informazioni ausiliarie. Infine, dividiamo il nostro set di dati in insiemi di allenamento e di test.

Ora possiamo semplicemente usare la classe PCA di scikit-learn per eseguire la riduzione della dimensionalità per noi! Dobbiamo selezionare il numero di componenti, cioè la dimensionalità dell’output (il numero di autovettori su cui proiettare), che vogliamo ridurre, e sentitevi liberi di modificare questo parametro per cercare di ottenere il miglior risultato! Noi useremo 100 componenti. Inoltre, sbianchiremo i nostri dati, il che è facile da fare con una semplice bandiera booleana! (Lo sbiancamento fa sì che i nostri dati risultanti abbiano una varianza unitaria, che ha dimostrato di produrre risultati migliori)

1
2
3
4
5
6
7

# Calcola una PCA
n_components = 100
pca = PCA(n_components=n_components, whiten=Vero).fit(X_train)
# applica la trasformazione PCA
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)

Possiamo applicare la trasformazione per portare le nostre immagini in uno spazio di 100 dimensioni. Notate che non stiamo eseguendo la PCA sull’intero set di dati, solo sui dati di allenamento. Questo per poter generalizzare meglio ai dati non visti.

Ora che abbiamo un vettore a dimensione ridotta, possiamo allenare la nostra rete neurale!

1
2
3

# addestra una rete neurale
print(“Fitting the classifier to the training set”)
clf = MLPClassifier(hidden_layer_sizes=(1024,), batch_size=256, verbose=True, early_stopping=True).fit(X_train_pca, y_train)

Per vedere come la nostra rete si sta allenando, possiamo impostare il flag verbose. Inoltre, usiamo l’arresto anticipato.

Discutiamo l’arresto anticipato come una breve parentesi. Essenzialmente, il nostro ottimizzatore monitorerà l’accuratezza media per il set di validazione per ogni epoca. Se nota che la nostra accuratezza di validazione non è aumentata significativamente per un certo numero di epoche, allora fermiamo l’allenamento. Questa è una tecnica di regolarizzazione che impedisce al nostro modello di adattarsi troppo!

Considerate il grafico sopra. Notiamo l’overfitting quando la precisione del nostro set di validazione inizia a diminuire. A quel punto, interrompiamo immediatamente l’addestramento per evitare l’overfitting.

Infine, possiamo fare una previsione e usare una funzione per stampare un intero rapporto di qualità per ogni classe.

1
2

y_pred = clf.predict(X_test_pca)
print(classification_report(y_test, y_pred, target_names=target_names))

Ecco un esempio di rapporto di classificazione.

1
2
3
4
5
6
7
8
9

precisione richiamo f1-punteggio supporto
Colin Powell 0.86 0.89 0.87 66
Donald Rumsfeld 0.85 0.61 0.71 38
George W Bush 0.88 0.94 0.91 177
Gerhard Schroeder 0.67 0.69 0.68 26
Tony Blair 0.86 0.71 0.78 35
avg / totale 0.85 0.85 0.85 342

Nota che non esiste una metrica di precisione. La precisione non è il tipo di metrica più specifico per iniziare. Invece, vediamo precisione, richiamo, f1-score e supporto. Il supporto è semplicemente il numero di volte che questa etichetta di verità di base si è verificata nel nostro set di test, ad esempio, nel nostro set di test, c’erano effettivamente 35 immagini di Tony Blair. L’F1-Score è in realtà solo calcolato dai punteggi di precisione e richiamo. Precisione e richiamo sono misure più specifiche di un singolo punteggio di accuratezza. Un valore più alto per entrambi è migliore.

Dopo aver addestrato il nostro classificatore, possiamo dargli alcune immagini da classificare.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Visualizzazione
def plot_gallery(images, titoli, h, w, righe=3, cols=4):
plt.figure()
for i in range(rows * cols):
plt.subplot(rows, cols, i + 1)
plt.imshow(images.reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles)
plt.xticks(())
plt.yticks(())
def titles(y_pred, y_test, target_names):
per i in range(y_pred.shape):
pred_name = target_names].split(‘ ‘)
true_name = target_names].split(‘ ‘)
yield ‘predicted: {0}\ntrue: {1}’.format(pred_name, true_name)
prediction_titles = list(titles(y_pred, y_test, target_names))
plot_gallery(X_test, prediction_titles, h, w)

(funzioni plot_gallery e titoli modificate dalla documentazione di scikit-learn)

Possiamo vedere le previsioni della nostra rete e il valore di verità per ogni immagine.

Un’altra cosa interessante da visualizzare sono gli autovalori stessi. Ricordate che la PCA produce autovettori. Possiamo rimodellare questi autovettori in immagini e visualizzare gli autofaces.

Questi rappresentano i volti “generici” del nostro dataset. Intuitivamente, questi sono vettori che rappresentano le direzioni nello “spazio delle facce” e sono ciò che la nostra rete neurale usa per aiutare la classificazione. Ora che abbiamo discusso l’approccio eigenfaces, potete costruire applicazioni che utilizzano questo algoritmo di riconoscimento facciale!

Abbiamo discusso un approccio popolare al riconoscimento facciale chiamato eigenfaces. L’essenza di eigenfaces è un algoritmo non supervisionato di riduzione della dimensionalità chiamato Principal Components Analysis (PCA) che usiamo per ridurre la dimensionalità delle immagini in qualcosa di più piccolo. Ora che abbiamo una rappresentazione più piccola dei nostri volti, applichiamo un classificatore che prende l’input a dimensione ridotta e produce un’etichetta di classe. Per il nostro classificatore, abbiamo usato una rete neurale a singolo strato.

Il riconoscimento dei volti è un affascinante esempio di fusione tra computer vision e machine learning e molti ricercatori stanno lavorando ancora oggi su questo impegnativo problema!

Oggi, le reti neurali convoluzionali profonde sono utilizzate per il riconoscimento dei volti, e hanno vaste implicazioni in termini di sviluppo del mondo della carriera. Provane una su questo set di dati!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.