Kasvojentunnistus on yksi koneoppimista hyödyntävistä aloista, ja sitä käytetään laajalti monilla aloilla aina valokuvien merkitsemisestä sosiaalisessa mediassa ja samoja kasvonpiirteitä omaavien ihmisten yhteensovittamisesta deittisivustoilla, rikollisten jäljittämisestä ja rajojen turvaamisesta suurten rullien pelaajien pitämiseen loitolla kasinoilla.

Minusta on kiehtovaa, että voimme simuloida kasvojentunnistusprosessia huomattavan tarkasti, kun taas samaan aikaan on ihmisiä, jotka kärsivät prosopagnosiasta eli ”kasvosokeudesta” ja jotka eivät ole yhtä onnekkaita. Erään Cracked-artikkelin kirjoittaja, johon törmäsin jokin aika sitten, kuvailee tätä kokemusta kuin näkisi kasan LEGO-palikoita, joiden kohdalla ei enää pysty kuvaamaan yksityiskohtaisesti, minkä värisiä ja muotoisia kukin pala on tai miten ne on sijoitettu. Olen miettinyt, liittyykö tämä kognitiivinen häiriö jotenkin muistin jakamiseen. Onneksi tietokoneilla on runsaasti muistia, emmekä ole vielä edes raapaisseet pintaa kaikista kvanttilaskennan tarjoamista mahdollisuuksista.

Mutta takaisin omiin näkymiin.

Kuvan visuaalista dataa voidaan kuvata vektoriksi, jossa jokainen merkintä edustaa vastaavan pikselin kirkkautta. Kun otetaan joukko kuvia, voidaan muodostaa matriisi, jonka jokainen rivi vastaa tiettyä kuvavektoria. Ihannetapauksessa kuvat normalisoidaan ensin siten, että peruspiirteet, kuten silmät, nenä ja suu, kohdistetaan toisiinsa tarkkuuden lisäämiseksi ja kohinan vähentämiseksi. Omat kasvot ovat sitten omavektoreita, jotka johdetaan tämän analysoidun kasvodatan matriisin kovarianssimatriisista.

Käyttämämme kasvotietokanta saatiin ystävällisesti AT&T Laboratoriesilta Cambridgesta, ja se koostui 40 yksittäisestä kasvosta, joista jokaisesta oli 10 kuvaa, joissa oli vaihtelevia ilmeitä ja pään asentoja.

Harjoituksessa käytettiin seuraavia Python-kirjastoja ja -moduuleja:

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-funktio skaalaa jokaisen yksittäisen otosvektorin niin, että sillä on yksikkönormi.
  • PCA eli periaatekomponenttianalyysi on lineaarinen dimensioiden pienentämisprosessi, jossa käytetään datan singulaariarvojen hajotusta sen projisoimiseksi alempiulotteiseen avaruuteen. Toisin sanoen se on prosessi, jossa etsitään datan perimmäinen rakenne tai suunnat, joissa on eniten varianssia.
  • matplotlib.pyplot on tuttu piirtofunktio.
  • imread käytetään kuvan lukemiseen tiedostosta matriisina.
  • chain on iteraattori, joka käy listan läpi palauttaen yksittäisiä elementtejä jokaisesta iteraattorista.
  • numpy on perustavanlaatuinen Python-paketti tieteelliseen laskentaan.
  • scipy on toinen tieteelliseen ja tekniseen laskentaan tarkoitettu paketti, joka on samankaltainen kuin numpy, mutta joka sisältää monipuolisemmat versiot lineaarialgebran moduuleista sekä monia muita numeerisia algoritmeja.
  • glob moduuli etsii kaikki polkujen nimet, jotka sopivat määritettyyn kuvioon.

Ensimmäisenä vaiheena poimitaan pakatusta arkistosta kaikki tiedostojen nimet. Sitten luodaan matriisi purkamalla kuvamatriisit vektoreiksi chain-komennolla ja pinoamalla ne. Näin luodaan 400×10304-matriisi, jonka jokainen rivi sisältää kaikki tiedot tietystä 112×92-kokoisesta kuvasta.

filenames = m = for i in range(400)]for i in range(400):
m = list(chain.from_iterable(imread(filenames)))
m = np.matrix(m)

Seuraavaksi matriisi normalisoidaan ja sovelletaan PCA:ta. Tässä olemme pienentäneet vektoriavaruutemme vain 40:een ulottuvuuteen 10304:stä:

model = PCA(n_components=40)
pts = normalize(m)
model.fit(pts)
pts2 = model.transform(pts)

Viimeiseksi voidaan näyttää model.components_:n sisältämät ominaissivut:

fig, ax = plt.subplots(1,40)for i in range(40):
ord = model.components_
img = ord.reshape(112,92)
ax.imshow(img,cmap='gray')

>

Ja siinäpä se. Joukko karmivia kasvoja.

Mitä olemme pohjimmiltaan tehneet, on luonut ortogonaalisen perusjoukon, jossa kukin ominaissuure korostaa tietynlaista piirrettä, ja josta käyttämämme kasvot voidaan rekonstruoida ominaissuureiden erilaisten yhdistelmien ja suhteiden avulla.

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")

Koska tiivistimme vektoriavaruuttamme niin paljon (emmekä alun perin kohdistaneet kasvoja toisiinsa sopiviksi), paljon yksityiskohtia hävisi, mutta kasvot pysyivät silti jokseenkin tunnistettavina.

Tietokonenäön ongelman, ihmisten kasvojen tunnistamisen, tavoitteena on siis luoda mahdollisimman pieni määrä omia kasvoja, jotka voivat edustaa riittävästi koko harjoitusjoukkoa. Jos harjoitusjoukko on riittävän monipuolinen, tuloksena olevan ominaisten kasvojen joukon pitäisi pystyä edustamaan kaikki kasvot. Vaikka kasvontunnistusalgoritmeissa on viime vuosina tapahtunut merkittävää edistystä, on vielä paljon parannettavaa.

Toisaalta, kuten aina, yhä laajeneviin ohjelmistoihin, jotka pystyvät tunnistamaan, simuloimaan ja siten mahdollisesti pettämään ja manipuloimaan pahaa-aavistamatonta ihmistä, liittyy joitakin vaaroja, ja meidän on ryhdyttävä riittäviin varotoimiin varmistaaksemme, että niitä käytetään asianmukaisesti.

Ja jätän tämän tähän vain esimerkkinä ja viihdykkeeksi.

Kaiken tämän lisäksi jätän tämän tähän.

Vastaa

Sähköpostiosoitettasi ei julkaista.