感知:了解是什么,比如能够可以看到物体,如面前的一块屏幕
推理:基于感知到的现象,想象或推测未来会发生什么
知识:根据看到的数据或者现象,形成自己的知识
规划:根据学习到的知识,做出长远的规划
◆ Q1:领域专家是什么意思?
举个例子,比如我要做农业上的物体识别,我种了一棵树,想要看今年的收成怎么样,我有很多很多土地,用人去一个个查看很费力,于是我用一个无人机,将农作物的情况拍下来,假设得到了树的一些图片,而数据科学家不知道农作物什么样的情况是好,什么样是坏,于是领域专家进行解释,比如多少叶子算是好,什么样不好。同时数据科学家将领域专家的问题翻译成机器学习能做的任务。所以可以认为领域专家是提需求的人甲方,而数据科学家是乙方。
◆ Q2:符号学可以和机器学习融合起来吗?
确实是可以的。目前来说,符号学在深度学习有一些新的进展,以前说符号学就是做一些符号上的推理,目前深度学习如图神经网络,可以做一些比较复杂的推理。
Q3:说自然语言处理仅仅停留在感知层面似乎不太合适?因为语言的理解和产出不仅仅是感知,也涉及到语言知识和世界知识,也涉及到规划,比如机器规划下一步要做什么。
语言当然是一个很复杂的过程,我只是想说,自然语言处理我们做得还很一般,虽然能做一些感知以外的东西,但是我感觉是说,不如深度学习特别机器学习,在图片上的应用做得好一些。当然AI地图上也只是一个大致的分类。
◆ Q4:如何寻找自己领域的paper的经验吗?
因为大家如果现在去读paper的话,可能每天都有一百篇paper出来,你怎么样去找到你想要的paper,总不能天天看朋友圈推文,这样只能知道别人读过的paper,不会有自己独特的见解。
◆ Q5:以无人驾驶为例,误判率在不断下降,但误判的影响还是很严重的,有可能从已有的判断case(样例)得到修正,从而完全避免这样的错误吗?
无人驾驶中,任何一次出现的错误,都可能带来毁灭性的灾难。大家可能看到,特斯拉今天撞了,明天又撞了。所以说,无人驾驶对于错误率确实是非常注重的。
机器学习在学术界现在有很多关于uncertainty或者robustness的研究,就是说模型在数据偏移或者极端情况下会不会给出很不好的答案,我们不会特别深入去讲这个事情,但是无人驾驶这一块确实会通过大量的技术,比如说把不同的模型融合在一起,不是仅仅train一个模型,用多个模型来做投票。汽车有很多雷达、摄像头,它会通过不同的传感器来进行模型的融合,从而降低误差。
因为涉及到评价无人驾驶的特别技术,但在竞赛中我们会给大家看到如何通过融合多个模型提升精度的做法。
自主性的与非自主性的注意力提示解释了人类的注意力的方式,下面来看看如何通过这两种注意力提示,用神经网络来设计注意力机制的框架,
首先,考虑一个相对简单的状况,即只使用非自主性提示。要想将选择偏向于感官输入,则可以简单地使用参数化的全连接层,甚至是非参数化的最大汇聚层或平均汇聚层。
因此:
这个框架下的模型将成为本章的中心。然而,注意力机制的设计有许多替代方案。例如可以设计一个不可微的注意力模型,该模型可以使用强化学习方法(Mnih et al., 2014)进行训练。
平均汇聚层可以被视为输入的加权平均值,其中各输入的权重是一样的。实际上,注意力汇聚得到的是加权平均的总和值,其中权重是在给定的查询和不同的键之间计算得出的。
import torch
import matplotlib.pyplot as plt
from matplotlib_inline import backend_inline
# from d2l import torch as d2l
# metrices: shape, [要显示的行数,要显示的列数,查询的数目, 键的数目]
# 可视化注意力权重
#@save
def show_heatmaps(matrices, xlabel, ylabel, titles=None, figsize=(2.5, 2.5),
cmap='Reds'):
"""显示矩阵热图"""
backend_inline.set_matplotlib_formats('svg') # format
# 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)
fig, axes = 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);
# 当查询和键相同时,注意力权重为1,否则为0
attention_weights = torch.eye(10).reshape((1, 1, 10, 10))
# 显示注意力权重
show_heatmaps(attention_weights, xlabel='Keys', ylabel='Queries')
上面的栗子,仅当查询和键相同时,注意力权重为1,否则为0。后面也经常用show_heatmaps
函数来显示注意力权重。
【小结】
【练习】
(1)在机器翻译中通过解码序列词元时,其自主性提示可能是什么?非自主性提示和感官输入又是什么?
(2)随机生成一个10 X 10
矩阵并使用softmax运算来确保每行都是有效的概率分布,然后可视化输出注意力权重。
import torch
import torch.nn.functional as F
matrix = torch.randn(10, 10)
# 确保每行是有效的概率分布
softmax_matrix = F.softmax(matrix, dim = 1)
# 可视化注意力权重
show_heatmaps(softmax_matrix.unsqueeze(0).unsqueeze(0), "Keys", "Queries")
回归问题:给定的成对的“输入-输出”数据集 { ( x 1 , y 1 ) , … , ( x n , y n ) } \{(x_1, y_1), \ldots, (x_n, y_n)\} {(x1,y1),…,(xn,yn)},如何学习 f f f来预测任意新输入 x x x的输出 y ^ = f ( x ) \hat{y} = f(x) y^=f(x)?
【准备数据集】根据下面的非线性函数生成一个人工数据集,其中加入的噪声项为 ϵ \epsilon ϵ: y i = 2 sin ( x i ) + x i 0.8 + ϵ , y_i = 2\sin(x_i) + x_i^{0.8} + \epsilon, yi=2sin(xi)+xi0.8+ϵ,
# 导库,绘图格式设置
import torch
import torch.nn as nn
from d2l import torch as d2l
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', alpha=0.5)
# 和上面和下面的可视化函数结果等价
def use_svg_display():
"""Use the svg format to display a plot in Jupyter.
Defined in :numref:`sec_calculus`"""
backend_inline.set_matplotlib_formats('svg')
def set_figsize(figsize=(3.5, 2.5)):
"""Set the figure size for matplotlib.
Defined in :numref:`sec_calculus`"""
use_svg_display()
d2l.plt.rcParams['figure.figsize'] = figsize
def set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend):
"""Set the axes for matplotlib.
Defined in :numref:`sec_calculus`"""
axes.set_xlabel(xlabel)
axes.set_ylabel(ylabel)
axes.set_xscale(xscale)
axes.set_yscale(yscale)
axes.set_xlim(xlim)
axes.set_ylim(ylim)
if legend:
axes.legend(legend)
axes.grid()
def plot(X, Y=None, xlabel=None, ylabel=None, legend=None, xlim=None,
ylim=None, xscale='linear', yscale='linear',
fmts=('-', 'm--', 'g-.', 'r:'), figsize=(3.5, 2.5), axes=None):
"""Plot data points.
Defined in :numref:`sec_calculus`"""
if legend is None:
legend = []
set_figsize(figsize)
axes = axes if axes else d2l.plt.gca()
# Return True if `X` (tensor or list) has 1 axis
def has_one_axis(X):
return (hasattr(X, "ndim") and X.ndim == 1 or isinstance(X, list)
and not hasattr(X[0], "__len__"))
if has_one_axis(X):
X = [X]
if Y is None:
X, Y = [[]] * len(X), X
elif has_one_axis(Y):
Y = [Y]
if len(X) != len(Y):
X = X * len(Y)
axes.cla()
for x, y, fmt in zip(X, Y, fmts):
if len(x):
axes.plot(x, y, fmt)
else:
axes.plot(y, fmt)
set_axes(axes, xlabel, ylabel, xlim, ylim, xscale, yscale, legend)
def plot_kernel_reg(y_hat):
plot(x_test, [y_truth, y_hat], 'x', 'y', legend=['Truth', 'Pred'],
xlim=[0, 5], ylim=[-1, 5])
plt.plot(x_train, y_train, 'o', alpha=0.5);
# 1. build dataset
n_train = 50 # 训练样本数
x_train, _ = torch.sort(torch.rand(n_train) * 5) # 排序后的训练样本
def f(x):
return 2 * torch.sin(x) + x**0.8
y_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) # 测试样本数
# 2. 平均汇聚
y_hat = torch.repeat_interleave(y_train.mean(), n_test)
plot_kernel_reg(y_hat)
上面使用最简单的评估器——平均汇聚求所有训练样本输出值的平均值,显然没啥用,相差有点大。
显然,平均汇聚忽略了输入 x i x_i xi。
于是Nadaraya :cite:Nadaraya.1964
和Watson :cite:Watson.1964
提出了一个更好的想法,根据输入的位置对输出 y i y_i yi进行加权:
f ( x ) = ∑ i = 1 n K ( x − x i ) ∑ j = 1 n K ( x − x j ) y i , f(x) = \sum_{i=1}^n \frac{K(x - x_i)}{\sum_{j=1}^n K(x - x_j)} y_i, f(x)=i=1∑n∑j=1nK(x−xj)K(x−xi)yi,
其中 K K K是核(kernel)。上面公式所描述的估计器被称为Nadaraya-Watson核回归(Nadaraya-Watson kernel regression)。
但受此启发,我们可以上图中的注意力机制框架的角度重写 :eqref:eq_nadaraya-watson
,成为一个更加通用的注意力汇聚(attention pooling)公式:
f ( x ) = ∑ i = 1 n α ( x , x i ) y i , f(x) = \sum_{i=1}^n \alpha(x, x_i) y_i, f(x)=i=1∑nα(x,xi)yi,
其中 x x x是查询, ( x i , y i ) (x_i, y_i) (xi,yi)是键值对。比较上面公式和平均汇聚公式,注意力汇聚是 y i y_i yi的加权平均。
将查询 x x x和键 x i x_i xi之间的关系建模为注意力权重(attention weight) α ( x , x i ) \alpha(x, x_i) α(x,xi),如上一个公式所示,这个权重将被分配给每一个对应值 y i y_i yi。对于任何查询,模型在所有键值对注意力权重都是一个有效的概率分布:它们是非负的,并且总和为1。
为了更好地理解注意力汇聚,下面考虑一个高斯核(Gaussian kernel),其定义为:
K ( u ) = 1 2 π exp ( − u 2 2 ) . K(u) = \frac{1}{\sqrt{2\pi}} \exp(-\frac{u^2}{2}). K(u)=2π1exp(−2u2).
将高斯核代入 第一个公式和第二个公式可以得到:
f ( x ) = ∑ i = 1 n α ( x , x i ) y i = ∑ i = 1 n exp ( − 1 2 ( x − x i ) 2 ) ∑ j = 1 n exp ( − 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 . \begin{aligned} f(x) &=\sum_{i=1}^n \alpha(x, x_i) y_i\\ &= \sum_{i=1}^n \frac{\exp\left(-\frac{1}{2}(x - x_i)^2\right)}{\sum_{j=1}^n \exp\left(-\frac{1}{2}(x - x_j)^2\right)} y_i \\&= \sum_{i=1}^n \mathrm{softmax}\left(-\frac{1}{2}(x - x_i)^2\right) y_i. \end{aligned} f(x)=i=1∑nα(x,xi)yi=i=1∑n∑j=1nexp(−21(x−xj)2)exp(−21(x−xi)2)yi=i=1∑nsoftmax(−21(x−xi)2)yi.
在上面公式中,如果一个键 x i x_i xi越是接近给定的查询 x x x,那么分配给这个键对应值 y i y_i yi的注意力权重就会越大,也就“获得了更多的注意力”。
值得注意的是,Nadaraya-Watson核回归是一个非参数模型。因此,上面公式是非参数的注意力汇聚(nonparametric attention pooling)模型。下面将基于这个非参数的注意力汇聚模型来绘制预测结果。从绘制的结果会发现新的模型预测线是平滑的,并且比平均汇聚的预测更接近真实。
# 非参数注意力汇聚(Nd核回归)
# 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, dim=1)
# y_hat的每个元素都是值的加权平均值,其中的权重是注意力权重
y_hat = torch.matmul(attention_weights, y_train)
plot_kernel_reg(y_hat)
# 注意力权重可视化
show_heatmaps(attention_weights.unsqueeze(0).unsqueeze(0),
xlabel='Sorted training inputs',
ylabel='Sorted testing inputs')
【批量矩阵乘法】
为了更有效地计算小批量数据的注意力,可以利用深度学习开发框架中提供的批量矩阵乘法。
假设第一个小批量数据包含 n n n个矩阵 X 1 , … , X n \mathbf{X}_1,\ldots, \mathbf{X}_n X1,…,Xn,形状为 a × b a\times b a×b,第二个小批量包含 n n n个矩阵 Y 1 , … , Y n \mathbf{Y}_1, \ldots, \mathbf{Y}_n Y1,…,Yn,形状为 b × c b\times c b×c。
它们的批量矩阵乘法得到 n n n个矩阵 X 1 Y 1 , … , X n Y n \mathbf{X}_1\mathbf{Y}_1, \ldots, \mathbf{X}_n\mathbf{Y}_n X1Y1,…,XnYn,形状为 a × c a\times c a×c。因此,[假定两个张量的形状分别是 ( n , a , b ) (n,a,b) (n,a,b)和 ( n , b , c ) (n,b,c) (n,b,c),它们的批量矩阵乘法输出的形状为 ( n , a , c ) (n,a,c) (n,a,c)]。
# 批量矩阵乘法
X = torch.ones((3, 1, 5))
Y = torch.ones((3, 5, 9))
# torch.Size([3, 1, 9])
torch.bmm(X, Y).shape
# 小批量矩阵乘法
weights = torch.ones((2, 10)) * 0.1
values = torch.arange(20.0).reshape((2, 10))
torch.bmm(weights.unsqueeze(1), values.unsqueeze(-1)).shape
# torch.Size([2, 1, 1])
非参数的Nadaraya-Watson核回归具有一致性(consistency)的优点:如果有足够的数据,此模型会收敛到最优结果。尽管如此,我们还是可以轻松地将可学习的参数集成到注意力汇聚中。
例如,与2.2模型略有不同,在下面的查询 x x x和键 x i x_i xi之间的距离乘以可学习参数 w w w:
f ( x ) = ∑ i = 1 n α ( x , x i ) y i = ∑ i = 1 n exp ( − 1 2 ( ( x − x i ) w ) 2 ) ∑ j = 1 n exp ( − 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 . \begin{aligned}f(x) &= \sum_{i=1}^n \alpha(x, x_i) y_i \\&= \sum_{i=1}^n \frac{\exp\left(-\frac{1}{2}((x - x_i)w)^2\right)}{\sum_{j=1}^n \exp\left(-\frac{1}{2}((x - x_j)w)^2\right)} y_i \\&= \sum_{i=1}^n \mathrm{softmax}\left(-\frac{1}{2}((x - x_i)w)^2\right) y_i.\end{aligned} f(x)=i=1∑nα(x,xi)yi=i=1∑n∑j=1nexp(−21((x−xj)w)2)exp(−21((x−xi)w)2)yi=i=1∑nsoftmax(−21((x−xi)w)2)yi.
# 1. 定义模型
class NWKernelRegression(nn.Module):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.w = nn.Parameter(torch.rand((1,), requires_grad=True))
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, dim=1)
# values的形状为(查询个数,“键-值”对个数)
return torch.bmm(self.attention_weights.unsqueeze(1),
values.unsqueeze(-1)).reshape(-1)
# 2. model train
# X_tile的形状:(n_train,n_train),每一行都包含着相同的训练输入
X_tile = x_train.repeat((n_train, 1))
# Y_tile的形状:(n_train,n_train),每一行都包含着相同的训练输出
Y_tile = y_train.repeat((n_train, 1))
# keys的形状:('n_train','n_train'-1)
keys = X_tile[(1 - torch.eye(n_train)).type(torch.bool)].reshape((n_train, -1))
# values的形状:('n_train','n_train'-1)
values = Y_tile[(1 - torch.eye(n_train)).type(torch.bool)].reshape((n_train, -1))
net = NWKernelRegression()
loss = nn.MSELoss(reduction='none')
trainer = torch.optim.SGD(net.parameters(), lr=0.5)
animator = d2l.Animator(xlabel='epoch', ylabel='loss', 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(f'epoch {epoch + 1}, loss {float(l.sum()):.6f}')
animator.add(epoch + 1, float(l.sum()))
使用平方损失函数和随机梯度下降进行训练。
分析上图:在拟合带噪声的数据时,预测的曲线没有之前非参数模型的预测曲线平滑。因为前者加入可学习的参数后,曲线在注意力权重较大的地方变得更加不平滑。
show_heatmaps(net.attention_weights.unsqueeze(0).unsqueeze(0),
xlabel='Sorted training inputs',
ylabel='Sorted testing inputs')
【小结】
第二节使用了高斯核来对查询和键之间的关系建模。高斯核指数部分可以视为注意力评分函数(attention scoring function),简称评分函数(scoring function),然后把这个函数的输出结果输入到softmax函数中进行运算。通过上述步骤,将得到与键对应的值的概率分布(即注意力权重)。最后,注意力汇聚的输出就是基于这些注意力权重的值的加权和。
从宏观来看,上述算法可以用来实现对应的注意力机制框架。说明了如何将注意力汇聚的输出计算成为值的加权和,其中 a a a表示注意力评分函数。由于注意力权重是概率分布,因此加权和其本质上是加权平均值。
用数学语言描述,假设有一个查询 q ∈ R q \mathbf{q} \in \mathbb{R}^q q∈Rq和 m m m个“键-值”对 ( k 1 , v 1 ) , … , ( k m , v m ) (\mathbf{k}_1,\mathbf{v}_1), \ldots, (\mathbf{k}_m, \mathbf{v}_m) (k1,v1),…,(km,vm),其中 k i ∈ R k \mathbf{k}_i \in \mathbb{R}^k ki∈Rk, v i ∈ R v \mathbf{v}_i \in \mathbb{R}^v vi∈Rv。注意力汇聚函数 f f f就被表示成值的加权和:
f ( q , ( k 1 , v 1 ) , … , ( k m , v m ) ) = ∑ i = 1 m α ( q , k i ) v i ∈ R v , f(\mathbf{q}, (\mathbf{k}_1, \mathbf{v}_1), \ldots, (\mathbf{k}_m, \mathbf{v}_m)) = \sum_{i=1}^m \alpha(\mathbf{q}, \mathbf{k}_i) \mathbf{v}_i \in \mathbb{R}^v, f(q,(k1,v1),…,(km,vm))=i=1∑mα(q,ki)vi∈Rv,
其中查询 q \mathbf{q} q和键 k i \mathbf{k}_i ki的注意力权重(标量)是通过注意力评分函数 a a a将两个向量映射成标量,再经过softmax运算得到的:
α ( q , k i ) = s o f t m a x ( a ( q , k i ) ) = exp ( a ( q , k i ) ) ∑ j = 1 m exp ( a ( q , k j ) ) ∈ R . \alpha(\mathbf{q}, \mathbf{k}_i) = \mathrm{softmax}(a(\mathbf{q}, \mathbf{k}_i)) = \frac{\exp(a(\mathbf{q}, \mathbf{k}_i))}{\sum_{j=1}^m \exp(a(\mathbf{q}, \mathbf{k}_j))} \in \mathbb{R}. α(q,ki)=softmax(a(q,ki))=∑j=1mexp(a(q,kj))exp(a(q,ki))∈R.
正如上图所示,选择不同的注意力评分函数 a a a会导致不同的注意力汇聚操作。本节将介绍两个流行的评分函数,稍后将用他们来实现更复杂的注意力机制。
【小结】
【小结】
在实现多头注意力之前,让我们用数学语言将这个模型形式化地描述出来。
给定查询 q ∈ R d q \mathbf{q} \in \mathbb{R}^{d_q} q∈Rdq、键 k ∈ R d k \mathbf{k} \in \mathbb{R}^{d_k} k∈Rdk和值 v ∈ R d v \mathbf{v} \in \mathbb{R}^{d_v} v∈Rdv,每个注意力头 h i \mathbf{h}_i hi( i = 1 , … , h i = 1, \ldots, h i=1,…,h)的计算方法为:
h i = f ( W i ( q ) q , W i ( k ) k , W i ( v ) v ) ∈ R p v , \mathbf{h}_i = f(\mathbf W_i^{(q)}\mathbf q, \mathbf W_i^{(k)}\mathbf k,\mathbf W_i^{(v)}\mathbf v) \in \mathbb R^{p_v}, hi=f(Wi(q)q,Wi(k)k,Wi(v)v)∈Rpv,
其中,可学习的参数包括 W i ( q ) ∈ R p q × d q \mathbf W_i^{(q)}\in\mathbb R^{p_q\times d_q} Wi(q)∈Rpq×dq、 W i ( k ) ∈ R p k × d k \mathbf W_i^{(k)}\in\mathbb R^{p_k\times d_k} Wi(k)∈Rpk×dk和 W i ( v ) ∈ R p v × d v \mathbf W_i^{(v)}\in\mathbb R^{p_v\times d_v} Wi(v)∈Rpv×dv,以及代表注意力汇聚的函数 f f f。 f f f可以是第三节中的加性注意力和缩放点积注意力。多头注意力的输出需要经过另一个线性转换,它对应着 h h h个头连结后的结果,因此其可学习参数是 W o ∈ R p o × h p v \mathbf W_o\in\mathbb R^{p_o\times h p_v} Wo∈Rpo×hpv:
W o [ h 1 ⋮ h h ] ∈ R p o . \mathbf W_o \begin{bmatrix}\mathbf h_1\\\vdots\\\mathbf h_h\end{bmatrix} \in \mathbb{R}^{p_o}. Wo h1⋮hh ∈Rpo.
基于这种设计,每个头都可能会关注输入的不同部分,可以表示比简单加权平均值更复杂的函数。
给定一个由词元组成的输入序列 x 1 , … , x n \mathbf{x}_1, \ldots, \mathbf{x}_n x1,…,xn,其中任意 x i ∈ R d \mathbf{x}_i \in \mathbb{R}^d xi∈Rd( 1 ≤ i ≤ n 1 \leq i \leq n 1≤i≤n)。该序列的自注意力输出为一个长度相同的序列 y 1 , … , y n \mathbf{y}_1, \ldots, \mathbf{y}_n y1,…,yn,其中:
y i = f ( x i , ( x 1 , x 1 ) , … , ( x n , x n ) ) ∈ R d \mathbf{y}_i = f(\mathbf{x}_i, (\mathbf{x}_1, \mathbf{x}_1), \ldots, (\mathbf{x}_n, \mathbf{x}_n)) \in \mathbb{R}^d yi=f(xi,(x1,x1),…,(xn,xn))∈Rd
根据之前定义的注意力汇聚函数 f f f: f ( x ) = ∑ i = 1 n α ( x , x i ) y i f(x)=\sum_{i=1}^n \alpha\left(x, x_i\right) y_i f(x)=i=1∑nα(x,xi)yi
下面的代码片段是基于多头注意力对一个张量完成自注意力的计算,张量的形状为(批量大小,时间步的数目或词元序列的长度, d d d)。输出与输入的张量形状相同。
在处理词元序列时,循环神经网络是逐个的重复地处理词元的,而自注意力则因为并行计算而放弃了顺序操作。为了使用序列的顺序信息,通过在输入表示中添加位置编码(positional encoding)来注入绝对的或相对的位置信息。位置编码可以通过学习得到也可以直接固定得到。接下来描述的是基于正弦函数和余弦函数的固定位置编码( (Vaswani et al., 2017)。)。
假设输入表示 X ∈ R n × d \mathbf{X} \in \mathbb{R}^{n \times d} X∈Rn×d包含一个序列中 n n n个词元的 d d d维嵌入表示。位置编码使用相同形状的位置嵌入矩阵 P ∈ R n × d \mathbf{P} \in \mathbb{R}^{n \times d} P∈Rn×d输出 X + P \mathbf{X} + \mathbf{P} X+P,矩阵第 i i i行、第 2 j 2j 2j列和 2 j + 1 2j+1 2j+1列上的元素为:
p i , 2 j = sin ( i 1000 0 2 j / d ) , p i , 2 j + 1 = cos ( i 1000 0 2 j / d ) . \begin{aligned} p_{i, 2j} &= \sin\left(\frac{i}{10000^{2j/d}}\right),\\p_{i, 2j+1} &= \cos\left(\frac{i}{10000^{2j/d}}\right).\end{aligned} pi,2jpi,2j+1=sin(100002j/di),=cos(100002j/di).
在解释这个设计之前,让我们先在下面的PositionalEncoding
类中实现它。
除了捕获绝对位置信息之外,上述的位置编码还允许模型学习得到输入序列中相对位置信息。这是因为对于任何确定的位置偏移 δ \delta δ,位置 i + δ i + \delta i+δ处的位置编码可以线性投影位置 i i i处的位置编码来表示。
这种投影的数学解释是,令 ω j = 1 / 1000 0 2 j / d \omega_j = 1/10000^{2j/d} ωj=1/100002j/d,对于任何确定的位置偏移 δ \delta δ,中的任何一对 ( p i , 2 j , p i , 2 j + 1 ) (p_{i, 2j}, p_{i, 2j+1}) (pi,2j,pi,2j+1)都可以线性投影到
( p i + δ , 2 j , p i + δ , 2 j + 1 ) (p_{i+\delta, 2j}, p_{i+\delta, 2j+1}) (pi+δ,2j,pi+δ,2j+1):
[ cos ( δ ω j ) sin ( δ ω j ) − sin ( δ ω j ) cos ( δ ω j ) ] [ p i , 2 j p i , 2 j + 1 ] = [ cos ( δ ω j ) sin ( i ω j ) + sin ( δ ω j ) cos ( i ω j ) − sin ( δ ω j ) sin ( i ω j ) + cos ( δ ω j ) cos ( i ω j ) ] = [ sin ( ( i + δ ) ω j ) cos ( ( i + δ ) ω j ) ] = [ p i + δ , 2 j p i + δ , 2 j + 1 ] , \begin{aligned} &\begin{bmatrix} \cos(\delta \omega_j) & \sin(\delta \omega_j) \\ -\sin(\delta \omega_j) & \cos(\delta \omega_j) \\ \end{bmatrix} \begin{bmatrix} p_{i, 2j} \\ p_{i, 2j+1} \\ \end{bmatrix}\\ =&\begin{bmatrix} \cos(\delta \omega_j) \sin(i \omega_j) + \sin(\delta \omega_j) \cos(i \omega_j) \\ -\sin(\delta \omega_j) \sin(i \omega_j) + \cos(\delta \omega_j) \cos(i \omega_j) \\ \end{bmatrix}\\ =&\begin{bmatrix} \sin\left((i+\delta) \omega_j\right) \\ \cos\left((i+\delta) \omega_j\right) \\ \end{bmatrix}\\ =& \begin{bmatrix} p_{i+\delta, 2j} \\ p_{i+\delta, 2j+1} \\ \end{bmatrix}, \end{aligned} ===[cos(δωj)−sin(δωj)sin(δωj)cos(δωj)][pi,2jpi,2j+1][cos(δωj)sin(iωj)+sin(δωj)cos(iωj)−sin(δωj)sin(iωj)+cos(δωj)cos(iωj)][sin((i+δ)ωj)cos((i+δ)ωj)][pi+δ,2jpi+δ,2j+1],
2 × 2 2\times 2 2×2投影矩阵不依赖于任何位置的索引 i i i。
打卡日:19号周日、21号周二、23号周四、28号周二、30号周四。
内容 | 任务 | 预估天数 | 任务时间 | 完成情况 |
---|---|---|---|---|
task1 | dl基础+CP10-注意力机制(一) | 一天 | 3月19号周日 | 完成 |
task2 | CP10-注意力机制(二)10.1-10.4 | 两天 | 3月20、21号周二 | |
task3 | CP10-注意力机制(三) 10.5-10.7 | 两天 | 3月22号周三、23号周四 | |
task4 | CP14-预训练(一)14.8-14.9 | 两天 | 3月24号周五、25号周六 | |
task5 | CP14-预训练(二) 14.10 | 两天 | 3月26周日、27、28周二 | |
task6 | CP15-NLP应用15.4-15.5 | 两天 | 3月29号、30号周四 |
[1] 动手学深度学习.李沐
[2] 动手学深度学习-文本处理
[3] 动手学深度学习-注意力机制CP10
[4] https://discuss.d2l.ai
[5] 教材:https://zh-v2.d2l.ai/
[6] 视频: https://space.bilibili.com/1567748478/channel/seriesdetail?sid=358497
[7] 笔记:https://github.com/MLNLP-World/DeepLearning-MuLi-Notes/tree/main/notes
[8] 竞赛:https://tianchi.aliyun.com/competition/entrance/231784/introduction?spm=5176.12281973.0.0.7c47106baWMBl3
[9] OpenI:https://openi.pcl.ac.cn/Datawhale/d2l
[10] 注意力汇聚:Nadaraya-Watson 核回归——动手学dl的讨论区