Gezichtsherkenning met Eigenfaces

Gezichtsherkenning is alomtegenwoordig in science fiction: de protagonist kijkt naar een camera, en de camera scant zijn of haar gezicht om de persoon te herkennen. Meer formeel kunnen we gezichtsherkenning formuleren als een classificatietaak, waarbij de inputs afbeeldingen zijn en de outputs namen van mensen. We gaan een populaire techniek voor gezichtsherkenning bespreken, eigenfaces genaamd. En de kern van eigenfaces is een techniek voor onbewaakte dimensiereductie genaamd principale componentenanalyse (PCA), en we zullen zien hoe we deze algemene techniek kunnen toepassen op onze specifieke taak van gezichtsherkenning. Download de volledige code hier.

Mis het niet! Aanbieding eindigt over
  • Toegang tot alle 200+ cursussen
  • Maandelijks nieuwe cursussen
  • Op elk moment annuleren
  • Certificaten van voltooiing

Gezichtsherkenning

Voordat we de principale componentenanalyse bespreken, moeten we eerst ons probleem definiëren. Gezichtsherkenning is de uitdaging om te classificeren wiens gezicht zich in een invoerbeeld bevindt. Dit is anders dan gezichtsherkenning, waarbij de uitdaging is vast te stellen of er een gezicht in het invoerbeeld voorkomt. Voor gezichtsherkenning hebben we een bestaande database van gezichten nodig. Gegeven een nieuw beeld van een gezicht, moeten wij de naam van de persoon rapporteren.

Een naïeve manier om dit te bereiken is het nieuwe beeld te nemen, het af te vlakken tot een vector, en de Euclidische afstand te berekenen tussen het en alle andere afgevlakte beelden in onze database.

Er zijn verscheidene nadelen aan deze benadering. Ten eerste, als we een grote database van gezichten hebben, dan duurt het een tijdje om deze vergelijking voor elk gezicht te doen! Stel je voor dat we een gezichtsherkenningssysteem bouwen voor real-time gebruik! Hoe groter onze dataset, hoe trager ons algoritme. Maar meer gezichten zal ook betere resultaten opleveren! We willen een systeem dat zowel snel als accuraat is. Hiervoor gebruiken we een neuraal netwerk! We kunnen ons netwerk trainen op onze dataset en het gebruiken voor onze gezichtsherkenningstaak.

Er is een probleem met het direct gebruiken van een neuraal netwerk: afbeeldingen kunnen groot zijn! Als we een enkele mvaak n

afbeelding zouden hebben, zouden we deze moeten afvlakken tot een enkelemvaak nv keer 1vector om als invoer in ons neurale netwerk te voeren. Voor grote afbeeldingen kan dit de snelheid schaden! Dit is gerelateerd aan het tweede probleem met het gebruik van afbeeldingen zoals ze zijn in onze naïeve benadering: ze zijn hoog-dimensionaal! (Een

mx nafbeelding is eigenlijk eenmx1vector) Een nieuwe invoer kan een hoop ruis bevatten en het vergelijken van elke pixel met matrix aftrekking en Euclidische afstand kan ons een hoge fout en foute classificaties opleveren!

Deze problemen zijn de reden waarom we de naïeve methode niet gebruiken. In plaats daarvan willen we onze hoog-dimensionale beelden nemen en ze terugbrengen tot een kleinere dimensionaliteit met behoud van de essentie of belangrijke delen van het beeld.

Dimensionaliteitsreductie

Het vorige gedeelte motiveert onze reden voor het gebruik van een dimensionaliteitsreductietechniek. Dimensionaliteitsreductie is een vorm van leren zonder toezicht waarbij we hoger-dimensionale gegevens, zoals afbeeldingen, willen nemen en ze weergeven in een lager-dimensionale ruimte. Laten we de volgende afbeelding als voorbeeld gebruiken.

Deze plots tonen dezelfde gegevens, behalve dat de onderste grafiek het nulpunt aangeeft. Merk op dat aan onze gegevens geen labels zijn gekoppeld, want dit is leren zonder toezicht! In ons eenvoudige geval zal dimensionaliteitsreductie deze gegevens van een 2D-vlak reduceren tot een 1D-lijn. Als we 3D-gegevens hadden, zouden we die kunnen herleiden tot een 2D-vlak of zelfs een 1D-lijn.

Alle technieken voor dimensionaliteitsreductie hebben tot doel een hypervlak, een hoger-dimensionale lijn, te vinden om de punten op te projecteren. We kunnen ons een projectie voorstellen als het nemen van een zaklamp loodrecht op het hypervlak waarop we projecteren en plotten waar de schaduwen op dat hypervlak vallen. Bijvoorbeeld, in onze bovenstaande gegevens, als we onze punten willen projecteren op de x-as, dan doen we alsof elk punt een bal is en onze zaklamp zou rechtstreeks naar beneden of naar boven wijzen (loodrecht op de x-as) en de schaduwen van de punten zouden op de x-as vallen. Dit is een projectie. We zullen ons niet druk maken over de exacte wiskunde hierachter, omdat scikit-learn deze projectie voor ons kan toepassen.

In ons eenvoudige 2D geval, willen we een lijn vinden om onze punten op te projecteren. Nadat we de punten hebben geprojecteerd, hebben we gegevens in 1D in plaats van 2D! Op dezelfde manier, als we 3D-gegevens hadden, willen we een vlak vinden om de punten op te projecteren om de dimensionaliteit van onze gegevens terug te brengen van 3D naar 2D. Bij de verschillende soorten dimensionaliteitsreductie gaat het erom uit te vinden welke van deze hypervlakken we moeten kiezen: er zijn er oneindig veel!

Principale Componenten Analyse

Een techniek voor dimensionaliteitsreductie heet principale componentenanalyse (PCA). Het idee achter PCA is dat we het hypervlak zo willen kiezen dat wanneer alle punten erop worden geprojecteerd, ze maximaal worden uitgesmeerd. Met andere woorden, we willen de as met de grootste variantie! Laten we eens kijken naar ons voorbeeldplot hierboven. Een mogelijke as is de x-as of de y-as, maar in beide gevallen is dat niet de beste as. Als we echter een lijn kiezen die onze gegevens diagonaal snijdt, is dat de as waar de gegevens het meest gespreid zouden zijn!

De langere blauwe as is de juiste as! Als we onze punten op deze as zouden projecteren, zouden ze maximaal uit elkaar liggen! Maar hoe bepalen we deze as? We kunnen een term lenen uit de lineaire algebra genaamd eigenvectoren! Hieraan dankt eigenfaces zijn naam! In wezen berekenen we de covariantiematrix van onze gegevens en bekijken we de grootste eigenvectoren van die covariantiematrix. Dat zijn onze hoofdassen en de assen waar we onze gegevens op projecteren om de dimensies te reduceren. Met deze aanpak kunnen we hoogdimensionale gegevens tot een lagere dimensie terugbrengen door de grootste eigenvectoren van de covariantiematrix te selecteren en op die eigenvectoren te projecteren.

Omdat we de assen van maximale spreiding berekenen, behouden we de belangrijkste aspecten van onze gegevens. Het is gemakkelijker voor onze classificator om gezichten te scheiden wanneer onze gegevens worden uitgespreid in tegenstelling tot samengebundeld.

(Er zijn andere dimensionaliteitstechnieken, zoals Lineaire Discriminant Analyse, die supervised learning gebruiken en ook worden gebruikt in gezichtsherkenning, maar PCA werkt echt goed!)

Hoe heeft dit betrekking op onze uitdaging van gezichtsherkenning? We kunnen onze mx n

afbeeldingen beschouwen als punten in eenmx n-dimensionale ruimte. Dan kunnen we PCA gebruiken om onze ruimte vanm\dot nte verkleinen tot iets veel kleiners. Dit zal onze berekeningen versnellen en robuust zijn tegen ruis en variatie.

Terzijde bij Gezichtsdetectie

Tot nu toe hebben we aangenomen dat het invoerbeeld alleen dat van een gezicht is, maar in de praktijk moeten we niet eisen dat de camerabeelden een perfect gecentreerd gezicht hebben. Daarom voeren we een out-of-the-box algoritme voor gezichtsdetectie uit, zoals een cascade classifier getraind op gezichten, om uit te zoeken welk deel van het invoerbeeld een gezicht bevat. Wanneer we die bounding box hebben, kunnen we gemakkelijk dat deel van het invoerbeeld schuiven en eigenfaces gebruiken op dat schuiven. (Gewoonlijk maken we die doorsnede glad en voeren we een affiene transformatie uit om het gezicht te ontwarren als het onder een hoek verschijnt). Voor onze doeleinden nemen we aan dat we al beelden van gezichten hebben.

Eigenfaces Code

Nu we PCA en eigenfaces hebben besproken, laten we een gezichtsherkenningsalgoritme coderen met scikit-learn! Eerst hebben we een dataset nodig. Voor ons doel gebruiken we een out-of-the-box dataset van de Universiteit van Massachusetts, genaamd Labeled Faces in the Wild (LFW).

Voel je vrij om je eigen dataset te gebruiken! Als je je eigen gezichtsdataset wilt maken, heb je meerdere foto’s nodig van het gezicht van elke persoon (onder verschillende hoeken en belichting), samen met de ground-truth labels. Hoe meer verschillende gezichten u gebruikt, hoe beter de herkenner het zal doen. De eenvoudigste manier om een dataset voor gezichtsherkenning te maken is door voor elke persoon een map aan te maken en daar de gezichtsafbeeldingen in te plaatsen. Zorg ervoor dat ze allemaal even groot zijn en resize ze zodat het geen grote afbeeldingen zijn! Onthoud dat PCA de dimensie van de afbeelding zal verminderen wanneer we op die ruimte projecteren, dus het gebruik van grote, high-definition afbeeldingen zal niet helpen en zal ons algoritme vertragen. Een goede grootte is ~512×512 voor elk beeld. De afbeeldingen moeten allemaal even groot zijn, zodat je ze kunt opslaan in een numpy array met afmetingen (num_examples, height, width) . (We gaan uit van afbeeldingen in grijstinten). Gebruik vervolgens de mapnamen om klassen te disambigueren. Met deze aanpak kun je je eigen afbeeldingen gebruiken.

Hoewel, we zullen de LFW dataset gebruiken. Gelukkig kan scikit-learn automatisch onze dataset voor ons laden in het juiste formaat. We kunnen een functie aanroepen om onze gegevens te laden. Als de gegevens niet op schijf beschikbaar zijn, zal scikit-learn ze automatisch voor ons downloaden van de website van de Universiteit van 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
# opsplitsen in een training- en een testset
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

Het argument voor onze functie verwijdert gewoon alle mensen zonder minstens 100 gezichten, waardoor het aantal klassen wordt verminderd. Dan kunnen we onze dataset en andere hulpinformatie extraheren. Tenslotte splitsen we onze dataset in training- en testsets.

Nu kunnen we gewoon de PCA-klasse van scikit-learn gebruiken om de dimensionaliteitsreductie voor ons uit te voeren! We moeten het aantal componenten selecteren, d.w.z. de uitgangsdimensionaliteit (het aantal eigenvectoren om op te projecteren), waartoe we willen reduceren, en voel je vrij om deze parameter te tweaken om te proberen het beste resultaat te krijgen! Wij gebruiken 100 componenten. Bovendien zullen we onze gegevens witten, wat gemakkelijk te doen is met een eenvoudige booleaanse vlag! (Whitening zorgt er gewoon voor dat onze resulterende gegevens een eenheidsvariantie hebben, waarvan is aangetoond dat het betere resultaten oplevert)

1
2
3
4
5
6
7

# Bereken een PCA
n_components = 100
pca = PCA(n_components=n_components, whiten=True).fit(X_train)
# PCA-transformatie toepassen
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)

>

We kunnen de transformatie toepassen om onze afbeeldingen terug te brengen naar een 100-dimensionale ruimte. Merk op dat we geen PCA uitvoeren op de volledige dataset, maar alleen op de trainingsgegevens. Dit is zodat we beter kunnen generaliseren naar ongeziene gegevens.

Nu we een vector met gereduceerde dimensionaliteit hebben, kunnen we ons neurale netwerk trainen!

1
2
3

# train een neuraal netwerk
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)

Om te zien hoe ons netwerk traint, kunnen we de vlag verbose instellen. Bovendien maken we gebruik van vroegtijdig stoppen.

Laten we het vroegtijdig stoppen even terzijde bespreken. In essentie zal onze optimizer de gemiddelde nauwkeurigheid voor de validatie set voor elke tijdspanne controleren. Als het merkt dat onze validatie nauwkeurigheid niet significant is toegenomen voor een bepaald aantal epochs, dan stoppen we met trainen. Dit is een regularisatietechniek die voorkomt dat ons model overfitte!

Kijk eens naar de bovenstaande grafiek. We merken overfitting op wanneer de nauwkeurigheid van onze validatieset begint af te nemen. Op dat moment stoppen we onmiddellijk met trainen om overfitting te voorkomen.

Ten slotte kunnen we een voorspelling doen en een functie gebruiken om een volledig kwaliteitsrapport voor elke klasse af te drukken.

1
2

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

Hier volgt een voorbeeld van een classificatierapport.

1
2
3
4
5
6
7
8
9

precision recall f1-score ondersteuning
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 Schröder 0,67 0,69 0.68 26
Tony Blair 0.86 0.71 0.78 35
avg / totaal 0.85 0.85 0.85 342

Merk op dat er geen nauwkeurigheidsmaatstaf is. Nauwkeurigheid is niet het meest specifieke soort meeteenheid om mee te beginnen. In plaats daarvan zien we precisie, recall, f1-score, en ondersteuning. De ondersteuning is gewoon het aantal keren dat dit ground truth label voorkwam in onze testverzameling, bijvoorbeeld, in onze testverzameling waren er 35 afbeeldingen van Tony Blair. De F1-Score wordt eigenlijk gewoon berekend uit de precisie- en de recall-score. Precisie en recall zijn meer specifieke maatstaven dan een enkele nauwkeurigheidsscore. Een hogere waarde voor beide is beter.

Na het trainen van onze classificator, kunnen we het een paar afbeeldingen geven om te classificeren.

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

# Visualisatie
def plot_gallery(images, titles, h, w, rows=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):
for i in range(y_pred.shape):
pred_name = target_names].split(‘ ‘)
true_name = target_names].split(‘ ‘)
yield ‘predicted: {0}’.format(pred_name, true_name)
prediction_titles = list(titles(y_pred, y_test, target_names))
plot_gallery(X_test, prediction_titles, h, w)

(plot_gallery en titles functies aangepast van de scikit-learn documentatie)

We kunnen de voorspellingen van ons netwerk en de grondwaarheid waarde voor elke afbeelding zien.

Een ander interessant ding om te visualiseren zijn de eigenfaces zelf. Onthoud dat PCA eigenvectoren produceert. We kunnen die eigenvectoren omvormen tot afbeeldingen en de eigenfaces visualiseren.

Deze vertegenwoordigen de “generieke” gezichten van onze dataset. Intuïtief zijn dit vectoren die richtingen in de “gezichtsruimte” weergeven en die ons neurale netwerk gebruikt om te helpen bij de classificatie. Nu we de eigenfaces-benadering hebben besproken, kun je toepassingen bouwen die dit gezichtsherkenningsalgoritme gebruiken!

We hebben een populaire benadering van gezichtsherkenning besproken die eigenfaces heet. De essentie van eigenfaces is een niet-begeleid dimensionaliteitsverminderend algoritme genaamd Principal Components Analysis (PCA) dat we gebruiken om de dimensionaliteit van afbeeldingen te verminderen tot iets kleiners. Nu we een kleinere representatie van onze gezichten hebben, passen we een classifier toe die de gereduceerde dimensie input neemt en een klasse-etiket produceert. Voor onze classifier hebben we een enkellaags neuraal netwerk gebruikt.

Gezichtsherkenning is een fascinerend voorbeeld van het samenvoegen van computervisie en machinaal leren en veel onderzoekers werken vandaag de dag nog steeds aan dit uitdagende probleem!

Nu worden diepe convolutionele neurale netwerken gebruikt voor gezichtsherkenning, en hebben enorme implicaties in termen van de ontwikkelingscarrière wereld. Probeer er een uit op deze dataset!

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.