主要内容

使用SSD深度学习对象检测

这个例子展示了如何训练一枪检测器(SSD)。

概述

深度学习是一个功能强大的机器学习技术,自动学习图像特征检测所需的任务。有几个对象检测使用深度学习的技巧,例如R-CNN更快,你只看一次(YOLO v2意思),和SSD。这个例子列车SSD车辆探测器使用trainSSDObjectDetector函数。有关更多信息,请参见对象检测

下载Pretrained探测器

下载pretrained检测器来避免等待培训完成。如果你想训练检测器,设置doTraining变量为true。

doTraining = false;如果~ doTraining & & ~存在(“ssdResNet50VehicleExample_22b.mat”,“文件”)disp (“下载pretrained检测器(44 MB)…”);pretrainedURL =“//www.tatmou.com/金宝appsupportfiles/vision/data/ssdResNet50VehicleExample_22b.mat”;websave (“ssdResNet50VehicleExample_22b.mat”,pretrainedURL);结束

加载数据集

这个例子使用一个小型车辆的数据集,其中包含295张图片。这些图片来自加州理工学院的汽车1999年和2001年的数据集,由Pietro Perona一起提供,经允许使用。每个图像都包含一个或两个标签的实例。一个小数据集用于探索SSD训练过程,但在实践中,需要更多的标记图像训练一个健壮的探测器。

解压缩vehicleDatasetImages.zipdata =负载(“vehicleDatasetGroundTruth.mat”);vehicleDataset = data.vehicleDataset;

训练数据存储在一个表中。第一列包含图像文件的路径。剩下的列包含车辆的ROI标签。显示的前几行数据。

vehicleDataset (1:4,:)
ans =4×2表imageFilename车辆_________________________________ _________________ {' vehicleImages / image_00001.jpg '} {[220 136 35 28]} {' vehicleImages / image_00002.jpg '} {[45 175 126 61]} {' vehicleImages / image_00003.jpg '} {[45 108 120 33]} {' vehicleImages / image_00004.jpg '} {[124 112 38 36]}

将数据集分为训练集训练检测器和评估探测器的测试集。选择60%的数据进行训练。其余的用于评估。

rng (0);shuffledIndices = randperm(高度(vehicleDataset));地板idx =(0.6 *长度(shuffledIndices));trainingData = vehicleDataset (shuffledIndices (1: idx):);testData = vehicleDataset (shuffledIndices (idx + 1:结束):);

使用imageDatastoreboxLabelDatastore加载图片和标签数据在训练和评估。

imdsTrain = imageDatastore (trainingData {:,“imageFilename”});bldsTrain = boxLabelDatastore (trainingData (:,“汽车”));imdsTest = imageDatastore (testData {:,“imageFilename”});bldsTest = boxLabelDatastore (testData (:,“汽车”));

结合图像和数据存储盒标签。

trainingData =结合(imdsTrain bldsTrain);testData =结合(imdsTest bldsTest);

标签显示的一个训练图像和盒子。

data =阅读(trainingData);我={1}数据;bbox ={2}数据;annotatedImage = insertShape(我“矩形”,bbox);annotatedImage = imresize (annotatedImage 2);图imshow (annotatedImage)

图包含一个坐标轴对象。坐标轴对象包含一个类型的对象的形象。

创建一个SSD对象检测网络

使用ssdObjectDetector函数自动创建一个SSD对象探测器。ssdObjectDetector需要你指定SSD几个输入参数化对象探测器,包括基本网络也称为特征提取网络,输入大小、类名、锚箱和检测网络来源。使用特定的层从输入基础网络指定检测网络来源。检测网络会自动连接到输入基地网络ssdObjectDetector函数。

特征提取网络通常是一个pretrained CNN(见Pretrained深层神经网络(深度学习工具箱)更多的细节)。这个示例使用ResNet-50特征提取。其他pretrained网络也可以使用如MobileNet v2或ResNet-18取决于应用程序的需求。检测子是一个小的CNN与特征提取网络和由一些特定于SSD卷积的一层又一层。

网= resnet50 ();lgraph = layerGraph(净);

在选择网络输入大小,考虑训练图像的大小,计算成本的处理数据选择大小。在可行的情况下,选择一个网络输入大小接近训练图像的大小。然而,减少运行这个示例的计算成本,网络输入大小选择(300 300)。在培训期间,trainSSDObjectDetector自动调整训练图像,网络输入的大小。

inputSize = (300 300 3);

定义对象类检测。

一会= {“汽车”};

从ResNet-50删除额外的层网络和添加额外的层为学习基础网络更健壮的检测。

iRemoveLayers()helper函数将提到层后删除层layerGraph对象。我们需要这个函数删除分类和完全连接层从pretrained网络像ResNet-50准备用于骨干网。进行特征提取主干网络更健壮的我们将添加7额外卷积层. .

ssdLayerGraph = iRemoveLayers (lgraph,“activation_40_relu”);weightsInitializerValue =“glorot”;biasInitializerValue =“零”;%添加额外的层的基础网络。extraLayers = [];%添加conv6_1和相应reLUfilterSize = 1;numFilters = 256;numChannels = 1024;conv6_1 = convolution2dLayer (filterSize、numFilters NumChannels = NumChannels,Name =“conv6_1”,WeightsInitializer = weightsInitializerValue,BiasInitializer = biasInitializerValue);relu6_1 = reluLayer (Name =“relu6_1”);extraLayers = [extraLayers;conv6_1;relu6_1];%添加conv6_2和相应reLUfilterSize = 3;numFilters = 512;numChannels = 256;conv6_2 = convolution2dLayer (filterSize、numFilters NumChannels = NumChannels,填充= iSamePadding (filterSize),步= (2,2),Name =“conv6_2”,WeightsInitializer = weightsInitializerValue,BiasInitializer = biasInitializerValue);relu6_2 = reluLayer (Name =“relu6_2”);extraLayers = [extraLayers;conv6_2;relu6_2];%添加conv7_1和相应reLUfilterSize = 1;numFilters = 128;numChannels = 512;conv7_1 = convolution2dLayer (filterSize、numFilters NumChannels = NumChannels,Name =“conv7_1”,WeightsInitializer = weightsInitializerValue,BiasInitializer = biasInitializerValue);relu7_1 = reluLayer (Name =“relu7_1”);extraLayers = [extraLayers;conv7_1;relu7_1];%添加conv7_2和相应reLUfilterSize = 3;numFilters = 256;numChannels = 128;conv7_2 = convolution2dLayer (filterSize、numFilters NumChannels = NumChannels,填充= iSamePadding (filterSize),步= (2,2),Name =“conv7_2”,WeightsInitializer = weightsInitializerValue,BiasInitializer = biasInitializerValue);relu7_2 = reluLayer (Name =“relu7_2”);extraLayers = [extraLayers;conv7_2;relu7_2];%添加conv8_1和相应reLUfilterSize = 1;numFilters = 128;numChannels = 256;conv8_1 = convolution2dLayer (filterSize、numFilters NumChannels = NumChannels,Name =“conv8_1”,WeightsInitializer = weightsInitializerValue,BiasInitializer = biasInitializerValue);relu8_1 = reluLayer (Name =“relu8_1”);extraLayers = [extraLayers;conv8_1;relu8_1];%添加conv8_2和相应reLUfilterSize = 3;numFilters = 256;numChannels = 128;conv8_2 = convolution2dLayer (filterSize、numFilters NumChannels = NumChannels,Name =“conv8_2”,WeightsInitializer = weightsInitializerValue,BiasInitializer = biasInitializerValue);relu8_2 = reluLayer (Name =“relu8_2”);extraLayers = [extraLayers;conv8_2;relu8_2];%添加conv9_1和相应reLUfilterSize = 1;numFilters = 128;numChannels = 256;conv9_1 = convolution2dLayer (filterSize、numFilters NumChannels = NumChannels,填充= iSamePadding (filterSize),Name =“conv9_1”,WeightsInitializer = weightsInitializerValue,BiasInitializer = biasInitializerValue);relu9_1 = reluLayer (“名字”,“relu9_1”);extraLayers = [extraLayers;conv9_1;relu9_1];如果~ isempty (extraLayers) lastLayerName = ssdLayerGraph.Layers(结束). name;ssdLayerGraph = addLayers (ssdLayerGraph extraLayers);ssdLayerGraph = connectLayers (ssdLayerGraph、lastLayerName extraLayers (1) . name);结束

指定的网络层的名字从检测网络源将被添加。

detNetworkSource = [“activation_22_relu”,“activation_40_relu”,“relu6_2”,“relu7_2”,“relu8_2”];

指定锚箱。锚箱(M×1单元阵列)数必须相同(M)检测网络源数。

anchorBoxes ={(60岁30;30、60;60岁,21岁,42岁,30);(60 111;60111;111年,35;64年,60岁,111年,42岁,78年,60岁);[162111,111162,162,64,94111,162,78,115111];(213162;162213;213年,94;123162;213115;151162);(264213;213264;264151;187213)};

创建SSD对象探测器对象。

探测器= ssdObjectDetector (ssdLayerGraph,一会,anchorBoxes DetectionNetworkSource = detNetworkSource InputSize = InputSize ModelName =“ssdVehicle”);

数据增加

数据增加用于提高网络精度通过随机改变原始数据在训练。通过使用数据,您可以添加更多的各种训练数据而不必实际增加标记训练样本的数量。使用变换增加训练数据

  • 随机翻箱标签相关的形象和水平。

  • 随机规模相关的图片,箱标签。

  • 抖动图像颜色。

注意数据增加不是应用到测试数据。理想情况下,应该代表的原始数据和测试数据修改的公正的评价。

augmentedTrainingData =变换(trainingData @augmentData);

可视化增强训练数据通过阅读多次相同的图像。

augmentedData =细胞(4,1);k = 1:4 data =阅读(augmentedTrainingData);augmentedData {k} = insertShape(矩形数据{1},{2}=数据);重置(augmentedTrainingData);结束图蒙太奇(augmentedData BorderSize = 10)

图包含一个坐标轴对象。坐标轴对象包含一个类型的对象的形象。

训练数据进行预处理

预处理增强训练数据为培训做准备。

preprocessedTrainingData =变换(augmentedTrainingData @(数据)preprocessData(数据、inputSize));

阅读训练数据预处理。

data =阅读(preprocessedTrainingData);

显示图像和边界框。

我={1}数据;bbox ={2}数据;annotatedImage = insertShape(我“矩形”,bbox);annotatedImage = imresize (annotatedImage 2);图imshow (annotatedImage)

图包含一个坐标轴对象。坐标轴对象包含一个类型的对象的形象。

火车SSD对象探测器

使用trainingOptions指定网络培训选项。集“CheckpointPath”到一个临时位置。这使得储蓄的部分训练过程中训练有素的探测器。如果中断训练,如停电或系统故障,你可以从保存的检查点恢复训练。

选择= trainingOptions (“个”,MiniBatchSize = 16,InitialLearnRate = 1 e - 3,LearnRateSchedule =“分段”,LearnRateDropPeriod = 30,LearnRateDropFactor = 0.8,MaxEpochs = 20,VerboseFrequency = 50,CheckpointPath = tempdir,洗牌=“every-epoch”);

使用trainSSDObjectDetector功能训练对象探测器如果SSDdoTraining为true。否则,加载一个pretrained网络。

如果doTraining%训练SSD探测器。[探测器,信息]= trainSSDObjectDetector (preprocessedTrainingData、探测器、期权);其他的%负载pretrained检测器的例子。pretrained =负载(“ssdResNet50VehicleExample_22b.mat”);探测器= pretrained.detector;结束

这个例子验证在NVIDIA™泰坦X GPU 12 GB的内存。如果你的GPU内存更少,你可能会耗尽内存。如果发生这种情况,降低的MiniBatchSize的使用trainingOptions函数。培训这个网络使用这个设置了大约2个小时。训练时间要取决于您所使用的硬件。

作为一个快速测试,运行探测器在一个测试图像。

data =阅读(testData);我={1 1}数据;我= imresize(我inputSize (1:2));[bboxes,分数]=检测(探测器,I);

显示结果。

我= insertObjectAnnotation (,“矩形”bboxes,分数);图imshow(我)

图包含一个坐标轴对象。坐标轴对象包含一个类型的对象的形象。

评估探测器使用测试集

评估培训对象探测器在大组图像测量性能。计算机视觉工具箱™提供了对象探测器评价函数来测量常见的指标,如平均精度(evaluateDetectionPrecision)和log-average错过率(evaluateDetectionMissRate)。对于这个示例,使用平均精度指标来评估性能。的平均精度提供了一个数字,包含探测器的能力做出正确的分类(精度)和探测器的能力找到所有相关对象(回忆)。

应用相同的预处理变换的测试数据作为训练数据。注意数据增加不是应用到测试数据。测试数据应该代表原始数据和修改的公正的评价。

preprocessedTestData =变换(testData @(数据)preprocessData(数据、inputSize));

所有的测试图像上运行探测器。

detectionResults =检测(探测器,preprocessedTestData MiniBatchSize = 32);

评估对象探测器使用平均精度指标。

[据美联社、召回、精密]= evaluateDetectionPrecision (detectionResults preprocessedTestData);

精密/回忆(PR)曲线突显出准确的探测器在不同级别的召回。理想情况下,精度会召回级别1。使用更多的数据可以帮助提高平均精度,但可能需要更多的训练时间策划公关曲线。

图绘制(召回、精密)包含(“回忆”)ylabel (“精度”网格)标题(sprintf (的平均精度= % .2f '据美联社)),

图包含一个坐标轴对象。坐标轴对象标题平均精度= 0.88包含一个类型的对象。

代码生成

一旦探测器训练和评估,可以生成代码ssdObjectDetector使用GPU编码器™。更多细节,请参阅代码生成的对象检测采用单发射击Multibox探测器的例子。

金宝app支持功能

函数B = augmentData (A)%应用随机水平翻转,和随机的X / Y缩放。盒子,%比例范围以外剪如果重叠高于0.25。同时,%抖动图像颜色。B =细胞(大小(A));我= {1};深圳=大小(I);如果元素个数(深圳)= = 3 & &深圳(3)= = 3 = jitterColorHSV(我,我对比= 0.2,颜色= 0,饱和= 0.1,亮度= 0.2);结束%随机图像翻转和规模。tform = randomAffine2d (XReflection = true,规模= 1.1 [1]);溃败= affineOutputView(深圳、tform BoundsStyle =“CenterOutput”);B {1} = imwarp(我tform OutputView =溃败);% Sanitize框,如果需要的话。{2}= helperSanitizeBoxes ({2}, sz);%应用相同的转换盒。[B{2},指数]= bboxwarp ({2}, tform溃败,OverlapThreshold = 0.25);B{3} ={3}(指标);%返回原始数据只有当所有盒子都被扭曲。如果isempty(指数)B =;结束结束函数targetSize data = preprocessData(数据)% targetSize调整图像和边界框。深圳=大小(数据{1}、(1 2));规模= targetSize(1:2)。/深圳;{1}= imresize数据(数据{1},targetSize (1:2));% Sanitize框,如果需要的话。{2}= helperSanitizeBoxes数据(数据{2},sz);%调整盒子。{2}= bboxresize数据(数据{2},规模);结束函数lgraph = iRemoveLayers (lgraph lastLayer)% lastLayer后删除所有层。dg = vision.internal.cnn.RCNNLayers.digraph (lgraph);%找到最后一层。id = findnode (dg, char (lastLayer));%搜索所有节点从特征提取%层。如果~ ((id) = = 0)和id = dfsearch (dg、身份证);名称= dg.Nodes.Name (id:);lgraph = removeLayers (lgraph,名字(2:结束);结束结束函数p = iSamePadding (FilterSize) p =地板(FilterSize / 2);结束

引用

[1]刘魏,Dragomir Anguelov, Dumitru Erhan,基督教Szegedy,斯科特•里德程杨傅,亚历山大·c·伯格。“SSD:单一multibox探测器拍摄的。”In 14th European Conference on Computer Vision, ECCV 2016. Springer Verlag, 2016.

另请参阅

应用程序

功能

对象

相关的话题