所有文章 > AI驱动 > 讲透一个强大算法案例,LSTM !!

讲透一个强大算法案例,LSTM !!

基本结构

LSTM单元包括三个主要的门,这些门用于控制信息的流动,LSTM单元的结构如下:

  1. 遗忘门(Forget Gate):决定当前时刻哪些信息需要被遗忘。
  2. 输入门(Input Gate):决定当前时刻哪些信息需要被写入。
  3. 输出门(Output Gate):决定当前时刻的隐藏状态。

每个LSTM单元还包含一个单独的细胞状态(cell state),用来记录长期信息。

公式推导

1. 遗忘门(Forget Gate)

遗忘门用于决定前一时刻的细胞状态  中哪些信息需要被遗忘。公式如下:

其中:

  •  是遗忘门的输出。
  •  是sigmoid激活函数。
  •  是遗忘门的权重矩阵。
  •  是前一时刻的隐藏状态。
  •  是当前时刻的输入。
  •  是遗忘门的偏置。

2. 输入门(Input Gate)

输入门用于决定当前时刻哪些信息需要写入细胞状态。包括两个步骤:

  • 计算输入门的激活值。
  • 生成新的候选细胞状态。

计算输入门的激活值:

生成新的候选细胞状态:

其中:

  •  是输入门的输出。
  •  是新的候选细胞状态。
  •  是输入门的权重矩阵。
  •  是候选细胞状态的权重矩阵。
  •  是输入门的偏置。
  •  是候选细胞状态的偏置。

3. 更新 Cell State

细胞状态的更新包括两部分:保留部分旧的细胞状态和添加新的细胞状态。公式如下:

其中:

  •  是当前时刻的细胞状态。
  •  是元素级别的乘法。

4. 输出门(Output Gate)

输出门用于决定当前时刻的隐藏状态。公式如下:

当前时刻的隐藏状态:

其中:

  •  是输出门的输出。
  •  是输出门的权重矩阵。
  •  是输出门的偏置。

总的来说,LSTM通过引入遗忘门、输入门和输出门,有效地控制了信息的流动,解决了传统RNN在处理长序列数据时的梯度消失和梯度爆炸问题。

这里再汇总一下上面的公式:

  1. 遗忘门:
  2. 输入门:
  3. 候选细胞状态:$ \tilde{C}t = \tanh(W_C \cdot [h{t-1}, x_t] + b_C) $
  4. 更新细胞状态:
  5. 输出门:
  6. 隐藏状态:

通过这些公式,LSTM能够有效地捕捉和保留序列中的长期依赖关系,从而在处理时间序列数据、自然语言处理等任务中表现出色。

案例:利用LSTM进行时间序列预测

数据集介绍

数据集来自UCI机器学习库的北京PM2.5数据集。数据包含2010年至2014年北京空气质量监测数据,包括PM2.5浓度、天气数据等。

公众号后台,回复「数据集」,取PRSA_data_2010.1.1-2014.12.31.csv

PRSA_data_2010.1.1-2014.12.31.csv 数据集包括以下列:

  • No: 行号
  • year: 年
  • month: 月
  • day: 日
  • hour: 小时
  • pm2.5: PM2.5浓度(ug/m^3)
  • DEWP: 露点温度(摄氏度)
  • TEMP: 温度(摄氏度)
  • PRES: 压力(hPa)
  • cbwd: 风向
  • Iws: 风速(m/s)
  • Is: 累计小时数
  • Ir: 累计降雨量(mm)

算法流程

  1. 数据加载与预处理
    • 加载数据并进行数据清洗。
    • 处理缺失值。
    • 数据标准化。
    • 生成训练集和测试集。
  2. 构建LSTM模型
    • 定义模型架构。
    • 编译模型。
  3. 模型训练
    • 训练模型。
    • 监控训练过程。
  4. 模型评估
    • 进行预测并评估模型性能。
    • 进行可视化分析。

完整代码

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import LSTM, Dense
from keras.callbacks import EarlyStopping

# 数据加载
data = pd.read_csv('PRSA_data_2010.1.1-2014.12.31.csv')

# 数据预处理
data['pm2.5'].fillna(data['pm2.5'].mean(), inplace=True) # 处理缺失值

# 选择特征和目标变量
features = ['DEWP', 'TEMP', 'PRES', 'Iws']
target = 'pm2.5'

# 标准化
scaler = MinMaxScaler()
data_scaled = scaler.fit_transform(data[features + [target]])

# 创建时间序列数据集
def create_dataset(dataset, look_back=1):
X, y = [], []
for i in range(len(dataset) - look_back):
X.append(dataset[i:(i + look_back), :-1])
y.append(dataset[i + look_back, -1])
return np.array(X), np.array(y)

look_back = 24
X, y = create_dataset(data_scaled, look_back)

# 划分训练集和测试集
train_size = int(len(X) * 0.8)
X_train, X_test = X[:train_size], X[train_size:]
y_train, y_test = y[:train_size], y[train_size:]

# 构建LSTM模型
model = Sequential()
model.add(LSTM(50, return_sequences=True, input_shape=(look_back, len(features))))
model.add(LSTM(50))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mean_squared_error')

# 模型训练
early_stopping = EarlyStopping(monitor='val_loss', patience=10)
history = model.fit(X_train, y_train, epochs=100, batch_size=32, validation_split=0.2, callbacks=[early_stopping])

# 模型评估
y_pred = model.predict(X_test)

# 反标准化
y_test_inv = scaler.inverse_transform(np.concatenate((X_test[:, -1, :-1], y_test.reshape(-1, 1)), axis=1))[:, -1]
y_pred_inv = scaler.inverse_transform(np.concatenate((X_test[:, -1, :-1], y_pred), axis=1))[:, -1]

# 绘制结果
plt.figure(figsize=(12, 6))
plt.plot(y_test_inv, label='True')
plt.plot(y_pred_inv, label='Predicted')
plt.legend()
plt.show()

# 绘制损失曲线
plt.figure(figsize=(12, 6))
plt.plot(history.history['loss'], label='Training Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.legend()
plt.show()

代码中的步骤一些细节,再给大家说一下:

  1. 超参数调整
    • 调整LSTM层的神经元数量和层数。
    • 尝试不同的学习率和优化器。
    • 调整batch size和epochs数量。
  2. 特征工程
    • 添加更多的特征,如历史PM2.5值。
    • 尝试不同的时间窗口大小(look_back)。
  3. 数据处理
    • 处理风向(cbwd)等分类变量。
    • 处理可能的异常值。
  4. 模型改进
    • 尝试不同的模型结构,如双向LSTM或GRU。
    • 使用更复杂的网络结构,如卷积神经网络(CNN)与LSTM结合。

最后

以上,整个是一个完整的LSTM时间序列预测的案例,包括数据预处理、模型构建、训练、评估和可视化。大家在自己实际的实验中,根据需求进行进一步的调整和优化。

本文章转载微信公众号@深夜努力写Python