该 MATLAB 代码实现了一个基于 CNN-GRU-Attention 时序和空间特征结合-融合注意力机制混合神经网络模型的风速预测。以下是对代码的简要分析:
一、主要功能
该代码用于风速时间序列预测,使用历史风速特征数据(18个特征,75天,每小时一个样本)训练一个深度学习模型,并预测未来24小时的风速值。
二、算法步骤
-
数据导入与预处理:
- 从Excel文件中读取特征数据和实际风速值。
- 将数据重塑为4-D格式(特征维度 × 时间步长 × 通道数 × 天数)。
- 转换为cell数组以便用于序列训练。
-
训练/测试集划分:
- 训练输入(XTrain):第1–73天的特征。
- 训练输出(YTrain):第2–74天的实际风速。
- 测试输入(XTest):第74天的特征。
- 测试输出(YTest):第75天的实际风速。
-
网络结构搭建(CNN-GRU-Attention):
- 输入层:接收18×24×1的序列。
- 卷积层(Conv2D):32个3×3卷积核,Padding=‘same’。
- 批归一化层(BatchNormalization)。
- ReLU激活层。
- 最大池化层(MaxPooling2D):3×3池化窗口。
- 展平层(Flatten)。
- GRU层:50个隐藏单元。
- 自注意力层(Self-Attention):1个头,50维。
- 全连接层(FullyConnected):输出24个节点(对应24小时预测)。
- 回归输出层(RegressionOutput)。
-
训练设置:
- 使用SGDM优化器。
- 最大训练轮数:300。
- 初始学习率:0.01(不衰减)。
- 训练环境:CPU。
- 每批次样本数:15。
- 序列长度:24。
-
训练与评估:
- 训练网络并绘制训练进度。
- 可视化卷积层的特征图。
- 对测试集进行预测,计算误差指标(SSE, MAE, MSE, RMSE, MAPE, R)。
- 绘制预测值与真实值对比图。
三、技术路线
- 数据处理:时间序列数据按天组织,每个样本为24小时。
- 模型架构:
- CNN用于提取局部空间特征。
- GRU用于捕捉时间依赖关系。
- Self-Attention机制增强关键时间步的表示。
- 训练策略:使用回归任务常用的均方误差(MSE)作为损失函数。
- 评估指标:多角度误差评估 + 相关性分析。
四、参数设定
参数 | 值/类型 | 说明 |
---|---|---|
优化器 | SGDM | 带动量的随机梯度下降 |
MaxEpochs | 300 | 最大训练轮数 |
LearnRate | 0.01 | 初始学习率 |
MiniBatchSize | 15 | 每批样本数 |
SequenceLength | 24 | 序列长度(小时) |
GRU单元数 | 50 | L层隐藏单元数 |
卷积核数量 | 32 | 卷积层输出通道数 |
注意力头数 | 1 | 自注意力机制头数 |
五、运行环境
- 软件环境:MATLAB(需安装 Deep Learning Toolbox)
- 硬件环境:CPU(代码中指定
ExecutionEnvironment
为'cpu'
) - 数据格式:Excel文件(需包含18行特征和1行实际值)
代码分享
CNN-GRU-Attention多变量多步预测超前24步
%% 清除内存、清除屏幕
clc
clear%% 导入特征数据、当天的风速数据
data = xlsread('特征序列及实际值.xlsx');
Features = data(1:18,:); %% 特征输入 :75天,每天24小时,每小时一个采样点,共计75*24=1800小时,18个特征数据
Wind_data = data(19,:); %% 实际值输出:75天,每天24小时,每小时一个采样点,共计75*24=1800小时的风速数据%% 数据信息%% 数据平铺为4-D
LP_Features = double(reshape(Features,18,24,1,75)); %% 特征数据格式为18*24*1*75,分别对应18特征24小时,75天
LP_WindData = double(reshape(Wind_data,24,1,1,75)); %% 实际数据格式为24*1*1*75 ,分别对应24小时,75天%% 格式转换为cell
NumDays = 75; %% 数据总天数为 75天
for i=1:NumDaysFeaturesData{1,i} = LP_Features(:,:,1,i);
endfor i=1:NumDaysRealData{1,i} = LP_WindData(:,:,1,i);
end%% 划分数据
XTrain = FeaturesData(:,1:73); %% 训练集输入为 1-73 天的特征
YTrain = RealData(:,2:74); %% 训练集输出为 2-74天 的实际值 XTest = cell2mat(FeaturesData(: , 74)); %% 测试集输入第 74 天的特征
Ytest = cell2mat(RealData(: , 75)); %% 测试集输出为第 75天 的实际值%% CNN-GRU-Attention网络搭建
layers = [sequenceInputLayer([18 24 1],"Name","sequence")convolution2dLayer([3 3],32,"Name","conv","Padding","same")batchNormalizationLayer("Name","batchnorm")reluLayer("Name","relu")maxPooling2dLayer([3 3],"Name","maxpool","Padding","same")flattenLayer("Name","flatten")gruLayer(50,"Name","gru")selfAttentionLayer(1,50,"Name","selfattention")fullyConnectedLayer(24,"Name","fc")regressionLayer("Name","regressionoutput")];%% 参数设置
options = trainingOptions('sgdm', ... % SGDM 梯度下降算法'MaxEpochs',300, ... % 最大训练次数 300'GradientThreshold',1,... % 渐变的正阈值 1'ExecutionEnvironment','cpu',... % 网络的执行环境 cpu'InitialLearnRate',0.01,... % 初始学习率 0.01'LearnRateSchedule','none',... % 训练期间降低整体学习率的方法 不降低'Shuffle','every-epoch',... % 每次训练打乱数据集'SequenceLength',24,... % 序列长度 24'Plots','training-progress',... % 画出训练曲线'MiniBatchSize',15,... % 训练批次大小 每次训练样本个数15'Verbose',0); % 有关训练进度的信息不打印到命令窗口中
analyzeNetwork(layers); % 分析网络结构
%% 训练网络
net = trainNetwork(XTrain,YTrain,layers,options);%% 绘制某层的特征图,实现特征可视化
%激活某一层
LayersNeed = activations(net,XTrain,'conv','OutputAs','channels');% flatten层的特征%% 画图
numNeed = 3 ; %按需要取几张特征图
for i = 1:numNeed
LayersFeature = reshape(cell2mat(LayersNeed(1,:)),18,24,32,[]); %根据analyzeNetwork分析结果,构造合适尺寸的特征图
axes1 = axes('Parent',figure);
hold(axes1,'on');
image(LayersFeature(:,:,i),'Parent',axes1,'CDataMapping','scaled');
colormap(hsv)
xlim([0, size(LayersFeature,2)]);% 限制坐标轴
ylim([0, size(LayersFeature,1)]);% 限制坐标轴
end%% 步骤5:测试与评估
YPredicted = net.predict(XTest); %% 计算误差
% 过程
error2 = YPredicted-Ytest; % 测试值和真实值的误差
[~,len]=size(Ytest); % len获取测试样本个数,数值等于testNum,用于求各指标平均值
SSE1=sum(error2.^2); % 误差平方和
MAE1=sum(abs(error2))/len; % 平均绝对误差
MSE1=error2*error2'/len; % 均方误差
RMSE1=MSE1^(1/2); % 均方根误差
MAPE1=mean(abs(error2./mean(Ytest))); % 平均百分比误差
r=corrcoef(Ytest,YPredicted); % corrcoef计算相关系数矩阵,包括自相关和互相关系数
R1=r(1,2); %% 绘图
figure
plot(Ytest,'m-*','LineWidth',2);
hold on
plot(YPredicted,'c-o','LineWidth',2);
legend('真实值','预测值');
xlabel('预测样本');
ylabel('预测结果');
string={'测试集预测结果对比';['MAPE=' num2str(MAPE1)]};
title(string)
grid