赞
踩
提示:主要是结合李沐老师在B站的课以及《动手深度学习》做的一些笔记
参考视频、参考代码。
不随意线索(非自主性提示)
非自主性提示是基于环境中物体的突出性和易见性。假设目前环境中有5个物品:一份报纸、一篇研究报告、一杯咖啡、一个笔记本和一本书,所有纸制品都是黑白印刷的,但是咖啡杯是红色的
。很自然咖啡杯相较于其他物品来说会更加引起人们的注意,如下图所示:
随意线索(自主性提示)
当我们想读书时,面对同样5个物体,这时我们的注意力便会放在书上。如下图所示
我的理解
以上述这个例子来说,不随意线索
就是没有主观意识,主要受环境等客观因素影响;而随意线索
是本身意识和认知产生,主要受主观因素影响。
注意力机制
只考虑不随意线索
考虑随意线索
随意线索
被称之为查询(query)
非参注意力池化层
给定数据
(
x
i
,
y
i
)
,
i
=
1
,
.
.
.
,
n
(x_i, y_i),i = 1,...,n
(xi,yi),i=1,...,n,平均池化是最简单的方案:
f
(
x
)
=
1
n
∑
i
y
i
f(x)=\frac{1}{n}\sum_iy_i
f(x)=n1∑iyi。注意
:
(
x
i
,
y
i
)
(x_i, y_i)
(xi,yi)是键值对,
x
x
x是query(随意线索)。
更好的方案Nadaraya-Watson核回归
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}^nK(x-x_j)}y_i
f(x)=i=1∑n∑j=1nK(x−xj)K(x−xi)yi注意
:
x
x
x是query,
x
j
x_j
xj是key,
y
i
y_i
yi是value。
K
(
x
)
K(x)
K(x)是一个核函数,其基本思路是若
x
x
x和
x
i
x_i
xi距离较近,则
K
(
x
−
x
i
)
K(x-x_i)
K(x−xi)越大。
若使用高斯核
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
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_{i=1}^n\frac{exp(-\frac{1}{2}{(x-x_i)^2})}{\sum_{j=1}^nexp(-\frac{1}{2}{(x-x_j)^2})}y_i\\=\sum_{i=1}^nsoftmax(-\frac{1}{2}{(x-x_i)}^2)y_i
f(x)=i=1∑n∑j=1nexp(−21(x−xj)2)exp(−21(x−xi)2)yi=i=1∑nsoftmax(−21(x−xi)2)yi参数化的注意力机制
在之前基础上引入可以学习的
w
w
w
f
(
x
)
=
∑
i
=
1
n
s
o
f
t
m
a
x
(
−
1
2
(
(
x
−
x
i
)
w
)
2
)
y
i
f(x)=\sum_{i=1}^nsoftmax(-\frac{1}{2}{((x-x_i)w)^2})y_i
f(x)=i=1∑nsoftmax(−21((x−xi)w)2)yi
上图理解
本质就是经过注意力评分函数
a
a
a和softmax层就得到了一个注意力权重,查询和键相似度越高,注意力权重就越大,然后将注意力权重与对应键的值相乘再相加就得到了最终输出。实质就是加权平均值。
扩展到高维度
假设query
q
∈
R
q
\bm{q}∈R^q
q∈Rq,
m
m
m对key-value
(
k
1
,
v
1
)
,
.
.
.
,
(\bm{k}_1,\bm{v}_1),...,
(k1,v1),..., 这里
k
i
∈
R
k
,
v
i
∈
R
v
\bm{k}_i∈R^k,\bm{v}_i∈R^v
ki∈Rk,vi∈Rv
注意力池化层
:
f
(
q
,
(
k
1
,
v
1
)
,
.
.
.
,
(
k
m
,
v
m
)
)
=
∑
i
=
1
m
α
(
q
,
k
i
)
v
i
∈
R
v
f(\bm{q},(\bm{k}_1,\bm{v}_1),...,(\bm{k}_m,\bm{v}_m))=\sum_{i=1}^mα(\bm{q},\bm{k}_i)\bm{v}_i∈R^v
f(q,(k1,v1),...,(km,vm))=i=1∑mα(q,ki)vi∈Rv
α
(
q
,
k
i
)
=
s
o
f
t
m
a
x
(
a
(
q
,
k
i
)
)
=
e
x
p
(
a
(
q
,
k
i
)
)
∑
j
=
1
m
e
x
p
(
a
(
q
,
k
j
)
)
∈
R
α(\bm{q},\bm{k}_i)=softmax(a(\bm{q},\bm{k}_i))=\frac{exp(a(\bm{q},\bm{k}_i))}{\sum_{j=1}^mexp(a(\bm{q},\bm{k}_j))}∈R
α(q,ki)=softmax(a(q,ki))=∑j=1mexp(a(q,kj))exp(a(q,ki))∈R其中
a
(
q
,
k
i
)
a(\bm{q},\bm{k}_i)
a(q,ki)是注意力分数,为常量。
Additive Attention(加性注意力)
Scale Dot-Product Attention(缩放点积注意力)
基本思想
使用独立学习得到的h组不同的线性投影来变换查询、键和值。然后,将h组变换后的查询、键和值并行地送到注意力汇聚中。最后,将这h个注意力汇聚的输出拼接在一起,并且通过另一个可以学习的线性投影进行变换,以产生最终输出。
其公式解析如下:
给定查询
q
∈
R
d
q
q∈R^{d_q}
q∈Rdq、
键
k
∈
R
d
k
键k∈R^{d_k}
键k∈Rdk和值
v
∈
R
d
v
v∈R^{d_v}
v∈Rdv,每个注意力头
h
i
(
i
=
1
,
.
.
.
,
h
)
h_i(i=1,...,h)
hi(i=1,...,h)的计算方法为:
h
i
=
f
(
W
i
(
q
)
q
,
W
i
(
k
)
k
,
W
i
(
v
)
v
)
∈
R
p
v
h_i = f(W^{(q)}_iq, W^{(k)}_ik, W^{(v)}_iv)∈R^{p_v}
hi=f(Wi(q)q,Wi(k)k,Wi(v)v)∈Rpv其中可以学习的参数包括
W
i
(
q
)
∈
R
p
q
×
d
q
W^{(q)}_i∈R^{p_q×d_q}
Wi(q)∈Rpq×dq、
W
i
(
k
)
∈
R
p
k
×
d
k
W^{(k)}_i∈R^{p_k×d_k}
Wi(k)∈Rpk×dk和
W
i
(
v
)
∈
R
p
v
×
d
v
W^{(v)}_i∈R^{p_v×d_v}
Wi(v)∈Rpv×dv,以及代表注意力汇聚的函数f。f可以是加性注意力和缩放点积注意力。多头注意力的输出需要经过另一个线性转换,它对应着
h
h
h个头连结后的结果,因此其可学习参数是
W
o
∈
R
p
o
×
h
p
v
W_o∈R^{p_o×hp_v}
Wo∈Rpo×hpv:
W
o
[
h
1
.
.
.
.
.
.
h
h
]
∈
R
p
o
W_o
提示
沐神代码初看起来是一个单头注意力,实则是将
h
h
h组全连接层的参数拼接起来了。
自注意力机制就是查询
q
q
q、键
k
k
k、值
v
v
v都相同
。现在我们假设我们有两句话,即batch_size大小为2,每句话长度为10,所以当前输入
x
x
x的shape就为(2, 10)。现在假设我们有注意力头为8个。一般在NLP来说,在输入到模型中时,我们会把每一个字映射为一个稠密向量,我们假设当前映射维度为96,所以经过“embbeding层”后,我们的输入
x
x
x维度变为了(2, 10, 96)(假设我们这里已经考虑了位置编码
),按照我们的上述要求,所以有:
q
1
=
k
1
=
v
1
=
q
2
=
k
1
=
v
2
=
.
.
.
=
q
8
=
k
8
=
v
8
=
x
q_1=k_1=v_1=q_2=k_1=v_2=...=q_8=k_8=v_8=x
q1=k1=v1=q2=k1=v2=...=q8=k8=v8=x
还有线性24个不同的线性变化层,如下:
l
i
n
e
a
r
q
1
、
l
i
n
e
a
r
k
1
、
l
i
n
e
a
r
v
1
、
.
.
.
、
l
i
n
e
a
r
q
8
、
l
i
n
e
a
r
k
8
、
l
i
n
e
a
r
v
8
linear_{q_1}、linear_{k_1}、linear_{v_1}、...、linear_{q_8}、linear_{k_8}、linear_{v_8}
linearq1、lineark1、linearv1、...、linearq8、lineark8、linearv8
即
q
1
q_1
q1先通过
l
i
n
e
a
r
q
1
linear_{q_1}
linearq1、
k
1
k_1
k1通过
l
i
n
e
a
r
k
1
linear_{k_1}
lineark1、
v
1
v_1
v1通过
l
i
n
e
a
r
v
1
linear_{v_1}
linearv1进行线性变化后,再采用注意力机制进行计算。这样的实现方法就很复杂。
在实际实现中,我们一般怎么实现的呢???
注意
96*8=768,所以首先在
x
x
x经过embbeding层后我们是直接将输入
x
x
x的shape转化为(2,10,768),看懂了吗,就是经过这个embbeding层后,我们已经将8个头的的输入
x
x
x拼接在一起了,可能有部分人会说,这样这8个头输入不就不相等了吗,其实这个不要紧,就算你相等,最后还不是经过线性层变化再用注意力机制求解的嘛,所以这是第一个技巧
。
第二个技巧
因为我们有
q
、
k
、
v
q、k、v
q、k、v,目前的话我们只得到了第一个,所以我们将输入
x
x
x经过如下变换就可以得到
q
、
k
、
v
q、k、v
q、k、v
import torch.nn as nn
c_attn = nn.Linear(768, 3*768)
q, k, v = c_attn(x).split(768, dim=2) # q、k、v的shape都为(2, 10, 768)
经过上述步骤后就得到了 q 、 k 、 v q、k、v q、k、v。然后做一个维度变换后,就可以使用注意力机制了,代码如下:
k = k.view(2, 10, 8, 768 // 8).transpose(1, 2) # (2, 8, 10, 96)
q = q.view(2, 10, 8, 768 // 8).transpose(1, 2) # (2, 8, 10, 96)
v = v.view(2, 10, 8, 768 // 8).transpose(1, 2) # (2, 8, 10, 96)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。