1. 自己注意メカニズムの原理
自己注意メカニズムの原理は、自己限定集合内の各メンバーの相関度を計算し、各メンバーに他のメンバーの情報を多かれ少なかれ付着させることです。重要なのは、このセットのメンバーはベクトル、スカラー、そしておそらく人々のグループである可能性があるということです。コレクションが人々のグループである場合、各メンバー (人々の間) の関連度を簡単に取得できます。コレクション内にいくつかのスカラーがある場合は、Dense_tention を使用して各スカラー間の接続の度合いを計算します。セット内にベクトルがある場合 (つまり、各サンプルに複数の特徴がある場合)、関連度はどのように計算すればよいでしょうか? ——答えは、李紅儀氏が言ったマトリックス形式で計算することです。サンプル特徴の次元を削減することも可能です。たとえば、SEnet では、2 次元行列 Global Maxpooling を 1x1xC の C スカラーに直接変換し、Dense_tention を使用してアテンション分布を直接計算します。これは完璧です。
つまり、セット内のメンバーの数が限られている限り、それに注意を払うことができます。重要なのは、各メンバーの特徴をスカラーにプールし (スカラーに重み付け)、それぞれをソフトマックスで出力することです。メンバー間の注意力の分散が行われます。ここでは、セルフアテンションのいくつかの応用例を示します: 特徴の次元削減、因果分析、解釈可能性など。
2、コード
次のコードは、コレクション内にいくつかのベクトルがあり、各ベクトルが D 次元であるという前提に基づいています。セット内に N 個のベクトルがあり、テンソルとして表現される場合、形状は(D,N)になります。これは、keras などの一部のフレームワークがデフォルトで最後のディメンションをサンプル サイズとして使用するために書かれています。ここで、CNN-1D ネットワーク層がいくつかの特徴を抽出します。コンボリューション カーネルは 32、出力は (None,8,32) です。8 はコンボリューション カーネル スライディングによって生成された特徴マップ ベクトルで、これは 32 次元を抽出するのと同等です。潜在特徴ベクトルは 8。これら 32 の特徴間の自己注意を計算する必要があります。最も簡単な方法は、グローバル マックスプーリングを 32 スカラーにし、次にソフトマックスで 32 の注意スコアにし、それらを乗算し直すことです。しかし、8 次元のようにはできませんベクトル 類似性を計算するには、より合理的な方法を使用する必要があります。
完全なコードは次のとおりです。
from keras import backend as K
from keras.layers import Layer,Permute
class Self_Attention(Layer):
def __init__(self,left_dim=None,scale_value=1,**kwargs):
if scale_value<=0:
raise ValueError('缩放值必须大于0')
self.scale_value=scale_value
self.output_dim=left_dim
super(Self_Attention, self).__init__(**kwargs)
def build(self, input_shape):
# 为该层创建一个可训练的权重
#inputs.shape = (batch_size, time_steps, seq_len),取(None, 8, 32)
print('input_shape is:',input_shape)
if self.output_dim is None:
self.output_dim = input_shape[1]
self.kernel = self.add_weight(name='kernel',
shape=(3, input_shape[1],self.output_dim),
initializer='uniform',
trainable=True)
#8X8大小,当然self.output_dim可以大于8也可以小于8,升维降维效果没试过
super(Self_Attention, self).build(input_shape) # 一定要在最后调用它
# 生成每个成员向量的query、key、value向量
def call(self, x):
x=Permute((2,1))(x)
#8x32变成32x8;原因是8x8右乘8x32keras的结果有问题,只能将x放在左边,即32x8,8x8
WQ = K.dot(x, self.kernel[0])
WK = K.dot(x, self.kernel[1])
WV = K.dot(x, self.kernel[2])
# 生成成员向量间的关联度
QK = K.batch_dot(WQ,K.permute_dimensions(WK, [0, 2, 1]))
# 关联度缩放
if self.scale_value <0:
raise ValueError('scale_value必须大于0')
QK = QK / (self.scale_value**0.5)
# 输出注意力分数,QK是32x32的矩阵
QK = K.softmax(QK)
# 抽取各个成员的信息组成新的向量集合
WV_=Permute((2,1))(WV)
V= K.batch_dot(WV_,QK)
return V
def compute_output_shape(self, input_shape):
return (input_shape[0],self.output_dim,input_shape[2])
上記のコードは、前に見た偉人によって書かれたものですが、特定のブログ投稿が見つかりません。コードは私によって変更されました (CNN-1D によって抽出された特徴間の関係を扱うために使用されました)。以下は大きな元のコードです。元のコードは次のとおりです。
from keras import backend as K
from keras.layers import Layer,Permute
class Self_Attention(Layer):
def __init__(self, output_dim, scale_value,**kwargs):
self.output_dim = output_dim
self.scale_value=scale_value
super(Self_Attention, self).__init__(**kwargs)
def build(self, input_shape):
# 为该层创建一个可训练的权重
#inputs.shape = (batch_size, time_steps, seq_len);provide is (8,32),output_dim=16
# print(input_shape)
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) # 一定要在最后调用它
# print('self.kernel[0].shape is:',self.kernel[0].shape)#self.kernel[0].shape is: (32, 16)
def call(self, x):
print(x.shape)
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]))
if self.scale_value <0:
raise 'scale_value必须大于0'
QK = QK / (self.scale_value**0.5)
QK = K.softmax(QK)
# print("QK.shape---",QK.shape)
# print("************************************")
V = K.batch_dot(QK,WV)
# print("-----------V--------------.shape",V.shape)
return V
def compute_output_shape(self, input_shape):
return (input_shape[0],input_shape[1],self.output_dim)