【深度学习-第4篇】使用MATLAB快速实现CNN多变量回归预测

上一篇我们讲了使用CNN进行分类的MATLAB代码。

这一篇我们讲CNN的多变量回归预测。

是的,同样是傻瓜式的快速实现。

一、什么是多变量回归预测

多变量回归预测则是指同时考虑多个输入特征进行回归预测。举几个例子:

  1. 房价预测:给定一组房产的特征,如面积、卧室数量、浴室数量、地理位置等,预测房产的销售价格。
  2. 股票价格预测:使用历史股票价格、交易量、财务指标等信息,预测未来某个时间点的股票价格。
  3. 销售预测:基于历史销售数据、季节性、促销活动等信息,预测未来某个时间段的销售额。
  4. 能源需求预测:考虑天气条件、时间(如一天中的时间、一周中的哪一天、一年中的哪个月份等)、历史能源需求等因素,预测未来的能源需求。
  5. 疾病风险预测:根据患者的年龄、性别、生活习惯、基因信息等,预测患者罹患某种疾病的风险。

在许多实际问题中,我们通常需要考虑多个输入特征。虽然 CNN 最初是为图像分类问题设计的,但它也可以应用于回归预测问题。在这种情况下,CNN 的目标不再是预测输入图像的类别,而是预测一个连续的目标值。为此,我们可以将 CNN 的最后一层全连接层修改为输出一个单一的连续值,然后使用一个回归损失函数(如均方误差)来训练网络。

CNN 由于其强大的特征提取能力,特别适合处理这种多变量的回归预测问题。

这篇文章我们就以房价预测为例吧

二、一个简单的案例------波士顿房价预测

下面我们将演示如何使用 MATLAB 的深度学习工具箱实现一个卷积神经网络(CNN)来进行波士顿房价的多变量回归预测。我们将使用波士顿房价数据集来训练我们的模型,该数据集包含波士顿城郊区域的房屋的多个特性(如犯罪率、房间数量、教师学生比例等)和房价。如下图每组房价数据由13个相关属性(即13个指标变量),1个目标变量(房价)组成,总共有506组数据,即为506*14的数组。

房价数据

1. 数据预处理

首先,我们从 'housing.txt' 中读取数据。

代码将数据分割为训练集和测试集,其中70%的数据用于训练,30%的数据用于测试。训练和测试数据的划分是随机的,但是通过设置随机种子rng(1),我们保证每次运行代码时都能得到相同的分割。

%% 1.数据预处理
data = readmatrix('housing.txt');  %读取数据文件
rng(1);%设置随机种子

% 分割数据为训练集和测试集
trainRatio = 0.7; % 70% 用于训练,其余的用于测试
trainCount = floor(size(data, 1) * trainRatio);
trainData = data(1:trainCount, :);
testData = data(trainCount+1:end, :);

% 分割输入特征和目标变量
XTrain = trainData(:, 1:end-1)';
YTrain = trainData(:, end)';
XTest = testData(:, 1:end-1)';
YTest = testData(:, end)';

2. 数据归一化

归一化是一个很重要的步骤,它能使不同范围和单位的特征值在模型训练中有着相同的权重。注意使用训练集的参数(最大值、最小值)来归一化测试集,以保持数据的一致性。

这里采用的是mapminmax方法,是一种常用的归一化方法,将数据映射到[-1, 1]区间。在后续步骤中,预测出的结果需要反归一化回原始数据的范围,要保证使用正确的参数和方法。

%% 2. 数据归一化
method=@mapminmax;
[XTrainMap,inputps]=method(XTrain);
XTestMap=method('apply',XTest,inputps);
[YTrainMap,outputps]=method(YTrain);
YTestMap=method('apply',YTest,outputps);

3. 数据转换

在这里,我们将数据转换成 CNN 模型可以接受的格式。

在CNN网络中,需要输入的是四维数组,而我们演示数据是二维的(506*14)。

如果数据形状和 CNN 模型的输入层不匹配,会出现错误,因此这一步需要特别小心。

%% 3. 数据转换
XTrainMapD=reshape(XTrain,[size(XTrain,1),1,1,length(XTrain)]);%训练集输入
XTestMapD =reshape(XTest,  [size(XTest,1),1,1,length(XTest)]); %测试集输入

4. 构建 CNN 模型

在定义 CNN 模型时,要确保各层的参数如卷积核大小、步长等设置得当。不合适的参数可能会导致模型训练的效果不佳。关于CNN模型的理论讲解大家可以看一下我之前发的文章,讲的可以说比较详细了。

Mr.看海:【深度学习-第2篇】CNN卷积神经网络30分钟入门!足够通俗易懂了吧(图解)

看完上边的文章,相信大家就知道下边的参数该怎么设置了吧!(如果不知道可以继续往后看)

%% 4.构建 CNN 模型
% 创建层
layers = [
    imageInputLayer([size(XTrain, 1),1 1]) % 输入层
    convolution2dLayer([3,1],64,'Stride',1,'Padding',1) % 卷积层
    batchNormalizationLayer
    reluLayer %ReLU激活函数层
    fullyConnectedLayer(1) % 全连接层
    regressionLayer]; % 回归层

% 显示层信息
analyzeNetwork(layers)

5. 指定训练选项

%% 5.指定训练选项
options = trainingOptions('sgdm', ...%求解器,'sgdm'(默认) | 'rmsprop' | 'adam'
    'ExecutionEnvironment','auto', ...
    'GradientThreshold',1, ...  %梯度极限
    'MaxEpochs',100, ...%最大迭代次数
    'InitialLearnRate', 0.03, ...%初始化学习速率
    'ValidationFrequency',10, ...%验证频率,即每间隔多少次迭代进行一次验证
    'MiniBatchSize',128, ...
    'LearnRateSchedule','piecewise', ...%是否在一定迭代次数后学习速率下降
    'LearnRateDropFactor',0.9, ...%学习速率下降因子
    'LearnRateDropPeriod',10, ...
    'SequenceLength','longest', ...
    'Shuffle','never', ...
    'ValidationData',{XTestMapD,YTestMap'},...
    'Verbose',true, ...
    'Plots','training-progress');%显示训练过程

% 训练模型
net = trainNetwork(XTrainMapD,YTrainMap',layers,options);

这段代码是使用 MATLAB 的深度学习框架来配置神经网络训练的参数。它创建了一个名为 options 的训练选项对象,这个对象包含了一系列用于训练神经网络模型的参数设置。

这些参数将会影响神经网络训练的效率和结果。通过调整这些参数,我们可以优化模型的训练过程,以得到更好的模型效果。

展开说的话,其中每个参数的具体含义如下:

'sgdm':这是训练算法,'sgdm' 代表带有动量的随机梯度下降(Stochastic Gradient Descent with Momentum)。这是一种常用的优化算法。
'ExecutionEnvironment', 'auto':此选项指定了训练算法的执行环境。可选值包括 'auto','cpu','gpu' 和 'multi-gpu'。其中,'auto' 表示 MATLAB 自动选择最佳环境,'cpu' 和 'gpu' 分别表示在 CPU 或 GPU 上执行训练,而 'multi-gpu' 表示在多个 GPU 上执行训练。
'GradientThreshold', Inf:这个参数设置了梯度裁剪阈值,当梯度的绝对值超过此阈值时,梯度将被裁剪。这是防止梯度爆炸的一种方法。在这个例子中,阈值设置为 Inf,意味着梯度裁剪实际上没有被激活。
'MaxEpochs', 30:此参数设定了模型训练的最大迭代次数。一次迭代(也称 epoch)意味着模型已经完整地学习过一次完整的训练集。在这个例子中,模型将会进行 30 次迭代。
'InitialLearnRate', 0.001:此参数设定了学习率的初始值。学习率是优化算法的一个重要参数,决定了模型参数更新的步长。如果学习率太大,可能导致模型无法找到最优解;如果学习率太小,可能导致模型收敛速度过慢。
'MiniBatchSize', 16:此参数设定了每次训练的小批量数据的大小。使用小批量可以加快模型训练速度,并且可以增加训练过程的随机性,有助于提高模型的泛化能力。
'LearnRateSchedule', 'piecewise':此参数设定了学习率的调整策略。'piecewise' 表示分段恒定策略,即在特定的迭代次数,学习率会乘以一个因子(由 'LearnRateDropFactor' 参数设定)。
'LearnRateDropFactor', 0.9:此参数设定了学习率调整的因子,只在 'LearnRateSchedule' 参数设定为 'piecewise' 时有效。在每个 'LearnRateDropPeriod' 周期后,学习率会乘以这个因子。
'LearnRateDropPeriod', 10:此参数设定了学习率调整的周期,只在 'LearnRateSchedule' 参数设定为 'piecewise' 时有效。每过这么多个迭代周期,学习率会按照 'LearnRateDropFactor' 设定的因子进行调整。
'SequenceLength', 'longest':此参数设定了序列处理方式,可选值有 'longest','shortest' 或一个正整数。'longest' 表示使用最长的序列长度,'shortest' 表示使用最短的序列长度,指定一个正整数则表示所有的序列都将被填充或者截断到这个长度。
'Shuffle', 'every-epoch':此参数设定了训练数据的混洗策略。'every-epoch' 表示在每次迭代开始时都会重新混洗训练数据。这可以增加训练的随机性,有助于提高模型的泛化能力。
'Verbose', 1:此参数设定是否在训练过程中打印详细信息。如果设定为 1,那么在每次迭代完成后都会打印出一些信息,例如当前的迭代次数、损失函数的值等。
'Plots', 'training-progress':设置了是否在训练过程中显示训练进度的图表,如果不显示,可以设置为'none'。

虽然这些设置内容看起来蛮多,但是真正核心的是以下这几个参数,在网络调试过程中,需要重点调试:

'MaxEpochs':最大迭代次数决定了模型在训练集上学习的次数。如果设定的迭代次数太少,模型可能无法充分学习;反之,如果迭代次数过多,可能会导致过拟合。
'InitialLearnRate':初始学习率对模型的训练速度和效果有很大影响。学习率太大可能会导致模型无法收敛,学习率太小则可能导致训练速度过慢。此外,学习率的设定也会影响到学习率调整策略的效果。
'MiniBatchSize':小批量大小影响了每次参数更新的计算效率和准确性。较小的批量大小可以增加模型训练的随机性,有助于防止过拟合,但也可能导致训练过程变慢。
'LearnRateSchedule''LearnRateDropFactor''LearnRateDropPeriod':这三个参数共同设定了学习率的调整策略。适当的调整学习率可以帮助模型更快地收敛,并达到更好的效果。

6. 对测试集进行预测

使用训练好的模型对测试集进行预测时,要确保预测函数的使用正确。同时,预测完成后,我们需要将数据进行反归一化,以还原到原始数据的范围。

%% 6.对测试集进行预测
YPred = predict(net,XTestMapD); 
% 反归一化
foreData=double(method('reverse',double(YPred'),outputps));

7. 对训练集进行拟合

对训练集进行拟合的步骤和测试集类似,也需要注意预测函数的正确使用和数据的反归一化。

%% 7.对训练集进行拟合
YpredTrain = predict(net,XTrainMapD); 
% 反归一化
foreDataTrain=double(method('reverse',double(YpredTrain'),outputps));

8. 训练集预测结果对比

通过可视化的方式对比模型的预测值和实际值,可以更直观地看到模型的预测效果。

%% 8. 训练集预测结果对比
figure('Color','w')
plot(foreDataTrain,'-','Color',[255 0 0]./255,'linewidth',1,'Markersize',5,'MarkerFaceColor',[250 0 0]./255)
hold on 
plot(YTrain,'-','Color',[150 150 150]./255,'linewidth',0.8,'Markersize',4,'MarkerFaceColor',[150 150 150]./255)
legend('CNN训练集预测值','真实值')
xlabel('预测样本')
ylabel('预测结果')
xlim([1, length(foreDataTrain)])
grid
ax=gca;hold on

9. 测试集预测结果对比

测试集的预测结果对比是评估模型性能的重要步骤。同样,我们也要通过可视化来直观地观察模型在未见过的数据上的表现。

%% 9. 测试集预测结果对比
figure('Color','w')
plot(foreData,'-','Color',[0 0 255]./255,'linewidth',1,'Markersize',5,'MarkerFaceColor',[0 0 255]./255)
hold on 
plot(YTest,'-','Color',[0 0 0]./255,'linewidth',0.8,'Markersize',4,'MarkerFaceColor',[0 0 0]./255)
legend('CNN测试集预测值','真实值')
xlabel('预测样本')
ylabel('预测结果')
xlim([1, length(foreData)])
grid
ax=gca;hold on

运行上述代码,可以得到以下几张图:

收敛过程

训练集拟合结果

测试集预测结果

三、"一行代码"实现CNN回归预测任务

上边章节演示了使用MATLAB实现CNN回归预测的基础代码演示,不过我们在实际研究中可能会面临更为复杂的困境:

  • 导入自己的数据后,网络结构一改就频频报错
  • 代码被改得乱七八糟,看的头大
  • 不知道该画哪些图、怎么画图
  • 想要学习更规范的代码编程
  • ......

按照本专栏的惯例,笔者封装了快速实现CNN回归预测的函数,在设定好相关参数后,只需要一行代码,就可以实现数据集训练集/验证集/测试集快速划分、快速绘制训练集/测试集预测结果对比图、绘制预测误差图,导出训练过程数据、计算MAE/MSE/MAPE/RMSE/R等指标等等常用功能,这个函数的介绍如下:

function [foreData,foreDataTrain,net,info] = FunRegCNNs(dataX,dataY,trainR,cLayer,poolingLayer,fcLayer,options,figflag)
% 使用CNN进行回归预测的快速实现函数
% 该函数需要输入的数据为array数组型
% 输入:
% dataX:输入数据,R*Q的矩阵,R为输入数据的维度,Q为批次数,输入该变量时一定要注意维度正确
%           例:对于一维特征,每组数据长度为20,共1000组数据,则dataX的可以维度为:20*1000
% dataY:输出结果
% trainR:数据集中训练集划分比例,如:trainR = 0.6,则代表60%数据用于训练集,40%数据用于测试集

% cLayer:卷积层结构,为n*5的二维数组,其中n为卷积层的数量
% 列向的5个维度时分别代表滤波器的高、滤波器的宽、滤波器数量、步长、填充
% 例,cLayer = [3,1,16,1,1;3,1,32,1,0]时,则代表有两层卷积层,其中第一层滤波器高为3,宽为1,滤波器数量为16,步长1,填充1
%                                                第二次滤波器高为3,宽为1,滤波器数量为32,步长1,填充0

% poolingLayer:池化层结构,为长度为n*5的cell数据,其中n为池化层的数量,和卷积层层数相同。
% 列向的三个维度分别代表:1.池化层类型,分为'maxPooling2dLayer'和'averagePooling2dLayer'两种,如果不用池化层设置为'none'
%                         2.池化区域高度尺寸
%                         3.池化区域宽度尺寸
%                         4.步长
%                         5.填充
% 例如:
% poolingLayer = {'maxPooling2dLayer',2,1,2,1; 'averagePooling2dLayer',2,1,1,0};
% 代表第一个池化层为最大池化层,尺寸为2*1,步长2,填充1,第二个池化层为平均池化层,尺寸为2*1,步长1,填充0
% 注意!如果对应卷积层后不设置池化层,请在对应的位置设置为'none',0,0,0,0
% 比如cLayer设置为两层时,如果只想在第一层卷积层后对应有池化层,第二层卷积层后无池化层,那么池化层应该设置为:
% poolingLayer = {'maxPooling2dLayer',1,2,1,0;
%                 'none',0,0,0,0 }; %后边的四个0主要是占位,不起实际作用

% options:一些与网络训练等相关的设置,使用结构体方式赋值,比如 options.MaxEpochs = 1000,具体包括:
%             solverName:求解器,'sgdm'(默认) | 'rmsprop' | 'adam'
%             MaxEpochs:最大迭代次数,默认30
%             MiniBatchSize:批尺寸,默认128
%             GradientThreshold:梯度极限,默认为Inf
%             InitialLearnRate:初始化学习速率(默认0.005)
%             Plots:是否显示训练过程,'none' 为不显示(默认) | 'training-progress'为显示
%             ValidationFrequency:验证频率,即每间隔多少次迭代进行一次验证,默认50
%             LearnRateSchedule:即LearnRateSchedule是否在一定迭代次数后学习速率下降, LearnRateSchedule ='piecewise'为使用,'none'为不使用(默认)
%             LearnRateDropPeriod:即LearnRateDropPeriod学习速率下降时的迭代数,默认为10
%             LearnRateDropFactor:即LearnRateDropFactor学习速率下降因子,下降后变为LearnRateDropFactor*InitialLearnRate,LearnRateSchedule为0时可以赋0,默认为0.1
%             (未启用)NorFlag:即Normalization Flag,设置为1时则在程序中进行数据归一化和反归一化操作,否则不进行,建议设置为1
%             SeedFlag:随机种子标志,设置为1时启用随机种子,(默认为1)
% fcLayer:全连接层,可以设置多层,如果设置fcLayer=[],则在网络结构中只包含一个全连接层,输出的维度与数据类别相同。
%                                  如果设置fcLayer为数组,则代表在上边的全连接层之前再加入对应数量的全连接层和ReLU层
%                                  例如设置fcLayer=[32,16],则代表在共有三个全连接层,第一个是fullyConnectedLayer(32)+ReLU,第二个是fullyConnectedLayer(16)+ReLU,
%                                                           第三个是fullyConnectedLayer(numClasses)
% figflag:是否画图,'on'为画图,'off'为不画
% 输出:
% foreData:测试集的回归预测结果
% foreDataTrain:训练集的回归预测结果
% net:训练好的网络
% info:神经网络训练相关参数,如loss值、准确度等

看注释写的蛮多的似乎有点唬人,其实使用起来比较简单。

例如上边波士顿房价预测的案例,整个第二章节代码可以用下述几行轻松实现:

%% 1.加载数据
boston = readmatrix('housing.txt');  %读取数据文件
% 将数据转为函数要求的格式
dataX = boston(:,1:13)'; %前13列数据为输入数据
dataY = boston(:,14)'; %第14行为房价数据
%% 2.调用函数进行回归预测
divideR = 0.7;  %训练集/验证集/测试集比例
figflag = 'on';           % 是否画图,'on'为画图,'off'为不画

%% 3.指定训练选项
options.solverName = 'sgdm'; %求解器,'sgdm'(默认) | 'rmsprop' | 'adam'
options.MaxEpochs = 100;    %最大迭代次数,默认30
options.InitialLearnRate = 0.03; %初始化学习速率(默认0.005)
options.Plots = 'training-progress'; %是否显示训练过程,'none' 为不显示(默认) | 'training-progress'为显示
options.ValidationFrequency = 10;   %验证频率,即每间隔多少次迭代进行一次验证
options.LearnRateSchedule = 'piecewise'; %是否在一定迭代次数后学习速率下降
options.LearnRateDropFactor = 0.9;  %学习速率下降因子
options.LearnRateDropPeriod = 100;   %学习速率下降时的迭代数
options.Plots = 'training-progress'; %显示训练过程
options.GradientThreshold = 1;       %梯度极限,默认为Inf

%% 4.网络结构设置
conLayer = [3,3,16,1,1]; %波器高为3,宽为3,滤波器数量为128,步长1,填充1
poolingLayer = {'none',0,0,0,0}; %不设置池化层
fcLayer = [];
%% 5.调用函数进行分类
[accuracy,net,info] = FunRegCNNs(dataX,dataY,divideR,conLayer,poolingLayer,fcLayer,options,figflag);

上述代码中留下需要设置的,都是必要的参数,这也是为了在保证代码易用性的同时充分保证灵活性。

运行上述代码可以得到一系列图片和指标,这些在写论文过程中都是很有用的

具体包括:

收敛过程图

网络结构图

训练过程中损失值和RMSE收敛图

训练集拟合结果对比图

训练集预测结果相对误差

测试集拟合结果对比图

测试集预测结果相对误差

在命令行窗口还会打印出以下内容:

网络结构

每层网络的输出尺寸

MAE/MSE/MAPE/RMSE/R等指标

三、总结

使用封装函数对复杂的CNN训练和评估流程进行了高度封装,大家只需要提供数据和指定参数,就可以轻松进行模型的训练和评估,大大减轻了同学们负担;另外函数接收多个参数作为输入,包括网络结构和训练选项等,使得用户可以根据自己的需求灵活地定制和配置模型,适应各种不同的应用场景;此函数不仅实现了CNN模型的训练,还对模型的性能进行了全面评估,并返回了训练过程中的详细信息,助力用户快速理解模型的性能,并进行后续的优化调整。

需要上述案例的代码和封装函数的代码,同学们可以在下述链接获取:

使用CNN进行回归预测代码 - 工具箱文档 | 工具箱文档

关于CNN的理论讲解可以看这里:

Mr.看海:【深度学习-第2篇】CNN卷积神经网络30分钟入门!足够通俗易懂了吧(图解)

关于MATLAB快速实现CNN分类可以看这里:

Mr.看海:【深度学习-第3篇】使用MATLAB快速实现CNN分类(模式识别)任务,含一维、二维、三维数据演示案例

相关推荐
AIGC大时代22 分钟前
如何使用ChatGPT辅助文献综述,以及如何进行优化?一篇说清楚
人工智能·深度学习·chatgpt·prompt·aigc
人机与认知实验室2 小时前
人、机、环境中各有其神经网络系统
人工智能·深度学习·神经网络·机器学习
Evand J2 小时前
LOS/NLOS环境建模与三维TOA定位,MATLAB仿真程序,可自定义锚点数量和轨迹点长度
开发语言·matlab
孤亭远见7 小时前
COMSOL with Matlab
matlab
靴子学长7 小时前
基于字节大模型的论文翻译(含免费源码)
人工智能·深度学习·nlp
海棠AI实验室9 小时前
AI的进阶之路:从机器学习到深度学习的演变(一)
人工智能·深度学习·机器学习
图南楠9 小时前
simulink离散传递函数得到差分方程并用C语言实现
matlab
信号处理学渣10 小时前
matlab画图,选择性显示legend标签
开发语言·matlab
苏言の狗11 小时前
Pytorch中关于Tensor的操作
人工智能·pytorch·python·深度学习·机器学习
paixiaoxin14 小时前
CV-OCR经典论文解读|An Empirical Study of Scaling Law for OCR/OCR 缩放定律的实证研究
人工智能·深度学习·机器学习·生成对抗网络·计算机视觉·ocr·.net