matlab实现卷积神经网络CNN(二)——代码实现与解析

        基于上一篇文章对于CNN网络结构的整理,我们将用matlab实现一维数据的CNN网络单\多输入和单\多输出。

        文中字母含义详情可见上一篇文章。

一、加载数据与数据集划分

clc;clear;close all;
data=load('data.csv')'; %总数据
label=load('label.csv')'; %总标签

[train_x,train_y,test_x,test_y,val_x,val_y]=spilt(data,label,0.8,0.1,0.1); 
%划分训练集、测试集和验证集

        data数据格式应为M×SN;M为一维数据的长度(即一个样本有多少个点),由于是一维数据,所以宽度N为1;SN则为样本个数。

        label数据格式应为P×SN;P代表输出特征个数(也就是单输出和多输出),SN为样本个数。

        spilt是个自定义函数,用来随机划分训练集、测试集和验证集,当然你也可以自行划分好后分别导入。

function [trainData,trainLabel,testData,testLabel,valData,valLabel]=spilt(data,label,trainRatio,testRatio,validationRatio)

% 生成随机分组索引
c = cvpartition(size(data,2), 'HoldOut', testRatio);
trainIdx = c.training;
testIdx = c.test;

% 对剩余数据再次进行随机分组
c = cvpartition(sum(trainIdx), 'HoldOut', validationRatio/(1-testRatio));
true_trainIdx=c.training;
valIdx = c.test;

% 将训练集、验证集和测试集分别保存到不同的变量中
trainData = data(:,trainIdx);
trainLabel = label(trainIdx);
valData = trainData(:,valIdx);
valLabel = trainLabel(valIdx);
testData = data(:,testIdx);
testLabel = label(testIdx);
trainData = trainData(:,true_trainIdx);
trainLabel = trainLabel(true_trainIdx);

总之,train_x、test_x和val_x数据格式应该分别为M×样本个数

           train_y、test_y和val_y数据格式应该分别为P×样本个数

二、数据预处理

%method=@mapminmax; %归一化
method=@mapstd; %标准化

[train_x,train_ps]=method(train_x,0,1);
test_x=method('apply',test_x,train_ps);
val_x=method('apply',val_x,train_ps);

[train_y,output_ps]=method(train_y,0,1);
test_y=method('apply',test_y,output_ps);
val_y=method('apply',val_y,output_ps);

选择对数据进行归一化或者标准化。

三、数据输入格式转换

trainD=reshape(train_x,[M,N,D,SN]);
%训练集输入,[单个样本长度,单个样本宽度,输入特征个数,样本数]
testD=reshape(test_x,[M,N,D,SN]);
%测试集输入,[单个样本长度,单个样本宽度,输入特征个数,样本数]
valD=reshape(val_x,[M,N,D,SN]);
%验证集输入,[单个样本长度,单个样本宽度,输入特征个数,样本数]

其中,因为是一维数据,所以N=1,下文同。

CNN的输入数据格式应为【单个样本长度,单个样本宽度,输入特征个数,样本数】;

【M,N,D,SN】。

D=1则代表单输入。

四、CNN网络结构建立

layers = [
    imageInputLayer([M N D]) %输入层参数设置,[M,N,D]
%第一层卷积层和池化层
    convolution2dLayer([64,1],128,'Padding','same')
    %[64,1]是卷积核大小,128是个数
    %对于一维数据,卷积核第二个参数为1就行了,这样就是一维卷积
    reluLayer %relu激活函数
    maxPooling2dLayer([32 1],'Stride',10)

%第二层卷积层和池化层
    convolution2dLayer([32,1],128,'Padding','same')
    reluLayer %relu激活函数
    maxPooling2dLayer([16 1],'Stride',20)

%两层全连接层
    fullyConnectedLayer(20) % 20个全连接层神经元
    reluLayer %relu激活函数
    fullyConnectedLayer(10) % 10个全连接层神经元
    fullyConnectedLayer(P) % 输出层神经元个数P
    regressionLayer];%添加回归层,用于计算损失值

        上述代码中的卷积核大小、个数等参数不具备参考意义,应当根据自身数据结构自行调整。

        convolution2dLayer代表卷积层;【64,1】是卷积核的大小,由于是一维数据,所以第二个参数为1;128是卷积核个数;’Padding’,’same’代表填充使得该层的神经元输入和输出个数相同。我们也可以自定义其他填充方式或者步幅大小。

详情可见官方文档:https://ww2.mathworks.cn/help/deeplearning/ref/nnet.cnn.layer.convolution2dlayer.html

        maxPooling2dLayer代表最大池化层;【32,1】是池化层大小;’Stride’,10代表池化步幅。

        fullyConnectedLayer代表全连接层,最后一层全连接层需决定输出特征个数P;reluLayer代表激活函数的选择。

        regressionLayer代表回归层,也可以换成分类层softmaxLayer和classificationLayer

analyzeNetwork(net);

我们可以采用该指令来查看网络结构,包括层结构和每一层的输入输出大小。 

        有时候你的卷积核大小、个数、步幅以及池化层大小和步幅设置的不合理,导致网络出错,我们就可以通过该命令检查每一层的输入输出。比如,某一池化层的大小不能大于上一层的输出个数。

        具体可见下一篇文章,CNN结合灰狼优化算法进行超参数优化。

五、模型设置

options = trainingOptions('adam', ...%优化方法:sgdm、adam等
    'MaxEpochs',30, ...
    'MiniBatchSize',20, ...
    'InitialLearnRate',0.001, ...
    'GradientThreshold',1, ...
    'Verbose',false,...
    'ExecutionEnvironment','multi-gpu',...% GPU训练
    'Plots','training-progress',...%'none'代表不显示训练过程
    'ValidationData',{valD,val_y'});%验证集

值得一提的是验证集的输入,在很多书籍中,验证集和测试集是同一个数据集。

六、模型训练与测试

net = trainNetwork(trainD,train_y',layers,options);

% 预测
YPred = predict(net,testD);

% 结果
YPred=double(YPred');%输出是n*1的single型数据,要转换为1*n的double是数据形式

% 反归一化
predict_value=method('reverse',YPred,output_ps);predict_value=double(predict_value);
true_value=method('reverse',test_y,output_ps);true_value=double(true_value);

七、结果评估

rmse=sqrt(mean((true_value-predict_value).^2));
disp(['根均方差:',num2str(rmse)])
mae=mean(abs(true_value-predict_value));
disp(['平均绝对误差:',num2str(mae)])
maxape=max(abs((true_value-predict_value)./true_value));
disp(['最大相对百分误差:',num2str(maxape*100),'%'])
mape=mean(abs((true_value-predict_value)./true_value));
disp(['平均相对百分误差:',num2str(mape*100),'%'])

文章出处登录后可见!

已经登录?立即刷新

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2023年12月27日
下一篇 2023年12月27日

相关推荐