La atención es un método para la agregación de un conjunto de vectores $v_i$ en un solo vector, a menudo a través de un vector de búsqueda $u$. Generalmente, $v_i$ es cualquiera de las entradas del modelo o de los estados ocultos de la vez anterior-pasos, o los estados ocultos en la planta de abajo (en el caso de la apilados LSTMs).
El resultado es a menudo llamado el contexto de vectores $c$, ya que contiene el contexto relevante para el momento actual-el paso.
En este contexto adicional de vectores $c$ luego se introduce en la RNN/LSTM así (puede ser simplemente que se concatena con la entrada original). Por lo tanto, el contexto puede ser utilizada para ayudar con la predicción.
La forma más sencilla de hacer esto es calcular la probabilidad de vectores $p = \text{softmax}(V^Tu)$ $c = \sum_i p_i v_i$ donde $V$ es la concatenación de todos los anteriores $v_i$. Un común vector de búsqueda $u$ es el actual estado oculto $h_t$.
Hay muchas variaciones de este, y usted puede hacer las cosas tan complicado como usted quiera. Por ejemplo, en lugar de usar $v_i^T u$ como los logits, uno puede elegir la $f(v_i, u)$ lugar donde $f$ es arbitrario de la red neuronal.
Una atención comunes mecanismo para la secuencia a la secuencia de los modelos que utiliza $p = \text{softmax}(q^T \tanh(W_1 v_i + W_2 h_t))$ donde $v$ ocultos estados del codificador, y $h_t$ es el actual estado oculto de la decodificador. $q$ y el tanto $W$s son los parámetros.
Algunos documentos que muestran las diferentes variaciones en la atención de la idea:
Puntero de Redes de uso de la atención a las entradas de referencia con el fin de resolver problemas de optimización combinatoria.
Recurrente Entidad de Redes de mantener la memoria independiente unidos por diferentes entidades (personas y objetos), mientras que la lectura del texto, y actualizar el correcto estado de la memoria mediante la atención.
Aquí está una rápida implementación de una forma de atención, aunque no puedo garantizar la exactitud más allá del hecho de que pasar algunas pruebas sencillas.
Básica RNN:
def rnn(inputs_split):
bias = tf.get_variable('bias', shape = [hidden_dim, 1])
weight_hidden = tf.tile(tf.get_variable('hidden', shape = [1, hidden_dim, hidden_dim]), [batch, 1, 1])
weight_input = tf.tile(tf.get_variable('input', shape = [1, hidden_dim, in_dim]), [batch, 1, 1])
hidden_states = [tf.zeros((batch, hidden_dim, 1), tf.float32)]
for i, input in enumerate(inputs_split):
input = tf.reshape(input, (batch, in_dim, 1))
last_state = hidden_states[-1]
hidden = tf.nn.tanh( tf.matmul(weight_input, input) + tf.matmul(weight_hidden, last_state) + bias )
hidden_states.append(hidden)
return hidden_states[-1]
Con atención, se añade sólo un par de líneas antes de que el nuevo estado oculto se calcula:
if len(hidden_states) > 1:
logits = tf.transpose(tf.reduce_mean(last_state * hidden_states[:-1], axis = [2, 3]))
probs = tf.nn.softmax(logits)
probs = tf.reshape(probs, (batch, -1, 1, 1))
context = tf.add_n([v * prob for (v, prob) in zip(hidden_states[:-1], tf.unstack(probs, axis = 1))])
else:
context = tf.zeros_like(last_state)
last_state = tf.concat([last_state, context], axis = 1)
hidden = tf.nn.tanh( tf.matmul(weight_input, input) + tf.matmul(weight_hidden, last_state) + bias )
el código completo