基于卷积神经网络-门控循环单元的时间序列预测 CNN-GRU 基于MATLAB环境 替换自己的...
基于卷积神经网络-门控循环单元的时间序列预测 CNN-GRU 基于MATLAB环境 替换自己的数据即可 数据回归预测评价指标为RMSE R2 MAE MBE
最近在捣鼓时间序列预测的时候试了把CNN和GRU组队干活,发现这俩组合拳效果还挺有意思。直接把一维CNN当特征提取器,后面接GRU捕捉时序依赖,在MATLAB里折腾了几个数据集发现预测效果稳得一批。今天就把这个炼丹过程记录一下,附上能直接跑的代码框架。
先甩个模型结构图镇楼:
!CNN-GRU结构示意图
基于卷积神经网络-门控循环单元的时间序列预测 CNN-GRU 基于MATLAB环境 替换自己的数据即可 数据回归预测评价指标为RMSE R2 MAE MBE
其实核心就两句话:CNN负责从时间窗口里抠局部特征,GRU拿着这些特征继续琢磨时间规律。这种结构对既有空间模式又有时间依赖的数据特别管用,比如电力负荷、股票走势这种磨人的小妖精。
上硬货前先准备好数据。假设你有个N×M的矩阵,行是时间点,列是特征(单变量预测就一列)。重点是要构造时间窗口,像这样:
% 假设原始数据是data向量 lookback = 24; % 时间窗口长度 [X, Y] = createTimeSeriesData(data, lookback); % 自己实现的滑动窗口函数 function [features, targets] = createTimeSeriesData(data, lookback) num_samples = length(data) - lookback; features = zeros(num_samples, lookback, 1); % 保持通道数 targets = zeros(num_samples, 1); for i = 1:num_samples features(i,:,:) = data(i:i+lookback-1); targets(i) = data(i+lookback); end end这里要注意归一化!别头铁直接用原始数据,建议用mapminmax把数据压到[-1,1]之间,不然训练时梯度能给你整出骚操作。
模型搭建才是重头戏,直接上layer大法:
layers = [ sequenceInputLayer(1) % 单变量输入 convolution1dLayer(3, 16, 'Padding','same') % 3点卷积核 batchNormalizationLayer reluLayer maxPooling1dLayer(2, 'Stride',2) gruLayer(32, 'OutputMode','sequence') flattenLayer fullyConnectedLayer(1) regressionLayer];这里有几个坑要注意:
- 卷积核别整太大,时间序列不像图像需要大感受野
- GRU层要设OutputMode为sequence才能把完整序列传给后面
- 最后那个flatten是必须的,不然全连接层接不上GRU的输出
训练参数设置直接抄这个:
options = trainingOptions('adam', ... 'MaxEpochs', 100, ... 'MiniBatchSize', 64, ... 'InitialLearnRate', 0.001, ... 'LearnRateSchedule','piecewise', ... 'LearnRateDropPeriod', 30, ... 'Verbose', 0);实测发现对于多数时间序列数据,初始学习率设1e-3刚刚好。如果loss曲线抽风,可以试试梯度裁剪:
options.GradientThreshold = 1; % 防梯度爆炸预测结果评价不能只看RMSE,四个指标打包带走:
pred = predict(net, XTest); pred = postprocess(pred); % 反归一化 rmse = sqrt(mean((YTest - pred).^2)); mae = mean(abs(YTest - pred)); mbe = mean(YTest - pred); r2 = 1 - sum((YTest - pred).^2)/sum((YTest - mean(YTest)).^2);这里注意MBE(平均偏差)能看出模型是习惯性高估还是低估,比如能源预测中负的MBE说明预测值偏保守。
最后说下实际应用时的玄学调参:
- 时间窗口长度建议取数据周期的整数倍(比如小时数据取24的倍数)
- GRU层节点数别超过特征数量的10倍
- 在池化层后可以加dropout防过拟合,但别超过0.3
- 训练时盯着验证集loss,连续5个epoch不降就直接早停
完整代码骨架已放在GitHub(假装有链接),替换自己的数据时记得检查维度匹配。遇到维度报错大概率是输入数据的通道数没设置对,特别是从CSV导入时别漏了reshape操作。
