
注意力机制作为一种模拟人脑信息处理的关键工具,在深度学习领域中得到了广泛应用。本系列实验旨在通过理论分析和代码演示,深入了解注意力机制的原理、类型及其在模型中的实际应用。
本文将介绍将介绍带有掩码的 softmax 操作
本系列实验使用了PyTorch深度学习框架,相关操作如下:
conda create -n DL python=3.7 conda activate DLpip install torch==1.8.1+cu102 torchvision==0.9.1+cu102 torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.htmlconda install matplotlib conda install scikit-learn软件包 | 本实验版本 | 目前最新版 |
|---|---|---|
matplotlib | 3.5.3 | 3.8.0 |
numpy | 1.21.6 | 1.26.0 |
python | 3.7.16 | |
scikit-learn | 0.22.1 | 1.3.0 |
torch | 1.8.1+cu102 | 2.0.1 |
torchaudio | 0.8.1 | 2.0.2 |
torchvision | 0.9.1+cu102 | 0.15.2 |
人脑每个时刻接收的外界输入信息非常多,包括来源于视 觉、听觉、触觉的各种各样的信息。单就视觉来说,眼睛每秒钟都会发送千万比特的信息给视觉神经系统。人脑通过注意力来解决信息超载问题,注意力分为两种主要类型:
在深度学习领域,注意力机制已被广泛应用,尤其是在自然语言处理任务中,如机器翻译、文本摘要、问答系统等。通过引入注意力机制,模型可以更灵活地处理不同位置的信息,提高对长序列的处理能力,并在处理输入时动态调整关注的重点。
(缩小方差,增大softmax梯度)
(非对称性)
【深度学习实验】注意力机制(一):注意力权重矩阵可视化(矩阵热图heatmap)


【深度学习实验】注意力机制(三):打分函数——加性注意力模型
(缩小方差,增大softmax梯度)
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]
self.scores = torch.bmm(queries, keys.transpose(1, 2)) / math.sqrt(d)
self.attention_weights = masked_softmax(self.scores, valid_lens)
return torch.bmm(self.dropout(self.attention_weights), values)__init__):
dropout: Dropout 正则化的概率。forward):
queries: 查询张量,形状为 (batch_size, num_queries, d)。keys: 键张量,形状为 (batch_size, num_kv_pairs, d)。values: 值张量,形状为 (batch_size, num_kv_pairs, value_size)。valid_lens: 有效长度张量,形状为 (batch_size,) 或 (batch_size, num_queries)。(batch_size, num_queries, value_size)。queries 和 keys 的点积,然后除以 进行缩放,其中
是查询或键的维度。
masked_softmax 函数计算注意力权重,根据有效长度对注意力进行掩码。class DotProductAttention2(nn.Module):
"""点积注意力"""
def __init__(self, dropout, **kwargs):
super(DotProductAttention2, self).__init__(**kwargs)
# 使用暂退法进行模型正则化
self.dropout = nn.Dropout(dropout)
def forward(self, queries, keys, values, valid_lens=None):
# P195:(8.3),(8.4)
# 在计算得分时不进行缩放操作(即不再除以sqrt(d))
self.scores = torch.bmm(queries, keys.transpose(1, 2))
self.attention_weights = masked_softmax(self.scores, valid_lens)
return torch.bmm(self.dropout(self.attention_weights), values)queries 和 keys 的点积。queries, keys = torch.normal(0, 1, (2, 1, 2)), torch.ones((2, 10, 2))
values = torch.arange(40, dtype=torch.float32).reshape(1, 10, 4).repeat(
2, 1, 1)
valid_lens = torch.tensor([2, 6])# 创建缩放点积注意力模型
attention = DotProductAttention(0.5)
attention.eval()
# 使用模型进行前向传播
attention(queries, keys, values, valid_lens)
# 创建点积注意力模型
attention2 = DotProductAttention2(0.5)
attention2.eval()
# 使用模型进行前向传播
attention2(queries, keys, values, valid_lens)
show_heatmaps 函数,通过热图的形式展示注意力权重。# 可视化缩放点积注意力权重
show_heatmaps(attention.attention_weights.reshape((1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')
# 可视化点积注意力权重
show_heatmaps(attention2.attention_weights.reshape((1, 1, 2, 10)),
xlabel='Keys', ylabel='Queries')

# 导入必要的库
import math
import torch
from torch import nn
import torch.nn.functional as F
from d2l import torch as d2l
from torch.utils import data
def masked_softmax(X, valid_lens):
"""通过在最后一个轴上掩蔽元素来执行softmax操作"""
# X:3D张量,valid_lens:1D或2D张量
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)
# 最后一轴上被掩蔽的元素使用一个非常大的负值替换,从而其softmax输出为0
X = d2l.sequence_mask(X.reshape(-1, shape[-1]), valid_lens, value=-1e6)
return nn.functional.softmax(X.reshape(shape), dim=-1)
def show_heatmaps(matrices, xlabel, ylabel, titles=None, figsize=(2.5, 2.5), cmap='Reds'):
"""显示矩阵热图"""
d2l.use_svg_display()
num_rows, num_cols = matrices.shape[0], matrices.shape[1]
fig, axes = d2l.plt.subplots(num_rows, num_cols, figsize=figsize,
sharex=True, sharey=True, squeeze=False)
for i, (row_axes, row_matrices) in enumerate(zip(axes, matrices)):
for j, (ax, matrix) in enumerate(zip(row_axes, row_matrices)):
pcm = ax.imshow(matrix.detach().numpy(), cmap=cmap)
if i == num_rows - 1:
ax.set_xlabel(xlabel)
if j == 0:
ax.set_ylabel(ylabel)
if titles:
ax.set_title(titles[j])
fig.colorbar(pcm, ax=axes, shrink=0.6)
class DotProductAttention(nn.Module):
"""缩放点积注意力"""
def __init__(self, dropout, **kwargs):
super(DotProductAttention, self).__init__(**kwargs)
# 使用暂退法进行模型正则化
self.dropout = nn.Dropout(dropout)
# queries的形状:(batch_size,查询的个数,d)
# keys的形状:(batch_size,“键-值”对的个数,d)
# values的形状:(batch_size,“键-值”对的个数,值的维度)
# valid_lens的形状:(batch_size,)或者(batch_size,查询的个数)
def forward(self, queries, keys, values, valid_lens=None):
print(queries)
d = queries.shape[-1]
print(d)
self.scores = torch.bmm(queries, keys.transpose(1, 2)) / math.sqrt(d)
print(self.scores)
self.attention_weights = masked_softmax(self.scores, valid_lens)
return torch.bmm(self.dropout(self.attention_weights), values)
class DotProductAttention2(nn.Module):
"""点积注意力"""
def __init__(self, dropout, **kwargs):
super(DotProductAttention2, self).__init__(**kwargs)
# 使用暂退法进行模型正则化
self.dropout = nn.Dropout(dropout)
# queries的形状:(batch_size,查询的个数,d)
# keys的形状:(batch_size,“键-值”对的个数,d)
# values的形状:(batch_size,“键-值”对的个数,值的维度)
# valid_lens的形状:(batch_size,)或者(batch_size,查询的个数)
def forward(self, queries, keys, values, valid_lens=None):
# P195:(8.3),(8.4)
# 在计算得分时不进行缩放操作(即不再除以sqrt(d))
self.scores = torch.bmm(queries, keys.transpose(1, 2))
print(self.scores)
self.attention_weights = masked_softmax(self.scores, valid_lens)
return torch.bmm(self.dropout(self.attention_weights), values)
queries, keys = torch.normal(0, 1, (2, 1, 2)), torch.ones((2, 10, 2))
values = torch.arange(40, dtype=torch.float32).reshape(1, 10, 4).repeat(
2, 1, 1)
valid_lens = torch.tensor([2, 6])
# 缩放点积注意力模型
attention = DotProductAttention(0.5)
attention.eval()
attention(queries, keys, values, valid_lens)
# 点积注意力模型
attention2 = DotProductAttention2(0.5)
attention2.eval()
attention2(queries, keys, values, valid_lens)