主要内容

对象检测使用YOLO V3深度学习

这个例子展示了如何训练YOLO V3.对象探测器。

深度学习是一种强大的机器学习技术,可以用来训练健壮的目标探测器。有几种用于物体检测的技术,包括Faster R-CNN、you only look once (YOLO) v2和single shot detector (SSD)。这个例子展示了如何训练YOLO v3对象检测器。YOLO v3在YOLO v2的基础上进行了改进,增加了多尺度的检测,帮助检测更小的对象。将用于训练的损失函数分解为边界盒回归的均方误差和用于目标分类的二叉交叉熵,以提高检测精度。

注意:这个例子需要计算机视觉工具箱™模型用于YOLO v3对象检测。您可以从附加组件资源管理器中安装用于YOLO v3对象检测的计算机视觉工具箱模型。有关安装附加组件的详细信息,请参见获取和管理加载项

下载Pretrained网络

使用helper函数下载预先训练过的网络downloadPretrainedYOLOv3Detector以避免等待训练完成。如果你想训练网络,设置doTraining变量来真正的

doTraining = false;如果〜DOTRAINATEPPRETRINEDETTECTOR = DOWNLOWPRETRAYYOLOV3DETCHER();结束

数据加载

此示例使用包含295个图像的小标记数据集。这些图像中的许多图片来自Caltech汽车1999和2001年数据集,可在Caltech计算视觉上提供网站,由Pietro Perona创作并获得许可使用。每个图像包含一个或两个已标记的车辆实例。较小的数据集对于研究YOLO v3训练过程很有用,但在实践中,需要更多标记的图像来训练健壮的网络。

解压缩车辆图像,加载车辆地面真实数据。

解压缩vehicleDatasetImages.zipdata =负载(“vehicleDatasetGroundTruth.mat”);vehicleDataset = data.vehicleDataset;%添加的完整路径,本地车辆数据文件夹。vehicleDataset。imageFilename = fullfile(pwd,车辆数据集。imageFilename);

注意:在多个类的情况下,数据还可以组织为三列,其中第一列包含带有路径的图像文件名,第二列包含边界框,第三列必须是包含与每个边界框对应的标签名称的单元格向量。有关如何排列边框和标签的更多信息,请参见boxLabelDatastore

所有的边界框必须在表单中[x y宽度高度].这个向量指定左上角和边界框的大小(以像素为单位)。

将数据集分割为训练网络的训练集和评估网络的测试集。将60%的数据用于训练集,其余数据用于测试集。

rng (0);shuffledIndices = randperm(高度(vehicleDataset));idx = floor(0.6 * length(shuffledIndices));trainingDataTbl =车辆数据集(shuffledIndices(1:idx),:);testDataTbl = vehicleDataset(shuffledIndices(idx+1:end),:);

创建用于加载图像的图像数据存储。

imdstrain = imageageatastore(trainingdatatbl.imagefilename);imdstest = imageageatastore(testdatatbl.imagefilename);

为地面真相边界框创建一个数据存储。

bldsTrain = boxLabelDatastore(trainingDataTbl(:, 2:end));bldsTest = boxLabelDatastore(testDataTbl(:, 2:end));

合并图像和框标签数据存储。

trainingData = combine(imdsTrain, bldsTrain);testData = combine(imdsTest, bldsTest);

使用validateInputData检测无效图像、边框或标签,例如,

  • 图像格式无效或包含NAN的示例

  • 边界包含零的盒/ NaN的/ INFS /空

  • 缺少/无类别标签。

所述边界框的值应该是有限的,正的,非分数的,非NaN的,并应具有正的高度和宽度的图像边界之内。任何无效的样品必须被丢弃或者固定适当的培训。

validateInputData (trainingData);validateInputData (testData);

数据扩张

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

使用变换函数将自定义数据增强应用于训练数据。的augmentData辅助函数在示例的末尾列出,将以下增强应用于输入数据。

  • 在HSV空间的色彩抖动增大

  • 随机水平翻转

  • 随机比例由10%

augmentedTrainingData = transform(trainingData, @augmentData);

读相同的图像四次,并显示增强的训练数据。

%可视化增强图像。augmentedData =细胞(4,1);k = 1:4 data = read(augmentedTrainingData);augmentedData {k} = insertShape(数据{1 1},“矩形”,数据{1,2});重置(AugmentedTrainingData);结束图蒙太奇(augmentedData,'毗邻', 10)

定义YOLO v3对象检测器

本例中的YOLO v3探测器基于SqueezeNet,采用了SqueezeNet中的特征提取网络,并在最后增加了两个检测头。第二个检测头的尺寸是第一个检测头的两倍,所以它能更好地检测小物体。注意,您可以根据您想要检测的对象的大小指定任意数量的不同大小的检测头。YOLO v3检测器使用使用训练数据估计的锚盒,以获得更好的对应于数据集类型的初始先验,并帮助检测器学习准确预测锚盒。有关锚框的信息,请参见用于对象检测的锚盒

YOLO v3探测器中的YOLO v3网络如下图所示。

您可以使用深层网络设计师(深度学习工具箱)创建图中所示的网络。

指定网络输入大小。在选择网络输入尺寸时,考虑网络本身运行所需的最小尺寸、训练图像的尺寸以及在选定尺寸下处理数据所需要的计算代价。在可行的情况下,选择一个与训练图像尺寸相近且大于网络所需输入尺寸的网络输入尺寸。为了减少运行示例的计算成本,指定网络输入大小为[227 227]。

networkInputSize = [227 227 3];

首先,使用变换对训练数据进行预处理,以便计算锚盒,因为本例中使用的训练图像大于227 × 227,且大小不同。将锚的数量指定为6,以在锚的数量和平均IoU之间实现良好的权衡。使用estimateAnchorBoxes函数来估计锚盒。有关锚盒估计的详细信息,请参见根据训练数据估计锚盒.在使用普拉维拉yolov3对象检测器的情况下,需要指定在特定训练数据集上计算的锚盒。请注意,估计过程不是确定性的。为了防止估计的锚盒在调整其他封路时在调整其他普通参数时在使用RNG之前设置随机种子。

rng(0) trainingdatafreestimation = transform(trainingData, @(data)preprocessData(data, networkInputSize));numAnchors = 6;[锚,meanIoU] = estimateAnchorBoxes(trainingdatafestimation, numAnchors)
锚=6×241 34 163 130 98 93 144 125 33 24 69 66
meanIoU = 0.8507

指定anchorBoxes用于两个探测头。anchorBoxes为[mx]单元阵列,其中M为检测头数。每个检测头由的[Nx2]矩阵组成,其中N是要使用的锚的数量。选择anchorBoxes基于特征图大小对每个检测头进行检测。使用更大的规模更小在更高的规模。为此,对首先使用较大的锚盒,并将前三个锚盒分配给第一个检测头,将后三个锚盒分配给第二个检测头。

区域=锚(:,1)。*锚(:,2);[〜,IDX] =排序(区域,“下”);锚=锚(idx,:);anchorBoxes ={锚(1:3,:)锚(4:6,:)};

在Imagenet数据集上加载预先训练好的SqueezeNet网络,然后指定类名。您还可以选择在COCO数据集上加载不同的预训练网络,例如tiny-yolov3-cocoDarknet53-Coco.或想象成数据集,例如MobileNet-V2或Reset-18。当您使用磨具网络时,YOLO V3执行更好并提高培训。

baseNetwork = squeezenet;类名= trainingDataTbl.Properties.VariableNames(2:结束);

接下来,创建yolov3ObjectDetector对象,通过添加检测网络源。选择最优的检测网络源需要反复试验,可以使用analyzeNetwork查找网络内潜在探测网络源的名称。在本例中,使用fire9-CONCATFIRE5-CONCAT层,DetectionNetworkSource

yolov3Detector = yolov3ObjectDetector(baseNetwork, classNames, anchorBoxes,“DetectionNetworkSource”,{“fire9-concat”“fire5-concat”});

另外,与上面使用SqueezeNet创建的网络不同,使用MS-COCO等更大的数据集训练的其他预先训练的YOLOv3架构可以用来在自定义目标检测任务中迁移学习检测器。迁移学习可以通过改变类名和锚盒来实现。

训练数据进行预处理

对增强后的训练数据进行预处理,为训练做准备。的进行预处理方法yolov3ObjectDetector,将以下预处理操作应用于输入数据。

  • 通过保持宽高比来调整图像到网络输入的大小。

  • 在范围内缩放图像像素[0 1]

preprocesedtrainingdata = transform(augmentedTrainingData, @(data)preprocess(yolov3Detector, data));

阅读预处理训练数据。

data =阅读(preprocessedTrainingData);

显示带有边框的图像。

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

重置数据存储。

重置(preprocessedTrainingData);

指定培训选项

指定这些培训选项。

  • 设置纪元数为80。

  • 设置小批量大小8..当使用更高的小批量时,稳定的训练可能具有更高的学习率不过,这应该根据可用内存进行设置。

  • 学习率设置为0.001。

  • 设置预热期为1000迭代。该参数表示根据公式指数增加学习率的迭代次数 learningRate × 迭代 warmupPeriod 4. .它有助于在较高的学习速率下稳定梯度。

  • 设置L2正则化系数为0.0005。

  • 指定惩罚阈值为0.5。与地面真实值重叠小于0.5的检测将被扣分。

  • 初始化梯度的速度为[].这是SGDM用来存储梯度的速度。

numEpochs = 80;miniBatchSize = 8;learningRate = 0.001;warmupPeriod = 1000;l2Regularization = 0.0005;penaltyThreshold = 0.5;速度= [];

火车模型

在GPU上训练(如果有的话)。使用GPU需要并行计算工具箱™和支持CUDA®的NVIDIA®GPU。有关支持的计算能力的信息,请参见金宝appGPU支金宝app持情况(并行计算工具箱)

使用minibatchqueue函数,对预处理后的训练数据进行批量分割,并提供支持功能金宝appcreateBatchData它返回与各自类id相结合的批处理图像和包围框。为了更快地提取训练所需的批处理数据,dispatchInBackground应设置为确保平行池的使用“真”。

minibatchqueue自动检测GPU的可用性。如果没有GPU,或者不希望使用一个训练,设置OutputEnvironment参数“中央处理器”

如果canUseParallelPool dispatchInBackground = true;其他的dispatchInBackground = false;结束mbqTrain = minibatchqueue(preprocesedtrainingdata, 2,)...“MiniBatchSize”miniBatchSize,...“minibatchfcn”, @(images, boxes, labels) createBatchData(images, boxes, labels, classNames),...“MiniBatchFormat”, (“SSCB”],...“disparctinbackground”dispatchInBackground,...“OutputCast”, (“替身”]);

创建使用支撑功能训练进度绘图仪金宝appconfigureTrainingProgressPlotter在使用自定义训练循环训练检测器对象时查看情节。

最后,指定自定义训练循环。对于每次迭代:

  • 读取数据minibatchqueue.如果没有任何数据,则重置minibatchqueue和洗牌。

  • 使用dlfevalMapicalGRADENTERS.功能。功能MapicalGRADENTERS.,作为支持函数列出,返回相对金宝app于中的可学习参数的损失梯度,对应的小批损失,以及当前批的状态。

  • 应用的权重衰减因子的梯度,以正规化为更稳健的培训。

  • 确定学习率基于迭代使用piecewiseLearningRateWithWarmup金宝app支持功能。

  • 方法更新检测器参数sgdmupdate功能。

  • 更新状态探测器参数随移动平均线。

  • 显示每次迭代的学习速率、总损耗和个体损耗(盒损耗、对象损耗和类损耗)。这些可以用来解释在每个迭代中各自的损失是如何变化的。例如,在几次迭代后盒子丢失的突然峰值意味着预测中有Inf或nan。

  • 更新培训进度图。

如果损失在少数时期达到饱和,培训也可以终止。

如果doTraining%创建学习率和小批量损失的子图。无花果=图;[lossPlotter, learningrateful plotter] = configureTrainingProgressPlotter(fig);迭代= 0;%自定义训练循环。历元= 1:numEpochs复位(mbqTrain);洗牌(mbqTrain);(hasdata(mbqTrain))迭代=迭代+ 1;[XTrain,YTrain] =下一个(mbqTrain);使用dlfeval和%MACEMEGRADENTERS功能。[梯度,状态,lossInfo] = dlfeval(@modelGradients,yolov3Detector,XTrain,YTrain,penaltyThreshold);%应用L2正则化。渐变= dlupdate(@(g,w)g + l2regularization * w,渐变,yolov3detector.learnables);%确定当前的学习率值。currentLR = piecewiseLearningRateWithWarmup(迭代中,历元,learningRate,warmupPeriod,numEpochs);%更新使用SGDM优化检测器可以学习的参数。[yolov3Detector。= sgdmupdate(yolov3检测器。学习性,梯度,速度,当前tlr);%更新dlnetwork的状态参数。yolov3Detector。=状态;%显示进度。displayLossInfo(epoch, iteration, currenttlr, lossInfo);%更新培训的情节与新的点。updateplot (lossPlotter, learningrateful plotter, iteration, currenttlr, lossInfo.totalLoss);结束结束其他的yolov3Detector = preTrainedDetector;结束

评估模型

Computer Vision Toolbox™提供对象检测器评估功能,以测量平均精度等常用度量(evaluateDetectionPrecision)和日志平均遗漏率(评估法律).在本例中,使用的是平均精度度量。平均精度提供了一个单一的数字,该数字包括探测器进行正确分类的能力(精度)和探测器找到所有相关对象的能力(回忆)。

结果=检测(yolov3Detector testData,“MiniBatchSize”,8);使用平均精度度量来评估物体探测器。[据美联社、召回、精密]= evaluateDetectionPrecision(结果,testData);

精确召回(PR)曲线显示了探测器在不同召回级别上的精确程度。理想情况下,所有召回级别的精度都是1。

绘制精度-召回率曲线。图图(召回,精度)xlabel(“回忆”) ylabel ('精确'网格)标题(sprintf ('平均精度= %.2f',AP))

使用YOLO V3检测对象

使用检测器进行对象检测。

%读取数据存储。data =阅读(testData);%获取图像。我={1}数据;[bboxes、分数、标签]=检测(yolov3Detector,我);%显示图像的检测。I = insertObjectAnnotation(I,“矩形”bboxes,分数);图imshow(我)

金宝app支持功能

模型梯度函数

功能MapicalGRADENTERS.yolov3ObjectDetector对象,小批量的输入数据的XTrain与对应的地面实况箱YTrain时,指定的惩罚阈值作为输入参数并且返回损失的梯度相对于所述可学习参数在yolov3ObjectDetector,对应的小批丢失信息,以及当前批的状态。

该模型梯度函数计算通过执行这些操作全部损失和梯度。

  • 生成预测从输入的一批图像使用向前方法。

  • 收集CPU上的预测以进行后处理。

  • 将YOLO v3网格单元坐标的预测转换为边界框坐标,以方便与地面真实数据进行比较anchorBoxGenerator的方法yolov3ObjectDetector

  • 利用转换后的预测和地面真实数据生成损失计算目标。这些目标是针对边界框位置(x, y,宽度,高度),对象可信度和类别概率生成的。见支持函数金宝appgenerateTargets

  • 计算预测的边界盒坐标与目标盒的均方误差。见支持函数金宝appbboxoffsetloss.

  • 确定预测对象置信度得分的二进制交叉熵与目标对象置信度分数。见支持函数金宝appobjectnessLoss

  • 确定预测类目标与目标的二元交叉熵。见支持函数金宝appclassConfidenceLoss

  • 计算总损失作为所有损失的总和。

  • 计算learnables的梯度相对于总损耗。

函数[gradient, state, info] = modelGradients(detector, XTrain, YTrain, penaltyThreshold) inputImageSize = size(XTrain,1:2);%在CPU中收集地面真相进行后期处理YTrain =收集(extractdata (YTrain));%从检测器中提取预测。[gatheredPredictions, YPredCell, state] = forward(检测器,XTrain);%生成从地面真实数据的预测的目标。[boxTarget,objectnessTarget,classTarget,objectMaskTarget,boxErrorScale] = generateTargets(gatheredPredictions,...YTrain inputImageSize,探测器。AnchorBoxes penaltyThreshold);%计算损失。boxLoss = bboxOffsetLoss(YPredCell(:,[2 3 7 8]),boxTarget,objectMaskTarget,boxErrorScale);objLoss = objectnessLoss(YPredCell(:,1),objectnessTarget,objectMaskTarget);clsLoss = classConfidenceLoss(YPredCell(:,6),classTarget,objectMaskTarget);totalLoss = boxLoss + objLoss + clsLoss;info.boxLoss = boxLoss;info.objLoss = objLoss;info.clsLoss = clsLoss;info.totalLoss = totalLoss;%计算可学习物品相对于损失的梯度。gradient = dlgradient(totalLoss, detector.Learnables);结束函数boxLoss = bboxOffsetLoss(boxPredCell,boxDeltaTarget,boxMaskTarget,boxErrorScaleTarget)限定框位置的均方误差。lossX =总和(cellfun(@(A,B,C,d)MSE(A * C * d,B * C * d),boxPredCell(:。。,1),boxDeltaTarget(:,1),boxMaskTarget(:,1),boxErrorScaleTarget));有损=总和(cellfun(@(A,B,C,d)MSE(A * C * d,B * C * d),boxPredCell(:。。,2),boxDeltaTarget(:,2),boxMaskTarget(:,1),boxErrorScaleTarget));lossW =总和(cellfun(@(A,B,C,d)MSE(A * C * d,B * C * d),boxPredCell(:。。,3),boxDeltaTarget(:,3),boxMaskTarget(:,1),boxErrorScaleTarget));lossH =总和(cellfun(@(A,B,C,d)MSE(A * C * d,B * C * d),boxPredCell(:。。,4),boxDeltaTarget(:,4),boxMaskTarget(:,1),boxErrorScaleTarget));boxLoss = lossX +有损+ lossW + lossH;结束函数objLoss = objectnessLoss(objectnessPredCell, objectnessDeltaTarget, boxMaskTarget)%客观分数的二元交叉熵损失。objLoss = sum(cellfun(@(a,b,c)) crossentropy(a.*c,b.*c,))“TargetCategories”“独立”),Objectnesspredcell,ObjectnessDeltatarget,BoxMaskTarget(:,2)));结束函数clsloss = classconfidenceLoss(classpredcell,classtarget,boxmasktarget)类置信度的二元交叉熵损失。clsLoss = sum(cellfun(@(a,b,c)) crossentropy(a.*c,b.*c,))“TargetCategories”“独立”)、classPredCell classTarget boxMaskTarget (:, 3)));结束

增强和数据处理功能

函数data = augmentData (A)%应用随机水平翻转和随机X / Y轴缩放。的箱子,GET如果重叠大于0.25,则在边界外缩放的%被截断。同时,抖动图像颜色。数据=单元格(大小(a));ii = 1:size(A,1) I = A{ii,1};bboxes = {ii, 2};标签= {ii, 3};深圳=大小(I);如果numel(sz) == 3 && sz(3) == 3 I = jitterColorHSV(I,...'对比',0.0,...“颜色”,0.1,...“饱和”,0.2,...“亮度”, 0.2);结束%随机翻转图像。TForm的= randomAffine2d(“XReflection”,真的,“规模”1.1 [1]);tform溃败= affineOutputView(深圳,“BoundsStyle”“centerOutput”);I = imwarp(I,TForm的,“OutputView”,溃败);对方框应用相同的转换。[bboxes,指数]= bboxwarp (bboxes、tform溃败,“OverlapThreshold”, 0.25);标签=标签(指标);%收益只有当翘曲被删除所有箱子的原始数据。如果isempty(indices) data(ii,:) = A(ii,:);其他的data(ii,:) = {I, bboxes, labels};结束结束结束函数数据= preprocessData(数据,的targetSize)%调整大小的图像和缩放的像素为0和1之间还缩放%对应的边界框。ii = 1:size(data,1) I = data{ii,1};imgSize =大小(I);将单通道输入图像转换为3通道。如果nummel (imgSize) < 3 I = repmat(I,1,1,3);结束bboxes = data {ii,2};i = im2single(imresize(i,targetsize(1:2)));scale = targetsize(1:2)./ Imgsize(1:2);bboxes = bboxresize(bboxes,scale);数据(II,1:2)= {i,bboxes};结束结束函数[XTrain, YTrain] = createBatchData(data, groundTruthBoxes, groundTruthClasses, classNames)沿XTrain批次尺寸合并%返回的图像和在YTrain中用classid连接的归一化包围盒%沿批处理尺寸连接图像。XTrain = cat(4, data{:,1});%从类名中获取类ID。ClassNames = Repmat({分类(ClassNames')},大小(地面基条));[〜,classIndices] = Cellfun(@(a,b)是member(a,b),地区,classnames,“UniformOutput”, 错误的);%添加标签索引和训练图像大小到缩放的边界框%并创建一个响应单元格数组。@(bbox, classid)[bbox, classid], groundTruthBoxes, classIndices,“UniformOutput”, 错误的);LEN = MAX(cellfun(@(x)的大小(X,1),combinedResponses));paddedBBoxes = cellfun(@(V)padarray(V,[LEN-大小(V,1),0],0,“职位”)、combinedResponses“UniformOutput”、假);YTrain = cat(4, paddeddbboxes {:,1});结束

学习率Schedule命令功能

函数currenttlr = piecewiselearningretwithwarmup (iteration, epoch, learningRate, warmupPeriod, numEpochs)% piecewiselearningrateful withwarmup函数计算当前基于迭代号的百分比学习率。执着的warmUpEpoch;如果迭代<= warmupPeriod%增加了预热期间迭代次数的学习率。currentlr =学会*((迭代/ harmupperiod)^ 4);harmupepoch = epoch;elseif迭代> = Harmupperiod && Epoch 预热期后%,如果剩余的时期数量小于60%,则保持学习率常数。currentLR = learningRate;elseifepoch >= warmUpEpoch+floor(0.6*(numEpochs-warmUpEpoch)) && epoch < warmUpEpoch+floor(0.9*(numEpochs-warmUpEpoch))%剩余纪元数超过60%但少于60%90%以上的学习率乘以0.1。currentLR = learningRate * 0.1;其他的%如果剩余的时期超过90%,则乘以学习%率0.01。currentLR = learningRate * 0.01;结束结束

效用函数

函数[lossPlotter, learningrateful plotter] = configureTrainingProgressPlotter(f)%创建子图来显示丢失和学习率。图(f);clf次要情节(2,1,1);ylabel (学习速率的);Xlabel(“迭代”);学习平板=动画线;子图(2,1,2);ylabel (“全损”);Xlabel(“迭代”);lockplotter =动画线;结束函数displayLossInfo(epoch, iteration, currenttlr, lossInfo)显示%显示每个迭代的损失信息。DISP(”时代:“+时代+“|迭代:”+迭代+|学习率:+ currentLR +...“|总损失:”+双(收集(extractdata (lossInfo.totalLoss))) +...“|箱损:”+双(收集(extractdata (lossInfo.boxLoss))) +...“|物体丢失:”+双(收集(extractdata (lossInfo.objLoss))) +...“|丢失:”+双(收集(extractdata (lossInfo.clsLoss))));结束函数updateplot (lossPlotter, learningrateful plotter, iteration, currenttlr, totalLoss)%更新的损失和学习率地块。addpoints (lossPlotter、迭代、双(extractdata(收集(totalLoss))));addpoints (learningRatePlotter迭代,currentLR);drawnow结束函数探测器= downloadPretrainedYOLOv3Detector ()下载一个经过训练的yolov3探测器。如果~ (“yolov3SqueezeNetVehicleExample_21aSPKG.mat”“文件”如果~ (“yolov3SqueezeNetVehicleExample_21aSPKG.zip”“文件”) disp (“正在下载预训练的探测器......”);pretrainedURL =“https://ssd.mathworks.com/金宝appsupportfiles/vision/data/yolov3SqueezeNetVehicleExample_21aSPKG.zip”;websave (“yolov3SqueezeNetVehicleExample_21aSPKG.zip”, pretrainedURL);结束解压缩(“yolov3SqueezeNetVehicleExample_21aSPKG.zip”);结束pretrained =负载(“yolov3squeezenetvehicleexample_21apkg.mat”);检测器= pretrained.detector;结束

参考

雷蒙德,约瑟夫和阿里·法哈迪。“YOLOv3:一个渐进的改进。”预印本,2018年4月8日提交。https://arxiv.org/abs/1804.02767。

另请参阅

||||(深度学习工具箱)||

相关的话题