基于keras的LSTM时间序列预测

详细代码见github: https://github.com/pjgao/lstm_helloworld/

1 简介

针对时间序列预测问题传统方法如ARIMA算法来拟合序列,综合考虑趋势、循环、季节等因素。
随着深度学习的飞速发展,基于RNN的方法在时间序列中的应用越来越广泛。
本文使用air passenger航空公司乘客数据集,来测试LSTM在时间序列中的预测:

2 问题

这里我们使用前n个月的乘客量来预测下一个月的乘客量

3 数据分析

航空公司乘客数据集为1949年1月到1960年12月每月乘客的数量
乘客数据
从图中可以看出该序列有一定的周期性。
这里写图片描述

4 数据处理

这里一定要注意,需要先对数据进行归一化处理,否则结果惨不忍睹!
这里我们使用sklearn中的MinMaxScaler对数据进行归一化处理。这里使用过去10个月的数据来推断下一个月的数据,因此infer_seq_length设置为10

#将数据归一化
scaler_minmax = MinMaxScaler()
data = scaler_minmax.fit_transform(df)
infer_seq_length = 10#用于推断的历史序列长度

d = []
for i in range(data.shape[0]-infer_seq_length):
    d.append(data[i:i+infer_seq_length+1].tolist())
d = np.array(d)

d的shape为(134, 11, 1),前10维为已知序列,最后一维为预测值。
数据d

5 lstm模型

这里使用了两层lstm来搭建模型,lstm不宜太多。

  • 因为有两层,所以第一层lstm的return_sequences要设置为True,否则两层不会连接到一起。
  • 因为我们预测的只有乘客数量一个变量,因此第一层lstm的输入shape为1
  • lstm完了之后一般会接一个全连接层Dense用于输出,这里Dense的激活函数为Linear
def create_model():
    model = Sequential()
    #输入数据的shape为(n_samples, timestamps, features)
    #隐藏层设置为256, input_shape元组第二个参数1意指features为1
    #下面还有个lstm,故return_sequences设置为True
    model.add(LSTM(units=256,input_shape=(None,1),return_sequences=True))
    model.add(LSTM(units=256))
    #后接全连接层,直接输出单个值,故units为1
    model.add(Dense(units=1))
    model.add(Activation('linear'))
    model.compile(loss='mse',optimizer='adam')
    return model

这里写图片描述

6 训练模型

我们在选择前面一些天的数据作为训练集,在训练集上训练模型。

model.fit(X_train, y_train, batch_size=20,epochs=100,validation_split=0.1)

训练过程:
这里写图片描述

7 预测结果

红色虚线是LSTM在整个序列上的预测结果:
这里写图片描述

放大后观测部分:
这里写图片描述

### LSTM 超参数设置及调优方法 #### 1. 创建 BiLSTM 模型及其初始配置 构建双向长短时记忆网络 (BiLSTM) 需要定义一系列基础参数,例如输入维度、隐藏单元数量以及数等。以下是基于引用中的描述创建模型的核心要素[^1]: - **输入尺寸**: 定义特征向量的大小。 - **隐藏单位数**: 控制神经元的数量,通常需要通过实验确定。 - **数**: 增加数可以提升复杂模式的学习能力,但也可能导致过拟合。 下面展示了一个简单的 BiLSTM 构建代码示例: ```python import torch.nn as nn class BiLSTMModel(nn.Module): def __init__(self, input_size, hidden_size, num_layers, output_size): super(BiLSTMModel, self).__init__() self.lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_size, num_layers=num_layers, batch_first=True, bidirectional=True) self.fc = nn.Linear(hidden_size * 2, output_size) def forward(self, x): lstm_out, _ = self.lstm(x) out = self.fc(lstm_out[:, -1, :]) return out ``` --- #### 2. 使用网格搜索进行超参数调整 网格搜索是一种穷举策略,在给定范围内测试所有可能的超参数组合,并记录每种情况下模型的表现。这种方法适用于较小规模的数据集或较少的超参数范围[^2]。 具体实现如下所示: ```python from sklearn.model_selection import GridSearchCV from keras.wrappers.scikit_learn import KerasClassifier def create_model(optimizer='adam'): model = Sequential() model.add(LSTM(50, activation='relu', input_shape=(n_timesteps, n_features))) model.add(Dense(1)) model.compile(loss='mean_squared_error', optimizer=optimizer) return model model = KerasClassifier(build_fn=create_model, verbose=0) param_grid = {'batch_size': [10, 20], 'epochs': [10, 50], 'optimizer': ['SGD', 'Adam']} grid_search = GridSearchCV(estimator=model, param_grid=param_grid, cv=3) grid_result = grid_search.fit(X_train, y_train) print(f"Best Parameters: {grid_result.best_params_}") ``` 尽管此方法简单直观,但它的时间成本较高,尤其是在高维空间中运行时。 --- #### 3. 利用贝叶斯优化加速寻找最优解 相比网格搜索,贝叶斯优化采用概率模型预测潜在更佳的超参数集合,从而减少不必要的计算开销。其核心在于平衡探索与开发之间的关系,即优先考虑那些最有可能改善现有结果的区域。 一种常见的工具是 `BayesianOptimization` 库,用于高效地执行此类任务: ```python from bayes_opt import BayesianOptimization from tensorflow.keras.optimizers import Adam def evaluate_lstm(lr, units): model = Sequential([ LSTM(int(units), activation='tanh', input_shape=(X_train.shape[1], X_train.shape[2])), Dense(1)]) opt = Adam(learning_rate=float(lr)) model.compile(loss="mse", optimizer=opt) history = model.fit(X_train, y_train, epochs=10, validation_data=(X_val, y_val), verbose=0) val_loss = min(history.history['val_loss']) del model return -val_loss pbounds = {"lr": (0.001, 0.01), "units": (32, 128)} optimizer = BayesianOptimization(evaluate_lstm, pbounds) optimizer.maximize(init_points=5, n_iter=20) best_params = optimizer.max["params"] print(best_params) ``` 上述脚本展示了如何动态调整学习率 (`lr`) 和隐含节点数目 (`units`) 来获得更高的验证精度。 --- #### 4. PyTorch 中的优化器策略 为了进一步增强 LSTM 性能,选择合适的优化算法至关重要。PyTorch 提供了多种内置选项,如 SGD、Adagrad 或 AdamW 等。此外还可以自定义梯度裁剪机制防止爆炸梯度现象发生[^3]。 以下是一段典型代码片段说明如何应用 AdamW 并加入 L2 正则项: ```python criterion = nn.MSELoss() optimizer = torch.optim.AdamW(model.parameters(), lr=0.001, weight_decay=1e-4) for epoch in range(num_epochs): for i, (inputs, labels) in enumerate(train_loader): outputs = model(inputs) loss = criterion(outputs, labels) optimizer.zero_grad() loss.backward() nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) # Gradient Clipping optimizer.step() ``` --- #### 5. 参数效率对比:Prefix-Tuning vs Adapter-Tuning 当涉及大规模 Transformer 结构下的微调操作时,prefix-tuning 方法表现出显著优势——仅需少量额外参数即可达到接近全量更新的效果。相比之下 adapter-tuning 尽管同样冻结原始权重矩阵,但由于引入较多中间变量反而增加了整体负担[^4]。 这表明对于资源受限环境而言 prefix-tuning 更具吸引力;然而实际选型还需综合考量目标领域特性等因素决定最终方案取舍。 ---
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值