Blog
Cómo desarrollar modelos de Deep Learning con Keras
- Publicado por: Rafael Fernandez
- Categoría: Natural Language Processing
Las redes neuronales de aprendizaje profundo son muy fáciles de crear y evaluar en Python con Keras. En este capítulo descubrirá el ciclo paso a paso para crear, entrenar y evaluar redes neuronales de aprendizaje profundo en Keras y cómo hacer predicciones con un modelo entrenado. También descubrirá cómo utilizar la API funcional que proporciona más flexibilidad a la hora de diseñar modelos. Después de leer este capítulo sabrá:
- Cómo definir, compilar, ajustar y evaluar una red neuronal de aprendizaje profundo en Keras.
- Cómo seleccionar valores predeterminados estándar para problemas de modelos predictivos de regresión y clasificación.
- Cómo utilizar los Perceptrones multicapa estándar, Redes Neuronales Convolucionales y Recurrentes.
Se asume que el lector tiene una familiaridad básica con Deep Learning en Keras, este capítulo debería proporcionar una actualización de la API de Keras. La mayoría de los fragmentos de código en este tutorial son sólo de referencias y no son ejemplos completos. Para un ejemplo completo le recomendamos el post: Cómo hacer tu Primera Red Neural en Python con Keras Paso a Paso
Keras Model Life-Cycle
A continuación se presenta una visión general de los 5 pasos del ciclo de vida del modelo de red neuronal en Keras:
- Definir grafo.
- Compilar red.
- Ajustar red.
- Evaluar la red.
- Haga predicciones.
Paso 1: Definir el grafo
El primer paso es definir su red neuronal. Las redes neuronales se definen en Keras como una secuencia de capas. El contenedor para estas capas es la clase Sequencial. El primer paso es crear una instancia de la clase Sequential. Luego puede crear sus capas y añadirlas en el orden en que deberían estar conectadas. Por ejemplo, podemos hacerlo en dos pasos:
model = Sequential() model.add(Dense(2))
Pero también podemos hacer esto en un solo paso creando una matriz de capas y pasándosela al constructor de la clase Sequential.
layers = [Dense(2)] model = Sequential(layers)
La primera capa de la red debe definir el número de entradas a esperar. La forma en que se especifica esto puede diferir dependiendo del tipo de red, pero para un modelo de Perceptron multicapa esto se especifica mediante el atributo input_dim. Por ejemplo, un pequeño modelo de Perceptron multicapa con 2 entradas en la capa visible, 5 neuronas en la capa oculta y una neurona en la capa de salida se puede definir como:
model = Sequential() model.add(Dense(5, input_dim=2)) model.add(Dense(1))
Piense en un modelo secuencial como una tubería con sus datos brutos introducidos en la parte inferior y las predicciones que salen en la parte superior. Esta es una concepción útil en Keras, ya que las preocupaciones que tradicionalmente se asociaban con una capa también pueden dividirse y añadirse como capas separadas, mostrando claramente su papel en la transformación de los datos de entrada a predicción. Por ejemplo, las funciones de activación que transforman una señal sumada de cada neurona en una capa, pueden ser extraídas y añadidas a la Sequencial como un objeto similar a una capa llamado la clase Activation.
model = Sequential() model.add(Dense(5, input_dim=2)) model.add(Activation('relu')) model.add(Dense(1)) model.add(Activation('sigmoid'))
La elección de la función de activación es más importante para la capa de salida, ya que definirá el formato que tendrán las predicciones. Por ejemplo, a continuación se muestran algunos tipos de problemas comunes de modelado predictivo y la estructura y función de activación estándar que se pueden utilizar en la capa de salida:
- Regresión: Función de activación lineal, o linear, y el número de neuronas que coinciden con el número de salidas.
- Clasificación binaria (2 clases): Función de activación logística, o sigmoide, y una neurona en la capa de salida.
- Clasificación multiclase (>2 clase): Función de activación Softmax, o softmax, y una neurona de salida por valor de clase, asumiendo un patrón de salida con codificado en caliente (hot enconding).
Paso 2. Compilar Red
Una vez definida nuestra red, debemos compilarla. Transforma la simple secuencia de capas que definimos en una serie de matrices altamente eficientes en un formato destinado a ser ejecutado en su GPU o CPU, dependiendo de cómo esté configurado Keras. Piense en la compilación como un paso previo al cálculo para su red. Siempre es necesario después de definir un modelo.
La compilación requiere que se especifiquen una serie de parámetros, adaptados específicamente a la formación de su red. Específicamente, el algoritmo de optimización a utilizar para entrenar la red y la función de pérdida utilizada para evaluar la red que es minimizada por el algoritmo de optimización. Por ejemplo, a continuación se presenta un caso de compilación de un modelo definido y especificación del algoritmo de optimización de descenso de gradiente estocástico (sgd) y la función de pérdida de error medio cuadrado (mean_squared_error), destinado a un problema de tipo regresivo.
model.compile(optimizer='sgd', loss='mean_squared_error')
Alternativamente, el optimizador puede ser creado y configurado antes de ser proporcionado como argumento para el paso de compilación.
algorithm = SGD(lr=0.1, momentum=0.3) model.compile(optimizer=algorithm, loss='mean_squared_error')
El tipo de problema de modelado predictivo impone restricciones al tipo de función de pérdida que se puede utilizar. Por ejemplo, a continuación se presentan algunas funciones de pérdida estándar para diferentes tipos de modelos predictivos:
- Regresión: Mean Squared Error o mean_squared_error.
- Clasificación binaria (2 clases): Pérdida Logarítmica, también llamada entropía cruzada o binario_crossentropía.
- Clasificación multiclase (>2 clase): Pérdida logarítmica multiclase o cruces_clásicos.
El algoritmo de optimización más común es el descenso de gradiente estocástico, pero Keras también soporta un conjunto de otros algoritmos de optimización de última generación que funcionan bien con poca o ninguna configuración. Tal vez los algoritmos de optimización más utilizados debido a su mejor rendimiento en general son:
- Descenso de Gradiente Estocástico, o sgd, que requiere la configuración de una velocidad de aprendizaje e impulso.
- Adam, o Adam, que requiere la configuración del ritmo de aprendizaje.
- RMSprop, o rmsprop, que requiere la configuración de la velocidad de aprendizaje.
Por último, también puede especificar las métricas que desea recopilar al ajustar el modelo, además de la función de pérdida. Por lo general, la métrica adicional más útil para recopilar es la precisión de los problemas de clasificación. Las métricas a recoger se especifican por nombre en una matriz. Por ejemplo:
model.compile(optimizer='sgd', loss='mean_squared_error', metrics=['accuracy'])
Paso 3: Ajustar la red
Una vez compilada la red, se puede ajustar, lo que significa adaptar los pesos a un conjunto de datos de formación. El ajuste de la red requiere que se especifiquen los datos de formación, tanto una matriz de patrones de entrada, X, como una matriz de patrones de salida coincidentes. La red se forma utilizando el algoritmo de retropropagación y se optimiza de acuerdo con el algoritmo de optimización y la función de pérdida especificados al compilar el modelo.
El algoritmo de retropropagación requiere que la red sea entrenada para un número específico de épocas o exposiciones al conjunto de datos de entrenamiento. Cada época puede dividirse en grupos de pares de patrones input-output llamados lotes. Define el número de patrones a los que se expone la red antes de que se actualicen las ponderaciones dentro de una época. También es una optimización de la eficiencia, asegurando que no se carguen demasiados patrones de entrada en la memoria a la vez. Un ejemplo mínimo de instalación de una red es el siguiente:
history = model.fit(X, y, batch_size=10, epochs=100)
Una vez en forma, se devuelve un objeto de historial que proporciona un resumen del rendimiento del modelo durante el entrenamiento. Esto incluye tanto la pérdida como cualquier métrica adicional especificada al compilar el modelo, registrada en cada época. La formación puede llevar mucho tiempo, de segundos a horas o días, dependiendo del tamaño de la red y del tamaño de los datos de formación.
De forma predeterminada, se muestra una barra de progreso en la línea de comandos para cada época. Esto puede crear demasiado ruido para usted, o puede causar problemas para su entorno, como si está en un portátil interactivo o IDE. Puede reducir la cantidad de información mostrada sólo a la pérdida de cada época fijando el argumento verbose en 2. Puede desactivar toda la salida fijando verbose en 0. Por ejemplo:
history = model.fit(X, y, batch_size=10, epochs=100, verbose=0)
Paso 4. Evaluar la red
Una vez que la red es entrenada, puede ser evaluada. La red puede evaluarse a partir de los datos de formación, pero esto no proporcionará una indicación útil del rendimiento de la red como modelo predictivo ya que ha visto todos estos datos anteriormente. Podemos evaluar el rendimiento de la red en un conjunto de datos separado, no visto durante las pruebas. Esto proporcionará una estimación del rendimiento de la red a la hora de hacer predicciones de datos no vistos en el futuro.
El modelo evalúa la pérdida a través de todos los patrones de prueba, así como cualquier otra métrica especificada cuando se compiló el modelo, como la precisión de clasificación. Se devuelve una lista de métricas de evaluación. Por ejemplo, para un modelo compilado con la métrica de precisión, podríamos evaluarlo en un nuevo conjunto de datos de la siguiente manera:
loss, accuracy = model.evaluate(X, y)
Al igual que en el caso de la adaptación de la red, se proporciona una salida detallada para dar una idea del progreso de la evaluación del modelo. Podemos desactivarlo poniendo el argumento verbose a 0.
loss, accuracy = model.evaluate(X, y, verbose=0)
Paso 5. Haga predicciones
Una vez que estemos satisfechos con el rendimiento de nuestro modelo de ajuste, podemos usarlo para hacer predicciones sobre nuevos datos. Esto es tan fácil como llamar a la función predict() en el modelo con una serie de nuevos patrones de entrada. Por ejemplo:
predictions = model.predict(X)
Las predicciones se devolverán en el formato proporcionado por la capa de salida de la red. En el caso de un problema de regresión, estas predicciones pueden estar en el formato del problema directamente, proporcionado por una función de activación lineal. Para un problema de clasificación binaria, las predicciones pueden ser un conjunto de probabilidades para la primera clase que pueden ser convertidas a 1 o 0 por redondeo.
Para un problema de clasificación multiclase, los resultados pueden ser en forma de una matriz de probabilidades (asumiendo una variable de salida codificada en caliente) que puede necesitar ser convertida a una predicción de salida de clase única usando la función argmax() de NumPy. Alternativamente, para problemas de clasificación, podemos usar la función predict_classes() que convertirá automáticamente predicciones no nítidas en valores de clases enteras.
predictions = model.predict_classes(X)
Al igual que con el ajuste y la evaluación de la red, se proporciona una salida verbose para dar una idea del progreso del modelo haciendo predicciones. Podemos desactivarlo poniendo el argumento verbose a 0.
predictions = model.predict(X, verbose=0)
Modelos Funcionales Keras
La API secuencial le permite crear modelos capa por capa para la mayoría de los problemas. Es limitado en el sentido de que no permite crear modelos que compartan capas o tengan múltiples entradas o salidas. La API funcional en Keras es una forma alternativa de crear modelos que ofrece mucha más flexibilidad, incluyendo la creación de modelos más complejos.
Específicamente le permite definir múltiples modelos de entrada o salida, así como modelos que comparten capas. Además, permite definir gráficos de red acíclicos ad hoc. Los modelos se definen creando instancias de capas y conectándolas directamente entre sí en pares, y luego definiendo un Modelo que especifica las capas que actuarán como entrada y salida del modelo. Veamos los tres aspectos únicos de la API funcional de Keras:
Definición de entrada
A diferencia del modelo secuencial, debe crear y definir una capa de Input independiente que especifique la forma de los datos de entrada. La capa de entrada toma un argumento de forma que es una tupla que indica la dimensionalidad de los datos de entrada. Cuando los datos de entrada son unidimensionales, como en el caso de un Perceptrón multicapa, la forma debe dejar espacio explícitamente para la forma del tamaño del mini-batch (mini lote) utilizado al dividir los datos cuando se entrena la red. Por lo tanto, la forma de la tupla siempre se define con una última dimensión colgante (2,), así es como se debe definir una tupla unidimensional en Python, por ejemplo:
from keras.layers import Input visible = Input(shape=(2,))
Conexión de capas
Las capas del modelo se conectan por parejas. Esto se hace especificando de dónde viene la entrada cuando se define cada nueva capa. Se utiliza un corchete o notación funcional, de modo que después de crear la capa, se especifica la capa de la que procede la entrada a la capa actual. Aclaremos esto con un breve ejemplo. Podemos crear la capa de entrada como en el ejemplo anterior, luego crear una capa oculta como un Dense que recibe entrada sólo de la capa de entrada.
from keras.layers import Input from keras.layers import Dense visible = Input(shape=(2,)) hidden = Dense(2)(visible)
Tenga en cuenta que es el visible después de la creación de la capa Dense que conecta la salida de la capa de entrada como la entrada a la capa oculta Dense. Es esta forma de conectar las capas pieza por pieza la que da flexibilidad a la API funcional. Por ejemplo, puede ver lo fácil que sería empezar a definir gráficos ad hoc de capas
Creación del modelo
Después de crear todas las capas del modelo y conectarlas entre sí, debe definir el modelo. Al igual que con la API secuencial, el modelo es lo que puede resumir, ajustar, evaluar y usar para hacer predicciones. Keras proporciona una clase Model que puede utilizar para crear un modelo a partir de las capas creadas. Requiere que sólo se especifiquen las capas de entrada y de salida. Por ejemplo:
from keras.models import Model from keras.layers import Input from keras.layers import Dense visible = Input(shape=(2,)) hidden = Dense(2)(visible) model = Model(inputs=visible, outputs=hidden)
Ahora que conocemos todas las piezas claves de la API funcional de Keras, trabajemos definiendo un conjunto de modelos diferentes y hagamos un poco de práctica con él. Cada ejemplo es ejecutable e imprime la estructura y crea un diagrama del gráfico. Recomiendo hacer esto para sus propios modelos para dejar claro qué es exactamente lo que ha definido. Espero que estos ejemplos le proporcionen plantillas cuando desee definir sus propios modelos utilizando la API funcional en el futuro.
Modelos de red estándar
Al comenzar con la API funcional, es una buena idea ver cómo se definen algunos modelos de redes neuronales estándar. En esta sección, analizaremos la definición de una red simple de percepción multicapa, una red neuronal convolucional y una red neuronal recurrente. Estos ejemplos proporcionarán una base para entender los ejemplos más elaborados más adelante.
Perceptrón multicapa
En esta sección definimos un modelo de Perceptron multicapa para la clasificación binaria. El modelo tiene 10 entradas, 3 capas ocultas con 10, 20 y 10 neuronas, y una capa de salida con solo 1 salida. Las funciones de activación lineal rectificada se utilizan en cada capa oculta y una función de activación sigmoide se utiliza en la capa de salida, para la clasificación binaria.
# Perceptrón multicapa from keras.utils import plot_model from keras.models import Model from keras.layers import Input from keras.layers import Dense visible = Input(shape=(10,)) hidden1 = Dense(10, activation='relu')(visible) hidden2 = Dense(20, activation='relu')(hidden1) hidden3 = Dense(10, activation='relu')(hidden2) output = Dense(1, activation='sigmoid')(hidden3) model = Model(inputs=visible, outputs=output) # resumir capas model.summary() # gráfico de trazado plot_model(model, to_file='Perceptron_multicapa_grafica.png')
Ejecutando el ejemplo se imprime la estructura de la red.
_________________________________________________________________ Capa (tipo) Forma de salida Parámetro # ================================================================= input_1 (InputLayer) (None, 10) 0 _________________________________________________________________ dense_1 (Dense) (None, 10) 110 _________________________________________________________________ dense_2 (Dense) (None, 20) 220 _________________________________________________________________ dense_3 (Dense) (None, 10) 210 _________________________________________________________________ dense_4 (Dense) (None, 1) 11 ================================================================= Parámetros totales: 551 Parámetros entrenables: 551 Parámetros no entrenables: 0 ________________________
También se crea un gráfico del modelo y se guarda en un archivo png.
para crear gráficas de modelos de Keras es necesario instalar pydot y pygraphviz (la librería graphviz y la envoltura python). Las instrucciones para instalar estas bibliotecas varían según el sistema que usted tenga. Para instalar pydot y pygraphviz en anaconda visitar este post.
Red Neuronal Convolucional
En esta sección, definiremos una red neuronal convolucional para la clasificación de imágenes. El modelo recibe imágenes en blanco y negro de 64 x 64 como entrada, luego tiene una secuencia de dos capas convolucionales y de agrupamiento como extractores de características, seguidas de una capa completamente conectada para interpretar las características y una capa de salida con activación sigmoide para predicciones de dos clases.
# Red Neuronal Convolucional from keras.utils import plot_model from keras.models import Model from keras.layers import Input from keras.layers import Dense from keras.layers.convolutional import Conv2D from keras.layers.pooling import MaxPooling2D visible = Input(shape=(64,64,1)) conv1 = Conv2D(32, kernel_size=4, activation='relu')(visible) pool1 = MaxPooling2D(pool_size=(2, 2))(conv1) conv2 = Conv2D(16, kernel_size=4, activation='relu')(pool1) pool2 = MaxPooling2D(pool_size=(2, 2))(conv2) hidden1 = Dense(10, activation='relu')(pool2) output = Dense(1, activation='sigmoid')(hidden1) model = Model(inputs=visible, outputs=output) # resumir capas model.summary() # gráfico de trazado plot_model(model, to_file='Red_Neuronal_Convolucional.png')
Al ejecutar el ejemplo se resumen las capas del modelo, se vería así.
_________________________________________________________________ Capa (tipo) Forma de salida Parámetro # ================================================================= input_1 (InputLayer) (None, 64, 64, 1) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 61, 61, 32) 544 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 30, 30, 32) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 27, 27, 16) 8208 _________________________________________________________________ max_pooling2d_2 (MaxPooling2 (None, 13, 13, 16) 0 _________________________________________________________________ dense_1 (Dense) (None, 13, 13, 10) 170 _________________________________________________________________ dense_2 (Dense) (None, 13, 13, 1) 11 ================================================================= Total de parámetros: 8.933 Parámetros entrenables: 8,933 Parámetros no entrenables: 0 ____________________________
También se crea un gráfico del modelo y se guarda en un archivo.
Red Neural Recurrente
# Red Neural Recurrente from keras.utils import plot_model from keras.models import Model from keras.layers import Input from keras.layers import Dense from keras.layers.recurrent import LSTM visible = Input(shape=(100,1)) hidden1 = LSTM(10)(visible) hidden2 = Dense(10, activation='relu')(hidden1) output = Dense(1, activation='sigmoid')(hidden2) model = Model(inputs=visible, outputs=output) # resumir capas model.summary() # gráfico de trazado plot_model(model, to_file='Red_Neural_Recurrente.png')
_________________________________________________________________ Capa (tipo) Forma de salida Parámetro # ================================================================= input_1 (InputLayer) (None, 100, 1) 0 _________________________________________________________________ lstm_1 (LSTM) (None, 10) 480 _________________________________________________________________ dense_1 (Dense) (None, 10) 110 _________________________________________________________________ dense_2 (Dense) (None, 1) 11 ================================================================= Parámetros totales: 601 Parámetros entrenables: 601 Parámetros no entrenables: 0 _________________________________________________________________
➡ Aprende mucho mas en nuestro curso: