G5 Proyecto Final Reconocimiento facial..docx PDF

Title G5 Proyecto Final Reconocimiento facial..docx
Author JORGE SANTIAGO SOTO
Course Inteligencia Artificial
Institution Universidad Nacional Mayor de San Marcos
Pages 9
File Size 541.1 KB
File Type PDF
Total Downloads 52
Total Views 137

Summary

reconocimiento facial de unas imágenes con inteligencia artificial lo cual permite incluir en diferentes aplicaciones. Se muestra la implementación en un código de Python...


Description

Procesamiento Digital de Imágenes Para Detectar Emociones Mediante Redes Neuronales Convolucionales en Tiempo Real Poma Chamorro, Cielo Celeste Justa; Panduro Ruiz, Angel Jesus; Gonzales Leyva, Jean Franco; Santiago Soto, Jorge Gustavo; Villanueva Guerrero, Luis; Cusipuma Ayuque, Juan Jaime Ingeniería Electrónica, Universidad Nacional Mayor de San Marcos Lima, Perú [email protected] [email protected] [email protected] [email protected]

Abstract— Hoy en día el paso clave en la humanización de la robótica es la capacidad de clasificar la emoción del ser humano. En este documento presentamos el diseño de un sistema artificial inteligente con un lenguaje de programación, Python, siendo capaz de reconocer emociones a través de expresiones faciales, donde tres arquitecturas de redes neuronales prometedoras se personalizan, entrenan y someten a varias tareas de clasificación, después se optimiza aún más la red con el mejor rendimiento. Finalmente, se verifica el modelo final con el retrato en una aplicación de video en vivo que puede devolver instantáneamente la emoción del usuario.

- Cámara web en el ordenador a utilizar. - Tener instalado el Anaconda. Luego descargamos los archivos para después importar los archivos de requerimientos como se muestra en la Fig.1.

Keywords— Artificial, emociones, inteligencia, Python, reconocer, red, robótica, vivo. I. INTRODUCCIÓN Desde el desarrollo de las computadoras, los científicos e ingenieros pensaron en sistemas artificialmente inteligentes que son mental y/o físicamente equivalentes a los humanos. En las últimas décadas, el aumento de la potencia computacional generalmente disponible brindó una mano para el desarrollo de máquinas de aprendizaje rápido, mientras que internet proporciona una enorme cantidad de datos para la capacitación. Estos dos desarrollos impulsaron la investigación sobre sistemas inteligentes de autoaprendizaje, siendo las redes neuronales una de las técnicas más prometedoras. II. DESARROLLO DEL PROYECTO A partir de esta sección, se desarrollan los contenidos del tema, de una forma ordenada y secuencial. A. Instalación necesaria para correr el programa y características En esta sección se especifican los software que se deben instalar para correr el programa, así como la primera parte del código. Se debe tener en cuenta los siguientes requisitos para entender y aplicar el proyecto: - Conocimientos básicos en Python.

Fig. 1 Carpeta del proyecto

Fig. 2 Carpeta de las emociones en 7 categorías

El código se hizo para ejecutar dos modelos, uno para entrenamiento y otro para ejecución. En la carpeta también se obtendrán los conjuntos de datos que constan de múltiples imágenes clasificadas en siete emociones, tanto para entrenamiento como para un modelo ya entrenado (Fig. 2).

Ahora, para poder ejecutar el código se necesita instalar: - Python 3 - OpenCV - Tensorflow Además, también se puede instalar los paquetes necesarios o que nos faltan cuando ejecutamos el siguiente comando en Anaconda Prompt: pip install -r requirements.txt.

Si no encuentra la carpeta en el Anaconda ponemos cd, se deja un espacio y enseguida en enlace de la ubicación de la carpeta.

Fig. 3 Panel de Anaconda Prompt

Luego, se instalará las siguientes requerimientos como mínimo para que funcione: numpy==1.17.4 opencv-python==4.1.2.30 tensorflow==2.2.0rc1 tflearn==0.3.2 keras==2.2.4 También se puede instalar uno por uno si se tiene algún error. Luego de la instalación se podrá visualizar la aplicación. El detalle del código y del procedimiento para visualizar la aplicación lo veremos en el transcurso del documento. Primero conoceremos las librerías necesarias, siendo el siguiente código a utilizar: # Importamos las librerías necesarias import numpy as np import argparse import cv2 from keras.models import Sequential from keras.layers.core import Dense, Dropout, Flatten from keras.layers.convolutional import Conv2D from keras.optimizers import Adam from keras.layers.pooling import MaxPooling2D from keras.preprocessing.image import ImageDataGenerator

import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' import matplotlib as mpl mpl.use('TkAgg') import matplotlib.pyplot as plt Donde: NumPy es una librería de Python especializada en el cálculo numérico y el análisis de datos, especialmente para un gran volumen de datos. [1] Argparse incluye herramientas para construir procesadores de argumentos y opciones de línea de comando. Fue agregado a Python 2.7 como reemplazo de optparse. Keras es un framework de alto nivel para el aprendizaje, escrito en Python y capaz de correr sobre los frameworks TensorFlow, CNTK, o Theano. Fue desarrollado con el objeto de facilitar un proceso de experimentación rápida. Lo que haremos en este experimento es entrenar modelos de clasificación de imágenes. Esto consiste en dada una serie de imágenes etiquetadas, reconocer una imagen y asignarle dicha etiqueta. [2] ImageDataGenerator es una clase que al usarla define el generador de imágenes de entrenamiento. [3] Matplotlib es una librería para generar gráficas a partir de datos contenidos en listas, vectores, en el lenguaje de programación Python y en su extensión matemática NumPy. [4] Gracias al uso de las librerías nos facilita el uso de pocas líneas de código siendo un proyecto que se entrena con un conjunto de datos. B. Método para representar gráficos de los valores de precisión y pérdidas. Se puede aprender mucho sobre las redes neuronales y los modelos de aprendizaje profundo observando su rendimiento a lo largo del tiempo durante el entrenamiento. Esto es posible gracias a la librería Keras, la cual proporciona la capacidad de registrar devoluciones de llamada al entrenar un modelo de aprendizaje profundo. Una de las devoluciones de llamada predeterminadas que se registra al entrenar todos los modelos de aprendizaje profundo es la devolución de llamada del historial . La misma que se encarga de registrar métricas de entrenamiento para cada época, incluyendo el de la pérdida y la precisión, que es lo que precisamente necesitamos. El objeto histórico se devuelve de las llamadas a la función fit () utilizada para entrenar el modelo. Las métricas se almacenan en un diccionario en el miembro histórico del objeto devuelto. Es así que aplicando este concepto a nuestro programa, construimos las siguientes instrucciones: def plot_model_history(model_history): """ Método que nos permitirá representar los valores de exactitud y pérdidas mediante gráficos.

""" fig, axs = plt.subplots(1,2,figsize=(15,5)) # Definimos las características del gráfico del historial de precisión. axs[0].plot(range(1,len(model_history.history['acc'])+1), model_history.history['acc']) # “acc” es la precisión calculada en el conjunto de entrenamiento (datos que el modelo ha podido ver con anterioridad). axs[0].plot(range(1,len(model_history.history['val_acc']) +1),model_history.history['val_acc']) # “val_acc” es la precisión calculada en el conjunto de validación (es decir, sobre datos que el modelo "nunca ha visto"). # Implementamos las etiquetas que tendrá nuestro gráfico de precisión. axs[0].set_title('Model Accuracy') axs[0].set_ylabel('Accuracy') axs[0].set_xlabel('Epoch') axs[0].set_xticks(np.arange(1,len(model_history.history[ 'acc'])+1),len(model_history.history['acc'])/10) axs[0].legend(['train', 'val'], loc='best')

Fig. 4. Gráfico de Precisión del modelo,

Se observa cómo en cada época el modelo de entrenamiento tiene una mejora muy significativa en su precisión. Pero esta no necesariamente seguirá aumentando en función al número de épocas, pues está el problema del Overfitting, lo que ocurrirá es que nuestra máquina sólo se ajustará a aprender los casos particulares que le enseñamos y será incapaz de reconocer nuevos datos de entrada.

# Definimos las características del gráfico del historial de pérdidas. axs[1].plot(range(1,len(model_history.history['loss'])+1), model_history.history['loss']) # “acc” es la precisión calculada en el conjunto de entrenamiento (datos que el modelo ha podido ver con anterioridad). axs[1].plot(range(1,len(model_history.history['val_loss']) +1),model_history.history['val_loss']) # “val_acc” es la precisión calculada en el conjunto de validación (es decir, sobre datos que el modelo "nunca ha visto").

Fig. 5. El problema del underfitting y el overfitting.

# Implementamos las etiquetas que tendrá nuestro gráfico de pérdidas. axs[1].set_title('Model Loss') axs[1].set_ylabel('Loss') axs[1].set_xlabel('Epoch') axs[1].set_xticks(np.arange(1,len(model_history.history[ 'loss'])+1),len(model_history.history['loss'])/10) axs[1].legend(['train', 'val'], loc='best') # Se guarda ambos gráficos en formato png. fig.savefig('plot.png') plt.show() De esta forma, ejecutando el modelo de entrenamiento, obtenemos tanto la gráfica de precisión como la de pérdidas:

Fig. 6. Gráfico de pérdidas del modelo.

De forma análoga vemos cómo las pérdidas se reducen a medida que el número de épocas es mayor. Pero como vimos, tenemos que tener cuidado de sobreajustar el modelo (Overfitting). Es entonces que debemos encontrar el número de épocas adecuado para obtener la mayor precisión sin caer en dicho sobreajuste. C. Preprocesamiento de datos En esta sección se describe el código utilizado para el

pre-procesamiento de los datos y el reconocimiento en tiempo real de las emociones faciales.

componente de la ruta. 4. Inicializamos la cuenta de cada emoción.

1. Importamos las siguientes librerías: import numpy as np import pandas as pd from PIL import Image from tqdm import tqdm import os 2. Definimos un atoi(s) que nos permitirá convertir strings en enteros. def atoi(s): n=0 for i in s: n = n*10 + ord(i) - ord("0") return n El método ord () devuelve un número entero que representa el punto Unicode para el carácter Unicode dado. Donde (ord (i) - ord ("0")) es una conversión ASCII simple donde ord ("0") es 47. 3. Luego creamos las carpetas test(prueba) y train(entrenamiento), donde cada una de ellas tendrán las carpetas con los nombres de las emociones que el programa reconocerá, Enfadado, Disgustado, Temeroso, Feliz, Triste, Sorprendido, Normal. outer_names = ['test','train'] inner_names = ['Enfadado', 'Disgustado', 'Temeroso', 'Feliz', 'Triste', 'Sorprendido', 'Normal'] os.makedirs('data', exist_ok=True) for outer_name in outer_names: os.makedirs(os.path.join('data',outer_name), exist_ok=True) for inner_name in inner_names: os.makedirs(os.path.join('data',outer_name,inner_name), exist_ok=True) Donde la función: - os.makedirs(), el método creará todo el directorio no disponible / faltante en la ruta especificada. - exist_ok=True, deja el directorio inalterado. - os.path.join, este método concatena varios componentes de la ruta con exactamente un separador de directorio ("/") después de cada parte no vacía, excepto el último

angry = 0 disgusted = 0 fearful = 0 happy = 0 sad = 0 surprised = 0 neutral = 0 angry_test = 0 disgusted_test = 0 fearful_test = 0 happy_test = 0 sad_test = 0 surprised_test = 0 neutral_test = 0 df = pd.read_csv('./fer2013.csv') mat = np.zeros((48,48),dtype=np.uint8) print("Saving images...") Donde: -

pd.read_csv('./fer2013.csv'),

lee

el

archivo

csv

(./fer2013.csv), donde este conjunto de datos consta de 35887 imágenes faciales en escala de grises de tamaño 48x48 con siete emociones: enojado, disgustado, temeroso, feliz, neutral, triste y sorprendido. - np.zeros(48,48),dtype=np.uint8), creamos un arreglo de tamaño 48x48 con ceros donde el tipo de dato son enteros de 8 bits. 5. Realizamos la lectura del archivo csv línea por línea. Donde la lectura corresponde a la columna pixeles del archivo csv. for i in tqdm(range(len(df))): txt = df['pixels'][i] words = txt.split() Donde: - tqdm(range(len(df))), es una biblioteca en Python que se utiliza para crear medidores de progreso o barras de progreso. Donde el rango se define de acuerdo con el tamaño de la lista de df (variable donde se almacenaron los datos del archivo csv).

- txt.split(), El método divide una cadena en una lista.

img.save('train/angry/im'+str(angry)+'.png'), permite guardar la imagen que corresponde a la emoción de la

6. Almacenamos los datos de la lista en una matriz mat,

carpeta, guardándose en la dirección de la carpeta con su respectivo nombre y formato.

for j in range(2304): xind = j // 48 yind = j % 48 mat[xind][yind] = atoi(words[j])

8. Realizamos el test. Se vuelve a realizar la misma acción que del paso anterior, pero con la carpeta del test. La diferencia radica que la opción de entrenar permite que el programa entrene guardando la imagen que se le presenta

img = Image.fromarray(mat)

con su respectiva emoción ingresada, por lo tanto, al realizar la opción de test presentará mejores resultados de interpretar

Donde:

las emociones a medida que se aumenta el entrenamiento.

-Image.fromarray(mat), toma el objeto array como entrada y devuelve el objeto imagen hecho del objeto array.

else:

7. Procedemos a entrenar. El cual consiste en pasar los archivos del csv hacia la carpeta de entrenar y clasificarlas de forma que al momento de leer se pueda determinar con mayor rapidez el tipo de emoción, donde cada carpeta de emoción le corresponde su respectiva imagen de acuerdo con esta. if i < 28709: if df['emotion'][i] == 0: img.save('train/angry/im'+str(angry)+'.png') angry += 1 elif df['emotion'][i] == 1: img.save('train/disgusted/im'+str(disgusted)+'.png') disgusted += 1 elif df['emotion'][i] == 2: img.save('train/fearful/im'+str(fearful)+'.png') fearful += 1 elif df['emotion'][i] == 3: img.save('train/happy/im'+str(happy)+'.png') happy += 1 elif df['emotion'][i] == 4: img.save('train/sad/im'+str(sad)+'.png') sad += 1 elif df['emotion'][i] == 5: img.save('train/surprised/im'+str(surprised)+'.png') surprised += 1 elif df['emotion'][i] == 6: img.save('train/neutral/im'+str(neutral)+'.png') neutral += 1 Donde:

if df['emotion'][i] == 0: img.save('test/angry/im'+str(angry_test)+'.png') angry_test += 1 elif df['emotion'][i] == 1: img.save('test/disgusted/im'+str(disgusted_test)+'.png') disgusted_test += 1 elif df['emotion'][i] == 2: img.save('test/fearful/im'+str(fearful_test)+'.png') fearful_test += 1 elif df['emotion'][i] == 3: img.save('test/happy/im'+str(happy_test)+'.png') happy_test += 1 elif df['emotion'][i] == 4: img.save('test/sad/im'+str(sad_test)+'.png') sad_test += 1 elif df['emotion'][i] == 5: img.save('test/surprised/im'+str(surprised_test)+'.png') surprised_test += 1 elif df['emotion'][i] == 6: img.save('test/neutral/im'+str(neutral_test)+'.png') neutral_test += 1 print("Done!") D. Técnica de IA Las redes neuronales artificiales: están basadas en el funcionamiento de las redes de neuronas biológicas. A nivel esquemático, una neurona artificial se representa del siguiente modo:

Al principio, sólo tenemos un conjunto de datos que contiene todo nuestro data disponible. Para entrenar nuestro modelo de Machine Learning y poder saber si está funcionando bien, se procederá a separar el conjunto de datos inicial en 2: conjunto de entrenamiento (train) y conjunto de pruebas (test). Por lo general se divide haciendo “80-20”. Y se toman muestras aleatorias -no en secuencia, si no, mezcladas. # Definimos Fig. 7 neurona artificial

En el caso de las neuronas artificiales, la suma de las entradas multiplicadas por sus pesos asociados determina el “impulso nervioso” que recibe la neurona. Este valor, se procesa en el interior de la célula mediante una función de activación que devuelve un valor que se envía como salida de la neurona. Del mismo modo que nuestro cerebro está compuesto por neuronas interconectadas entre sí, una red neuronal artificial está formada por neuronas artificiales conectadas entre sí y agrupadas en diferentes niveles que denominamos capas.

las

variables

que

usaremos como

generadores de datos. train_dir = 'data/train' val_dir = 'data/test' donde: Train-test es un método para medir la precisión de su modelo, se llama así ya que divide el conjunto de datos en dos conjuntos: un conjunto de entrenamiento y un conjunto de prueba. num_train = 28709 num_val = 7178 batch_size = 64

» Una capa es un conjunto de neuronas cuyas entradas num_epoch = 50 provienen de una capa anterior (o de los datos de entrada en el caso de la primera capa) y cuyas salidas son la donde: entrada de una capa posterior.» ● num_train: cantidad de registros para entrenar En la siguiente imagen podemos ver una red con cuatro capas:



num_val: cantidad de registros para test ●

Batch Size: este es el número de ejemplos que se introducen en la red para que entrene de cada vez. Si el número es pequeño, significa que la red tiene en memoria poca cantidad de datos, y entrena más rápido. Sin embargo, es posible que no aprenda las características

y

detalles

que

pueden

ser

significativos en la predicción. Si es grande, ocurre al contrario: es más probable que tenga en cuenta los casos más importantes a la hora de aprender,

Fig. 8 Red de 4 capas

Épocas: Cuanto menor sea la pérdida para una red, más precisa será., Se puede cuantificar el proceso de aprendizaje como la reducción del resultado de la función de pérdida. Cada ciclo de corrección de propagación hacia atrás y hacia adelante para reducir la pérdida se denomina época. En resumen, la propagación hacia atrás consiste en determinar las mejores ponderaciones y sesgos de entrada para obtener un resultado más preciso o "minimizar la pérdida".

pero entrena más lento. ●

Epoch: este es el número de veces que se van a pasar cada ejemplo de entrenamiento por la red. Es fácil caer en la tentación de pensar que un alto número de Epoch puede hacer que la red aprenda más fácil. En general, en determinado momento, el peso y el bias de cada neurona converge a un cierto valor para una Epoch concreta, y a partir de ahí

además de consumir inútilmente tiempo y energía entrenando,

corre

el

riesgo

de

producirse

Las capas que le agregaremos a nuestra red son las siguientes: capa con función Redu y con función Softmax:

overfitting. Por otro lado, un número bajo de Epoch puede provocar underfitting en la red, ya

model = Sequential()

que no aprenda lo suficiente. ➔ train_datagen = ImageDataGenerator(rescale=1./255)

model.add(Conv2D(ep32, kernel_size=(3, 3),

val_datagen =

activation='relu', input_shape=(48,48,1)))

ImageDataGenerator(rescale=1./255)

model.add(Conv2D(64, kernel_size=(3, 3),

train_generator =

activation='relu'))

train_datagen.flow_from_directory( train_dir, target_size=(48,48), batch_size=batch_size, color_mode="grayscale", class_mode='categorical')

model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Conv2D(128, kernel_size=(3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Conv2D(128, kernel_size=(3, 3),



validation_generator =

activation='relu'))

val_datagen.flow_from_directory(

model.add(MaxPooling2D(pool_size=(2, 2)))

val_dir, target_size=(48,48),

model.add(Dropout(0.25))

batch_size=batch_size,

model.add(Flatten())

color_mode="grayscale",

model.add(Dense(1024, activation='relu'))

class_mode='categorical')

model.add(Dropout(0.5))

Finalmente ponemos la características de las imágenes de

model.add(Dense(7, activation='softmax'))

las cuales entrenaremos y validamos a nuestra r...


Similar Free PDFs