Генерация кода для обнаружения объектов с использованием глубокого обучения YOLO v3

В этом примере показано, как сгенерировать CUDA ® MEX для детектора объектов (YOLO) v3 только один раз с пользовательскими слоями. YOLO v3 улучшается после YOLO v2, добавляя обнаружение в нескольких шкалах, чтобы помочь обнаружить меньшие объекты. Кроме того, функция потерь, используемая для обучения, разделена на среднюю квадратичную невязку для ограничивающей прямоугольной регрессии и бинарную перекрестную энтропию для классификации объектов, чтобы помочь улучшить точность обнаружения. Сеть YOLO v3, используемая в этом примере, была обучена на примере обнаружения объектов с использованием YOLO v3 Глубокого обучения в Computer Vision Toolbox(TM). Для получения дополнительной информации смотрите Обнаружение объектов с использованием YOLO v3 Глубокое Обучение (Computer Vision Toolbox).

Необходимые условия для третьих лиц

Необходимый

  • CUDA включает графический процессор NVIDIA ® и совместимый драйвер.

Дополнительный

Для сборок, не являющихся MEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.

Проверьте окружение GPU

Чтобы убедиться, что компиляторы и библиотеки для выполнения этого примера настроены правильно, используйте coder.checkGpuInstall (GPU Coder) функцию.

envCfg = coder.gpuEnvConfig('host');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

Сеть YOLO v3

Сеть YOLO v3 в этом примере основана на squeezenet, и использует сеть редукции данных в SqueezeNet с сложением двух головок обнаружения в конце. Вторая детекторная головка в два раза больше первой детекторной головки, поэтому она лучше способна обнаруживать небольшие объекты. Обратите внимание, что любое количество головок обнаружения различных размеров может быть задано на основе размера объектов, которые будут обнаружены. Сеть YOLO v3 использует якорные коробки, оцененные с помощью обучающих данных, чтобы иметь лучшие начальные приоритеты, соответствующие типу набора данных, и помочь сети научиться точно предсказывать коробки. Дополнительные сведения о анкерных коробках см. в разделе Якорные коробки для обнаружения объектов (Computer Vision Toolbox).

Сеть YOLO v3 в этом примере проиллюстрирована на следующей схеме.

Каждая детекторная головка предсказывает координаты ограничивающего прямоугольника (x, y, ширину, высоту), доверие объекта и вероятности класса для соответствующих маск якорного прямоугольника. Поэтому для каждой детекторной головки количество выхода фильтров в последнем слое свертки является количеством маски якорной коробки, умноженным на количество элементов предсказания на якорную коробку. Детекторные головки содержат выход слой сети.

Предварительно обученная сеть YOLO v3

Загрузите сеть 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 (Image Processing Toolbox), чтобы изменить размер 2-D входного изображения путем репликации соседних значений пикселя с коэффициентом масштабирования 2. Этот resize2DLayer реализован как пользовательский слой, поддерживаемый для генерации кода. Для получения дополнительной информации смотрите Задать Пользовательский Слой Глубокого Обучения для Генерации Кода.

Примечание. Вы также можете использовать предварительно обученную доступность сети детектора через Toolbox™ Computer Vision Модели для пакета поддержки YOLO v3 Обнаружения объектов.

Чтобы использовать эту предварительно обученную сеть, необходимо сначала установить модель Computer Vision Toolbox для Обнаружения объектов YOLO v3 из Add-On Explorer. Дополнительные сведения об установке дополнений см. в разделе Получение и управление Дополнений.

Затем сохраните сеть из yolov3ObjectDetector объект в MAT-файл и продолжить. Для примера,

detector = yolov3ObjectDetector('darknet53-coco');
net = detector.Network;
matFile = 'pretrainedYOLOv3Detector.mat';
save(matFile,'net');

The yolov3Detect Функция точки входа

The yolov3Detect функция точки входа принимает входное изображение и передает его в обученную сеть для предсказания через yolov3Predict функция. The 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);

Считайте примеры изображений, полученных из набора маркированных данных из примера Обнаружения объектов Using 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 MEX

Чтобы сгенерировать код CUDA ® для yolov3Detect функция точки входа, создайте объект строения кода GPU для цели MEX и установите целевой язык на C++. Используйте coder.DeepLearningConfig (GPU Coder) для создания объекта строения глубокого обучения CuDNN и назначения его DeepLearningConfig свойство объекта строения кода GPU.

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 свойство.

Запуск сгенерированного MEX

Вызовите сгенерированный MEX CUDA с тем же вводом изображения 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);

Служебные функции

Перечисленные ниже функции утилиты основаны на таковых, используемой в Обнаружение объектов Using 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.

Для просмотра документации необходимо авторизоваться на сайте