讲透一个强大算法案例,LSTM !!
2025-01-08
基本结构
LSTM单元包括三个主要的门,这些门用于控制信息的流动,LSTM单元的结构如下:
- 遗忘门(Forget Gate):决定当前时刻哪些信息需要被遗忘。
- 输入门(Input Gate):决定当前时刻哪些信息需要被写入。
- 输出门(Output Gate):决定当前时刻的隐藏状态。
每个LSTM单元还包含一个单独的细胞状态(cell state),用来记录长期信息。
公式推导
1. 遗忘门(Forget Gate)
遗忘门用于决定前一时刻的细胞状态 中哪些信息需要被遗忘。公式如下:
其中:
- 是遗忘门的输出。
- 是sigmoid激活函数。
- 是遗忘门的权重矩阵。
- 是前一时刻的隐藏状态。
- 是当前时刻的输入。
- 是遗忘门的偏置。
2. 输入门(Input Gate)
输入门用于决定当前时刻哪些信息需要写入细胞状态。包括两个步骤:
- 计算输入门的激活值。
- 生成新的候选细胞状态。
计算输入门的激活值:
生成新的候选细胞状态:
其中:
- 是输入门的输出。
- 是新的候选细胞状态。
- 是输入门的权重矩阵。
- 是候选细胞状态的权重矩阵。
- 是输入门的偏置。
- 是候选细胞状态的偏置。
3. 更新 Cell State
细胞状态的更新包括两部分:保留部分旧的细胞状态和添加新的细胞状态。公式如下:
其中:
- 是当前时刻的细胞状态。
- 是元素级别的乘法。
4. 输出门(Output Gate)
输出门用于决定当前时刻的隐藏状态。公式如下:
当前时刻的隐藏状态:
其中:
- 是输出门的输出。
- 是输出门的权重矩阵。
- 是输出门的偏置。
总的来说,LSTM通过引入遗忘门、输入门和输出门,有效地控制了信息的流动,解决了传统RNN在处理长序列数据时的梯度消失和梯度爆炸问题。
这里再汇总一下上面的公式:
- 遗忘门:
- 输入门:
- 候选细胞状态:$ \tilde{C}t = \tanh(W_C \cdot [h{t-1}, x_t] + b_C) $
- 更新细胞状态:
- 输出门:
- 隐藏状态:
通过这些公式,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)
算法流程
- 数据加载与预处理
- 加载数据并进行数据清洗。
- 处理缺失值。
- 数据标准化。
- 生成训练集和测试集。
- 构建LSTM模型
- 定义模型架构。
- 编译模型。
- 模型训练
- 训练模型。
- 监控训练过程。
- 模型评估
- 进行预测并评估模型性能。
- 进行可视化分析。
完整代码
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()
代码中的步骤一些细节,再给大家说一下:
- 超参数调整
- 调整LSTM层的神经元数量和层数。
- 尝试不同的学习率和优化器。
- 调整batch size和epochs数量。
- 特征工程
- 添加更多的特征,如历史PM2.5值。
- 尝试不同的时间窗口大小(look_back)。
- 数据处理
- 处理风向(cbwd)等分类变量。
- 处理可能的异常值。
- 模型改进
- 尝试不同的模型结构,如双向LSTM或GRU。
- 使用更复杂的网络结构,如卷积神经网络(CNN)与LSTM结合。
最后
以上,整个是一个完整的LSTM时间序列预测的案例,包括数据预处理、模型构建、训练、评估和可视化。大家在自己实际的实验中,根据需求进行进一步的调整和优化。
本文章转载微信公众号@深夜努力写Python
同话题下的热门内容