Matlab使用CNN卷积神经网络进行图像分类,使用了猫狗大战数据集的4000个图像(2000猫2000狗),分为猫狗两个类别。 也可以改成多分类。 注释详细,可直接运行,可以直接换成自己的数据,源代码和数据文件都会发给你。 工作如下: 1、加载数据集,并划分,70%训练,10%验证,20%测试。 数据量一共为4000(2000猫2000狗)。 2、搭建CNN网络,网络为三层,构建优化器。 3、训练 4、测试,计算准确率,绘制混淆矩阵。 注:本程序只用于教学练习如何在Matlab里使用CNN,由于数据量太少和网络简单,准确率结果并不是很好。 4000样本时,GPU运行时间大约7分钟。 为了方便没有GPU的同学学习,又设计了CPU版本。 不用GPU的版本:只用了1000个样本(500猫500狗),在CPU上训练大约用时15分钟。 网络层数也降低为了两层,且没有使用验证集。

一、引言

在机器学习领域,图像分类是一个非常重要的任务,而卷积神经网络(CNN)在图像分类上表现卓越。今天咱们就来聊聊如何在Matlab中利用CNN对猫狗大战数据集进行图像分类,这不仅能帮大家掌握CNN在Matlab中的应用,还能加深对图像分类流程的理解。

二、数据集相关操作

(一)完整数据集划分(GPU版本)

咱们一共有4000个图像(2000猫和2000狗),要将其按70%训练,10%验证,20%测试划分。

% 加载图像数据存储库
imageDir = 'your_path_to_dataset'; % 这里换成实际数据集路径
imds = imageDatastore(imageDir, 'IncludeSubfolders', true, 'LabelSource', 'foldernames');

% 划分数据集
numImages = numel(imds.Files);
idx = randperm(numImages);
trainIdx = idx(1:round(numImages*0.7));
valIdx = idx(round(numImages*0.7)+1:round(numImages*0.8));
testIdx = idx(round(numImages*0.8)+1:end);

trainDS = subset(imds, trainIdx);
valDS = subset(imds, valIdx);
testDS = subset(imds, testIdx);

代码分析:首先,我们通过imageDatastore函数来加载数据集,IncludeSubfolders设置为true表示包含子文件夹,LabelSource设置为foldernames意味着文件夹名就是图像的类别标签。然后通过随机数生成打乱图像顺序的索引idx,再根据比例划分出训练集、验证集和测试集的索引,最后用subset函数分别创建三个子集。

(二)小数据集划分(CPU版本)

对于没有GPU的同学,我们准备了小数据集版本,只用1000个样本(500猫和500狗),且不使用验证集。

% 加载小图像数据存储库
smallImageDir = 'your_path_to_small_dataset'; % 小数据集路径
smallImds = imageDatastore(smallImageDir, 'IncludeSubfolders', true, 'LabelSource', 'foldernames');

% 划分小数据集
numSmallImages = numel(smallImds.Files);
smallIdx = randperm(numSmallImages);
smallTrainIdx = smallIdx(1:round(numSmallImages*0.8));
smallTestIdx = smallIdx(round(numSmallImages*0.8)+1:end);

smallTrainDS = subset(smallImds, smallTrainIdx);
smallTestDS = subset(smallImds, smallTestIdx);

代码分析:和上面类似,只是针对小数据集进行操作,同样是用imageDatastore加载,再随机划分训练集和测试集。

三、搭建CNN网络

(一)三层CNN网络(GPU版本)

% 搭建三层CNN网络
layers = [
    imageInputLayer([224 224 3]) % 输入层,假设图像大小224x224x3(RGB图像)
    
    convolution2dLayer(3,16,'Padding','same') % 卷积层,3x3卷积核,16个滤波器,same填充
    batchNormalizationLayer % 批归一化层
    reluLayer % ReLU激活函数层
    
    maxPooling2dLayer(2,'Stride',2) % 最大池化层,2x2池化窗口,步长2
    
    convolution2dLayer(3,32,'Padding','same')
    batchNormalizationLayer
    reluLayer
    
    maxPooling2dLayer(2,'Stride',2)
    
    convolution2dLayer(3,64,'Padding','same')
    batchNormalizationLayer
    reluLayer
    
    maxPooling2dLayer(2,'Stride',2)
    
    fullyConnectedLayer(2) % 全连接层,2个输出(对应猫和狗两个类别)
    softmaxLayer % Softmax层
    classificationLayer]; % 分类层

代码分析:从输入层开始,图像大小设置为224x224x3。然后依次添加卷积层、批归一化层和ReLU激活函数层,卷积层用于提取图像特征,批归一化加速网络收敛,ReLU增加非线性。接着是最大池化层,用于下采样减少数据量。最后通过全连接层输出类别分数,再经过Softmax和分类层得到最终分类结果。

(二)两层CNN网络(CPU版本)

% 搭建两层CNN网络
smallLayers = [
    imageInputLayer([224 224 3])
    
    convolution2dLayer(3,16,'Padding','same')
    batchNormalizationLayer
    reluLayer
    
    maxPooling2dLayer(2,'Stride',2)
    
    convolution2dLayer(3,32,'Padding','same')
    batchNormalizationLayer
    reluLayer
    
    maxPooling2dLayer(2,'Stride',2)
    
    fullyConnectedLayer(2)
    softmaxLayer
    classificationLayer];

代码分析:整体结构类似三层网络,只是减少了一层卷积层,这是为了在CPU上能够更高效运行。

四、构建优化器

(一)GPU版本优化器

% 构建优化器
options = trainingOptions('adam',...
    'MaxEpochs',10,...
    'InitialLearnRate',0.001,...
    'ValidationData',valDS,...
    'ValidationFrequency',3,...
    'Verbose',false,...
    'Plots','training-progress');

代码分析:这里使用Adam优化器,设置最大训练轮数为10,初始学习率0.001。将验证集valDS传入,并设置每3轮验证一次,关闭详细输出,同时开启训练进度绘图。

(二)CPU版本优化器

% 构建优化器
smallOptions = trainingOptions('adam',...
    'MaxEpochs',10,...
    'InitialLearnRate',0.001,...
    'Verbose',false,...
    'Plots','training-progress');

代码分析:同样是Adam优化器,只是因为没有验证集,所以没有相关设置,其他参数类似。

五、模型训练

(一)GPU版本训练

% 训练网络
net = trainNetwork(trainDS, layers, options);

代码分析:调用trainNetwork函数,传入训练集trainDS、网络层layers和优化器选项options,开始训练网络。

(二)CPU版本训练

% 训练小网络
smallNet = trainNetwork(smallTrainDS, smallLayers, smallOptions);

代码分析:和GPU版本类似,只是使用小训练集smallTrainDS、小网络层smallLayers和小优化器选项smallOptions进行训练。

六、模型测试与评估

(一)GPU版本测试

% 预测测试集
YPred = classify(net, testDS);
YTest = testDS.Labels;

% 计算准确率
accuracy = sum(YPred == YTest)/numel(YTest);
fprintf('GPU版本测试准确率: %.2f%%\n', accuracy*100);

% 绘制混淆矩阵
confMat = confusionmat(YTest, YPred);
figure;
confusionchart(confMat);
title('GPU版本混淆矩阵');

代码分析:先用训练好的网络net对测试集testDS进行预测得到预测标签YPred,再获取测试集真实标签YTest。通过比较两者计算准确率。最后用confusionmat函数生成混淆矩阵,并使用confusionchart绘制出来。

(二)CPU版本测试

% 预测小测试集
smallYPred = classify(smallNet, smallTestDS);
smallYTest = smallTestDS.Labels;

% 计算准确率
smallAccuracy = sum(smallYPred == smallYTest)/numel(smallYTest);
fprintf('CPU版本测试准确率: %.2f%%\n', smallAccuracy*100);

% 绘制混淆矩阵
smallConfMat = confusionmat(smallYTest, smallYPred);
figure;
confusionchart(smallConfMat);
title('CPU版本混淆矩阵');

代码分析:和GPU版本测试流程一样,只是针对小网络和小测试集进行操作。

七、总结

通过以上步骤,我们在Matlab中完成了基于CNN的图像分类任务,分别实现了GPU和CPU版本。大家可以根据自己的硬件条件选择合适的版本来运行,并且可以很方便地将其应用到自己的数据上。由于本次使用的数据量较少且网络简单,准确率可能不太理想,但这并不影响我们通过这个案例学习Matlab中CNN的使用流程。希望大家在实际应用中可以进一步优化网络和数据集,得到更好的效果。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐