Импорт предварительно обученного детектора объектов ONNX YOLO v2

В этом примере показано, как импортировать предварительно обученную ONNX™ (Open Neural Network Exchange), которую вы смотрите только один раз (YOLO) v2 [1] сети обнаружения объектов и используете ее для обнаружения объектов. После импорта сети ее можно развернуть на встраиваемых платформах с помощью GPU Coder™ или переобучить на пользовательских данных с помощью передачи обучения с trainYOLOv2ObjectDetector.

Скачать ONNX YOLO v2 Network

Загрузите файлы, относящиеся к предварительно обученной сети Tiny YOLO v2.

pretrainedURL = 'https://ssd.mathworks.com/supportfiles/vision/deeplearning/models/yolov2/tiny_yolov2.tar';
pretrainedNetTar = 'yolov2Tiny.tar';
if ~exist(pretrainedNetTar,'file')
    disp('Downloading pretrained network (58 MB)...');
    websave(pretrainedNetTar,pretrainedURL);
end
Downloading pretrained network (58 MB)...

Извлечение сети YOLO v2

Чтобы извлечь сеть Tiny YOLO v2, распакуйте загруженный файл. Загрузите 'Model.onnx' модель из tiny_yolov2 папка, которая является сетью ONNX YOLO v2, предварительно обученной на наборе данных PASCAL VOC. Сеть может обнаруживать объекты из 20 различных классов [4].

onnxfiles = untar(pretrainedNetTar);
pretrainedNet = 'tiny_yolov2/Model.onnx';

Импорт слоев ONNX YOLO v2

Используйте importONNXLayers функция для импорта загруженной сети.

lgraph = importONNXLayers(pretrainedNet,'ImportWeights',true);
Warning: Imported layers have no output layer because ONNX files do not specify the network's output layer type. The layers will not be trainable until an output layer is added. Either add an output layer to the imported layers, or specify the output layer type using 'OutputLayerType' in the call to importONNXLayers.

В этом примере вы добавляете слой выхода к импортированным слоям, поэтому можно игнорировать это предупреждение. В разделе Add YOLO v2 Transform and Output Layers показано, как добавить выходной слой YOLO v2 вместе со слоем YOLO v2 Transform к импортированным слоям.

Сеть в этом примере не содержит неподдерживаемых слоев. Обратите внимание, что если импортируемая сеть имеет неподдерживаемые слои, функция импортирует их как слои-заполнители. Перед использованием импортированной сети необходимо заменить эти слои. Дополнительные сведения о замене слоев-заполнителей см. в разделе findPlaceholderLayers (Deep Learning Toolbox).

Задайте якорные коробки YOLO v2

YOLO v2 использует предопределенные якорные рамки для предсказания местоположения объекта. Анкерные ящики, используемые в импортированной сети, определены в файле строения сети Tiny YOLO v2 [5]. Якоря ONNX заданы относительно выхода размера конечного слоя свертки, который составляет 13 на 13. Как использовать якоря с yolov2ObjectDetectorизмените размер анкерных блоков на размер входного сигнала сети, который составляет 416 416. Якорные коробки для yolov2ObjectDetector необходимо указать в форме [высота, ширина].

onnxAnchors = [1.08,1.19; 3.42,4.41; 6.63,11.38; 9.42,5.11; 16.62,10.52];

inputSize = lgraph.Layers(1,1).InputSize(1:2);
lastActivationSize = [13,13];
upScaleFactor = inputSize./lastActivationSize;
anchorBoxesTmp = upScaleFactor.* onnxAnchors;
anchorBoxes = [anchorBoxesTmp(:,2),anchorBoxesTmp(:,1)];

Переупорядочение весов слоя обнаружения

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

  • Каналы с 1 по 5 - значения IoU для пяти якорей

  • Каналы с 6 по 10 - значения X для пяти якорей

  • Каналы с 11 по 15 - значения Y для пяти якорей

  • Каналы с 16 по 20 - Значения ширины для пяти якорей

  • Каналы с 21 по 25 - Значения высоты для пяти якорей

  • Каналы с 26 по 30 - значения вероятностей класса 1 для пяти якорей

  • Каналы с 31 по 35 - значения вероятностей класса 2 для пяти якорей

  • Каналы с 121 по 125 - значения вероятностей класса 20 для пяти якорей

Однако в последнем слое свертки, который имеет размер 13 на 13, активации расположены по-другому. Каждый из 25 каналов в карте функций соответствует:

  • Канал 1 - значения X

  • Канал 2 - значения Y

  • Канал 3 - Значения ширины

  • Канал 4 - Значения высоты

  • Канал 5 - значения IoU

  • Канал 6 - значения вероятностей класса 1

  • Канал 7 - значения вероятностей класса 2

  • Канал 25 - значения вероятностей класса 20

Используйте вспомогательную функцию rearrangeONNXWeights, перечисленный в конце этого примера, чтобы переупорядочить веса и смещения последнего слоя свертки в импортированной сети и получить активации в формате, требуемом yolov2ObjectDetector.

weights = lgraph.Layers(end,1).Weights;
bias = lgraph.Layers(end,1).Bias;
layerName = lgraph.Layers(end,1).Name;

numAnchorBoxes = size(onnxAnchors,1);
[modWeights,modBias] = rearrangeONNXWeights(weights,bias,numAnchorBoxes);

Замените веса и смещения последнего слоя свертки в импортированной сети новым слоем свертки с помощью переупорядоченных весов и смещений.

filterSize = size(modWeights,[1 2]);
numFilters = size(modWeights,4);
modConvolution8 = convolution2dLayer(filterSize,numFilters,...
    'Name',layerName,'Bias',modBias,'Weights',modWeights);
lgraph = replaceLayer(lgraph,'convolution8',modConvolution8);

Добавление слоев преобразования YOLO v2 и выхода

Сеть обнаружения YOLO v2 требует слоев преобразования YOLO v2 и выхода YOLO v2. Создайте оба этих слоев, сложите их последовательно и присоедините слой преобразования YOLO v2 к последнему слою свертки.

classNames = tinyYOLOv2Classes;

layersToAdd = [
    yolov2TransformLayer(numAnchorBoxes,'Name','yolov2Transform');
    yolov2OutputLayer(anchorBoxes,'Classes',classNames,'Name','yolov2Output');
    ];

lgraph = addLayers(lgraph, layersToAdd);
lgraph = connectLayers(lgraph,layerName,'yolov2Transform');

The ElementwiseAffineLayer в импортированной сети дублирует шаг предварительной обработки, выполненный yolov2ObjectDetector. Следовательно, удалите ElementwiseAffineLayer из импортированной сети.

yoloScaleLayerIdx = find(...
    arrayfun( @(x)isa(x,'nnet.onnx.layer.ElementwiseAffineLayer'), ...
    lgraph.Layers));

if ~isempty(yoloScaleLayerIdx)
    for i = 1:size(yoloScaleLayerIdx,1)
        layerNames {i} = lgraph.Layers(yoloScaleLayerIdx(i,1),1).Name;
    end
    lgraph = removeLayers(lgraph,layerNames);
    lgraph = connectLayers(lgraph,'Input_image','convolution');
end

Создайте детектор объектов YOLO v2

Соберите график слоев с помощью assembleNetwork и создайте детектор объектов YOLO v2 с помощью yolov2ObjectDetector функция.

net = assembleNetwork(lgraph)
net = 
  DAGNetwork with properties:

         Layers: [34×1 nnet.cnn.layer.Layer]
    Connections: [33×2 table]
     InputNames: {'Input_image'}
    OutputNames: {'yolov2Output'}

yolov2Detector = yolov2ObjectDetector(net)
yolov2Detector = 
  yolov2ObjectDetector with properties:

            ModelName: 'importedNetwork'
              Network: [1×1 DAGNetwork]
    TrainingImageSize: [416 416]
          AnchorBoxes: [5×2 double]
           ClassNames: [aeroplane    bicycle    bird    boat    bottle    bus    car    cat    chair    cow    diningtable    dog    horse    motorbike    person    pottedplant    sheep    sofa    train    tvmonitor]

Обнаружение объектов с помощью импортированного детектора YOLO v2

Используйте импортированный детектор для обнаружения объектов в тестовом изображении. Отображение результатов.

I = imread('highway.png');
% Convert image to BGR format.
Ibgr = cat(3,I(:,:,3),I(:,:,2),I(:,:,1));
[bboxes, scores, labels] = detect(yolov2Detector, Ibgr);
detectedImg = insertObjectAnnotation(I, 'rectangle', bboxes, scores);
figure
imshow(detectedImg);

Вспомогательные функции

function [modWeights,modBias] = rearrangeONNXWeights(weights,bias,numAnchorBoxes)
%rearrangeONNXWeights rearranges the weights and biases of an imported YOLO
%v2 network as required by yolov2ObjectDetector. numAnchorBoxes is a scalar
%value containing the number of anchors that are used to reorder the weights and
%biases. This function performs the following operations:
%   * Extract the weights and biases related to IoU, boxes, and classes.
%   * Reorder the extracted weights and biases as expected by yolov2ObjectDetector.
%   * Combine and reshape them back to the original dimensions.

weightsSize = size(weights);
biasSize = size(bias);
sizeOfPredictions = biasSize(3)/numAnchorBoxes;

% Reshape the weights with regard to the size of the predictions and anchors.
reshapedWeights = reshape(weights,prod(weightsSize(1:3)),sizeOfPredictions,numAnchorBoxes);

% Extract the weights related to IoU, boxes, and classes.
weightsIou = reshapedWeights(:,5,:);
weightsBoxes = reshapedWeights(:,1:4,:);
weightsClasses = reshapedWeights(:,6:end,:);

% Combine the weights of the extracted parameters as required by
% yolov2ObjectDetector.
reorderedWeights = cat(2,weightsIou,weightsBoxes,weightsClasses);
permutedWeights = permute(reorderedWeights,[1 3 2]);

% Reshape the new weights to the original size.
modWeights = reshape(permutedWeights,weightsSize);

% Reshape the biases with regared to the size of the predictions and anchors.
reshapedBias = reshape(bias,sizeOfPredictions,numAnchorBoxes);

% Extract the biases related to IoU, boxes, and classes.
biasIou = reshapedBias(5,:);
biasBoxes = reshapedBias(1:4,:);
biasClasses = reshapedBias(6:end,:);

% Combine the biases of the extracted parameters as required by yolov2ObjectDetector.
reorderedBias = cat(1,biasIou,biasBoxes,biasClasses);
permutedBias = permute(reorderedBias,[2 1]);

% Reshape the new biases to the original size.
modBias = reshape(permutedBias,biasSize);
end


function classes = tinyYOLOv2Classes()
% Return the class names corresponding to the pretrained ONNX tiny YOLO v2
% network.
%
% The tiny YOLO v2 network is pretrained on the Pascal VOC data set,
% which contains images from 20 different classes [4].

classes = [ ...
    " aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car",...
    "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike",...
    "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"];
end

Ссылки

[1] Редмон, Джозеф и Али Фархади. «YOLO9000: Лучше, Быстрее, Сильнее». В 2017 году IEEE Conference on Компьютерное Зрение and Pattern Recognition (CVPR), 6517-25. Гонолулу, HI: IEEE, 2017. https://doi.org/10.1109/CVPR.2017.690.

[2] «Tiny YOLO v2 Model». https://github.com/onnx/models/tree/master/vision/object_detection_segmentation/tiny-yolov2

[3] «Tiny YOLO v2 Model License». https://github.com/onnx/onnx/blob/master/LICENSE.

[4] Эверингем, Марк, Люк Ван Голь, Кристофер К. И. Уильямс, Джон Уинн и Эндрю Зиссерман. «Вызов Pascal Visual Классы (LOS)». Международный журнал компьютерного зрения 88, № 2 (июнь 2010): 303-38. https://doi.org/10.1007/s11263-009-0275-4.

[5] «yolov2-tiny-voc.cfg» https://github.com/pjreddie/darknet/blob/master/cfg/yolov2-tiny-voc.cfg.

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