1. 程式人生 > >Keras實現注意力機制

Keras實現注意力機制

Keras實現注意力機制


這裡主要記錄幾種Keras的注意力機制的實現,僅作為個人記錄。

  • python 3
  • keras 2.1.0 (tensorflow backend)

寫法1

這種寫法比較簡單,參考自這裡。相似度函式採用的是一層全連線層。全連線層的輸出經過softmax啟用函式計算權重。他對隱層向量的每一維在每個時間步上進行了softmax操作,這裡函式的返回值是三維的,也就是說這裡只是乘上了權重,但並沒有求和。

def attention_3d_block(inputs, single_attention_vector=False)
:
# 如果上一層是LSTM,需要return_sequences=True # inputs.shape = (batch_size, time_steps, input_dim) time_steps = K.int_shape(inputs)[1] input_dim = K.int_shape(inputs)[2] a = Permute((2, 1))(inputs) a = Dense(time_steps, activation='softmax')(a) if single_attention_vector: a = Lambda(lambda
x: K.mean(x, axis=1))(a) a = RepeatVector(input_dim)(a) a_probs = Permute((2, 1))(a) # 乘上了attention權重,但是並沒有求和,好像影響不大 # 如果分類任務,進行Flatten展開就可以了 # element-wise output_attention_mul = Multiply()([inputs, a_probs]) return output_attention_mul

注意:這裡直接對經過線性變換後的所有向量進行了softmax,並沒有乘上context vector後再做,好像在分類例子裡影響不大。這裡time_steps有時候不太容易取,需要事先手動指定,而且有時候可能需要可變的time_steps,這就可能有問題。

寫法2

這裡我仿照上面的寫法,自定義了一個Keras層。不同的是,這裡在softmax之前還加了tanh啟用函式,而且將輸出進行了求和,所以輸出是二維的。借用這篇文章中的圖,應該大致描述了這個意思。
注意力機制

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]

Hierarchical Attention Networks

這篇論文提出了一種層級的注意力機制,在詞彙級別和句子級別應用注意力機制對文件進行分類,得到了不錯的效果。這裡寫圖片描述
這篇部落格好像做了實現,使用的資料集來自這裡。我也按照他的程式碼進行了實驗,並且用到了上文提到的自定義的Attention層。程式碼在這裡,簡單試了一下,準確率為90.52%。

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)