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。预测效果比较理想。

### 使用Transformer模型进行时间序列预测 #### 数据准备与预处理 为了有效利用Transformer模型进行时间序列预测,数据预处理是一个至关重要的环节。通常情况下,原始的时间序列数据需要经过标准化或归一化处理,以便更好地适应神经网络的学习机制[^1]。 ```python from sklearn.preprocessing import StandardScaler scaler = StandardScaler() data_scaled = scaler.fit_transform(data_raw) ``` #### 构建Transformer模型结构 基于PyTorch框架下的实现方式提供了灵活且高效的解决方案。具体来说,可以通过定义编码器层、解码器层以及位置编码来搭建完整的Transformer架构[^2]。 ```python import torch.nn as nn class TransformerModel(nn.Module): def __init__(self, input_dim, model_dim, num_heads, num_layers, output_dim): super(TransformerModel, self).__init__() self.embedding = nn.Linear(input_dim, model_dim) encoder_layer = nn.TransformerEncoderLayer(d_model=model_dim, nhead=num_heads) self.transformer_encoder = nn.TransformerEncoder(encoder_layer, num_layers=num_layers) self.fc_out = nn.Linear(model_dim, output_dim) def forward(self, src): embedded = self.embedding(src) transformer_output = self.transformer_encoder(embedded) prediction = self.fc_out(transformer_output) return prediction ``` #### 训练过程 在训练阶段,采用均方误差(MSE)作为损失函数,并借助Adam优化算法调整参数权重,从而最小化预测值与真实标签之间的差距。 ```python criterion = nn.MSELoss() optimizer = optim.Adam(model.parameters(), lr=0.001) for epoch in range(num_epochs): optimizer.zero_grad() outputs = model(train_data) loss = criterion(outputs, labels) loss.backward() optimizer.step() ``` #### 预测操作 完成模型训练之后,在执行预测任务前需先加载保存的最佳模型状态字典;随后输入待预测样本至该模型中获取最终的结果输出。 ```python model.load_state_dict(torch.load('best_model.pth')) model.eval() with torch.no_grad(): predictions = model(test_input) ``` 通过上述方法能够有效地运用Transformer模型来进行时间序列数据分析及未来趋势预测工作。值得注意的是,对于不同的应用场景还需针对性地调整部分超参设置以达到最优效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值