前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深度学习笔记(一) tf.keras 构建lstm神经网络进行时间序列预测

深度学习笔记(一) tf.keras 构建lstm神经网络进行时间序列预测

作者头像
forxtz
发布2021-03-09 16:04:54
2.9K1
发布2021-03-09 16:04:54
举报
文章被收录于专栏:源懒由码

  简介:长短期记忆人工神经网络(Long-Short Term Memory, LSTM)是一种时间递归神经网络(RNN),论文首次发表于1997年。由于独特的设计结构,LSTM适合于处理和预测时间序列中间隔和延迟非常长的重要事件。

  目的:学会使用tf.keras构建lstm神经网络进行一个基本的时间序列数据预测(入门版),基于官方案例-预测天气数据进行学习。

  用户:同通过学习库的使用而进行应用的用户,本节笔记不包含原理解读。

参考链接:

  官方案例(具体代码可从官方下载):https://keras.io/api/preprocessing/timeseries/#timeseries_dataset_from_array-function

  深度学习-理解keras中的loss和val_loss:https://blog.csdn.net/JaysonRen/article/details/103273519

  机器学习之优化器keras.optimizers.Adam()详解:https://blog.csdn.net/i_canjnu/article/details/106035640

主要步骤分为:

  1、确定使用目的;2、读取数据;3、数据预处理;4、构造样本数据和测试数据;5、创建模型;6、训练模型;7、展示训练结果;8、进行预测;

下面开始上demo学习。

1、确定使用目的:

  马克斯·普朗克生物地球化学研究所记录了耶拿气候数据,时间为2009年1月10日至2016年12月31日,每10分钟记录一次,具有14个特征,例如温度,压力,湿度等。

集构建一个天气预测模型 。

  由于气候的变化在一个小时内并不明显,所以考虑使用这个数据建立一个温度预测模型,使用前720分钟(120个小时)数据72分钟后(12个小时后)的温度时点进行预测。

2、读取数据

代码语言:javascript
复制
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow import keras
from zipfile import ZipFile
import os

uri = "https://storage.googleapis.com/tensorflow/tf-keras-datasets/jena_climate_2009_2016.csv.zip"
zip_path = keras.utils.get_file(origin=uri, fname="jena_climate_2009_2016.csv.zip")
zip_file = ZipFile(zip_path)
zip_file.extractall()
csv_path = "jena_climate_2009_2016.csv"

df = pd.read_csv(csv_path)

获取原始数据后,对原始数据进行一个观察,包括每个字段的趋势。

代码语言:javascript
复制
# 绘制数据的情况

# 每个图的标题
titles = ["Pressure","Temperature","Temperature in Kelvin","Temperature (dew point)","Relative Humidity","Saturation vapor pressure","Vapor pressure",
    "Vapor pressure deficit","Specific humidity","Water vapor concentration","Airtight","Wind speed","Maximum wind speed","Wind direction in degrees",]

# 原始数据的字段名
feature_keys = ["p (mbar)", "T (degC)","Tpot (K)","Tdew (degC)","rh (%)","VPmax (mbar)","VPact (mbar)","VPdef (mbar)","sh (g/kg)","H2OC (mmol/mol)",
    "rho (g/m**3)","wv (m/s)","max. wv (m/s)","wd (deg)",]

# 绘制的图片颜色
colors = ["blue","orange","green","red","purple","brown","pink","gray","olive","cyan",]

date_time_key = "Date Time"

# 展示原始数据可视化
def show_raw_visualization(data):
    time_data = data[date_time_key]
    # 7*2的总图形结构
    fig, axes = plt.subplots(
        nrows=7, ncols=2, figsize=(15, 20), dpi=80, facecolor="w", edgecolor="k"
    )
    for i in range(len(feature_keys)):
        key = feature_keys[i]
        c = colors[i % (len(colors))] # 选择一个颜色,循环选择
        t_data = data[key] # 获取对应字段数据
        t_data.index = time_data # 设置索引为时间
        t_data.head()
        ax = t_data.plot(
            ax=axes[i // 2, i % 2],
            color=c,
            title="{} - {}".format(titles[i], key),
            rot=25,
        )
        ax.legend([titles[i]])
    plt.tight_layout()  # 这个的作用是?自适应图片大小


show_raw_visualization(df)

两两字段间的相关性:

代码语言:javascript
复制
def show_heatmap(data):
    plt.matshow(data.corr())
    plt.xticks(range(data.shape[1]), data.columns, fontsize=14, rotation=90)
    plt.gca().xaxis.tick_bottom()
    plt.yticks(range(data.shape[1]), data.columns, fontsize=14)

    cb = plt.colorbar()
    cb.ax.tick_params(labelsize=14)
    plt.title("Feature Correlation Heatmap", fontsize=14)
    plt.show()


show_heatmap(df)  # 展示字段两两相关性

3、数据预处理

由于原始数据不同字段的数据差异会比较多,所以需要进行无量纲处理,这里采用z-scroce。最后对数据进行拆分。

代码语言:javascript
复制
split_fraction = 0.715   # 训练和测试数据集划分比例
train_split = int(split_fraction * int(df.shape[0]))  # 计算出划分的索引处
step = 6 # 数据的选取步频

past = 720 # 使用前720个数据时间进行预测
future = 72 # 预测72个数据时点后的数据
learning_rate = 0.001 # 学习速率,用于建模的优化器参数
batch_size = 256 # 训练的数据批此规模
epochs = 10 # 训练次数

# 归一化,z-score
def normalize(data, train_split):
    data_mean = data[:train_split].mean(axis=0)
    data_std = data[:train_split].std(axis=0)
    return (data - data_mean) / data_std
代码语言:javascript
复制
# 从相关热图中可以看到,相对湿度和比湿度等很少参数是多余的。因此,我们将使用选择功能,而不是全部。
print(
    "The selected parameters are:",
    ", ".join([titles[i] for i in [0, 1, 5, 7, 8, 10, 11]]),
)
# 选择更合适的字段进行建模
selected_features = [feature_keys[i] for i in [0, 1, 5, 7, 8, 10, 11]]
features = df[selected_features]
features.index = df[date_time_key]
features.head()

# 所有数据进行归一化
features = normalize(features.values, train_split)
features = pd.DataFrame(features)
#print(features.head(2))

# 划分训练数据和测试数据
train_data = features.loc[0 : train_split - 1] # 训练数据
val_data = features.loc[train_split:]  # 测试数据,为什么val_data会被修改呢,哦,因为前面还没有进行划分

print(train_data.head(2))
print(val_data.head(2))

4、构造样本数据和测试数据

按前面所说,每10分钟记录一次观察,即每小时6次。由于我们预计60分钟之内不会发生重大变化,因此我们将每小时重新采样一个点。函数timeseries_dataset_from_array中的sampling_rate参数可以达到此目的,可以快速的以一个滑动窗口获取数据。

代码语言:javascript
复制
# 构造训练数据
# 形成[[1,7,...720],[2,8,...,721]] 的x数据集,[[721],[722]...]的y数据集
# 类型于滑动窗口取数一样
dataset_train = keras.preprocessing.timeseries_dataset_from_array(
    x_train,
    y_train,
    sequence_length=sequence_length, # 一批采集120次
    sampling_rate=step, # 6步采集一次,即 60分钟采集一次
    batch_size=batch_size,
)
代码语言:javascript
复制
测试集
代码语言:javascript
复制
# 构造验证数据
x_end = len(val_data) - past - future  # 因为是用720个监测数据去预测72个窗口数据后的值,所以要倒减一下

label_start = train_split + past + future # 同理Y值要延后一下

x_val = val_data.iloc[:x_end][[i for i in range(7)]].values
y_val = features.iloc[label_start:][[1]]

dataset_val = keras.preprocessing.timeseries_dataset_from_array(
    x_val,
    y_val,
    sequence_length=sequence_length,
    sampling_rate=step,
    batch_size=batch_size,
)


for batch in dataset_train.take(1):
    inputs, targets = batch

print("Input shape:", inputs.numpy().shape)
print("Target shape:", targets.numpy().shape)

5、创建模型

创建模型,创建一个(120,7)输入,中间32个节点,输入了1个节点的模型。还需要学习如何确定模型层数和中间层节点数。连续型数据,loss采用mse:均方损失函数。

代码语言:javascript
复制
# 创建模型
inputs = keras.layers.Input(shape=(inputs.shape[1], inputs.shape[2]))
lstm_out = keras.layers.LSTM(32)(inputs)
outputs = keras.layers.Dense(1)(lstm_out)

model = keras.Model(inputs=inputs, outputs=outputs)
# optimizer 优化器,加快学习速度,loss 损失计算
model.compile(optimizer=keras.optimizers.Adam(learning_rate=learning_rate), loss="mse")
# 展示模型
model.summary()

6、训练模型

使用ModelCheckpoint回调EarlyStopping函数定期保存检查点,并使用该回调函数在验证损失不再改善时中断训练

代码语言:javascript
复制
# 设置损失函数和训练
path_checkpoint = "model_checkpoint.h5"
es_callback = keras.callbacks.EarlyStopping(monitor="val_loss", min_delta=0, patience=5)

# 使用ModelCheckpoint回调EarlyStopping函数定期保存检查点,并使用该回调函数在验证损失不再改善时中断训练。
modelckpt_callback = keras.callbacks.ModelCheckpoint(
    monitor="val_loss",
    filepath=path_checkpoint,
    verbose=1,
    save_weights_only=True,
    save_best_only=True,
)

history = model.fit(
    dataset_train,
    epochs=epochs,
    validation_data=dataset_val,
    callbacks=[es_callback, modelckpt_callback],
)

7、展示训练结果

从结果看,通过训练loss和val_loss都往更好的方向发展。

代码语言:javascript
复制
loss下降,val_loss下降:训练网络正常,最好情况。

loss下降,val_loss稳定:网络过拟合化,可以添加Dropout和Max pooling。

loss稳定,val_loss下降:数据集有严重问题,建议重新选择。

loss稳定,val_loss稳定:学习过程遇到瓶颈,需要减小学习率(自适应网络效果不大)或batch数量。

loss上升,val_loss上升:网络结构设计问题,训练超参数设置不当,数据集需要清洗等问题,最差情况。
代码语言:javascript
复制
# 显示结果
# loss:训练集的差距大小 和 val_loss 测试集的差距大小
def visualize_loss(history, title):
    loss = history.history["loss"]
    val_loss = history.history["val_loss"]
    epochs = range(len(loss))
    plt.figure()
    plt.plot(epochs, loss, "b", label="Training loss")
    plt.plot(epochs, val_loss, "r", label="Validation loss")
    plt.title(title)
    plt.xlabel("Epochs")
    plt.ylabel("Loss")
    plt.legend()
    plt.show()


visualize_loss(history, "Training and Validation Loss")

8、进行预测

从测试数据集中再选出5个节点进行预测查看。预测值和实际值存在有点误差。

代码语言:javascript
复制
# 预测
def show_plot(plot_data, delta, title):
    labels = ["History", "True Future", "Model Prediction"]
    marker = [".-", "rx", "go"]
    time_steps = list(range(-(plot_data[0].shape[0]), 0))
    if delta:
        future = delta
    else:
        future = 0

    plt.title(title)
    for i, val in enumerate(plot_data):
        if i:
            # 绘制预测数据
            plt.plot(future, plot_data[i], marker[i], markersize=10, label=labels[i])
        else:
            # 绘制历史数据
            plt.plot(time_steps, plot_data[i].flatten(), marker[i], label=labels[i])
    plt.legend()
    plt.xlim([time_steps[0], (future + 5) * 2])
    plt.xlabel("Time-Step")
    plt.show()
    return

# 输入5个批此数据,历史数据是120个小时,预测数据是12个小时以后,使用模型预测处结果
for x, y in dataset_val.take(5):
    show_plot(
        [x[0][:, 1].numpy(), y[0].numpy(), model.predict(x)[0]],
        12,
        "Single Step Prediction",
    )

总结:

对keras创建Lstm神经网络的流程大致有了一个了解,下来需要进一步了解具体的原理进行深入的学习,这样的模型参数设置,和结果的好坏才有更准确的把握。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-03-06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、确定使用目的:
  • 2、读取数据
  • 3、数据预处理
  • 4、构造样本数据和测试数据
  • 5、创建模型
  • 6、训练模型
  • 7、展示训练结果
  • 8、进行预测
相关产品与服务
腾讯云 BI
腾讯云 BI(Business Intelligence,BI)提供从数据源接入、数据建模到数据可视化分析全流程的BI能力,帮助经营者快速获取决策数据依据。系统采用敏捷自助式设计,使用者仅需通过简单拖拽即可完成原本复杂的报表开发过程,并支持报表的分享、推送等企业协作场景。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档