很长时间没有更新内容了,上一篇可以看做是刚接触深度学习写的,看法非常狭隘,内容非常粗糙。
在最近的学习中接触到了Pytorch,不得不承认,相对于TensorFlow来讲,灵活很多。
这次就使用pytroch来进行一下交通流预测,数据和上一篇文章数据一样。

百度网盘: https://pan.baidu.com/s/19vKN2eZZPbOg36YEWts4aQ
密码 4uh7

准备开始

目录

  • 加载数据
  • 构造数据集
    • 构造Dataset
    • 生成训练数据
  • 构造LSTM模型
    • 定义模型和损失函数
  • 模型预测
  • 模型评价
  • 完整代码

加载数据

导入数据的时候,需要把Network这一列删除

f = pd.read_csv('..\Desktop\AE86.csv')
# 从新设置列标
def set_columns():columns = []for i in f.loc[2]:columns.append(i.strip())return columns
f.columns = set_columns()
f.drop([0,1,2], inplace = True)
# 读取数据
data = f['Total Carriageway Flow'].astype(np.float64).values[:, np.newaxis]
data.shape # (2880, 1)

构造数据集

pytorch对于Batch输入,提供了规范的划分数据的模块, Dataset 和 DataLoader,这两个是很多刚使用pytorch的朋友头疼的地方,我简单说一下就不专门讲太多了可以去官网或者其他博客看一下

Dataset相当于装东西的大箱子,比如装苹果的箱子,一个大箱子里可以有很多小盒子,小盒子里装着苹果,不同的大箱子里小盒子装的苹果个数可以是不同的
Dataloader相当于使用什么方法在大箱子里拿盒子,比如,可以按顺序一次拿10个小盒子或者随机的拿5个小盒子

但这种使用Dataset和DataLoader创建数据集并不是唯一的方法,比如也可以使用上篇文章中使用的方法直接形成数据

当然,既然是使用pytorch那就使用它的特色吧,下面基于以上Dataset的方法,我们就可以构造自己的数据集

定义自己的Dataset比较麻烦, Dataset必须包括两部分:len 和 getitem

len 用来统计生成Dataset的长度
getitem 是可以index来获取相应的数据

同时为了方便,这Dataset中,增加了数据标准化以及反标准化的过程

构造Dataset

class LoadData(Dataset):def __init__(self, data, time_step, divide_days, train_mode):self.train_mode = train_modeself.time_step = time_stepself.train_days = divide_days[0]self.test_days = divide_days[1]self.one_day_length = int(24 * 4)# flow_norm (max_data. min_data)self.flow_norm, self.flow_data = LoadData.pre_process_data(data)# 不进行标准化
#         self.flow_data = datadef __len__(self, ):if self.train_mode == "train":return self.train_days * self.one_day_length - self.time_stepelif self.train_mode == "test":return self.test_days * self.one_day_lengthelse:raise ValueError(" train mode error")def __getitem__(self, index):if self.train_mode == "train":index = indexelif self.train_mode == "test":index += self.train_days * self.one_day_lengthelse:raise ValueError(' train mode error')data_x, data_y = LoadData.slice_data(self.flow_data, self.time_step, index,self.train_mode)data_x = LoadData.to_tensor(data_x)data_y = LoadData.to_tensor(data_y)return {"flow_x": data_x, "flow_y": data_y}# 这一步就是划分数据的重点部分@staticmethoddef slice_data(data, time_step, index, train_mode):if train_mode == "train":start_index = indexend_index = index + time_stepelif train_mode == "test":start_index = index - time_stepend_index = indexelse:raise ValueError("train mode error")data_x = data[start_index: end_index, :]data_y = data[end_index]return data_x, data_y# 数据与处理@staticmethoddef pre_process_data(data, ):# data N T Dnorm_base = LoadData.normalized_base(data)normalized_data = LoadData.normalized_data(data, norm_base[0], norm_base[1])return norm_base, normalized_data# 生成原始数据中最大值与最小值@staticmethoddef normalized_base(data):max_data = np.max(data, keepdims=True) #keepdims保持维度不变min_data = np.min(data, keepdims=True)# max_data.shape  --->(1, 1)return max_data, min_data# 对数据进行标准化@staticmethoddef normalized_data(data, max_data, min_data):data_base = max_data - min_datanormalized_data = (data - min_data) / data_basereturn normalized_data@staticmethod# 反标准化  在评价指标误差以及画图的使用使用def recoverd_data(data, max_data, min_data):data_base = max_data - min_datarecoverd_data = data * data_base - min_datareturn recoverd_data@staticmethoddef to_tensor(data):return torch.tensor(data, dtype=torch.float)

生成训练数据

# 使用前25天作为训练集,后5天作为预测集
divide_days = [25, 5]
time_step = 5 #时间步长
batch_size = 48
train_data = LoadData(data, time_step, divide_days, "train")
test_data = LoadData(data,  time_step, divide_days, "test")
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, )
test_loader = DataLoader(test_data,batch_size=batch_size, shuffle=False, )

在test数据中,不使用shuffle随机化,可以使用train_data[0]看一下,返回出来第一个时间步的数据,以及时间步+1的值,但这是已经归一化后的数据,在init函数中可以不使用pre_process_data函数,这样来检测一下数据是否正确


不使用归一化第一个时间步的数据

需要说一下,DataLoader是一个item的数据类型,需要循环取出

构造LSTM模型

pytorch比较灵活,可以清楚的看到模型内部的运算过程,使用pytorch构建模型,一般包括两部分 : init 和 forward

init 定义需要使用的模型结构
forward进行计算

# LSTM构建网络
class LSTM(nn.Module):def __init__(self, input_num, hid_num, layers_num, out_num, batch_first=True):super().__init__()self.l1 = nn.LSTM(input_size = input_num,hidden_size = hid_num,num_layers = layers_num,batch_first = batch_first)self.out = nn.Linear(hid_num, out_num)def forward(self, data):flow_x = data['flow_x']   # B * T * Dl_out, (h_n, c_n) = self.l1(flow_x, None)  # None表示第一次 hidden_state是0print(l_out[:, -1, :].shape)out = self.out(l_out[:, -1, :])return out

pytorch中的LSTM与TensorFlow不同的是,pytorch中的LSTM可以一次定义多个层,不需要一直叠加LSTM层,而且每次LSTM返回三个部分的值:所有层的输出(l_out)、隐藏状态(l_h)和细胞状态(c_n)。

l_out是集合了每个变量的l_h输出, 所以return的时候,可以在l_c中切片取最后一个值,当然也可以直接使用l_h

pytorch也可以使用Sequential,如果要使用Seqential就需要修改上面的Dataset,因为Dataset定义的使用返回是一个字典{“flow_x”, “flow_y”},如果使用Sequential传入模型的只能是"flow_x"。或者像tensorflow一样,不使用Dataset构建数据,直接通过一系列的方法进行划分(和上一篇文章一样)。

定义模型和损失函数

input_num = 1 # 输入的特征维度
hid_num = 50  # 隐藏层个数
layers_num = 3 # LSTM层个数
# out_num = 1
lstm = LSTM(input_num, hid_num, layers_num, out_num)
loss_func = nn.MSELoss()
optimizer = torch.optim.Adam(lstm.parameters())

模型预测

pytorch中不像tensorflow那么容易描述损失值,所以输出都需要自己来进行表示,当然也可以使用Tensorboard来查看损失值变化,但对新手而言比较麻烦

lstm.train()
epoch_loss_change = []
for epoch in range(30):epoch_loss = 0.0start_time = time.time()for data_ in train_loader:lstm.zero_grad()predict = lstm(data_)loss = loss_func(predict, data_['flow_y'])epoch_loss += loss.item()loss.backward()optimizer.step()epoch_loss_change.append(1000 * epoch_loss / len(train_data))end_time = time.time()print("Epoch: {:04d}, Loss: {:02.4f}, Time: {:02.2f} mins".format(epoch, 1000 * epoch_loss / len(train_data),(end_time-start_time)/60))
plt.plot(epoch_loss_change)

模型评价

lstm.eval()
with torch.no_grad(): # 关闭梯度total_loss = 0.0pre_flow = np.zeros([batch_size, 1]) # [B, D],T=1 # 目标数据的维度,用0填充real_flow = np.zeros_like(pre_flow)for data_ in test_loader:pre_value = lstm(data_)loss = loss_func(pre_value, data_['flow_y'])total_loss += loss.item()# 反归一化pre_value = LoadData.recoverd_data(pre_value.detach().numpy(),test_data.flow_norm[0].squeeze(1), # max_datatest_data.flow_norm[1].squeeze(1), # min_data)target_value = LoadData.recoverd_data(data_['flow_y'].detach().numpy(),test_data.flow_norm[0].squeeze(1), test_data.flow_norm[1].squeeze(1),)pre_flow = np.concatenate([pre_flow, pre_value])real_flow = np.concatenate([real_flow, target_value])pre_flow  = pre_flow[batch_size: ]real_flow  = real_flow[batch_size: ]
#     # 计算误差
mse = mean_squared_error(pre_flow, real_flow)
rmse = math.sqrt(mean_squared_error(pre_flow, real_flow))
mae = mean_absolute_error(pre_flow, real_flow)
print('均方误差---', mse)
print('均方根误差---', rmse)
print('平均绝对误差--', mae)# 画出预测结果图
font_set = FontProperties(fname=r"C:\Windows\Fonts\simsun.ttc", size=15)    # 中文字体使用宋体,15号
plt.figure(figsize=(15,10))
plt.plot(real_flow, label='Real_Flow', color='r', )
plt.plot(pre_flow, label='Pre_Flow')
plt.xlabel('测试序列', fontproperties=font_set)
plt.ylabel('交通流量/辆', fontproperties=font_set)
plt.legend()
# 预测储存图片
# plt.savefig('...\Desktop\123.jpg')

完整代码

import pandas as pd
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.utils.data as Data
from torchsummary import summary
import math
from torch.utils.data import DataLoader
from torch.utils.data import Dataset
import time
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error, mean_absolute_error
import math
from matplotlib.font_manager import FontProperties  # 画图时可以使用中文# 加载数据
f = pd.read_csv('..\Desktop\AE86.csv')
# 从新设置列标
def set_columns():columns = []for i in f.loc[2]:columns.append(i.strip())return columns
f.columns = set_columns()
f.drop([0,1,2], inplace = True)
# 读取数据
data = f['Total Carriageway Flow'].astype(np.float64).values[:, np.newaxis]class LoadData(Dataset):def __init__(self, data, time_step, divide_days, train_mode):self.train_mode = train_modeself.time_step = time_stepself.train_days = divide_days[0]self.test_days = divide_days[1]self.one_day_length = int(24 * 4)# flow_norm (max_data. min_data)self.flow_norm, self.flow_data = LoadData.pre_process_data(data)# 不进行标准化# self.flow_data = datadef __len__(self, ):if self.train_mode == "train":return self.train_days * self.one_day_length - self.time_stepelif self.train_mode == "test":return self.test_days * self.one_day_lengthelse:raise ValueError(" train mode error")def __getitem__(self, index):if self.train_mode == "train":index = indexelif self.train_mode == "test":index += self.train_days * self.one_day_lengthelse:raise ValueError(' train mode error')data_x, data_y = LoadData.slice_data(self.flow_data, self.time_step, index,self.train_mode)data_x = LoadData.to_tensor(data_x)data_y = LoadData.to_tensor(data_y)return {"flow_x": data_x, "flow_y": data_y}# 这一步就是划分数据@staticmethoddef slice_data(data, time_step, index, train_mode):if train_mode == "train":start_index = indexend_index = index + time_stepelif train_mode == "test":start_index = index - time_stepend_index = indexelse:raise ValueError("train mode error")data_x = data[start_index: end_index, :]data_y = data[end_index]return data_x, data_y# 数据与处理@staticmethoddef pre_process_data(data, ):norm_base = LoadData.normalized_base(data)normalized_data = LoadData.normalized_data(data, norm_base[0], norm_base[1])return norm_base, normalized_data# 生成原始数据中最大值与最小值@staticmethoddef normalized_base(data):max_data = np.max(data, keepdims=True) #keepdims保持维度不变min_data = np.min(data, keepdims=True)# max_data.shape  --->(1, 1)return max_data, min_data# 对数据进行标准化@staticmethoddef normalized_data(data, max_data, min_data):data_base = max_data - min_datanormalized_data = (data - min_data) / data_basereturn normalized_data@staticmethod# 反标准化  在评价指标误差以及画图的使用使用def recoverd_data(data, max_data, min_data):data_base = max_data - min_datarecoverd_data = data * data_base - min_datareturn recoverd_data@staticmethoddef to_tensor(data):return torch.tensor(data, dtype=torch.float)# 划分数据
divide_days = [25, 5]
time_step = 5
batch_size = 48
train_data = LoadData(data, time_step, divide_days, "train")
test_data = LoadData(data,  time_step, divide_days, "test")
train_loader = DataLoader(train_data, batch_size=batch_size, shuffle=True, )
test_loader = DataLoader(test_data,batch_size=batch_size, shuffle=False, )# LSTM构建网络
class LSTM(nn.Module):def __init__(self, input_num, hid_num, layers_num, out_num, batch_first=True):super().__init__()self.l1 = nn.LSTM(input_size = input_num,hidden_size = hid_num,num_layers = layers_num,batch_first = batch_first)self.out = nn.Linear(hid_num, out_num)def forward(self, data):flow_x = data['flow_x']   # B * T * Dl_out, (h_n, c_n) = self.l1(flow_x, None)  # None表示第一次 hidden_state是0
#         print(l_out[:, -1, :].shape)out = self.out(l_out[:, -1, :])return out# 定义模型参数
input_num = 1 # 输入的特征维度
hid_num = 50  # 隐藏层个数
layers_num = 3 # LSTM层个数
out_num = 1
lstm = LSTM(input_num, hid_num, layers_num, out_num)
loss_func = nn.MSELoss()
optimizer = torch.optim.Adam(lstm.parameters())# 训练模型
lstm.train()
epoch_loss_change = []
for epoch in range(30):epoch_loss = 0.0start_time = time.time()for data_ in train_loader:lstm.zero_grad()predict = lstm(data_)loss = loss_func(predict, data_['flow_y'])epoch_loss += loss.item()loss.backward()optimizer.step()epoch_loss_change.append(1000 * epoch_loss / len(train_data))end_time = time.time()print("Epoch: {:04d}, Loss: {:02.4f}, Time: {:02.2f} mins".format(epoch, 1000 * epoch_loss / len(train_data),(end_time-start_time)/60))
plt.plot(epoch_loss_change)#评价模型
lstm.eval()
with torch.no_grad(): # 关闭梯度total_loss = 0.0pre_flow = np.zeros([batch_size, 1]) # [B, D],T=1 # 目标数据的维度,用0填充real_flow = np.zeros_like(pre_flow)for data_ in test_loader:pre_value = lstm(data_)loss = loss_func(pre_value, data_['flow_y'])total_loss += loss.item()# 反归一化pre_value = LoadData.recoverd_data(pre_value.detach().numpy(),test_data.flow_norm[0].squeeze(1), # max_datatest_data.flow_norm[1].squeeze(1), # min_data)target_value = LoadData.recoverd_data(data_['flow_y'].detach().numpy(),test_data.flow_norm[0].squeeze(1), test_data.flow_norm[1].squeeze(1),)pre_flow = np.concatenate([pre_flow, pre_value])real_flow = np.concatenate([real_flow, target_value])pre_flow  = pre_flow[batch_size: ]real_flow  = real_flow[batch_size: ]
#     # 计算误差
mse = mean_squared_error(pre_flow, real_flow)
rmse = math.sqrt(mean_squared_error(pre_flow, real_flow))
mae = mean_absolute_error(pre_flow, real_flow)
print('均方误差---', mse)
print('均方根误差---', rmse)
print('平均绝对误差--', mae)# 画出预测结果图
font_set = FontProperties(fname=r"C:\Windows\Fonts\simsun.ttc", size=15)    # 中文字体使用宋体,15号
plt.figure(figsize=(15,10))
plt.plot(real_flow, label='Real_Flow', color='r', )
plt.plot(pre_flow, label='Pre_Flow')
plt.xlabel('测试序列', fontproperties=font_set)
plt.ylabel('交通流量/辆', fontproperties=font_set)
plt.legend()
# 预测储存图片
# plt.savefig('...\Desktop\123.jpg')``

交通流预测爬坑记(三):使用pytorch实现LSTM预测交通流相关推荐

  1. 交通流预测爬坑记(二):最简单的LSTM预测交通流,使用tensorflow2实现

    说到时间序列预测,我想一定首先想到RNN,然后想到LSTM,LSTM原理就不说了,网上有很多相关文章. 下面使用tensorflow2.0来实现预测 不得不说tensorflow2.0 太香了,太简单 ...

  2. 交通流预测爬坑记(一):交通流数据集,原始数据

    目录 主要数据类型 个人出行数据,轨迹数据 高速公路观察点数据集 其他 出行数据集 高速公路数据集 其他 赠人玫瑰 如今网上有非常多的数据集,在CSDN,知乎什么搜一下可以找到一大堆,在收集数据时,发 ...

  3. 小小甜菜Movidius爬坑记

    小小甜菜Movidius爬坑记 我是在神经计算棒+树莓派3B上看到实际效果后决定使用本方案的,实际项目中使用树莓派CM3作为核心板卡,使用Movidius 2或Movidius X(具体版本看项目需求 ...

  4. 小白爬坑记:C语言学习点滴——我对单、双引号的理解

    小白爬坑记:C语言学习点滴--我对单.双引号的理解 一.单引号的作用: 二.双引号的作用: 三.字符或字符串容易犯的错误: 三.做个小题: 一.单引号的作用: 将单引号中间的所有符号直接转换为ASCI ...

  5. 我在「小米爬坑记」里,看到的 3 个创业真相

    小米把10年的创业经历,做了一次「开源」. 就在昨晚,雷军做了小米十周年的公开演讲.在演讲中,雷军对小米10年的发展做了一次大梳理,既有成绩,也有反思,还有小米历史上一些非常关键的发展节点.其实上个月 ...

  6. 小小甜菜深度学习爬坑记

    小小甜菜深度学习爬坑记 主要目的是整理一路学习的技术分享贴.我的电脑是笔记本联想拯救者R720,显卡是GTX1050Ti.其它环境仅供参考. 安装ubuntu+win10双系统 详情见技术贴用 Eas ...

  7. Spring Cloud Contract 爬坑记

    前言:spring-cloud-starter-contract-verifier:2.1.1.RELEASE. spring-cloud-contract-maven-plugin:2.2.1.RE ...

  8. 小小甜菜百度AI爬坑记

    小小甜菜百度AI爬坑记 作为国内较好的深度学习平台,我是在2018百度开发者大会拉入坑的.其可分为语音识别,语音合成,文字识别,图像识别,人体分析,人脸识别,理解与互交技术,AR增强现实等多个方向.我 ...

  9. npm run build 打包爬坑记(1)

    npm run build 打包爬坑记 先说说打包过程,npm run build 后放入phpstudy里面,访问本地ip,查看phpstudy的端口号,就能访问页面了(访问地址:http://19 ...

  10. 小小甜菜keras爬坑记

    小小甜菜keras爬坑记 前言 安装(参考深度学习爬坑记安装ubuntu16.04+cuda9+cudnn+tensorflow1.9.0) 视频资料 相关模型资料 学习笔记 ssd模型 yolov3 ...

最新文章

  1. GraphSAGE: GCN落地必读论文
  2. 如何自学python基础-零基础小白该如何学习Python?
  3. MariaDB配置慢日志
  4. 火焰效果材质实现_利用噪音图制作一个纸张燃烧的效果
  5. 创建provider服务
  6. Rabbits UVALive - 8211
  7. 涉及子模块_COMSOL Multiphysics 5.6 RF模块更新详解
  8. 使用ffmpeg简单合并视频(2个以上)
  9. 软件设计模式与体系结构课后作业汇总
  10. [python][project][爬虫] 堆糖网图片下载
  11. Java 练习题:猜数小游戏
  12. 迈动互联布局华北、华东、华南三大业务中心
  13. 人才管理是什么意思_复合型人才是什么意思(复合型人才八种能力)
  14. blender关于怎么导出上完色的FBX格式模型、以及导出后再导入,材质预览和渲染模式下材质透明度混乱的解决办法。
  15. [LLVM教程]LLVM之第一个语言前端
  16. 篮球社交小程序开发功能
  17. 《财富》封面文章:重新审视世界500强,它们又卷土重来了
  18. 沟通修炼 I型沟通-U型沟通
  19. 互联网信息服务业务(ICP许可证)
  20. 博士学位真的那么重要吗?上交大博士亲述科研心路,获4万高赞~

热门文章

  1. Win7如何简单的关闭445端口及445端口入侵详解
  2. 联想电脑EasyCamera无法打开摄像头
  3. FC网络光纤通信 c语言实现,[2018年最新整理]光纤通信实验指导书(含原理).doc
  4. 计算机网络网线制作与测试结果,网线制作和测试
  5. 【安全知识分享】PPTX|精益安全管理(130页)(附下载)
  6. linux电源管理配置,Arch Linux 如何修改默认电源管理设置
  7. 【Unity Shaders】ShadowGun系列之二——雾和体积光
  8. windows 定时杀掉进程
  9. 联想H61主板BIOS刷新(启天M7100系列)
  10. 计算机管理usb出现问号,在Windows操作系统的设备管理器中的多个设备名上有问号...