原贴博客:https://blog.csdn.net/zfrycw/article/details/80633979
目录
前言
一、利用现成网络进行分类
二、构建简单的分类网络
三、迁移学习
前言
Matlab从2016a版本开始提供了深度学习的相关工具,可以很方便地构建自己的网络或下载一些现成的经典网络(如AlexNet,GoogLeNet和VGG系列)进行迁移学习。作为一个初学者,我粗浅地认为,对于深度学习,我们实际的操作步骤可以分三大块:数据集(包括载入图片,制作训练集验证集,送入网络前对图片进行预处理),构建网络和选择训练方式。本文将基于Matlab2017b,紧抓这三块,基于3个Matlab的官方示例,分享Matlab深度学习工具的初步试玩心得。
一、利用现成网络进行分类
该部分将利用GoogLeNet进行图片分类,目的在于通过介绍几个内置函数的使用,演示如何在Matlab2017b中进行现成网络的下载,如何调整图片尺寸以与网络输入层相符,以及怎么将下载的网络运用在单独的一张图片上进行测试。
1、载入网络
在使用GoogLeNet之前,需要在add-one explorer上进行下载安装,同时界面上会介绍网络的相关使用方式(由于GoogLeNet过于复杂,在此不展示其内部结构):
根据上述内容,载入GoogLeNet:
net = googlenet;
2、调整图片尺寸
Matlab官方示例的图片是经过预先裁剪处理后的,最终运行得精确度在95%左右,现在我们随便选择一张未经预处理的桌面壁纸(1920X1080)进行测试,看效果如何。
调整图片尺寸的目的是为了与网络输入层参数相匹配,因此我们需要首先获取GoogLeNet输入层参数:
inputSize = net.Layers(1).InputSize;
调整图片尺寸,在此我们需要用到imread()和imresize()两个函数:
%读入图像 B = imread(‘bird.jpg‘); %重设图像尺寸,若inputSize=[227 227 3],则inputSize[1:2]=[227 227],相当于取inputSize前两维 B = imresize(B, inputSize(1:2));
3、图片分类测试
现在,将调整后的图片送入GoogLeNet进行测试:
figure imshow(B) %取Googlenet输出层最后能分辨的对象类别 classNames = net.Layers(end).ClassNames; title(string(label) + "," + num2str(100*scores(classNames == label), 4) + "%");
测试结果显示图片内容有51.65%的可能性为brambling(燕雀),由于测试图片含有大量背景干扰,仅图片大约中间位置为待测对象,而不论图片中的是否为燕雀,预测结果的大方向是可以接受的。
二、构建简单的分类网络
该部分将实现一个简单分类网络的构建并在新数据集上运行测试,目的在于熟悉深度学习的核心步骤,并通过介绍几个内置函数的使用实现从载入数据、构建网络、训练网络到作出预测的整个流程。
1、数据集处理
假设我们已获取所需图片,并人为将其分门别类放置于地址‘D:\Matlab\ImageData‘下的各子文件夹中(如本例数据集中含写有数字0-9的图片,我们将所有含数字0的图片放在上述地址下的子文件0内,其余图片同理)。
(1)载入数据
载入数据部分介绍两个函数:fullfile()和imageDatastore():
%fullfife()用于将输入的字符串组合成文件或文件夹路径 F = fullfile(‘E:‘,‘Matlab‘,‘Work‘);
运行结果为F = ‘E:\Matlab\Work‘。
%imageDatastore()用于把指定路径的图片集存为特殊格式ImageDatastore imds = imageDatastore(F,‘IncludeSubfolders‘,true,‘LabelSource‘,‘foldernames‘);
运行结果将生成一个名为imds的ImageDatastore特殊变量。
第一个入口参数用于指定路径,若文件夹在Matlab的当前工作目录下,可直接以‘文件夹名‘形式输入参数,否则需要‘文件夹详细地址‘,如‘E:\Matlab\Work\MerchData‘。
‘IncludeSubfolders‘用于表示是否包含子目录图片,通过参数true/false表示是/否。
‘LabelSource‘用于指定各图片获取label值的源,若入口参数为‘foldernames‘,各图片的label将根据其所在的文件夹名确定。
(2)查看图片
在载入图片集后,为了确认操作正确,我们可以通过查看图片进行检验,并统计imds中各标签值的图片数:
figure; %打开figure界面 perm = randperm(10000,20); %从1-1000中任取20个数 for i = 1:20 subplot(4,5,i); %将figure界面分割为4X5个小格,并选中第i个小格 imshow(imds.Files{perm(i)}); %在第i个小格上显示标号为i的图片 end labelCount = countEachLabel(imds); %统计imds中各标签值的图片数
(3)划分训练集和验证集
利用splitEachLabel()把数据集分为训练集和验证集两部分:
% 共有1000张图片,任取750个定为训练集,剩下的为验证集 numTrainFiles = 750; [imdsTrain,imdsValidation] = splitEachLabel(imds,numTrainFiles,‘randomize‘);
2、构建网络
由于神经网络的输入层的参数与数据集中的图片规格是对应的,因此在构建网络前,我们首先需要查明数据集中图片的尺寸:
根据上述操作可知图片尺寸为28X28X1(灰度图像,仅一个通道),由此从输入层开始构建网络如下:
layers = [ imageInputLayer([28 28 1]) convolution2dLayer(3,8,‘Padding‘,1) batchNormalizationLayer reluLayer maxPooling2dLayer(2,‘Stride‘,2) convolution2dLayer(3,16,‘Padding‘,1) batchNormalizationLayer reluLayer maxPooling2dLayer(2,‘Stride‘,2) convolution2dLayer(3,32,‘Padding‘,1) batchNormalizationLayer reluLayer fullyConnectedLayer(10) softmaxLayer classificationLayer];
3、训练网络
(1)名词解释
在训练网络时,我们会见到三个容易混淆的名词:
batch:实际训练时我们采用的是随机梯度下降法(sgd),在这一算法中,我们把训练集的样本分成多个块,每个块叫做一个batch,每次前向传播只用到一个batch的样本而非训练集中的所有样本。
iteration:用一个batch的样本完成一次训练称为一个iteration。
epoch:完成一次所有样本的训练称为一个epoch。
(2)选择训练方式
%trainingOptions()用于选择训练方式 options = trainingOptions(‘sgdm‘,‘MaxEpochs‘,4,‘ValidationData‘,imdsValidation,‘ValidationFrequency‘,30,‘Verbose‘,false,‘Plots‘,‘training-progress‘);
第一个入口参数‘sgdm‘表示选择带冲量的随机梯度下降法进行训练
‘MaxEpochs‘表示训练过程中的epoch数,上述代码我们将该值定为4
‘ValidationData‘训练过程中用于验证的数据,上述代码中我们使用验证集imdsValidation
‘ValidationFrequency‘表示经过几次iteration进行一次验证,上述代码我们将其设为30
‘Verbose‘用于选择是否将训练过程中的信息显示在控制窗口,通过true/false进行设置
‘Plots‘用于选择是否在训练过程中绘制图像显示,通过参数‘progress-training‘/‘none‘设置
(3)训练网络
%trainNetwork()用于训练网络,三个入口参数分别为:训练集,网络结构和训练方式 net = trainNetwork(imdsTrain,layers,options);
4、验证网络
(1)测试
我们使用训练好的网络对验证集中的图片进行测试
%classify()用于分类,两个入口参数分别为:用于分类的网络和需要预测的图片 YPred = classify(net,imdsValidation);
(2)计算准确率
YValidation = imdsValidation.Labels; accuracy = sum(YPred == YValidation)/numel(YValidation);
numel(YValidation):返回YValidation中元素个数
YPred == YValidation:逐个比较YPred和YValidation中的各元素,相等则对应位置为1,否则为0
三、迁移学习
该部分介绍基于AlexNet的简单迁移学习方法,即如何快速地利用现成网络应对新的数据,并结合例子二中介绍的工具,实现从载入数据、构建网络、训练网络到作出预测的整个流程。
我们知道,相对于自己构建网络,利用已在其它训练集上训练好的神经网络在新的数据集上进行训练会更加快速,效果也更好。具体操作原理为,由于网络的浅层部分用于学习较低级的特征,我们保持网络的浅层不变,仅调整位于网络末尾用于提取针对当下数据集复杂特征的层,然后用这个微调后的神经网络,配置好数据集(Training set/Validation set)和训练方式后进行训练。
1、数据加载
(1)载入图片
Location = ‘E:\Matlab\Work\MerchData‘; imds = imageDatastore(Location,‘IncludeSubfolders‘,true,‘LabelSource‘,‘foldernames‘);
(2)划分数据集
spitEachLabel()不仅可以通过指定数量划分数据集,还能按比例划分:
%将数据集按7:3分为训练集和验证集 [imdsTrain, imdsValidation] = splitEachLabel(imds,0.7,‘randomized‘);
(3)查看图片
numTrainImages = numel(imdsTrain.Labels); %获得训练集中图片数量,注意imdsTrain是一个1X1的ImageDataset,故运行numel(imdsTrain)的结果是1 pick = randperm(numTrainImages, 16); %任取16个数随意排序 figure %打开figure窗口 for i = i:16 subplot(4,4,i); %把画图窗口分为4X4的小格,并选定第i小格 I = readimage(imdsTrain,pick(i)); imshow(I); end
2、基于迁移学习构建网络
(1)载入AlexNet
首先在add-one explorer中下载并安装AlexNet,同时在下载页面可以找到使用说明:
然后利用下述代码载入网络:
net = alexnet;
之后可以根据使用说明利用net.Layers查看AlexNet的内部结构:
(2)改造网络
根据分析,我们需要保留AlexNet浅层不变(用于学习初级特征),改变与实际数据集相对应的个别深层。原始的AlexNet网络可对1000中不同对象进行分类,而本例中我们数据集中的对象种类远远小于1000,因而我们需要据此调整网络结构。
首先,我们需要获取浅层不变层,即AlexNet前1-22层:
layersTransfer = net.Layers(1:end-3);
接着,我们需要获取数据集中的对象种类数以调整原始网络:
numClass = numel(categories(imdsTrain.Labels));
最后,输入以下程序构建新的网络结构:
layers = [ layersTransfer %前保持不变的1-22层 fullyConnectedLayer(numClasses,‘WeightLearnRateFactor‘,20,‘BiasLearnRateFactor‘,20) %新23层,为了加快学习速度,将Weight和Bias的学习率定为20 softmaxLayer %新24层 classificationLayer]; %新25层,默认的loss函数为交叉熵
3、训练网络
(1)调整数据集
在将图片输入神经网络进行训练之前,我们需要进行图片增强,分两步:一是将训练集中的图片平移,翻转,以避免过拟合(overfitting)并记住训练图片的详细特征;二是调整图片尺寸,以与网络的输入层参数相符。
%imageDataAugmenter用于设定数据增强的参数 imageAugmenter = imageDataAugmenter(‘RandXReflection‘,true,‘RandXTranslation‘,[-30,30],‘RandYTranslation‘,[-30,30]); %augmentedImageSource()用于数据增强,第一个入口参数表示增强后数据的输出尺寸,第二个参数表示需要增强的数据,在此是对训练集进行增强。 %注意:该函数仅适用于Matlab2018a,2017b只能用augmentedImageSoure代替 %对训练集数据进行增强操作 augimdsTrain = augmentedImageDatastore (inputSize(1:2),imdsTrain, ‘DataAugmentation‘,imageAugmenter); %对验证集数据进行增强操作 augimdsValidation =augmentedImageSource(inputSize(1:2),imdsTrain );
(2)设置训练方式
在此,将学习率调低,由于之前将最后的全连接层的学习率调得较高,两者的整体效果使得AlexNet中保留的层级训练较慢,更改的层级训练较快:
options = trainingOptions(‘sgdm‘,‘MiniBatchSize‘,10,‘MaxEpochs‘,6,‘InitialLearnRate‘,1e-4,‘ValidationData‘,augimdsValidation,‘ValidationFrequency‘,3,‘ValidationPatience‘,Inf,‘Verbose‘,false,‘Plots‘,‘training-progress‘);
(3)训练网络
netTransfer = trainNetwork(augimdsTrain,layers,options);
运行后的返回值存入netTransfer,即是训练后的网络。
4、网络验证
和例二相似,输入下列代码,在验证集上运行神经网络并计算准确率:
[YPred, scores] = classify(netTransfer,augimdsValidation); YValidation = imdsValidation.Labels; accuracy = mean(YPred == YValidation);
原文地址:https://www.cnblogs.com/Caelum/p/9167506.html