手把手教你用Keras搭建Seq2Seq LSTM模型:以航空公司乘客数据预测为例

张开发
2026/4/17 20:02:16 15 分钟阅读

分享文章

手把手教你用Keras搭建Seq2Seq LSTM模型:以航空公司乘客数据预测为例
从零构建Seq2Seq LSTM模型航空乘客预测的工程实践当我们需要预测未来三个月航空公司的乘客数量时传统的时间序列分析方法往往捉襟见肘。这正是Seq2Seq LSTM模型大显身手的场景——它能够捕捉长期依赖关系实现端到端的多步预测。不同于简单的单步预测模型Seq2Seq结构通过编码器-解码器框架将输入序列编码为固定长度的上下文向量再解码为目标序列这种架构特别适合解决多输入多输出的时序预测问题。1. 理解Seq2Seq架构的核心组件Seq2Seq模型由两大核心部分组成编码器(Encoder)和解码器(Decoder)。编码器负责将输入序列压缩为一个固定维度的上下文向量(context vector)这个向量理论上包含了输入序列的所有信息解码器则根据这个上下文向量逐步生成输出序列。在Keras中实现这一架构时我们需要特别关注几个关键层LSTM层作为编码器和解码器的基础LSTM能够有效捕捉时间序列中的长期依赖关系。设置return_stateTrue可以获取LSTM的隐藏状态和细胞状态这些状态将作为解码器的初始状态。RepeatVector层这是连接编码器和解码器的桥梁。由于解码器需要逐步生成多个时间步的输出RepeatVector将编码器的最后一个隐藏状态重复n次n为预测步长为解码器提供统一的初始输入。TimeDistributed层包装在普通的Dense层外面使其能够处理序列数据。对于每个时间步的输出都应用相同的全连接层确保输出序列的每个时间步都经过相同的变换。实际工程中常见的误区是忽略了状态传递的重要性。编码器的最终状态必须正确传递给解码器作为初始状态否则模型将失去对输入序列的记忆能力。2. 数据准备与特征工程航空乘客数据集是时间序列预测的经典案例包含1949年至1960年每月国际航空乘客数量。高质量的数据准备是模型成功的前提。2.1 数据加载与预处理import pandas as pd from sklearn.preprocessing import MinMaxScaler # 加载数据 data pd.read_csv(airline-passengers.csv) data[Month] pd.to_datetime(data[Month]) data.set_index(Month, inplaceTrue) # 划分训练集和测试集 train_size int(len(data) * 0.8) train_data data[:train_size] test_data data[train_size:] # 归一化处理 scaler MinMaxScaler() train_scaled scaler.fit_transform(train_data) test_scaled scaler.transform(test_data)提示时间序列数据必须按时间顺序划分训练集和测试集随机划分会破坏时间依赖性。2.2 构造监督学习格式Seq2Seq模型需要将时间序列转换为监督学习问题。我们需要定义滑动窗口的大小将过去N个月的乘客数量作为输入预测未来M个月的数值。import numpy as np def create_dataset(series, n_past, n_future): X, y [], [] for i in range(len(series)-n_past-n_future1): X.append(series[i:(in_past)]) y.append(series[(in_past):(in_pastn_future)]) return np.array(X), np.array(y) n_past 12 # 使用过去12个月的数据 n_future 3 # 预测未来3个月 n_features 1 # 单变量时间序列 X_train, y_train create_dataset(train_scaled, n_past, n_future) X_test, y_test create_dataset(test_scaled, n_past, n_future) # 调整形状为LSTM需要的格式(样本数, 时间步长, 特征数) X_train X_train.reshape((X_train.shape[0], n_past, n_features)) y_train y_train.reshape((y_train.shape[0], n_future, n_features)) X_test X_test.reshape((X_test.shape[0], n_past, n_features)) y_test y_test.reshape((y_test.shape[0], n_future, n_features))3. 构建Seq2Seq模型架构现在进入核心环节——用Keras构建完整的编码器-解码器结构。我们将采用函数式API因为它提供了更大的灵活性来定义复杂模型。3.1 编码器部分实现编码器接收形状为(n_past, n_features)的输入序列通过LSTM层提取特征并输出最终的状态。from tensorflow.keras.layers import Input, LSTM from tensorflow.keras.models import Model # 编码器 encoder_inputs Input(shape(n_past, n_features)) encoder_lstm LSTM(128, return_stateTrue) encoder_outputs, state_h, state_c encoder_lstm(encoder_inputs) # 保留状态用于解码器 encoder_states [state_h, state_c]3.2 解码器部分实现解码器使用编码器的最终状态作为初始状态并通过RepeatVector和TimeDistributed层生成多步预测。from tensorflow.keras.layers import RepeatVector, TimeDistributed, Dense # 解码器 decoder_inputs RepeatVector(n_future)(encoder_outputs) decoder_lstm LSTM(128, return_sequencesTrue) decoder_outputs decoder_lstm(decoder_inputs, initial_stateencoder_states) decoder_dense TimeDistributed(Dense(n_features)) decoder_outputs decoder_dense(decoder_outputs) # 完整模型 model Model(encoder_inputs, decoder_outputs)3.3 模型编译与训练选择合适的损失函数和优化器对模型性能至关重要。对于时间序列预测Huber损失是一个稳健的选择它对异常值不那么敏感。from tensorflow.keras.optimizers import Adam from tensorflow.keras.losses import Huber model.compile(optimizerAdam(learning_rate0.001), lossHuber(), metrics[mae]) history model.fit(X_train, y_train, epochs100, batch_size16, validation_data(X_test, y_test), verbose1)4. 模型评估与预测技巧训练完成后我们需要系统地评估模型性能并掌握一些实用的预测技巧。4.1 预测结果反归一化由于我们对数据进行了归一化预测结果也需要反归一化才能得到实际的乘客数量。# 在测试集上进行预测 predictions model.predict(X_test) # 反归一化 predictions_actual scaler.inverse_transform(predictions.reshape(-1, 1)) y_test_actual scaler.inverse_transform(y_test.reshape(-1, 1))4.2 多步预测可视化将预测结果与真实值对比可视化可以直观评估模型性能。import matplotlib.pyplot as plt plt.figure(figsize(12, 6)) plt.plot(y_test_actual, labelActual) plt.plot(predictions_actual, labelPredicted) plt.title(Airline Passengers: Actual vs Predicted) plt.xlabel(Time Steps) plt.ylabel(Passenger Count) plt.legend() plt.show()4.3 模型性能指标除了可视化我们还需要量化指标来评估模型指标公式说明MAE$\frac{1}{n}\sum_{i1}^ny_i - \hat{y}_iRMSE$\sqrt{\frac{1}{n}\sum_{i1}^n (y_i - \hat{y}_i)^2}$均方根误差MAPE$\frac{100%}{n}\sum_{i1}^n \left\frac{y_i - \hat{y}_i}{y_i}\right计算这些指标的Python实现from sklearn.metrics import mean_absolute_error, mean_squared_error def mean_absolute_percentage_error(y_true, y_pred): return np.mean(np.abs((y_true - y_pred) / y_true)) * 100 mae mean_absolute_error(y_test_actual, predictions_actual) rmse np.sqrt(mean_squared_error(y_test_actual, predictions_actual)) mape mean_absolute_percentage_error(y_test_actual, predictions_actual) print(fMAE: {mae:.2f}) print(fRMSE: {rmse:.2f}) print(fMAPE: {mape:.2f}%)5. 高级技巧与模型优化基础模型构建完成后我们可以通过多种方式进一步提升预测性能。5.1 注意力机制增强传统的Seq2Seq模型依赖固定长度的上下文向量这可能成为信息瓶颈。引入注意力机制可以让解码器在生成每个时间步的输出时关注编码器不同时间步的隐藏状态。from tensorflow.keras.layers import Dot, Concatenate, Activation # 注意力层实现 def attention_block(encoder_outputs, decoder_outputs): score Dot(axes[2, 2])([decoder_outputs, encoder_outputs]) attention_weights Activation(softmax)(score) context_vector Dot(axes[2, 1])([attention_weights, encoder_outputs]) return context_vector # 修改解码器部分 context_vector attention_block(encoder_outputs, decoder_outputs) decoder_combined_context Concatenate(axis-1)([decoder_outputs, context_vector]) decoder_outputs TimeDistributed(Dense(n_features))(decoder_combined_context)5.2 超参数调优模型性能很大程度上取决于超参数的选择。我们可以使用Keras Tuner来自动搜索最佳超参数组合。import keras_tuner as kt def build_model(hp): # 可调超参数 lstm_units hp.Int(lstm_units, min_value64, max_value256, step64) learning_rate hp.Choice(learning_rate, values[1e-2, 1e-3, 1e-4]) # 模型构建 inputs Input(shape(n_past, n_features)) encoder_lstm LSTM(lstm_units, return_stateTrue) encoder_outputs, state_h, state_c encoder_lstm(inputs) decoder_inputs RepeatVector(n_future)(encoder_outputs) decoder_lstm LSTM(lstm_units, return_sequencesTrue) decoder_outputs decoder_lstm(decoder_inputs, initial_state[state_h, state_c]) outputs TimeDistributed(Dense(n_features))(decoder_outputs) model Model(inputs, outputs) model.compile(optimizerAdam(learning_ratelearning_rate), lossHuber(), metrics[mae]) return model tuner kt.RandomSearch( build_model, objectiveval_loss, max_trials10, executions_per_trial2, directorytuning, project_nameairline_passengers ) tuner.search(X_train, y_train, epochs50, validation_data(X_test, y_test), verbose1)5.3 模型集成与鲁棒性提升单一模型的预测可能不够稳定我们可以训练多个Seq2Seq模型并集成它们的预测结果。from tensorflow.keras.wrappers.scikit_learn import KerasRegressor from sklearn.ensemble import VotingRegressor # 创建多个模型变体 def create_seq2seq_model(): inputs Input(shape(n_past, n_features)) encoder_lstm LSTM(128, return_stateTrue) encoder_outputs, state_h, state_c encoder_lstm(inputs) decoder_inputs RepeatVector(n_future)(encoder_outputs) decoder_lstm LSTM(128, return_sequencesTrue) decoder_outputs decoder_lstm(decoder_inputs, initial_state[state_h, state_c]) outputs TimeDistributed(Dense(n_features))(decoder_outputs) model Model(inputs, outputs) model.compile(optimizerAdam(learning_rate0.001), lossHuber(), metrics[mae]) return model # 创建集成模型 models [(model1, KerasRegressor(build_fncreate_seq2seq_model, epochs100, batch_size16, verbose0)), (model2, KerasRegressor(build_fncreate_seq2seq_model, epochs100, batch_size16, verbose0)), (model3, KerasRegressor(build_fncreate_seq2seq_model, epochs100, batch_size16, verbose0))] ensemble VotingRegressor(models) ensemble.fit(X_train.reshape(X_train.shape[0], -1), y_train.reshape(y_train.shape[0], -1))6. 生产环境部署考量当模型开发完成后我们需要考虑如何将其部署到生产环境中实现实时预测。6.1 模型序列化与加载# 保存模型 model.save(seq2seq_airline.h5) # 加载模型 from tensorflow.keras.models import load_model loaded_model load_model(seq2seq_airline.h5)6.2 构建预测API使用Flask可以快速构建一个预测API服务from flask import Flask, request, jsonify import numpy as np app Flask(__name__) model load_model(seq2seq_airline.h5) app.route(/predict, methods[POST]) def predict(): data request.json[data] scaled_data scaler.transform(np.array(data).reshape(-1, 1)) X scaled_data[-n_past:].reshape(1, n_past, n_features) prediction model.predict(X) prediction_actual scaler.inverse_transform(prediction.reshape(-1, 1)) return jsonify({prediction: prediction_actual.flatten().tolist()}) if __name__ __main__: app.run(host0.0.0.0, port5000)6.3 持续监控与再训练生产环境中模型性能会随着时间推移而下降需要建立监控和再训练机制记录预测结果和实际值的偏差设置性能阈值当指标超过阈值时触发再训练实现自动化数据管道定期用新数据重新训练模型采用影子部署(Shadow Deployment)测试新模型不影响生产流量

更多文章