网站目标关键词,建设银行杭州网站首页,公司网站建设济南兴田德润地址,网上商城运营方案#x1f468;#x1f393;作者简介#xff1a;一位即将上大四#xff0c;正专攻机器学习的保研er #x1f30c;上期文章#xff1a;机器学习深度学习——常见循环神经网络结构#xff08;RNN、LSTM、GRU#xff09; #x1f4da;订阅专栏#xff1a;机器… 作者简介一位即将上大四正专攻机器学习的保研er 上期文章机器学习深度学习——常见循环神经网络结构RNN、LSTM、GRU 订阅专栏机器学习深度学习 希望文章对你们有所帮助 机器学习深度学习——注意力提示、注意力池化核回归 注意力提示引入查询、键和值注意力的可视化小结 注意力池化Nadaraya-Watson核回归生成数据集平均池化非参数注意力池化带参数注意力池化批量矩阵乘法定义模型训练 小结 注意力提示
引入
之前讲过的CNN和RNN模型容易发现的一个点是他们并没有刻意的、主观的针对某个点去做训练和预测这是因为他们并没有注意力。讲到注意力我们就要知道心理学中的非自主性提示和自主性提示。 什么叫非自主性提示呢举个例子一群杀马特中间的老大是个光头根本不需要别人告知你你就会觉得这人很突兀很不一般也就是说人的注意力没有受到认知和意识的控制。 而自主性提示就是人的注意力受到认知和意识的控制因此注意力在基于自主性提示去辅助选择时将更为谨慎。受试者的主观意愿推动选择的力量也就更强大。
查询、键和值
自主性的与非自主性的注意力提示解释了人类的注意力的方式下面来看看如何通过这两种注意力提示用神经网络来设计注意力机制的框架 首先考虑简单的非自主性提示。要想将选择偏向于感官输入可以简单使用参数化的全连接层甚至是非参数化的最大池化层或平均池化层。 所以“是否包含自主性提示”将注意力机制与全连接层或池化层区别开来。 在注意力机制下自主性提示被称为查询给定任何查询注意力机制通过注意力池化将选择引导至感官输入。在注意力机制中这些感官输入被称为值每个值都有一个键配对可以想象成感官输入的非自主性提示。如下所示 注意汇聚就是池化。
注意力的可视化
平均池化层可以被视为输入的加权平均值其中各输入的权重是一样的。实际上注意力池化得到的是加权平均的总和值其中权重是在给定的查询和不同的键之间计算得出的。 下面来进行注意力可视化我们通过热力图的方式来展示定义一个show_heatmaps其输入matrices的形状是要显示的行数要显示的列数查询的数目键的数目。
import torch
from d2l import torch as d2l#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)
d2l.plt.show()输出结果
小结
1、人类的注意力是有限的、有价值和稀缺的资源。 2、使用非自主性和自主性提示有选择性地引导注意力前者基于突出性后者则依赖于意识。 3、注意力机制与全连接层或者池化层的区别源于增加的自主提示。 4、由于包含了自主性提示注意力机制与全连接的层或池化层不同。 5、注意力机制通过注意力池化使选择偏向于值感官输入其中包含查询自主性提示和键非自主性提示。键和值是成对的。 6、可视化查询和键之间的注意力权重是可行的。
注意力池化Nadaraya-Watson核回归
上面已经介绍了注意力机制的主要成分查询自主提示和键非自主提示之间的交互形成了注意力池化。注意力池化有选择地聚合了值感官输入以生成最终的输出。后面将会以简单例子来进行讲解。
import torch
from torch import nn
from d2l import torch as d2l生成数据集
简单起见考虑下面这个回归问题给定的成对的“输入输出”数据集如何学习f来预测任意新输入的x其输出y_hatf(x)。 生成一个人工数据集加入噪声项σ y i 2 s i n ( x i ) x i 0.8 σ y_i2sin(x_i)x_i^{0.8}\sigma yi2sin(xi)xi0.8σ 其中σ服从均值为0标准差0.5的正态分布。在这里生成了50个训练样本和50个测试样本。为了更好地可视化之后的注意力模式需要将训练样本进行排序。
import torch
from torch import nn
from d2l import torch as d2ln_train 50 # 训练样本数
x_train torch.sort(torch.rand(n_train) * 5)[0] # 排序后的训练样本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) # 测试样本数下面函数将绘制所有的训练样本圆圈表示不带噪声项的真实数据生成函数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)平均池化
其表达式为 f ( x ) 1 n ∑ i 1 n y i f(x)\frac{1}{n}\sum_{i1}^ny_i f(x)n1i1∑nyi 在绘制预测结果之前先介绍一下repeat_interleave函数可以看下面的这一篇博客看懂用法 【PyTorch】repeat_interleave()方法详解 现在我们可以绘制预测结果
y_hat torch.repeat_interleave(y_train.mean(), n_test)
plot_kernel_reg(y_hat)
d2l.plt.show()可以发现真实函数和预测函数的差距很大并不是很好的方式。
非参数注意力池化
很显然平均池化只注意y而没有注意x于是提出了更好的想法根据输入的位置对输出y进行加权 f ( x ) ∑ i 1 n K ( x − x i ) ∑ j 1 n K ( x − x j ) y i f(x)\sum_{i1}^n\frac{K(x-x_i)}{\sum_{j1}^nK(x-x_j)}y_i f(x)i1∑n∑j1nK(x−xj)K(x−xi)yi 其中K是核上面的估计器被称为Nadaraya-Watson核回归。我们可以从注意力机制的框架角度重写上式成为一个更通用的注意力池化公式 f ( x ) ∑ i 1 n α ( x , x i ) y i 其中 x 是查询 ( x i , y i ) 是键值对 f(x)\sum_{i1}^nα(x,x_i)y_i\\ 其中x是查询(x_i,y_i)是键值对 f(x)i1∑nα(x,xi)yi其中x是查询(xi,yi)是键值对 显然注意力池化就是yi的加权平均将查询x和键xi之间的关系建模为注意力权重α。容易知道对于任何查询模型在所有键值对注意力权重都是一个有效的概率分布它们是非负的并且总和为1。 比如我们可以考虑一个高斯核定义为 K ( u ) 1 2 π e x p ( − u 2 2 ) K(u)\frac{1}{\sqrt{2π}}exp(-\frac{u^2}{2}) K(u)2π 1exp(−2u2) 将高斯核带入上式得 f ( x ) ∑ i 1 n α ( x , x i ) y i ∑ i 1 n e x p ( − 1 2 ( x − x i ) 2 ) ∑ j 1 n e x p ( − 1 2 ( x − x j ) 2 ) y i ∑ i 1 n s o f t m a x ( − 1 2 ( x − x i ) 2 ) y i f(x)\sum_{i1}^nα(x,x_i)y_i\\ \sum_{i1}^n\frac{exp(-\frac{1}{2}(x-x_i)^2)}{\sum_{j1}^nexp(-\frac{1}{2}(x-x_j)^2)}y_i\\ \sum_{i1}^nsoftmax(-\frac{1}{2}(x-x_i)^2)y_i f(x)i1∑nα(x,xi)yii1∑n∑j1nexp(−21(x−xj)2)exp(−21(x−xi)2)yii1∑nsoftmax(−21(x−xi)2)yi 可以看出如果一个键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.plt.show()运行结果 现在我们来观察注意力的权重。这里测试数据的输入相当于查询而训练数据的输入相当于键。因为两个输入都是经过排序的因此由观察可知“查询-键”对越接近注意力汇聚的注意力权重就越高
# unsqueeze(0)表示增加第一维度增加两次维度
d2l.show_heatmaps(attention_weights.unsqueeze(0).unsqueeze(0),xlabelSorted training inputs,ylabelSorted testing inputs)
d2l.plt.show()运行结果
带参数注意力池化
非参数的Nadaraya-Watson核回归具有一致性的优点若有足够数据该模型会收敛到最优结果。尽管如此我们还是可以轻松地将可学习的参数集成到注意力池化中。 与之前不同在下面的查询x和键xi之前的距离乘以可学习的参数w f ( x ) ∑ i 1 n α ( x , x i ) y i ∑ i 1 n e x p ( − 1 2 ( ( x − x i ) w ) 2 ) ∑ j 1 n e x p ( − 1 2 ( ( x − x j ) w ) 2 ) y i ∑ i 1 n s o f t m a x ( − 1 2 ( ( x − x i ) w ) 2 ) ) y i f(x)\sum_{i1}^nα(x,x_i)y_i\\ \sum_{i1}^n\frac{exp(-\frac{1}{2}((x-x_i)w)^2)}{\sum_{j1}^nexp(-\frac{1}{2}((x-x_j)w)^2)}y_i\\ \sum_{i1}^nsoftmax(-\frac{1}{2}((x-x_i)w)^2))y_i f(x)i1∑nα(x,xi)yii1∑n∑j1nexp(−21((x−xj)w)2)exp(−21((x−xi)w)2)yii1∑nsoftmax(−21((x−xi)w)2))yi 下面将通过训练这个模型来学习注意力汇聚的参数。
批量矩阵乘法
对于矩阵乘法我们之前已经知道对于两个形状分别为a×b和b×c的矩阵进行矩阵乘法以后矩阵的形状就变成a×c的现在做个推广假设两个张量的形状分别为n×a×b和n×b×c则进行批量矩阵乘法后输出n×a×c。 在注意力机制的背景中我们可以使用小批量矩阵乘法来计算小批量数据中的加权平均值。
weights torch.ones((2, 10)) * 0.1
values torch.arange(20.0).reshape((2, 10))
print(torch.bmm(weights.unsqueeze(1), values.unsqueeze(-1)))输出结果
定义模型
使用小批量矩阵乘法定义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))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()))
d2l.plt.show()运行结果 接着绘制预测结果
# 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.plt.show()运行结果 容易发现在尝试拟合带噪声的训练数据时预测结果绘制的线不如之前非参数模型的平滑。 可以尝试查看热力图带参数的模型加入可学习的参数后曲线在注意力权重较大的区域变得更不平滑
d2l.show_heatmaps(net.attention_weights.unsqueeze(0).unsqueeze(0),xlabelSorted training inputs,ylabelSorted testing inputs)
d2l.plt.show()运行结果
小结
1、Nadaraya-Watson核回归是具有注意力机制的机器学习范例。 2、Nadaraya-Watson核回归的注意力池化是对训练数据中输出的加权平均。从注意力的角度来看分配给每个值的注意力权重取决于将值所对应的键和查询作为输入的函数。 3、注意力池化可以分为非参数型和带参数型。