tensorflow调用并实现注意力机制

1 什么是注意力机制

 

当我们观看一张图片时,会直接关注最关心的内容,例如会只看到兔子,而忽略兔子嘴里叼的草和蓝天白云。注意力机制就是你模仿人脑自动捕捉最重要信息的能力,使得模型更好的学习关键内容。

注意力机制适合位置信息和时序信息,和CNN和RNN结合使用是典型的方法,如上图中人的眼睛和耳朵。

下面从encoder-decoder架构角度解释注意力机制:

 

上图显示了传统encoder-decoder模型的计算方式,encoder输出全部的语义信息c,然后作为输入,decoder计算由c推出的目标信息。decoder模型将注意力放在全部语义信息中,这有时是不合适的。所以引入注意力机制。

下图显示了添加注意力机制后的encoder-decoder模型,输入x会返回注意力权重c,每个c_i记录了要预测的单词y_i在原信息x中的重要性。那么,理解了注意力机制后,就是考虑如何计算c,这也是最不容易理解的部分。

 

2  注意力机制计算方式

下图就明确的表示了注意力权重的计算方式。

要计算的是某个单词在原句子中和哪些单词相关度高,即计算目标单词的注意力概率分布,例如X=(我是中国人,我爱中国),要翻译成y=(i am chinese, i love china),china对应的概率分布可能是(0.1, 0.001, 0.5, 0.5, 0.2, 0.01, 0.2, 0.5, 0.5),再经过归一化后和原句子做加权求和。

下图中,Query表示要查询的目标单词的位置,暂时这么理解,不同模型Query取值不同;key是输入的原句子;a表示每个目标单词的注意力概率分布。

下面以自编码器为例,详细解释了注意力值的计算方式,包括数据流的维度,需要点耐心!

 RNN-based encoder-decoder framework,目标是预测P(y_1, y_2, …, y_i | x_1, x_2, …, x_i),x.shape=(b, sentence_x_len, word_x_len),y.shape=(b, sentence_y_len, word_y_len)。训练阶段结构图如下所示。

 

encoder:

单词序列经过embedding层得到分布式向量表达,由RNN计算得出序列的特征,送到decoder翻译。

h_t = f(W@x_t, h_t-1) 单词序列对应的状态,最后一个h记录了全部状态,shape(b, sentence_x_len, units_encoder);

c = q({h_i}) q为计算概率分布的函数,上下文向量,最简单的是最后一个h,可以是点积、网络…,shape(b, units_encoder);

decoder:

在获得h、上下文向量c和已经预测出的输出y_t-1的条件下,预测下个输出y_t,即条件概率分布。

P(y) = g(y_t | {y_1, y_2, …, y_t-1}, c, h) g为计算函数,一般为全连接层加softmax,y-i(b, units_decoder)是由RNN得出,即图中的W。

到此非注意力自编码器介绍完毕。下面以RNN-based encoder-decoder with attention framework为模型,解释注意力概率分布的计算过程:

 

不同之处就在于c的计算方式,不是简单的取最后一个h,而是计算不同目标单词在原句中的重要性概率分布,即注意力概率分布attention vector(b, units_y)。

encoder:

单词序列经过BiLSTM提取特征后全部送到Attention模块中。

inputs:x(b, sentence_len),embedding后为:(b, sentence_len, word_len)

outputs: y(), h(b, sentence_len, units_encoder)

decoder:

输入为经过添加注意力之后的上下文向量和上一时刻的隐藏状态,再输出为目标单词。

inputs:y_t-1(b, sentence_len), context(b, units_encoder)

outputs: s(b, units_decoder)

attention:

inputs:[s_t-1, h]

outputs: [context_t]

计算公式:context_t = h * softmax(f(s_t-1, h))

3  attention调用

3.1 Attention()

Attention模块参数:

use_scale,取值True或者False,它表示是否对计算出来的得分(score)进行权重缩放,如果是True,进行权重缩放,如果False,不进行缩放,默认值是False。通常也使用默认,因为它只是在最后计算出score是乘一个scale。

inputs:

query_seq_decoding(batch_size, Tq, dim),

value_seq_encoding(batch_size, Tv, dim),

key(batch_size, Tv, dim),可选的,如果没有给定,则默认key=value

outputs:

[batch_size, Tq, dim]

计算过程:

scores=query@key^T =>(Tq, Tv) \\[2ex] attention=softmax(scores) \\[2ex] result=attention@value=>(Tq, dim)

可知Attention是非常简单的,没有参数要训练,但是可以自定义分数scores的计算方式,如神经网络。

encoder_out = tf.random.normal([50, 80, 30])
decoder_out = tf.random.normal([50, 1, 30])
attention = layers.Attention()
y = attention([decoder_out, encoder_out])
print(y)  # (50, 1, 30)

3.2 自定义attention

attention模块中分数计算部分可以有不同方式,下面实现一种矩阵参数的。

TensorFlow2.0中自定义层,要点如下:

1、如果需要使用到其他Layer结构或者Sequential结构,需要在init()函数里赋值;2、在build()里面根据输入shape构建权重参数, 每个参数需要赋值name,如果参数没有name,当训练到第2个epoch时会报错:AttributeError: ‘NoneType’ object has no attribute ‘replace’;3、在call()里写计算逻辑。

class AttentionConcat(layers.Layer):
    def __init__(self, bias=True):
        """
        scores = query @ W @ key^T  => shape(b, Tq, Tv)
        W = (dim, dim)
        result = scores @ value + bias
        # Input shape
            [query(batch_size, Tq, dim),
            value(batch_size, Tv, dim),
            key(batch_size, Tv, dim)]
        # Output shape
            (batch_size, Tq, dim)
        :param bias: shape(b, Tq, dim)
        """
        super(AttentionConcat, self).__init__()
        self.bias = bias

    def build(self, input_shape):
        """

        :param input_shape:
        :return:
        """
        self.batch = input_shape[0][0]
        self.Tq = input_shape[0][1]
        self.Tv = input_shape[1][1]
        self.dim = input_shape[0][-1]
        self.W = self.add_weight(
            name='{}_W'.format(self.name),
            shape=(self.batch, self.dim, self.dim),
            initializer='one',
            trainable=True
        )
        if self.bias:
            self.b = self.add_weight(
                # name='{}_b'.format(self.name),
                shape=(self.batch, self.Tq, self.dim),
                initializer='zero',
                trainable=True
            )
        else:
            self.b = None



    def call(self, inputs, **kwargs):
        # (
        scores = inputs[0] @ self.W @ tf.transpose(inputs[2], perm=[0, 2, 1])

        scores_flat = tf.reshape(scores, shape=[-1, self.Tq * self.Tv])
        attention_flat = tf.nn.softmax(scores_flat)
        attention = tf.reshape(attention_flat, shape=[-1, self.Tq, self.Tv])

        # (N, step, d) (N, step, 1) ====> (N, step, d)
        result = attention @ inputs[1]
        if self.bias:
            result += self.bias

        return result

来源:三叶草~

物联沃分享整理
物联沃-IOTWORD物联网 » tensorflow调用并实现注意力机制

发表评论