参考链接:
将Source中的构成元素想象成是由一系列的
模型 | 公式 |
---|---|
加性模型 | (, ) = v T t a n h ( W x + U q ) v^Ttanh(Wx + Uq) vTtanh(Wx+Uq) |
点积模型 | (, ) = x T q x^Tq xTq |
缩放点击模型 | (, ) = x T q D \frac{x^Tq}{\sqrt{D}} DxTq |
双线性模型 | (, ) = x T W q x^TWq xTWq |
理论上,加性模型和点积模型的复杂度差不多,但是点积模型在实现上可以更好地利用矩阵乘积,从而计算效率更高。当输入向量的维度 比较高时,点积模型的值通常有比较大的方差,从而导致Softmax函数的梯度会比较小。因此,缩放点积模型可以较好地解决这个问题。
双线性模型是一种泛化的点积模型。假设公式中 = T,双线性模型可以写为(, ) = TT = ()T(),即分别对 和 进行线性变换后计算点积。相比点积模型,双线性模型在计算相似度时引入了非对称性。
多头注意力(Multi-Head Attention)利用多个查询 = [1, ⋯ , ],来并行地从输入信息中选取多组信息,每个注意力关注输入信息的不同部分。
在之前介绍中,我们假设所有的输入信息是同等重要的,是一种扁平(Flat)结构,注意力分布实际上是在所有输入信息上的多项分布.但如果输入信息本身具有层次(Hierarchical)结构,比如文本可以分为词、句子、段落、篇章等不同粒度的层次,我们可以使用层次化的注意力来进行更好的信息选择[Yang et al.,2016].此外,还可以假设注意力为上下文相关的二项分布,用一种图模型来构建更复杂的结构化注意力分布[Kim et al., 2017]。
如果要建立输入序列之间的长距离依赖关系,可以使用以下两种方法:一种方法是增加网络的层数,通过一个深层网络来获取远距离的信息交互;另一种方法是使用全连接网络.全连接网络是一种非常直接的建模远距离依赖的模型,但是无法处理变长的输入序列.不同的输入长度,其连接权重的大小也是不同的.这时我们就可以利用注意力机制来“动态”地生成不同连接的权重,这就是自注意力模型(Self-Attention Model)。
引入Self Attention后会更容易捕获句子中长距离的相互依赖的特征,因为如果是RNN或者LSTM,需要依次序序列计算,对于远距离的相互依赖的特征,要经过若干时间步步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小。
为了提高模型能力,自注意力模型经常采用查询-键-值(Query-Key-Value,QKV)模式,其计算过程如图8.4所示,其中红色字母表示矩阵的维度。
return_sequences=True
,即需LSTM输出三维向量)class AttentionLayer(Layer):
def __init__(self, **kwargs):
super(AttentionLayer, self).__init__(** kwargs)
def build(self, input_shape):
assert len(input_shape)==3
# W.shape = (time_steps, time_steps)
self.W = self.add_weight(name='att_weight',
shape=(input_shape[1], input_shape[1]),
initializer='uniform',
trainable=True)
self.b = self.add_weight(name='att_bias',
shape=(input_shape[1],),
initializer='uniform',
trainable=True)
super(AttentionLayer, self).build(input_shape)
def call(self, inputs):
# inputs.shape = (batch_size, time_steps, seq_len)
x = K.permute_dimensions(inputs, (0, 2, 1))
# x.shape = (batch_size, seq_len, time_steps)
a = K.softmax(K.tanh(K.dot(x, self.W) + self.b))
outputs = K.permute_dimensions(a * x, (0, 2, 1))
outputs = K.sum(outputs, axis=1)
return outputs
def compute_output_shape(self, input_shape):
return input_shape[0], input_shape[2]