注意力机制代码研读

论文名称

原文:

Effective Approaches to Attention-based Neural Machine Translation

本篇主要记录的是global attention的用法
文章中,机器翻译的模型是encoder-decoder模型。
其中将LSTM隐层状态的输出作为注意力层的输入。
这里将输入的向量记为 h t h_t ht
文章里面提到了两个向量:
第一步:计算出contect_vector: c t c_t ct:,通过该向量我们可以推断出当前的target对象和所有source的联系。
第二步:计算出 c t c_t ct之后,将其和原本的 h t h_t ht进行拼接,从而可以产生一个attention_state
公式如下:
在这里插入图片描述
第三步:将得到的 h t ′ h'_{t} ht通过一个softmax函数,从而就可以求得它的概率分布:公式如下在这里插入图片描述
那么如何计算 c t c_t ct呢?

global attention

需要注意的是,global考虑编码器的所有隐层状态。
这里提到一个对齐向量(align_vector),它是由当前的target_hidden_state和每一个source_hidden_state推出来的,这里其实可以将 a t a_t at看作每一个输入结点对于该输出结点的注意力分配系数。
计算公式如下
在这里插入图片描述
那么这里的score要如何计算呢?三种计算方法:
在这里插入图片描述
下面看一下代码吧:
这里的attention_mechanism:是seq to one的,而文章中提到的机器翻译其实是seq to seq的。
自定义一个Attention layer层。
这里Attention 是继承了Layer层的
一._call_函数中:

  1. hidden_states就等于当前的输入。
  2. hidden_size的值代表输入向量的维度的大小
  3. score_second_part:将输入的hidden_states放入Dense层中,其实就是 h s ′ h'_s hs
    如何得到 h ’ s h’_s hs:输入向量乘以1个权重矩阵W。这里的W是可训练的。
    其中:hidden_state的维度大小为(batch,time_step,hidden_size).
    W的维度大小为(hidden_size,hidden_size)。
    矩阵的相乘:不需要管batch,即(time_step,hidden_size)和(hidden_size,hidden_size)作dot
    输出的score_second_part的维度大小为
    (batch,time_step,hidden_size).
  4. h_t:作者将得到的the last hidden state作为hidden_target.
  5. 计算attention_weight(score)即 h t 和 h ‘ s h_t和h`_s hths作dot,内积是在h_s的2维度和h_t的一维度作内积。
    所以下面的代码中出现了axes=[1,2]。具体为什么,可以参考之前写的tensordot函数的原理,这里大概提一下,由于hidden_size和hidden_size的大小是相同的,所以会被抵消掉维度。
    h_s的维度:(batch,time_step,hidden_size)
    h_t的维度:(batch,hidden_size)
    得到的attention_weight的形状大小为
    (batch,time_step)
  6. 计算context_vector:即输入的hidden_state和attention_weight作内积,对应元素相加再求和。
    这里需要注意以下:dot的时候要选择对应的轴。和上面是一样的。
  7. 之后的几步就是上面的公式了,将得到的 c t c_t ct h t h_t ht进行拼接,然后输入到全连接层中,使用的激活函数是tanh。得到最终的attention_vector
from tensorflow.keras.layers import Dense, Lambda, Dot, Activation, Concatenate
from tensorflow.keras.layers import Layer

class Attention(Layer):
    def __init__(self, units=128, **kwargs):
        self.units = units
        super().__init__(**kwargs)

    def __call__(self, inputs):
        """
        Many-to-one attention mechanism for Keras.
        @param inputs: 3D tensor with shape (batch_size, time_steps, input_dim).
        @return: 2D tensor with shape (batch_size, 128)
        @author: felixhao28, philipperemy.
        """
        hidden_states = inputs
        hidden_size = int(hidden_states.shape[2])
        
        score_second_part = Dense(hidden_size, use_bias=False, name='attention_score_vec')(hidden_states)
        
        h_t = Lambda(lambda x: x[:,-1,:], output_shape=(hidden_size,), name='last_hidden_state')(hidden_states)
        
        score = Dot(axes=[1, 2], name='attention_score')([h_t, score_second_part])
        
        attention_weights = Activation('softmax', name='attention_weight')(score)
        
        context_vector = Dot(axes=[1, 1], name='context_vector')([hidden_states, attention_weights])
        
        pre_activation = Concatenate(name='attention_output')([context_vector, h_t])
        
        attention_vector = Dense(self.units, use_bias=False, activation='tanh', name='attention_vector')(pre_activation)
        
        return attention_vector

    def get_config(self):
        return {'units': self.units}

    @classmethod
    def from_config(cls, config):
        return cls(**config)

大体的思路就是这样的,我自己也是刚看这块的内容,记录一下,要不然很快就会忘记。
如果有错误,希望大家可以指出来。
贴一下这个项目的整理代码:
项目整个代码

python知识点:
python中的self相当于c++中的this指针,打印出来可以看到,是test对象的地址。
_call函数:可以使得对象像函数一样被调用:如下所示:

class test:
	def __init__(self,name,age):
		self.x=name
		self.y=age

	def __call__(self):
		print("姓名是",self.x)
		print("年龄是",self.y)
		print(self)


a=test("tianjinghua",5)
a()
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值