Transformer多步时序预测:多变量输入,单变量输出

文章目录

  • Transformer类
  • 数据集类
  • 训练函数
  • 测试函数
  • 画图
  • 计算指标
  • 读取数据
  • 计时
  • 开始训练

数据集来源: https://github.com/zhouhaoyi/ETDataset

import torch
import torch.nn as nn
import numpy as np
import pandas as pd
import math
import time
from sklearn.preprocessing import MinMaxScaler
from torch.utils.data import Dataset, DataLoader
import matplotlib.pyplot as plt
from matplotlib_inline import backend_inline 
backend_inline.set_matplotlib_formats('svg')

Transformer类

只使用encoder,然后把encoder的输出展平,后接线性层进行输出,理解为encoder只是把原始特征进行变换。

class PositionalEncoding(nn.Module):def __init__(self, d_model, max_len=5000):super(PositionalEncoding, self).__init__()pe = torch.zeros(max_len, d_model)position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))pe[:, 0::2] = torch.sin(position * div_term)pe[:, 1::2] = torch.cos(position * div_term)pe = pe.unsqueeze(0).transpose(0, 1)self.register_buffer('pe', pe)def forward(self, x):return x + self.pe[:x.size(0), :] # [seq_length, batch_size, d_model]class TransformerTimeSeriesModel(nn.Module):def __init__(self, input_size, output_size, seq_length, label_length, d_model = 256, nhead = 8, num_layers = 2, dropout=0.5):'''input_size, output_size, seq_length, label_length分别为输入维度、输出维度、历史时刻步数、多步预测步数'''super(TransformerTimeSeriesModel, self).__init__()self.src_mask = Noneself.embedding = nn.Linear(input_size, d_model)self.pos_coding = PositionalEncoding(d_model)self.encoder_layer = nn.TransformerEncoderLayer(d_model = d_model, nhead = nhead, dim_feedforward=4 * d_model, dropout = dropout)self.transformer_encoder = nn.TransformerEncoder(self.encoder_layer, num_layers = num_layers)self.fc1 = nn.Linear(seq_length * d_model, label_length * d_model)self.fc2 = nn.Linear(label_length * d_model, label_length * output_size)self.init_weights()def forward(self, src):if self.src_mask is None:device = src.devicemask = self._generate_square_subsequent_mask(len(src)).to(device)self.src_mask = masksrc = self.embedding(src)src = self.pos_coding(src)en_output = self.transformer_encoder(src, self.src_mask) # [seq_length, batch_size, d_model]en_output = en_output.view(en_output.size(1), -1)  # [batch_size, seq_length * d_model]output = self.fc1(en_output) # [batch_size, label_length * d_model]output = self.fc2(output) # [batch_size, label_length * output_size]return output.view(-1, label_length, output_size) # [batch_size, label_length, output_size]def init_weights(self):initrange = 0.1for module in self.modules():if isinstance(module, nn.Linear):module.weight.data.uniform_(-initrange, initrange)if module.bias is not None:module.bias.data.zero_()def _generate_square_subsequent_mask(self, sz):mask = (torch.triu(torch.ones(sz, sz)) == 1).transpose(0, 1)mask = mask.float().masked_fill(mask == 0, float('-inf')).masked_fill(mask == 1, float(0.0))return mask

数据集类

class get_dataset(Dataset):def __init__(self, data_path, seq_length, label_length, features, train_split, mode):self.mode = modeself.data_path = data_pathself.features = featuresself.seq_length = seq_lengthself.label_length = label_lengthself.data, self.data_mean, self.data_std = self.get_data()print('self.data.shape:',self.data.shape)# print(self.data[0, :self.seq_length, :].shape) # torch.Size([96, 7])# print(self.data[0, -self.label_length:, -1].shape) # torch.Size([24])train_num = int(train_split * len(self.data))if self.mode == 'train':print('train_samples_num:',train_num)self.data = self.data[:train_num, :, :]else:print('test_samples_num:',len(self.data)-train_num)self.data = self.data[train_num:, :, :]def __len__(self):return len(self.data)def __getitem__(self, index):en_input = self.data[index, :self.seq_length, :]label = self.data[index, -self.label_length:, -1].unsqueeze(1)return en_input, labeldef get_data(self):data = pd.read_csv(self.data_path)data.index = pd.to_datetime(data['date'])data = data.drop('date', axis=1)data_mean = data.mean()data_std = data.std()data = (data - data_mean) / data_stdnum_sample = len(data) - self.seq_length - self.label_length + 1print('len(data):', len(data), 'num_sample:', num_sample)print('len(self.features):',len(self.features))seq_data = torch.zeros(num_sample, self.seq_length + self.label_length, len(self.features))# print(data.iloc[0:0 + self.seq_length + 1, [*range(len(self.features))]].values)for i in range(num_sample):seq_data[i] = torch.tensor(data.iloc[i:i + self.seq_length + self.label_length,[*range(len(self.features))]].values)return seq_data, data_mean, data_std

训练函数

def train(model, dataset, epochs, optim, loss_function, batch_size, shuffle=True):print('training on :', device)data_loader = DataLoader(dataset, batch_size = batch_size, shuffle=shuffle)val_i = np.random.randint(0, 3400, 5)for epoch in range(epochs):train_loss = 0model.train()for x, label in data_loader:# print(x.shape, label.shape) # torch.Size([32, 96, 7]) torch.Size([32, 24, 1])x, label = x.permute(1,0,2).to(device), label.to(device)pred = model(x) # torch.Size([32, 24, 1])loss = loss_function(pred, label)optim.zero_grad()loss.backward()optim.step()train_loss += loss.item()train_loss /= len(data_loader)print(f'[{timeSince(start)}] ', end='')print('epoch: %d, lr: %.8f, train loss : %.8f' % (epoch + 1, scheduler.get_last_lr()[0],train_loss), end='')scheduler.step() pred_array, true_array = test(model, dataset_test, batch_size, shuffle=False)for i in val_i:print(f'验证集上第{i+1}个样本的MAE:', calculate_mae(pred_array, true_array, i=i))draw_one_sample(pred_array, true_array, i = i)

测试函数

def test(model, dataset, batch_size, shuffle = False):model.eval()val_loss = 0.data_loader = DataLoader(dataset, batch_size, shuffle = shuffle)# print(dataset.data_mean,dataset.data_std)pred_list = []true_list = []for x, label in data_loader:# print(x.shape, label.shape) # torch.Size([32, 96, 7]) torch.Size([32, 24, 1])x, label = x.permute(1,0,2).to(device), label.to(device)pred = model(x) # torch.Size([32, 24, 1])loss = loss_function(pred, label)val_loss += loss.item()pred = pred.squeeze(2).detach().cpu().numpy()true = label.squeeze(2).detach().cpu().numpy()# print(pred.shape, true.shape) # (32, 24) (32, 24)pred = pred * dataset.data_std['OT'] + dataset.data_mean['OT']true = true * dataset.data_std['OT'] + dataset.data_mean['OT']x_true = x.permute(1,0,2)[:, :, -1].detach().cpu().numpy() # (32, 96)x_true = x_true * dataset.data_std['OT'] + dataset.data_mean['OT']combined = np.concatenate((x_true, true), axis=1) # (32, 120)pred_list.append(pred)true_list.append(combined)# print(len(pred_list)) # 109 # 可知109 * 32 = 3488 > 3461(验证集的数量),即最后一个batch的样本数不足32pred_array = np.vstack(pred_list)  # 形状为 (验证集的数量, 24)true_array = np.vstack(true_list)  # 形状为 (验证集的数量, 120)print(' val loss : %.8f' % (val_loss/len(data_loader)))return pred_array, true_array

画图

def draw_one_sample(pred_array, true_array, i=0):'''绘制验证集上第i个样本的预测结果图pred_array.shape: (验证集的数量, 24) 24为多步预测的步数true_array.shape: (验证集的数量, 120) 120为真实数据,前96步为历史数据,后24步为目标真实值'''pred = pred_array[i]  # shape: (24,)true = true_array[i]  # shape: (120,)historical_true = true[:seq_length]  # 前96步为历史数据target_true = true[seq_length:]       # 后24步为目标真实值plt.figure(figsize=(8, 4))plt.plot(historical_true, label='Historical Data', color='blue', marker='o', markersize=3)plt.plot(range(seq_length, seq_length+label_length), target_true, label='Target True Values', color='green', marker='o', markersize=3)plt.plot(range(seq_length, seq_length+label_length), pred, label='Predicted Values', color='red', linestyle='--', marker='x', markersize=3)plt.legend()plt.title(f'Prediction vs True Values for Sample {i+1}')plt.xlabel('Time Steps')plt.ylabel('Values')plt.grid()plt.show()

计算指标

def calculate_mae(pred_array, true_array,i):"""计算平均绝对误差 (MAE)参数:pred_array: np.ndarray,预测值数组,形状为 (验证集的数量, 24)true_array: np.ndarray,真实值数组,形状为 (验证集的数量, 120)返回:mae: float,平均绝对误差"""# 取出真实值中的目标部分(即后 24 个时间步)true_values = true_array[i, -label_length:]mae = np.mean(np.abs(pred_array[i,:] - true_values))return mae

读取数据

seed = 0
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
torch.manual_seed(seed)
if torch.cuda.is_available():torch.cuda.manual_seed(seed)torch.cuda.manual_seed_all(seed)  
np.random.seed(seed)  
torch.backends.cudnn.benchmark = False
torch.backends.cudnn.deterministic = Trueseq_length = 96
label_length = 24
features = ['HUFL','HULL','MUFL','MULL','LUFL','LULL','OT'] # 'OT'为标签列,其历史数据可以帮助预测其未来值,故也可以当作特征
input_size = len(features) # 7
output_size = 1
train_split = 0.8
data_path = '/kaggle/input/example-dataset/ETTh1.csv'dataset_train = get_dataset(data_path, seq_length, label_length, features, train_split = train_split, mode = 'train')
dataset_test = get_dataset(data_path, seq_length, label_length, features, train_split = train_split, mode = 'test')
len(data): 17420 num_sample: 17301
len(self.features): 7
self.data.shape: torch.Size([17301, 120, 7])
train_samples_num: 13840
len(data): 17420 num_sample: 17301
len(self.features): 7
self.data.shape: torch.Size([17301, 120, 7])
test_samples_num: 3461

计时

def timeSince(since):now = time.time()s = now - sincem = math.floor(s / 60)  # math.floor()向下取整s -= m * 60return '%dmin %ds' % (m, s)

开始训练

epochs = 24
lr = 0.001
batch_size = 32
d_model = 20
nhead = 1
num_layers = 1
dropout = 0.1
model = TransformerTimeSeriesModel(input_size, output_size, seq_length, label_length, d_model, nhead,num_layers, dropout = dropout).to(device)optim = torch.optim.AdamW(model.parameters(), lr=lr)
scheduler = torch.optim.lr_scheduler.StepLR(optim, 1.0, gamma=0.98)
loss_function = nn.MSELoss()
start = time.time()
train(model, dataset_train, epochs, optim, loss_function, batch_size, shuffle = True)
# torch.save(model.state_dict(), 'transformer.pth')# pred_array, true_array = test(model, dataset_test, batch_size, shuffle=False)
[1min 33s] epoch: 24, lr: 0.00062835, train loss : 0.65996791 val loss : 0.26256496
验证集上第2733个样本的MAE: 0.7049041

在这里插入图片描述

验证集上第2608个样本的MAE: 1.7675642

在这里插入图片描述

验证集上第1654个样本的MAE: 1.8673252

在这里插入图片描述

验证集上第3265个样本的MAE: 0.9914896

在这里插入图片描述

验证集上第836个样本的MAE: 2.9960492

在这里插入图片描述

感觉在ETTh1数据集上使用transformer效果一般。

最后,今天在知乎上看到一篇文章挺好的:

「万字长文」长序列预测 & 时空预测,你是否被这些问题困扰过?一文带你探索多元时间序列预测的研究进展!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/458761.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RabbitMq-队列交换机绑定关系优化为枚举注册

📚目录 📚简介:🚀比较💨通常注册🌈优化后注册 ✍️代码💫自动注册的关键代码 📚简介: 该项目介绍,rabbitMq消息中间件,对队列的注册,交换机的注册&#xff0c…

使用pyinstaller将python代码打包为exe程序

打包exe 对于不懂程序的人来说,可能有这样一个认识上的误区:只有能够直接打开的exe才是平常经常见到的程序,py文件不能算是程序。 在这种情况下,一些python的使用者可能非常苦恼:怎么才能够让我的程序,看…

博客搭建之路:hexo搜索引擎收录

文章目录 hexo搜索引擎收录以百度为例 hexo搜索引擎收录 hexo版本5.0.2 npm版本6.14.7 next版本7.8.0 写博客的目的肯定不是就只有自己能看到,想让更多的人看到就需要可以让搜索引擎来收录对应的文章。hexo支持生成站点地图sitemap 在hexo下的_config.yml中配置站点…

2-ZYNQ 折腾记录 -PMU

The AMD Zyng UltraScale MPSoC包括一个专用的用户可编程处理器,该平台测量单元(Platform Measurement Unit, PMU)处理器用于电源、错误管理和执行可选的软件测试库(Software Test Library, STL)用于功能安全应用。 PMU执行以下一组任务。启动前对系统的初始化。电…

Video-XL:面向小时级视频理解的超长视觉语言模型

在人工智能领域,视频理解一直是一个挑战性的任务,尤其是对于长时间视频内容的理解。现在,Video-XL的问世标志着我们在这一领域迈出了重要的一步。Video-XL是一个专为小时级视频理解设计的超长视觉语言模型,它能够处理超长视频序列…

BUUCTF之web篇

第一题 [极客大挑战 2019]EasySQL 打开靶机后可以看到这是一个登陆的页面 我们可以尝试两种方式登录 弱口令爆破(burpsuite) 通过SQL注入里的万能密码来跳过账户和密码验证的过程 这里就需要万能密码aor true # 在这里单引号的作用是结束用户名或者密码…

【Javaee】网络原理—http协议(一)

前言 本篇文章将详细介绍http协议,将介绍http抓包工具的下载与使用。 目录 一.http协议初识 1.概念 2.特点 1)版本 2)工作方式 二.http抓包工具 1.抓包是什么 2.抓包软件下载(Fiddler) 3.使用 三.http格式 …

04C++循环结构

//while 循环#include <iostream> using namespace std; int main() { int num0; while (num<10){ cout<<num<<endl; num; } return 0; } //do while语句 #include <iostream> using namespace std; int mai…

Appium中的api(一)

目录 1.基础python代码准备 1--参数的一些说明 2--python内所要编写的代码 解释 2.如何获取包名和界面名 1-api 2-完整代码 代码解释 3.如何关闭驱动连接 4.安装卸载app 1--卸载 2--安装 5.判断app是否安装 6.将应用放到后台在切换为前台的时间 7.UIAutomatorViewer的使用 1--找…

并联 高电压、高电流 放大器实现 2 倍输出电流模块±2A

1.1 并联输出电路设计注意事项 直接对两个功率运算放大器的输出进行硬接线并不是一种好的电气做法。如果两个运算放大器的输出直接连接在一起&#xff0c;则可能会导致不均匀的电流共享。这是因为其中的每个运算放大器都尝试强制施加略微不同的 Vout 电压&#xff0c;该电压取决…

vulnhub(16):sickos(两种打点方式)

端口 ip&#xff1a;192.168.72.154 nmap -Pn -p- 192.168.72.154 --min-rate 10000PORT STATE SERVICE 22 open ssh 3128 open http-proxy 8080 closed http-proxy web渗透方式一&#xff1a;web后台 正常访问80端口&#xff0c;是不开放的&#xff0c;我们需要配置…

高速定向广播声光预警系统赋能高速安全管控

近年来&#xff0c;高速重大交通事故屡见不鲜&#xff0c;安全管控一直是高速运营的重中之重。如何利用现代化技术和信息化手段&#xff0c;创新、智能、高效的压降交通事故的发生概率&#xff0c;优化交通安全管控质量&#xff0c;是近年来交管部门的主要工作&#xff0c;也是…

云原生Istio基础

一&#xff0e;Service Mesh 架构 Service Mesh&#xff08;服务网格&#xff09;是一种用于处理服务到服务通信的专用基础设施层。它的主要目的是将微服务之间复杂的通信和治理逻辑从微服务代码中分离出来&#xff0c;放到一个独立的层中进行管理。传统的微服务架构中&#x…

浅析Android View绘制过程中的Surface

前言 在《浅析Android中View的测量布局流程》中我们对VSYNC信号到达App进程之后开启的View布局过程进行了分析&#xff0c;经过对整个App界面的View树进行遍历完成了测量和布局&#xff0c;确定了View的大小以及在屏幕中所处的位置。但是&#xff0c;如果想让用户在屏幕上看到…

【十六进制数转十进制数 】

【十六进制数转十进制数 】 C语言版本C 版本Java版本Python版本 &#x1f490;The Begin&#x1f490;点点关注&#xff0c;收藏不迷路&#x1f490; 从键盘接收一个十六进制数&#xff0c;编程实现将其转换成十进制数。 输入 输入一个十六进制数 输出 输出一个十进制数 样…

GitHub 上的优质 Linux 开源项目,真滴硬核!

作为一名互联网人&#xff0c;提起 Linux 大家都不陌生&#xff0c;尤其是日常跟 Linux 操作系统打交道最多的&#xff0c;最熟悉不过了。互联网上关于 Linux 相关的教程和资料也非常的多&#xff0c;但是当你从中筛选出真正对自己有帮助的资料是需要花费很大精力与时间的。 G…

JVM基础(内存结构)

文章目录 内存结构JAVA堆方法区 &#xff08;Method Area&#xff09;运行时常量池&#xff08;Runtime Constant Pool&#xff09; 虚拟机栈 &#xff08;Java Virtual Machine Stack&#xff09;本地方法摘栈&#xff08;Native Method Stacks&#xff09;程序计数器&#xf…

交易的人生就是对未来不断的挑战!

在这个充满不确定性的市场中&#xff0c;我们每个人都渴望找到一条通往成功的路径。在Eagle Trader交易员中&#xff0c;有一位资深交易者&#xff0c;他不仅对交易有着不同寻常的执着和热爱&#xff0c;而且他的真诚见解和独到的交易哲学&#xff0c;可能会触动你的心弦。他的…

尚硅谷-react教程-求和案例-@redux-devtools/extension 开发者工具使用-笔记

## 7.求和案例_react-redux开发者工具的使用(1).npm install redux-devtools/extension(2).store中进行配置import { composeWithDevTools } from redux-devtools/extension;export default createStore(allReducer,composeWithDevTools(applyMiddleware(thunk))) src/redux/s…

OpenCV系列教程六:信用卡数字识别、人脸检测、车牌/答题卡识别、OCR

文章目录 一、信用卡数字识别1.1 模板匹配1.2 匹配多个对象1.3 处理数字模板1.4 预处理卡片信息&#xff0c;得到4组数字块。1.5 遍历数字块&#xff0c;将卡片中每个数字与模板数字进行匹配 二、人脸检测2.1人脸检测算法原理2.2 OpenCV中的人脸检测流程 三、车牌识别3.1 安装t…