, 则 缩放点积注意力 (scaled dot-product attention)评分函数为:a ( q , k ) = q ⊤ k / d a(\mathbf q, \mathbf k) = \mathbf{q}^\top \mathbf{k} /\sqrt{d} a ( q , k ) = q ⊤ k / d
考虑小批量计算时,整个注意力机制的输出可以写成:
s o f t m a x ( Q K ⊤ d ) V \mathrm{softmax}\left(\frac{\mathbf Q \mathbf K^\top }{\sqrt{d}}\right) \mathbf V softmax ( d Q K ⊤ ) V
向量点积之所以能表示相似度,是因为其源头是余弦距离 (不考虑方向)
多头注意力机制 在实践中,为了捕捉不同方面的信息,将注意力机制分为多个头,形成多个子空间表示(representation subspaces)是有意义的。
用独立学习得到的h h h 组不同的 线性投影 (linear projections)来变换查询、键和值。 然后将它们并行地 送到注意力池化中。 最后,将这h h h 个输出拼接在一起, 并且通过另一个可以学习的线性投影进行变换, 以产生最终输出。 这种设计就被称为 多头注意力 (Multi-Head Attention)。
第i i i 个 head 的查询、键和值线性变换后的结果如下:
以小批量样本输入的矩阵形式 给出,此处暂且忽略板书时对符号的加粗
Q i = Q W i Q , K i = K W i K , V i = V W i V Q_i=QW_i^Q,\;K_i=KW_i^K,\;V_i=VW_i^V Q i = Q W i Q , K i = K W i K , V i = V W i V
从而第i i i 个 head 的输出为:
h e a d i = A t t e n t i o n ( Q i , K i , V i ) A t t e n t i o n ( Q i , K i , V i ) = s o f t m a x ( Q i K i ⊤ d ) V i \begin{aligned} \mathrm{head}_i&=\mathrm{Attention}(Q_i,K_i,V_i)\\ \mathrm{Attention}(Q_i,K_i,V_i)&=\mathrm{softmax}\left(\frac{Q_iK_i^\top }{\sqrt{d}}\right)V_i \end{aligned} head i Attention ( Q i , K i , V i ) = Attention ( Q i , K i , V i ) = softmax ( d Q i K i ⊤ ) V i
最终的多头注意力输出为:
A t t e n t i o n ( Q , K , V ) = C o n c a t ( h e a d 1 , . . , h e a d i , . . ) W O \mathrm{Attention}(Q,K,V)=\mathrm{Concat}\left(\mathrm{head}_1,..,\mathrm{head}_i,..\right)W^O Attention ( Q , K , V ) = Concat ( head 1 , .. , head i , .. ) W O
自注意力机制 自注意力机制 (self-attention)也被称为内部注意力(intra-attention),顾名思义就是对输入数据自身进行和传统注意力机制类似的处理。特别地,有q = k = v \bf q=k=v q = k = v 。
如果输入小批量样本X = { x 1 , . . . , x n } ∈ R n × d , x i ∈ R d {\bf X}=\{\boldsymbol x_1,...,\boldsymbol x_n\}\in\Bbb R^{n\times d},\;\boldsymbol x_i\in\Bbb R^d X = { x 1 , ... , x n } ∈ R n × d , x i ∈ R d ,那么一个自注意力机制任务中,任意一个键值对可以表示成( x i , x i ) (\boldsymbol x_i,\boldsymbol x_i) ( x i , x i ) ,由其自身构成。从而当查询q = x i q=\boldsymbol x_i q = x i 时,有:
y i = f ( x i , ( x 1 , x 1 ) , ( x 2 , x 2 ) , . . . , ( x n , x n ) ) ∈ R d \boldsymbol y_i=f\left(\boldsymbol x_i,\;(\boldsymbol x_1,\boldsymbol x_1),(\boldsymbol x_2,\boldsymbol x_2),...,(\boldsymbol x_n,\boldsymbol x_n)\right)\in\Bbb R^d y i = f ( x i , ( x 1 , x 1 ) , ( x 2 , x 2 ) , ... , ( x n , x n ) ) ∈ R d
其中,f f f 是注意力机制的一般范式。值得注意的是,通过注意力机制映射完之后的y i \boldsymbol y_i y i 的尺寸与输入一致。
实际中的自注意力 通常情况下,我们并不是直接取q = k = v \bf q=k=v q = k = v ,而是对原始输入x i \boldsymbol x_i x i 进行3种仿射变换,依次得到:q i = W q x i , k i = W k x i , v i = W v x i , i = 1 , . . , n \boldsymbol q_i=W^q\boldsymbol x_i,\;\boldsymbol k_i=W^k\boldsymbol x_i,\;\boldsymbol v_i=W^v\boldsymbol x_i,\quad i=1,..,n q i = W q x i , k i = W k x i , v i = W v x i , i = 1 , .. , n .
然后再进行:
y i = f ( q i , ( k 1 , v 1 ) , ( k 2 , v 2 ) , . . . , ( k n , v n ) ) ∈ R d \boldsymbol y_i=f\left(\boldsymbol q_i,\;(\boldsymbol k_1,\boldsymbol v_1),(\boldsymbol k_2,\boldsymbol v_2),...,(\boldsymbol k_n,\boldsymbol v_n)\right)\in\Bbb R^d y i = f ( q i , ( k 1 , v 1 ) , ( k 2 , v 2 ) , ... , ( k n , v n ) ) ∈ R d
即是用q i \boldsymbol q_i q i 作为查询,对所有的键值对进行注意力评分,然后加权得到第i i i 个输入的输出结果。如下图所示:
用同样的方法,我们可以并行地 计算出和x 1 , . . . , x n \boldsymbol x_1,...,\boldsymbol x_n x 1 , ... , x n 同样多的输出y 1 , . . . , y n \boldsymbol y_1,...,\boldsymbol y_n y 1 , ... , y n 。而且这些输出中的每一个都考虑到了所有的输入。
PyTorch 实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Attention (nn.Module): def __init__ (self, dim, heads = 8 , dim_head = 64 , dropout = 0. ): ''' dim: 输入维度 heads: 多头注意力的头的个数 dim_head: 每个头的输出维度 dropout: dropout比率 ''' super ().__init__() inner_dim = dim_head * heads project_out = not (heads == 1 and dim_head == dim) self.heads = heads self.scale = dim_head ** -0.5 self.norm = nn.LayerNorm(dim) self.attend = nn.Softmax(dim = -1 ) self.dropout = nn.Dropout(dropout) self.to_qkv = nn.Linear(dim, inner_dim * 3 , bias = False ) self.to_out = nn.Sequential( nn.Linear(inner_dim, dim), nn.Dropout(dropout) ) if project_out else nn.Identity() def forward (self, x ): x = self.norm(x) qkv = self.to_qkv(x).chunk(3 , dim = -1 ) q, k, v = map (lambda t: rearrange(t, 'b n (h d) -> b h n d' , h = self.heads), qkv) dots = torch.matmul(q, k.transpose(-1 , -2 )) * self.scale attn = self.attend(dots) attn = self.dropout(attn) out = torch.matmul(attn, v) out = rearrange(out, 'b h n d -> b n (h d)' ) return self.to_out(out)
Self-attention vs. CNN 论文 《On the Relationship between Self-Attention andConvolutional Layers》
(https://arxiv.org/abs/1911.03584)指出,CNN其实就是自注意力机制的一种特例。
奠基之作 注意力机制的集大成者是如今赫赫有名的 Transformer 模型,本文中略过了不少注意力机制在该模型中的使用,这在本站下面这篇文章中将再次展开。感谢你看到这里!
番外:Att的Bug? 待更:https://zhuanlan.zhihu.com/p/645922048 https://www.evanmiller.org/attention-is-off-by-one.html
参考 动手学习深度学习|D2L Discussion - Dive into Deep Learning 详解深度学习中的注意力机制(Attention) - 知乎 拆 Transformer 系列二:Multi- Head Attention 机制详解 11.【李宏毅机器学习2021】自注意力机制 (Self-attention) -bilibili