step-into-transformers

注意力机制

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$$
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import 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)
    上述实现中涉及到attention_mask,主要原因是在处理数据过程中为方便模型进行矩阵运算,将不同语料padding到相同长度,而padding部分是与任务无关的,所以在计算注意力分数时这些位置都要变为0。
    1
    2
    3
    4
    5
    6
    7
    8
    def 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

Transformer结构

通过Transformer实现文本机器翻译