划水休息两天不看论文了 ~ 来重新复习一下基础qaq
以下讲解参考大名鼎鼎的 nndl 邱锡鹏 《神经网络与深度学习》 部分内容(详见第八章,注意力与外部记忆)是对于不太行的初学者也比较友好的一本,当然不能要求一本书既全面又深入,阅读过程还是建议自己去更多地从别的渠道了解细节内容,但个人觉得即使是顺着通读亦对关于深度学习的整体框架搭建蛮有帮助的qaq
同时参考了这篇综述:An Attentive Survey of Attention Models,具体这篇论文的阅读笔记也蛮多的就不找时间再写了(https://www.cnblogs.com/ydcode/p/11040811.html 这篇就写的很好~)
注意力机制本身想要解决的问题很简单,就是算不动了
在整体模型越来越庞大的情况下,大家明显地觉得运算开始吃力了,这样的问题下直观的思想就是考虑如何按重要性更好地将手头有限的计算资源进行分配,以保证更多的计算资源可以分配到确实重要的内容上,而尽量不要太浪费在所谓不重要的内容上。人脑面对海量信息往往利用 注意力 将部分不重要的信息略去而只关注于重要的信息,这里将注意力分为两种:
自上而下的有意识的注意力,也就是 聚焦式注意力(Focus Attention):此时的注意力是确定地有一个目的的,也就是会主动地去关注某一个特定的对象,本身依赖目的,存在预定的任务(举例阅读理解问题,此时给定问题以后,关注的只是和问题相似的文本段落对象,对其他对象可以少输入或不输入模型以节约计算资源)
自下而上的无意识的注意力,也就是 基于显著性的注意力(Saliency Based Attention):也就是说此时并没有预先根据某种目的或任务关注某一个特定的对象,而是单纯地当某一个对象表现出某种特征的时候,比如某一个对象值很大时则转而主动关注这样的对象(举例 max 池化,门控机制)
这里来一个 nndl 中的例子:
一个和注意力有关的例子是鸡尾酒会效应。当一个人在吵闹的鸡尾酒会上和朋友聊天时,尽管周围噪音干扰很多,他还是可以听到朋友的谈话内容,而忽略其他人的声音(聚焦式注意力)。同时,如果背景声中有重要的词(比如他的名字),他会马上注意到(显著性注意力)
从这个思路出发,当前已经进行了较多的尝试,比如最简单的 池化层:最大池化本身也就是选择一个范围内的最大值保存下来,直观理解可以认为就是只关注了值最大的部分而将其他部分内容舍去,以更好地将更宝贵的计算资源放在可能重要的部分
进一步地从当前主流的 encode - decode (编码器 - 解码器)模型来讨论一下 注意力机制 的优势。传统的编码器解码器模型存在以下两个很大的问题:
而 注意力机制,也就是尝试 在输入的信息上计算注意力分布 → 从而得到 不同输入信息对应当前任务的重要性分布 = 不同的权重 → 再根据不同的重要性,也就是不同的权重 计算当前输入信息的加权平均,以实现(对重要的,和任务相关的信息赋予更高的权重,而将不重要的信息基本忽略或赋予较低的权重)以更有效率地利用计算资源
注意力机制 本身只是一种思想,并不依赖某一个特定的模型(虽然总是依赖编码器 - 解码器的模型来解释它),可以简单地总结为两个步骤:
简化问题,考虑此时输入 N 个向量 : [ x 1 , . . . , x N ] [x_1, ... , x_N] [x1,...,xN],我想要从中选出对于我的目标而言比较重要的信息,需要引入我的目标任务的表示,称为 查询向量(query vector),则此时问题可以转换为考察 输入的不同内容和查询向量之间的相关度,一个简单的思路就是通过一个 注意力打分函数 对不同内容进行打分,赋予与我当前任务比较相关的部分更大的权重,再直接地通过一个 softmax 层得到分布,也就是输入信息的不同部分的权重。
这里的注意力打分函数主要有以下几种:
上面的 W U 都是可以学习的参数,D是输入向量的维度
比较常用的就是 点积模型,简单 + 有效
通过每一个输入 x 和 q 计算得分函数 → 再通过 softmax 层,则第 i 个输入 xi 对应的权重也就是 s o f t m a x ( s ( x , q ) ) softmax(s(x,q)) softmax(s(x,q))
这里分为两种方式:
软性注意力机制:也就是每一个输入的按各自权重的加权平均
a t t ( X , q ) = ∑ n = 1 N a n x n att(X,q) = \sum_{n=1}^N a_n x_n att(X,q)=n=1∑Nanxn
硬性注意力机制:也就是只关注某一个向量,此时用某一个向量来直接代替所有输入的信息,而将其他的信息都一概忽略
主要有以下两种形式:
但是注意到,这里硬性注意力机制的最大的问题就是它本身是不可导的(比如选择权重最大实际上就是通过了一个 max 函数),也就是说这一步会导致无法使用反向传播算法,一般只能依赖强化学习进行训练
在这里举个例子,考虑 seq2seq 框架下的 编码器 - 解码器模型中注意力机制最简单的应用方式
整体如下,此时左边是正常的编码器-解码器模型,右边是加入了注意力模块的
经过 encode,此时输入 x1 x2 x3 对应的得到三个隐藏状态 h1 h2 h3,考察上一步中解码器已经得到的隐藏状态 s2,可以将 s2 作为查询向量,计算所有的隐藏状态 h1 h2 h3 和 s2 的相关度(这里的得分是通过一个前馈神经网络来学习的) → 得到注意力分布 → 得到 h1 h2 h3 的聚合内容,也就是图中的 c2,再进一步依据模型设计将 c2 用于解码器
实际使用的时候直接利用最原本的模式的情况是不多的,这里讲几个应用比较广泛的变体:
也就是利用 键值对 的方式来输入信息,此时不再是只输入一个 x,而以: ( K , V ) = [ ( k 1 , v 1 ) , ( k 2 , v 2 ) , . . . , ( k N , v N ) ] (K,V) = [(k_1, v_1), (k_2, v_2) , ... , (k_N, v_N)] (K,V)=[(k1,v1),(k2,v2),...,(kN,vN)]
的方式输入 N 组信息。这里满足:
其他内容和基本形式是一样的,也就是说此时的聚合信息可以表示为(如果利用软性的信息聚合,打分函数为 s): a t t ( ( K , V ) , q ) = ∑ n = 1 N s o f t m a x ( s ( q , k n ) ) v n att((K,V), q) = \sum_{n=1}^N softmax(s(q, k_n)) v_n att((K,V),q)=n=1∑Nsoftmax(s(q,kn))vn
工作实质如图所示:
阶段1 → 通过打分函数,利用查询向量 q,对此时输入的 (键 key)的部分进行打分
阶段2 → 通过 softmax 将不同的打分作归一化处理,得到各个部分的注意力权重,也就是注意力分布
阶段3 → 通过输入的 (值 value)结合注意力分布进行信息聚合
K=V 的时候也就是普通的模型
也就是此时存在多个查询 Q: Q = [ q 1 , . . . , q M ] Q = [q_1, ... , q_M] Q=[q1,...,qM]
来通过一种 并行 的方式从输入中搜索需要的信息。直观理解就是解决问题需要很多不同的方面的信息,每一个不同的 qi 考察的都是不同的方面,此时利用不同的 qi 从不同的角度给输入信息的重要性进行打分,再进行某种程度的聚合。
一般不同查询对应得到的聚合信息直接用向量拼接的方式: a t t ( ( K , V ) , Q ) = a t t ( ( K , V ) , q 1 ) ⊕ . . . ⊕ a t t ( ( K , V ) , q M ) att((K,V), Q) = att((K,V), q_1) \oplus ... \oplus att((K,V), q_M) att((K,V),Q)=att((K,V),q1)⊕...⊕att((K,V),qM)
考虑当前针对输入序列的编码方式,如果我们需要将输入序列转化为一个定长的序列,此时卷积和循环神经网络均是较好的选择,但是注意到以上两种均只是一种局部编码的方式(循环神经网络本身由于长程依赖问题 / 梯度消失,实际上也只能建模局部的信息)
换一个思路,如果我想要捕捉整个输入序列中的某种长程依赖关系,此时常用的方法包括:
想要模拟全连接神经网络的思路来构建一种更好的,可以处理变长输入序列 + 捕捉长距离关系的模型,可以考虑利用注意力机制来 动态地 生成权重,这也就是 自注意力模型 的主要思路
考虑到往常的使用频率,这里先介绍一下最常用的 查询 - 键值对注意力模型(Query-Key-Value,QKV),实际上为了增强模型效果,基本不会使用上面广义形式对应的自注意力模型
假设此时的输入序列为 x,则自注意力模型可以分为以下几个步骤:
整体图解如下:
也就是说,输入三个(这里设 N=3)X 序列,每一个长度为 Dx,则此时得到三个查询向量,每一个查询向量得到一个对应的 (这三个 x 序列的线性组合),则此时得到三个结果,对应拼在一起,不改变输入的 X 的对应 N 这部分的维度,但是将长度 Dx 改变为了 Dv(这里的 Dv 是可以任意设置的,只要通过操作此时从 X 到值 V 的投影操作对应的矩阵 Wv 就可以了)
也就是说通过上述操作,此时可以将不定长的序列 Dx 动态地生成适合的权重并转化为某一个定长 Dv
其实也就是上述的自注意力操作加上了自注意力的思路
比如说此时对应的 x 是 Dx 维度,共 N 个,我每一次通过一个矩阵 Wq 将其投影为一个查询矩阵的时候都可以一次性得到 N 个查询向量,这 N 个查询向量可以保证后续输出的结果还是共 N 个(只是另一个维度由值向量的维度 Dv 决定),这是我们上一节的思路
考虑多头注意力,也就是说此时我们考虑能不能得到多个查询矩阵,以从不同的角度来捕捉 X 的重要情况,则此时我采用多个矩阵 Wqi 将它投影到 m 个不同的空间分别得到 m 个查询矩阵,共 m*N 个向量,再分别计算输出,最后采用向量拼接的方式把它拼起来得到最后的结果,这里思路是十分接近的,就不多说了。
简单总结一下注意力机制的几个优点:
但是可以注意到此时缺点也是很明显的:
当然后续的模型大多加入位置信息 embedding 来帮助缓解这个问题(比如 BERT 就是这么干的),所以并不认为这就是 attention 用在 nlp 上的致命伤
理解深度有限,存在错误 / 不足欢迎指出!期待进一步讨论~
转载请注明出处。知识见解与想法理应自由共享交流,禁止任何商用行为!