В этом примере показано, как создать CUDA ® MEX для детектора объектов YOLO v3 с пользовательскими слоями. YOLO v3 улучшает YOLO v2, добавляя обнаружение в нескольких масштабах, чтобы помочь обнаруживать объекты меньшего размера. Кроме того, функция потерь, используемая для обучения, разделяется на среднеквадратичную ошибку для регрессии ограничивающей рамки и двоичную перекрестную энтропию для классификации объектов, чтобы помочь улучшить точность обнаружения. Сеть YOLO v3, используемая в этом примере, была обучена на примере «Обнаружение объектов с помощью глубокого обучения YOLO v3» в панели инструментов Computer Vision Toolbox (TM). Дополнительные сведения см. в разделе Обнаружение объектов с помощью глубокого обучения YOLO v3 (Computer Vision Toolbox).
Графический процессор NVIDIA ® с поддержкой CUDA и совместимый драйвер.
Для построений, отличных от MEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.
Инструментарий NVIDIA CUDA.
Библиотека NVIDIA cuDNN.
Переменные среды для компиляторов и библиотек. Дополнительные сведения см. в разделах Аппаратное обеспечение сторонних производителей (GPU Coder) и Настройка необходимых продуктов (GPU Coder).
Чтобы убедиться, что компиляторы и библиотеки для выполнения этого примера настроены правильно, используйте coder.checkGpuInstall (Кодер графического процессора).
envCfg = coder.gpuEnvConfig('host'); envCfg.DeepLibTarget = 'cudnn'; envCfg.DeepCodegen = 1; envCfg.Quiet = 1; coder.checkGpuInstall(envCfg);
Сеть YOLO v3 в этом примере основана на squeezenetи использует сеть извлечения признаков в SqueeeNet с добавлением двух головок обнаружения в конце. Вторая детекторная головка в два раза больше, чем первая детекторная головка, поэтому она лучше способна обнаруживать мелкие объекты. Следует отметить, что любое количество головок обнаружения различных размеров может быть определено на основе размера обнаруживаемых объектов. Сеть YOLO v3 использует якорные ящики, оцененные с использованием обучающих данных, чтобы иметь лучшие начальные приоры, соответствующие типу набора данных, и чтобы помочь сети научиться точно предсказывать ящики. Сведения о ящиках привязки см. в разделе Ящики привязки для обнаружения объектов (панель инструментов компьютерного зрения).
Сеть YOLO v3 в этом примере показана на следующей схеме.

Каждая головка обнаружения предсказывает координаты ограничивающей рамки (x, y, ширину, высоту), достоверность объекта и вероятности классов для соответствующих масок якорной рамки. Следовательно, для каждой головки обнаружения количество выходных фильтров в последнем слое свертки является количеством маски блока привязки, умноженным на количество элементов прогнозирования на блок привязки. Головки обнаружения содержат выходной уровень сети.
Загрузите сеть YOLO v3.
fileName = matlab.internal.examples.downloadSupportFile('vision/data/','yolov3SqueezeNetVehicleExample_21a.zip'); unzip(fileName);
Сеть YOLO v3, используемая в этом примере, была обучена с использованием шагов, описанных в разделе Обнаружение объектов с помощью глубокого обучения YOLO v3 (Computer Vision Toolbox).
matFile = 'yolov3SqueezeNetVehicleExample_21a.mat';
pretrained = load(matFile);
net = pretrained.net;Сеть YOLO v3 использует resize2dLayer(Панель инструментов обработки изображений) для изменения размера 2-D входного изображения путем репликации значений соседних пикселей с коэффициентом масштабирования 2. Этот resize2DLayer реализован как пользовательский уровень, поддерживаемый для создания кода. Дополнительные сведения см. в разделе Определение пользовательского уровня глубокого обучения для создания кода.
Примечание.Вы также можете использовать предварительно обученную сеть детекторов, доступную с помощью Computer Vision Toolbox™ Model для пакета поддержки YOLO v3 Object Detection.
Чтобы использовать эту предварительно подготовленную сеть, необходимо сначала установить модель панели инструментов Computer Vision Toolbox для обнаружения объектов YOLO v3 из проводника надстроек. Дополнительные сведения об установке надстроек см. в разделе Получение надстроек и управление ими.
Затем сохраните сеть из yolov3ObjectDetector объект в MAT-файл и продолжите. Например,
detector = yolov3ObjectDetector('darknet53-coco'); net = detector.Network; matFile = 'pretrainedYOLOv3Detector.mat'; save(matFile,'net');
yolov3Detect Функция точки входа yolov3Detect функция точки входа принимает входное изображение и передает его в обученную сеть для прогнозирования через yolov3Predict функция. yolov3Predict функция загружает сетевой объект из MAT-файла в постоянную переменную и повторно использует постоянный объект для последующих вызовов прогнозирования. В частности, функция использует dlnetwork представление сети, обученной в примере «Обнаружение объектов с помощью глубокого обучения YOLO v3» (Computer Vision Toolbox). Прогнозы из координат ячейки сетки YOLO v3, полученные из yolov3Predict вызовы затем преобразуются в координаты ограничивающей рамки с помощью вспомогательных функций generateTiledAnchors и applyAnchorBoxOffsets.
type('yolov3Detect.m')function [bboxes,scores,labelsIndex] = yolov3Detect(matFile, im,...
networkInputSize, networkOutputs, confidenceThreshold,...
overlapThreshold, classes)
% The yolov3Detect function detects the bounding boxes, scores, and
% labelsIndex in an image.
%#codegen
% Copyright 2020-2021 The MathWorks, Inc.
%% Preprocess Data
% This example applies all the preprocessing transforms to the data set
% applied during training, except data augmentation. Because the example
% uses a pretrained YOLO v3 network, the input data must be representative
% of the original data and left unmodified for unbiased evaluation.
% Specifically the following preprocessing operations are applied to the
% input data.
% 1. Resize the images to the network input size, as the images are
% bigger than networkInputSize. 2. Scale the image pixels in the range
% [0 1]. 3. Convert the resized and rescaled image to a dlarray object.
im = dlarray(preprocessData(im, networkInputSize), "SSCB");
imageSize = size(im,[1,2]);
%% Define Anchor Boxes
% Specify the anchor boxes estimated on the basis of the preprocessed
% training data used when training the YOLO v3 network. These anchor box
% values are same as mentioned in "Object Detection Using YOLO v3 Deep
% Learning" example. For details on estimating anchor boxes, see "Anchor
% Boxes for Object Detection".
anchors = [
41 34;
163 130;
98 93;
144 125;
33 24;
69 66];
% Specify anchorBoxMasks to select anchor boxes to use in both the
% detection heads of the YOLO v3 network. anchorBoxMasks is a cell array of
% size M-by-1, where M denotes the number of detection heads. Each
% detection head consists of a 1-by-N array of row index of anchors in
% anchorBoxes, where N is the number of anchor boxes to use. Select anchor
% boxes for each detection head based on size-use larger anchor boxes at
% lower scale and smaller anchor boxes at higher scale. To do so, sort the
% anchor boxes with the larger anchor boxes first and assign the first
% three to the first detection head and the next three to the second
% detection head.
area = anchors(:, 1).*anchors(:, 2);
[~, idx] = sort(area, 'descend');
anchors = anchors(idx, :);
anchorBoxMasks = {[1,2,3],[4,5,6]};
%% Predict on Yolov3
% Predict and filter the detections based on confidence threshold.
predictions = yolov3Predict(matFile,im,networkOutputs,anchorBoxMasks);
%% Generate Detections
% indices corresponding to x,y,w,h predictions for bounding boxes
anchorIndex = 2:5;
tiledAnchors = generateTiledAnchors(predictions,anchors,anchorBoxMasks,...
anchorIndex);
predictions = applyAnchorBoxOffsets(tiledAnchors, predictions,...
networkInputSize, anchorIndex);
[bboxes,scores,labelsIndex] = generateYOLOv3DetectionsForCodegen(predictions,...
confidenceThreshold, overlapThreshold, imageSize, classes);
end
function YPredCell = yolov3Predict(matFile,im,networkOutputs,anchorBoxMask)
% Predict the output of network and extract the confidence, x, y,
% width, height, and class.
% load the deep learning network for prediction
persistent net;
if isempty(net)
net = coder.loadDeepLearningNetwork(matFile);
end
YPredictions = cell(coder.const(networkOutputs), 1);
[YPredictions{:}] = predict(net, im);
YPredCell = extractPredictions(YPredictions, anchorBoxMask);
% Apply activation to the predicted cell array.
YPredCell = applyActivations(YPredCell);
end
Выполните следующие действия для оценки функции точки входа на изображении по данным теста.
Укажите порог достоверности как 0,5 для сохранения только обнаружений с показателями достоверности выше этого значения.
Для удаления перекрывающихся обнаружений задайте порог перекрытия равным 0,5.
Считывание изображения из входных данных.
Использовать функцию точки входа yolov3Detect чтобы получить прогнозируемые ограничивающие рамки, оценки достоверности и метки класса.
Отображение изображения с ограничивающими прямоугольниками и показателями достоверности.
Определите требуемые пороговые значения.
confidenceThreshold = 0.5; overlapThreshold = 0.5;
Укажите размер сетевого входа обученной сети и количество сетевых выходов.
networkInputSize = [227 227 3]; networkOutputs = numel(net.OutputNames);
Прочитайте пример данных изображения, полученных из набора помеченных данных из примера «Обнаружение объектов с помощью глубокого обучения YOLO v3» (Computer Vision Toolbox). Это изображение содержит один экземпляр объекта типа транспортного средства.
I = imread('vehicleImage.jpg');Укажите имена классов.
classNames = {'vehicle'};Вызовите метод обнаружения в сети YOLO v3 и просмотрите результаты.
[bboxes,scores,labelsIndex] = yolov3Detect(matFile,I,... networkInputSize,networkOutputs,confidenceThreshold,overlapThreshold,classNames); labels = classNames(labelsIndex); % Display the detections on the image IAnnotated = insertObjectAnnotation(I,'rectangle',bboxes,strcat(labels,{' - '},num2str(scores))); figure imshow(IAnnotated)

Создание кода CUDA ® для yolov3Detect создание объекта конфигурации кода GPU для цели MEX и установка целевого языка на C++. Используйте coder.DeepLearningConfig (GPU Coder), чтобы создать объект конфигурации глубокого обучения CuDNN и назначить его DeepLearningConfig свойства объекта конфигурации кода графического процессора.
cfg = coder.gpuConfig('mex'); cfg.TargetLang = 'C++'; cfg.DeepLearningConfig = coder.DeepLearningConfig(TargetLibrary='cudnn'); args = {coder.Constant(matFile),I,coder.Constant(networkInputSize),... coder.Constant(networkOutputs),confidenceThreshold,... overlapThreshold,classNames}; codegen -config cfg yolov3Detect -args args -report
Code generation successful: View report
Чтобы создать код CUDA ® для цели TensorRT, создайте и используйте объект конфигурации глубокого обучения TensorRT вместо объекта конфигурации CuDNN. Аналогично, чтобы создать код для цели MKLDNN, создайте объект конфигурации кода CPU и используйте объект конфигурации глубокого обучения MKLDNN в качестве егоDeepLearningConfig собственность.
Вызовите сгенерированный CUDA MEX с тем же входным изображением I как и прежде, и просмотр результатов.
[bboxes,scores,labelsIndex] = yolov3Detect_mex(matFile,I,... networkInputSize,networkOutputs,confidenceThreshold,... overlapThreshold,classNames); labels = classNames(labelsIndex); figure; IAnnotated = insertObjectAnnotation(I,'rectangle',bboxes,strcat(labels,{' - '},num2str(scores))); imshow(IAnnotated);

Перечисленные ниже функции utillity основаны на функциях, используемых в примере «Обнаружение объектов с помощью глубокого обучения YOLO v3» (Computer Vision Toolbox), и изменены, чтобы сделать функции утилиты подходящими для генерации кода.
type('applyActivations.m')function YPredCell = applyActivations(YPredCell) %#codegen
% Copyright 2020-2021 The MathWorks, Inc.
numCells = size(YPredCell, 1);
for iCell = 1:numCells
for idx = 1:3
YPredCell{iCell, idx} = sigmoidActivation(YPredCell{iCell,idx});
end
end
for iCell = 1:numCells
for idx = 4:5
YPredCell{iCell, idx} = exp(YPredCell{iCell, idx});
end
end
for iCell = 1:numCells
YPredCell{iCell, 6} = sigmoidActivation(YPredCell{iCell, 6});
end
end
function out = sigmoidActivation(x)
out = 1./(1+exp(-x));
end
type('extractPredictions.m')function predictions = extractPredictions(YPredictions, anchorBoxMask)
%#codegen
% Copyright 2020-2021 The MathWorks, Inc.
numPredictionHeads = size(YPredictions, 1);
predictions = cell(numPredictionHeads,6);
for ii = 1:numPredictionHeads
% Get the required info on feature size.
numChannelsPred = size(YPredictions{ii},3);
numAnchors = size(anchorBoxMask{ii},2);
numPredElemsPerAnchors = numChannelsPred/numAnchors;
allIds = (1:numChannelsPred);
stride = numPredElemsPerAnchors;
endIdx = numChannelsPred;
YPredictionsData = extractdata(YPredictions{ii});
% X positions.
startIdx = 1;
predictions{ii,2} = YPredictionsData(:,:,startIdx:stride:endIdx,:);
xIds = startIdx:stride:endIdx;
% Y positions.
startIdx = 2;
predictions{ii,3} = YPredictionsData(:,:,startIdx:stride:endIdx,:);
yIds = startIdx:stride:endIdx;
% Width.
startIdx = 3;
predictions{ii,4} = YPredictionsData(:,:,startIdx:stride:endIdx,:);
wIds = startIdx:stride:endIdx;
% Height.
startIdx = 4;
predictions{ii,5} = YPredictionsData(:,:,startIdx:stride:endIdx,:);
hIds = startIdx:stride:endIdx;
% Confidence scores.
startIdx = 5;
predictions{ii,1} = YPredictionsData(:,:,startIdx:stride:endIdx,:);
confIds = startIdx:stride:endIdx;
% Accumulate all the non-class indexes
nonClassIds = [xIds yIds wIds hIds confIds];
% Class probabilities.
% Get the indexes which do not belong to the nonClassIds
classIdx = setdiff(allIds, nonClassIds, 'stable');
predictions{ii,6} = YPredictionsData(:,:,classIdx,:);
end
end
type('generateTiledAnchors.m')function tiledAnchors = generateTiledAnchors(YPredCell,anchorBoxes,...
anchorBoxMask,anchorIndex)
% Generate tiled anchor offset for converting the predictions from the YOLO
% v3 grid cell coordinates to bounding box coordinates
%#codegen
% Copyright 2020-2021 The MathWorks, Inc.
numPredictionHeads = size(YPredCell,1);
tiledAnchors = cell(numPredictionHeads, size(anchorIndex, 2));
for i = 1:numPredictionHeads
anchors = anchorBoxes(anchorBoxMask{i}, :);
[h,w,~,n] = size(YPredCell{i,1});
[tiledAnchors{i,2},tiledAnchors{i,1}] = ndgrid(0:h-1,0:w-1,...
1:size(anchors,1),1:n);
[~,~,tiledAnchors{i,3}] = ndgrid(0:h-1,0:w-1,anchors(:,2),1:n);
[~,~,tiledAnchors{i,4}] = ndgrid(0:h-1,0:w-1,anchors(:,1),1:n);
end
end
type('applyAnchorBoxOffsets.m')function YPredCell = applyAnchorBoxOffsets(tiledAnchors,YPredCell,...
inputImageSize,anchorIndex) %#codegen
% Convert the predictions from the YOLO v3 grid cell coordinates to
% bounding box coordinates
% Copyright 2020-2021 The MathWorks, Inc.
for i = 1:size(YPredCell,1)
[h,w,~,~] = size(YPredCell{i,1});
YPredCell{i,anchorIndex(1)} = (tiledAnchors{i,1}+...
YPredCell{i,anchorIndex(1)})./w;
YPredCell{i,anchorIndex(2)} = (tiledAnchors{i,2}+...
YPredCell{i,anchorIndex(2)})./h;
YPredCell{i,anchorIndex(3)} = (tiledAnchors{i,3}.*...
YPredCell{i,anchorIndex(3)})./inputImageSize(2);
YPredCell{i,anchorIndex(4)} = (tiledAnchors{i,4}.*...
YPredCell{i,anchorIndex(4)})./inputImageSize(1);
end
end
type('preprocessData.m')function image = preprocessData(image, targetSize)
% Resize the images and scale the pixels to between 0 and 1.
%#codegen
% Copyright 2020-2021 The MathWorks, Inc.
imgSize = size(image);
% Convert an input image with single channel to 3 channels.
if numel(imgSize) < 1
image = repmat(image,1,1,3);
end
image = im2single(rescale(image));
image = iLetterBoxImage(image,coder.const(targetSize(1:2)));
end
function Inew = iLetterBoxImage(I,targetSize)
% LetterBoxImage returns a resized image by preserving the width and height
% aspect ratio of input Image I. 'targetSize' is a 1-by-2 vector consisting
% the target dimension.
%
% Input I can be uint8, uint16, int16, double, single, or logical, and must
% be real and non-sparse.
[Irow,Icol,Ichannels] = size(I);
% Compute aspect Ratio.
arI = Irow./Icol;
% Preserve the maximum dimension based on the aspect ratio.
if arI<1
IcolFin = targetSize(1,2);
IrowFin = floor(IcolFin.*arI);
else
IrowFin = targetSize(1,1);
IcolFin = floor(IrowFin./arI);
end
% Resize the input image.
Itmp = imresize(I,[IrowFin,IcolFin]);
% Initialize Inew with gray values.
Inew = ones([targetSize,Ichannels],'like',I).*0.5;
% Compute the offset.
if arI<1
buff = targetSize(1,1)-IrowFin;
else
buff = targetSize(1,2)-IcolFin;
end
% Place the resized image on the canvas image.
if (buff==0)
Inew = Itmp;
else
buffVal = floor(buff/2);
if arI<1
Inew(buffVal:buffVal+IrowFin-1,:,:) = Itmp;
else
Inew(:,buffVal:buffVal+IcolFin-1,:) = Itmp;
end
end
end
1. Редмон, Джозеф и Али Фархади. «YOLOv3: инкрементное улучшение». Препринт, представлен 8 апреля 2018 года. https://arxiv.org/abs/1804.02767.