En este repositorio se realiza el proyecto de reconocimiento facial usando la base de datos de CelebA.
-
Entrenar una red convolucional para predecir los atributos de la base de datos CelebA que contiene imagenes de rostros etiquetadas con 40 atributos.
-
Posteriormente construir un modelo con las capas convolucionales del modelo entrenado pero quitandole el clasificador (capas densas del final).
-
Aumentar un clasificador apropiado para distinguir solo si es el rostro o no (una sola neurona de salida).
-
Congelar los pesos de la parte pre-entrenada (o primeras capas)
-
Entrenar este modelo.
La base de datos que se usa es la de CelebA, la cual consiste de:
- Una colección de 202,599 imagenes de rostros de celebridades
- Un archivo de texto binario que tiene etiquetado 40 atributos de cada imagen.
Esta base de datos y su documentacion se puede encontrar en el sitio de kaggle: https://www.kaggle.com/datasets/jessicali9530/celeba-dataset
Una vez obtenida la base de datos e importadas las paqueterias, tenemos que cargar los dos tipos de datos: una carpeta con puras imagenes de rostros y un archivo de texto binario con los atributos de cada imagen.
Comenzamos con el segundo porque al ser un archivo de texto con datos estructurados es más fácil de manejar si lo tratamos como un csv, es decir, un archivo Comma Separated Value, el cual tiene formato de tabla, para convertir el archivo de texto a un archivo CSV usamos la paquetería de Pandas.
Para las imagenes definimos la ruta en la que se encuentra la carpeta e iniciamos el procesamiento de imagenes que en este caso consiste en asignarle el nombre de la imagen, sus atributos y la imagen misma en un solo dato el cual llamamos imagen etiquetada, transformar la imagen de 3 canales RGB a un tensor en escala de grises, redimensionar la imagen y por ultimo normalizar la intensidad de los tonos de grises, el cual va de 0 (negro) a 255 (blanco).
Una vez procesados los datos podemos comenzar con el modelo predictivo, el cual consiste de una secuencia de redes neuronales convolucionales 2D con su respectiva activación ReLu y un MaxPooling2D para procesar las matrices de imagenes y por ultimo se "aplana" la red para usar una red neuronal densa y una activación sigmoide que procese los datos para poder predecir si una imagen contiene o no cada atributo de los 40 considerados.
Para este tipo de problemas es conveniente usar una funcion de costo binaria como el Binary_crossentropy y el optimizador RMSprop (Root Mean Squared Propagation) con una metrica binaria.
Para finalizar con este primer modelo, se entrenó con 10 epocas, con lo cual se obtuvo una precision cerca del 90%.
En este caso volvemos a cargar los datos, los cuales serán imagenes. Para el conjunto de entrenamiento y de validación tenemos que deben estar las imagenes deben estar etiquetadas para poder entrenar el modelo, por ello hay dos carpetas en cada conjunto, una con fotos de nuestro rostro y otra con fotos de otras personas, por otro lado, para el conjunto de prueba estarán mezcladas las fotos de nosotros con las de otras personas para evaluar el modelo. Una vez cargadas las imagenes, tenemos que procesarlas, para esto podemos usar la clase ImageDataGenerator para normalizar y redimensionar las imagenes.
Para el modelo clasificador o de reconocimiento facial se usa una técnica llamada Transfer Learning, la cual consiste en usar un modelo pre entrenado para crear otro modelo, basta con entrenar el modelo original con los nuevos datos de interés. En nuestro caso, el modelo original ya fue entrenado para identificar atributos en los rostros, por lo que es capaz de distinguir rostros, ahora usaremos este desempeño para que pueda reconocer mi rostro, solo basta con usar las capas convolucionales del modelo entrenado y agregarle un clasificador, el cual tendrá como salida un sí o no.
Cargamos el modelo 1 pre entrenado.
Definimos la estructura del modelo 2, el clasificador y congelamos los pesos de las capas convolucionales, dado que ya fueron entrenadas.
Definimos la funcion de costo, el optimizador y la metrica correspondiente.
En este caso después de usar distintos optimizadores, se optó por utilizar el optimizador Adam dado que con otros el resultado era ineficiente, igualmente me di cuenta que al disminuir el learning rate se obtenían mejores resultados.
Por ultimo, se entrena el modelo.
Algunos problemas encontrados:
Al momento de procesar los datos del modelo 1, dado que la lista de atributos era un archivo de texto tipo estructurado pero separado por espacios en blanco, se tuvo que reemplazar los espacios en blanco por comas para poder tratarlo como un CSV con la paquetería de Pandas.
En el proceso del Modelo 2 hubo complicaciones desde el principio dado que al usar ImageDataGenerator no leía mis fotos, después de intentar arreglarlo me di cuenta que era por el tipo de formato, la clase ImageDataGenerator no lee formatos tipo .JFIF, por lo cual hubo que transformar el formato para poder procesarlo.
Por otra parte, en la generación de imágenes del modelo 2, me salió un error de que el directorio de una imagen mía no existía y por lo tanto no se podían generar nuevas imagenes, este error aún no sé cómo solucionarlo, así que decidí usar la funcion flow_from_directory() la cual transforma las imagenes mientras se entrena, de esta forma pude entrenar el modelo.
Conclusiones:
-
Antes de realizar este proyecto, desconocía lo versatil que puede ser trabajar con los modelos de redes neuronales, el poder crear un modelo nuevo a partir de otro ya entrenado es una herramienta muy poderosa que es escalable fuera del area de las imagenes.
-
Si bien trabajar con redes neuronales e imagenes puede ser abrumador porque todo tiene que encajar correctamente, también es verdad que conociendo las bases y leyendo la documentación correspondiente de keras, es posible tener una idea general de lo que sucede.