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

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

Сторонние необходимые условия

Необходимый

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

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

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

Проверьте среду графического процессора

Чтобы проверить, что компиляторы и библиотеки для выполнения этого примера настраиваются правильно, используйте 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, используемая в этом примере, была обучена с помощью шагов, описанных в Обнаружении объектов Используя Глубокое обучение (Computer Vision Toolbox) YOLO v3.

matFile = 'yolov3SqueezeNetVehicleExample_21a.mat';
pretrained = load(matFile);
net = pretrained.net;

Сеть YOLO v3 использует resize2dLayer (Image Processing Toolbox), чтобы изменить размер 2D входного изображения путем тиражирования соседних пиксельных значений масштабным коэффициентом 2. resize2DLayer реализован как пользовательский слой, поддержанный для генерации кода. Для получения дополнительной информации смотрите, Задают Пользовательский Слой Глубокого обучения для Генерации кода.

Примечание: можно также использовать предварительно обученную сеть детектора availabe через Модель Computer Vision Toolbox™ для пакета поддержки обнаружения объектов 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');

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

yolov3Detect функция точки входа берет входное изображение и передает его обучившему сеть для предсказания через yolov3Predict функция. yolov3Predict функционируйте загружает сетевой объект из MAT-файла в персистентную переменную и снова использует постоянный объект для последующих вызовов предсказания. А именно, функция использует dlnetwork представление сети, обученной в Обнаружении объектов Используя Глубокое обучение (Computer Vision Toolbox) пример YOLO v3. Предсказания от координат ячейки сетки 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);

Считайте данные изображения в качестве примера, полученные из набора маркированных данных от Обнаружения объектов Используя Глубокое обучение (Computer Vision Toolbox) пример YOLO v3. Это изображение содержит один экземпляр объекта транспортного средства типа.

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)

Сгенерируйте MEX CUDA

Сгенерировать код CUDA® для yolov3Detect функция точки входа, создайте объект настройки графического процессора кода для цели 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, создайте объект настройки центрального процессора кода и используйте объект настройки глубокого обучения 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);

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

Служебные описанные ниже функции основаны на тех используемых в Обнаружении объектов Используя Глубокое обучение (Computer Vision Toolbox) пример YOLO v3 и измененный, чтобы сделать служебные функции подходящими для генерации кода.

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. Redmon, Джозеф и Али Фархади. “YOLOv3: Инкрементное Улучшение”. Предварительно распечатайте, представленный 8 апреля 2018. https://arxiv.org/abs/1804.02767.