数据分析-循环神经网络-LSTM-案例

目录

前言

RNN循环神经网络

LSTM

应用案例

导入必要的模块

 设置使用的GPU

 读入数据

 查看数据

数据预处理

 生成数据集

 数据集划分

 建模

 编译

 训练

 可视化训练过程

预测

评价 


前言

传统的前馈神经可以比较好的处理回归、分类问题,CNN可以很好的处理图像数据,这些数据处理方法都只考虑当前时刻(样本)的特征。而时间序列数据、语音识别、语言建模,翻译等问题,不仅与当前时刻相关还与前n个时刻相关。

RNN循环神经网络

其中x_{t}为t时刻的输入,h_{t}为t时刻的输出,循环使得信息一步步向下一时刻传递。

 Recurrent Neural Networks have loops.

 RNN 可以被看做是同一神经网络的多次复制,每个神经网络模块会把消息传递给下一个。如果将这个循环展开:

An unrolled recurrent neural network.

RNN链式的结构,揭示了 RNN 本质上是与序列数据相关的。RNN是处理这类数据最好的神经网络架构。

RNN 的关键点之一就是可以接收先前的信息用到当前的时刻。

有时候,我们仅仅需要知道先前的很少几个时刻的信息就可以确定当前的输出。

例如,我们有一个语言模型用来基于先前的词来预测当前词。如果我们试着推测 “the clouds are in the   ?” 最后的词,我们不需要任何其他的上下文 (仅这个句子就够)—— 这个词很显然就应该是 sky。在这样的场景中,相关的信息和预测的词位置之间的间隔是非常小的

但是同样会有一些更加复杂的场景。假设我们试着去预测“I grew up in France... I speak fluent  ?”最后的词。当前的信息建议下一个词可能是一种语言的名字,但是如果我们需要弄清楚是什么语言,我们是需要先前提到的离当前位置很远的 France 的上下文的。这说明相关信息和当前预测位置之间的间隔就肯定变得相当的大。

不幸的是,在这个间隔不断增大时,基本的RNN 会丧失学习到连接如此远的信息的能力。

LSTM 并没有这个问题!


LSTM

长短期记忆(Long short-term memory)—— 一般就叫做 LSTM ——是一种 RNN 特殊的类型,可以学习长期依赖信息。LSTM 由Hochreiter & Schmidhuber (1997)提出,并在近期被Alex Graves进行了改良和推广。在很多领域,LSTM 都取得成功,并得到了广泛的使用。

LSTM 专门设计来避免长期依赖问题。记住长期的信息是 LSTM 的基本功能。

所有 RNN 都具有一种重复神经网络模块的链式的形式。在标准的 RNN 中,这个重复的模块只有一个非常简单的结构,例如一个 tanh 层。

标准的 RNN  

 LSTM的结构要比标准的RNN复杂得多。

LSTM 

其中

x_{t-1}为上一时刻的输入,x_{t}为当前t时刻的输入,x_{t+1}下一时刻的输入;


c_{t-1} 为上一时刻的cell状态,   c_{t}  为当前时刻的cell状态, c_{t+1} 为下一时刻的cell状态

​​​c为LSTM 的关键cell状态(保存过去的信息),水平线在图上方,向下一时刻传送信息。通过遗忘门f_{t}决定多少过去的信息会保留,多少被遗忘。

通过输入门i_{t}决定多少现在的信息会传送到下一时刻。

c_{t}=f_{t}*c_{t-1}+i_{t}*\bar{c}_{t}

\bar{c}_{t}=\sigma (W_{c}[h_{t-1},x_{t}]+b_{c})

 f_{t}为遗忘门,控制c_{t-1}多少进入当前时刻,当f_{t}为0时全部遗忘,当其为1时,全部进入当前时刻。

f_{t}=\sigma (W_{f}[h_{t-1},x_{t}]+b_{f})

 i_{t}为输入门,控制多少输入信息以及多少上一时刻的输出进入当前时刻。

i_{t}=\sigma (W_{i}[h_{t-1},x_{t}]+b_{i})


h_{t-1}为上一时刻的输出,h_{t}为当前t时刻的输出,h_{t+1}下一时刻的输出;

h_{t}=o_{t}*tanh(c_{t})

o_{t}为输出门,控制c_{t}多少信息会被输出。

o_{t}=\sigma (W_{o}[h_{t-1},x_{t}]+b_{o})

应用案例

这里使用北京空气质量数据集,该数据集记录了北京某段时间每小时的气象情况和污染程度。

根据前几个小时的记录预测下一小时PM2.5的浓度。

该数据集包括日期时间、PM2.5浓度、露点、温度、风向、风速等字段,具体如下:

  • No:样本编号
  • year:该行记录的年
  • month:该行记录的月
  • day:该行记录的日
  • hour:该行记录的小时
  • pm2.5: PM2.5浓度
  • DEWP:露点
  • TEMP:温度
  • PRES:大气压力
  • cbwd:组合风向
  • lws:累计风速
  • ls:累计小时下雪量
  • lr:累计小时下雨量

尽管只采用单一维度的PM2.5变化的时间序列,也可以预测下一时刻PM2.5的浓度,考虑其它维度对预测的精度有帮助,本案例使用的多维度的数据进行PM2.5的预测。

导入必要的模块

from tensorflow import keras
from tensorflow.keras import layers
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

 设置使用的GPU

print(tf.test.gpu_device_name())
"""
Returns the name of a GPU device if available or a empty string.
"""
print(tf.config.list_physical_devices("GPU"))  #default cpu&gpu
"""
Return a list of physical devices visible to the host runtime.
"""
import os
os.environ["CUDA_VISIBLE_DEVICES"] = "0"  

 读入数据

data = pd.read_csv('d:/datasets/PRSA_data_2010.1.1-2014.12.31.csv')

 查看数据

data.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 43824 entries, 0 to 43823
Data columns (total 13 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   No      43824 non-null  int64  
 1   year    43824 non-null  int64  
 2   month   43824 non-null  int64  
 3   day     43824 non-null  int64  
 4   hour    43824 non-null  int64  
 5   pm2.5   41757 non-null  float64
 6   DEWP    43824 non-null  int64  
 7   TEMP    43824 non-null  float64
 8   PRES    43824 non-null  float64
 9   cbwd    43824 non-null  object 
 10  Iws     43824 non-null  float64
 11  Is      43824 non-null  int64  
 12  Ir      43824 non-null  int64  
dtypes: float64(4), int64(8), object(1)
memory usage: 4.3+ MB

共43824样本,明显pm2.5有缺失。

数据预处理

删除前面连续缺失的部分,中间少量的缺失不能删除样本(保证时间序列连续),采用填补的方法。

data[data['pm2.5'].isna()]
data = data.iloc[24:].copy()
data.fillna(method='ffill', inplace=True)

 删除没有意义的特征"No"

data.drop('No', axis=1, inplace=True)

 将年月日时转换为时间型索引

import datetime
data['time'] = data.apply(lambda x: datetime.datetime(year=x['year'],
                                       month=x['month'],
                                       day=x['day'], 
                                       hour=x['hour']), 
                          axis=1)
data.set_index('time', inplace=True)
data.drop(columns=['year', 'month', 'day', 'hour'], inplace=True)
data.head()

对cbwd为object型,需要对其编码 

data = data.join(pd.get_dummies(data.cbwd))
del data['cbwd']
data['pm2.5'].plot()

 生成数据集

时间序列数据考虑的是前一些时刻的数据与当前时刻的输出相关。时间序列的数据要进行形式变换。

如用前5小时的数据预测1小时的,就要对数据按6小时,滑动窗格方式取出,其中前5小时为X,后1小时的为Y。

如0:5,1:6,2:7...,n-5:n,直到最后一个样本n,每次取6小时数据。

其中0:4共5小时为X,5为Y;1:5共5小时为第二个样本的X,6小时的为第二个样本Y。以此共n-4个样本。

sequence_length = 5*24  #预测使用的基础序列长度,可以根据预测结果调整
pred = 1         #预测长度,可调整
data_ = []
#连续重叠开窗分块数据(如0:5*24+1—1,1-5*24+1,2:5*24+2,...等),每一块是一个样本,得到LSTM需要的数据集。
for i in range(len(data) - sequence_length - pred):
    data_.append(data.iloc[i: i + sequence_length + pred])
data_ = np.array([df.values for df in data_])

 数据集划分

#乱序
np.random.shuffle(data_)
#基础数据序列与预测数据分离  (特征与标签分离)
x = data_[:, :-pred, :]  # 基础数据序列,含所有特征。数据集X
y = data_[:, -pred:, 0]   #预测数据,只包含pm2.5。数据集Y,前面的0:-pred数据序列,预测-delay:

#设置数据集划分的比例
split_0 = int(data_.shape[0] * 0.7)
split_1 = int(data_.shape[0] * 0.9)
#测试集训练集划分
train_x = x[: split_0]  #前面已乱序,取前70%为训练集,后30%为测试或验证数据
val_x=x[split_0:split_1]  #20%为验证集
test_x = x[split_1:]   #10%为测试集

train_y = y[: split_0]
val_y=y[split_0:split_1]
test_y = y[split_1:]

 建模

activation="tanh"是LSTM使用cuDNN必要条件,可以不使用cuDNN。

cuDNN(CUDA Deep Neural Network library):是NVIDIA打造的针对深度神经网络的加速库,是一个用于深层神经网络的GPU加速库。

model = keras.Sequential()
model.add(layers.LSTM(32, input_shape=(train_x.shape[1:]),activation="tanh", return_sequences=True))  
#注意return_sequences=True,确保下层的lstm输入为sequences
model.add(layers.LSTM(128,activation="tanh", return_sequences=True))
model.add(layers.LSTM(32,activation="tanh")) #下层为Dense,不需要return_sequences=True
model.add(layers.Dense(1))  #输出为实数,取值范围不限,不需要激活函数

注:本质上数据集划分后,用前馈神经网络,CNN都可以,只是效果上的差异。

'''
model_D = keras.Sequential()
model_D.add(layers.Flatten(input_shape=(train_x.shape[1:]))) #拍平
model_D.add(layers.Dense(16, activation='relu'))
model_D.add(layers.Dense(4, activation='relu'))
model_D.add(layers.Dense(1))

model_D.compile(optimizer=keras.optimizers.Adam(), loss='mse')

history = model_D.fit(train_x, train_y,
                    batch_size = 128,
                    epochs=40,
                    validation_data=(val_x, val_y),
                    use_multiprocessing=True
                    )
'''

 编译

model.compile(optimizer=keras.optimizers.Adam(), loss='mae')  #指定优化算法,损失函数

 训练

类似小学生做练习题。习题总数1000(训练样本总数),每次做128道题(batch_size=128),int(1000/128)次基本全部做完。但是只做一遍可能不够,需要反复训练,就要求把这1000道题做200遍(epochs=200)。每做一次可以采用验证集数据检验学习的效果(validation_data=(val_x, val_y))。

history = model.fit(train_x, train_y,
                    batch_size = 128,   #每次训练的数据量,全部数据训练一轮需要训练int(样本总数/batch_size)次
                    epochs=200,         #训练的轮数(样本重复使用的次数)
                    validation_data=(val_x, val_y))

Epoch 1/200
273/273 [==============================] - 3s 8ms/step - loss: 88.4373 - val_loss: 82.3908
Epoch 2/200
273/273 [==============================] - 2s 7ms/step - loss: 80.1071 - val_loss: 77.2936

每次128(batch_size), 全部做完一遍需要做273次,总样本数大致为273*128。

 可视化训练过程

plt.plot(history.epoch, history.history.get('loss'), 'y', label='Training loss')
plt.plot(history.epoch, history.history.get('val_loss'), 'b', label='Test loss')
plt.legend()

预测

pred_y=model.predict(test_x)

评价 

from sklearn.metrics  import r2_score,mean_squared_error
print(r2_score(pred_y,test_y))
print(mean_squared_error(y_test,pred_y))

  • 11
    点赞
  • 65
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

ITLiu_JH

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值