Обнаружение объектов с использованием глубокого обучения YOLO v2

В этом примере показано, как обучить детектор объектов (YOLO) v2 только один раз.

Глубокое обучение является мощным методом машинного обучения, который можно использовать для обучения устойчивых детекторов объектов. Существует несколько методов обнаружения объектов, включая Faster R-CNN, и вы смотрите только один раз (YOLO) v2. Этот пример обучает детектор транспортного средства YOLO v2, используя trainYOLOv2ObjectDetector функция. Для получения дополнительной информации смотрите Начало работы с YOLO v2.

Загрузить предварительно обученный детектор

Загрузите предварительно обученный детектор, чтобы избежать необходимости ждать завершения обучения. Если вы хотите обучить детектор, установите doTraining переменная - true.

doTraining = false;
if ~doTraining && ~exist('yolov2ResNet50VehicleExample_19b.mat','file')    
    disp('Downloading pretrained detector (98 MB)...');
    pretrainedURL = 'https://www.mathworks.com/supportfiles/vision/data/yolov2ResNet50VehicleExample_19b.mat';
    websave('yolov2ResNet50VehicleExample_19b.mat',pretrainedURL);
end

Загрузка набора данных

Этот пример использует небольшой набор данных транспортного средства, который содержит 295 изображений. Многие из этих изображений получены из наборов данных Caltech Cars 1999 и 2001, доступных на веб-сайте Caltech Computational Vision, созданном Пьетро Пероной и используемом с разрешения. Каждое изображение содержит один или два маркированных образца транспортного средства. Небольшой набор данных полезен для исследования процедуры обучения YOLO v2, но на практике для обучения устойчивого детектора необходимо больше маркированных изображений. Разархивируйте изображения транспортного средства и загружайте транспортное средство достоверных данных.

unzip vehicleDatasetImages.zip
data = load('vehicleDatasetGroundTruth.mat');
vehicleDataset = data.vehicleDataset;

Данные о транспортном средстве хранятся в двухколоночной таблице, где в первом столбце содержатся пути к файлам изображений, а во втором-ограничительные рамки транспортного средства.

% Display first few rows of the data set.
vehicleDataset(1:4,:)
ans=4×2 table
              imageFilename                vehicle   
    _________________________________    ____________

    {'vehicleImages/image_00001.jpg'}    {1×4 double}
    {'vehicleImages/image_00002.jpg'}    {1×4 double}
    {'vehicleImages/image_00003.jpg'}    {1×4 double}
    {'vehicleImages/image_00004.jpg'}    {1×4 double}

% Add the fullpath to the local vehicle data folder.
vehicleDataset.imageFilename = fullfile(pwd,vehicleDataset.imageFilename);

Разделите набор данных на наборы для обучения, валидации и тестирования. Выберите 60% данных для обучения, 10% для валидации и остальное для проверки обученного детектора.

rng(0);
shuffledIndices = randperm(height(vehicleDataset));
idx = floor(0.6 * length(shuffledIndices) );

trainingIdx = 1:idx;
trainingDataTbl = vehicleDataset(shuffledIndices(trainingIdx),:);

validationIdx = idx+1 : idx + 1 + floor(0.1 * length(shuffledIndices) );
validationDataTbl = vehicleDataset(shuffledIndices(validationIdx),:);

testIdx = validationIdx(end)+1 : length(shuffledIndices);
testDataTbl = vehicleDataset(shuffledIndices(testIdx),:);

Использование imageDatastore и boxLabelDatastore создать хранилища данных для загрузки изображения и данных о метках во время обучения и оценки.

imdsTrain = imageDatastore(trainingDataTbl{:,'imageFilename'});
bldsTrain = boxLabelDatastore(trainingDataTbl(:,'vehicle'));

imdsValidation = imageDatastore(validationDataTbl{:,'imageFilename'});
bldsValidation = boxLabelDatastore(validationDataTbl(:,'vehicle'));

imdsTest = imageDatastore(testDataTbl{:,'imageFilename'});
bldsTest = boxLabelDatastore(testDataTbl(:,'vehicle'));

Объедините хранилища данных меток изображений и коробок.

trainingData = combine(imdsTrain,bldsTrain);
validationData = combine(imdsValidation,bldsValidation);
testData = combine(imdsTest,bldsTest);

Отобразите одно из обучающих изображений и коробчатых меток.

data = read(trainingData);
I = data{1};
bbox = data{2};
annotatedImage = insertShape(I,'Rectangle',bbox);
annotatedImage = imresize(annotatedImage,2);
figure
imshow(annotatedImage)

Создайте сеть обнаружения объектов YOLO v2

Сеть обнаружения объектов YOLO v2 состоит из двух подсетей. Сеть редукции данных, за которой следует сеть обнаружения. Сеть редукции данных обычно является предварительно обученным CNN (для получения дополнительной информации смотрите Pretrained Глубоких нейронных сетей (Deep Learning Toolbox)). Этот пример использует ResNet-50 для редукции данных. Можно также использовать другие предварительно обученные сети, такие как MobileNet v2 или ResNet-18, также могут использоваться в зависимости от требований приложения. Подсеть обнаружения является небольшой CNN по сравнению с сетью редукции данных и состоит из нескольких сверточных слоев и слоев, характерных для YOLO v2.

Используйте yolov2Layers функция для создания сети обнаружения объектов YOLO v2 автоматически задает предварительно обученную ResNet-50 редукции данных сеть. yolov2Layers требует, чтобы вы задали несколько входов, которые параметризируют сеть YOLO v2:

  • Размер входа сети

  • Анкерные коробки

  • Сеть редукции данных

Во-первых, укажите размер входа сети и количество классов. При выборе размера входа сети учитывайте минимальный размер, требуемый самой сетью, размер обучающих изображений и вычислительные затраты, связанные с обработкой данных при выбранном размере. Когда это возможно, выберите размер входа сети, который близок к размеру обучающего изображения и больше, чем размер входного сигнала, необходимый для сети. Чтобы уменьшить вычислительные затраты на выполнение примера, укажите размер входа сети [224 224 3], который является минимальным размером, необходимым для запуска сети.

inputSize = [224 224 3];

Определите количество классов объектов, которые нужно обнаружить.

numClasses = width(vehicleDataset)-1;

Обратите внимание, что обучающие изображения, используемые в этом примере, больше 224 на 224 и варьируются в размере, поэтому вы должны изменить размер изображений на этапе предварительной обработки перед обучением.

Далее используйте estimateAnchorBoxes для оценки анкерных коробок на основе размера объектов в обучающих данных. Чтобы учесть изменение размера изображений перед обучением, измените размер обучающих данных для оценки анкерных коробок. Использование transform для предварительной обработки обучающих данных задайте количество анкерных коробок и оцените анкерные коробки. Измените размер обучающих данных на размер входного изображения сети с помощью вспомогательной функции preprocessData.

trainingDataForEstimation = transform(trainingData,@(data)preprocessData(data,inputSize));
numAnchors = 7;
[anchorBoxes, meanIoU] = estimateAnchorBoxes(trainingDataForEstimation, numAnchors)
anchorBoxes = 7×2

   162   136
    85    80
   149   123
    43    32
    65    63
   117   105
    33    27

meanIoU = 0.8472

Для получения дополнительной информации о выборе якорных коробок смотрите Оценка якорных коробок из обучающих данных (Computer Vision Toolbox™) и Якорных коробок для обнаружения объектов.

Теперь используйте resnet50 для загрузки предварительно обученной модели ResNet-50.

featureExtractionNetwork = resnet50;

Выберите 'activation_40_relu' как слой редукции данных для замены слоев после 'activation_40_relu' с подсетью обнаружения. Этот слой редукции данных выводит карты функций, которые уменьшаются в 16 раз. Такое количество понижающей дискретизации является хорошим компромиссом между пространственным разрешением и силой извлечённых функций, поскольку функции, извлеченные далее по сети, кодируют более сильные функции изображения за счет пространственного разрешения. Выбор оптимального слоя редукции данных требует эмпирического анализа.

featureLayer = 'activation_40_relu';

Создайте сеть обнаружения объектов YOLO v2.

lgraph = yolov2Layers(inputSize,numClasses,anchorBoxes,featureExtractionNetwork,featureLayer);

Визуализировать сеть можно используя analyzeNetwork или Deep Network Designer из Deep Learning Toolbox™.

Если требуется дополнительное управление сетевой архитектурой YOLO v2, используйте Deep Network Designer для разработки сети обнаружения YOLO v2 вручную. Для получения дополнительной информации смотрите Проект сети обнаружения YOLO v2.

Увеличение количества данных

Увеличение количества данных используется для повышения точности сети путем случайного преобразования исходных данных во время обучения. При помощи увеличения данных вы можете добавить больше разнообразия к обучающим данным, не увеличивая на самом деле количество маркированных обучающих выборок.

Использование transform увеличение обучающих данных путем случайного поворота изображения и связанных с ним прямоугольных меток горизонтально. Обратите внимание, что увеличение количества данных не применяется к тестовым и валидационным данным. В идеале данные испытаний и валидации должны быть показательными по сравнению с исходными данными и не должны быть изменены для объективной оценки.

augmentedTrainingData = transform(trainingData,@augmentData);

Считывайте одно и то же изображение несколько раз и отображайте дополненные обучающие данные.

% Visualize the augmented images.
augmentedData = cell(4,1);
for k = 1:4
    data = read(augmentedTrainingData);
    augmentedData{k} = insertShape(data{1},'Rectangle',data{2});
    reset(augmentedTrainingData);
end
figure
montage(augmentedData,'BorderSize',10)

Предварительная обработка обучающих данных

Предварительно обработайте дополненные обучающие данные и данные валидации для подготовки к обучению.

preprocessedTrainingData = transform(augmentedTrainingData,@(data)preprocessData(data,inputSize));
preprocessedValidationData = transform(validationData,@(data)preprocessData(data,inputSize));

Считайте предварительно обработанные обучающие данные.

data = read(preprocessedTrainingData);

Отобразите изображение и ограничительные рамки.

I = data{1};
bbox = data{2};
annotatedImage = insertShape(I,'Rectangle',bbox);
annotatedImage = imresize(annotatedImage,2);
figure
imshow(annotatedImage)

Обучите детектор объектов YOLO v2

Использование trainingOptions для определения опций обучения. Задайте 'ValidationData' к предварительно обработанным данным валидации. Задайте 'CheckpointPath' во временное место. Это позволяет экономить частично обученные детекторы в процессе обучения. Если обучение прервано, например, отключение степени или отказ системы, можно возобновить обучение с сохраненной контрольной точки.

options = trainingOptions('sgdm', ...
        'MiniBatchSize',16, ....
        'InitialLearnRate',1e-3, ...
        'MaxEpochs',20, ... 
        'CheckpointPath',tempdir, ...
        'ValidationData',preprocessedValidationData);

Использование trainYOLOv2ObjectDetector функция для обучения детектора объектов YOLO v2, если doTraining является true. В противном случае загружает предварительно обученную сеть

if doTraining       
    % Train the YOLO v2 detector.
    [detector,info] = trainYOLOv2ObjectDetector(preprocessedTrainingData,lgraph,options);
else
    % Load pretrained detector for the example.
    pretrained = load('yolov2ResNet50VehicleExample_19b.mat');
    detector = pretrained.detector;
end

Этот пример был проверен на NVIDIA™ графическом процессоре Titan X с 12 ГБ памяти. Если у вашего графического процессора меньше памяти, возможно, у вас закончится память. Если это произойдет, опустите 'MiniBatchSize' использование trainingOptions функция. Обучение этой сети заняло приблизительно 7 минут с помощью этой настройки. Время обучения варьируется в зависимости от используемого оборудования.

В качестве быстрого теста запустите детектор на тестовом изображении. Убедитесь, что вы изменили размер изображения на тот же размер, что и обучающие изображения.

I = imread('highway.png');
I = imresize(I,inputSize(1:2));
[bboxes,scores] = detect(detector,I);

Отображение результатов.

I = insertObjectAnnotation(I,'rectangle',bboxes,scores);
figure
imshow(I)

Оцените детектор с помощью тестового набора

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

Примените к тестовым данным то же преобразование предварительной обработки, что и к обучающим данным. Обратите внимание, что увеличение количества данных не применяется к тестовым данным. Тестовые данные должны быть показательными по сравнению с исходными данными и не должны быть изменены для объективной оценки.

preprocessedTestData = transform(testData,@(data)preprocessData(data,inputSize));

Запустите детектор на всех тестовых изображениях.

detectionResults = detect(detector, preprocessedTestData);

Оцените детектор объектов с помощью средней метрики точности.

[ap,recall,precision] = evaluateDetectionPrecision(detectionResults, preprocessedTestData);

Кривая точности/отзыва (PR) подсвечивает, насколько точен детектор на меняющихся уровнях отзыва. Идеальная точность 1 на всех уровнях отзыва. Использование большего количества данных может помочь улучшить среднюю точность, но может потребовать большего времени обучения. Постройте график кривой PR.

figure
plot(recall,precision)
xlabel('Recall')
ylabel('Precision')
grid on
title(sprintf('Average Precision = %.2f',ap))

Генерация кода

После обучения и оценки детектора можно сгенерировать код для yolov2ObjectDetector использование GPU Coder™. Более подробную информацию см. в разделе «Генерация кода для обнаружения объектов с помощью примера YOLO v2 (GPU Coder)».

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

function B = augmentData(A)
% Apply random horizontal flipping, and random X/Y scaling. Boxes that get
% scaled outside the bounds are clipped if the overlap is above 0.25. Also,
% jitter image color.

B = cell(size(A));

I = A{1};
sz = size(I);
if numel(sz)==3 && sz(3) == 3
    I = jitterColorHSV(I,...
        'Contrast',0.2,...
        'Hue',0,...
        'Saturation',0.1,...
        'Brightness',0.2);
end

% Randomly flip and scale image.
tform = randomAffine2d('XReflection',true,'Scale',[1 1.1]);
rout = affineOutputView(sz,tform,'BoundsStyle','CenterOutput');
B{1} = imwarp(I,tform,'OutputView',rout);

% Sanitize box data, if needed.
A{2} = helperSanitizeBoxes(A{2}, sz);

% Apply same transform to boxes.
[B{2},indices] = bboxwarp(A{2},tform,rout,'OverlapThreshold',0.25);
B{3} = A{3}(indices);

% Return original data only when all boxes are removed by warping.
if isempty(indices)
    B = A;
end
end

function data = preprocessData(data,targetSize)
% Resize image and bounding boxes to the targetSize.
sz = size(data{1},[1 2]);
scale = targetSize(1:2)./sz;
data{1} = imresize(data{1},targetSize(1:2));

% Sanitize box data, if needed.
data{2} = helperSanitizeBoxes(data{2},sz);

% Resize boxes to new image size.
data{2} = bboxresize(data{2},scale);
end

Ссылки

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

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