本文主要用于记录笔者深度学习注意力机制部分的学习过程,如有不准确之处,欢迎各路大神指出!谢谢!
自注意力机制(Attention Is All You Need)
from attention.SelfAttention import ScaledDotProductAttention
import torch
input=torch.randn(50,49,512)
sa = ScaledDotProductAttention(d_model=512, d_k=512, d_v=512, h=8)
output=sa(input,input,input)
print(output.shape)
- torch.randn()函数用于生成随机矩阵。例:
torch.randn(2, 3, 4) tensor([[[-2.0315, 0.1029, 0.4129, -0.3980], [-0.5129, -0.4984, -0.5934, 0.6140], [-0.0393, -2.1767, 0.1968, -0.5267]], [[ 0.7545, -0.1527, -1.5746, -0.8272], [ 0.6985, -1.1397, -1.2289, -0.3513], [-1.1178, 0.1474, -0.7278, -1.1510]]])
当参数有三个时,返回一个2行1列的张量,其中每个元素又是一个3行4列的张量。
下面开始重点解释ScaledDotProductAttention(缩放点积注意力)。
def masked_softmax(X, valid_lens):
if valid_lens is None:
return nn.functional.softmax(X, dim=-1)
else:
shape = X.shape
if valid_lens.dim() == 1:
valid_lens = torch.repeat_interleave(valid_lens, shape[1])
else:
valid_lens = valid_lens.reshape(-1)
X = d2l.sequence_mask(X.reshape(-1, shape[-1]), valid_lens,
value=-1e6)
return nn.functional.softmax(X.reshape(shape), dim=-1)
- softmax()函数的作用是将张量的每个元素缩放到(0,1)区间且和为1。
- torch.repeat_interleave()函数的作用是重复张量的元素。例:
>>> x = torch.tensor([1, 2, 3]) >>> x.repeat_interleave(2) tensor([1, 1, 2, 2, 3, 3]) # 传入多维张量,默认`展平` >>> y = torch.tensor([[1, 2], [3, 4]]) >>> torch.repeat_interleave(y, 2) tensor([1, 1, 2, 2, 3, 3, 4, 4])
- .reshape(-1)函数的作用是重新定义矩阵形状。例:
z = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]) z.shape (4, 4)
z.reshape(-1) array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])
- d2l.sequence_mask()函数的作用是给定一个矩阵A,一个张量B,根据张量B中的元素来屏蔽A中元素。
总结第一段代码的简单原理为:
传入的张量(X)可能只有一部分是有用(有效长度即valid_lens)的,所以需要将没用的部分屏蔽(mask)掉,只对剩下的部分进行softmax计算。比如,传入一个长度为5的张量,我们仅需前两个数据,则经过softmax()函数之后,后三个数加起来是0,前两个数加起来是1。
class DotProductAttention(nn.Module):
def __init__(self, dropout, **kwargs):
super(DotProductAttention, self).__init__(**kwargs)
self.dropout = nn.Dropout(dropout)
def forward(self, queries, keys, values, valid_lens=None):
d = queries.shape[-1]
scores = torch.bmm(queries, keys.transpose(1,2)) / math.sqrt(d)
self.attention_weights = masked_softmax(scores, valid_lens)
return torch.bmm(self.dropout(self.attention_weights), values)
- nn.Dropout()函数用于防止或减轻过拟合而使用的函数,一般用于全连接层。在训练过程的前向传播中,让每个神经元以一定概率p处于不激活的状态。
- torch.bmm()函数用于两个矩阵的乘法。
- transpose()函数用于交换矩阵的两个维度。
- math.sqrt(x)函数用于返回 x 的平方根。使用公式计算注意力
总结这段代码的简单原理为:
利用公式计算注意力分数(scores),使用masked_softmax()计算注意力权重,对注意力权重进行dropout计算后,最后返回注意力权重和values的乘积。
参考文章:
(12条消息) 神经网络学习小记录64——Pytorch 图像处理中注意力机制的解析与代码详解_Bubbliiiing的博客-CSDN博客
代码实现 缩放点积注意力 | scaled dot-product attention #51CTO博主之星评选#_LolitaAnn的技术博客_51CTO博客(13条消息) sequence_mask_取个名字真难呐的博客-CSDN博客_sequence_mask