5 时间序列预测入门:LSTM+Transformer

news2024/11/24 15:41:50

0 引言

论文地址:https://arxiv.org/abs/1706.03762

 1 Transformer

        Transformer 模型是一种用于处理序列数据的深度学习模型,主要用于解决自然语言处理(NLP)任务。它在许多 NLP 任务中取得了重大突破,如机器翻译、文本摘要、语言生成、问答系统等。

      Transformer 模型的主要优势在于能够捕捉长距离依赖关系,而不需要使用递归或卷积等传统的序列模型。它引入了自注意力机制(self-attention),使得模型可以同时考虑输入序列中的所有位置,从而更好地理解上下文关系。

        Transformer 模型还具有可并行计算的能力,因为它可以在整个序列上进行并行计算,而不需要按顺序处理每个位置。这使得 Transformer 在处理大规模数据时具有较高的效率。

除了 NLP 任务,Transformer 模型还可以应用于其他序列数据的建模和处理,如音频处理、时间序列预测等。它的灵活性使得它成为处理序列数据的重要工具之一。

        

Transformer 模型是一种基于自注意力机制(self-attention)的深度学习模型,用于处理序列数据。它最大的特点是:

1. 自注意力机制:Transformer 引入了自注意力机制,使得模型可以在处理序列时同时考虑输入序列中的所有位置。传统的序列模型通常使用固定的窗口或滑动窗口来捕捉上下文关系,而自注意力机制可以根据输入序列的不同部分自动调整权重,更好地捕捉长距离的依赖关系。

2. 并行计算:Transformer 模型可以在整个序列上进行并行计算,而不需要按顺序处理每个位置。这是由于自注意力机制的特性,每个位置的表示可以同时考虑整个序列的信息。这使得 Transformer 在处理大规模数据时具有较高的效率。

3. 编码器-解码器结构:Transformer 模型通常由编码器和解码器组成。编码器用于将输入序列编码为一系列表示,而解码器则根据编码器的输出和之前的预测生成输出序列。这种结构在机器翻译等任务中表现出色。

4. 多头注意力机制:Transformer 模型还引入了多头注意力机制,允许模型在不同的表示子空间中学习多个不同的注意力表示。这有助于模型更好地捕捉不同类型的关系和特征。

总的来说,Transformer 模型的最大特点是其能够处理长距离依赖关系、并行计算能力强、具有多头注意力机制等特性,使其成为处理序列数据的重要模型。

本文提出使用LSTM结合Transformer的结构提取数据信息,尝试预测。由于数据集与计算能力有限并不能很好的拟合。

数据集: https://download.csdn.net/download/qq_28611929/88573481?spm=1001.2014.3001.5503icon-default.png?t=N7T8https://download.csdn.net/download/qq_28611929/88573481?spm=1001.2014.3001.5503

2 pytorch模块介绍

```python
class torch.nn.TransformerEncoderLayer(d_model, nhead, dim_feedforward=2048, dropout=0.1, activation='relu')
```

- `d_model`:输入和输出的特征维度(隐藏单元数)。
- `nhead`:多头注意力机制中的头数。
- `dim_feedforward`:前馈神经网络中间层的维度。
- `dropout`:Dropout 层的丢弃率。
- `activation`:激活函数的类型,默认为 ReLU。

`nn.TransformerEncoderLayer` 的输入和输出形状如下:

输入形状:(序列长度, 批量大小, 特征维度) 或 (批量大小, 序列长度, 特征维度)。

输出形状:与输入形状相同。

注意,输入和输出的维度顺序取决于是否设置了 `batch_first=True`。如果设置了 `batch_first=True`,则输入和输出的维度顺序为 (批量大小, 序列长度, 特征维度)。否则,维度顺序为 (序列长度, 批量大小, 特征维度)。

```python
class torch.nn.TransformerEncoder(encoder_layer, num_layers, norm=None)
```

- `encoder_layer`:一个 `nn.Module` 对象,表示 Transformer 编码器层。可以使用 `nn.TransformerEncoderLayer` 创建。
- `num_layers`:编码器层的数量。
- `norm`:可选的归一化层,用于对每个编码器层的输出进行归一化处理。

`nn.TransformerEncoder` 的输入和输出形状如下:

输入形状:(序列长度, 批量大小, 特征维度) 或 (批量大小, 序列长度, 特征维度)。

输出形状:与输入形状相同。

请注意,输入和输出的维度顺序取决于是否设置了 `batch_first=True`。如果设置了 `batch_first=True`,则输入和输出的维度顺序为 (批量大小, 序列长度, 特征维度)。否则,维度顺序为 (序列长度, 批量大小, 特征维度)。

map: 输入输出的维度相同,就想做了一个转换,我的躯体还是我,只是灵魂变了;

y. = TransformerEncoder(input)

input (批量大小, 序列长度, 特征维度)

y (批量大小, 序列长度, 特征维度) 

2.1 使用transformer的encoder模块

import numpy as np
import pandas as pd
import torch
import torch.nn as nn
from torch.nn.utils import weight_norm
#import tushare as ts
from sklearn.preprocessing import StandardScaler, MinMaxScaler
from torch.utils.data import TensorDataset
from tqdm import tqdm
from sklearn.model_selection import train_test_split

import matplotlib.pyplot as plt
import sys
import os
import gc
import argparse
import warnings
 
warnings.filterwarnings('ignore')


class Config():
    data_path = '../data/data1/train/power.csv'
    timestep = 18  # 时间步长,就是利用多少时间窗口
    batch_size = 32  # 批次大小
    feature_size = 1  # 每个步长对应的特征数量,这里只使用1维,
    hidden_size = 64
    num_heads = 4
    output_size = 1  # 由于是单卷机和输出任务,最终输出层大小为1
    num_layers = 2  # lstm的层数
    epochs = 10 # 迭代轮数
    best_loss = 0 # 记录损失
    learning_rate = 0.003 # 学习率
    model_name = 'transformer' # 模型名称
    save_path = './{}.pth'.format(model_name) # 最优模型保存路径
    
config = Config()

# 读取数据
train_power_forecast_history = pd.read_csv('../data/data1/train/power_forecast_history.csv')
train_power = pd.read_csv('../data/data1/train/power.csv')
train_stub_info = pd.read_csv('../data/data1/train/stub_info.csv')
 
test_power_forecast_history = pd.read_csv('../data/data1/test/power_forecast_history.csv')
test_stub_info = pd.read_csv('../data/data1/test/stub_info.csv')
 
# 聚合数据
train_df = train_power_forecast_history.groupby(['id_encode','ds']).head(1)
del train_df['hour']
 
test_df = test_power_forecast_history.groupby(['id_encode','ds']).head(1)
del test_df['hour']
 
tmp_df = train_power.groupby(['id_encode','ds'])['power'].sum()
tmp_df.columns = ['id_encode','ds','power']
 
# 合并充电量数据
train_df = train_df.merge(tmp_df, on=['id_encode','ds'], how='left')
 
### 合并数据
train_df = train_df.merge(train_stub_info, on='id_encode', how='left')
test_df = test_df.merge(test_stub_info, on='id_encode', how='left')

h3_code = pd.read_csv("../data/h3_lon_lat.csv")
train_df = train_df.merge(h3_code,on='h3')
test_df = test_df.merge(h3_code,on='h3')

# 卡尔曼平滑
def kalman_filter(data, q=0.0001, r=0.01):
    # 后验初始值
    x0 = data[0]                              # 令第一个估计值,为当前值
    p0 = 1.0
    # 存结果的列表
    x = [x0]
    for z in data[1:]:                        # kalman 滤波实时计算,只要知道当前值z就能计算出估计值(后验值)x0
        # 先验值
        x1_minus = x0                         # X(k|k-1) = AX(k-1|k-1) + BU(k) + W(k), A=1,BU(k) = 0
        p1_minus = p0 + q                     # P(k|k-1) = AP(k-1|k-1)A' + Q(k), A=1
        # 更新K和后验值
        k1 = p1_minus / (p1_minus + r)        # Kg(k)=P(k|k-1)H'/[HP(k|k-1)H' + R], H=1
        x0 = x1_minus + k1 * (z - x1_minus)   # X(k|k) = X(k|k-1) + Kg(k)[Z(k) - HX(k|k-1)], H=1
        p0 = (1 - k1) * p1_minus              # P(k|k) = (1 - Kg(k)H)P(k|k-1), H=1
        x.append(x0)                          # 由输入的当前值z 得到估计值x0存入列表中,并开始循环到下一个值
    return x


#kalman_filter()
train_df['new_label'] = 0
for i in range(500):
    #print(i)
    label = i
    #train_df[train_df['id_encode']==labe]['power'].values
    train_df.loc[train_df['id_encode']==label, 'new_label'] = kalman_filter(data=train_df[train_df['id_encode']==label]['power'].values)

### 数据预处理
train_df['flag'] = train_df['flag'].map({'A':0,'B':1})
test_df['flag'] = test_df['flag'].map({'A':0,'B':1})
 
def get_time_feature(df, col):
 
    df_copy = df.copy()
    prefix = col + "_"
    df_copy['new_'+col] = df_copy[col].astype(str)
 
    col = 'new_'+col
    df_copy[col] = pd.to_datetime(df_copy[col], format='%Y%m%d')
    #df_copy[prefix + 'year'] = df_copy[col].dt.year
    df_copy[prefix + 'month'] = df_copy[col].dt.month
    df_copy[prefix + 'day'] = df_copy[col].dt.day
    # df_copy[prefix + 'weekofyear'] = df_copy[col].dt.weekofyear
    df_copy[prefix + 'dayofweek'] = df_copy[col].dt.dayofweek
    # df_copy[prefix + 'is_wknd'] = df_copy[col].dt.dayofweek // 6
    df_copy[prefix + 'quarter'] = df_copy[col].dt.quarter
    # df_copy[prefix + 'is_month_start'] = df_copy[col].dt.is_month_start.astype(int)
    # df_copy[prefix + 'is_month_end'] = df_copy[col].dt.is_month_end.astype(int)
    del df_copy[col]
 
    return df_copy
 
train_df = get_time_feature(train_df, 'ds')
test_df = get_time_feature(test_df, 'ds')

train_df = train_df.fillna(999)
test_df = test_df.fillna(999)

cols = [f for f in train_df.columns if f not in ['ds','power','h3','new_label']]


scaler = MinMaxScaler(feature_range=(0,1))
scalar_falg = False
if scalar_falg == True:
    df_for_training_scaled = scaler.fit_transform(train_df[cols+['new_label']])
    df_for_testing_scaled= scaler.transform(test_df[cols])
else:
    df_for_training_scaled = train_df[cols+['new_label']]
    df_for_testing_scaled = test_df[cols]
#df_for_training_scaled
# scaler_label = MinMaxScaler(feature_range=(0,1))
# label_for_training_scaled = scaler_label.fit_transform(train_df['new_label']..values)
# label_for_testing_scaled= scaler_label.transform(train_df['new_label'].values)
# #df_for_training_scaled

#x_train, x_test, y_train, y_test = train_test_split(df_for_training_scaled.values, train_df['new_label'].values,shuffle=False, test_size=0.2)
x_train_list = []
y_train_list = []
x_test_list = []
y_test_list = []

for i in range(500):
    temp_df = df_for_training_scaled[df_for_training_scaled.id_encode==i]
    x_train, x_test, y_train, y_test = train_test_split(temp_df[cols].values, temp_df['new_label'].values,shuffle=False, test_size=0.2)
    x_train_list.append(x_train)
    y_train_list.append(y_train)

    x_test_list.append(x_test)
    y_test_list.append(y_test)

x_train = np.concatenate(x_train_list)
y_train = np.concatenate(y_train_list)

x_test = np.concatenate(x_test_list)
y_test = np.concatenate(y_test_list)

# 将数据转为tensor
x_train_tensor = torch.from_numpy(x_train.reshape(-1,config.timestep,1)).to(torch.float32)
y_train_tensor = torch.from_numpy(y_train.reshape(-1,1)).to(torch.float32)
x_test_tensor = torch.from_numpy(x_test.reshape(-1,config.timestep,1)).to(torch.float32)
y_test_tensor = torch.from_numpy(y_test.reshape(-1,1)).to(torch.float32)

# 5.形成训练数据集
train_data = TensorDataset(x_train_tensor, y_train_tensor)
test_data = TensorDataset(x_test_tensor, y_test_tensor)

# 6.将数据加载成迭代器
train_loader = torch.utils.data.DataLoader(train_data,
                                           config.batch_size,
                                           True)

test_loader = torch.utils.data.DataLoader(test_data,
                                          config.batch_size,
                                          True)


class Transformer(nn.Module):
    # d_model : number of features
    def __init__(self,feature_size=1,hidden_size=128,num_layers=3,nhead=4,dropout=0.2):
        super(Transformer, self).__init__()
        self.lstm = nn.LSTM(feature_size, hidden_size, num_layers, batch_first=True)
        
        """
        `d_model`:模型的维度,也就是输入和输出的特征维度。
        `nhead`:注意力头数,控制多头注意力的并行度。
        """
        self.encoder_layer = nn.TransformerEncoderLayer(d_model=hidden_size, nhead=4, dropout=dropout,batch_first=True)
        self.transformer_encoder = nn.TransformerEncoder(self.encoder_layer, num_layers=num_layers,mask_check=False) 
        
        self.decoder = nn.Linear(hidden_size, 1) #feature_size是input的个数,1为output个数
        self.init_weights()
    
    #init_weight主要是用于设置decoder的参数
    def init_weights(self):
        initrange = 0.1    
        self.decoder.bias.data.zero_()
        self.decoder.weight.data.uniform_(-initrange, initrange)
 
    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
 
    def forward(self, src, device='cpu'):
        output, (h0,c0) = self.lstm(src)
        # output (batch_size, time_stamp, hidden_size)
        batch_size, time_stamp, hidden_size = output.shape
        
        #print(output.reshape (time_stamp,batch_size,hidden_size).shape)
        #print(output.shape, h0.shape)
        #mask = self._generate_square_subsequent_mask(len(x)).to(device)
        mask = None
        #output = output.reshape(time_stamp,batch_size,hidden_size)
        output = self.transformer_encoder(output)
        #print(output.shape)
        output = self.decoder(output[:,-1,:])
        return output
model = Transformer(feature_size=config.feature_size,hidden_size=config.hidden_size,
                    nhead=config.num_heads,dropout=0.2)

loss_function = nn.MSELoss()  # 定义损失函数
optimizer = torch.optim.AdamW(model.parameters(), lr=config.learning_rate)  # 定义优化器
# 8.模型训练
for epoch in range(50):
    model.train()
    running_loss = 0
    train_bar = tqdm(train_loader)  # 形成进度条
    for data in train_bar:
        x_train, y_train = data  # 解包迭代器中的X和Y
        optimizer.zero_grad()
        y_train_pred = model(x_train)
        loss = loss_function(y_train_pred, y_train.reshape(-1, 1))
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        train_bar.desc = "train epoch[{}/{}] loss:{:.3f}".format(epoch + 1,
                                                                 config.epochs,
                                                                 loss)

    # 模型验证
    model.eval()
    test_loss = 0
    with torch.no_grad():
        test_bar = tqdm(test_loader)
        for data in test_bar:
            x_test, y_test = data
            y_test_pred = model(x_test)
            test_loss = loss_function(y_test_pred, y_test.reshape(-1, 1))

    if test_loss < config.best_loss:
        config.best_loss = test_loss
        torch.save(model.state_dict(), save_path)

print('Finished Training')

ref:

Transformer 模型详解_空杯的境界的博客-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微服务实战系列之Cache

前言 欢迎来到Cache&#xff08;缓存&#xff09;的世界&#xff01; 自从世界第一台计算机诞生之日起&#xff0c;人们对效率的渴望逐步增强。从CPU到存储&#xff0c;从芯片到内存&#xff0c;一批又一批的先驱以一种孜孜不倦的“工匠”精神&#xff0c;为计算机运行效率的提…

【数据结构 —— 二叉树的链式结构实现】

数据结构 —— 二叉树的链式结构实现 1.树的概念及其结构1.1.树概念1.2.树的结构1.3树的相关概念1.4.树的表示1.5. 树在实际中的运用&#xff08;表示文件系统的目录树结构&#xff09; 2.二叉树的概念及其结构2.1二叉树的概念2.2.现实中的二叉树&#xff1a;2.3. 特殊的二叉树…

Flutter开发type ‘Future<int>‘ is not a subtype of type ‘int‘ in type cast错误

文章目录 问题描述错误源码 问题分析解决方法修改后的代码 问题描述 今天有个同事调试flutter程序时报错&#xff0c;问我怎么解决&#xff0c;程序运行时报如下错误&#xff1a; type ‘Future’ is not a subtype of type ‘int’ in type cast 错误源码 int order Databas…

FFmpeg介绍

官方网站&#xff1a;http://www.ffmpeg.org/ 项目组成 libavformat 封装模块&#xff0c;封装了Protocol层和Demuxer、Muxer层&#xff0c;使得协议和格式对于开发者来说是透明的。FFmpeg能否支持一种封装格式的视频的封装与解封装&#xff0c;完全取决于这个库&#xff0c…

《微信小程序开发从入门到实战》学习三十五

4.2 云开发JSON数据库 4.2.3 权限控制 在云开发控制台可以对数据库中的数据进行操作&#xff0c; 在小程序端和云函数可以分别使用小程序API和服务端API对数据中的数据进行操作。 以上操作受到权限控制。 对数据库进行查询属于读操作&#xff0c;增删改操作属于写操作。 …

Python自动化办公:PDF文件的加密与解密

在本篇文章中&#xff0c;我们将介绍如何使用PyPDF2库对PDF文件进行加密和解密操作。 包括如何给PDF文件添加密码&#xff0c;以及如何从受密码保护的PDF文件中删除密码。 注&#xff1a;删除密码的操作&#xff0c;前提是需要知道密码哦 1. 安装PyPDF2库 首先&#xff0c;…

【小黑嵌入式系统第十课】μC/OS-III概况——实时操作系统的特点、基本概念(内核任务中断)、与硬件的关系实现

文章目录 一、为什么要学习μC/OS-III二、嵌入式操作系统的发展历史三、实时操作系统的特点四、基本概念1. 前后台系统2. 操作系统3. 实时操作系统&#xff08;RTOS&#xff09;4. 内核5. 任务6. 任务优先级7. 任务切换8. 调度9. 非抢占式&#xff08;合作式&#xff09;内核10…

el-table,列表合并,根据名称列名称相同的品名将其它列值相同的进行合并

el-table,列表合并,根据名称列名称相同的品名讲其它列值相同的进行合并,并且不能垮品名合并 如图 用到el-table合并行的方法合并 tableSpanMethod({ row, column, rowIndex, columnIndex }) {if (column.property "materielName") {//合并商品名const _row this…

CI/CD 构建中能保护好 SSHKEY吗?

目录 背景 方案 编码存储 逐行存储 合并存储 打马赛克 结论 背景 使用极狐GitLab CI/CD&#xff0c;在部署方面&#xff0c;主要有两种方式&#xff1a; 部署到K8S集群 Push模式&#xff1a;流水线通过kubectl执行命令部署&#xff0c;这需要把K8S的权限给流水线&#xf…

【python程序】把小于10的数值都变成1

【python程序】把小于10的数值都变成1 import numpy as np import xarray as xra xr.DataArray(np.arange(25).reshape(5, 5)) a[np.where(a < 10)] 1 print(a)

微信小程序+中草药分类+爬虫+torch

1 介绍 本项目提供中草药数据集&#xff0c;使用gpu、cpu版本的torch版本进行训练&#xff0c;将模型部署到后端flask&#xff0c;最后使用微信小程序进行展示出来。 数据爬虫可以参考&#xff1a;http://t.csdnimg.cn/7Olus 项目中的爬虫代码&#xff0c;并且本项目提供相同的…

拆解按摩器:有意思的按键与LED控制电路,学习借鉴一下!

拆解 外观和配色个人感觉还行,比较青春 拉开拉链&#xff0c;拆开外面的布面&#xff0c;里面还有一层纱面 按键部分使用魔术贴固定 拆开纱面后&#xff0c;看到里面的结构&#xff0c;整体是一个海绵 可以看到如下&#xff0c;电池&#xff0c;按键板&#xff0c;充电线的三条…

匿名内部类(内部类) - Java

匿名内部类 1、理解2、语法3、使用&#xff08;1&#xff09;基于接口的内部类&#xff08;2&#xff09;基于类的内部类&#xff08;3&#xff09;基于抽象类的匿名内部类 4、细节&注意事项5、最佳应用场景&#xff08;1&#xff09;当作实参直接传递&#xff0c;简洁高效…

Alibaba Java诊断工具Arthas查看Dubbo动态代理类

原创/朱季谦 阅读Dubbo源码过程中&#xff0c;会发现&#xff0c;Dubbo消费端在做远程调用时&#xff0c;默认通过 Javassist 框架为服务接口生成动态代理类&#xff0c;调用javassist框架下的JavassistProxyFactory类的getProxy(Invoker invoker, Class<?>[] interfac…

GO 集成Prometheus

一、Prometheus介绍 Prometheus&#xff08;普罗米修斯&#xff09;是一套开源的监控&报警&时间序列数据库的组合&#xff0c;起始是由SoundCloud公司开发的。随着发展&#xff0c;越来越多公司和组织接受采用Prometheus&#xff0c;社会也十分活跃&#xff0c;他们便…

GAN:GAN论文学习

论文&#xff1a;https://arxiv.org/pdf/1406.2661.pdf 发表&#xff1a;2014 一、GAN简介&#xff1a;Generative Adversarial Network GAN是由Ian Goodfellow于2014年提出&#xff0c;GAN&#xff1a;全名叫做生成对抗网络。GAN的目的就是无中生有&#xff0c;以假乱真。 …

day64 django中间件的复习使用

django中间件 django中间件是django的门户 1.请求来的时候需要先经过中间件才能达到真正的django后端 2.响应走的时候也需要经过中间件 ​ djangp自带七个中间件MIDDLEWARE [django.middleware.security.SecurityMiddleware,django.contrib.sessions.middleware.SessionMiddle…

java开发需要掌握的maven相关知识和Junit单元测试

maven简介 什么是maven&#xff1a; maven是一款管理和构建java项目的工具&#xff0c;是apache旗下的一个开源项目。 maven的作用&#xff1a; 依赖管理&#xff1a; 方便快捷的管理项目依赖的资源&#xff08;jar包&#xff09;。 项目构建&#xff1a; 标准化的跨平台&#…

MacBook如何远程控制华为手机?

将手机屏幕投影到电脑上可以提供更大的屏幕空间&#xff0c;方便观看电影、浏览照片、阅读文档等。然而&#xff0c;除了想将手机投屏到电脑&#xff0c;还想要在电脑上直接操作手机&#xff0c;有方法可以实现吗&#xff1f; 现在使用AirDroid Cast的远程控制手机功能就可以实…

【数据结构】树与二叉树(廿五):树搜索给定结点的父亲(算法FindFather)

文章目录 5.3.1 树的存储结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法1. 获取大儿子、大兄弟结点2. 搜索给定结点的父亲a. 算法FindFatherb. 算法解析c. 代码实现 3. 代码整合 5.3.1 树的存储结构 5. 左儿子右兄弟链接结构 【数据结构】树与二叉树&#xff08;十九&…