• 使用pytorch搭建lstm时间序列预测


    前言:网上找的代码是keras以tensorflow为后端的,苦于不知道具体版本号,所以各种报错,所以参考网上的代码将其修改为基于pytorch的

    参考链接:
    https://blog.csdn.net/Muzi_Water/article/details/103921115
    https://blog.csdn.net/jejune5/article/details/121673615

    最终可用的版本

    预测一维数据

    数据格式:

    "Month","Sales"
    "1964-01",2815
    "1964-02",2672
    "1964-03",2755
    "1964-04",2721
    "1964-05",2946
    "1964-06",3036
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码

    # %%
    import pandas as pd
    import numpy as np
    import torch
    from torch import nn
    from torch.nn import functional as F
    from torch.utils.data import TensorDataset, DataLoader
    import torchkeras
    from plotly import graph_objects as go
    from sklearn.preprocessing import MinMaxScaler
    
    # %%
    # 导入数据
    # 数据下载:https://www.kaggle.com/kankanashukla/champagne-data
    # 下载地址2:https://gitee.com/jejune/Datasets/blob/master/champagne.csv
    df = pd.read_csv('champagne.csv', index_col=0)
    df.head()
    # %%
    # 数据预览
    fig = go.Figure()
    fig.add_trace(go.Scatter(y=df['Sales'], name='Sales'))
    fig.show()
    # %%
    # 数据处理
    # 归一化 [0, 1]
    scaler = MinMaxScaler()
    predict_field = 'Scaler'
    df[predict_field] = scaler.fit_transform(df['Sales'].values.reshape(-1, 1))
    df.head()
    
    
    # %%
    def create_dataset(data: list, time_step: int):
        arr_x, arr_y = [], []
        for i in range(len(data) - time_step - 1):
            x = data[i: i + time_step]
            y = data[i + time_step]
            arr_x.append(x)
            arr_y.append(y)
        return np.array(arr_x), np.array(arr_y)
    
    
    time_step = 8
    X, Y = create_dataset(df[predict_field].values, time_step)
    # %%
    # cuda
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    # 转化成 tensor->(batch_size, seq_len, feature_size)
    X = torch.tensor(X.reshape(-1, time_step, 1), dtype=torch.float).to(device)
    Y = torch.tensor(Y.reshape(-1, 1, 1), dtype=torch.float).to(device)
    print('Total datasets: ', X.shape, '-->', Y.shape)
    
    # 划分数据
    split_ratio = 0.8
    len_train = int(X.shape[0] * split_ratio)
    X_train, Y_train = X[:len_train, :, :], Y[:len_train, :, :]
    print('Train datasets: ', X_train.shape, '-->', Y_train.shape)
    # %%
    # 构建迭代器
    batch_size = 10
    ds = TensorDataset(X, Y)
    dl = DataLoader(ds, batch_size=batch_size, num_workers=0)
    ds_train = TensorDataset(X_train, Y_train)
    dl_train = DataLoader(ds_train, batch_size=batch_size, num_workers=0)
    # 查看第一个batch
    x, y = next(iter(dl_train))
    print(x.shape)
    print(y.shape)
    
    
    # %%
    # 定义模型
    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.lstm = nn.LSTM(input_size=1, hidden_size=6, num_layers=3, batch_first=True)
            self.fc = nn.Linear(in_features=6, out_features=1)
    
        def forward(self, x):
            # x is input, size (batch_size, seq_len, input_size)
            x, _ = self.lstm(x)
            # x is output, size (batch_size, seq_len, hidden_size)
            x = x[:, -1, :]
            x = self.fc(x)
            x = x.view(-1, 1, 1)
            return x
    
    
    # %%
    # 自定义训练方式
    model = Net().to(device)
    loss_function = nn.MSELoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=1e-2)
    
    
    # 测试一个batch
    # features, labels = next(iter(dl_train))
    # loss = train_step(model, features, labels)
    # print(loss)
    
    
    
    
    def train_step(model, features, labels):
        # 正向传播求损失
        predictions = model.forward(features)
        loss = loss_function(predictions, labels)
        # 反向传播求梯度
        loss.backward()
        # 参数更新
        optimizer.step()
        optimizer.zero_grad()
        return loss.item()
    
    
    # 测试一个batch
    # features, labels = next(iter(dl_train))
    # loss = train_step(model, features, labels)
    
    
    # %%
    # 训练模型
    def train_model(model, epochs):
        for epoch in range(1, epochs + 1):
            list_loss = []
            for features, labels in dl_train:
                lossi = train_step(model, features, labels)
                list_loss.append(lossi)
            loss = np.mean(list_loss)
            if epoch % 10 == 0:
                print('epoch={} | loss={} '.format(epoch, loss))
        print("finish training")
        save_path = './myLstm_learn.pth'
        torch.save(model.state_dict(), save_path)
    
    
    # %%
    # 自定义训练方式
    # 训练-----
    # train_model(model, 150)
    # model = Net().to(device)
    # loss_function = nn.MSELoss()
    # optimizer = torch.optim.Adam(model.parameters(), lr=1e-2)
    # 测试---------
    model = Net().to(device)
    model.load_state_dict(torch.load('myLstm_learn.pth'))
    loss_function = nn.MSELoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=1e-2)
    
    # %%
    # 预测验证预览
    y_true = Y.cpu().numpy().squeeze()
    print('Y[0:10]:{0} shape:{1}'.format(Y[0:10], Y.shape))
    print(y_true[0:10])
    y_pred = model.forward(X).detach().cpu().numpy().squeeze()
    print('y_pred[0:10]:{0} shape:{1}'.format(y_pred[0:10], y_pred.shape))
    fig = go.Figure()
    fig.add_trace(go.Scatter(y=y_true, name='y_true'))
    fig.add_trace(go.Scatter(y=y_pred, name='y_pred'))
    fig.show()
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161

    下图是没有归一化过的原数据
    在这里插入图片描述
    下图是归一化后的原数据和预测数据
    在这里插入图片描述我的疑问,time_step = 8,意味着每8个数据预测下一个数据,为什么预测后的图画出来和原始数据的形状一直呢?
    后来想明白了,除了前八个数没有,其他数经过迭代,Y里面都包含了,所以观察上面两个图,会发现第二幅图比第一幅图少了前面一截数据图

    预测二维坐标数据

    数据样例

    "x","y"
    323.0,253.0
    323.0,253.0
    323.0,253.0
    323.0,253.0
    323.0,253.0
    323.0,253.0
    323.5,253.0
    323.5,253.0
    323.5,253.0
    323.5,253.0
    324.0,253.0
    324.0,252.5
    324.0,252.5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    代码

    import numpy as np
    from torch import nn
    import pandas as pd
    import os
    import torch
    from torch.utils.data import TensorDataset, DataLoader
    from plotly import graph_objects as go
    import matplotlib.pyplot as plt
    
    os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"
    os.environ['CUDA_VISIBLE_DEVICES'] = '0'
    
    
    def create_dataset(data, n_predictions, n_next):
        '''
        对数据进行处理
        '''
        dim = data.shape[1]
        train_X, train_Y = [], []
        for i in range(data.shape[0] - n_predictions - n_next - 1):
            a = data[i:(i + n_predictions), :]
            train_X.append(a)
            tempb = data[(i + n_predictions):(i + n_predictions + n_next), :]
            b = []
            for j in range(len(tempb)):
                for k in range(dim):
                    b.append(tempb[j, k])
            train_Y.append(b)
        train_X = np.array(train_X, dtype='float64')
        train_Y = np.array(train_Y, dtype='float64')
    
        test_X, test_Y = [], []
        i = data.shape[0] - n_predictions - n_next - 1
        a = data[i:(i + n_predictions), :]
        test_X.append(a)
        tempb = data[(i + n_predictions):(i + n_predictions + n_next), :]
        b = []
        for j in range(len(tempb)):
            for k in range(dim):
                b.append(tempb[j, k])
        test_Y.append(b)
        test_X = np.array(test_X, dtype='float64')
        test_Y = np.array(test_Y, dtype='float64')
    
        return train_X, train_Y, test_X, test_Y
    
    
    def NormalizeMult(data, set_range):
        '''
        返回归一化后的数据和最大最小值
        '''
        normalize = np.arange(2 * data.shape[1], dtype='float64')
        normalize = normalize.reshape(data.shape[1], 2)
    
        for i in range(0, data.shape[1]):
            if set_range == True:
                list = data[:, i]
                listlow, listhigh = np.percentile(list, [0, 100])
            else:
                if i == 0:
                    listlow = -90
                    listhigh = 90
                else:
                    listlow = -180
                    listhigh = 180
    
            normalize[i, 0] = listlow
            normalize[i, 1] = listhigh
    
            delta = listhigh - listlow
            if delta != 0:
                for j in range(0, data.shape[0]):
                    data[j, i] = (data[j, i] - listlow) / delta
    
        return data, normalize
    
    
    class Net(nn.Module):
        def __init__(self):
            super(Net, self).__init__()
            self.lstm = nn.LSTM(input_size=2, hidden_size=6, num_layers=3, batch_first=True)  # 特征是x,y两个坐标,此处修改为2
            self.fc = nn.Linear(in_features=6, out_features=2)  # 预测结果是x,y两个坐标,此处修改为2
    
        def forward(self, x):
            # x is input, size (batch_size, seq_len, input_size)
            x, _ = self.lstm(x)
            # x is output, size (batch_size, seq_len, hidden_size)
            x = x[:, -1, :]
            x = self.fc(x)
            x = x.view(-1, 1, 2)  # 此处修改为2
            return x
    
    
    def train_step(model, features, labels):
        # 正向传播求损失
        predictions = model.forward(features)
        print('predictions:', predictions)
        print('labels:', labels)
        loss = loss_function(predictions, labels)
        # 反向传播求梯度
        loss.backward()
        # 参数更新
        optimizer.step()
        optimizer.zero_grad()
        return loss.item()
    
    
    # %%
    # 训练模型
    def train_model(model, epochs):
        for epoch in range(1, epochs + 1):
            list_loss = []
            for features, labels in dl_train:
                lossi = train_step(model, features, labels)
                list_loss.append(lossi)
            loss = np.mean(list_loss)
            if epoch % 10 == 0:
                print('epoch={} | loss={} '.format(epoch, loss))
        print("finish training")
        save_path = './myLstm1.pth'
        torch.save(model.state_dict(), save_path)
    
    
    
    if __name__ == "__main__":
        device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
        train_num = 9
        per_num = 1
        # set_range = False
        set_range = True
    
        # 读入时间序列的文件数据
        data = pd.read_csv('0809.txt', sep=',').iloc[:, 0:2].values
        print('data shape:',data.shape)
        print("样本数:{0},维度:{1}".format(data.shape[0], data.shape[1]))
        # print(data)
    
        # # 画样本数据库
        # plt.scatter(data[:, 1], data[:, 0], c='b', marker='o', label='traj_A')
        # plt.legend(loc='upper left')
        # plt.grid()
        # plt.show()
    
        # 归一化
        data, normalize = NormalizeMult(data, set_range)
        # # 生成训练数据
        X_train, Y_train, test_X, test_Y = create_dataset(data, train_num, per_num)
    
        model = Net().to(device)
        model.load_state_dict(torch.load('myLstm1.pth'))
        loss_function = nn.MSELoss()
        optimizer = torch.optim.Adam(model.parameters(), lr=1e-2)
    
        X_train = torch.tensor(X_train.reshape(-1, train_num, 2), dtype=torch.float).to(device)
        Y_train = torch.tensor(Y_train.reshape(-1, 1, 2), dtype=torch.float).to(device)
        print('X_train.shape: ', X_train.shape, 'Y_train.shape:', Y_train.shape)
    
        # 构建迭代器
        batch_size = 10
        # ds = TensorDataset(X, Y)
        # dl = DataLoader(ds, batch_size=batch_size, num_workers=0)
        ds_train = TensorDataset(X_train, Y_train)
        dl_train = DataLoader(ds_train, batch_size=batch_size, num_workers=0)
        # # 查看第一个batch
        # x, y = next(iter(dl_train))
        # print(x.shape)
        # print(y.shape)
        # 下面三行的作用:开启训练前,调通一个前向传播
        # features, labels = next(iter(dl_train))
        # loss = train_step(model, features, labels)
        # print(loss)
    
        # 开启训练
        # train_model(model, 100)
    
        # %%
        # 预测验证预览
        y_true = Y_train.squeeze().cpu().numpy()
        print("y_true.shape:",y_true.shape)
        y_pred = model.forward(X_train).detach().squeeze().cpu().numpy()
        print("y_pred.shape:", y_pred.shape)
    
        # 画样本数据库
        plt.scatter(y_true[:, 1], y_true[:, 0], c='b', marker='o', label='y_true')
        plt.scatter(y_pred[:, 1], y_pred[:, 0], c='r', marker='o', label='y_pred')
        plt.legend(loc='upper left')
        plt.grid()
        plt.show()
    
        # fig = go.Figure()
        # fig.add_trace(go.Scatter(y=y_true, name='y_true'))
        # fig.add_trace(go.Scatter(y=y_pred, name='y_pred'))
        # fig.show()
    
    
        #
        # print("x\n", train_X.shape)#(176, 10, 2)
        # print("train_X.shape[1], train_X.shape[2]",train_X.shape[1], train_X.shape[2])#10 2
        # train_X.shape[1], train_X.shape[2]
        # print("y\n", train_Y.shape)
        #
        # # 训练模型
        # model = trainModel(train_X, train_Y)
        # loss, acc = model.evaluate(train_X, train_Y, verbose=2)
        # print('Loss : {}, Accuracy: {}'.format(loss, acc * 100))
        #
        # # 保存模型
        # np.save("./traj_model_trueNorm.npy", normalize)
        # model.save("./traj_model_120.h5")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210

    效果

    在这里插入图片描述

    pytorch中lstm单元的使用

    nn.lstm功课

    参考https://blog.csdn.net/qq_40728805/article/details/103959254

    什么时候选择双向lstm

    我的理解是,对于离线训练来讲,貌似可以双向,那对于在线监测那种,我无法先知道后续的数据,如何反向再来一遍呢?
    是不是因为,训练过程我们是有后面数据的,所以训练过程双向没有问题,训练过程确定下来的权重,会用于测试过程的计算而已,可是,网络是双向的,是不是以为着预测的时候也会双向啊,此时又该如何双向呢?
    而且,双向的时候,反向时候的数据怎么弄呢?
    参考https://blog.csdn.net/aliceyangxi1987/article/details/77094970
    在这里插入图片描述


    下面是调试过程中遇到的问题记录
    1,报错https://blog.csdn.net/m0_50736744/article/details/121799432

    解决OMP: Error #15: Initializing libiomp5md.dll, but found libiomp5md.dll already initialized.报错问题
    
    • 1

    解决办法:
    在pycharm里调试程序时可以直接通过在程序前添加这两个语句解决

    import os
    os.environ[KMP_DUPLICATE_LIB_OK]=TRUE
    • 1
    • 2
    • 3

    2,torchkeras安装,pip install torchkeras

    3,data[:,0] data[1,:]的含义

    data[ a , b ] a的位置限制第几行,b的位置限制第几列
    “ : ”表示全部数据
    例如:

    data[:,0]表示第1列所有数据
    data[1,:]表示第2行所有数据
    data[:, 1:]表示从第2列开始所有数据
    
    • 1
    • 2
    • 3
  • 相关阅读:
    正点原子嵌入式linux驱动开发——Linux SPI驱动
    接口测试的几种方法
    神经网络的图像识别技术,神经网络图像角度分析
    Oracle/PLSQL: Lower Function
    第一章:Java第一阶段
    单片机入门:LED数码管
    OpenGL 图像色调
    SQL优化
    【CSS】背景样式(颜色、图片、平铺、附着和位置)
    【光学】基于matlab GUI光栅条纹投影生成【含Matlab源码 2118期】
  • 原文地址:https://blog.csdn.net/weixin_43745234/article/details/125893920