В этом примере показано, как сгенерировать CUDA® MEX для вы только смотрите однажды (YOLO) v3 детектор объектов с пользовательскими слоями. Пример использует обнаружение объектов YOLO v3, чтобы проиллюстрировать:
Генерация кода CUDA для нейронной сети для глубокого обучения с пользовательскими слоями.
Преобразуйте глубокое обучение dlnetwork
Объект (Deep Learning Toolbox) в DAGNetwork
Объект (Deep Learning Toolbox) для генерации кода.
YOLO v3 улучшает YOLO v2 путем добавления обнаружения в нескольких шкалах, чтобы помочь обнаружить меньшие объекты. Кроме того, функция потерь, используемая для обучения, разделена на среднеквадратическую ошибку для регрессии ограничительной рамки и бинарную перекрестную энтропию для предметной классификации, чтобы помочь улучшить точность обнаружения. Этот пример использует сеть YOLO v3, обученную в Обнаружении объектов Используя пример YOLO v3 Глубокого обучения от Computer Vision Toolbox(TM). Для получения дополнительной информации смотрите, что Обнаружение объектов Использует Глубокое обучение (Computer Vision Toolbox) YOLO v3.
CUDA включил NVIDIA® графический процессор и совместимый драйвер.
Для сборок неMEX, таких как статические, динамические библиотеки или исполняемые файлы, этот пример имеет следующие дополнительные требования.
NVIDIA инструментарий CUDA.
Библиотека NVIDIA cuDNN.
Переменные окружения для компиляторов и библиотек. Для получения дополнительной информации смотрите Стороннее Оборудование и Подготовку Необходимых как условие продуктов.
Чтобы проверить, что компиляторы и библиотеки для выполнения этого примера настраиваются правильно, используйте coder.checkGpuInstall
функция.
envCfg = coder.gpuEnvConfig('host'); envCfg.DeepLibTarget = 'cudnn'; envCfg.DeepCodegen = 1; envCfg.Quiet = 1; coder.checkGpuInstall(envCfg);
Сеть YOLO v3 в этом примере основана на squeezenet
(Deep Learning Toolbox) и использование сеть извлечения признаков в SqueezeNet со сложением двух голов обнаружения в конце. Вторая голова обнаружения является дважды размером первой головы обнаружения, таким образом, это лучше способно обнаружить маленькие объекты. Обратите внимание на то, что любое количество глав обнаружения различных размеров может быть задано на основе размера объектов, которые будут обнаружены. Использование сети YOLO v3 поля привязки, оцененные с помощью обучающих данных, чтобы иметь лучшее начальное уголовное прошлое, соответствующее типу набора данных и помочь сети учиться предсказывать поля точно. Для получения информации о полях привязки смотрите Поля Привязки для Обнаружения объектов (Computer Vision Toolbox).
Сеть YOLO v3 в этом примере проиллюстрирована в следующей схеме.
Каждый глава обнаружения предсказывает координаты ограничительной рамки (x, y, ширина, высота), объектное доверие и вероятности класса для соответствующих масок поля привязки. Поэтому для каждой головы обнаружения, количество выхода просачивается, последний слой свертки является номером времен маски поля привязки количество элементов предсказания на поле привязки. Головы обнаружения включают выходной слой сети.
Загрузите сеть YOLO v3, обученную в Обнаружении объектов Используя пример YOLO v3 Глубокого обучения. Чтобы обучить сеть самостоятельно, смотрите, что Обнаружение объектов Использует Глубокое обучение (Computer Vision Toolbox) YOLO v3.
pretrained = load("yolov3SqueezeNetVehicleExample_20a.mat");
net = pretrained.net;
Предварительно обученной моделью YOLO v3 является dlnetwork
объект, который не поддерживается для генерации кода. Извлеките график слоев dlnetwork
объект при помощи layerGraph
(Deep Learning Toolbox) функция.
lGraph = layerGraph(net);
График слоев выводится layerGraph
функция не включает выходные слои. Добавьте слой регрессии в график слоев для каждых из его выходных параметров при помощи addLayers
(Deep Learning Toolbox) и connectLayers
(Deep Learning Toolbox) функции.
outLayerIdx = 1:numel(lGraph.Layers); isOutLayer = arrayfun(@(x) any(strcmp(x.Name, net.OutputNames)), lGraph.Layers); outLayerIdx(~isOutLayer) = []; for iOut = 1:numel(outLayerIdx) outLayer = lGraph.Layers(outLayerIdx(iOut)); newLayer = regressionLayer('Name', [outLayer.Name '_output_' num2str(iOut)]); lGraph = addLayers(lGraph, newLayer); lGraph = connectLayers(lGraph, outLayer.Name, newLayer.Name); end
Количество выходных слоев сети - то же самое как количество голов обнаружения в сети.
Использование сети YOLO v3 пользовательское сверхдискретизировало слой для повышающей дискретизации входных данных изображения. Здесь, мы используем совместимую версию генерации кода upsampleLayer
упомянутый в Обнаружении объектов Используя Глубокое обучение (Computer Vision Toolbox) пример YOLO v3. upsampleBy2Layer
сверхдискретизировал входное изображение путем тиражирования соседних пиксельных значений на коэффициент 2 использований repelem
функция. Поскольку генерация кода для repelem
функция поддерживается только для векторных или 2D матричных входных параметров, upsampleBy2Layer
реализация должна быть параметрирована при помощи coder.target
функция. При выполнении симуляции на MATLAB, одном вызове repelem
достаточно, когда вход может быть матрицей N-D. Для генерации кода пример использует вложенные циклы for так, чтобы вход к repelem
функция является 2D матрицей для каждого вызова repelem
в сгенерированном коде. Кроме того, для выходного размера слоя генерации кода требуется, чтобы быть постоянным во время генерации кода. Следовательно, свойство UpsampleFactor слоя изменяется, чтобы быть Константом.
type('upsampleBy2Layer.m')
% Upsample by replicating neighbouring pixel values. % Copyright 2020 The MathWorks, Inc. classdef upsampleBy2Layer < nnet.layer.Layer properties (Constant) % factor to upsample the input. UpSampleFactor = 2 end methods function layer = upsampleBy2Layer(name) % Set layer name. layer.Name = name; % Set layer description. layer.Description = "upSamplingLayer with factor " + layer.UpSampleFactor; end function Z = predict(layer, X) % Z = predict(layer, X) forwards the input data X through the % layer and outputs the result Z. if coder.target('MATLAB') Z = repelem(X,layer.UpSampleFactor,layer.UpSampleFactor); else numChannels = size(X, 3); numBatches = size(X, 4); Zsize = coder.const([size(X, 1) size(X, 2) numChannels numBatches] .* [layer.UpSampleFactor layer.UpSampleFactor 1 1]); Z = coder.nullcopy(zeros(Zsize, 'like', X)); coder.gpu.kernel(-1, -1); for iBatch = 1:numBatches for iChannel = 1:numChannels Z(:, :, iChannel, iBatch) = repelem(X(:, :, iChannel, iBatch), layer.UpSampleFactor, layer.UpSampleFactor); end end end end end end
Замените upsampleLayer
существующий в предварительно обученной сети с ее совместимой версией генерации кода upsampleBy2Layer
при помощи replaceLayer
(Deep Learning Toolbox) функция.
isUpsampleLayer = arrayfun(@(x) isa(x, 'upsampleLayer'), lGraph.Layers);
layerNameToReplace = lGraph.Layers(isUpsampleLayer).Name;
lGraph = replaceLayer(lGraph, layerNameToReplace, upsampleBy2Layer(layerNameToReplace));
Соберите layerGraph
в DAGNetwork
возразите готовый использовать для генерации кода при помощи assembleNetwork
(Deep Learning Toolbox) функция.
dagNet = assembleNetwork(lGraph)
dagNet = DAGNetwork with properties: Layers: [72×1 nnet.cnn.layer.Layer] Connections: [80×2 table] InputNames: {'data'} OutputNames: {'conv2Detection1_output_1' 'conv2Detection2_output_2'}
Сохраните сеть в MAT-файл.
matFile = 'yolov3DAGNetwork.mat'; save(matFile, 'dagNet');
yolov3Detect
Функция точки входаyolov3Detect
функция точки входа берет входное изображение и передает его обучившему сеть для предсказания через yolov3Predict
функция. yolov3Predict
функционируйте загружает сетевой объект из MAT-файла в персистентную переменную и снова использует постоянный объект для последующих вызовов предсказания. А именно, функция использует представление DAGNetwork сети, обученной в Обнаружении объектов Используя Глубокое обучение (Computer Vision Toolbox) пример YOLO v3. Предсказания от координат ячейки сетки YOLO v3 получены из yolov3Predict
вызовы затем преобразованы в координаты ограничительной рамки при помощи функций поддержки generateTiledAnchors
и applyAnchorBoxOffsets
.
type('yolov3Detect.m')
function [bboxes,scores,labels] = yolov3Detect(matFile, im, networkInputSize, networkOutputs, confidenceThreshold, overlapThreshold, classes) % The yolov3Detect function detects the bounding boxes, scores, and labels in an image. coder.extrinsic('generateYOLOv3Detections'); %% Preprcess 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]. im = preprocessData(im, networkInputSize); 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 % <docid:vision_ug#mw_47d9a223-5ec7-4d36-a020-4f9d147ecdec Object Detection % Using YOLO v3 Deep Learning> example. For details on estimating anchor % boxes, see <docid:vision_ug#mw_f9f22f48-0ad0-4f37-8bc1-22a2046637f2 % Anchor Boxes for Object Detection>. anchors = [150 127; 97 90; 68 67; 38 42; 41 29; 31 23]; % 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 anchorIndex = 2:5; % indices corresponding to x,y,w,h predictions for bounding boxes tiledAnchors = generateTiledAnchors(predictions,anchors,anchorBoxMasks,anchorIndex); predictions = applyAnchorBoxOffsets(tiledAnchors, predictions, networkInputSize, anchorIndex); [bboxes,scores,labels] = generateYOLOv3Detections(predictions, confidenceThreshold, overlapThreshold, imageSize, classes); % Apply suppression to the detections to filter out multiple overlapping % detections. if ~isempty(scores) [bboxes, scores, labels] = selectStrongestBboxMulticlass(bboxes, scores, labels ,... 'RatioType', 'Union', 'OverlapThreshold', overlapThreshold); end 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(size(networkOutputs)); [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;
Получите сетевой входной размер от входного слоя обучившего сеть и количества сетевых выходных параметров.
networkInputIdx = arrayfun(@(x)isa(x,'nnet.cnn.layer.ImageInputLayer'),net.Layers);
networkInputSize = net.Layers(networkInputIdx).InputSize;
networkOutputs = numel(dagNet.OutputNames);
Считайте данные изображения в качестве примера, полученные из набора маркированных данных от Обнаружения объектов Используя Глубокое обучение (Computer Vision Toolbox) пример YOLO v3. Это изображение содержит один экземпляр объекта транспортного средства типа.
I = imread('vehicleImage.jpg');
Задайте имена классов.
classNames = {'vehicle'};
Вызовите обнаружить метод на сеть YOLO v3 и отобразите результаты.
[bboxes,scores,~] = yolov3Detect(matFile, I, networkInputSize, networkOutputs, confidenceThreshold, overlapThreshold, classNames); % Display the detections on the image IAnnotated = insertObjectAnnotation(I, 'rectangle', bboxes, scores); figure imshow(IAnnotated)
Сгенерировать код CUDA® для yolov3Detect
функция точки входа, создайте объект настройки графического процессора кода для цели MEX и установите выходной язык на C++. Используйте coder.DeepLearningConfig
функция, чтобы создать настройку глубокого обучения CuDNN возражает и присвоить ее DeepLearningConfig
свойство объекта настройки графического процессора кода.
cfg = coder.gpuConfig('mex'); cfg.TargetLang = 'C++'; cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn'); args = {coder.Constant(matFile), I, coder.Constant(networkInputSize), networkOutputs, ... confidenceThreshold, overlapThreshold, classNames}; codegen -config cfg yolov3Detect -args args
Code generation successful: View report
Чтобы сгенерировать код CUDA® для цели TensorRT создают и используют объект настройки глубокого обучения TensorRT вместо объекта настройки CuDNN. Точно так же, чтобы сгенерировать код для цели MKLDNN, создайте объект настройки центрального процессора кода и используйте объект настройки глубокого обучения MKLDNN в качестве его DeepLearningConfig
свойство.
Вызовите сгенерированный MEX CUDA с тем же входом I
изображений
как прежде и отображают результаты.
[bboxes, scores, labels] = yolov3Detect_mex(matFile, I, networkInputSize, networkOutputs, ... confidenceThreshold, overlapThreshold, classNames); figure; IAnnotated = insertObjectAnnotation(I, 'rectangle', bboxes, scores); imshow(IAnnotated);
Служебные описанные ниже функции похожи на тех используемых в Обнаружении объектов Используя Глубокое обучение (Computer Vision Toolbox) пример YOLO v3, за исключением preProcessData
функция. В этом примере мы только предварительно обрабатываем данные изображения, различающиеся в Обнаружении объектов Используя Глубокое обучение (Computer Vision Toolbox) пример YOLO v3, где ограничительные рамки также обрабатываются.
type('applyActivations.m')
function YPredCell = applyActivations(YPredCell) for idx = 1:3 YPredCell{:, idx} = sigmoidActivation(YPredCell{:,idx}); end for idx = 4:5 YPredCell{:, idx} = exp(YPredCell{:, idx}); end YPredCell{:, 6} = sigmoidActivation(YPredCell{:, 6}); end function out = sigmoidActivation(x) out = 1./(1+exp(-x)); end
type('extractPredictions.m')
function predictions = extractPredictions(YPredictions, anchorBoxMask) predictions = cell(size(YPredictions, 1),6); for ii = 1:size(YPredictions, 1) numAnchors = size(anchorBoxMask{ii},2); % Confidence scores. startIdx = 1; endIdx = numAnchors; predictions{ii,1} = YPredictions{ii}(:,:,startIdx:endIdx,:); % X positions. startIdx = startIdx + numAnchors; endIdx = endIdx+numAnchors; predictions{ii,2} = YPredictions{ii}(:,:,startIdx:endIdx,:); % Y positions. startIdx = startIdx + numAnchors; endIdx = endIdx+numAnchors; predictions{ii,3} = YPredictions{ii}(:,:,startIdx:endIdx,:); % Width. startIdx = startIdx + numAnchors; endIdx = endIdx+numAnchors; predictions{ii,4} = YPredictions{ii}(:,:,startIdx:endIdx,:); % Height. startIdx = startIdx + numAnchors; endIdx = endIdx+numAnchors; predictions{ii,5} = YPredictions{ii}(:,:,startIdx:endIdx,:); % Class probabilities. startIdx = startIdx + numAnchors; predictions{ii,6} = YPredictions{ii}(:,:,startIdx:end,:); 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 tiledAnchors = cell(size(anchorIndex)); for i=1:size(YPredCell,1) 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) % Convert the predictions from the YOLO v3 grid cell coordinates to bounding box coordinates 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. 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(imresize(image, coder.const(targetSize(1:2)))); end
1. Redmon, Джозеф и Али Фархади. “YOLOv3: Инкрементное Улучшение”. Предварительно распечатайте, представленный 8 апреля 2018. https://arxiv.org/abs/1804.02767.