[Pytorch Framework] 2.5 Red neuronal recurrente

import torch
torch.__version__
'1.4.0'

2.5 Red neuronal recurrente

2.5.1 Introducción a RNN

Una de las características más importantes que distingue a nuestro cerebro de las máquinas es que tenemos recuerdos y podemos deducir asuntos desconocidos basados ​​en nuestros propios recuerdos. Nuestros pensamientos son persistentes. Sin embargo, los elementos de la estructura de la red neuronal que se presentan actualmente en este tutorial son independientes entre sí, y la entrada y la salida son independientes.

La causa de RNN

En el mundo real, muchos elementos están conectados entre sí. Por ejemplo, la temperatura exterior cambia periódicamente con el cambio climático, y nuestro lenguaje también necesita confirmar el significado expresado a través del contexto. Pero es bastante difícil para la máquina realizar este paso. Por tanto, existe la actual red neuronal cíclica, cuya esencia es: tiene la capacidad de recordar y hará inferencias a partir del contenido de estos recuerdos. Por lo tanto, su salida depende de la entrada y la memoria actuales.

¿Por qué necesitamos RNN?

La idea detrás de RNN es utilizar información secuencial. En las redes neuronales tradicionales, asumimos que todas las entradas (y salidas) son independientes entre sí. Si desea predecir la siguiente palabra en una oración, debe saber qué palabras están delante de ella y debe ver las siguientes palabras para poder dar la respuesta correcta.
Los RNN se denominan bucles porque realizan la misma tarea en cada elemento de la secuencia y todas las salidas dependen de cálculos previos.
Desde otra perspectiva, RNN tiene "memoria" y puede capturar la información calculada hasta el momento. En teoría, los RNN pueden usar información en secuencias arbitrariamente largas, pero en la práctica se limitan a revisar unos pocos pasos.
La propuesta de la red neuronal cíclica se basa en la idea del modelo de memoria. Se espera que la red pueda recordar las características que aparecieron antes e inferir los resultados posteriores en función de las características, y la estructura general de la red sigue circulando. debido al nombre de red neuronal cíclica.

¿Qué puede hacer RNN?

RNN ha logrado un gran éxito en muchas tareas de PNL. En este punto, debo mencionar que el tipo de RNN más comúnmente utilizado es LSTM, que es mucho mejor que RNN para capturar dependencias a largo plazo. Pero no se preocupe, LSTM es básicamente el mismo que el RNN que desarrollaremos en este tutorial, solo usan una forma diferente de calcular el estado oculto. Presentaremos LSTM con más detalle más adelante. Los siguientes son algunos ejemplos de RNN en PNL:
modelado de lenguaje y generación de texto

A través del modelado del lenguaje, podemos generar textos falsos y reales que los humanos pueden entender a partir de palabras dadas.

máquina traductora

La traducción automática es similar al modelado de idiomas: ingresamos una serie de palabras en el idioma de origen y, a través del cálculo del modelo, podemos generar el contenido correspondiente al idioma de destino.

Reconocimiento de voz

Dada la secuencia de entrada de señales acústicas de ondas sonoras, podemos predecir una serie de fragmentos de voz y sus probabilidades, y convertir la voz en texto.

Generar descripción de imagen

Junto con las redes neuronales convolucionales, RNN puede generar descripciones de imágenes sin etiquetar.

2.5.2 Estructura y principio de la red RNN

RNN

La estructura básica de la red neuronal cíclica es particularmente simple, es decir, la salida de la red se almacena en una unidad de memoria y esta unidad de memoria ingresa a la red neuronal junto con la siguiente entrada. Podemos ver que la red se combinará con la unidad de memoria como entrada cuando se ingrese. La red no solo emite el resultado, sino que también guarda el resultado en la unidad de memoria. La siguiente figura es un diagrama esquemático del método neuronal recurrente más simple. red cuando se ingresa. Fuente de imagen

RNN puede verse como múltiples asignaciones de la misma red neuronal. Cada módulo de red neuronal pasará el mensaje al siguiente. Expandimos la estructura de este gráfico.

La red tiene una estructura cíclica, que es el origen del nombre de la red neuronal cíclica. Al mismo tiempo, de acuerdo con la estructura de la red neuronal cíclica, se puede ver que tiene una ventaja natural en el procesamiento de datos de tipo secuencia. . Debido a que la red en sí es una estructura de secuencia, esta es también la estructura más esencial de todas las redes neuronales recurrentes.

La red neuronal cíclica tiene características de memoria particularmente buenas y puede aplicar el contenido de la memoria a la situación actual, pero la capacidad de memoria de la red no es tan efectiva como se imagina. El mayor problema con la memoria es que tiene olvidos. Siempre recordamos los eventos recientes con mayor claridad y olvidamos los eventos que sucedieron hace mucho tiempo. Las redes neuronales recurrentes también tienen este problema.

pytorch usa la clase nn.RNN para construir una red neuronal recurrente basada en secuencia. Su constructor tiene los siguientes parámetros:

  • input_size: el número de valores de características de los datos de entrada X.
  • hidden_size: el número de neuronas en la capa oculta, es decir, el número de entidades en la capa oculta.
  • num_layers: el número de capas de la red neuronal recurrente, el valor predeterminado es 1.
  • sesgo: el valor predeterminado es verdadero. Si es falso, la neurona no utiliza el parámetro de sesgo.
  • batch_first: si se establece en Verdadero, la primera dimensión en las dimensiones de los datos de entrada es el valor del lote y el valor predeterminado es Falso. De forma predeterminada, la primera dimensión es la longitud de la secuencia, la segunda dimensión es - lote y la tercera dimensión es el número de entidades.
  • abandono: si no está vacío, significa que la última capa de abandono descarta parte de los datos, y este parámetro especifica el porcentaje de datos descartados.

Los parámetros más importantes en RNN son input_size y hidden_size, estos dos parámetros deben aclararse. Por lo general, no es necesario configurar el resto de los parámetros, solo use los valores predeterminados.

rnn = torch.nn.RNN(20,50,2)
input = torch.randn(100 , 32 , 20)
h_0 =torch.randn(2 , 32 , 50)
output,hn=rnn(input ,h_0) 
print(output.size(),hn.size())
torch.Size([100, 32, 50]) torch.Size([2, 32, 50])

Los principiantes que ven la introducción anterior definitivamente todavía están perdidos ¿Qué son estas cosas y cómo usarlas en la práctica?
A continuación, usamos pytorch para escribir una implementación de RNN, de esta manera, a través de nuestra propia implementación, tendremos una comprensión más profunda de la estructura de RNN.

Antes de la implementación, continuamos introduciendo el mecanismo de trabajo de RNN en profundidad. RNN es en realidad una red neuronal ordinaria, excepto que hay un hidden_state adicional para guardar información histórica. La función de este hidden_state es guardar el estado anterior. A menudo decimos que la información del estado de la memoria guardada en el RNN es este hidden_state.

Para RNN, solo necesitamos vivir en una fórmula:

ht = tanh ⁡ (W ihxt + bih + W hhh (t - 1) + bhh) h_t = \ tanh (W_ {ih} x_t + b_ {ih} + W_ {hh} h _ {(t-1)} + b_ {S.S}) ht=tanh ( W.y hXt+By h+Wh hh( T - 1 )+Bh h)

Esta fórmula proviene del sitio web oficial:
https://pytorch.org/docs/stable/nn.html?highlight=rnn#torch.nn.RNN

Xt x_t en esta fórmulaXtEs el valor de entrada de nuestro estado actual, h (t - 1) h _ {(t-1)}h( T - 1 )Es el hidden_state del estado anterior que se pasará como se mencionó anteriormente, que es la parte de la memoria.
La parte de toda la red que debe capacitarse es W ih W_ {ih}Wy hEl peso del valor de entrada del estado actual, W hh W_ {hh}Wh hhidden_state es el peso del estado anterior y los dos valores de compensación de entrada. Estos cuatro valores se suman para usar tanh para la activación. Pytorch usa tanh como la activación de forma predeterminada, o puede usar relu como la función de activación mediante la configuración.

Los pasos mencionados anteriormente son un proceso de cálculo encerrado en un círculo con un marco rojo.

Este paso no es diferente de las redes neuronales ordinarias, y debido a que RNN tiene más dimensión de secuencia, necesita ejecutar la propagación hacia adelante n veces con el mismo modelo. Este n es el número de nuestra configuración de secuencia.
Comencemos a implementar nuestra RNN manualmente: consulte el artículo de Karpathy: https://karpathy.github.io/2015/05/21/rnn-effectiveness/

class RNN(object):
    def __init__(self,input_size,hidden_size):
        super().__init__()
        self.W_xh=torch.nn.Linear(input_size,hidden_size) #因为最后的操作是相加 所以hidden要和output 的shape一致
        self.W_hh=torch.nn.Linear(hidden_size,hidden_size)
        
    def __call__(self,x,hidden):
        return self.step(x,hidden)
    def step(self, x, hidden):
        #前向传播的一步
        h1=self.W_hh(hidden)
        w1=self.W_xh(x)
        out = torch.tanh( h1+w1)
        hidden=self.W_hh.weight
        return out,hidden
rnn = RNN(20,50)
input = torch.randn( 32 , 20)
h_0 =torch.randn(32 , 50) 
seq_len = input.shape[0]
for i in range(seq_len):
    output,hn= rnn(input[i, :], h_0)
print(output.size(),h_0.size())
torch.Size([32, 50]) torch.Size([32, 50])

LSTM

LSTM es la abreviatura de Long Short Term Memory Networks, literalmente traducida como Long Short Term Memory Networks. La estructura de red de LSTM fue propuesta por Hochreiter y Schmidhuber en 1997, y luego esta estructura de red se hizo muy popular.
Aunque LSTM solo resuelve el problema de la dependencia a corto plazo y utiliza un diseño deliberado para evitar la dependencia a largo plazo, este enfoque ha demostrado ser muy eficaz en aplicaciones prácticas y muchas personas han realizado un seguimiento del trabajo relacionado para resolver muchos problemas prácticos. , Así que ahora LSTM todavía se usa ampliamente. Fuente de imagen
Inserte la descripción de la imagen aquí

La red neuronal recurrente estándar tiene solo una estructura de capa simple, mientras que LSTM tiene estructuras de 4 capas:

La primera capa es una capa de olvido: decida qué información descartar en el estado

La segunda capa de tanh se utiliza para generar candidatos para valores actualizados, lo que indica que el estado necesita fortalecerse en algunas dimensiones y debilitarse en algunas dimensiones.

La tercera capa de la capa sigmoidea (capa de puerta de entrada), su valor de salida debe multiplicarse por la salida de la capa tanh, que juega un papel de escala. En casos extremos, la salida sigmoidea 0 indica que el estado en la dimensión correspondiente no necesita ser actualizado

La última capa decide qué producir y el valor de salida está relacionado con el estado. La parte de los candidatos que finalmente se extraerá está determinada por una capa sigmoidea.

pytorch usa la clase nn.LSTM para construir una red neuronal recurrente basada en secuencia. Sus parámetros son básicamente similares a RNN, por lo que no lo enumeraré aquí.

lstm = torch.nn.LSTM(10, 20,2)
input = torch.randn(5, 3, 10)
h0 =torch.randn(2, 3, 20)
c0 = torch.randn(2, 3, 20)
output, hn = lstm(input, (h0, c0))
print(output.size(),hn[0].size(),hn[1].size())
torch.Size([5, 3, 20]) torch.Size([2, 3, 20]) torch.Size([2, 3, 20])

GRÚA TORRE

GRU es la abreviatura de unidades recurrentes cerradas y fue propuesto por Cho en 2014. La mayor diferencia entre GRU y LSTM es que GRU combina la puerta de olvido y la puerta de entrada en una "puerta de actualización". Al mismo tiempo, la red ya no proporciona un estado de memoria adicional, sino que utiliza el resultado de salida como estado de memoria. para pasar continuamente hacia atrás, la entrada de la red y la salida se ha vuelto particularmente simple.

rnn = torch.nn.GRU(10, 20, 2)
input = torch.randn(5, 3, 10)
h_0= torch.randn(2, 3, 20)
output, hn = rnn(input, h0)
print(output.size(),hn.size())
torch.Size([5, 3, 20]) torch.Size([2, 3, 20])

2.5.3 Propagación hacia atrás de la red cíclica (BPTT)

En el caso de la propagación hacia adelante, la entrada del RNN avanza con cada paso de tiempo. En el caso de la retropropagación, "retrocedemos en el tiempo" para cambiar el peso, por lo que lo llamamos retropropagación a través del tiempo (BPTT).

Por lo general, tratamos la secuencia completa (palabras) como una muestra de entrenamiento, por lo que el error total es la suma de los errores en cada paso de tiempo (carácter). El peso es el mismo en cada paso de tiempo (por lo que se pueden actualizar juntos después de calcular el error total).

  1. Calcule el error de entropía cruzada utilizando la salida prevista y la salida real
  2. La red está completamente implementada en pasos de tiempo.
  3. Para la red expandida, calcule el gradiente del peso para cada paso de práctica.
  4. Debido a que los pesos son los mismos para todos los pasos de tiempo, los gradientes se pueden obtener juntos para todos los pasos de tiempo (en lugar de obtener diferentes gradientes para diferentes capas ocultas como una red neuronal)
  5. Luego, actualice el peso de las neuronas circulantes.

La red desplegada por RNN parece una red neuronal ordinaria. La propagación hacia atrás también es similar a una red neuronal normal, excepto que obtenemos los gradientes de todos los pasos de tiempo a la vez. Si hay 100 pasos de tiempo, la red se volverá muy grande después de desplegarse, por lo que para resolver este problema, aparecerán estructuras como LSTM y GRU.

Las redes neuronales recurrentes son actualmente las más populares en el procesamiento del lenguaje natural, por lo que el siguiente contenido presentará algunos otros conocimientos que las redes neuronales recurrentes deben usar al procesar la PNL.

2.5.4 incrustación de palabras

En el proceso de nuestra comunicación humana, el vocabulario de caracterización está directamente representado por palabras en inglés, pero para las computadoras, es imposible reconocer palabras directamente. Para que la computadora comprenda mejor nuestro idioma y construya un mejor modelo de lenguaje, necesitamos caracterizar el vocabulario.

La codificación one-hot se utilizará en el problema de clasificación de imágenes. Por ejemplo, hay 10 números del 0 al 9 en LeNet. Si este número es 2, su código es (0,0,1,0,0,0,0,0,0,0), que es el caso de la clasificación problemas. La expresión es muy clara, pero en el procesamiento del lenguaje natural, debido a que la cantidad de palabras es demasiado grande, por ejemplo, hay 10,000 palabras diferentes, entonces la eficiencia de usar one-hot para definirla es particularmente baja, y cada palabra es un vector de 10.000 dimensiones. Solo uno de ellos es 1, y el resto es 0, lo que ocupa memoria y no puede reflejar la parte del discurso de la palabra, porque cada palabra es one-hot, aunque algunas palabras estarán más cerca en semántica. Pero one-hot puede Para reflejar esta característica, es necesario utilizar otra forma de definir cada palabra.

Se utilizan diferentes características para caracterizar cada vocabulario. En comparación con diferentes características, diferentes palabras tienen diferentes valores. Esto es incrustación de palabras. La imagen de abajo sigue siendo una captura de pantalla del curso del profesor Wu Enda.

La incrustación de palabras no solo realiza la representación característica de diferentes palabras, sino que también calcula la similitud entre palabras. De hecho, en un espacio multidimensional, podemos encontrar la similitud de distancia de cada dimensión entre vectores de palabras. Razonamiento analógico, como verano y el calor, el invierno y el frío están relacionados.

En PyTorch, usamos la capa nn.Embedding para hacer el modelo de bolsa de palabras de inserción. La primera entrada de la capa de inserción indica cuántas palabras tenemos y la segunda entrada indica cuántas dimensiones de representación vectorial usa cada palabra.

# an Embedding module containing 10 tensors of size 3
embedding = torch.nn.Embedding(10, 3)
# a batch of 2 samples of 4 indices each
input = torch.LongTensor([[1,2,4,5],[4,3,2,9]])
output=embedding(input)
print(output.size())
torch.Size([2, 4, 3])

2.5.5 Otros conceptos importantes

Búsqueda de haz

Después de generar la distribución de la primera palabra, podemos usar la búsqueda codiciosa para seleccionar la primera palabra que tenga más probabilidades de aparecer de acuerdo con nuestro modelo de lenguaje condicional, pero para el algoritmo de búsqueda codiciosa, hay cientos de palabras en nuestra biblioteca de palabras. de millones de palabras, no es factible calcular la posibilidad de cada combinación de palabras. Por lo tanto, utilizamos métodos de búsqueda aproximados para maximizar o aproximar la probabilidad condicional máxima de oraciones, en lugar de utilizar palabras.

Beam Search (búsqueda de clústeres) es un algoritmo de búsqueda de gráficos heurísticos. Suele utilizarse cuando el espacio de solución del gráfico es relativamente grande. Para reducir el espacio y el tiempo que ocupa la búsqueda, se corta algo de calidad cuando la profundidad El paso se expande Nodos inferiores, mantenga algunos nodos de mayor calidad. Aunque el algoritmo Beam Search está incompleto, puede reducir la ocupación del espacio y el tiempo cuando se utiliza para comprender sistemas con espacios más grandes.

La búsqueda de haces se puede considerar como una búsqueda en amplitud con optimización restringida. Primero, se utiliza una estrategia en amplitud primero para construir un árbol de búsqueda. En cada nivel del árbol, los nodos se ordenan de acuerdo con el costo heurístico, y luego solo un número predeterminado (ancho de haz - ancho de grupo) nodos, solo estos nodos continúan expandiéndose en el siguiente nivel, y otros nodos se cortan.

  1. Inserte el nodo inicial en la lista
  2. El nodo estará fuera del montón, si el nodo es el nodo de destino, el algoritmo finaliza;
  3. De lo contrario, el nodo se expande y el nodo del ancho del grupo se incorpora a la pila. Luego vaya al segundo paso para continuar el ciclo.
  4. La condición para el final del algoritmo es encontrar la solución óptima o el montón está vacío.

En uso, el ancho del grupo puede ser preestablecido o variable, y la configuración específica se puede ajustar de acuerdo con la escena real.

Modelo de atención

Para los modelos RNN que utilizan codificación y decodificación, podemos lograr resultados de traducción automática relativamente precisos. Para oraciones cortas, su rendimiento es muy bueno, pero si es una oración muy larga, el resultado de la traducción será peor.
Cuando los humanos realizamos la traducción manual, traducimos parte por parte El mecanismo de atención introducido es muy similar al proceso de traducción humana, que también traduce largas oraciones parte por parte.

El contenido específico no se introducirá en detalle aquí.

Supongo que te gusta

Origin blog.csdn.net/yegeli/article/details/113688200
Recomendado
Clasificación