zhouhaoyi / Informer2020

The GitHub repository for the paper "Informer" accepted by AAAI 2021.
Apache License 2.0
5.38k stars 1.12k forks source link

求问variable pred_len的情况下如何用Informer #485

Open NudnikShpilkis opened 1 year ago

NudnikShpilkis commented 1 year ago

问下有木有同学有成功试过用Informer来做预测?这里pred_len是可变的。比如我的input是一个简单的正弦函数:

x = np.arange(0, 100, 0.25)
x_time = np.zeros(len(x))
y = np.sin(x)

x_train = x[:int(len(x) / 2)]
x_test = x
y_train = y[:int(len(x) / 2)]
y_test = y

用数据的前半部分来train:

# train
seq_len = 100
label_len = 50
pred_len = 100

假设我现在想要预测pred_len=300:

# test
seq_len = 100
label_len = 50
pred_len = 300

我试了一下发现预测的结果完全对不上,预测曲线的周期比实际周期要大很多。有没有同学有什么好的方法不?我的usecase需要预测的长度是可变的(当然seq_len和label_len也是可变的)。

import numpy as np
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import seaborn as sns
from torch.utils.data import DataLoader, Dataset

x = np.arange(0, 100, 0.25)
x_time = np.zeros(len(x))
y = np.sin(x)

sns.lineplot(x=x, y=y)

class sinDataset(Dataset):
    def __init__(self, x, x_time, seq_len, label_len, pred_len):
        self.x = torch.from_numpy(x).unsqueeze(-1)
        self.x_time = torch.from_numpy(x_time).unsqueeze(-1)
        self.seq_len = len(x)
        self.seq_len = seq_len
        self.label_len = label_len
        self.pred_len = pred_len

    def __len__(self):
        return 1

    def __getitem__(self, i):
        x_c = self.x.clone()

        x_s, x_e = 0, self.seq_len
        y_s, y_e = self.seq_len - self.label_len, self.seq_len
        x = x_c[: x_e]
        y = torch.zeros(self.pred_len).unsqueeze(-1)
        y = torch.cat([x_c[y_s: y_e], y], dim=0)

        x_time = self.x_time.clone()[: x_e]
        y_time = self.x_time.clone()[y_s: (y_e + self.pred_len)]

        y_tgt = x_c[y_s: x_e + self.pred_len]

        return dict(
            ts=torch.arange(self.seq_len),
            x=x,
            x_time=x_time,
            y=y,
            y_time=y_time,
            y_tgt=y_tgt,
            seq_len=self.seq_len,
            pred_len=self.pred_len,
        )

x_train = x[:int(len(x) / 2)]
x_test = x
y_train = y[:int(len(x) / 2)]
y_test = y

train_data = sinDataset(
    x=y_train,
    x_time=x_time,
    seq_len=100,
    label_len=50,
    pred_len=100,
)

test_data = sinDataset(
    x=y_test,
    x_time=x_time,
    seq_len=100,
    label_len=50,
    pred_len=300,
)

train_loader = DataLoader(train_data, collate_fn=train_data.collate)
test_loader = DataLoader(test_data, collate_fn=test_data.collate)

model1 = Informer(
    enc_in=1,
    dec_in=1,
    c_out=1,
    seq_len=75,
    label_len=50,
    out_len=25,
    factor=5,
    d_model=512,
    n_heads=8,
    e_layers=3,
    d_layers=2,
    d_ff=2048,
    dropout=0.1,
    attn='prob',
    embed='fixed',
    freq='h',
    activation='gelu',
    output_attention=False,
    distil=True,
    mix=True,
    device='cpu'
) \
    .to('cuda')

opt1 = torch.optim.Adam(model1.parameters(), lr=1e-4)
model1.train()
loss_fn = nn.MSELoss()

for i in range(250):
    for batch in train_loader:
        opt1.zero_grad()
        y_tgt = batch['y_tgt'].to('cuda')
        seq_len = batch['seq_len']
        pred_len = batch['pred_len']

        y_pred = model1(
            x_enc=batch['x'].to('cuda'),
            x_mark_enc=batch['x_time'].to('cuda'),
            x_dec=batch['y'].to('cuda'),
            x_mark_dec=batch['y_time'].to('cuda'),
        )
        y_tgt = y_tgt[:, -train_data.pred_len:]
        y_pred = y_pred[:, -train_data.pred_len:]

        loss = loss_fn(y_pred, y_tgt)
        loss.backward()
        opt1.step()

model1.to('cpu')
model1.eval()

with torch.no_grad():
    batch = next(iter(test_loader))
    y_pred = model1(batch['x'], batch['x_time'], batch['y'], batch['y_time'])

    y_pred = y_pred.sum(dim=[0, 2])
    y_tgt = batch['y_tgt'].sum(dim=[0, 2])

sns.lineplot(x=x_test[-test_data.pred_len:], y=y_pred[-test_data.pred_len:], ax=ax[0], marker='o', label='model')
sns.lineplot(x=x_test[-test_data.pred_len:], y=y_tgt[-test_data.pred_len:], ax=ax[0], marker='o', label='tgt')
Screen Shot 2023-03-29 at 4 10 02 PM
ANTAGNIST commented 1 year ago

import numpy as np import matplotlib.pyplot as plt from utils.metrics import metric

file_path = "../results/informer_custom_19.csv_test_0/" metrics = np.load(file_path+"metrics.npy") pred = np.load(file_path+"pred.npy") true = np.load(file_path+"true.npy")

true = np.hstack((true[0, :, -1], true[1:, -1, -1])) pred = np.hstack((pred[0, :, -1], pred[1:, -1, -1])) metric(true, pred)

plt.plot(true, color='b') plt.plot(pred, color='r')

informer_torch |_fig | |_plt_creation_truepred.ipynb |... |_... 你好,我是这么写的,预测出来的结果也不大好

ANTAGNIST commented 1 year ago

数据我放在github的surge_height那里了

samuel01028 commented 4 weeks ago

为啥效果这么差