注意力机制
Transformer与传统NLP特征提取类模型的区别主要在以下两点:
- Transformer是一个纯基于注意力机制的结构,并将自注意力机制和多头注意力机制的概念运用到模型中;
- 由于缺少RNN模型的时序性,Transformer引入了位置编码,在数据上而非模型中添加位置信息;
以上的处理带来了几个优点: - 更容易并行化,训练更加高效;
- 在处理长序列的任务中表现优秀,可以快速捕捉长距离中的关联信息。
计算注意力需要参考三个因素:Query、Key和Value - Query:任务内容
- Key:索引/标签
- Value: 答案
通过Query和Key进行点积计算得到相似度,同时避免Query和Key本身的“大小”影响到相似度的计算,所以需要除以\sqrt d_k
$$Attention Score(Q,K) = \frac{QK^T}{\sqrt d_k}$$
将相似度限制在0到1之间,并将其作用在value上。
$$Attention(Q,K,V) = softmax(\frac{QK^T}{\sqrt {d_k}})V$$上述实现中涉及到attention_mask,主要原因是在处理数据过程中为方便模型进行矩阵运算,将不同语料padding到相同长度,而padding部分是与任务无关的,所以在计算注意力分数时这些位置都要变为0。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import torch
class ScaledDotProductAttention(torch.nn.Module):
def __init__(self,dropout=0.):
super(ScaledDotProductAttention,self).__init__()
self.dropout = torch.nn.Dropout(1-dropout)
def forward(self,query,key,value,attention_mask = None):
embedding_size = query.size(-1)
scaling_factor = torch.sqrt(torch.tensor(embedding_size))
energy = torch.matmul(query,key.transpose(2,1)) / scaling_factor
if attention_mask:
energy = energy.masked_fill(mask==0,float("-1e20"))
attention = torch.softmax(energy,dim=-1)
attention = self.dropout(attention)
outputs = torch.matmul(attention,value)
return (outputs,attention)1
2
3
4
5
6
7
8def get_attention_mask(query_input_ids,key_input_ids,pad_idx):
query_lens = query_input_ids.size(0)
key_lens = key_input_ids.size(0)
query_mask = query_input_ids.eq(0).unsqueeze(-1).expand(query_input_ids.size(0),key_lens)
key_mask = key_input_ids.eq(0).unsqueeze(-1).expand(key_input_ids.size(0),query_lens)
key_mask = key_mask.transpose(0,1)
mask = torch.add(query_mask,key_mask)
return mask