Ansiktsigenkänning med egenytor

Ansiktsigenkänning är allestädes närvarande i science fiction: huvudpersonen tittar på en kamera och kameran skannar hans eller hennes ansikte för att känna igen personen. Mer formellt kan vi formulera ansiktsigenkänning som en klassificeringsuppgift, där indata är bilder och utdata är personers namn. Vi kommer att diskutera en populär teknik för ansiktsigenkänning som kallas eigenfaces. Och kärnan i eigenfaces är en oövervakad teknik för dimensionalitetsreducering som kallas huvudkomponentanalys (PCA), och vi kommer att se hur vi kan tillämpa denna allmänna teknik på vår specifika uppgift, nämligen ansiktsigenkänning. Ladda ner hela koden här.

Missa inte detta! Erbjudandet upphör i
  • Få tillgång till alla 200+ kurser
  • Nya kurser läggs till varje månad
  • Avbryt när som helst
  • Certifikat för avslutad kurs

Ansiktsigenkänning

För att diskutera huvudkomponentanalys bör vi först definiera vårt problem. Ansiktsigenkänning är utmaningen att klassificera vems ansikte som finns i en inmatad bild. Detta skiljer sig från ansiktsdetektering där utmaningen är att avgöra om det finns ett ansikte i den inmatade bilden. Vid ansiktsigenkänning behöver vi en befintlig databas med ansikten. Om vi får en ny bild av ett ansikte måste vi rapportera personens namn.

Ett naivt sätt att åstadkomma detta är att ta den nya bilden, platta den till en vektor och beräkna det euklidiska avståndet mellan den och alla andra platta bilder i vår databas.

Det finns flera nackdelar med detta tillvägagångssätt. För det första, om vi har en stor databas med ansikten, kommer det att ta ett tag att göra denna jämförelse för varje ansikte! Tänk dig att vi bygger ett system för ansiktsigenkänning för användning i realtid! Ju större vår datamängd är, desto långsammare blir vår algoritm. Men fler ansikten ger också bättre resultat! Vi vill ha ett system som är både snabbt och exakt. För detta kommer vi att använda ett neuralt nätverk! Vi kan träna vårt nätverk på vår datamängd och använda det för vår ansiktsigenkänningsuppgift.

Det finns ett problem med att direkt använda ett neuralt nätverk: bilder kan vara stora! Om vi hade en enda m\times n

bild skulle vi behöva platta ut den till en endam\dot n\times 1vektor att mata in i vårt neurala nätverk som indata. För stora bildstorlekar kan detta skada hastigheten! Detta hänger samman med det andra problemet med att använda bilderna som de är i vårt naiva tillvägagångssätt: de är högdimensionella! (Enm\times nbild är egentligen enm\dot n\times 1vektor) En ny inmatning kan innehålla massor av brus och att jämföra varje enskild pixel med hjälp av matrisubtraktion och euklidisk distans kan ge oss höga fel och felklassificeringar!

Dessa problem är anledningen till att vi inte använder den naiva metoden. Istället vill vi ta våra högdimensionella bilder och koka ner dem till en mindre dimensionalitet samtidigt som vi behåller essensen eller viktiga delar av bilden.

Dimensionality Reduction

I det föregående avsnittet motiveras vår anledning att använda en teknik för dimensionalitetsreduktion. Dimensionalitetsreducering är en typ av oövervakad inlärning där vi vill ta högdimensionella data, t.ex. bilder, och representera dem i ett lägre dimensionellt utrymme. Låt oss använda följande bild som exempel.

De här diagrammen visar samma data, förutom att det nedre diagrammet nollställer dem. Lägg märke till att våra data inte har några etiketter associerade med dem eftersom detta är oövervakad inlärning! I vårt enkla fall kommer dimensionalitetsreducering att reducera dessa data från ett 2D-plan till en 1D-linje. Om vi hade 3D-data skulle vi kunna reducera dem till ett 2D-plan eller till och med en 1D-linje.

Alla tekniker för dimensionalitetsreduktion syftar till att hitta ett hyperplan, en högre dimensionell linje, att projicera punkterna på. Vi kan föreställa oss en projektion som att ta en ficklampa vinkelrätt mot hyperplanet vi projicerar på och plotta var skuggorna faller på hyperplanet. Om vi till exempel vill projicera våra punkter på x-axeln i våra data ovan, kan vi låtsas att varje punkt är en boll och att vår ficklampa skulle peka rakt nedåt eller uppåt (vinkelrätt mot x-axeln) och punkternas skuggor skulle falla på x-axeln. Detta är en projektion. Vi kommer inte att oroa oss för den exakta matematiken bakom detta eftersom scikit-learn kan tillämpa denna projektion åt oss.

I vårt enkla 2D-fall vill vi hitta en linje att projicera våra punkter på. Efter att vi projicerat punkterna har vi data i 1D istället för 2D! På samma sätt, om vi hade 3D-data, vill vi hitta ett plan att projicera punkterna ner på för att minska dimensionaliteten hos våra data från 3D till 2D. De olika typerna av dimensionalitetsreducering handlar om att ta reda på vilket av dessa hyperplan vi ska välja: det finns ett oändligt antal av dem!

Princpal Component Analysis

En teknik för dimensionalitetsreducering kallas principal component analysis (PCA). Tanken bakom PCA är att vi vill välja det hyperplan som gör att när alla punkter projiceras på det, blir de maximalt utspridda. Med andra ord vill vi ha axeln med maximal varians! Låt oss betrakta vår exempelplott ovan. En potentiell axel är x-axeln eller y-axeln, men i båda fallen är det inte den bästa axeln. Om vi däremot väljer en linje som skär diagonalt genom våra data är det den axel där data skulle vara mest spridda!

Den längre blå axeln är den korrekta axeln! Om vi skulle projicera våra punkter på denna axel skulle de vara maximalt spridda! Men hur räknar vi ut denna axel? Vi kan låna en term från linjär algebra som heter egenvektorer! Det är här som egenvektorerna får sitt namn! I huvudsak beräknar vi kovariansmatrisen för våra data och betraktar den kovariansmatrisens största egenvektorer. Dessa är våra huvudaxlar och de axlar som vi projicerar våra data på för att minska dimensionerna. Med detta tillvägagångssätt kan vi ta högdimensionella data och reducera dem till en lägre dimension genom att välja de största egenvektorerna i kovariansmatrisen och projicera på dessa egenvektorer.

Då vi beräknar axlarna för maximal spridning behåller vi de viktigaste aspekterna av våra data. Det är lättare för vår klassificerare att separera ansikten när våra data är utspridda i motsats till hopklumpade.

(Det finns andra dimensioneringstekniker, t.ex. linjär diskriminantanalys, som använder sig av övervakad inlärning och som också används vid ansiktsigenkänning, men PCA fungerar riktigt bra!)

Hur hänger detta ihop med vår utmaning med ansiktsigenkänning? Vi kan konceptualisera våra m\times n

bilder som punkter im\dot n-dimensionella rum. Sedan kan vi använda PCA för att minska vårt utrymme frånm\dot ntill något mycket mindre. Detta kommer att bidra till att påskynda våra beräkningar och vara robust mot brus och variation.

Sidan om ansiktsdetektering

Sedan tidigare har vi antagit att den ingående bilden endast är den av ett ansikte, men i praktiken bör vi inte kräva att kamerabilderna ska ha ett perfekt centrerat ansikte. Därför kör vi en algoritm för ansiktsdetektering, t.ex. en kaskadklassificator som är tränad på ansikten, för att ta reda på vilken del av inmatningsbilden som innehåller ett ansikte. När vi har den avgränsande boxen kan vi enkelt skära ut den delen av inmatningsbilden och använda egna ansikten på den skivan. (Vanligtvis slätar vi ut den där skivan och utför en affintransformation för att avdramatisera ansiktet om det visas i en vinkel). För vårt syfte antar vi att vi redan har bilder av ansikten.

Kod för egenytor

Nu när vi har diskuterat PCA och egenytor ska vi koda en algoritm för ansiktsigenkänning med hjälp av scikit-learn! Först behöver vi en datamängd. För våra syften kommer vi att använda en färdig dataset från University of Massachusetts som heter Labeled Faces in the Wild (LFW).

Följ dig fri att ersätta din egen dataset! Om du vill skapa ditt eget dataset för ansikten behöver du flera bilder av varje persons ansikte (i olika vinklar och med olika belysning), tillsammans med grundsäkra etiketter. Ju större variation av ansikten du använder, desto bättre kommer igenkännaren att fungera. Det enklaste sättet att skapa en dataset för ansiktsigenkänning är att skapa en mapp för varje person och lägga ansiktsbilderna där. Se till att alla är lika stora och ändra storlek på dem så att de inte är stora bilder! Kom ihåg att PCA kommer att minska bildens dimensionalitet när vi projicerar på det utrymmet ändå så att använda stora, högupplösta bilder kommer inte att hjälpa och kommer att sakta ner vår algoritm. En bra storlek är ~512×512 för varje bild. Bilderna bör alla ha samma storlek så att du kan lagra dem i en numpy-array med dimensionerna (num_examples, height, width) . (Vi utgår från bilder i gråskala). Använd sedan mappnamnen för att särskilja klasserna. Med det här tillvägagångssättet kan du använda dina egna bilder.

Hur som helst kommer vi att använda datasetet LFW. Som tur är kan scikit-learn automatiskt ladda in vårt dataset åt oss i rätt format. Vi kan anropa en funktion för att ladda våra data. Om data inte finns tillgängliga på disk kommer scikit-learn automatiskt att ladda ner dem åt oss från University of Massachusetts webbplats.

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
# Ladda 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
# dela upp i en tränings- och testuppsättning
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

Argumentet till vår funktion rensar bara bort alla personer utan minst 100 ansikten, vilket minskar antalet klasser. Därefter kan vi extrahera vårt dataset och annan hjälpinformation. Slutligen delar vi upp vårt dataset i tränings- och testuppsättningar.

Nu kan vi helt enkelt använda scikit-learns PCA-klass för att utföra dimensionalitetsreduktionen åt oss! Vi måste välja antalet komponenter, dvs. utgångsdimensionaliteten (antalet egenvektorer att projicera på), som vi vill reducera ner till, och du får gärna justera denna parameter för att försöka få det bästa resultatet! Vi kommer att använda 100 komponenter. Dessutom kommer vi att bleka våra data, vilket är lätt att göra med en enkel boolsk flagga! (Att bleka gör bara att våra resulterande data har en enhetsvarians, vilket har visat sig ge bättre resultat)

1
2
3
4
5
6
7

# Beräkna en PCA
n_komponenter = 100
pca = PCA(n_komponenter=n_komponenter, whiten=True).fit(X_train)
# tillämpa PCA-transformation
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)

Vi kan tillämpa transformationen för att få ner våra bilder till ett 100-dimensionellt rum. Lägg märke till att vi inte utför PCA på hela datasetet, utan endast på träningsdata. Detta är för att vi bättre ska kunna generalisera till osynliga data.

När vi nu har en vektor med reducerad dimensionalitet kan vi träna vårt neurala nätverk!

1
2
3

# tränar ett neuralt nätverk
print(”Anpassning av klassificeraren till träningsuppsättningen”)
clf = MLPClassifier(hidden_layer_sizes=(1024,), batch_size=256, verbose=True, early_stopping=True).fit(X_train_pca, y_train)

För att se hur vårt nätverk tränar kan vi sätta flaggan verbose. Dessutom använder vi tidig stoppning.

Låt oss diskutera tidig stoppning som ett kort sidospår. I huvudsak kommer vår optimerare att övervaka den genomsnittliga noggrannheten för valideringsuppsättningen för varje epok. Om den märker att vår valideringsnoggrannhet inte har ökat avsevärt under ett visst antal epoker, stoppar vi träningen. Detta är en regleringsteknik som förhindrar att vår modell överanpassas!

Konsultera diagrammet ovan. Vi märker överanpassning när vår noggrannhet i valideringsuppsättningen börjar sjunka. Vid den tidpunkten stoppar vi omedelbart träningen för att förhindra överanpassning.

Slutligt kan vi göra en förutsägelse och använda en funktion för att skriva ut en hel rapport om kvaliteten för varje klass.

1
2

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

Här är ett exempel på en klassificeringsrapport.

1
2
3
4
5
6
7
8
9

precision recall f1-poäng stöd
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 / totalt 0,85 0,85 0,85 0,85 342

Observera att det inte finns något mått på noggrannhet. Noggrannhet är inte den mest specifika typen av mått att börja med. I stället ser vi precision, recall, f1-score och support. Stödet är helt enkelt antalet gånger som denna ground truth-etikett förekom i vår testuppsättning, t.ex. i vår testuppsättning fanns det faktiskt 35 bilder av Tony Blair. F1-poängen beräknas faktiskt bara från precision och recall-poängen. Precision och recall är mer specifika mått än en enda noggrannhetspoäng. Ett högre värde för båda är bättre.

När vi har tränat vår klassificerare kan vi ge den några bilder att klassificera.

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

# Visualisering
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}\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)

(plot_gallery och titles-funktioner modifierade från scikit-learn-dokumentationen)

Vi kan se vårt nätverks förutsägelser och ground truth-värdet för varje bild.

En annan sak som är intressant att visualisera är själva egenytorna. Kom ihåg att PCA producerar egenvektorer. Vi kan omforma dessa egenvektorer till bilder och visualisera egenytorna.

Dessa representerar de ”generiska” ansiktena i vårt dataset. Intuitivt sett är detta vektorer som representerar riktningar i ”ansiktsrymden” och är vad vårt neurala nätverk använder för att hjälpa till med klassificeringen. Nu när vi har diskuterat metoden med egenfaces kan du bygga program som använder denna algoritm för ansiktsigenkänning!

Vi diskuterade en populär metod för ansiktsigenkänning som kallas egenfaces. Kärnan i eigenfaces är en oövervakad algoritm för dimensionalitetsreducering som kallas Principal Components Analysis (PCA) som vi använder för att reducera dimensionaliteten i bilder till något mindre. Nu när vi har en mindre representation av våra ansikten tillämpar vi en klassificerare som tar den reducerade dimensionen som indata och producerar en klassbeteckning. För vår klassificerare använde vi ett neuralt nätverk med ett lager.

Ansiktsigenkänning är ett fascinerande exempel på sammansmältning av datorseende och maskininlärning, och många forskare arbetar fortfarande med detta utmanande problem i dag!

Nuförtiden används djupa konvolutionella neurala nätverk för ansiktsigenkänning, och de har enorma implikationer när det gäller utvecklingen av karriärvärlden. Prova ett på det här datasetet!

Lämna ett svar

Din e-postadress kommer inte publiceras.