社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  机器学习算法

【深度学习】突破LSTM!时间序列预测 !!

机器学习初学者 • 4 天前 • 41 次点击  

今儿再来和大家聊聊 LSTM的问题,原理给家理清楚后,后面讲解一个完整的时间序列案例:用LSTM预测未来一周的天气变化

今天的内容包括以下几个大块:

1. 背景与原理:LSTM(长短期记忆网络)如何捕捉时间序列数据的特征以及用于天气预测的基本原理。

2. 数据预处理和虚拟数据集生成:准备一个合理的虚拟天气数据集,并进行数据处理。

3. LSTM模型构建与训练:在PyTorch中构建LSTM模型,设置损失函数和优化器。

4. 预测与可视化分析:用LSTM模型进行预测,并用图形展示结果和模型性能分析。

5. 模型优化与调参建议:提出模型优化方向和详细调参流程。

接下来,我们来详细的拆解每一个步骤。

老规矩如果大家伙觉得近期文章还不错!欢迎大家点个赞、转个发,文末赠送《机器学习学习小册》

文末可取本文PDF版本~

1. 基本原理

简单来说,LSTM 是 RNN 的一种,它通过引入“记忆单元”来捕捉长时间的依赖关系,使其在处理长期依赖问题时非常有效。对于天气数据的预测,LSTM特别适用,因为天气数据是高度时序依赖的。

例如,某一天的温度和湿度可能会受到前几天数据的影响,这些“依赖关系”是LSTM所擅长捕捉的。

LSTM 用于解决普通RNN在处理长序列时常见的梯度消失和梯度爆炸问题。其核心特点是引入了“记忆单元”(cell state)和三个“门”机制(遗忘门、输入门、输出门)来控制信息的流动。

基本结构

LSTM单元的主要结构包括:

  • 记忆单元(Cell State) :用于存储长期的信息。记忆单元在时间上连接,不同时间步的数据可以选择性地被保留或丢弃,这使得LSTM可以“记住”长期的信息。
  • 隐藏状态(Hidden State) :与普通RNN的隐藏状态类似,用于存储短期信息,但在LSTM中,隐藏状态还依赖于记忆单元的状态。

三个“门”机制

LSTM中的三个门分别用于控制信息的“遗忘”“更新”和“输出”:

1. 遗忘门(Forget Gate)

决定上一个时间步的记忆信息  是否被遗忘。遗忘门是一个0到1之间的系数(通过激活函数sigmoid生成),控制哪些信息从记忆单元中移除,哪些保留下来。

数学公式:

其中:

  •  是遗忘门的输出(0到1之间)。
  •  是权重矩阵, 是偏置项。
  •  是上一个时间步的隐藏状态, 是当前时间步的输入。

2. 输入门(Input Gate)

决定当前输入信息是否写入记忆单元中,用于更新记忆内容。输入门同样通过sigmoid函数生成一个0到1的值,表示当前输入数据的重要性。

数学公式为:

  •  是输入门的输出(0到1之间)。
  •  是权重矩阵, 是偏置项。

同时,我们会计算一个候选记忆状态(Candidate Memory Cell),用于提取输入信息的主要特征,并将其加入到记忆单元中:

  •  是候选记忆状态,表示当前输入信息的特征。
  • 这里使用的是tanh激活函数,将数据压缩到-1到1之间。

3. 输出门(Output Gate)

决定当前记忆单元中的信息输出到隐藏状态的程度,用于产生当前时刻的隐藏状态 ,并将其传递给下一个时间步和最终输出层。

数学公式:

  •  是输出门的输出(0到1之间)。
  •  和  分别是权重矩阵和偏置项。

然后,将更新后的记忆单元状态与输出门的控制相结合,得到新的隐藏状态:

记忆单元更新

在以上三个门的作用下,记忆单元状态  会被不断更新。具体步骤如下:

  • 首先,先将上一个时间步的记忆单元状态  乘以遗忘门 ,从而决定哪些信息需要保留,哪些需要遗忘。
  • 然后,将输入门  和候选记忆状态  的乘积相加,这部分决定当前输入的信息能否被写入记忆单元。

数学公式:

  • 其中  表示旧信息的遗忘程度, 表示新信息的引入。

这个更新机制让LSTM既能记住长期的重要信息,也能丢弃不必要的旧信息。最终,记忆单元的状态  和隐藏状态  将作为输入,传递给下一个时间步。

LSTM 整体流程

通过上述过程,LSTM在每个时间步的操作可以概括为以下步骤:

  1. 计算遗忘门 ,决定旧记忆单元信息的遗忘比例。
  2. 计算输入门  和候选记忆单元 ,决定新信息对记忆单元的更新比例。
  3. 更新记忆单元 ,结合遗忘门和输入门的结果,形成新的记忆状态。
  4. 计算输出门 ,控制隐藏状态  的生成。
  5. 根据记忆单元  和输出门 ,计算新的隐藏状态 ,并传递给下一个时间步。

通过这种记忆单元状态的更新与控制机制,LSTM能够有效地在较长的序列中保持记忆,从而适用于时间序列预测等长时序依赖的任务。

2. 数据预处理与虚拟数据集生成

为了更好的理解算法本身,实际数据非常大,不利于我们学习,我们构建一个虚拟天气数据集,包括温度、湿度、风速等变量。假设我们有一年的历史数据,每日更新。我们将模拟这些数据并将其用于训练和测试。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 生成虚拟天气数据集
np.random.seed(42)
days = 365  # 一年数据
temperature = 30 + 5 * np.sin(np.linspace(02 * np.pi, days)) + np.random.normal(0 1, days)
humidity = 50 + 10 * np.sin(np.linspace(02 * np.pi, days)) + np.random.normal(02, days)
wind_speed = 10 + 3 * np.sin(np.linspace(02 * np.pi, days)) + np.random.normal(01, days)

data = pd.DataFrame({
    'temperature': temperature,
    'humidity': humidity,
    'wind_speed': wind_speed
})

data.head()

数据标准化

在训练模型之前,需要将数据标准化,以便LSTM能够更有效地学习数据特征。

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(01))
data_scaled = scaler.fit_transform(data)

3. LSTM模型构建与训练

数据切分

将数据分为训练集和测试集(80%训练,20%测试)。

train_size = int(len(data_scaled) * 0.8)
train_data = data_scaled[:train_size]
test_data = data_scaled[train_size:]

def create_sequences(data, seq_length):
    xs, ys = [], []
    for i in range(len(data) - seq_length):
        x = data[i:i+seq_length]
        y = data[i+seq_length]
        xs.append(x)
        ys.append(y)
    return np.array(xs), np.array(ys)

seq_length = 7  # 用前7天的数据预测第8天
X_train, y_train = create_sequences(train_data, seq_length)
X_test, y_test = create_sequences(test_data, seq_length)

模型定义

我们使用PyTorch构建LSTM模型。

import torch
import torch.nn as nn

class WeatherLSTM(nn.Module):
    def __init__(self, input_size, hidden_size, output_size, num_layers=1):
        super(WeatherLSTM, self).__init__()
        self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True)
        self.fc = nn.Linear(hidden_size, output_size)
    
    def forward(self, x):
        out, _ = self.lstm(x)
        out = self.fc(out[:, -1, :])
        return out

# 定义超参数
input_size = 3  # 特征数:温度、湿度、风速
hidden_size = 64
output_size = 3
num_layers = 1

model = WeatherLSTM(input_size, hidden_size, output_size, num_layers)
criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)

模型训练

import torch.optim as optim

num_epochs = 100
for epoch in range(num_epochs):
    model.train()
    optimizer.zero_grad()
    outputs = model(torch.Tensor(X_train))
    loss = criterion(outputs, torch.Tensor(y_train))
    loss.backward()
    optimizer.step()
    
    if (epoch+1) % 10 == 0:
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

4. 预测与可视化分析

模型训练完成后,我们对测试集进行预测,用图形展示给大家~

预测结果

model.eval()
with torch.no_grad():
    predicted = model(torch.Tensor(X_test)).detach().numpy()
    predicted = scaler.inverse_transform(predicted)
    actual = scaler.inverse_transform(y_test)

# 转为DataFrame便于可视化
predicted_df = pd.DataFrame(predicted, columns=['temperature''humidity' 'wind_speed'])
actual_df = pd.DataFrame(actual, columns=['temperature''humidity''wind_speed'])

可视化分析

1. 温度预测结果:展示LSTM对温度的预测与实际值的比较。

2. 湿度预测结果:展示LSTM对湿度的预测与实际值的差距。

3. 风速预测结果:分析风速的预测效果。

4. 多特征趋势对比:对比所有特征在不同时间段的预测效果。

colors = ['#1f77b4''#ff7f0e']  # 蓝色:实际值,橙色:预测值
fig, axes = plt.subplots(31, figsize=(1210))

# 标题和字体设置
fig.suptitle('Weather Prediction Using LSTM', fontsize=16, weight='bold')

# 温度预测图
axes[0].plot(actual_df['temperature'], color=colors[0], label='Actual Temperature', linewidth=1.5)
axes[0].plot(predicted_df['temperature'], color=colors[1], linestyle='--', label='Predicted Temperature', linewidth=1.5)
axes[0].set_title('Temperature Prediction', fontsize=14, weight='bold')
axes[0].set_ylabel('Temperature (°C)', fontsize=12)
axes[0].legend(fontsize=10, loc='upper right')
axes[0].grid(alpha=0.3)

# 湿度预测图
axes[1].plot(actual_df['humidity'], color=colors[0], label='Actual Humidity', linewidth=1.5)
axes[1].plot(predicted_df['humidity'], color=colors[1], linestyle='--', label='Predicted Humidity', linewidth=1.5)
axes[1].set_title('Humidity Prediction', fontsize=14, weight='bold')
axes[1].set_ylabel('Humidity (%)', fontsize=12)
axes[1].legend(fontsize=10, loc='upper right')
axes[1].grid(alpha=0.3)

# 风速预测图
axes[2].plot(actual_df['wind_speed'], color=colors[0], label= 'Actual Wind Speed', linewidth=1.5)
axes[2].plot(predicted_df['wind_speed'], color=colors[1], linestyle='--', label='Predicted Wind Speed', linewidth=1.5)
axes[2].set_title('Wind Speed Prediction', fontsize=14, weight='bold')
axes[2].set_ylabel('Wind Speed (km/h)', fontsize=12)
axes[2].set_xlabel('Days', fontsize=12)
axes[2].legend(fontsize=10, loc='upper right')
axes[2].grid(alpha=0.3)

# 调整布局并显示
plt.tight_layout(rect=[0010.96])
plt.show()

我们使用了三个基本的折线图来对比LSTM模型在温度、湿度和风速预测方面的实际值和预测值。

温度预测的图形展示了LSTM模型对温度时间序列的捕捉能力。如果预测线能够紧密跟随实际温度曲线,说明模型能较好地捕捉温度的变化趋势。如果偏差较大,则需要调整模型复杂度或序列长度。

湿度预测的图形反映了LSTM对湿度时序变化的拟合效果。通常湿度变化较温度更不规则,因此湿度预测的误差可能更大,这提示我们可以考虑将湿度数据的平滑度处理,减少噪声。

风速图形反映了模型在风速数据上的预测效果。如果预测值偏差较大,可能说明风速的时序特征在当前的LSTM结构下未能得到充分捕捉,这时可以尝试增加风速数据的周期性特征,或调整输入序列长度。

5. 模型优化与调参建议

LSTM模型的性能在很大程度上依赖于参数设置和数据处理。下面论述一些比较重要的方面~

模型优化方向

1. 隐藏层数量和单元数优化

在 LSTM 中,隐藏层数量和每一层的隐藏单元数会影响模型的复杂度。通常情况下,较高的隐藏单元数和更多的LSTM层能够捕捉更复杂的时序特征,但过多的隐藏单元数和层数可能导致过拟合。

因此,我们可以尝试:

  • 单层LSTM vs 多层LSTM:从1层开始,如果模型效果不理想可以尝试增加到2-3层,逐渐观察效果的提升。
  • 单元数(Hidden Units):一般来说,选择16、32、64、128等值逐步增加,同时注意训练时间和过拟合的风险。

2. 学习率调整

学习率是优化器的重要参数之一,它决定了每次参数更新的步长。在训练过程中,可以使用学习率衰减策略,即随着训练轮次增加逐步减小学习率,帮助模型在接近最优点时更加平稳地收敛。常见策略:

  • Step Decay:每隔一定轮次将学习率缩小至原来的某个比例(如0.1倍)。
  • Exponential Decay:每次更新时将学习率按指数函数递减。
scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=30, gamma=0.1)
for epoch in range(num_epochs):
    # 模型训练代码...
    optimizer.step()
    scheduler.step()  # 调整学习率

3. 正则化手段

LSTM 模型可能会因数据有限而出现过拟合问题,适当的正则化手段可以提高模型的泛化能力:

  • Dropout:LSTM层中添加dropout可以有效防止过拟合。
  • L2正则化:在损失函数中添加L2惩罚项,限制权重的过大波动。
self.lstm = nn.LSTM(input_size, hidden_size, num_layers, batch_first=True, dropout=0.2)

4. 批量大小调整

批量大小决定了每次训练中使用的数据量,合适的批量大小(如32、64、128等)在计算效率和泛化性能上会有较好的平衡。对于时间序列数据,一般来说,较小的批量可以帮助捕捉更多的特征信息。

调参流程

在优化模型时,系统化的调参流程能够提高效率并找到最佳参数组合。

推荐的几个调参方式:

1. 确定基本模型结构:先从简单的LSTM结构入手,比如1层LSTM,16个隐藏单元,学习率0.01。

2. 逐步增加复杂度:根据模型初始结果,逐渐增加隐藏单元数或层数,并观察训练集和测试集的误差变化。

3. 优化学习率和批量大小:通过实验不同的学习率(0.01,0.001等)和批量大小,找到误差最小且收敛速度较快的组合。

4. 添加正则化项:当模型效果较好但存在过拟合时,添加正则化手段(如Dropout)并调整比例(如0.1、0.2等)。

5. 迭代实验:通过实验记录并分析结果曲线,继续微调参数,直至得到满意的结果。

最后

咱们这次实验,通过LSTM模型来预测未来一周的天气变化,涵盖了数据预处理、模型构建、训练、预测和结果分析等多个环节。通过优化模型参数,我们实现了对温度、湿度和风速等气象变量的预测,在图形中得到了直观展示。

未来的改进方向,大家可以考虑下面几点:

1. 集成模型:可以尝试使用多模型集成方法(如LSTM + GRU,LSTM + CNN)进一步提高模型的预测性能。

2. 多特征工程:引入更多气象数据(如气压、降水量等),并考虑时间因素(如季节性)来丰富输入特征。

3. 多步预测:通过多步预测来实现对更长期的天气预测。

4. 动态序列长度:针对不同气象变量优化序列长度,找到每个变量的最佳时间窗口。

以上内容,希望可以帮助大家理解LSTM模型在预测问题上的有效性和可行性。

最后

大家有问题可以直接在评论区留言即可~

喜欢本文的朋友可收藏、点赞、转发起来!

往期精彩回顾




  • 交流群

请备注:”昵称-学校/公司-研究方向“,例如:”张小明-浙大-CV“加群。

也可以加入机器学习交流qq群772479961


Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/175980
 
41 次点击