deep_learning 04. attention

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/WUUUSHAO/article/details/88175373

开始的话:
从基础做起,不断学习,坚持不懈,加油。
一位爱生活爱技术来自火星的程序汪

RNN系列

  1. BasicRNNCell
  2. BasicLSTMCell
  3. MultiRNNCell

说到RNN,我们就不得不说attention在RNN中的运用了。为啥使用attention我也就不多说了。

话不多说,直接上图(没水印且居中的图片,终于舒服了)。

看过前面几个章节的,图中 m a t c h match 以下的部分就不需要过多解释了。
h t h_t 就是每个时间步的输出
C 0 C_0 就是最后的 s t a t e state 输出

B a h d a n a u A t t e n t i o n BahdanauAttention 中:
u t = v T t a n h ( W 1 h + W 2 d t ) u^t=v^Ttanh(W_1h + W_2d_t)
a t = s o f t m a x ( u t ) a^t=softmax(u^t)
c t = t L a t h l c^t = \sum_t^{L}a^th_l

h h 表示每个时间步的输出
d t d_t 表示 d e c o d e r decoder 时候的状态
v T v^T 表示 w e i g h t s weights ,需要去学习的
剩下的就比较好理解了。

在分类的 t a s k task 中,是没有 d e c o d e r decoder

接下来会结合着 d e m o demo 和上面的图片来详细说明下过程。

def attention(inputs, hidden_size, dropout, attention_size):
    """
    :param inputs: [B, T, D] -> [batch_size, sequence_length, embedding_size]
    :param hidden_size: RNN output size
    :param dropout: dropout rate
    :param attention_size: attention output size
    :return:
    """
    fw = tf.nn.rnn_cell.GRUCell(hidden_size, name='fw')
    bw = tf.nn.rnn_cell.GRUCell(hidden_size, name='bw')

    if dropout:
        fw = tf.nn.rnn_cell.DropoutWrapper(fw, output_keep_prob=dropout)
        bw = tf.nn.rnn_cell.DropoutWrapper(bw, output_keep_prob=dropout)

    output, _ = tf.nn.bidirectional_dynamic_rnn(
        fw,
        bw,
        inputs=inputs,
        dtype=tf.float32
    )

    #   [batch_size, sequence_length, 2 * hidden_size]
    output = tf.concat(output, axis=2)

    #   W * X + B
    #   [batch_size, sequence_length, 2 * hidden_size] -> [batch_size, sequence_length, attention_size]
    I = tf.layers.dense(inputs=output, units=attention_size, activation=tf.tanh)

    V = tf.get_variable(name='v_omega', shape=[attention_size], dtype=tf.float32)

    #   [batch_size, sequence_length, attention_size]
    U = tf.multiply(I, V)
    #   [batch_size, sequence_length]
    U = tf.reduce_sum(U, axis=2)
    #   [batch_size, sequence_length]
    A = tf.nn.softmax(U, axis=1)

    #   multiply is [batch_size, sequence_length, 2 * hidden_size] * [batch_size, sequence_length, 1]
    #   multiply = [batch_size, sequence_length, 2 * hidden_size]
    #   reduce_sum = [batch_size, 2 * hidden_size]
    C = tf.reduce_sum(tf.multiply(output, tf.expand_dims(A, -1)), axis=1)
    return C, A

在拿到 r n n rnn 的输出结果 o u t p u t output 之后,我们就拿到了在上面公式中的 h h

I = tf.layers.dense(inputs=output, units=attention_size, activation=tf.tanh)

上面这行代码,就是公式中的
t a n h ( W 1 h + W 2 d t ) tanh(W_1h + W_2d_t)
只不过没有了 d t d_t ,可以改为:
t a n h ( W 1 h + b ) tanh(W_1h + b)

	V = tf.get_variable(name='v_omega', shape=[attention_size], dtype=tf.float32)

    #   [batch_size, sequence_length, attention_size]
    U = tf.multiply(I, V)

经过上面的两行代码,就得到了 u t u^t ,而这也是我们在图片中 m a t c h match 后的结果。
u t = v T t a n h ( W 1 h + b ) u^t=v^Ttanh(W_1h + b)

	#   [batch_size, sequence_length]
    U = tf.reduce_sum(U, axis=2)
    #   [batch_size, sequence_length]
    A = tf.nn.softmax(U, axis=1)

经过 s o f t m a x softmax 之后,就拿到了我们的attention结果,也就是图片中的 S t S_t ,对应着公式中的:
a t = s o f t m a x ( u t ) a^t=softmax(u^t)
最后将 a t t e n t i o n attention h h 做加权并求和。

	#   multiply is [batch_size, sequence_length, 2 * hidden_size] * [batch_size, sequence_length, 1]
    #   multiply = [batch_size, sequence_length, 2 * hidden_size]
    #   reduce_sum = [batch_size, 2 * hidden_size]
    C = tf.reduce_sum(tf.multiply(output, tf.expand_dims(A, -1)), 
    # C = tf.reduce_mean(tf.multiply(output, tf.expand_dims(A, -1)), axis=1)axis=1)

对应公式中的:
c t = t L a t h l c^t = \sum_t^{L}a^th_l

最后的 C C ,就是我们对一个输入的 v e c t o r vector 表示,不同的输入 x t x_t 贡献着不一样的权重。
上面的就是 a t t e n t i o n attention 在分类中的 d e m o demo 展示。
最后再提一句,在 e n c o d e r encoder - d e c o d e r decoder 中,我们可以拿到 r n n rnn 的输出也就是图片中的 h t h_t c 0 c_0 ,通过 h t h_t c 0 c_0 c 0 c_0 也就是 d e c o d e r decoder 的初始状态)计算 a t t e n t i o n attention 之后,我们能拿到 C C (也就是下面图片中的 X d 1 X_{d-1} ),在 d e c o d e r decoder 的时候,会把 X d 1 X_{d-1} c 0 c_0 作为解码中的第一次输出,从而得到 c 1 c_1 ,然后通过 c 1 c_1 以及 h t h_t 得到下一步的输入,以此迭代到输出结束为止。

看图加深下理解:

这时候的 a t t e n t i o n attention 就和 B a h d a n a u A t t e n t i o n BahdanauAttention 中的差不多啦。

当然 a t t e n t i o n attention 还是有很多变体的,主要是在 m a t c h match 的过程中有不同。
LuongAttention 中, m a t c h match 操作是这样的:
u t = d t W h u^t=d_tWh
a t = s o f t m a x ( u t ) a^t=softmax(u^t)
c t = t L a t h l c^t = \sum_t^{L}a^th_l

这两类 a t t e n t i o n attention 也就是我们经常说的加法 a t t e n t i o n attention 和乘法 a t t e n t i o n attention 了。

这个实例中我们用的是 g l o b a l global a t t e n t i o n attention ,也就是对所有的输入 X t X_t 进行了 a t t e n t i o n attention 的操作。还有一种 l o c a l local a t t e n t i o n attention 的操作,是在随机窗口内做 a t t e n t i o n attention 操作,减少了计算量,区别在于关注的是所有 e n c o d e r encoder 状态还是部分 e n c o d e r encoder 状态。
具体请看 L u o n g A t t e n t i o n LuongAttention 中的详细介绍。

随着 g o o g l e google 大佬提出了 t r a n s f o r m e r transformer 之后,一种更为一般化的 a t t e n t i o n attention 就出来了:

A t t e n t i o n ( Q , V , K ) = s o f t m a x ( Q K T d k ) V Attention(Q,V, K)= softmax(\frac{QK^T}{\sqrt{d^k}} ) V

对应上面公式中:
Q Q -> C 0 C_0
K K -> h t h_t
V V -> h t h_t

如果 Q Q K K V V 都是一个值得话,那就是我们的 s e l f self - a t t e n t i o n attention 了。

谢谢

更多代码请移步我的个人github,会不定期更新各种框架。
本章代码见code
欢迎关注

猜你喜欢

转载自blog.csdn.net/WUUUSHAO/article/details/88175373
今日推荐