self-attention和multihead-attention原理,代码实现

self-attention和multihead-attention原理,代码实现,第1张

self-attention和multihead-attention原理,代码实现

参考博客:https://zhuanlan.zhihu.com/p/148737297
原理其实就是去计算每个词和其他词特征向量相关性(特征向量和embedding差不多,不知道区别的话,就当成一个东西看)
主要有三个变量query key value
query和key主要是用来算embedding的相关性的,他们两个首先进行计算,得出所有embedding的相关性系数矩阵(权重矩阵)
value,原始的embedding
主要分为三步:
第一步,算出每个embedding和其他embedding的相关性,生成一个相关性矩阵
这个过程,大家都知道,其实embedding就是经过种种卷积或者其他 *** 作后生成的一个新的特征向量,那么两个向量之间是可以计算相关性系数的,主要有以下方式:
cosine相关性系数
欧氏距离
点乘等等
第二步,对相关性系数矩阵进行softmax
softmax其实就是给重新将这个系数矩阵映射到0-1之间,类似于那种sigmod函数
第三步,与原始的embedding相乘,将该embedding与其他embedding生成的相关性系数乘进去,这样也就将该embedding与其他embedding的相关性集成了进去
代码实现网上有好多,粘下来几个,供大家参考

#self-attention
import torch.nn as nn
def calculate_distance_for(x,y):
    batch_size=len(x)
    row=len(x[0])
    colum=len(y[0])
    m = torch.zeros(batch_size,row, colum).to(device)
    for i in range(batch_size):
        for j in range(row):
            for k in range(colum):
            # torch.cosine_similarity(x[i],x[j])
                d2=torch.dist(x[i][j]  ,y[i][k], p=2)
                m[i][j][k]=d2
    return m
class SelfAttention(nn.Module):
    def __init__(self, dropout, **kwargs):
        super(SelfAttention, self).__init__(**kwargs)
        self.dropout = nn.Dropout(dropout)
    def forward(self, queries, keys, values):
    		#下面两句就是计算相关性,你也可以换成别的,类似上边我说的欧氏距离之类的
        d = queries.shape[-1]
        scores = torch.bmm(queries, keys.transpose(1,2)) / math.sqrt(d)
        #欧氏距离:
        #scores =calculate_distance_for(queries,keys)
        #下面就是计算softmax,把所有的矩阵里面的数值重新映射,最后使得矩阵所有值加起来等于1
        self.attention_weights = torch.softmax(scores, dim=2)
        #下面就是将权重矩阵和原先的特征矩阵进行相乘,将该特征向量与其他特征向量的相关性聚合进去
        return torch.bmm(self.dropout(self.attention_weights), values)

attention = SelfAttention(dropout=0.5)
# batch_size就是batchsize的大小,你每次往模型里面输几个数据
#num_queries其实就是你输进去的数据的长度,比如,你是NLP方向,那这个就是词的长度,你是计生方向,这个就是蛋白质序列长度
#num_hiddens这个其实是你特征向量的维度,也可以换成你的embedding的维度。就看你的self_attention在哪个层里面
batch_size, num_queries, num_hiddens  = 2, 100, 21
#随机生成一个矩阵,维度是3,里面的每一维的含义,上边已经说了
X = torch.ones((batch_size, num_queries, num_hiddens))
#调用模型
ans = attention(X, X, X)
print(ans)

multihead attention(原理:将embedding划分成不同的块,对每块进行selfattention的 *** 作):

def clones(module, N):
    "Produce N identical layers."
    return nn.ModuleList([copy.deepcopy(module) for _ in range(N)])

def attention(query, key, value, mask=None, dropout=None):
    "Compute 'Scaled Dot Product Attention'"
    d_k = query.size(-1)
    scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(d_k)
    p_attn = F.softmax(scores, dim = -1)
    if dropout is not None:
        p_attn = dropout(p_attn)
    return torch.matmul(p_attn, value), p_attn


def MLP(channels, batch_norm=True):
    return Seq(*[
        Seq(Lin(channels[i - 1], channels[i]), ReLU(), LN(channels[i]))
        for i in range(1, len(channels))
    ])

class MultiHeadAttention(nn.Module):
    def __init__(self, h, d_model, dropout=0.1):
        "Take in model size and number of heads."
        super(MultiHeadAttention, self).__init__()
        assert d_model % h == 0
        self.d_k = d_model // h
        self.h = h
        self.linears = clones(nn.Linear(d_model, d_model), 4) # create 4 linear layers
        self.attn = None
        self.dropout = nn.Dropout(p=dropout)
        self.mlp = Seq(MLP([21,10]), Dropout(0.5), Lin(10, 1))

    def forward(self, query, key, value, mask=None):
     
        batch_size = query.size(0)
			#划分成不同的子块,将不同的子块进行selfattention的 *** 作
        query, key, value = [l(x) for l, x in zip(self.linears, (query, key, value))]
        query, key, value = [x.view(batch_size, -1, self.h, self.d_k).transpose(1, 2)
                             for x in (query, key, value)] # (batch_size, h, seq_length, d_k)
        
        x, self.attn = attention(query, key, value, mask=mask, dropout=self.dropout)
        x = x.transpose(1, 2).contiguous().view(batch_size, -1, self.h * self.d_k)
        out=self.linears[-1](x)
        return self.mlp(out)
h = 7
d_model = 21   #特征维度
batch_size = 16  
seq_length = 100   #序列长度
model = MultiHeadAttention(h, d_model)
query = torch.randn([batch_size, seq_length, d_model])
key = query
value = query
m = model(query, key, value)
print (m)

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5665933.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存