BahdanauAttention注意力机制、LuongAttention注意力机制

日萌社

人工智能AI:Keras PyTorch MXNet TensorFlow PaddlePaddle 深度学习实战(不定时更新)


Encoder编码器-Decoder解码器框架 + Attention注意力机制

Pytorch:Transformer(Encoder编码器-Decoder解码器、多头注意力机制、多头自注意力机制、掩码张量、前馈全连接层、规范化层、子层连接结构、pyitcast) part1

Pytorch:Transformer(Encoder编码器-Decoder解码器、多头注意力机制、多头自注意力机制、掩码张量、前馈全连接层、规范化层、子层连接结构、pyitcast) part2

Pytorch:解码器端的Attention注意力机制、seq2seq模型架构实现英译法任务

BahdanauAttention注意力机制、LuongAttention注意力机制

BahdanauAttention注意力机制:基于seq2seq的西班牙语到英语的机器翻译任务、解码器端的Attention注意力机制、seq2seq模型架构

图片的描述生成任务、使用迁移学习实现图片的描述生成过程、CNN编码器+RNN解码器(GRU)的模型架构、BahdanauAttention注意力机制、解码器端的Attention注意力机制

注意力机制、bmm运算

注意力机制 SENet、CBAM

机器翻译 MXNet(使用含注意力机制的编码器—解码器,即 Encoder编码器-Decoder解码器框架 + Attention注意力机制)

基于Seq2Seq的中文聊天机器人编程实践(Encoder编码器-Decoder解码器框架 + Attention注意力机制)

基于Transformer的文本情感分析编程实践(Encoder编码器-Decoder解码器框架 + Attention注意力机制 + Positional Encoding位置编码)

注意:这一文章“基于Transformer的文本情感分析编程实践(Encoder编码器-Decoder解码器框架 + Attention注意力机制 + Positional Encoding位置编码)”
	该文章实现的Transformer的Model类型模型,实际是改造过的特别版的Transformer,因为Transformer的Model类型模型中只实现了Encoder编码器,
	而没有对应实现的Decoder解码器,并且因为当前Transformer的Model类型模型处理的是分类任务,
	所以我们此处只用了Encoder编码器来提取特征,最后通过全连接层网络来拟合分类。

tensorflow提供了两种Attention Mechanisms(注意力机制)
    1.BahdanauAttention注意力机制:tfa.seq2seq.BahdanauAttention
            实现BahdanauAttention风格的(additive累积)注意力机制。
    2.LuongAttention注意力机制:tfa.seq2seq.LuongAttention
            实现LuongAttention风格的(multiplicative乘法)注意力机制
            
构建BahdanauAttention注意力机制类的伪代码:
        # 这里实现 BahdanauAttention注意力机制
        1, score = FC(tanh(FC(EO) + FC(H)))
        2, attention weights = softmax(score, axis = 1).
                解释: Softmax 默认被应用于最后一个轴,但是这里我们想将它应用于第一个轴,
                因为分数 (score) 的形状是 (批大小,最大长度,隐层大小),最大长度 (max_length) 是输入的长度。
                因为我们想为每个输入长度分配一个权重,所以softmax应该用在这个轴上。
        3, context vector = sum(attention weights * EO, axis = 1)
                解释: 选择第一个轴的原因同上.
        4, embedding output = 解码器输入 X 通过一个嵌入层
        5, merged vector = concat(embedding output, context vector)
        
        符号代表:
        FC: 全连接层
        EO: 编码器输出
        H: 隐藏层状态
        X: 解码器输入
#构建BahdanauAttention注意力机制类:
class BahdanauAttention(tf.keras.Model):
    def __init__(self, units):
        """初始化三个必要的全连接层"""
        super(BahdanauAttention, self).__init__()
        self.W1 = tf.keras.layers.Dense(units)
        self.W2 = tf.keras.layers.Dense(units)
        self.V = tf.keras.layers.Dense(1)

    """
    传入值:
        features:编码器的输出,(64, 16, 1024) 即 (BATCH_SIZE, 输入序列最大长度句子的长度, 隐藏层中的隐藏神经元数量)
        hidden:解码器的隐层输出状态,(64, 1024) 即 (batch_size, hidden_size) (BATCH_SIZE, 隐藏层中的隐藏神经元数量)
    返回值:
        attention_result:(64, 1024) 即 (batch size, units) (BATCH_SIZE, 隐藏层中的隐藏神经元数量)
        attention_weights:(64, 16, 1) 即 (batch_size, sequence_length, 1) (BATCH_SIZE, 输入序列最大长度句子的长度, 1)
    """
    def call(self, features, hidden):
        """
        description: 具体计算函数
        :param features: 编码器的输出
        :param hidden: 解码器的隐层输出状态
        return: 通过注意力机制处理后的结果和注意力权重attention_weights
        """
        """
        1.hidden_with_time_axis = tf.expand_dims(hidden, 1)
                解码器的隐层输出状态hidden,(64, 1024) 即 (batch_size, hidden_size) (BATCH_SIZE, 隐藏层中的隐藏神经元数量)。
                hidden扩展一个维度从(64, 1024)变成(64, 1,1024)。
        2.score = tf.nn.tanh(self.W1(features) + self.W2(hidden_with_time_axis))
                计算注意力得分score。
                features:编码器的输出,(64, 16, 1024)。
                hidden_with_time_axis:解码器的隐层输出状态,(64, 1,1024)
                W1和W2:Dense(隐藏层中的隐藏神经元数量1024)
                tanh(W1(features) + W2(hidden_with_time_axis)):
                ---> tanh(W1((64, 16, 1024)) + W2((64, 1,1024)))
                ---> tanh((64, 16, 1024))
                ---> (64, 16, 1024) 即 (BATCH_SIZE, 输入序列最大长度句子的长度, 隐藏层中的隐藏神经元数量)
        3.attention_weights = tf.nn.softmax(self.V(score), axis=1)
                计算注意力权重attention_weights。
                V:Dense(隐藏层中的隐藏神经元数量1)
                softmax(V(score), axis=1)
                ---> softmax(V((64, 16, 1024)), axis=1)
                ---> softmax((64, 16, 1), axis=1)
                ---> (64, 16, 1) 即 (BATCH_SIZE, 输入序列最大长度句子的长度, 1)
                因为注意力得分score的形状是(BATCH_SIZE, 输入序列最大长度句子的长度, 隐藏层中的隐藏神经元数量),
                输入序列最大长度句子的长度(max_length)是输入的长度。
                因为我们想为每个输入长度分配一个权重,所以softmax应该用在第一个轴(max_length)上axis=1,
                而softmax默认被应用于最后一个轴axis=-1。
        4.context_vector = tf.reduce_sum(attention_weights * features, axis=1)
                获得注意力机制处理后的结果context_vector。
                reduce_sum(attention_weights * features, axis=1)
                ---> reduce_sum((64, 16, 1) * (64, 16, 1024), axis=1)
                ---> reduce_sum((64, 16, 1024), axis=1)
                ---> (64, 1024) 即 (BATCH_SIZE, 隐藏层中的隐藏神经元数量)
        """
        # 为hidden扩展一个维度(batch_size, hidden_size) --> (batch_size, 1, hidden_size)
        hidden_with_time_axis = tf.expand_dims(hidden, 1)

        # 根据公式计算注意力得分, 输出score的形状为: (batch_size, 16, hidden_size)
        score = tf.nn.tanh(self.W1(features) + self.W2(hidden_with_time_axis))

        # 根据公式计算注意力权重, 输出attention_weights形状为: (batch_size, 16, 1)
        attention_weights = tf.nn.softmax(self.V(score), axis=1)

        # 最后根据公式获得注意力机制处理后的结果context_vector
        # context_vector的形状为: (batch_size, hidden_size)
        context_vector = attention_weights * features
        context_vector = tf.reduce_sum(context_vector, axis=1)
        return context_vector, attention_weights

#调用:
# attention_layer = BahdanauAttention(1024)
# attention_result, attention_weights = attention_layer(sample_output, sample_hidden)
# print("Attention result shape: (batch size, units) {}".format(attention_result.shape)) #(64, 1024)
# print("Attention weights shape: (batch_size, sequence_length, 1) {}".format(attention_weights.shape)) #(64, 16, 1)
"""
构建RNN解码器:这里RNN是指GRU, 同时在解码器中使用注意力机制.
"""
class Decoder(tf.keras.Model):
    def __init__(self, vocab_size, embedding_dim, dec_units, batch_sz):
        super(Decoder, self).__init__()
        # 所有的参数传递和实例化方法与编码器相同
        self.batch_sz = batch_sz
        self.dec_units = dec_units
        self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)
        self.gru = tf.keras.layers.GRU(self.dec_units,
                                       return_sequences=True,
                                       return_state=True,
                                       recurrent_initializer='glorot_uniform')
        # 实例化一个Dense层作为输出层
        self.fc = tf.keras.layers.Dense(vocab_size)

        # 在解码器阶段我们将使用注意力机制,这里实例化注意力的类
        self.attention = BahdanauAttention(self.dec_units)

    """
    1.x = self.embedding(x)
            输入:(64, 1) 64行1列,批量大小句子数为64,1列为该行句子的第N列的单词
            输出:(64, 1, 256) (BATCH_SIZE, 输入序列最大长度句子的长度, 嵌入维度)
    2.context_vector, attention_weights = self.attention(hidden, enc_output)
            attention_weights注意力权重:(64, 16, 1) 即 (BATCH_SIZE, 输入序列最大长度句子的长度, 1)
            context_vector注意力机制处理后的结果:(64, 1024) 即 (BATCH_SIZE, 隐藏层中的隐藏神经元数量)
    3.x = tf.concat([tf.expand_dims(context_vector, 1), x], axis=-1)
            tf.expand_dims(context_vector, 1):(64, 1, 1024) 即 (BATCH_SIZE, 1, 隐藏层中的隐藏神经元数量)
            concat([(64, 1, 1024),(64, 1, 256)], axis=-1):1024+256=1280,最终输出 (64, 1, 1280)
    4.GRU
        1.tf.keras.layers.GRU(self.dec_units, return_sequences=True, return_state=True, recurrent_initializer='glorot_uniform')
            return_sequences:
                    布尔值。是返回输出序列中的最后一个输出还是完整序列。 默认值:False。
                    True代表返回GRU序列模型的每个时间步的输出(每个输出做连接操作)
            return_state:
                    布尔值。 除输出外,是否返回最后一个状态。 默认值:False。
                    True代表除了返回输出外,还需要返回最后一个隐层状态。
            recurrent_initializer:
                    recurrent_kernel权重矩阵的初始化程序,用于对递归状态进行线性转换。 默认值:正交。
                    'glorot_uniform'即循环状态张量的初始化方式为均匀分布。
        2.output, state = gru(x)      
            output:
                    (64, 1, 1024) 即 (BATCH_SIZE, 1, 隐藏层中的隐藏神经元数量)
                    (当前批次的样本个数, 当前样本的序列长度(单词个数), 隐藏层中神经元数量 * 1)
            state:
                    (64, 1024) 即 (BATCH_SIZE, 隐藏层中的隐藏神经元数量)
    5.output = tf.reshape(output, (-1, output.shape[2]))
             (-1, output.shape[2]):表示把(64, 1, 1024)转换为(64, 1024) 即 (BATCH_SIZE, 隐藏层中的隐藏神经元数量)
    6.x = self.fc(output)
            x:(64, 4935) 即 (BATCH_SIZE, 目标序列的不重复单词的总数作为目标序列的字典大小)
    """
    def call(self, x, hidden, enc_output):
        """
        :param x: 每个时间步上解码器的输入
        :param hidden: 每次解码器的隐层输出
        :param enc_output: 编码器的输出
        """
        # print("x.shape",x.shape) #(64, 1)。64行1列,批量大小句子数为64,1列为该行句子的第N列的单词
        # 输入通过embedding层
        x = self.embedding(x)
        # print("x1.shape",x.shape) #(64, 1, 256)。(BATCH_SIZE, 输入序列最大长度句子的长度, 嵌入维度)
        # 使用注意力规则计算hidden与enc_output的'相互影响程度'
        context_vector, attention_weights = self.attention(enc_output, hidden)
        # print("tf.expand_dims(context_vector, 1).shape",tf.expand_dims(context_vector, 1).shape) #(64, 1, 1024)
        # 将这种'影响程度'与输入x拼接(这个操作也是注意力计算规则的一部分)
        x = tf.concat([tf.expand_dims(context_vector, 1), x], axis=-1)
        # print("x2.shape",x.shape) #(64, 1, 1280)
        # 将新的x输入到gru层中得到输出
        output, state = self.gru(x)
        # print("output1.shape",output.shape) #(64, 1, 1024) 即 (BATCH_SIZE, 1, 隐藏层中的隐藏神经元数量)
        # print("state.shape",state.shape) #(64, 1024) 即 (BATCH_SIZE, 隐藏层中的隐藏神经元数量)
        # 改变输出形状使其适应全连接层的输入形式
        output = tf.reshape(output, (-1, output.shape[2]))
        # print("output2.shape",output.shape) #(64, 1024) 即 (BATCH_SIZE, 隐藏层中的隐藏神经元数量)
        # 使用全连接层作为输出层
        # 输出的形状 == (批大小,vocab)
        x = self.fc(output)
        # print("x3.shape",x.shape) #(64, 4935) 即 (BATCH_SIZE, 目标序列的不重复单词的总数作为目标序列的字典大小)
        return x, state, attention_weights

#调用:
decoder = Decoder(vocab_tar_size, embedding_dim, units, BATCH_SIZE)
# sample_decoder_output, _, _ = decoder(tf.random.uniform((64, 1)), sample_output, sample_hidden)
# print ('Decoder output shape: (batch_size, vocab size) {}'.format(sample_decoder_output.shape)) #(64, 4935)
#构建模型的编码器部分:
class Encoder(tf.keras.Model):
    def __init__(self, vocab_size, embedding_dim, enc_units, batch_sz):
        """
        :param vocab_size: 非重复的词汇总数
        :param embedding_dim: 词嵌入的维度
        :enc_units: 编码器中GRU层的隐含节点数
        :batch_sz: 数据批次大小(每次参数更新用到的数据量)
        """
        super(Encoder, self).__init__()
        # 将变量传入类中
        self.batch_sz = batch_sz
        self.enc_units = enc_units
        # 实例化embedding层
        self.embedding = tf.keras.layers.Embedding(vocab_size, embedding_dim)
        """
        return_sequences:
                布尔值。是返回输出序列中的最后一个输出还是完整序列。 默认值:False。
                True代表返回GRU序列模型的每个时间步的输出(每个输出做连接操作)
        return_state:
                布尔值。 除输出外,是否返回最后一个状态。 默认值:False。
                True代表除了返回输出外,还需要返回最后一个隐层状态。
        recurrent_initializer:
                recurrent_kernel权重矩阵的初始化程序,用于对递归状态进行线性转换。 默认值:正交。
                'glorot_uniform'即循环状态张量的初始化方式为均匀分布。
        """
        # 实例化gru层
        # return_sequences=True代表返回GRU序列模型的每个时间步的输出(每个输出做连接操作)
        # return_state=True代表除了返回输出外,还需要返回最后一个隐层状态
        # recurrent_initializer='glorot_uniform'即循环状态张量的初始化方式为均匀分布
        self.gru = tf.keras.layers.GRU(self.enc_units,
                                       return_sequences=True,
                                       return_state=True,
                                       recurrent_initializer='glorot_uniform')

    def call(self, x, hidden):
        # 对输入进行embedding操作
        x = self.embedding(x)
        """initial_state:要传递给单元格的第一个调用的初始状态张量的列表(可选,默认为None,这将导致创建零填充的初始状态张量)。"""
        # 通过gru层获得最后一个时间步的输出和隐含状态
        output, state = self.gru(x, initial_state = hidden)
        return output, state

    def initialize_hidden_state(self):
        """ (BATCH_SIZE, 隐藏层中的隐藏神经元数量) """
        # gru层的隐含节点对应的参数张量以零张量初始化
        return tf.zeros((self.batch_sz, self.enc_units))

#调用:
# 实例化encoder
encoder = Encoder(vocab_inp_size, embedding_dim, units, BATCH_SIZE)

# 样本输入
# sample_hidden = encoder.initialize_hidden_state()
# sample_output, sample_hidden = encoder(example_input_batch, sample_hidden)
# #(64, 16, 1024) 即 (BATCH_SIZE, 输入序列最大长度句子的长度, 隐藏层中的隐藏神经元数量)
# print ('Encoder output shape: (batch size, sequence length, units) {}'.format(sample_output.shape))
# #(64, 1024) 即 (BATCH_SIZE, 隐藏层中的隐藏神经元数量)
# print ('Encoder Hidden state shape: (batch size, units) {}'.format(sample_hidden.shape))

  • 构建注意力机制的类:
    • 注意力机制的计算规则遵循以下公式:

 

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

あずにゃん

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值