前言
当前机器学习的算法已经获得应用,对于经典的支持向量机(SVM)算法,其有着实现简单、解释性较强、性能优越的特点。如今支持向量机的研究力度并没有减退,选择何种算法应该取决于具体的机器学习任务,对于多类别的图像分类任务,支持向量机或许是一个不错的选择。本文介绍的代码可以实现较高的分类测试准确率,所以想借此为大家提供一个学习的Demo共同交流。
思路是先基于核支持向量机(SVM)算法开发一个能够根据图片内容进行分类的脚本,所用到的数据集可以是当前公开的分类图片数据集,也可以是自行从网络上爬取的。除了算法实现,为了便于展示和训练,我们利用MATLAB的APP设计工具开发一个GUI系统界面,能够满足我们选择模型、图片、文件夹路径的需求,初始界面如上图所示。另外由于自行设定的数据集可能经常调整,所以相应的代码也需要调整,所以这里把数据集的调整考虑进去,设计了可选择训练数据集、设置训练参数的功能,其界面如下图所示。
本文给出了MATLAB实现的完整代码供大家参考,有基础的读者可按照文中的介绍复现出完整程序;对于想获取全部数据集及程序文件的朋友,可以点击提供的下载链接获取可直接运行的代码,原创不易,还请多多支持了。如本文对您有所帮助,敬请点赞、收藏、关注!
1. 效果演示
(一)选择模型+选择图片+历史记录
首先还是用动图先展示一下效果。进入软件界面后,点击模型选择按钮即可弹出文件选择窗口,可选择自行训练的模型文件;然后同样点击图片选择按钮,可以选择一张需要测试的图片,点击确认后,模型则自动识别图片内容,并给出预测的结果;结果会被记录在右侧的表格中,可供再次查看确认。本功能的界面展示如下图所示:
(二)批量图片识别+分类结果展示
对于需要批量识别的情况,可选择界面中的文件夹按钮,选择一个待测试的图片文件夹,系统自动识别文件夹下的文件并进行分类识别。在此过程中识别结果展示在右侧,包括分类结果、准确率、图片的历史记录。用户可点击右侧的结果记录表格中的对应序号,回看图片以及对应的识别结果,该部分演示如下图所示:
(三)自定义模型训练+参数设置+自动训练
如果想更换数据集并重新训练模型,这时只需要点击“训练”选项卡,可切换至训练界面。如下图所示,可选择一个自定义的图片文件夹,该文件夹下包含多个以类别命名的子文件夹,系统自动将文件夹的名字作为每一类的标签,并将读取的结果显示在界面中。可以选择训练占比和核函数的训练设置,点击“开始训练”即可自动进行训练,训练的过程信息显示在界面上,最终可以得到训练测试集准确率,以及各类别的混淆矩阵结果,模型自动保存在当前文件夹下供后续选择。
2. Caltech 101数据集
提到分类任务的数据集很容易想到ImageNet,它无疑是个巨大的训练图库,对于我们自行训练和测试其实是非常费力的事情(除非你拥有高端设备),所以我并不推荐在学习阶段就使用。至于早前不少论文中广泛使用的CIFAR10 / CIFAR100以及MNIST数据集,它们的尺寸过小,且本身任务比较简单,目前已不在普遍使用(水论文除外)。所以这里我们选择的数据集是更贴近真实情况的Caltech 101数据集,也是当前非常流行的数据集。
Caltech-101 Dataset是由 101 个类别的对象图片组成的数据集,它主要用于目标识别和图像分类,官网地址为https://www.vision.caltech.edu/Image_Datasets/Caltech101/。该数据集不同类别有 40 至 800 张图片,每张图片的大小在 300 * 200 像素,且数据集的发布者均已标注对应的目标以供使用。该数据集由加州理工学院的李菲菲、马克安德烈托和 Marc’Aurelio Ranzato 于 2003 年 9 月收集,相关论文有《Learning generative visual models from few training examples: an incremental Bayesian approach tested on 101 object categories》、《One-Shot learning of object categories》等。
下载完成后的数据集文件如上图所示,解压后即可看到其中包含101个子文件夹,每个文件夹对应一个类别的图片,文件夹的名字表示对应的标签。由于该数据集文件数目较大,这里选取其中的10类如下图所示,将这几个文件夹复制到新建的文件夹进行实验,最终确定所用的数据集。
数据集准备完毕,现在可以通过文件夹读取图片了。在MATLAB中可使用imageDatastore函数方便地批量读取图片集,它通过递归扫描文件夹目录,将每个文件夹名称自动作为图像的标签,该部分代码如下:
java clear clc rng default % 保证结果运行一致 mpath = matlab.desktop.editor.getActiveFilename; % 程序所在目录 [pathstr,~]=fileparts(mpath); cd(pathstr); % 自动切换至程序所在目录 imgDir = fullfile("../10_ObjectCategories/"); % imageDatastore递归扫描目录,将每个文件夹名称自动作为图像的标签 dataSet = imageDatastore(imgDir, 'IncludeSubfolders', true, 'LabelSource', 'foldernames');
至此读取到的数据集被存放在dataSet变量中,可以简单查看训练和测试集每类标签的样本个数,显示代码如下:
java trainSetDetail = countEachLabel(dataSet) % 训练数据
执行以上代码运行结果如下:
这里展示一下读取到的图片,代码如下所示:
java figure imshow(dataSet.Files{520});
执行该代码可以看到如下的运行结果:
这里我们划分训练和测试数据集,使用留一法将80%的数据用于训练,剩余的数据用于模型测试,将训练和测试文件保存在trainSet.Files及testSet.Files变量中,对应的标签则存在Label中,该部分代码如下:
java indices = crossvalind('Kfold',dataSet.Labels,5); % 进行交叉验证划分 t=1; test=(indices == t); train=~test; % 训练数据集 trainSet.Files = dataSet.Files(train); trainSet.Labels = dataSet.Labels(train); % 测试数据集 testSet.Files = dataSet.Files(test); testSet.Labels = dataSet.Labels(test);
至此完成数据集的读取和划分工作,接下来进行特征提取步骤。
3. HOG特征提取
真正用于训练分类器的数据并不是原始图片数据,而是先经过特征提取后得到的特征向量,这里使用的特征类型是HOG,也就是方向梯度直方图。所以这里重要的一点是正确提取出HOG特征,extractHOGFeatures是MATLAB自带的HOG特征提取函数,该函数不仅可以有效提取特征,还可以返回特征的可视化结果以方便展示。该部分代码如下:
java cellSize = [4 4]; img = readimage(dataSet, 23); img = rgb2gray(img); % 灰度化图片 img = imbinarize(img); img = imresize(img, [100 100]); [hog_4x4, vis4x4] = extractHOGFeatures(img,'CellSize',[4 4]); hogFeatureSize = length(hog_4x4); % 提取HOG特征 tStart = tic; [trainFeatures, trainLabels] = extractHogFromImageSet(trainSet, hogFeatureSize, cellSize); % 训练集特征提取 [testFeatures, testLabels] = extractHogFromImageSet(testSet, hogFeatureSize, cellSize); % 测试集特征提取 tEnd = toc(tStart); fprintf('提取特征所用时间:%.2f秒\n', tEnd);
以上代码首先进行图片灰度化、二值化、尺寸调整等预处理操作,然后调用extractHogFromImageSet函数提取训练和测试集的HOG特征。由于图片数量众多,提取特征过程尚需一定时间,这里对训练集、测试集提取过程进行计时,因计算机算力不同,执行时间可能会不一致,最终打印特征提取所用的时间。
java 提取特征所用的时间:18.73秒
4. 训练和评估模型
下面我们使用以上提取的HOG特征构建支持向量机模型,利用提取的训练集特征进行训练。首先利用templateSVM函数构建支持向量机模板参数,选择gaussian核函数,执行标准化处理数据,显示训练过程;利用fitcecoc函数执行训练过程,其代码如下。
java % 训练支持向量机 t = templateSVM('SaveSupportVectors',true, 'Standardize', true, 'KernelFunction','gaussian', ... 'KernelScale', 'auto','Verbose', 0); % 利用polynomial核函数, 标准化处理数据,显示训练过程(verbose取0时取消显示) tStart = tic; % 计时开始 classifier = fitcecoc(trainFeatures, trainLabels, 'Learner', t); % 训练SVM模型 tEnd = toc(tStart); fprintf('训练模型所用时间:%.2f秒\n', tEnd);
等待训练完成,我们可以使用训练好的分类器进行预测,这里先利用测试集评估模型并计算分类评价指标,对测试集进行预测的代码如下:
java tStart = tic; % 对测试数据集进行预测 predictedLabels = predict(classifier, testFeatures); tEnd = toc(tStart); fprintf('模型对测试集进行预测所用时间:%.2f秒\n', tEnd);
运行结果如下:
java 模型对测试集进行预测所用时间:5.75秒
得到了预测结果,可以使用混淆矩阵评估结果,以下代码首先计算混淆矩阵结果,然后将结果打印出来:
分类准确率可以通过以下代码进行计算:
java accuracy = sum(predictedLabels == testLabels) / numel(testLabels); fprintf('模型在测试集上的准确率:%.0f%%\n', accuracy*100);
以上代码显示了混淆矩阵的结果,但可能还不够直观,下面绘制混淆矩阵图帮助更好了解模型性能:
java % 绘制混淆矩阵图 plotconfusion(testLabels, predictedLabels);
运行代码后显示混淆矩阵图如下图所示,每行对角线上的网格(绿色网格)处显示了某类样本预测正确的数目及其占比。右下角网格表示分类的准确率,可以看出该分类器具有90.2%的总体分类准确率。
为了便于后续测试,这里保存模型文件,其代码如下:
java save('trainedSvmModel.mat','classifier');
5. 测试模型
这里我们选取几张图片进行测试,以便对模型的效果有个更直观的感受,这部分代码如下所示:
java clear clc rng default % 保证结果运行一致 img_test_1 = imread("../10_ObjectCategories/airplanes/image_0137.jpg"); img_test_2 = imread("../10_ObjectCategories/dragonfly/image_0001.jpg"); img_test_3 = imread("../10_ObjectCategories/inline_skate/image_0003.jpg"); img_test_4 = imread("../10_ObjectCategories/ketch/image_0005.jpg"); img_test_5 = imread("../10_ObjectCategories/Motorbikes/image_0006.jpg"); img_test_6 = imread("../10_ObjectCategories/umbrella/image_0010.jpg");
读取图片后,首先利用imshow函数将几张图片显示出来,采用subplot函数划分图片坐标轴区域,以便将6张图片展示出来:
java figure; subplot(2, 3, 1); imshow(img_test_1); subplot(2, 3, 2); imshow(img_test_2); subplot(2, 3, 3); imshow(img_test_3); subplot(2, 3, 4); imshow(img_test_4); subplot(2, 3, 5); imshow(img_test_5); subplot(2, 3, 6); imshow(img_test_6);
执行以上代码,运行结果如下图所示:
与上一章类似,首先提取HOG特征,这里将提取到的特征进行可视化展示,并将其与原始图片进行对比,其代码如下:
java img = rgb2gray(img_test_1); img = imbinarize(img); % img = imresize(img, [100 100]); [hog_1, vis_1] = extractHOGFeatures(img,'CellSize',[4 4]); figure subplot(2,1,1); imshow(img_test_1) title("原始图像") subplot(2, 1, 2) plot(vis_1); title("特征图像")
运行以上代码,特征提取的图像运行结果如下图所示:
接下来我们载入前面训练好的模型,对读取到的图片进行预测并显示结果。值得注意的是,每张图片在预测前的预处理工作,这里通过代码将灰度化、二值化、HOG特征的结果可视化在同一个绘图窗口中,其代码如下:
java load("trainedSvmModel.mat", "classifier"); img_gray = rgb2gray(img_test_4); img_bin = imbinarize(img_gray); img = imresize(img_bin, [100 100]); [hog_4, vis_4] = extractHOGFeatures(img,'CellSize',[4 4]); % 对测试数据集进行预测 fea_4 = extractHOGFeatures(img,'CellSize',[4 4]); predictedLabels = predict(classifier, fea_4); fprintf("预测结果:%s",predictedLabels); figure subplot(2,2,1) imshow(img_test_4); title(["预测结果:", char(predictedLabels)]) subplot(2,2,2) imshow(img_gray); subplot(2,2,3) imshow(img_bin); subplot(2,2,4) plot(vis_4)
运行以上代码,显示结果如下:
下载链接
若您想获得博文中涉及的实现完整全部程序文件(包括数据集,m, UI文件等,如下图),这里已打包上传至博主的面包多平台和CSDN下载资源。本资源已上传至面包多网站和CSDN下载资源频道,可以点击以下链接获取,已将所有涉及的文件同时打包到里面,点击即可运行,完整文件截图如下:
在文件夹下的资源显示如下: