Reconocimiento de caras con Eigenfaces

El reconocimiento de caras es omnipresente en la ciencia ficción: el protagonista mira a una cámara, y la cámara escanea su cara para reconocer a la persona. Más formalmente, podemos formular el reconocimiento de caras como una tarea de clasificación, en la que las entradas son imágenes y las salidas son nombres de personas. Vamos a hablar de una técnica popular para el reconocimiento de caras llamada eigenfaces. Y en el corazón de eigenfaces se encuentra una técnica de reducción de dimensionalidad no supervisada llamada análisis de componentes principales (PCA), y veremos cómo podemos aplicar esta técnica general a nuestra tarea específica de reconocimiento de caras. Descarga el código completo aquí.

¡No te lo pierdas! La oferta termina en
  • Accede a los más de 200 cursos
  • Se añaden nuevos cursos mensualmente
  • Cancela cuando quieras
  • Certificados de finalización

Reconocimiento de caras

Antes de hablar del análisis de componentes principales, debemos definir nuestro problema. El reconocimiento de caras es el reto de clasificar de quién es la cara en una imagen de entrada. Esto es diferente a la detección de caras, donde el reto es determinar si hay una cara en la imagen de entrada. En el caso del reconocimiento de rostros, necesitamos una base de datos de rostros existente. Dada una nueva imagen de una cara, necesitamos informar del nombre de la persona.

Una forma ingenua de lograr esto es tomar la nueva imagen, aplanarla en un vector, y calcular la distancia euclidiana entre ella y todas las demás imágenes aplanadas en nuestra base de datos.

Hay varias desventajas en este enfoque. En primer lugar, si tenemos una gran base de datos de caras, ¡hacer esta comparación para cada cara nos llevará un tiempo! Imagina que estamos construyendo un sistema de reconocimiento de caras para uso en tiempo real. Cuanto más grande sea nuestro conjunto de datos, más lento será nuestro algoritmo. Pero un mayor número de caras también producirá mejores resultados. Queremos un sistema que sea a la vez rápido y preciso. Para ello, utilizaremos una red neuronal. Podemos entrenar nuestra red en nuestro conjunto de datos y utilizarla para nuestra tarea de reconocimiento de caras.

Hay un problema con el uso directo de una red neuronal: ¡las imágenes pueden ser grandes! Si tuviéramos una sola imagen m\a n

, tendríamos que aplanarla en un solo vectorm\a n\a 1para alimentar nuestra red neuronal como entrada. En el caso de imágenes de gran tamaño, esto podría perjudicar la velocidad. Esto está relacionado con el segundo problema de utilizar las imágenes tal cual en nuestro enfoque ingenuo: ¡son de alta dimensión! (Una imagen

m\a nes en realidad un vectorm\a n\a 1) Una nueva entrada podría tener una tonelada de ruido y comparar todos y cada uno de los píxeles utilizando la sustracción de la matriz y la distancia euclidiana podría darnos un alto error y clasificaciones erróneas!

Estos problemas son la razón por la que no utilizamos el método ingenuo. En su lugar, nos gustaría tomar nuestras imágenes de alta dimensión y reducirlas a una dimensionalidad más pequeña, conservando la esencia o las partes importantes de la imagen.

Reducción de la dimensionalidad

La sección anterior motiva nuestra razón para utilizar una técnica de reducción de la dimensionalidad. La reducción de la dimensionalidad es un tipo de aprendizaje no supervisado en el que queremos tomar datos de mayor dimensión, como las imágenes, y representarlos en un espacio de menor dimensión. Usemos la siguiente imagen como ejemplo.

Estos gráficos muestran los mismos datos, excepto que el gráfico inferior los centra en cero. Observe que nuestros datos no tienen ninguna etiqueta asociada porque se trata de un aprendizaje no supervisado. En nuestro caso simple, la reducción de la dimensionalidad reducirá estos datos de un plano 2D a una línea 1D. Si tuviéramos datos en 3D, podríamos reducirlos a un plano en 2D o incluso a una línea en 1D.

Todas las técnicas de reducción de la dimensionalidad pretenden encontrar algún hiperplano, una línea de mayor dimensión, sobre la que proyectar los puntos. Podemos imaginar una proyección como si tomáramos una linterna perpendicular al hiperplano sobre el que estamos proyectando y trazáramos dónde caen las sombras en ese hiperplano. Por ejemplo, en nuestros datos anteriores, si quisiéramos proyectar nuestros puntos sobre el eje x, fingiríamos que cada punto es una pelota y nuestra linterna apuntaría directamente hacia abajo o hacia arriba (perpendicular al eje x) y las sombras de los puntos caerían sobre el eje x. Esto es una proyección. No nos preocuparemos por la matemática exacta detrás de esto ya que scikit-learn puede aplicar esta proyección por nosotros.

En nuestro simple caso 2D, queremos encontrar una línea para proyectar nuestros puntos. ¡Después de proyectar los puntos, entonces tenemos datos en 1D en lugar de 2D! Del mismo modo, si tuviéramos datos en 3D, queremos encontrar un plano para proyectar los puntos hacia abajo para reducir la dimensionalidad de nuestros datos de 3D a 2D. Los diferentes tipos de reducción de la dimensionalidad consisten en averiguar cuál de estos hiperplanos seleccionar: ¡hay un número infinito de ellos!

Análisis de componentes principales

Una técnica de reducción de la dimensionalidad se llama análisis de componentes principales (PCA). La idea detrás de PCA es que queremos seleccionar el hiperplano de tal manera que cuando todos los puntos se proyectan en él, son máximamente repartidos. En otras palabras, queremos el eje de máxima varianza. Consideremos nuestro ejemplo de gráfico anterior. Un eje potencial es el eje x o el eje y, pero, en ambos casos, no es el mejor eje. Sin embargo, si elegimos una línea que corte nuestros datos en diagonal, ¡ese es el eje en el que los datos estarían más repartidos!

¡El eje azul más largo es el eje correcto! Si proyectáramos nuestros puntos sobre este eje, ¡estarían máximamente repartidos! Pero, ¿cómo podemos calcular este eje? Podemos tomar prestado un término del álgebra lineal llamado vectores propios. De ahí viene el nombre de eigenfaces. Básicamente, calculamos la matriz de covarianza de nuestros datos y consideramos los mayores vectores propios de esa matriz de covarianza. Esos son nuestros ejes principales y los ejes sobre los que proyectamos nuestros datos para reducir las dimensiones. Usando este enfoque, podemos tomar datos de alta dimensión y reducirlos a una dimensión más baja mediante la selección de los mayores vectores propios de la matriz de covarianza y la proyección en esos vectores propios.

Dado que estamos calculando los ejes de máxima dispersión, estamos reteniendo los aspectos más importantes de nuestros datos. Es más fácil para nuestro clasificador separar las caras cuando nuestros datos están dispersos en lugar de agrupados.

(Hay otras técnicas de dimensionalidad, como el Análisis Discriminante Lineal, que utilizan el aprendizaje supervisado y también se utilizan en el reconocimiento de caras, pero el PCA funciona realmente bien))

¿Cómo se relaciona esto con nuestro reto de reconocimiento de caras? Podemos conceptualizar nuestras imágenes m\a n

como puntos en un espaciom\a n-dimensional. A continuación, podemos utilizar PCA para reducir nuestro espacio dem\dot na algo mucho más pequeño. Esto nos ayudará a acelerar nuestros cálculos y a ser robustos ante el ruido y la variación.

Aparte de la detección de caras

Hasta ahora, hemos asumido que la imagen de entrada es sólo la de una cara, pero, en la práctica, no debemos exigir que las imágenes de la cámara tengan una cara perfectamente centrada. Por eso ejecutamos un algoritmo de detección de rostros, como un clasificador en cascada entrenado en rostros, para averiguar qué parte de la imagen de entrada tiene un rostro. Cuando tenemos ese cuadro delimitador, podemos cortar fácilmente esa parte de la imagen de entrada y utilizar los rostros propios en ese corte. (Normalmente, suavizamos ese corte y realizamos una transformación afín para desenfocar la cara si aparece en un ángulo). Para nuestros propósitos, asumiremos que ya tenemos imágenes de caras.

Código de eigenfaces

Ahora que hemos discutido PCA y eigenfaces, ¡codifiquemos un algoritmo de reconocimiento de caras usando scikit-learn! En primer lugar, necesitaremos un conjunto de datos. Para nuestros propósitos, utilizaremos un conjunto de datos de la Universidad de Massachusetts llamado Labeled Faces in the Wild (LFW).

¡Siéntete libre de sustituir tu propio conjunto de datos! Si quieres crear tu propio conjunto de datos de caras, necesitarás varias fotos de la cara de cada persona (en diferentes ángulos e iluminación), junto con las etiquetas de la verdad. Cuanto mayor sea la variedad de caras que utilices, mejor será el reconocimiento. La forma más fácil de crear un conjunto de datos para el reconocimiento facial es crear una carpeta para cada persona y poner las imágenes de la cara allí. Asegúrate de que cada una tenga el mismo tamaño y redimensiónalas para que no sean imágenes grandes. Recuerda que el PCA reducirá la dimensionalidad de la imagen cuando la proyectemos en ese espacio, así que usar imágenes grandes y de alta definición no ayudará y ralentizará nuestro algoritmo. Un buen tamaño es ~512×512 para cada imagen. Las imágenes deben ser todas del mismo tamaño para que puedas almacenarlas en un array numpy con dimensiones (num_examples, height, width) . (Suponemos que son imágenes en escala de grises). A continuación, utiliza los nombres de las carpetas para desambiguar las clases. Usando este enfoque, puede utilizar sus propias imágenes.

Sin embargo, vamos a utilizar el conjunto de datos LFW. Por suerte, scikit-learn puede cargar automáticamente nuestro conjunto de datos para nosotros en el formato correcto. Podemos llamar a una función para cargar nuestros datos. Si los datos no están disponibles en el disco, scikit-learn los descargará automáticamente por nosotros desde el sitio web de la Universidad de 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
# split into a training and testing set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

El argumento de nuestra función sólo depura todas las personas que no tienen al menos 100 caras, reduciendo así el número de clases. A continuación, podemos extraer nuestro conjunto de datos y otra información auxiliar. Finalmente, dividimos nuestro conjunto de datos en conjuntos de entrenamiento y de prueba.

¡Ahora podemos simplemente utilizar la clase PCA de scikit-learn para realizar la reducción de dimensionalidad por nosotros! ¡Tenemos que seleccionar el número de componentes, es decir, la dimensionalidad de salida (el número de vectores propios para proyectar en), que queremos reducir a, y no dude en ajustar este parámetro para tratar de obtener el mejor resultado! Utilizaremos 100 componentes. Además, vamos a blanquear nuestros datos, lo que es fácil de hacer con una simple bandera booleana. (El blanqueo sólo hace que nuestros datos resultantes tengan una varianza unitaria, que se ha demostrado que produce mejores resultados)

1
2
3
4
5
6
7

# Calcula un PCA
n_componentes = 100
pca = PCA(n_componentes=n_componentes, whiten=True).fit(X_train)
# aplicar transformación PCA
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)

Podemos aplicar la transformación para reducir nuestras imágenes a un espacio de 100 dimensiones. Obsérvese que no estamos realizando el PCA en todo el conjunto de datos, sino sólo en los datos de entrenamiento. Esto es para poder generalizar mejor a los datos no vistos.

Ahora que tenemos un vector de dimensiones reducidas, ¡podemos entrenar nuestra red neuronal!

1
2
3

# entrenar una red neuronal
print(«Ajustando el clasificador al conjunto de entrenamiento»)
clf = MLPClassifier(hidden_layer_sizes=(1024,), batch_size=256, verbose=True, early_stopping=True).fit(X_train_pca, y_train)

Para ver cómo está entrenando nuestra red, podemos poner la bandera verbose. Además, utilizamos la parada temprana.

Discutiremos la parada temprana como un breve aparte. Esencialmente, nuestro optimizador controlará la precisión media del conjunto de validación para cada época. Si nota que nuestra precisión de validación no ha aumentado significativamente para un cierto número de épocas, entonces dejamos de entrenar. Esta es una técnica de regularización que evita que nuestro modelo se sobreajuste. Nos damos cuenta del sobreajuste cuando la precisión de nuestro conjunto de validación empieza a disminuir. En ese momento, detenemos inmediatamente el entrenamiento para evitar el sobreajuste.

Por último, podemos hacer una predicción y utilizar una función para imprimir un informe completo de la calidad de cada clase.

1
2

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

Aquí tienes un ejemplo de informe de clasificación.

1
2
3
4
5
6
7
8
9

precisión recuerdo f1-puntuación apoyo
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 / total 0,85 0,85 0,85 342

Nótese que no hay métrica de precisión. La exactitud no es el tipo de métrica más específico para empezar. En su lugar, vemos la precisión, recall, f1-score, y el apoyo. El apoyo es simplemente el número de veces que esta etiqueta de la verdad de tierra se produjo en nuestro conjunto de pruebas, por ejemplo, en nuestro conjunto de pruebas, en realidad había 35 imágenes de Tony Blair. La puntuación F1 se calcula a partir de las puntuaciones de precisión y recuperación. La precisión y la recuperación son medidas más específicas que una única puntuación de precisión. Un valor más alto para ambos es mejor.

Después de entrenar a nuestro clasificador, podemos darle algunas imágenes para clasificar.

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

# Visualización
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 títulos(y_pred, y_test, nombres_de_objetivo):
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)

(funciones plot_gallery y titles modificadas de la documentación de scikit-learn)

Podemos ver las predicciones de nuestra red y el valor de la verdad del terreno para cada imagen.

Otra cosa interesante de visualizar son las propias eigenfaces. Recordemos que el PCA produce vectores propios. Podemos remodelar esos vectores propios en imágenes y visualizar las caras propias.

Estas representan las caras «genéricas» de nuestro conjunto de datos. Intuitivamente, son vectores que representan direcciones en el «espacio facial» y son lo que nuestra red neuronal utiliza para ayudar a la clasificación. Ahora que hemos discutido el enfoque de eigenfaces, ¡puedes construir aplicaciones que usen este algoritmo de reconocimiento de caras!

Hemos discutido un enfoque popular para el reconocimiento de caras llamado eigenfaces. La esencia de eigenfaces es un algoritmo de reducción de dimensionalidad no supervisado llamado Análisis de Componentes Principales (PCA) que utilizamos para reducir la dimensionalidad de las imágenes en algo más pequeño. Ahora que tenemos una representación más pequeña de nuestros rostros, aplicamos un clasificador que toma la entrada de dimensión reducida y produce una etiqueta de clase. Para nuestro clasificador, utilizamos una red neuronal de una sola capa.

El reconocimiento de rostros es un ejemplo fascinante de la fusión de la visión por ordenador y el aprendizaje automático y muchos investigadores siguen trabajando en este desafiante problema hoy en día!

Hoy en día, las redes neuronales convolucionales profundas se utilizan para el reconocimiento de rostros, y tienen vastas implicaciones en términos del mundo de la carrera de desarrollo. Pruebe una en este conjunto de datos!

Deja una respuesta

Tu dirección de correo electrónico no será publicada.