Ansigtsgenkendelse er et af de områder, der anvender maskinlæring, og det anvendes bredt på mange områder lige fra tagging af fotos på sociale medier og matchning af personer med de samme ansigtstræk på datingwebsteder til opsporing af kriminelle og sikring af grænser og til at holde storspillere på afstand i kasinoer.
Jeg finder det fascinerende, at vi kan simulere processen med ansigtsgenkendelse med en betydelig grad af præcision, mens der samtidig er mennesker, der lider af prosopagnosia, eller “ansigtsblindhed”, som ikke er så heldige. En forfatter til en Cracked-artikel, som jeg faldt over for et stykke tid siden, beskriver denne oplevelse som at se en bunke LEGO-brikker, hvor man, så snart man kigger væk, ikke længere kan beskrive i nogen væsentlig detalje, hvilken farve og form hver enkelt brik havde, eller hvordan de var placeret. Jeg har spekuleret på, om denne kognitive forstyrrelse har noget at gøre med hukommelsesallokering. Heldigvis er hukommelse noget, som computere har masser af, og vi er ikke engang begyndt at skrabe på overfladen af alle de muligheder, som kvantecomputere vil frembyde.
Men tilbage til egenflader.
De visuelle data i et billede kan afbildes til en vektor, hvor hver post repræsenterer lysstyrken af den tilsvarende pixel. Ved at tage et sæt billeder kan der derefter konstrueres en matrix, hvor hver række svarer til en bestemt billedvektor. Ideelt set normaliseres billederne først på en sådan måde, at grundlæggende træk som f.eks. øjne, næse og mund tilpasses for at øge nøjagtigheden og reducere støj. Egenansigter er derefter de egenvektorer, der er afledt af kovariansmatrixen for denne matrix af analyserede ansigtsdata.
Datasættet af ansigter, vi anvendte, blev venligst stillet til rådighed af AT&T Laboratories i Cambridge og bestod af 40 individuelle ansigter, 10 billeder af hvert med varierende ansigtsudtryk og hovedpositioner.
Følgende Python-biblioteker og -moduler blev anvendt i denne øvelse:
from sklearn.preprocessing import normalize
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
from scipy.misc import imread
from itertools import chain
import numpy as np
import scipy as sp
import glob
-
normalize
funktionen skalerer hver enkelt prøvevektor til at have enhedsnorm. -
PCA
eller Principle Component Analysis, er en proces til lineær dimensionalitetsreduktion ved hjælp af Singular Value Decomposition af dataene for at projicere dem til et lavere dimensionelt rum. Med andre ord er det en proces, hvor man finder den underliggende struktur i dataene eller de retninger, hvor der er størst varians. -
matplotlib.pyplot
er den velkendte plottingfunktion. -
imread
bruges til at læse et billede fra en fil som et array. -
chain
er en iterator, der går gennem listen og returnerer individuelle elementer fra hver iterabel. -
numpy
er den grundlæggende Python-pakke til videnskabelige beregninger. -
scipy
er en anden pakke til videnskabelig og teknisk databehandling, der lignernumpy
, men som indeholder mere udbyggede versioner af modulerne til lineær algebra samt mange andre numeriske algoritmer. -
glob
modulet finder alle de stinavne, der matcher et angivet mønster.
Det første skridt er at udtrække alle filnavne fra det zippede arkiv. Derefter oprettes en matrix ved at optrævle billedmatricer til vektorer ved hjælp af kommandoen chain
og stable dem. Dette skaber en 400×10304-matrix, hvor hver række indeholder alle oplysninger om et specifikt 112×92-billede.
filenames = m = for i in range(400)]for i in range(400):
m = list(chain.from_iterable(imread(filenames)))
m = np.matrix(m)
Dernæst normaliseres matricen, og PCA’en anvendes. Her har vi reduceret vores vektorrum til kun 40 ud af 10304 dimensioner:
model = PCA(n_components=40)
pts = normalize(m)
model.fit(pts)
pts2 = model.transform(pts)
Endeligt kan egenfladerne, der er indeholdt i model.components_
, vises:
fig, ax = plt.subplots(1,40)for i in range(40):
ord = model.components_
img = ord.reshape(112,92)
ax.imshow(img,cmap='gray')
Og der har vi det. En masse uhyggelige ansigter.
Det, vi i bund og grund har gjort, er at skabe et ortogonalt basissæt, hvor hvert egenansigt fremhæver en bestemt type træk, og hvorfra de ansigter, vi har brugt, kan rekonstrueres gennem forskellige kombinationer og proportioner af egenvektorer.
faces_pca = PCA(n_components=40)
faces_pca.fit(m)
components = faces_pca.transform(m)
projected = faces_pca.inverse_transform(components)fig, axes = plt.subplots(40,10,figsize=(20,80))
for i, ax in enumerate(axes.flat):
ax.imshow(projected.reshape(112,92),cmap="gray")
Da vi komprimerede vores vektorrum så meget (og ikke justerede ansigterne til at begynde med), gik mange detaljer tabt, men ansigterne forblev stadig nogenlunde genkendelige.
Og derfor er målet for computervisionsproblemet med genkendelse af menneskelige ansigter at skabe det mindste antal egenansigter, der på passende vis kan repræsentere hele træningsmængden. Hvis træningsmængden er tilstrækkeligt forskelligartet, bør det resulterende sæt af egenansigter kunne repræsentere alle ansigter. Og selv om der er sket betydelige fremskridt i de seneste år med algoritmer til ansigtsgenkendelse, er der stadig lang vej igen og mange forbedringer, der skal foretages.
På den anden side, og som altid, er der nogle farer forbundet med de stadigt voksende muligheder for software, der er i stand til at genkende, simulere og dermed potentielt bedrage og manipulere et intetanende individ, og vi må tage passende forholdsregler for at sikre, at det bruges hensigtsmæssigt.
Og jeg vil bare lade dette stå her som et eksempel og til din underholdning.