网站搜索框,网络营销策略都有哪些,检测网站开发语言,学网页设计软件开发1 注意力提示
1.1 自主性的与非自主性的注意力提示
非自主性提示#xff1a; 可以简单地使用参数化的全连接层#xff0c;甚至是非参数化的最大汇聚层或平均汇聚层。 自主性提示 注意力机制与全连接层或汇聚层区别开来。在注意力机制的背景下#xff0c;自主性提示被称为查…1 注意力提示
1.1 自主性的与非自主性的注意力提示
非自主性提示 可以简单地使用参数化的全连接层甚至是非参数化的最大汇聚层或平均汇聚层。 自主性提示 注意力机制与全连接层或汇聚层区别开来。在注意力机制的背景下自主性提示被称为查询query。给定任何查询注意力机制通过注意力汇聚attention pooling将选择引导至感官输入sensory inputs例如中间特征表示。在注意力机制中这些感官输入被称为值value。 注意力机制通过注意力汇聚将查询自主性提示和键非自主性提示结合在一起实现对值感官输入的选择倾向
1.2 注意力的可视化
平均汇聚层可以被视为输入的加权平均值 其中各输入的权重是一样的。 实际上注意力汇聚得到的是加权平均的总和值 其中权重是在给定的查询和不同的键之间计算得出的。 为了可视化注意力权重需要定义一个show_heatmaps函数。 其输入matrices的形状是 要显示的行数要显示的列数查询的数目键的数目。
#save
def show_heatmaps(matrices, xlabel, ylabel, titlesNone, figsize(2.5, 2.5),cmapReds):显示矩阵热图d2l.use_svg_display()num_rows, num_cols matrices.shape[0], matrices.shape[1]fig, axes d2l.plt.subplots(num_rows, num_cols, figsizefigsize,sharexTrue, shareyTrue, squeezeFalse)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(), cmapcmap)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, axaxes, shrink0.6);在本例子中仅当查询和键相同时注意力权重为1否则为0。
attention_weights torch.eye(10).reshape((1, 1, 10, 10))
show_heatmaps(attention_weights, xlabelKeys, ylabelQueries)2 注意力汇聚Nadaraya-Watson 核回归
注意力机制的主要成分查询自主提示和键非自主提示之间的交互形成了注意力汇聚注意力汇聚有选择地聚合了值感官输入以生成最终的输出。 考虑下面这个回归问题给定的成对的“输入输出”数据集 {(x1, y1), . . . ,(xn, yn)}如何学习f来预测任意新输入x的输出yˆ f(x) 根据下面的非线性函数生成一个人工数据集其中加入的噪声项为ϵ
其中ϵ服从均值为0和标准差为0.5的正态分布。在这里生成了50个训练样本和50个测试样本。为了更好地可视化之后的注意力模式需要将训练样本进行排序。
n_train 50 # 训练样本数
x_train, _ torch.sort(torch.rand(n_train) * 5) # 排序后的训练样本def f(x):return 2 * torch.sin(x) x**0.8y_train f(x_train) torch.normal(0.0, 0.5, (n_train,)) # 训练样本的输出
x_test torch.arange(0, 5, 0.1) # 测试样本
y_truth f(x_test) # 测试样本的真实输出
n_test len(x_test) # 测试样本数
n_test下面的函数将绘制所有的训练样本样本由圆圈表示不带噪声项的真实数据生成函数f标记为“Truth”以及学习得到的预测函数标记为“Pred”。
def plot_kernel_reg(y_hat):d2l.plot(x_test, [y_truth, y_hat], x, y, legend[Truth, Pred],xlim[0, 5], ylim[-1, 5])d2l.plt.plot(x_train, y_train, o, alpha0.5);2.1 平均汇聚
基于平均汇聚来计算所有训练样本输出值的平均值
y_hat torch.repeat_interleave(y_train.mean(), n_test)
plot_kernel_reg(y_hat)显然 真实函数“Truth”和预测函数“Pred”相差很大。
2.2 非参数注意力汇聚
平均汇聚忽略了输入xi于是根据输入的位置对输出yi进行加权
K是核kernel。所描述的估计器被称为 Nadaraya-Watson核回归。 受此启发我们可以从注意力机制框架的角度重写成为一个更加通用的注意力汇聚attention pooling公式
x是查询(xi, yi)是键值对。注意力汇聚是yi的加权平均。将查询x和键xi之间的关系建模为 注意力权重attention weightα(x, xi)这个权重将被分配给每一个对应值yi。对于任何查询模型在所有键值对注意力权重都是一个有效的概率分布它们是非负的并且总和为1。 举个例子 考虑一个高斯核Gaussian kernel其定义为 将高斯核代入可以得到
在上面的表达式中如果一个键xi越是接近给定的查询x那么分配给这个键对应值yi的注意力权重就会越大也就“获得了更多的注意力”。 Nadaraya‐Watson核回归是一个非参数模型。接下来我们将基于这个非参数的注意力汇聚模型来绘制预测结果。从绘制的结果会发现新的模型预测线是平滑的并且比平均汇聚的预测更接近真实。
# X_repeat的形状:(n_test,n_train),
# 每一行都包含着相同的测试输入例如同样的查询
X_repeat x_test.repeat_interleave(n_train).reshape((-1, n_train))
# x_train包含着键。attention_weights的形状(n_test,n_train),
# 每一行都包含着要在给定的每个查询的值y_train之间分配的注意力权重
attention_weights nn.functional.softmax(-(X_repeat - x_train)**2 / 2, dim1)
# y_hat的每个元素都是值的加权平均值其中的权重是注意力权重
y_hat torch.matmul(attention_weights, y_train)
plot_kernel_reg(y_hat)现在来观察注意力的权重。 这里测试数据的输入相当于查询而训练数据的输入相当于键。 因为两个输入都是经过排序的因此由观察可知“查询-键”对越接近 注意力汇聚的[注意力权重]就越高。
d2l.show_heatmaps(attention_weights.unsqueeze(0).unsqueeze(0),xlabelSorted training inputs,ylabelSorted testing inputs)2.3 带参数注意力汇聚
在下面的查询x和键xi之间的距离乘以可学习参数w
接下来训练上面这个模型来学习注意力汇聚的参数w。
批量矩阵乘法
为了更有效地计算小批量数据的注意力我们可以利用深度学习开发框架中提供的批量矩阵乘法。 假设第一个小批量数据包含n个矩阵X1, . . . , Xn形状为a × b第二个小批量包含n个矩阵Y1, . . . , Yn形状为b × c。它们的批量矩阵乘法得到n个矩阵 X1Y1, . . . , XnYn形状为a × c。因此假定两个张量的形状分别是(n, a, b)和(n, b, c)它们的批量矩阵乘法输出的形状为(n, a, c)。 在注意力机制的背景中我们可以[使用小批量矩阵乘法来计算小批量数据中的加权平均值。
定义模型
定义Nadaraya‐Watson核回归的带参数版本为
class NWKernelRegression(nn.Module):def __init__(self, **kwargs):super().__init__(**kwargs)self.w nn.Parameter(torch.rand((1,), requires_gradTrue))def forward(self, queries, keys, values):# queries和attention_weights的形状为(查询个数“键值”对个数)queries queries.repeat_interleave(keys.shape[1]).reshape((-1, keys.shape[1]))self.attention_weights nn.functional.softmax(-((queries - keys) * self.w)**2 / 2, dim1)# values的形状为(查询个数“键值”对个数)return torch.bmm(self.attention_weights.unsqueeze(1),values.unsqueeze(-1)).reshape(-1)训练
将训练数据集变换为键和值用于训练注意力模型。 在带参数的注意力汇聚模型中 任何一个训练样本的输入都会和除自己以外的所有训练样本的“键值”对进行计算 从而得到其对应的预测输出。
# X_tile的形状:(n_trainn_train)每一行都包含着相同的训练输入
X_tile x_train.repeat((n_train, 1))
# Y_tile的形状:(n_trainn_train)每一行都包含着相同的训练输出
Y_tile y_train.repeat((n_train, 1))
# keys的形状:(n_trainn_train-1)
keys X_tile[(1 - torch.eye(n_train)).type(torch.bool)].reshape((n_train, -1))
# values的形状:(n_trainn_train-1)
values Y_tile[(1 - torch.eye(n_train)).type(torch.bool)].reshape((n_train, -1))训练带参数的注意力汇聚模型时使用平方损失函数MSE和随机梯度下降SGD。
net NWKernelRegression()
loss nn.MSELoss(reductionnone)
trainer torch.optim.SGD(net.parameters(), lr0.5)
animator d2l.Animator(xlabelepoch, ylabelloss, xlim[1, 5])for epoch in range(5):trainer.zero_grad()l loss(net(x_train, keys, values), y_train)l.sum().backward()trainer.step()print(fepoch {epoch 1}, loss {float(l.sum()):.6f})animator.add(epoch 1, float(l.sum()))训练完带参数的注意力汇聚模型后可以发现 尝试拟合带噪声的训练数据
# keys的形状:(n_testn_train)每一行包含着相同的训练输入例如相同的键
keys x_train.repeat((n_test, 1))
# value的形状:(n_testn_train)
values y_train.repeat((n_test, 1))
y_hat net(x_test, keys, values).unsqueeze(1).detach()
plot_kernel_reg(y_hat)预测结果绘制的线不如之前非参数模型的平滑。为什么新的模型更不平滑了呢 下面看一下输出结果的绘制图
d2l.show_heatmaps(net.attention_weights.unsqueeze(0).unsqueeze(0),xlabelSorted training inputs,ylabelSorted testing inputs)与非参数的注意力汇聚模型相比 带参数的模型加入可学习的参数后 曲线在注意力权重较大的区域变得更不平滑。