library(keras)
Warning: package 'keras' was built under R version 4.3.3
DNN: Tutorial básico de Keras
en R
Bienvenidos a la guía rápida para empezar con keras
en R para construir los primeros modelos de Deep Learning, particularmente los modelos de Perceptrón Multicapa (Multi Layer Perceptron, MLP). Keras es una API (Application Program Interface) basada en tensorflow
, diseñada para permitir una implementación rápida, fácil y modular con diferentes arquitecturas de Deep Learning.
Características clave de Keras incluyen:
Facilidad de uso: Keras tiene una API simple y coherente optimizada para casos de uso comunes, lo que facilita el entendimiento y la utilización, incluso para aquellos que son nuevos en el campo.
Modularidad: Keras está estructurada en módulos, lo que permite una configuración y expansión flexibles. Los componentes de Keras como las capas, funciones de activación, optimizadores, entre otros, son independientes y combinables.
Extensibilidad: Se puede extender fácilmente con nuevas funcionalidades como nuevos tipos de capas, funciones de pérdida, etc., lo que la hace adaptable a necesidades avanzadas.
Compatibilidad: Keras se ejecuta sobre varios frameworks de backend de computación, siendo TensorFlow el más común y recomendado. Esto significa que se puede aprovechar la potencia y flexibilidad de estos frameworks, incluyendo la capacidad de ejecución en GPU para procesamiento de alto rendimiento.
Keras se utiliza para construir y entrenar modelos de Deep Learning de manera eficiente, desde redes simples hasta complejas, con soporte para una amplia gama de arquitecturas de red. Su diseño y facilidad de uso la posiciona como una de las bibliotecas más populares en el ámbito del Deep Learning.
Esta guía está basada en la guía oficial de Keras en R (https://tensorflow.rstudio.com/guides/keras/basics).
library(keras)
Warning: package 'keras' was built under R version 4.3.3
El modelo secuencial (keras_model_sequential()
) en Keras utiliza una manera intuitiva para construir un modelo de red neuronal. Esencialmente, es un conjunto de capas apilado de manera lineal, es decir, que el modelo se va creando capa por capa de manera secuencial. Este tipo de modelo es muy útil cuando se tiene una cadena simple de capas, donde cada capa tiene exactamente un tensor de entrada y un tensor de salida.
Inicialización: Comenzamos inicializando el modelo Sequential. Esto es como preparar un contenedor vacío donde se irán añadiendo capas para nuestro modelo.
Añadir Capas: Luego, añadimos las capas al modelo. Keras proporciona una variedad de capas que se pueden añadir, como capas dense
(fully connected, i.e. MLP), capas de convolución, capas recurrentes, etc. Cada capa se va apilando sobre la anterior. Usaremos un modelo con dos capas ocultas, la primera y segunda capa oculta del modelo utilizarán una función de activación relu
y luego la capa de salida tendrá una activación de tipo softmax
.
<- keras_model_sequential()
model
%>%
model # Agrega la primer capa al modelo y establece la forma que tendrá la capa de entrada
layer_dense(units = 64, activation = 'relu', input_shape = c(32)) %>%
# Agrega otra capa:
layer_dense(units = 64, activation = 'relu') %>%
# Agrega la capa de salida (10 nodos) con la función 'softmax':
layer_dense(units = 10, activation = 'softmax')
Acá vemos algunas de las opciones que presenta la librería, las opciones consideran la función de activación, el inicializador para el kernel y algunas opciones de regularización:
activation
: Establece la función de activación para cada una de las capas.
kernel_initializer
y bias_initializer
: Los esquemas de inicialización que darán el punto de partida a los pesos de cada capa (kernel y bias). Por defecto, se utiliza el inicializador uniforme de Glorot.
kernel_regularizer
y bias_regularizer
: Los esquemas de regularización que se aplicarán a los pesos de cada capa (kernel and bias), como regularización en L1 o L2, o ambas. Por defecto no se aplica ningún método de regularización.
Ejemplos
# Creamos una capa con activación sigmoide:
layer_dense(units = 64, activation ='sigmoid')
# Una capa con regularización en L1 para el kernel y un factor de 0.01
layer_dense(units = 64, kernel_regularizer = regularizer_l1(0.01))
# Una capa con regularización en L2 para el bias y un factor de 0.01
layer_dense(units = 64, bias_regularizer = regularizer_l2(0.01))
# Una capa con inicialización de pesos en el kernel utilizando una matriz aleatoria ortogonal
layer_dense(units = 64, kernel_initializer = 'orthogonal')
# Una capa inicialización del vector bias en 2.0
layer_dense(units = 64, bias_initializer = initializer_constant(2.0))
Una vez se han añadido todas las capas necesarias, el siguiente paso es compilar el modelo. Aquí es donde se define la función de pérdida que el modelo tratará de minimizar, el optimizador que determina cómo el modelo actualizará los parámetros durante el entrenamiento, y las métricas de evaluación que queremos observar. Por ejemplo, para un problema de clasificación, se podría usar la función de pérdida de entropía cruzada categórica categorical_crossentropy
y el optimizador adam
.
%>% compile(
model optimizer = 'adam',
loss = 'categorical_crossentropy',
metrics = list('accuracy')
)
La función compile
toma tres argumentos importantes que se deben configurar adecuadamente, dependiendo de si el modelo se utiliza para tareas de clasificación o de regresión:
adam
para una amplia gama de aplicaciones, rmsprop
recomendado para redes recurrentes, y sgd
(descenso de gradiente estocástico) que es útil en contextos específicos y cuando se necesita un control más detallado sobre el entrenamiento.
adam
, rmsprop
, sgd
.categorical_crossentropy
para clasificación multiclase, binary_crossentropy
para clasificación binaria.mean_squared_error
(mse) para medir el promedio de los errores al cuadrado entre los valores predichos y reales, mean_absolute_error
(mae) para la diferencia media absoluta.accuracy
es comúnmente usada para evaluar la proporción de aciertos.mean_squared_error
o mse
para el error cuadrático medio, mean_absolute_error
o mae
para el error absoluto medio. pueden ser usadas para evaluar cuán cerca están las predicciones del modelo de los valores reales.Ejemplos de configuración del modelo:
# Configura un modelo para regresión
%>% compile(
model optimizer = 'adam',
loss = 'mse', # mean squared error
metrics = list('mae') # mean absolute error
)
# Configura un modelo para clasificación
%>% compile(
model optimizer = optimizer_rmsprop(learning_rate = 0.01),
loss = "categorical_crossentropy",
metrics = list("categorical_accuracy")
)
Se pueden entrenar modelos de Keras directamente en matrices y arreglos de R (que posiblemente se hayan creado a partir de data.frames
de R). Un modelo se ajusta a los datos de entrenamiento utilizando el método fit
. Las variables data
y labels
son matrices con elementos que siguen una distribución de probabilidad normal estándar.
#Datos de entrenamiento simulados
<- matrix(rnorm(1000 * 32), nrow = 1000, ncol = 32)
data <- matrix(rnorm(1000 * 10), nrow = 1000, ncol = 10)
labels
#Datos de prueba simulados
<- matrix(rnorm(300 * 32), nrow = 300, ncol = 32)
test_data <- matrix(rnorm(300 * 10), nrow = 300, ncol = 10)
test_labels
%>% fit(
model
data,
labels,epochs = 10,
batch_size = 32
)
Epoch 1/10
32/32 - 1s - loss: -2.0688e-01 - accuracy: 0.0960 - 675ms/epoch - 21ms/step
Epoch 2/10
32/32 - 0s - loss: -4.4227e-01 - accuracy: 0.1120 - 41ms/epoch - 1ms/step
Epoch 3/10
32/32 - 0s - loss: -6.3738e-01 - accuracy: 0.1200 - 29ms/epoch - 921us/step
Epoch 4/10
32/32 - 0s - loss: -8.5355e-01 - accuracy: 0.1360 - 34ms/epoch - 1ms/step
Epoch 5/10
32/32 - 0s - loss: -1.0190e+00 - accuracy: 0.1400 - 25ms/epoch - 780us/step
Epoch 6/10
32/32 - 0s - loss: -1.2954e+00 - accuracy: 0.1500 - 17ms/epoch - 537us/step
Epoch 7/10
32/32 - 0s - loss: -1.5062e+00 - accuracy: 0.1510 - 30ms/epoch - 932us/step
Epoch 8/10
32/32 - 0s - loss: -1.6185e+00 - accuracy: 0.1530 - 30ms/epoch - 925us/step
Epoch 9/10
32/32 - 0s - loss: -1.8616e+00 - accuracy: 0.1500 - 23ms/epoch - 727us/step
Epoch 10/10
32/32 - 0s - loss: -2.2438e+00 - accuracy: 0.1540 - 20ms/epoch - 624us/step
El método fit
toma tres argumentos importantes:
epochs: El entrenamiento se estructura en épocas. Una época es una iteración sobre todo el conjunto de datos de entrada.
batch_size: Cuando se pasan datos en forma de matriz o arreglo, el modelo divide los datos en conjuntos más pequeños e itera sobre estos estos conjuntos durante el entrenamiento. Este entero especifica el tamaño de cada lote. Es importante tener en cuenta que el último lote puede ser más pequeño si el número total de muestras no es divisible por el tamaño del lote.
validation_data: Al prototipar un modelo, es útil monitorear fácilmente su rendimiento en algunos datos de validación. Pasar este argumento —una lista de entradas y etiquetas— permite al modelo mostrar la pérdida y métricas en modo de inferencia para los datos pasados, al final de cada época.
Aquí se presenta un ejemplo utilizando validation_data
, donde creamos un set de datos adicional. Otra opción es utilizar validation_split()
, donde extraerá un subconjunto de datos del entrenamiento (tanto en los inputs X como en las etiquetas Y) para efectuar la validación:
<- matrix(rnorm(1000 * 32), nrow = 1000, ncol = 32)
data <- matrix(rnorm(1000 * 10), nrow = 1000, ncol = 10)
labels
<- matrix(rnorm(100 * 32), nrow = 100, ncol = 32)
val_data <- matrix(rnorm(100 * 10), nrow = 100, ncol = 10)
val_labels
%>% fit(
model
data,
labels,epochs = 10,
batch_size = 32,
validation_data = list(val_data, val_labels)
)
Epoch 1/10
32/32 - 0s - loss: 0.2927 - accuracy: 0.0930 - val_loss: -1.9791e+00 - val_accuracy: 0.1100 - 256ms/epoch - 8ms/step
Epoch 2/10
32/32 - 0s - loss: 0.0823 - accuracy: 0.1010 - val_loss: -1.4662e+00 - val_accuracy: 0.1000 - 54ms/epoch - 2ms/step
Epoch 3/10
32/32 - 0s - loss: -6.3662e-01 - accuracy: 0.0870 - val_loss: -1.1032e+00 - val_accuracy: 0.1300 - 46ms/epoch - 1ms/step
Epoch 4/10
32/32 - 0s - loss: -3.4476e-01 - accuracy: 0.1080 - val_loss: -1.4138e+00 - val_accuracy: 0.0900 - 61ms/epoch - 2ms/step
Epoch 5/10
32/32 - 0s - loss: -7.1458e-01 - accuracy: 0.1000 - val_loss: -2.6395e+00 - val_accuracy: 0.1300 - 42ms/epoch - 1ms/step
Epoch 6/10
32/32 - 0s - loss: -8.3069e-01 - accuracy: 0.1020 - val_loss: -1.3383e+00 - val_accuracy: 0.1500 - 50ms/epoch - 2ms/step
Epoch 7/10
32/32 - 0s - loss: -1.7367e+00 - accuracy: 0.1090 - val_loss: -7.6512e-01 - val_accuracy: 0.1000 - 40ms/epoch - 1ms/step
Epoch 8/10
32/32 - 0s - loss: -1.4613e+00 - accuracy: 0.1020 - val_loss: -1.9789e+00 - val_accuracy: 0.1400 - 50ms/epoch - 2ms/step
Epoch 9/10
32/32 - 0s - loss: -1.1939e+00 - accuracy: 0.1180 - val_loss: -1.7426e+00 - val_accuracy: 0.0900 - 44ms/epoch - 1ms/step
Epoch 10/10
32/32 - 0s - loss: -1.5717e+00 - accuracy: 0.1080 - val_loss: -1.4803e+00 - val_accuracy: 0.1000 - 47ms/epoch - 1ms/step
Para evaluar la función de pérdida y las métricas establecidas usamos evaluate
. Se puede utilizar tanto para el conjunto de entrenamiento como para el de prueba:
%>% evaluate(test_data, test_labels, batch_size = 32) model
10/10 - 0s - loss: -4.5548e-01 - accuracy: 0.1300 - 15ms/epoch - 2ms/step
loss accuracy
-0.4554779 0.1300000
Y para predecir la salida de la última capa en el conjunto de prueba (pero también se puede hacer para el entrenamiento):
%>% predict(test_data, batch_size = 32) %>% head() model
10/10 - 0s - 65ms/epoch - 7ms/step
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 0.195472911 0.020692170 0.11873411 0.090526842 0.04747483 0.063484013
[2,] 0.246287227 0.066558935 0.11277572 0.012254063 0.12813528 0.072297566
[3,] 0.057932884 0.003986907 0.09824687 0.002683881 0.77617496 0.002414052
[4,] 0.007556915 0.027510762 0.49224505 0.003122625 0.23085147 0.077297240
[5,] 0.037863251 0.012916965 0.20119390 0.041215729 0.20616631 0.122328557
[6,] 0.028843455 0.013159634 0.01308275 0.001210736 0.26774430 0.101673916
[,7] [,8] [,9] [,10]
[1,] 0.12658481 0.046494108 4.522344e-02 0.245312676
[2,] 0.09047966 0.005971425 4.420675e-02 0.221033350
[3,] 0.04951634 0.000399508 1.568512e-04 0.008487809
[4,] 0.03028112 0.009660723 9.086001e-05 0.121383168
[5,] 0.31157717 0.056666274 1.159394e-03 0.008912438
[6,] 0.03464352 0.018494736 1.734982e-02 0.503797114
Un callback es un objeto que se pasa a un modelo para personalizar y extender su comportamiento durante el entrenamiento. Se puede escribir un callback personalizado o utilizar los callbacks integrados en Keras (más detalles en este enlace de R-CRAN, que incluyen:
callback_model_checkpoint
: Guarda puntos de control del modelo a intervalos regulares.callback_learning_rate_scheduler
: Cambia dinámicamente la tasa de aprendizaje.callback_early_stopping
: Interrumpe el entrenamiento cuando el rendimiento en la validación ha dejado de mejorar.Para usar un callback
, se añade en la función fit
:
<- list(
callbacks callback_early_stopping(patience = 2, monitor = 'val_loss'),
callback_tensorboard(log_dir = './logs')
)
%>% fit(
model
data,
labels,batch_size = 32,
epochs = 5,
callbacks = callbacks,
validation_data = list(val_data, val_labels)
)
Se pueden guardar y cargar los pesos asociados a algún modelo
# Guardar los pesos del modelo
%>% save_model_weights_tf('ruta_al_archivo/')
model
# Cargar los pesos del modelo
%>% load_model_weights_tf('ruta_al_archivo/') model
También se puede guardar y cargar un modelo completo, sin necesidad de ejecutar el código nuevamente.
# Guardar modelo completo, en formato SavedModel
%>% save_model_tf('ruta_al_archivo/')
model
# Cargar modelo completo, incluidos pesos y optimizador en formato SavedModel
<- load_model_tf('ruta_al_archivo/') model
Espero esta guía sea de utilidad para poder comenzar a implementar los primeros modelos de Deep Learning.