Main Content

squeezenet

SqueezeNet 卷积神经网络

  • SqueezeNet network architecture

说明

SqueezeNet 是深度为 18 层的卷积神经网络。您可以从 ImageNet 数据库 [1] 中加载该网络的预训练版本,该版本基于 ImageNet 数据库的超过一百万个图像进行训练。该预训练网络可以将图像分类至 1000 个目标类别(例如键盘、鼠标、铅笔和多种动物)。因此,该网络已基于大量图像学习了丰富的特征表示。此函数返回一个 SqueezeNet v1.1 网络,它具有与 SqueezeNet v1.0 相似的准确度,但每次预测需要更少的浮点运算 [3]。该网络的图像输入大小为 227×227。有关 MATLAB® 中预训练网络的详细信息,请参阅预训练的深度神经网络

您可以通过 classify 使用 SqueezeNet 网络对新图像进行分类。有关示例,请参阅使用 SqueezeNet 对图像进行分类

您可以使用迁移学习来重新训练 SqueezeNet 网络以执行新任务。有关示例,请参阅使用 SqueezeNet 进行交互式迁移学习

示例

net = squeezenet 返回基于 ImageNet 数据集训练的 SqueezeNet 网络。

net = squeezenet('Weights','imagenet') 返回基于 ImageNet 数据集训练的 SqueezeNet 网络。此语法等效于 net = squeezenet

lgraph = squeezenet('Weights','none') 返回未经训练的 SqueezeNet 网络架构。

示例

全部折叠

加载一个预训练的 SqueezeNet 网络。

net = squeezenet
net = 

  DAGNetwork with properties:

         Layers: [68×1 nnet.cnn.layer.Layer]
    Connections: [75×2 table]

此函数返回一个 DAGNetwork 对象。

SqueezeNet 包含在 Deep Learning Toolbox™ 中。要加载其他网络,请使用 googlenet 等函数来获取链接,以便从附加功能资源管理器下载预训练网络。

此示例说明如何微调预训练的 SqueezeNet 网络以对新的图像集合进行分类。此过程称为迁移学习,通常比训练新网络更快更容易,因为您可以使用较少数量的训练图像将已学习的特征应用于新任务。要以交互方式准备用于迁移学习的网络,请使用深度网络设计器。

提取数据

在工作区中,提取 MathWorks Merch 数据集。这是包含 75 幅 MathWorks 商品图像的小型数据集,这些商品分属五个不同类(瓶盖魔方扑克牌螺丝刀手电筒)。

unzip("MerchData.zip");

在深度网络设计器中打开 SqueezeNet

用 SqueezeNet 打开深度网络设计器。

deepNetworkDesigner(squeezenet);

深度网络设计器在设计器窗格中显示整个网络的缩小视图。

浏览网络图。要使用鼠标放大,请使用 Ctrl + 滚轮。要平移,请使用箭头键,或按住滚轮并拖动鼠标。选择一个层以查看其属性。取消选择所有层,以在属性窗格中查看网络摘要。

导入数据

要将数据加载到深度网络设计器中,请在数据选项卡上,点击导入数据 > 导入图像分类数据

数据源列表中,选择文件夹。点击浏览并选择提取的 MerchData 文件夹。

将数据分为 70% 用作训练数据,30% 用作验证数据。

指定要对训练图像执行的增强操作。对于此示例,在 x 轴上进行随机翻转,在 [-90,90] 度范围内进行随机旋转,在 [1,2] 范围内进行随机重新缩放。数据增强有助于防止网络过拟合和记忆训练图像的具体细节。

点击导入将数据导入深度网络设计器。

可视化数据

使用深度网络设计器,您可以在数据选项卡中直观地查看训练和验证数据的分布情况。您还可以查看随机观测值及其标签作为训练前的一项简单检查。您可以看到在此示例中数据集中有五个类。

编辑迁移学习网络

网络的卷积层会提取最后一个可学习层和最终分类层用来对输入图像进行分类的图像特征。SqueezeNet 中的 'conv10''ClassificationLayer_predictions' 这两个层包含有关如何将网络提取的特征合并成类概率、损失值和预测标签的信息。要对预训练网络进行重新训练以对新图像进行分类,请使这两层适应新数据集。

要使用预训练网络进行迁移学习,您必须更改类的数量以匹配新数据集。首先,选择 'conv10' 层。在属性窗格的底部,点击解锁层。在出现的警告对话框中,点击仍要解锁。这将解锁层属性,以便您可以使其适应新任务。

在 R2023b 之前:要编辑层属性,您必须替换层,而不是解锁层。在新的卷积二维层中,将 FilterSize 设置为 [1 1]。

NumFilters 属性定义用于分类问题的类的数量。将 NumFilters 更改为新数据中的类数量,此示例中为 5

通过将 WeightLearnRateFactorBiasLearnRateFactor 设置为 10 来更改学习率,使新层中的学习速度快于迁移层的学习速度。

接下来,配置输出层。选择最终分类层 ClassificationLayer_predictions,点击解锁层,然后点击仍要解锁。对于解锁的输出层,不需要设置 OutputSize。在训练时,深度网络设计器会根据数据自动设置层的输出类。

检查网络

要确保编辑后的网络已准备好训练,请点击分析,并确保深度学习网络分析器报告零错误。

训练网络

指定训练选项。选择训练选项卡,然后点击训练选项

  • 将初始学习率设置为较小的值以减慢迁移的层中的学习速度。

  • 指定验证频率,以便每经过一轮训练就计算一次基于验证数据的准确度。

  • 指定少量轮数。一轮训练是对整个训练数据集的一个完整训练周期。对于迁移学习,所需的训练轮数相对较少。

  • 指定小批量大小,即每次迭代中使用多少个图像。为了确保在每轮训练中都使用整个数据集,请设置小批量大小以均分训练样本的数量。

对于此示例,将 InitialLearnRate 设置为 0.0001MaxEpochs 设置为 8ValidationFrequency 设置为 5。由于有 55 个观测值,请将 MiniBatchSize 设置为 11

要使用指定的训练选项训练网络,请点击确定,然后点击训练

深度网络设计器允许您可视化和监控训练进度。然后,如果需要,您可以编辑训练选项并重新训练网络。

导出结果并生成 MATLAB 代码

要导出具有训练权重的网络架构,请在训练选项卡上,选择导出 > 导出经过训练的网络和结果。深度网络设计器将经过训练的网络导出为变量 trainedNetwork_1,将训练信息导出为变量 trainInfoStruct_1

您也可以生成 MATLAB 代码,它可以重新创建所使用的网络和训练选项。在训练选项卡上,选择导出 > 生成训练代码。查看 MATLAB 代码,了解如何以编程方式准备训练数据、创建网络架构和训练网络。

对新图像进行分类

加载一个新图像以使用经过训练的网络对其进行分类。

I = imread("MerchDataTest.jpg");

深度网络设计器会在训练期间调整图像大小,以匹配网络输入大小。要查看网络输入大小,请转至设计器窗格,然后选择 imageInputLayer(第一层)。该网络的输入大小为 227×227。

调整测试图像的大小以匹配网络输入大小。

I = imresize(I, [227 227]);

使用经过训练的网络对测试图像进行分类。

[YPred,probs] = classify(trainedNetwork_1,I);
imshow(I)
label = YPred;
title(string(label) + ", " + num2str(100*max(probs),3) + "%");

此示例说明如何微调预训练的 SqueezeNet 卷积神经网络以对新的图像集合执行分类。

SqueezeNet 已基于超过一百万个图像进行训练,可以将图像分为 1000 个对象类别(例如键盘、咖啡杯、铅笔和多种动物)。该网络已基于大量图像学习了丰富的特征表示。网络以图像作为输入,然后输出图像中对象的标签以及每个对象类别的概率。

深度学习应用中常常用到迁移学习。您可以采用预训练的网络,基于它学习新任务。与使用随机初始化的权重从头训练网络相比,通过迁移学习微调网络要更快更简单。您可以使用较少数量的训练图像快速地将已学习的特征迁移到新任务。

加载数据

解压缩新图像并加载这些图像作为图像数据存储。imageDatastore 根据文件夹名称自动标注图像,并将数据存储为 ImageDatastore 对象。通过图像数据存储可以存储大图像数据,包括无法放入内存的数据,并在卷积神经网络的训练过程中高效分批读取图像。

unzip('MerchData.zip');
imds = imageDatastore('MerchData', ...
    'IncludeSubfolders',true, ...
    'LabelSource','foldernames');

将数据划分为训练数据集和验证数据集。将 70% 的图像用于训练,30% 的图像用于验证。splitEachLabelimages 数据存储拆分为两个新的数据存储。

[imdsTrain,imdsValidation] = splitEachLabel(imds,0.7,'randomized');

这个非常小的数据集现在包含 55 个训练图像和 20 个验证图像。显示一些示例图像。

numTrainImages = numel(imdsTrain.Labels);
idx = randperm(numTrainImages,16);

I = imtile(imds, 'Frames', idx);

figure
imshow(I)

Figure contains an axes object. The axes object contains an object of type image.

加载预训练网络

加载预训练的 SqueezeNet 神经网络。

net = squeezenet;

使用 analyzeNetwork 可以交互可视方式呈现网络架构以及有关网络层的详细信息。

analyzeNetwork(net)

第一层(图像输入层)需要大小为 227×227×3 的输入图像,其中 3 是颜色通道数。

inputSize = net.Layers(1).InputSize
inputSize = 1×3

   227   227     3

替换最终层

网络的卷积层会提取最后一个可学习层和最终分类层用来对输入图像进行分类的图像特征。SqueezeNet 中的 'conv10''ClassificationLayer_predictions' 这两个层包含有关如何将网络提取的特征合并成类概率、损失值和预测标签的信息。要对预训练网络进行重新训练以对新图像进行分类,请将这两个层替换为适合新数据集的新层。

从经过训练的网络中提取层图。

lgraph = layerGraph(net); 

查找要替换的两个层的名称。您可以手动执行此操作,也可以使用支持函数 findLayersToReplace 自动查找这两个层。

[learnableLayer,classLayer] = findLayersToReplace(lgraph);
[learnableLayer,classLayer] 
ans = 
  1x2 Layer array with layers:

     1   'conv10'                            2-D Convolution         1000 1x1x512 convolutions with stride [1  1] and padding [0  0  0  0]
     2   'ClassificationLayer_predictions'   Classification Output   crossentropyex with 'tench' and 999 other classes

在大多数网络中,具有可学习权重的最后一层是全连接层。而在某些网络(如 SqueezeNet)中,最后一个可学习层是一个 1×1 卷积层。在这种情况下,请将该卷积层替换为新的卷积层,其中滤波器的数量等于类的数量。要使新层中的学习速度快于迁移的层,请增大卷积层的 WeightLearnRateFactorBiasLearnRateFactor 值。

numClasses = numel(categories(imdsTrain.Labels))
numClasses = 5
newConvLayer =  convolution2dLayer([1, 1],numClasses,'WeightLearnRateFactor',10,'BiasLearnRateFactor',10,"Name",'new_conv');
lgraph = replaceLayer(lgraph,'conv10',newConvLayer);

分类层指定网络的输出类。将分类层替换为没有类标签的新分类层。trainNetwork 会在训练时自动设置层的输出类。

newClassificatonLayer = classificationLayer('Name','new_classoutput');
lgraph = replaceLayer(lgraph,'ClassificationLayer_predictions',newClassificatonLayer);

训练网络

网络要求输入图像的大小为 227×227×3,但图像数据存储中的图像具有不同大小。使用增强的图像数据存储可自动调整训练图像的大小。指定要对训练图像额外执行的增强操作:沿垂直轴随机翻转训练图像,以及在水平和垂直方向上随机平移训练图像最多 30 个像素。数据增强有助于防止网络过拟合和记忆训练图像的具体细节。

pixelRange = [-30 30];
imageAugmenter = imageDataAugmenter( ...
    'RandXReflection',true, ...
    'RandXTranslation',pixelRange, ...
    'RandYTranslation',pixelRange);
augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain, ...
    'DataAugmentation',imageAugmenter);

要在不执行进一步数据增强的情况下自动调整验证图像的大小,请使用增强的图像数据存储,而不指定任何其他预处理操作。

augimdsValidation = augmentedImageDatastore(inputSize(1:2),imdsValidation);

指定训练选项。对于迁移学习,请保留预训练网络的较浅层中的特征(迁移的层权重)。要减慢迁移的层中的学习速度,请将初始学习速率设置为较小的值。在上一步中,您增大了卷积层的学习率因子,以加快新的最终层中的学习速度。这种学习率设置组合只会加快新层中的学习速度,对于其他层则会减慢学习速度。执行迁移学习时,所需的训练轮数相对较少。一轮训练是对整个训练数据集的一个完整训练周期。将小批量大小指定为 11,以便在每轮训练中考虑所有数据。软件在训练过程中每 ValidationFrequency 次迭代验证一次网络。

options = trainingOptions('sgdm', ...
    'MiniBatchSize',11, ...
    'MaxEpochs',7, ...
    'InitialLearnRate',2e-4, ...
    'Shuffle','every-epoch', ...
    'ValidationData',augimdsValidation, ...
    'ValidationFrequency',3, ...
    'Verbose',false, ...
    'Plots','training-progress');

训练由迁移层和新层组成的网络。默认情况下,trainNetwork 使用 GPU(如果有)。这需要 Parallel Computing Toolbox™ 和支持的 GPU 设备。有关受支持设备的信息,请参阅GPU Computing Requirements (Parallel Computing Toolbox)。否则,trainNetwork 将使用 CPU。您还可以使用 trainingOptions'ExecutionEnvironment' 名称-值对组参数指定执行环境。

netTransfer = trainNetwork(augimdsTrain,lgraph,options);

Figure Training Progress (19-Aug-2023 11:48:09) contains 2 axes objects and another object of type uigridlayout. Axes object 1 with xlabel Iteration, ylabel Loss contains 14 objects of type patch, text, line. Axes object 2 with xlabel Iteration, ylabel Accuracy (%) contains 14 objects of type patch, text, line.

对验证图像进行分类

使用经过微调的网络对验证图像进行分类。

[YPred,scores] = classify(netTransfer,augimdsValidation);

显示四个示例验证图像及预测的标签。

idx = randperm(numel(imdsValidation.Files),4);
figure
for i = 1:4
    subplot(2,2,i)
    I = readimage(imdsValidation,idx(i));
    imshow(I)
    label = YPred(idx(i));
    title(string(label));
end

Figure contains 4 axes objects. Axes object 1 with title MathWorks Playing Cards contains an object of type image. Axes object 2 with title MathWorks Playing Cards contains an object of type image. Axes object 3 with title MathWorks Cube contains an object of type image. Axes object 4 with title MathWorks Cube contains an object of type image.

计算针对验证集的分类准确度。准确度是网络预测正确的标签的比例。

YValidation = imdsValidation.Labels;
accuracy = mean(YPred == YValidation)
accuracy = 1

有关提高分类准确度的提示,请参阅Deep Learning Tips and Tricks

使用 SqueezeNet 对图像进行读取、调整大小和分类。

首先,加载一个预训练的 SqueezeNet 模型。

net = squeezenet;

使用 imread 读取图像。

I = imread('peppers.png');
figure
imshow(I)

Figure contains an axes object. The axes object contains an object of type image.

预训练模型要求图像大小与网络的输入大小相同。使用网络第一层的 InputSize 属性确定网络的输入大小。

sz = net.Layers(1).InputSize
sz = 1×3

   227   227     3

将图像大小调整为网络的输入大小。

I = imresize(I,sz(1:2));
figure
imshow(I)

Figure contains an axes object. The axes object contains an object of type image.

使用 classify 对图像进行分类。

label = classify(net,I)
label = categorical
     bell pepper 

将图像和分类结果一起显示。

figure
imshow(I)
title(label)

Figure contains an axes object. The axes object with title bell pepper contains an object of type image.

此示例说明如何从预训练的卷积神经网络中提取已学习的图像特征,并使用这些特征来训练图像分类器。

特征提取是使用预训练深度网络的表征能力的最简单最快捷的方式。例如,您可以使用 fitcecoc(Statistics and Machine Learning Toolbox™) 基于提取的特征来训练支持向量机 (SVM)。由于特征提取只需要遍历一次数据,因此如果没有 GPU 来加速网络训练,则不妨从特征提取开始。

加载数据

解压缩示例图像并加载这些图像作为图像数据存储。imageDatastore 根据文件夹名称自动标注图像,并将数据存储为 ImageDatastore 对象。通过图像数据存储可以存储大图像数据,包括无法放入内存的数据。将数据拆分,其中 70% 用作训练数据,30% 用作测试数据。

unzip("MerchData.zip");

imds = imageDatastore("MerchData", ...
    IncludeSubfolders=true, ...
    LabelSource="foldernames");

[imdsTrain,imdsTest] = splitEachLabel(imds,0.7,"randomized");

这个非常小的数据集现在具有 55 个训练图像和 20 个验证图像。显示一些示例图像。

numImagesTrain = numel(imdsTrain.Labels);
idx = randperm(numImagesTrain,16);

I = imtile(imds,"Frames",idx);

figure
imshow(I)

加载预训练网络

加载一个预训练的 SqueezeNet 网络。SqueezeNet 已基于超过一百万个图像进行训练,可以将图像分为 1000 个对象类别(例如键盘、鼠标、铅笔和多种动物)。因此,该模型已基于大量图像学习了丰富的特征表示。

net = squeezenet;

分析网络架构。

analyzeNetwork(net)

2022-01-07_16-31-30.png

第一层(图像输入层)需要大小为 227×227×3 的输入图像,其中 3 是颜色通道数。

inputSize = net.Layers(1).InputSize
inputSize = 1×3

   227   227     3

提取图像特征

网络构造输入图像的分层表示。层越深,包含的特征级别就越高,这些层使用较浅层的较低级别特征构建而成。要获得训练图像和测试图像的特征表示,请对全局平均池化层 "pool10" 使用 activations。要获得图像的较低级别表示,请使用网络中较浅的层。

网络要求输入图像的大小为 227×227×3,但图像数据存储中的图像具有不同大小。要在将训练图像和测试图像输入到网络之前自动调整它们的大小,请创建增强的图像数据存储,指定所需的图像大小,并将这些数据存储用作 activations 的输入参数。

augimdsTrain = augmentedImageDatastore(inputSize(1:2),imdsTrain);
augimdsTest = augmentedImageDatastore(inputSize(1:2),imdsTest);

layer = "pool10";
featuresTrain = activations(net,augimdsTrain,layer,OutputAs="rows");
featuresTest = activations(net,augimdsTest,layer,OutputAs="rows");

从训练数据和测试数据中提取类标签。

TTrain = imdsTrain.Labels;
TTest = imdsTest.Labels;

拟合图像分类器

使用从训练图像中提取的特征作为预测变量,并使用 fitcecoc (Statistics and Machine Learning Toolbox) 拟合多类支持向量机 (SVM)。

mdl = fitcecoc(featuresTrain,TTrain);

对测试图像进行分类

使用经过训练的 SVM 模型和从测试图像中提取的特征对测试图像进行分类。

YPred = predict(mdl,featuresTest);

显示四个示例测试图像及预测的标签。

idx = [1 5 10 15];
figure
for i = 1:numel(idx)
    subplot(2,2,i)
    I = readimage(imdsTest,idx(i));
    label = YPred(idx(i));
    
    imshow(I)
    title(label)
end

计算针对测试集的分类准确度。准确度是网络预测正确的标签的比例。

accuracy = mean(YPred == TTest)
accuracy = 0.9500

此 SVM 有很高的准确度。如果使用特征提取时的准确度不够高,则尝试迁移学习。

输出参数

全部折叠

预训练 SqueezeNet 卷积神经网络,以 DAGNetwork 对象形式返回。

未经训练的 SqueezeNet 卷积神经网络架构,以 LayerGraph 对象形式返回。

参考

[1] ImageNet. http://www.image-net.org

[2] Iandola, Forrest N., Song Han, Matthew W. Moskewicz, Khalid Ashraf, William J. Dally, and Kurt Keutzer. "SqueezeNet: AlexNet-level accuracy with 50x fewer parameters and <0.5 MB model size." Preprint, submitted November 4, 2016. https://arxiv.org/abs/1602.07360.

[3] Iandola, Forrest N. "SqueezeNet." https://github.com/forresti/SqueezeNet.

扩展功能

版本历史记录

在 R2018a 中推出