将这个类“%% 空间注意力层定义
classdef spatialAttentionLayer < nnet.layer.Layer
% 空间注意力层实现
properties (Learnable)
Conv % 卷积层用于生成注意力权重
end
methods
function layer = spatialAttentionLayer(name)
% 构造函数
layer.Name = name;
% 使用7x1卷积核(适应输入形状)
layer.Conv = convolution2dLayer([7 1], 1, 'Padding', 'same');
end
function Z = predict(layer, X)
% 前向传播
% X: 输入特征图 [H, W, C, N]
mean_pool = mean(X, 3); % 通道平均 [H, W, 1, N]
max_pool = max(X, [], 3); % 通道最大值 [H, W, 1, N]
concat = cat(3, mean_pool, max_pool); % 拼接特征 [H, W, 2, N]
% 生成空间注意力权重图
weights = sigmoid(layer.Conv.predict(concat)); % [H, W, 1, N]
% 应用注意力权重到所有通道
Z = X .* weights; % 广播乘法 [H, W, C, N]
end
end
end”以函数的形式融入下述代码“%% 主程序:端到端CNN回归建模
clc;
clear;
close all;
% ========== 步骤1: 数据准备 ==========
fprintf('正在加载和预处理数据...\n');
filename = 'C:/Users/lzy/Desktop/new1/daojumosun.xlsx';
data = xlsread(filename);
% 分离特征和目标
X = data(:, 1:7)'; % 7个特征,转置为7×N
Y = data(:, 8); % 目标变量
% 数据集划分 (80%训练, 20%测试)
rng(42); % 固定随机种子
num_samples = size(X, 2);
indices = randperm(num_samples);
train_ratio = 0.8;
train_num = round(train_ratio * num_samples);
train_idx = indices(1:train_num);
test_idx = indices(train_num+1:end);
XTrain = X(:, train_idx);
YTrain = Y(train_idx);
XTest = X(:, test_idx);
YTest = Y(test_idx);
% 数据归一化 (Z-score标准化)
[XTrain, mu, sigma] = zscore(XTrain, 0, 2); % 按行(特征)归一化
XTest = (XTest - mu) ./ sigma;
% 重塑为CNN输入格式: [特征数, 1, 1, 样本数]
XTrain = reshape(XTrain, [7, 1, 1, size(XTrain, 2)]);
XTest = reshape(XTest, [7, 1, 1, size(XTest, 2)]);
% ========== 步骤2: 构建带空间注意力的CNN网络 ==========
fprintf('构建带空间注意力的CNN网络...\n');
layers = [
imageInputLayer([7 1 1], 'Name', 'input') % 输入层
% 第一个卷积模块
convolution2dLayer([3 1], 64, 'Padding', 'same', 'Name', 'conv1')
batchNormalizationLayer('Name', 'bn1')
reluLayer('Name', 'relu1')
% 空间注意力模块1
spatialAttentionLayer('spatial_att1')
% 第二个卷积模块
convolution2dLayer([3 1], 128, 'Padding', 'same', 'Name', 'conv2')
batchNormalizationLayer('Name', 'bn2')
reluLayer('Name', 'relu2')
% 空间注意力模块2
spatialAttentionLayer('spatial_att2')
% 全局平均池化层
globalAveragePooling2dLayer('Name', 'globalPool')
% 全连接层和回归输出
fullyConnectedLayer(1, 'Name', 'fc')
regressionLayer('Name', 'output')
];
% 可视化网络架构
analyzeNetwork(layers);
% ========== 步骤3: 训练配置与训练网络 ==========
fprintf('开始训练网络...\n');
options = trainingOptions('adam', ...
'MaxEpochs', 100, ...
'MiniBatchSize', 32, ...
'InitialLearnRate', 0.001, ...
'LearnRateSchedule', 'piecewise', ...
'LearnRateDropFactor', 0.5, ...
'LearnRateDropPeriod', 30, ...
'Shuffle', 'every-epoch', ...
'ValidationData', {XTest, YTest}, ...
'ValidationFrequency', 30, ...
'Plots', 'training-progress', ... % 启用训练进度图
'Verbose', true);
% 训练网络
[net, trainInfo] = trainNetwork(XTrain, YTrain, layers, options);
% ========== 步骤4: 预测与评估 ==========
fprintf('进行预测和模型评估...\n');
% 测试集预测
YPred = predict(net, XTest);
% 计算评估指标
residuals = YPred - YTest;
mse = mean(residuals.^2);
rmse = sqrt(mse);
mae = mean(abs(residuals));
r2 = 1 - sum(residuals.^2) / sum((YTest - mean(YTest)).^2);
fprintf('模型评估指标:\n');
fprintf('均方误差(MSE): %.4f\n', mse);
fprintf('均方根误差(RMSE): %.4f\n', rmse);
fprintf('平均绝对误差(MAE): %.4f\n', mae);
fprintf('决定系数(R²): %.4f\n', r2);
% ========== 步骤5: 可视化分析 ==========
fprintf('生成可视化结果...\n');
% 1. 真实值与预测值对比图
figure('Name', '真实值 vs 预测值', 'NumberTitle', 'off', 'Position', [100, 100, 800, 400]);
plot(YTest, 'b-o', 'LineWidth', 1.5, 'MarkerSize', 6, 'MarkerFaceColor', 'b');
hold on;
plot(YPred, 'r-s', 'LineWidth', 1.5, 'MarkerSize', 6, 'MarkerFaceColor', 'r');
hold off;
title('真实值与预测值对比 (带空间注意力)', 'FontSize', 14);
xlabel('样本索引', 'FontSize', 12);
ylabel('目标值', 'FontSize', 12);
legend({'真实值', '预测值'}, 'Location', 'best');
grid on;
% 2. 训练过程损失曲线图
figure('Name', '训练损失曲线', 'NumberTitle', 'off', 'Position', [100, 100, 800, 400]);
plot(trainInfo.TrainingLoss, 'b-', 'LineWidth', 1.5);
hold on;
if isfield(trainInfo, 'ValidationLoss')
validLoss = trainInfo.ValidationLoss;
validLoss(isnan(validLoss)) = []; % 移除NaN值
plot(validLoss, 'r--', 'LineWidth', 1.5);
legend({'训练损失', '验证损失'}, 'Location', 'best');
else
legend({'训练损失'}, 'Location', 'best');
end
hold off;
title('训练过程损失曲线', 'FontSize', 14);
xlabel('迭代次数', 'FontSize', 12);
ylabel('损失值', 'FontSize', 12);
grid on;
% 3. 残差分析图
figure('Name', '残差分析', 'NumberTitle', 'off', 'Position', [100, 100, 800, 600]);
subplot(2,1,1);
plot(residuals, 'o', 'MarkerSize', 6, 'MarkerFaceColor', [0.3, 0.6, 0.9]);
title('残差分布图', 'FontSize', 14);
xlabel('样本索引', 'FontSize', 12);
ylabel('残差', 'FontSize', 12);
grid on;
refline(0, 0); % 添加参考线 y=0
subplot(2,1,2);
histogram(residuals, 20, 'FaceColor', [0.5, 0.8, 0.9], 'EdgeColor', 'k');
title('残差直方图', 'FontSize', 14);
xlabel('残差值', 'FontSize', 12);
ylabel('频数', 'FontSize', 12);
grid on;
% 4. 注意力权重可视化(新增)
try
% 提取注意力层
attLayer1 = net.Layers(5); % 第一个空间注意力层
attLayer2 = net.Layers(8); % 第二个空间注意力层
% 可视化第一个注意力层的权重
figure('Name', '空间注意力权重', 'NumberTitle', 'off');
subplot(1,2,1);
weights = extractdata(attLayer1.Conv.Weights);
bar(weights, 'FaceColor', [0.2, 0.6, 0.8]);
title('第一层空间注意力权重', 'FontSize', 12);
xlabel('特征索引', 'FontSize', 10);
ylabel('权重值', 'FontSize', 10);
grid on;
% 可视化第二个注意力层的权重
subplot(1,2,2);
weights = extractdata(attLayer2.Conv.Weights);
bar(weights, 'FaceColor', [0.8, 0.4, 0.2]);
title('第二层空间注意力权重', 'FontSize', 12);
xlabel('特征索引', 'FontSize', 10);
ylabel('权重值', 'FontSize', 10);
grid on;
catch
fprintf('注意力权重可视化需要额外处理,已跳过\n');
end
% 保存工作区变量
fprintf('保存模型和结果...\n');
save('CNN_Regression_Model.mat', 'net', 'mu', 'sigma', 'trainInfo', 'YPred', 'YTest');
fprintf('程序执行完成!\n');”
最新发布