注意力机制的本质_多对多

如图所示,一般描述注意力机制都是这样的图这样的图其实就是

序列元素之间彼此建立一种关系,那么看此图可以知道元素自己和自己建立了关系,这个人觉得是浪费权重的表现,其实要建立元素和元素之间的关系

其实可以这样看上图

竖着的一侧作为输入,横着的每个作为输出这样就能建立关系。但是有一个疑问就是无论输出是什么输入都是一样的,所以我们不能这样输入

我们要将输入一个输出建立一种对应关系,这个关系就是无论输入是多长输入不能存在输出,但是又不能没有关系(我们规定输出只有一个元素)那么我们可以使输入必须使用一个cls 占位输出的位置(也即是输入的序列必须包含输出但是不能表示为输出,只是使用一个其他用来占位,这个占位可以帮助任何的元素占位,也就是未知数,输入只能由一个未知数),这样输入和输出就存在必然关系,且网络也能建立元素之间的位置关系。

其实这个和bert的mask 差不多只不过bert是采用多对多的机制,我们力求将问题简化,也就是说我们的输出的结果只有元素个类别。

举例说明

数据 三体文明

输入 cls 体文明

输出 三

输入 三cls文明

输出 体

输入 三体cls明

输出 文

输入 三体文cls

输出 明

例子代码

import torch
from torch import nn
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
class autoencoder(nn.Module):
def __init__(self,seq_len,num_class):
super(autoencoder, self).__init__()

self.liner_1=nn.Linear(seq_len,100,bias=True)
self.relu=nn.ReLU(True)
self.bn=nn.BatchNorm1d(100)
self.liner_2=nn.Linear(100,num_class)
def forward(self,x):
x=self.liner_1(x)

x = self.relu(x)
x = self.bn(x)


x=self.liner_2(x)


return x
data="ABCDEFGHIGKLMNOPQRSTUVWXYZ"
seq_len=10
data_list=[]
for j in data:
for i in range(0,len(data[data.index(j):]),seq_len):
res=data[data.index(j):][i:i+seq_len]
if len(res)==seq_len:

#制作label 使用27代表cls
for z in res:
res_num = [0]*seq_len
label=data.index(z)

res_num[res.index(z)]=len(data)+1
for z_ in res:
if z_==z:
continue
else:
res_num[res.index(z_)] =data.index(z_)


data_list.append([res_num,label])
train_data = DataLoader(dataset=data_list, batch_size=10, shuffle=True)
model=autoencoder(seq_len,len(data))
loss_f=torch.nn.CrossEntropyLoss()
opt=torch.optim.Adam(model.parameters(),0.001,weight_decay=0.0001)

# 绘图设置
#定义两个数组
Loss_list = []
Accuracy_list = []




for epoch in range(200):
loss_list=[]
for i,data_ in enumerate(train_data):
input_data=torch.Tensor([i.numpy().tolist() for i in data_[0]]).permute(1,0)
output=model(input_data)
loss=loss_f(output,data_[1])


loss_list.append(loss.data.numpy().tolist())

opt.zero_grad()
loss.backward()
opt.step()
Loss_list.append(sum(loss_list)/len(loss_list))


#我这里迭代了200次,所以x的取值范围为(0,200),然后再将每次相对应的准确率以及损失率附在x上
x2 = range(len(Loss_list))


y2 = Loss_list


plt.subplot(1, 1, 1)
plt.plot(x2, y2, '-')
plt.xlabel('Train loss vs. epoches')
plt.ylabel('Train loss')

plt.show()
# plt.savefig("accuracy_loss.jpg")

if __name__ == '__main__':
pass

看下图可以知道这是一个盆地。说明这样的设计数据集和标签学到了东西并且收敛了,可以调节seq_len 的长度

注意力机制的本质_取值范围_02