Keras實現Self-Attention

本文轉載自:http://www.noobyard.com/article/p-zpxbfigc-b.html

1、Self-Attention概念詳解

對於self-attention來說,Q(Query), K(Key), V(Value)三個矩陣均來自同一輸入,首先咱們要計算Q與K之間的點乘,而後爲了防止其結果過大,會除以一個尺度標度其中 d_k 爲一個query和key向量的維度。再利用Softmax操做將其結果歸一化爲機率分佈,而後再乘以矩陣V就獲得權重求和的表示。該操做能夠表示爲html

若是將輸入的全部向量合併爲矩陣形式,則全部query, key, value向量也能夠合併爲矩陣形式表示python

其中 W^Q, W^K, W^V 是咱們模型訓練過程學習到的合適的參數。上述操做便可簡化爲矩陣形式網絡

2、Self_Attention模型搭建

筆者使用Keras來實現對於Self_Attention模型的搭建,因爲網絡中間參數量比較多,這裏採用自定義網絡層的方法構建Self_Attention,關於如何自定義Keras能夠參看這裏:編寫你本身的 Keras 層post

Keras實現自定義網絡層。須要實現如下三個方法:(注意input_shape是包含batch_size項的)學習

  • build(input_shape): 這是你定義權重的地方。這個方法必須設 self.built = True,能夠經過調用 super([Layer], self).build() 完成。
  • call(x): 這裏是編寫層的功能邏輯的地方。你只須要關注傳入 call 的第一個參數:輸入張量,除非你但願你的層支持masking。
  • compute_output_shape(input_shape): 若是你的層更改了輸入張量的形狀,你應該在這裏定義形狀變化的邏輯,這讓Keras可以自動推斷各層的形狀
from keras.preprocessing import sequence
from keras.datasets import imdb
from matplotlib import pyplot as plt
import pandas as pd
 
from keras import backend as K
from keras.engine.topology import Layer
 
 
class Self_Attention(Layer):
 
    def __init__(self, output_dim, **kwargs):
        self.output_dim = output_dim
        super(Self_Attention, self).__init__(**kwargs)
 
    def build(self, input_shape):
        # 爲該層建立一個可訓練的權重
        #inputs.shape = (batch_size, time_steps, seq_len)
        self.kernel = self.add_weight(name='kernel',
                                      shape=(3,input_shape[2], self.output_dim),
                                      initializer='uniform',
                                      trainable=True)
 
        super(Self_Attention, self).build(input_shape)  # 必定要在最後調用它
 
    def call(self, x):
        WQ = K.dot(x, self.kernel[0])
        WK = K.dot(x, self.kernel[1])
        WV = K.dot(x, self.kernel[2])
 
        print("WQ.shape",WQ.shape)
 
        print("K.permute_dimensions(WK, [0, 2, 1]).shape",K.permute_dimensions(WK, [0, 2, 1]).shape)
 
 
        QK = K.batch_dot(WQ,K.permute_dimensions(WK, [0, 2, 1]))
 
        QK = QK / (64**0.5)
 
        QK = K.softmax(QK)
 
        print("QK.shape",QK.shape)
 
        V = K.batch_dot(QK,WV)
 
        return V
 
    def compute_output_shape(self, input_shape):
 
        return (input_shape[0],input_shape[1],self.output_dim)

  

 

轉載於:https://www.cnblogs.com/siyuan1998/p/11348470.htmlui