深度学习进阶(二)多头自注意力机制(Multi-Head Attention)
Attention(,,)softmax()再概述一下自注意力的本质通过一次全局加权将序列中的所有信息重新融合到每一个位置上最终强化信息表示。但单头的自注意力还是有些局限一组 (,,) 只能用一种方式去理解序列。这其实和在卷积层中使用多个卷积核是相似的道理我们不能只用一个卷积核去提取纹理、色彩、形状等所有特征。同理我们不能指望一组参数矩阵就能学习到序列在语义、语法、情感等多个方面的关联。因此我们在实际算法设计中使用的往往是多头自注意力。其原理并不复杂只是在单头自注意力基础上的简单改进。1. 多头注意力的核心思想#多头注意力的核心思想很直观在“一层自注意力层”中不只做一次注意力而是做多次注意力每次关注不同的信息子空间。具体来说就是不再只用一组 (,,) 而是同时学习 ℎ 组不同的参数矩阵这样的每一组参数矩阵就是一个“头”综合所有头的注意力信息得到最终输出。比如第 个头为()()()然后每一个头都独立进行注意力计算Attention(,,)由于每个注意力头拥有独立的初始化参数矩阵所以每一个头都是一个“观察角度”它们分别回答在不同语义空间下相关性问题。其计算过程和单头自注意力并无区别但一个新的问题是如何融合多头输出2. 多头的融合方式#2.1 拼接#通过多头自注意力现在我们得到了多个输出1,2,…,ℎ而要回答这些信息怎么合在一起首先要了解 Transformer 对每个头的维度划分设计ℎ这里的 仍是表示序列中一个位置或者说一个token的特征维度。举个例子来说明假定每个 token进入模型的特征维度8并且使用两个注意力头两个注意力头ℎ2(两个注意力头)那么每个头的维度为ℎ824这代表每个头的 Query / Key 向量维度和 Value 输出维度都为 4分别计算注意力得到输出1,2∈×4明确了维度变化后我们就能进行多头输出融合的第一步拼接。Concat(1,2,…,ℎ)思路很明确就是把所有头的输出先直接拼在一起∈×(ℎ⋅)可以发现拼接后的维度重新恢复到了原始的模型维度 。这样的切分逻辑可以在固定模型维度 的前提下使多头不会增加总体计算复杂度的数量级从而避免因头数增加而产生计算量爆炸问题。同时这种让输入输出维度相同的设计也和 Transformer 的后续逻辑相关。2.2 线性变换#拼接完还没有结束实际上在这之后 还需要经过一个线性层final,∈×你会发现这里没有加入偏置。实际上线性层本身自然是拥有偏置的但许多 Transformer 实现都会选择关闭偏置这是因为 Transformer block 的结构中仍存在后续线性变换以及归一化操作这里的单个线性层中的偏置项对整体表达能力的影响较小因此在理论公式中经常省略。现在把整体写成一行如下MultiHead(,,)Concat(1,…,ℎ)这就是多头注意力的融合公式。到这里你可能有这样一个问题只拼接不行吗为什么还要再过一个线性层我们举个例子来回答这个问题假设对于某个位置 经过多头注意力后我们得到了两个头的输出语法结构顺序主谓语法结构顺序主谓1()[语法结构顺序主谓]语义情感主题语境语义情感主题语境2()[语义情感主题语境]拼接之后得到语法结构顺序主谓语义情感主题语境语法结构顺序主谓语义情感主题语境()[语法结构顺序主谓语义情感主题语境]此时不同头的信息只是被“并排放在一起”但它们之间并没有发生任何交互或关联。也就是说有点用但还不够。现在再进行融合()()这步计算实际上是对拼接后的所有特征进行一次“重新加权组合”。假设经过学习后 做出的组合类似于把“主谓” “语义”组合得到更准确的句法语义关系。把“结构” “语境”组合得到更高层次的上下文理解。把“情感”适当放大或抑制。最终形成新的表示综合特征综合特征综合特征综合特征()[综合特征1,综合特征2,…]由此所有头的信息被打散并重新组合模型可以自由地学习跨多头的特征关系。这就是多头自注意力机制的详细内容我们由此实现了从多个角度对输入信息的强化表示从模型整体角度来说多头注意力本质上是一个用于建模序列内部关系的计算模块。因此在 Transformer 中多头注意力并不是单独使用的而是被嵌入到一个更完整的结构单元中这个单元就是Transformer Block我们在下一篇中再对其展开介绍。