Path: blob/master/site/es-419/guide/keras/rnn.ipynb
39484 views
Copyright 2020 The TensorFlow Authors.
Redes neuronales recurrentes (RNN) con Keras
Introducción
Las redes neuronales recurrentes (RNN) son una clase de redes neuronales potentes para modelar datos secuenciales, como series temporales o lenguaje natural.
En términos esquemáticos, una capa RNN utiliza un bucle for para iterar sobre los pasos de tiempo de una secuencia, mientras mantiene un estado interno que codifica la información sobre los pasos de tiempo que ha visto hasta el momento.
La API Keras RNN está diseñada con un enfoque en:
Facilidad de uso: las capas incorporadas
keras.layers.RNN,keras.layers.LSTM,keras.layers.GRUpermiten construir rápidamente modelos recurrentes sin tener que tomar decisiones difíciles sobre la configuración.Facilidad de personalización: También puede definir su propia capa de celdas RNN (la parte interna del bucle
for) con un comportamiento personalizado, y utilizarla con la capa genéricakeras.layers.RNN(el propio buclefor). Esto le permite crear rápidamente prototipos de diferentes ideas de investigación de una manera flexible con un código mínimo.
Preparación
Capas RNN integradas: un ejemplo simple
Hay tres capas RNN integradas en Keras:
keras.layers.SimpleRNN, una RNN completamente conectada en la que la salida del paso de tiempo anterior debe alimentar el siguiente paso de tiempo.keras.layers.GRU, propuesto por primera vez en Cho et al., 2014.keras.layers.LSTM, propuesto por primera vez en Hochreiter & Schmidhuber, 1997.
A principios del 2015, Keras tuvo las primeras implementaciones reutilizables de código abierto en Python de LSTM y GRU.
Este es un ejemplo sencillo de un modelo de Sequential que procesa secuencias de números enteros, incrusta cada número entero en un vector de 64 dimensiones y, a continuación, procesa la secuencia de vectores utilizando una capa LSTM.
Las RNN integradas admiten varias funciones útiles:
Abandono recurrente, mediante los argumentos
dropoutyrecurrent_dropout.Capacidad para procesar una secuencia de entrada en sentido inverso, mediante el argumento
go_backwards.Desenrollar bucles (que puede suponer un gran aumento de velocidad al procesar secuencias cortas en el CPU), mediante el argumento
unroll....y mucho más.
Para obtener más información, consulte la Documentación de la API RNN.
Salidas y estados
De forma predeterminada, la salida de una capa RNN contiene un único vector por muestra. Este vector es la salida de la célula RNN correspondiente al último paso de tiempo, que contiene información sobre toda la secuencia de entrada. La forma de esta salida es (batch_size, units) donde units corresponde al argumento units pasado al constructor de la capa.
Una capa RNN también puede devolver la secuencia completa de salidas para cada muestra (un vector por paso de tiempo por muestra), si se establece return_sequences=True. La forma de esta salida es (batch_size, timesteps, units).
Además, una capa RNN puede devolver su estados internos finales. Los estados devueltos pueden utilizarse para reanudar la ejecución de la RNN más tarde, o para inicializar otra RNN. Esta configuración se utiliza comúnmente en el modelo secuencia-a-secuencia codificador-decodificador, donde el estado final del codificador se utiliza como estado inicial del decodificador.
Para configurar una capa RNN para que devuelva su estado interno, establezca el parámetro return_state en True al crear la capa. Tenga en cuenta que LSTM tiene 2 tensores de estado, pero GRU solo tiene uno.
Para configurar el estado inicial de la capa, basta con llamar a la capa con el argumento adicional initial_state. Tenga en cuenta que la forma del estado debe coincidir con el tamaño de la unidad de la capa, como en el siguiente ejemplo.
Capas RNN y celdas RNN
Además de las capas RNN integradas, la API RNN también proporciona APIs a nivel de celda. A diferencia de las capas RNN, que procesan lotes enteros de secuencias de entrada, la celda RNN solo procesa un único paso temporal.
La celda es el interior del bucle for de una capa RNN. Al envolver una celda dentro de una capa keras.layers.RNN se obtiene una capa capaz de procesar lotes de secuencias, por ejemplo RNN(LSTMCell(10)).
Matemáticamente, RNN(LSTMCell(10)) produce el mismo resultado que LSTM(10). De hecho, la implementación de esta capa en TF v1.x era simplemente crear la celda RNN correspondiente y envolverla en una capa RNN. Sin embargo, el uso de las capas integradas GRU y LSTM permite el uso de CuDNN y se puede ver un mejor rendimiento.
Hay tres celdas RNN integradas, cada una de las cuales corresponde a la capa RNN correspondiente.
keras.layers.SimpleRNNCellcorresponde a la capaSimpleRNN.keras.layers.GRUCellcorresponde a la capaGRU.keras.layers.LSTMCellcorresponde a la capaLSTM.
La abstracción de celdas, junto con la clase genérica keras.layers.RNN, hacen que sea muy fácil implementar arquitecturas RNN personalizadas para su investigación.
Estado de los lotes cruzados
Al procesar secuencias muy largas (posiblemente infinitas), es posible que desee utilizar el patrón de estado de los lotes cruzados.
Normalmente, el estado interno de una capa RNN se restablece cada vez que ve un nuevo lote (es decir, se supone que cada muestra vista por la capa es independiente del pasado). La capa solo mantendrá un estado mientras procesa una muestra determinada.
Sin embargo, si tiene secuencias muy largas, es útil dividirlas en secuencias más cortas y alimentar estas secuencias más cortas secuencialmente en una capa RNN sin restablecer el estado de la capa. De este modo, la capa puede retener información sobre toda la secuencia, aunque solo vea una subsecuencia cada vez.
Puede hacerlo estableciendo stateful=True en el constructor.
Si tiene una secuencia s = [t0, t1, ... t1546, t1547], la dividiría, por ejemplo, en:
Entonces lo procesaría a través de:
Cuando desee borrar el estado, puede utilizar layer.reset_states().
Nota: En esta configuración, se supone que la muestra
ide un lote determinado es la continuación de la muestraidel lote anterior. Esto significa que todos los lotes deben contener el mismo número de muestras (tamaño del lote). Por ejemplo, si un lote contiene[sequence_A_from_t0_to_t100, sequence_B_from_t0_to_t100], el siguiente lote debería contener[sequence_A_from_t101_to_t200, sequence_B_from_t101_to_t200].
Este es un ejemplo completo:
Los estados registrados de la capa RNN no se incluyen en layer.weights(). Si desea reutilizar el estado de una capa RNN, puede recuperar el valor de los estados mediante layer.states y utilizarlo como estado inicial para una nueva capa mediante la API funcional de Keras como new_layer(inputs, initial_state=layer.states), o la subclase de modelos.
Tenga en cuenta también que el modelo sequential no se puede utilizar en este caso, ya que solo admite capas con una entrada y una salida, y la entrada adicional del estado inicial hace que sea imposible utilizarlo aquí.
RNNs bidireccionales
Para secuencias que no sean series temporales (por ejemplo, texto), suele ocurrir que un modelo RNN puede funcionar mejor si no solo procesa la secuencia de principio a fin, sino también hacia atrás. Por ejemplo, para predecir la siguiente palabra de una frase, suele ser útil disponer del contexto que rodea a la palabra, no únicamente de las palabras que la preceden.
Keras proporciona una API sencilla para construir RNNs bidireccionales: el envoltorio keras.layers.Bidirectional.
En este caso, Bidirectional copiará la capa RNN introducida e invertirá el campo go_backwards de la nueva capa copiada, de forma que procesará las entradas en orden inverso.
La salida de la RNN Bidirectional será, de forma predeterminada, la concatenación de la salida de la capa hacia adelante y la salida de la capa hacia atrás. Si necesita un comportamiento de fusión diferente, por ejemplo, que una concatenación, cambie el parámetro merge_mode en el constructor de la envoltura Bidirectional. Para obtener más información sobre Bidirectional, consulte la documentación de la API.
Optimización del rendimiento y kernels CuDNN
En TensorFlow 2.0, las capas LSTM y GRU incorporadas se actualizaron para aprovechar los núcleos CuDNN de forma predeterminada cuando está disponible una GPU. Con este cambio, las capas anteriores keras.layers.CuDNNLSTM/CuDNNGRU quedaron obsoletas, y podrá construir su modelo sin preocuparse por el hardware en el que se ejecutará.
Dado que el kernel CuDNN se construye con ciertas suposiciones, esto significa que la capa no podrá utilizar el kernel CuDNN si cambia los valores predeterminados de las capas incorporadas LSTM o GRU. Por ejemplo:
Cambiar la función
activationdetanha algo distinto.Cambiar la función
recurrent_activationdesigmoidea algo diferente.Usar
recurrent_dropout> 0.Establecer
unrollen True, lo que obligará a LSTM/GRU a descomponer el bucletf.while_loopinterno en un buclefordesenrollado.Establecer
use_biasen False.Utilizar el enmascaramiento cuando los datos de entrada no están estrictamente rellenados a la derecha (si la máscara corresponde a datos estrictamente rellenados a la derecha, CuDNN puede seguir utilizándose. Este es el caso más común).
Para obtener la lista detallada de restricciones, consulte la documentación de las capas LSTM y GRU.
Cómo utilizar los kernels CuDNN cuando estén disponibles
Construyamos un modelo LSTM sencillo para demostrar la diferencia de rendimiento.
Utilizaremos como secuencias de entrada la secuencia de filas de dígitos MNIST (tratando cada fila de pixeles como un paso de tiempo), y predeciremos la etiqueta del dígito.
Carguemos el conjunto de datos MNIST:
Creemos una instancia del modelo y vamos a entrenarla.
Elegimos sparse_categorical_crossentropy como función de pérdida para el modelo. La salida del modelo tiene forma de [batch_size, 10]. El objetivo para el modelo es un vector entero, cada uno de los enteros está en el rango de 0 a 9.
Ahora, comparemos con un modelo que no utiliza el kernel CuDNN:
Cuando se ejecuta en una máquina con una GPU NVIDIA y CuDNN instalada, el modelo construido con CuDNN es mucho más rápido de entrenar en comparación con el modelo que utiliza el kernel TensorFlow normal.
El mismo modelo CuDNN habilitado también se puede utilizar para ejecutar la inferencia en un entorno basado únicamente en el CPU. La anotación tf.device de abajo solo está forzando la colocación del dispositivo. El modelo se ejecutará en la CPU de forma predeterminada si no hay una GPU disponible.
Ya no tendrá que preocuparse por el hardware que utiliza. ¿No es genial?
RNNs con entradas de lista/dict, o entradas anidadas
Las estructuras anidadas permiten a los programadores incluir más información en un solo paso de tiempo. Por ejemplo, un fotograma de video podría tener entrada de audio y video al mismo tiempo. La forma de los datos en este caso podría ser:
[batch, timestep, {"video": [height, width, channel], "audio": [frequency]}]
En otro ejemplo, los datos de escritura manual podrían tener coordenadas x y y para la posición actual del bolígrafo, así como información sobre la presión. Así que la representación de los datos podría ser la siguiente:
[batch, timestep, {"location": [x, y], "pressure": [force]}]
El siguiente código proporciona un ejemplo de cómo construir una celda RNN personalizada que acepte tales entradas estructuradas.
Cómo definir una celda personalizada que admita entradas/salidas anidadas
Consulte Creación de nuevas capas y modelos mediante subclases para obtener más información sobre cómo crear sus propias capas.
Cómo construir un modelo RNN con entrada/salida anidada
Vamos a construir un modelo Keras que utilice una capa keras.layers.RNN y la celda personalizada que acabamos de definir.
Entrene el modelo con datos generados aleatoriamente
Dado que no existe un buen conjunto de datos para este modelo, utilizaremos datos aleatorios de Numpy para realizar la demostración.
Con la capa keras.layers.RNN de Keras, solo se espera que defina la lógica matemática para un paso individual dentro de la secuencia, y la capa keras.layers.RNN administrará la iteración de la secuencia por usted. Es una forma increíblemente potente de crear rápidamente prototipos de nuevos tipos de RNN (por ejemplo, una variante de LSTM).
Para obtener más información, visite los documentos de la API.
Ver en TensorFlow.org
Ejecutar en Google Colab
Ver el código fuente en GitHub
Descargar el bloc de notas