MATLAB深度学习入门之旅

目录

1. 简介

2. 使用预训练网络:使用已创建和训练后的网络进行分类

2.1 课程示例-识别一些图像中的对象

2.1.1  任务1:读取图像

2.1.2  任务2:显示图像

2.2 进行预测

2.2.1  任务1:定义网络

2.2.2  任务2:进行分类

2.3 CNN结构

2.3.1  任务1:提取网络的层

2.3.2  任务2:提取某一层

2.3.3  任务3:提取某一层的某个属性

2.3.4  任务4:图像维度

2.3.5  任务5:提取输出层的类属性

2.4 调查预测

2.4.1  任务1:预测分数

2.4.2  任务2:创建预测分类的条形图

2.4.3  任务3:挑出主要分数

2.4.4  任务4:显示挑选预测分数后的条形图

2.4.4  任务5:为x轴增加类别标签

3 管理数据集:使用已创建和训练后的网络执行分类

3.1 图像数据集

3.1.1  任务1:使用imageDatastore创建数据存储(DataStore)

3.1.2  任务2:获取文件名

3.1.3  任务3:从数据存储(DataStore)中导入某幅图像

3.1.4  任务4:预测数据存储(DataStore)中的所有图像

3.2 准备输入图像

3.2.1  任务1:查看图像大小

3.2.2  任务2:查看网络输入层的输入图像大小

3.2.3  任务3:将输入图像调整至要求大小并显示

3.3 在数据存储(DataStore)中处理图像

3.3.1  创建增强图像数据存储(DataStore)

3.3.2  使用增强的图像数据存储(DataStore)进行颜色预处理

3.4 使用子文件夹创建一个数据存储(DataStore)

3.4.1  任务1:创建数据存储(Data Store)

3.4.2  任务2:分类

4 迁移学习:修改预训练网络对图像分类

4.1 什么是迁移学习?

4.2 迁移学习所需的组件

4.3 准备训练数据

4.3.1  标记图像

4.3.2  分割数据以用于训练和测试

4.4 修改网络层

4.4.1  任务1:使用fullyConnectedLayer函数创建一个新的全连接层

4.4.2  任务2:对层的数组通过索引进行修改

4.4.3  任务3:将输出层与前面的层(第23层)进行匹配

4.5 设置训练选项

4.5.1  任务1:使用trainingOptions设置训练算法的一些选项(一定要查看帮助手册)

4.5.2  任务2:设置初始学习率

4.6 训练网络

4.6.1  mini-batch

4.6.2  使用GPUs

4.6.3  迁移学习示例(脚本)

4.7 评估性能

4.7.1  评估训练和测试性能

4.7.2  调查测试性能


1. 简介

该课程为MATLAB官网免费课程(英文),此笔记只对该课程进行一定的翻译和记录,方便日后复习,如有错误,还请大佬批评指正。官网链接为https://ww2.mathworks.cn/learn/tutorials/deep-learning-onramp.html(深度学习入门之旅)。

2. 使用预训练网络:使用已创建和训练后的网络进行分类

2.1 课程示例-识别一些图像中的对象

本节将学习如何使用预先制作的深度神经网络来分类下面12幅图像的内容。理想的分类应该是“海滩”、“猫”、“纸杯蛋糕”、“湖泊”、“鱼”等等。

2.1.1  任务1:读取图像

I = imread('filename.png');  % 以分号结束将不会打印出结果

2.1.2  任务2:显示图像

imshow(I)

2.2 进行预测

2.2.1  任务1:定义网络

net = alexnet  % 这里的网络模型使用Alexnet

2.2.2  任务2:进行分类

[pred, score] = classify(net,img)  % 将网络和输入图像传入分类函数,将得到输入图像的类别preds以及它在每一类中的预测分数score

2.3 CNN结构

MATLAB将CNN表示为一个层的数组,数组的第一个元素为输入层,最后一个元素为输出层。

2.3.1  任务1:提取网络的层

ly = net.Layers  % 由下图可以看出Alexnet是一个具有25层的数组

2.3.2  任务2:提取某一层

inlayer = ly(1)  % 输入层

layer2 = ly(2)  % 第二层

outlayer = ly(end)  % 分类输出层

2.3.3  任务3:提取某一层的某个属性

insz = inlayer.InputSize  % 输入层的输入图像大小

2.3.4  任务4:图像维度

输入图像是彩色图像,尺寸为:227×227×3。灰度图像的尺寸为227×227。

2.3.5  任务5:提取输出层的类属性

categorynames = outlayer.Classes  % 得到一个列向量,表示Alexnet的1000个类的名字

2.4 调查预测

2.4.1  任务1:预测分数

上面的分类函数classify只是将输入图像预测为某一类,并不知道输入图像是该类的概率。该任务不仅会得到预测分类,还会得出预测分数。

[pred,scrs] = classify(net,img)  % 得到的分数是一个行向量,表示1000个类的预测分数

2.4.2  任务2:创建预测分类的条形图

bar(scrs)

2.4.3  任务3:挑出主要分数

由上图可知,1000个分类中大部分的值为0,仅有少数预测分数不等于0,本任务旨在将主要分数挑选出来,可以创建一个逻辑数组,返回scrs中大于0.01的值

highscores = scrs > 0.01  % 将scrs数组中大于0.01的元素赋为1,其他为0

2.4.4  任务4:显示挑选预测分数后的条形图

bar(scores(highscores))  % scores(highscores)返回大于0.01的类别的预测分数

2.4.5  任务5:为x轴增加类别标签

xticklabels(categorynames(highscores))  % categorynames(highscores) 返回大于0.01的类别的名字

3 管理数据集:使用已创建和训练后的网络执行分类

3.1 图像数据集

3.1.1  任务1:使用imageDatastore创建数据存储(DataStore)

ls *.jpg  % list列出工作空间里与.jpg相关的文件,工作空间中文件夹里的无法列出

net = alexnet;

imds = imageDatastore('*.jpg')  % 使用通配符*指定多个文件。

3.1.2  任务2:获取文件名

fname = imds.Files  % 使用数据存储(DataStore)Files属性获取包含路径的文件名

3.1.3  任务3:从数据存储(DataStore)中导入某幅图像

使用函数:read, readimage, readall可以手动地从数据存储(DataStore)中导入图像

for i = 1:3

    img = read(imds)  % 按顺序依次读取图像,每次仅返回一张图像

end

img = readimage(imds, 7)  % 读取并返回数据存储(DataStore)中的某张(7)图像

img = readall(imds)  % 一次性读取数据存储(DataStore)中的所有图像,返回的并不是图像数据

3.1.4  任务4:预测数据存储(DataStore)中的所有图像

preds = classify(net, imds)

3.2 准备输入图像

由于不同的网络对输入图像的要求不同,所以需要对输入图像进行预处理后再输入网络。

3.2.1  任务1:查看图像大小

img = imread('filename.jpg');

imshow(img)

sz = size(img)  % 返回图像的高度、宽度、通道数

3.2.2  任务2:查看网络输入层的输入图像大小

net = alexnet

ly = net.Layers

insz = ly(1).InputSize

3.2.3  任务3:将输入图像调整至要求大小并显示

img = imresize(img, [r, c]);  % r为行(高度),c为列(宽度)

imshow(img)

3.3 在数据存储(DataStore)中处理图像

上面是对单个图像进行预处理,但平常的数据集中的图像数量相当之大。因此,直接对整个图像数据集进行处理就显得很有必要了。

3.3.1  创建增强图像数据存储(DataStore)

3.3.3.1  任务1:创建数据存储(DataStore)

ls *.jpg

net = alexnet

imds = imageDatastore('*.jpg')

3.3.3.2  任务2:创建增强的图像数据存储(DataStore)

auds = augmentedImageDatastore([r c],imds)  % 数据存储(DataStore)中所有图像的大小统一调整到[r c]大小,特别强调rc没有逗号

3.3.3.3  任务3:对预处理后的图像数据存储(DataStore)进行分类

preds = classify(net, auds)

3.3.2  使用增强的图像数据存储(DataStore)进行颜色预处理

3.3.2.1  任务1:蒙太奇(montage)

ls *.jpg

net = alexnet

montage(imds)  % 使用蒙太奇手法显示数据存储(DataStore)中的所有图像

3.3.2.2  任务2:创建增强图像数据存储(DataStore)

这里做的增强除了调整大小之外,还有灰色图像转换为彩色图像

auds = augmentedImageDatastore([227 227], imds, 'ColorPreprocessing', 'gray2rgb')

3.3.2.3  任务3:对预处理后的图像数据存储(DataStore)进行分类

preds = classify(net, auds)

3.4 使用子文件夹创建一个数据存储(DataStore)

将每一类的图像放在一个子文件夹下,图像已经按照这种格式放置,而非按照这种方式去创建。

3.4.1  任务1:创建数据存储(Data Store)

net = alexnet;

ds = imageDatastore('folder', 'IncludeSubfolders', true)  % folder为图像数据集的路径,使用“IncludeSubfolders”选项在给定文件夹的子文件夹中查找图像。

3.4.2  任务2:分类

preds = classify(net, ds)

4 迁移学习:修改预训练网络对图像分类

4.1 什么是迁移学习?

如果从网络架构和随机权重开始,自己构建和训练网络。但要达到合理的结果需要付出很多努力:(1)网络架构的知识和经验,(2)大量的训练数据,(3)大量的计算机时间。

迁移学习是解决许多问题的有效方法。训练需要一些数据和计算机时间,但比从零开始的培训要少得多,其结果是形成了适合您的特定问题的网络。

4.2 迁移学习所需的组件

三大件:

修改后的网络Network layers

知道标签的训练数据Training data

训练算法Algorithm options

4.3 准备训练数据

将训练数据按照类别数分为一定的子文件夹进行存放,每个子文件夹的名字为相应类别的标签。如下图,花的数据集,包含12个类,所以有12个子文件夹,每个子文件夹的名字为每类花的名字。

4.3.1  标记图像

4.3.1.1  任务1:创建带标签的数据集

load pathToImages  % 加载数据集文件pathToImages.mat

flwrds = imageDatastore(pathToImages,'IncludeSubfolders', true);

flowernames = flwrds.Labels

训练所需的标签可以存储在图像数据存储库的标签属性中。默认情况下,标签属性为空。

通过指定“LabelSource”选项,可以让数据存储自动确定文件夹名称中的标签。如果指定了 'foldernames',将根据文件夹名称分配标签并存储在 Labels 属性中。您以后可以通过直接访问 Labels 属性来修改标签。

flwrds = imageDatastore(pathToImages, 'IncludeSubfolders',true, 'LabelSource', 'foldernames')

4.3.1.2  任务2:提取新的标签

flowernames = flwrds.Labels

4.3.2  分割数据以用于训练和测试

4.3.2.1  任务1:使用splitEachLabel函数分割数据集

[ds1,ds2] = splitEachLabel(imds,p)  % imds是创建的数据存储,p是零一之间的一个比例,返回的ds1imdsp倍,剩下的imds分配给ds2,即ds2imds(1-p)

4.3.2.2  任务2:随机分割分割

[ds1,ds2] = splitEachLabel(imds,p,'randomized')

4.3.2.3  任务3:处理不平衡的训练数据

由于某些数据集在类别上是不平衡的,也即是说,可能有些类的数据多一些,有些类的数据少一些,它们的数目并不是相等的。因此,使用按比例分配的方式主要在数据多的类上进行学习,在数据少的类少学习很少。为了避免这种情况,可以对数据进行分割,使每个类的训练图像具有相等的数量。

[ds1,ds2] = splitEachLabel(imds, n, 'randomized')  % 确保ds1中的每一类都有n个数据,剩下的数据分给ds2, 'randomized'可选

4.4 修改网络层

不同的数据集往往类别数也不同,因此,需要对网络中的某些层进行修改,比如输出层的神经元个数应该修改为数据集的类别数。

4.4.1  任务1:使用fullyConnectedLayer函数创建一个新的全连接层

anet = alexnet;

layers = anet.Layers

fc = fullyConnectedLayer(n)  % n是新建全连接层的神经元个数

4.4.2  任务2:对层的数组通过索引进行修改

layers(23) = fc  % Alexnet的第23层修改为上述新建的全连接层

4.4.3  任务3:将输出层与前面的层(23)进行匹配

layers(end) = classificationLayer  % 使用classificationLayer函数新建一个分类层,并赋给最后一层(输出层),该函数将自动确定输出层的神经元个数

4.5 设置训练选项

4.5.1  任务1:使用trainingOptions设置训练算法的一些选项(一定要查看帮助手册)

opts = trainingOptions(solverName)  % 返回一个由solverName指定的优化器的选项,solverName默认为'sgdm'

还可以设置

options = trainingOptions('sgdm', ...
    'LearnRateSchedule','piecewise', ...  % 学习率减少方案
    'LearnRateDropFactor',0.2, ...
    'LearnRateDropPeriod',5, ...  % 每5个epoch减少0.2倍的学习率
    'MaxEpochs',20, ...  % 最多迭代的epoch数
    'MiniBatchSize',64, ...  % 每个epoch迭代的batchsize

         'Plots','training-progress')

'Plots'设置为'training-progress'时有下图

4.5.2  任务2:设置初始学习率

学习率控制算法改变网络权重的幅度。迁移学习的目标是对现有的网络进行微调,因此通常希望更改权重,而不是像从头开始训练时那样大刀阔斧。

opts = trainingOptions('sgdm','Name', value)  % 指定训练选项的名称'Name'和值value(相当于字典的键值对)

opts = trainingOptions('sgdm', 'InitialLearnRate', 0.001)

4.6 训练网络

4.6.1  mini-batch

mini-batch是指在每一次迭代过程中,用到的部分训练集。每次迭代都会使用不同的mini-batch。当整个数据集都被使用过一次后,这样的一个周期称为epoch。训练多少个周期可以通过设置'MaxEpochs'来实现。

值得注意的是,损失和准确率是针对当前的mini-batch而言的,而非整个训练集的平均

默认在划分mini-batch之前,通常会对数据集进行洗牌,你可以通过shuffle选项来设置。

4.6.2  使用GPUs

GPU可以显著提高深度学习的计算性能。如果你的计算机不支持GPU的话,MATLAB将会在CPU上执行训练过程,不过这会花费大量的时间。

4.6.3  迁移学习示例(脚本)

  • 获取训练图像

flower_ds = imageDatastore('Flowers','IncludeSubfolders',true,'LabelSource','foldernames');

[trainImgs,testImgs] = splitEachLabel(flower_ds,0.6);

numClasses = numel(categories(flower_ds.Labels));  % 这句话是前面没有的,目的是取类别数。numel表示取数组的元素数目,categories返回一个字符向量元胞数组,其中包含分类数组的类别。

  • 创建一个修改后的Alexnet

net = alexnet;

layers = net.Layers;

layers(end-2) = fullyConnectedLayer(numClasses);

layers(end) = classificationLayer;

  • 设置训练算法选项

options = trainingOptions('sgdm','InitialLearnRate', 0.001);

  • 执行训练

[flowernet,info] = trainNetwork(trainImgs, layers, options);  % flowernet是训练后的网络(具有新的参数)info是训练信息(包含训练损失、准确率等信息)

  • 使用训练网络去分类测试图像

testpreds = classify(flowernet,testImgs);

4.7 评估性能

4.7.1  评估训练和测试性能

4.7.1.1  任务1:画出训练损失(位于info的TrainingLoss中)

load pathToImages

load trainedFlowerNetwork flowernet info

plot(info.TrainingLoss)

4.7.1.2  任务2:分类图像

dsflowers =imageDatastore(pathToImages,'IncludeSubfolders',true,'LabelSource', 'foldernames');

[trainImgs,testImgs] = splitEachLabel(dsflowers,0.98);

flwrPreds = classify(flowernet,testImgs)

4.7.2  调查测试性能

4.7.2.1  任务1:提取测试数据集的标签

load pathToImages.mat

pathToImages

flwrds = imageDatastore(pathToImages,'IncludeSubfolders',true,'LabelSource', 'foldernames');

[trainImgs,testImgs] = splitEachLabel(flwrds,0.98);

load trainedFlowerNetwork flwrPreds

flwrActual = testImgs.Labels  % trainImgs,testImgs是对数据存储进行划分得到的,所以它们具有数据存储的相关属性

4.7.2.2  任务2:计算正确个数

numCorrect = nnz(flwrActual == flwrPreds)  % nnz函数返回的是矩阵非零元素的数目,flwrActual == flwrPreds将得到一个0-1矩阵

4.7.2.3  任务3:计算正确率

fracCorrect = numCorrect/numel(flwrPreds)  % 就是正确个数除以测试数据的个数

上面的计算有些麻烦,先改写为:

mean(flwrActual == flwrPreds)

4.7.2.4  任务4:显示预测分类的混淆矩阵

混淆矩阵又称误差矩阵,矩阵中的元素(j,k)表示第j个类被预测为第k个类的数目,主对角线的元素表示正确预测,其余元素表示误分类。

confusionchart(knownclass,predictedclass)  % 第一个参数为已知类,即flwrActual;第二个参数为预测类,即flwrPreds

 

 

 

 

 

 

 

 

 

 

 

 

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页