0. 导言
attention机制是模仿人类注意力而提出的一种解决问题的办法,简单地说就是从大量信息中快速筛选出高价值信息。主要用于解决LSTM/RNN模型输入序列较长的时候很难获得最终合理的向量表示问题,做法是保留LSTM的中间结果,用新的模型对其进行学习,并将其与输出进行关联,从而达到信息筛选的目的。
1. 知识点前述
encoder+decoder,中文名字是编码器和解码器,应用于seq2seq问题,其实就是固定长度的输入转化为固定长度输出。其中encoder和decoder可以采用的模型包括CNN/RNN/BiRNN/GRU/LSTM等,可以根据需要自己的喜好自由组合。
![](https://i-blog.csdnimg.cn/blog_migrate/591a13a5ab44ef16563c8dde41bead24.png)
encoder过程将输入的句子转换为语义中间件,decoder过程根据语义中间件和之前的单词输出,依次输出最有可能的单词组成句子。
![](https://i-blog.csdnimg.cn/blog_migrate/a38104a66cde887e1d6cef31618f8702.png)
问题就是当输入长度非常长的时候,这个时候产生的语义中间件效果非常的不好,需要调整。
2. attention模型
attention模型用于解码过程中,它改变了传统decoder对每一个输入都赋予相同向量的缺点,而是根据单词的不同赋予不同的权重。在encoder过程中,输出不再是一个固定长度的中间语义,而是一个由不同长度向量构成的序列,decoder过程根据这个序列子集进行进一步处理。
![](https://i-blog.csdnimg.cn/blog_migrate/fdcd43e528b18e7c386654bea23ac2f1.png)
这么说比较抽象,具体是怎么做的呢。用一个小例子来说明:
假设输入为一句英文的话:Tom chase Jerry
那么最终的结果应该是逐步输出 “汤姆”,“追逐”,“杰瑞”。
那么问题来了,如果用传统encoder-decoder模型,那么在翻译Jerry时,所有输入单词对翻译的影响都是相同的,但显然Jerry的贡献度应该更高。
引入attention后,每个单词都会有一个权重:(Tom,0.3)(Chase,0.2) (Jerry,0.5),现在的关键是权重怎么算的呢。
![](https://i-blog.csdnimg.cn/blog_migrate/d5fd0a173bb8d73401382071f37a76ff.png)
从图上可以看出来,加了attention机制以后,encoder层的每一步输出都会和当前的输出进行联立计算(wx+b形式),最后用softmx函数生成概率值。
概率值出来了,最后的结果就是一个加权和的形式。
![](https://i-blog.csdnimg.cn/blog_migrate/266bbeb9682ff53605dba5ad59939abe.png)
基本上所有的attention都采用了这个原理,只不过算权重的函数形式可能会有所不同,但想法相同。
3.attention应用
attention的应用领域非常广泛,文本、图片等都有应用。
文本:应用于seq2seq模型,最常见的应用是翻译。
图片:应用于卷积神经网络的图片提取
当然还有很多其他应用,大家可以自己探索。
4.attention简单实现
4.1 思路1:直接对原文本进行权重计算
这个思路非常暴力,我们说过要对输入进行权重计算,此种方法的计算很简单,就是将输入来一个全连接,随后采用softmax函数激活算概率。先看代码:
from keras.layers import Permute
from keras.layers import Dense
from keras.layers import Lambda
from keras.layers import RepeatVector
from keras.layers import Multiply
def attention_3d_block(inputs, single_attention_blick=False):
time_steps = K.int_shape()[1]#返回输入的元组,以列表的形式储存
input_dim = K.int_shape()[2]#记住输入是[训练批量,时间长度,输入维度]
#下面是函数建模方式
a = Permute((2, 1))(inputs)
a = Dense(time_steps, activation='softmax')(a)
if single_attention_blick:
a = Lambda(lambda x: K.mean(x, axis=1))(a)
a = RepeatVector(input_dim)(a)
a_probs = Permute((2, 1))(a)
output_attention_mul = Multiply()([inputs, a.prob])
return output_attention_mul
4.2 思路2:加入激活函数并求和
这个的思路是权重计算之后加了一个tanh激活函数,然后求完权重进行了加和,更加符合attention机制的习惯,其实方法是一样的只不过返回是乘完加和而已。代码来自网上,原作者自己定义了一个attention层。
![](https://i-blog.csdnimg.cn/blog_migrate/6c2e43861317826266854fd4c85de3ff.png)
class attention_layers(Layer):
def __init__(self, **kwargs):
super(attention_layers, self).__init__(**kwargs)
def build(self,inputshape):
assert len(inputshape) == 3
#以下是keras的自己开发工作
self.W = self.add_weight(name='attr_weight',
shape=(inputshape[1], inputshape[2]),
initializer='uniform',
trainable=True)
self.b = self.add_weight(name='attr_bias',
shape=(inputshape[1],),
initializer='uniform',
trainable=True)
super(attention_layers, self).bulid(inputshape)
def call(self,inputs):
x = K.permute_dimensions(inputs, (0, 2, 1))
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]
4.3 层级attention模型
这是比较新的一种思路,在句子和单词层面都输出了一个向量。思路图如下:
![](https://i-blog.csdnimg.cn/blog_migrate/12176af4f094753aada52d3b8e948f56.png)
sentence_input = Input(shape=(MAX_SENT_LENGTH,), dtype='int32')
embedded_sequences = embedding_layer(sentence_input)
l_lstm = Bidirectional(GRU(100, return_sequences=True))(embedded_sequences)
l_dense = TimeDistributed(Dense(200))(l_lstm)
l_att = AttentionLayer()(l_dense)
sentEncoder = Model(sentence_input, l_att)
review_input = Input(shape=(MAX_SENTS,MAX_SENT_LENGTH), dtype='int32')
review_encoder = TimeDistributed(sentEncoder)(review_input) # 对文档中每个句子
l_lstm_sent = Bidirectional(GRU(100, return_sequences=True))(review_encoder)
l_dense_sent = TimeDistributed(Dense(200))(l_lstm_sent)
l_att_sent = AttentionLayer()(l_dense_sent)
preds = Dense(2, activation='softmax')(l_att_sent)
model = Model(review_input, preds)
作者:不分享的知识毫无意义
链接:https://www.jianshu.com/p/1d67638139da
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。