[Pytorch系列-52]:循环神经网络RNN - 全连接网络与RNN网络在时间序列数据集上拟合的比较

作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客

本文网址:https://blog.csdn.net/HiWangWenBing/article/details/121526014


目录

第1章 概述

1.1 业务需求概述

1.2 业务分析

1.3 导入库

第1章 数据集

1.1 数据集概述

1.2 从文件中读取数据

1.3 提取有效数据

第2章 全连接网络的拟合

2.1 定义全连接网络

2.2 定义loss与优化器

2.3 训练前准备

2.4 开始训练

2.5 loss显示 

2.6 结果分析

第3章 RNN网络的拟合

3.1 定义RNN网络

3.2 生成网络

3.3 定义loss与优化器

3.4 训练前的准备

3.5 开始训练

3.6 显示loss

3.7 分析



第1章 概述

1.1 业务需求概述

有一批最近52周的销售数据,希望能够根据这些数据,预测未来几周销售数据。

1.2 业务分析

这是一个线性拟合的问题,那么每周的数据之间是独立的?还是每周的数据之间有时间的相关性?

本文就采用层数的全连接网络和RNN网络对数据进行拟合与比较。

如果全连接网络的拟合度比RNN网络好,则证明每周的数据是独立无关的。

如果全连接网络的拟合度没有RNN网络好,则证明每周的数据是具有时间相关性。

1.3 导入库

%matplotlib inline
import torch
import torch.nn as nn
from torch.nn import functional as F
from torch.autograd import Variable
from torch import optim

import numpy as np
import math, random
import matplotlib.pyplot as plt
import pandas as pd

from torch.utils.data import Dataset
from torch.utils.data import DataLoader

第1章 数据集

1.1 数据集概述

销售数据是通过Excel存放的:包含多个样本数据,每个样本包含52周的数据,如下图所示:

横轴:不同的样本

纵轴:每个样本包含的序列52周的销售数据。

1.2 从文件中读取数据

# 从excel文件中数据
sales_data = pd.read_csv('time_serise_sale.csv')

sales_data.head()

1.3 提取有效数据

# 提取有效数据
source_data = sales_data
source_data.values.shape
source_data.values
array([[0.00000000e+00, 2.29157429e+00, 2.88283833e+00, ...,
        2.52078778e+00, 2.63721001e+00, 2.74892268e+00],
       [1.00000000e+00, 6.09664112e-01, 2.52360427e+00, ...,
        1.66285479e+00, 2.48192522e+00, 2.41120153e+00],
       [2.00000000e+00, 3.42279275e+00, 1.81265116e+00, ...,
        1.72005177e+00, 2.16993942e+00, 2.16170153e+00],
       ...,
       [1.50490000e+04, 3.83370716e+00, 3.54807088e+00, ...,
        3.03134190e+00, 1.85208859e+00, 3.00563077e+00],
       [1.50500000e+04, 3.18643937e+00, 1.70323164e+00, ...,
        1.19605309e+00, 3.34099104e+00, 2.92155740e+00],
       [1.50510000e+04, 3.10427003e+00, 2.82717086e+00, ...,
        1.33781619e+00, 2.71468770e+00, 2.34349413e+00]])
# 显示数据集数据
source_data
Unnamed: 0week_1week_2week_3week_4week_5week_6week_7week_8week_9...week_43week_44week_45week_46week_47week_48week_49week_50week_51week_52
002.2915742.8828383.5818054.0138751.1099242.8342472.6250452.1968844.208887...1.2422502.7710723.7781433.1616343.7926452.0154812.8261842.5207882.6372102.748923
110.6096642.5236042.6095373.6959973.3992722.6166121.6519351.3482953.862523...2.4775052.2845133.4617833.1010523.4424201.9157762.4261681.6628552.4819252.411202
223.4227931.812651-0.0979661.7240643.0936601.7812782.8499462.9497073.560835...2.2196672.3598341.9320292.7319471.8362451.2199331.2227401.7200522.1699392.161702
333.3722832.5772543.8543083.4496792.5176762.6356792.3527062.8562161.948434...1.6709120.9091133.2166521.7753463.2704842.3997093.0320711.7036661.7505851.821736
442.9977271.7994153.6480902.3915672.3767781.8647170.4080622.3467263.260303...2.3040583.0389052.0387332.8251862.2329372.5090502.881796-1.7121312.1403661.926818
..................................................................
15047150471.9527261.5476371.9027890.8132612.6009792.9106382.8783960.5942163.526187...0.4860733.3362523.3072703.0268351.4721163.2207922.6640441.5461533.0269482.611774
15048150480.6528243.5891913.2577072.8212762.1859372.534801-0.7743753.8356953.776809...2.6841531.3849123.1845702.8329412.0920332.6061980.7531933.1605993.0858002.814394
15049150493.8337073.5480713.1941601.9934373.0135471.8250472.3051960.5224753.126647...2.9289371.6337543.0785982.4665630.4893803.5187253.4064663.0313421.8520893.005631
15050150503.1864391.7032323.1965912.407803-0.4743703.8799433.7624083.4156691.790529...1.6426122.3877702.1498930.6884633.1508053.2422092.9727281.1960533.3409912.921557
15051150513.1042702.8271711.1764283.2749672.9346552.3491882.4129351.2190542.843297...2.5512590.8192033.4165323.2420212.8101772.0374872.6816941.3378162.7146882.343494

15052 rows × 53 columns

第2章 全连接网络的拟合

2.1 定义全连接网络

class FullyConnected(nn.Module):
    def __init__(self, x_size, hidden_size, output_size):
        super(FullyConnected, self).__init__()
        self.hidden_size = hidden_size

        self.linear_with_tanh = nn.Sequential(
            nn.Linear(10, self.hidden_size),
            nn.Tanh(),
            nn.Linear(self.hidden_size, self.hidden_size),
            nn.Tanh(),
            nn.Linear(self.hidden_size, output_size)
        )
        
    def forward(self, x):
        yhat = self.linear_with_tanh(x)
        
        return yhat
# 输入样本的size
x_size = 1

# 隐藏层的size:try to change this parameters 
hidden_size = 2 

#数据特征的size
output_size = 10

fc_model = FullyConnected(x_size = x_size, hidden_size = hidden_size, output_size = output_size)
print(fc_model)

fc_model = fc_model.double()
print(fc_model)
FullyConnected(
  (linear_with_tanh): Sequential(
    (0): Linear(in_features=10, out_features=2, bias=True)
    (1): Tanh()
    (2): Linear(in_features=2, out_features=2, bias=True)
    (3): Tanh()
    (4): Linear(in_features=2, out_features=10, bias=True)
  )
)

fc_model.state_dict()['linear_with_tanh.0.weight']
tensor([[ 0.2028,  0.0721,  0.0101,  0.2866, -0.3106,  0.1612,  0.0082, -0.1394,
          0.2630, -0.2903],
        [ 0.0596, -0.2646,  0.2036, -0.2676, -0.0198,  0.2969,  0.2596,  0.0965,
          0.0746, -0.0195]], dtype=torch.float64)

2.2 定义loss与优化器

#定义loss函数
criterion = nn.MSELoss()

# 使用 Adam 优化器 比课上使用的 SGD 优化器更加稳定 
optimizer = optim.AdamW(fc_model.parameters(), lr=0.01) 

2.3 训练前准备

n_epochs = 30
n_layers = 1
batch_size = seq_length
seq_length = 10

fc_losses = np.zeros(n_epochs) 


data_loader = torch.utils.data.DataLoader(source_data.values, batch_size = batch_size, shuffle=True)
print(data_loader)
print(data_loader.batch_size )

2.4 开始训练

# 开始训练
for epoch in range(n_epochs):
    # 定义用于每个epoch的平均loss
    epoch_losses = []
    
    # 读取batch数据
    for iter_, data in enumerate(data_loader):
        #当读到数据不足batch size时,跳过batch size
        if data.shape[0] != batch_size: 
            continue 
        
        #随机的获取长度=seq_length的数据
        random_index = random.randint(0, data.shape[-1] - seq_length - 1)
        train_x = data[:, random_index: random_index+seq_length]
        #train_y = data[:, random_index + 1: random_index + seq_length + 1]
        train_y = train_x
        
        #进行前向运算
        outputs = fc_model(train_x.double())
        
        #复位梯度
        optimizer.zero_grad()
        
        #求此次前向运算的loss
        loss = criterion(outputs, train_y)
        
        #反向求导
        loss.backward()
        
        #梯度迭代
        optimizer.step()

        #
        epoch_losses.append(loss.detach())
        
        if iter_  == 0:
            plt.clf();
            plt.ion()
            plt.title("Epoch {}, iter {}".format(epoch, iter_))
            plt.plot(torch.flatten(train_y),'c-',linewidth=1,label='Label')
            #plt.plot(torch.flatten(train_x),'g-',linewidth=1,label='Input')
            plt.plot(torch.flatten(outputs.detach()),'r-',linewidth=1,label='Output')
            plt.draw();
            plt.pause(0.05);
    fc_losses[epoch] = np.mean(epoch_losses)

 ................................................................

2.5 loss显示 

plt.plot(fc_losses)

2.6 结果分析

全连接网络应对这种时序序列问题,拟合性不是很好。

第3章 RNN网络的拟合

3.1 定义RNN网络

class SimpleRNN(nn.Module):
    def __init__(self, x_size, hidden_size, n_layers, batch_size, output_size):
        super(SimpleRNN, self).__init__()
        self.hidden_size = hidden_size
        self.n_layers = n_layers
        self.batch_size = batch_size
        #self.inp = nn.Linear(1, hidden_size) 
        self.rnn = nn.RNN(x_size, hidden_size, n_layers, batch_first=True)
        self.out = nn.Linear(hidden_size, output_size) # 10 in and 10 out

    def forward(self, inputs, hidden=None):
        hidden = self.__init__hidden()
        #print("Forward hidden {}".format(hidden.shape))
        #print("Forward inps {}".format(inputs.shape))
        output, hidden = self.rnn(inputs.float(), hidden.float())
        #print("Out1 {}".format(output.shape))
        output = self.out(output.float());
        #print("Forward outputs {}".format(output.shape))

        return output, hidden

    def __init__hidden(self):
        hidden = torch.zeros(self.n_layers, self.batch_size, self.hidden_size, dtype=torch.float64)
        return hidden

3.2 生成网络

x_size = 1
hidden_size = 2 # try to change this parameters 
n_layers = 1
seq_length = 10
output_size = 1

#rnn_model = SimpleRNN(x_size, hidden_size, n_layers, seq_length, output_size)
rnn_model = SimpleRNN(x_size, hidden_size, n_layers, seq_length, output_size)

print(rnn_model)
SimpleRNN(
  (rnn): RNN(1, 2, batch_first=True)
  (out): Linear(in_features=2, out_features=1, bias=True)
)

3.3 定义loss与优化器

# 定义loss
criterion = nn.MSELoss()

#定义优化器
optimizer = optim.AdamW(rnn_model.parameters(), lr=0.01) # 使用 Adam 优化器 比课上使用的 SGD 优化器更加稳定 

3.4 训练前的准备

# 训练前的准备
n_epochs = 30
rnn_losses = np.zeros(n_epochs) 

data_loader = torch.utils.data.DataLoader(source_data.values, batch_size=seq_length, shuffle=True)

3.5 开始训练

# 开始训练
for epoch in range(n_epochs):
    for iter_, t in enumerate(data_loader):
        if t.shape[0] != seq_length: continue 

        random_index = random.randint(0, t.shape[-1] - seq_length - 1)
        train_x = t[:, random_index: random_index+seq_length]
        #train_y = t[:, random_index + 1: random_index + seq_length + 1]
        train_y = train_x
        
        #获取输出
        outputs, hidden = rnn_model(train_x.double().unsqueeze(2), hidden_size)
        
        #梯度复位
        optimizer.zero_grad()
        
        #定义损失函数
        loss = criterion(outputs.double(), train_y.double().unsqueeze(2))
        
        # 反向求导
        loss.backward()
        
        #梯度迭代
        optimizer.step()
        
        #记录loss
        epoch_losses.append(loss.detach())
        
        #显示拟合图像
        if iter_ == 0:
            plt.clf();
            plt.ion()
            plt.title("Epoch {}, iter {}".format(epoch, iter_))
            plt.plot(torch.flatten(train_y),'c-',linewidth=1,label='Label')
            plt.plot(torch.flatten(train_x),'g-',linewidth=1,label='Input')
            plt.plot(torch.flatten(outputs.detach()),'r-',linewidth=1,label='Output')
            plt.draw();
            plt.pause(0.05);
    rnn_losses[epoch] = np.mean(epoch_losses)

 

3.6 显示loss

3.7 分析

RNN网络在第一个epoch完成后,拟合度就非常好。


作者主页(文火冰糖的硅基工坊):文火冰糖(王文兵)的博客_文火冰糖的硅基工坊_CSDN博客

本文网址:https://blog.csdn.net/HiWangWenBing/article/details/121526014

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文火冰糖的硅基工坊

你的鼓励是我前进的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值