MATLAB深度学习时间序列预测:换数据集后预测结果异常求助
我来帮你分析这个问题,预测结果变成直线是时间序列深度学习中很常见的问题,咱们一步步拆解原因和解决办法:
问题背景
我按照MathWorks官网的「基于深度学习的时间序列预测」示例实现代码,原示例使用自带数据集输出正常(对应效果:
),但替换为自定义Excel数据集后,预测结果变成了一条直线(对应效果:
)。我怀疑是算法参数需要调整,但不知道具体如何操作,所用MATLAB代码如下:
%% Load Data %data = chickenpox_dataset; %data = [data{:}]; data = xlsread('data.xlsx'); data = data'; %% Divide Data: Training and Testing numTimeStepsTrain = floor(0.7*numel(data)); XTrain = data(1:numTimeStepsTrain); YTrain = data(2:numTimeStepsTrain+1); XTest = data(numTimeStepsTrain+1:end-1); YTest = data(numTimeStepsTrain+2:end); %% Standardize Data mu = mean(XTrain); sig = std(XTrain); XTrain = (XTrain - mu) / sig; YTrain = (YTrain - mu) / sig; XTest = (XTest - mu) / sig; %% Define LSTM Network inputSize = 1; numResponses = 1; numHiddenUnits = 500; layers = [ ... sequenceInputLayer(inputSize) lstmLayer(numHiddenUnits) fullyConnectedLayer(numResponses) regressionLayer]; %% Training Options opts = trainingOptions('adam', ... 'MaxEpochs',500, ... 'GradientThreshold',1, ... 'InitialLearnRate',0.005, ... 'LearnRateSchedule','piecewise', ... 'LearnRateDropPeriod',125, ... 'LearnRateDropFactor',0.2, ... 'Verbose',0, ... 'Plots','training-progress'); %% Train Network net = trainNetwork(XTrain,YTrain,layers,opts); %% Forecast Future Time Steps net = predictAndUpdateState(net,XTrain); [net,YPred] = predictAndUpdateState(net,YTrain(end)); numTimeStepsTest = numel(XTest); for i = 2:numTimeStepsTest [net,YPred(1,i)] = predictAndUpdateState(net,YPred(i-1)); end %% Unstandardize the predictions using mu and sig calculated earlier. YPred = sig*YPred + mu; %% RMSE and MAE Calculation rmse = sqrt(mean((YPred-YTest).^2)) MAE = mae(YPred-YTest) %% Plot results figure plot(data(1:numTimeStepsTrain)) hold on idx = numTimeStepsTrain:(numTimeStepsTrain+numTimeStepsTest); plot(idx,[data(numTimeStepsTrain) YPred],'.-') hold off xlabel("Month") ylabel("Cases") title("Forecast") legend(["Observed" "Forecast"]) %% Compare the forecasted values with the test data figure subplot(2,1,1) plot(YTest) hold on plot(YPred,'.-') hold off legend(["Observed" "Forecast"]) ylabel("Cases") title("Forecast") subplot(2,1,2) stem(YPred - YTest) xlabel("Month") ylabel("Error") title("RMSE = " + rmse)
异常原因分析
预测结果呈直线通常意味着模型完全无法学习到时间序列的时序依赖关系,常见诱因包括以下几点:
1. 数据预处理与序列构造问题
- 数据分布不匹配:自定义数据集的统计特性(比如趋势、周期、波动幅度)和原示例的水痘数据集差异极大,简单的Z-score标准化可能不足以让模型捕捉有效特征。如果你的数据存在明显的上升/下降趋势,直接标准化会抹平这种关键的时序信息。
- 单步输入窗口不足:当前代码用
t时刻的数据预测t+1时刻,只给了模型一个时间步的上下文,对于有长期依赖的序列来说,这点信息完全不够支撑模型学习规律。
2. 模型结构与参数不合理
- LSTM隐藏单元过载:你设置了
numHiddenUnits = 500,这个数量对于大多数小规模自定义时间序列来说太大了——模型会过度拟合训练数据中的噪声,反而在测试时无法泛化,最终只能输出一个接近训练集均值的固定值(也就是你看到的直线)。 - 训练策略失当:
- 初始学习率
0.005偏高,容易导致模型训练时权重震荡,无法收敛到有效的参数组合。 - 500轮的迭代次数过多,尤其是当训练数据量较小时,模型早就过拟合了,后续训练只是在优化噪声。
- 学习率下降的周期和幅度设置不合理,125轮就降到原来的20%,可能导致后期模型提前停止学习。
- 初始学习率
3. 递归预测的误差累积
当前代码用前一步的预测结果作为下一步的输入(递归多步预测),这种方式的误差会不断累积。如果模型本身对单步预测的准确性就不高,几轮预测后误差会放大到让模型只能输出一个稳定的均值。
参数与方案调优建议
一、先从数据预处理和序列构造入手
- 改用多步输入窗口:给模型提供更多上下文信息,比如用过去5个时刻的数据预测下一个时刻,修改代码如下:
% 设置输入窗口大小,比如5 windowSize = 5; % 构造训练集 XTrain = []; YTrain = []; for i = 1:numel(data)-windowSize XTrain = [XTrain; data(i:i+windowSize-1)]; YTrain = [YTrain; data(i+windowSize)]; end XTrain = XTrain'; % 转置为序列格式 YTrain = YTrain'; % 构造测试集同理 XTest = []; YTest = []; for i = numTimeStepsTrain+1:numel(data)-windowSize XTest = [XTest; data(i:i+windowSize-1)]; YTest = [YTest; data(i+windowSize)]; end XTest = XTest'; YTest = YTest'; % 记得修改输入层的inputSize为windowSize inputSize = windowSize; - 尝试趋势消除+标准化:如果数据有明显趋势,先做一阶差分消除趋势,再做标准化:
dataDiff = diff(data); % 一阶差分 % 后续用dataDiff来划分训练测试集,最后预测时再还原趋势
二、调整模型结构
- 缩小LSTM隐藏单元数量:从
32或64开始尝试,逐步增加直到验证集效果不再提升。比如先改成:numHiddenUnits = 32; - 尝试堆叠LSTM层:如果单一层不够,可以添加一层LSTM增强特征提取能力:
layers = [ ... sequenceInputLayer(inputSize) lstmLayer(32,'OutputMode','sequence') % 第一层输出完整序列 lstmLayer(32) % 第二层输出最后一个时刻的特征 fullyConnectedLayer(numResponses) regressionLayer];
三、优化训练策略
- 降低学习率并减少迭代次数:
opts = trainingOptions('adam', ... 'MaxEpochs',150, ... 'GradientThreshold',1, ... 'InitialLearnRate',0.001, ... 'LearnRateSchedule','piecewise', ... 'LearnRateDropPeriod',50, ... 'LearnRateDropFactor',0.5, ... 'Verbose',1, ... 'Plots','training-progress'); - 添加验证集监控过拟合:提前划分验证集,让模型在训练时监控验证集损失,防止过拟合:
% 划分验证集(比如从训练集中拿出20%) numTimeStepsVal = floor(0.2*numel(XTrain)); XValidation = XTrain(:,end-numTimeStepsVal+1:end); YValidation = YTrain(:,end-numTimeStepsVal+1:end); XTrain = XTrain(:,1:end-numTimeStepsVal); YTrain = YTrain(:,1:end-numTimeStepsVal); % 修改trainingOptions opts = trainingOptions('adam', ... 'MaxEpochs',150, ... 'GradientThreshold',1, ... 'InitialLearnRate',0.001, ... 'ValidationData',{XValidation,YValidation}, ... 'ValidationFrequency',10, ... 'Verbose',1, ... 'Plots','training-progress');
四、改进预测方式
- 混合预测减少误差累积:在滚动预测时,每隔几步用真实的测试集数据替换预测值作为输入,比如:
net = predictAndUpdateState(net,XTrain); YPred = []; % 前几步用真实数据输入,之后交替用预测和真实数据 for i = 1:numTimeStepsTest if mod(i,3) == 0 % 每3步用真实测试数据输入 [net, yPredStep] = predictAndUpdateState(net, XTest(:,i)); else if i == 1 [net, yPredStep] = predictAndUpdateState(net, YTrain(end)); else [net, yPredStep] = predictAndUpdateState(net, YPred(end)); end end YPred = [YPred, yPredStep]; end
内容的提问来源于stack exchange,提问作者Ahmad Namvar
相关产品推荐
相关产品推荐

