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

В этом примере показано, как обучить одиночный детектор выстрела (SSD).

Обзор

Глубокое обучение является мощным методом машинного обучения, которая автоматически изучает функции изображений, необходимые для задач обнаружения. Существует несколько методов обнаружения объектов с помощью глубокого обучения, таких как Faster R-CNN, You Only Look Once (YOLO v2) и SSD. Этот пример обучает детектор транспортного средства SSD, используя trainSSDObjectDetector функция. Для получения дополнительной информации см. Раздел «Обнаружение объектов».

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

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

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

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

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

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

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

vehicleDataset(1:4,:)
ans=4×2 table
              imageFilename                   vehicle     
    _________________________________    _________________

    {'vehicleImages/image_00001.jpg'}    {[220 136 35 28]}
    {'vehicleImages/image_00002.jpg'}    {[175 126 61 45]}
    {'vehicleImages/image_00003.jpg'}    {[108 120 45 33]}
    {'vehicleImages/image_00004.jpg'}    {[124 112 38 36]}

Разделите набор данных на набор обучающих данных для настройки детектора и тестовый набор для оценки детектора. Выберите 60% данных для обучения. Остальное используйте для оценки.

rng(0);
shuffledIndices = randperm(height(vehicleDataset));
idx = floor(0.6 * length(shuffledIndices) );
trainingData = vehicleDataset(shuffledIndices(1:idx),:);
testData = vehicleDataset(shuffledIndices(idx+1:end),:);

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

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

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

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

trainingData = combine(imdsTrain,bldsTrain);
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)

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

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

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

Используйте ssdLayers функция для автоматического изменения предварительно обученной ResNet-50 сети в сеть обнаружения объектов SSD. ssdLayers требуется задать несколько входов, которые параметризируют сеть SSD, включая размер входного сигнала сети и количество классов. При выборе размера входа сети учитывайте размер обучающих изображений и вычислительные затраты, связанные с обработкой данных при выбранном размере. Когда это возможно, выберите размер входа сети, который близок к размеру обучающего изображения. Однако, чтобы уменьшить вычислительные затраты на выполнение этого примера, размер входа сети выбирается равным [300 300 3]. Во время обучения, trainSSDObjectDetector автоматически изменяет размер обучающих изображений на размер входа сети.

inputSize = [300 300 3];

Задайте количество классов объектов для обнаружения.

numClasses = width(vehicleDataset)-1;

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

lgraph = ssdLayers(inputSize, numClasses, 'resnet50');

Визуализировать сеть можно используя analyzeNetwork или D eepNetworkDesigner из Deep Learning Toolbox™. Обратите внимание, что вы также можете создать пользовательский слой сети SSD. Для получения дополнительной информации смотрите Создание сети обнаружения объектов SSD.

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

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

  • Случайное отражение изображения и связанных прямоугольных меток по горизонтали.

  • Случайным образом масштабируйте изображение, связанные прямоугольные метки.

  • Цвет изображения дрожания.

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

augmentedTrainingData = transform(trainingData,@augmentData);

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

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));

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

data = read(preprocessedTrainingData);

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

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

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

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

options = trainingOptions('sgdm', ...
        'MiniBatchSize', 16, ....
        'InitialLearnRate',1e-1, ...
        'LearnRateSchedule', 'piecewise', ...
        'LearnRateDropPeriod', 30, ...
        'LearnRateDropFactor', 0.8, ...
        'MaxEpochs', 300, ...
        'VerboseFrequency', 50, ...        
        'CheckpointPath', tempdir, ...
        'Shuffle','every-epoch');

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

if doTraining
    % Train the SSD detector.
    [detector, info] = trainSSDObjectDetector(preprocessedTrainingData,lgraph,options);
else
    % Load pretrained detector for the example.
    pretrained = load('ssdResNet50VehicleExample_20a.mat');
    detector = pretrained.detector;
end

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

В качестве быстрого теста запустите детектор на одном тестовом изображении.

data = read(testData);
I = data{1,1};
I = imresize(I,inputSize(1:2));
[bboxes,scores] = detect(detector,I, 'Threshold', 0.4);

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

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

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

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

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

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

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

detectionResults = detect(detector, preprocessedTestData, 'Threshold', 0.4);

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

[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))

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

После обучения и оценки детектора можно сгенерировать код для ssdObjectDetector использование GPU Coder™. Для получения дополнительной информации смотрите Генерацию кода для обнаружения объектов с помощью примера Single Shot Multibox Detector.

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

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 boxes, 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 boxes, if needed.
data{2} = helperSanitizeBoxes(data{2}, sz);

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

Ссылки

[1] Лю, Вэй, Драгомир Ангуэлов, Думитру Эрхан, Кристиан Сегеди, Скотт Рид, Чэн Ян Фу, и Александр К. Берг. SSD: Single shot multibox detector (неопр.) (недоступная ссылка). 14-я Европейская конференция по компьютерному зрению, ECCV 2016. Springer Verlag, 2016.

См. также

Приложения

Функции

Объекты

Похожие темы