RNN(LSTM)预测全球婴幼儿人口数值严重失真问题求助
问题描述
我正在构建AI网络以预测全球大规模疫情,第一步是预测未来数年的相关因子数据。目前通过自定义函数AIcooker构建并保存模型,其中model4用于基于1950-2022年全球百余个国家的婴幼儿(0-4岁)人口数据(存储于0-4.csv)进行预测,但预测结果随时间推移严重失真(如出现-98千垓量级的错误值)。尝试过过度拟合、长时间训练(通过设置未定义的val_loss关闭EarlyStopping)均无效,其他数据集对应的模型运行正常,特寻求技术帮助。
代码片段
import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.preprocessing import MinMaxScaler from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, LSTM, Dropout import tensorflow as tf import tensorflow.keras as kr from keras.preprocessing.sequence import TimeseriesGenerator import math def AIcooker(name_of_the_pdf, number_of_epochs, vertical_length_of_set, horizontal_length_of_set, splitting_percentage, window_size, time_horizon, i_var): water = pd.read_csv( name_of_the_pdf, parse_dates = True, index_col = 'Date' ) water = water.drop('Date.1', axis = 1) warray = water.values water.replace([np.inf, -np.inf, np.nan], 0, inplace=True) nom = math.floor(vertical_length_of_set*splitting_percentage) train = water.iloc[:nom] test = water.iloc[nom:] scaler = MinMaxScaler() scaler.fit(train) scaler_train = scaler.transform(train) scaler_test = scaler.transform(test) n_input = window_size n_features = horizontal_length_of_set generator = TimeseriesGenerator(scaler_train, scaler_train, length = n_input, batch_size = 1) X, y = generator[0] X.shape model = kr.Sequential() model.add(kr.layers.Reshape((n_input, n_features))) model.add(LSTM(512, activation = 'relu', input_shape = (n_input, n_features))) model.add(Dense(512)) model.add(Dense(512)) model.add(Dense(512)) model.add(Dense(n_features)) model.compile(optimizer = 'adam', loss = 'mse') i = tf.keras.callbacks.EarlyStopping( monitor=i_var, patience=20, restore_best_weights=True, verbose = 1 ) model.fit(generator, epochs = number_of_epochs, callbacks = [i]) last_trained_batch = scaler_train[-n_input:] last_trained_batch = last_trained_batch.reshape((1, n_input, n_features)) c = model.predict(last_trained_batch) test_predictions = [] first_eval_batch = scaler_train[-n_input:] current_batch = first_eval_batch.reshape((1, n_input, n_features)) for i in range(time_horizon): # Iterate for the specified time horizon current_pred = model.predict(current_batch)[0] test_predictions.append(current_pred) current_batch = np.append(current_batch[:, 1:, :], [[current_pred]], axis=1) ui = scaler.inverse_transform(test_predictions) print(ui) return model, ui """ model1, ui1 = AIcooker('HI - HI.csv', 10000, 23, 130, 0.9, 8, 100, 'loss') model1.save('WaterQuality.keras') np.savetxt('WaterQualityResults.txt', ui1, fmt='%.18f') model2, ui2 = AIcooker('yy.csv', 10000, 30, 192, 0.8, 7, 100, 'loss') model2.save('PD.keras') np.savetxt('PDResults.txt', ui2, fmt='%.18f') model3, ui3 = AIcooker('34.csv', 3000, 22, 192, 0.8, 7, 100, 'loss') model3.save('P.keras') np.savetxt('PResults.txt', ui3, fmt='%.18f')""" '''model4, ui4 = AIcooker('0-4.csv', 5000, 71, 236, 0.8, 7, 100, 'val_loss') model4.save('0-4.keras') np.savetxt('0-4Results.txt', ui4, fmt='%.18f')''' model5, ui5 = AIcooker('6.csv', 5000, 7, 126, 0.8, 7, 100, 'loss') model5.save('0-0.keras') np.savetxt('0-0Results.txt', ui5, fmt='%.18f')
分析与解决方案
1. 数据预处理问题
人口数据不可能为负或存在无穷值,直接将NaN/inf替换为0会破坏数据分布,导致模型学习到错误的模式。
- 修改数据填充逻辑:对每个国家的人口序列用均值/中位数填充缺失值,而非统一填0;
- 先做数据校验:遍历
0-4.csv,找出异常值(如负数、远超合理范围的数值)并清理,确保输入数据符合人口数据的真实分布。
示例修改:
# 替换原有的replace逻辑 for col in water.columns: water[col] = water[col].replace([np.inf, -np.inf], np.nan) # 用中位数填充,避免均值受极端值影响 water[col] = water[col].fillna(water[col].median())
2. 模型结构与激活函数问题
- LSTM层默认激活函数是
tanh,使用relu容易导致梯度消失/爆炸,尤其在多变量长序列预测中; - 3层512单元的Dense层参数冗余过多,对于236个特征的预测任务,模型过于复杂,易出现不稳定的预测结果。
修改建议:
model = kr.Sequential() model.add(kr.layers.Reshape((n_input, n_features))) # LSTM改用tanh激活,加入Dropout抑制过拟合 model.add(LSTM(256, activation='tanh', input_shape=(n_input, n_features), return_sequences=False)) model.add(Dropout(0.2)) # 减少Dense层数和单元数 model.add(Dense(256)) model.add(Dropout(0.2)) model.add(Dense(128)) model.add(Dense(n_features)) model.compile(optimizer='adam', loss='mse')
3. 验证集与EarlyStopping配置错误
调用model4时传入i_var='val_loss',但训练时并未传入验证集数据,导致EarlyStopping无法监控验证损失,相当于无效配置,模型可能在训练中发散。
修改训练逻辑,添加验证集生成器:
# 生成训练和验证generator train_generator = TimeseriesGenerator(scaler_train, scaler_train, length=n_input, batch_size=1) val_generator = TimeseriesGenerator(scaler_test, scaler_test, length=n_input, batch_size=1) # 训练时传入validation_data model.fit(train_generator, epochs=number_of_epochs, callbacks=[i], validation_data=val_generator)
4. 多步预测的误差累积问题
当前递归预测逻辑中,每一步都用模型的预测结果作为下一步输入,误差会持续累积,尤其当特征数多(236个)时,微小误差会被放大。
优化方案:
- 改用直接多步预测:调整模型输出为
time_horizon * n_features,一次性预测未来所有时间步的数值; - 或采用混合预测:前几步用真实数据,后面用预测数据,减少误差累积。
5. 归一化逆变换校验
检查MinMaxScaler的min_和scale_属性,确认是否存在训练集中某些特征的取值范围远小于测试/预测场景,导致逆变换后出现极端值。可以改用StandardScaler,或者对每个特征单独做归一化处理。
内容的提问来源于stack exchange,提问作者Mufarrid Ansari
相关产品推荐
相关产品推荐

