Transformer进行序列预测

Transformer进行序列预测


Transformer用于自然语言处理NLP取得很优秀的效果。尝试使用Transformer的编码器Encoder实现序列的预测。比如根据日期、销量、库等预测采购数量。为了验证模型首先用随机数产生源数据和目标数据,测试模型能否学习数据并做出正确的预测。
生成1000个样本每个样本10个随机数,相当于自然语言1000句话每句话10个词。需要训练的目标2个维度,第0个维度为随机数和源数据的最大值、最小值。第1个维度是随机数,为了增加难度乘以10。

device=torch.device('cuda' if torch.cuda.is_available() else 'cpu')
#数据行数
numberofdata = 1000

#每行维度,相当于每句话有多个词。
srcdim = 10

#目标维度
targetdim = 2
#注意力头数。
number_of_heads=2
#词向量维度
word_embeding_dim=16

trainepoch=200

def loaddata(numberofdata,srcdim,targetdim):
    gen = torch.Generator();
    gen.manual_seed(2)
    data=torch.rand((numberofdata, srcdim), generator=gen)
    datay = torch.rand((numberofdata, targetdim), generator=gen)

    #偶数行最大值
    datay[0::2,0]=data[0::2,:].max(dim=-1).values

    #奇数行最小值
    datay[1::6,0]=data[1::6,:].min(dim=-1).values

    #拉开范围
    datay[:,-1]=datay[:,-1]*10.0

    data=data.to(device)
    datay=datay.to(device)
    return data,datay

嵌入层和位置编码的处理。输入数据必须先进行编码,相当于将每个词编码成词向量。输入的每一个随机数当做一个Long类型的词input_ids。为了简化按数据行号和每个数据在样本中的位置进行编码。 位置编码按偶数和奇数计算正弦和余弦计算。

# 位置编码层
class PositionEmbedding(nn.Module):
    def __init__(self):
        super(PositionEmbedding,self).__init__()
        # pos是第几个词,i是词向量位置,d_model是维度总数
        def get_pe(pos, i, d_model):
            fenmu = 1e4 ** (i / d_model)
            pe = pos / fenmu
            pe = torch.tensor(pe)
            if i % 2 == 0:
                return torch.sin(pe)
            return torch.cos(pe)

        # 初始化位置编码矩阵
        pe = torch.empty(srcdim, word_embeding_dim)
        for i in range(srcdim):
            for j in range(word_embeding_dim):
                pe[i, j] = get_pe(i, j, word_embeding_dim)
        pe = pe.unsqueeze(0)

        # 定义为不更新的常量
        self.register_buffer('pe', pe)

        # 词编码层
        self.embed = nn.Embedding(srcdim*numberofdata, word_embeding_dim)
        # 初始化参数
        self.embed.weight.data.normal_(0, 0.1)


    def forward(self, rowindex, x):
        # [8, 50] -> [8, 50, 32]
        batchsize=x.shape[0]
        #每个input_ids的位置
        pos = torch.arange(0,srcdim).unsqueeze(0).repeat(batchsize,1).to(device)

        #行位置=行号*每行词向量维度
        rowpos = (rowindex * srcdim).unsqueeze(1).repeat(1,srcdim).to(device)
        pos = pos + rowpos
        embed = self.embed(pos)

        #词向量加位置
        embed = embed + self.pe
        return embed

编码调用Encoder,解码用一个维度1全连接层。输出结果取目标维度行,损失函数使用mse。

class SentenceModel(nn.Module):
    def __init__(self):
        super(SentenceModel,self).__init__()
        self.x_embeding=PositionEmbedding()
        num_encode_decode_layers=6
        encoderlayer = nn.TransformerEncoderLayer(word_embeding_dim, number_of_heads, batch_first=True, norm_first=True)
        self.encoder = nn.TransformerEncoder(encoderlayer, num_layers=num_encode_decode_layers)
        self.fc_out=nn.Linear(word_embeding_dim,1)

    #rowindex是数据生成时的行号,用于计算词向量
    def forward(self,rowindex,x):
        x_embeding=self.x_embeding(rowindex,x)

        pred = self.encoder(x_embeding)
        out = self.fc_out(pred)
        return out

经过多次迭代训练后取得了比较理想的效果。8个样本评估差方小于0.1。

def train():
    #每批8个
    samples_one_batch = 8
    loader = torch.utils.data.DataLoader(dataset=dataset, batch_size=samples_one_batch, shuffle=True)
    # Initializing a BERT bert-base-uncased style configuration
    optim = Adam(model.parameters(), lr=1e-3)
    sheduler = torch.optim.lr_scheduler.StepLR(optim, step_size=1000, gamma=0.99)
    model.train(True)

    for epoch in tqdm(range(trainepoch)):
        for batchindex,(rowindex,x,y) in enumerate(loader):
            optim.zero_grad()

            pred = model(rowindex,x)
            pred = pred[:,0:targetdim].reshape(-1)
            y = y.reshape(-1)
            loss = F.mse_loss(pred,y)
            loss.backward()
            #torch.nn.utils.clip_grad_norm_(model.parameters(),0.5)
            optim.step()
            sheduler.step()
            #使用交叉熵,softmax+log+nulloss,embedembed
        ev = evalmodel(model)
        lr =optim.param_groups[0]['lr']
        print(f'epoch={epoch},lr={lr},loss={loss},eval={ev}')

目标数据这样的

ys
tensor([0.9216, 1.2265, 0.4586, 5.7319, 0.9877, 1.9658, 0.0550, 0.4252, 0.9247,
        7.1420, 0.1124, 4.3715, 0.8366, 9.2239, 0.8488, 6.5507],
       device='cuda:0')

预测结果这样的

 pred
tensor([0.9448, 1.2840, 0.5323, 5.6820, 0.9052, 1.9387, 0.1148, 0.4421, 0.9674,
        7.0415, 0.1527, 4.3014, 0.9212, 9.0716, 0.8516, 6.4683],
       device='cuda:0', grad_fn=<UnsafeViewBackward0>)

差方和0.0788。预测效果比较理想。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值