Main Content

이 번역 페이지는 최신 내용을 담고 있지 않습니다. 최신 내용을 영문으로 보려면 여기를 클릭하십시오.

YOLO v2 딥러닝을 사용한 객체 검출

이 예제에서는 YOLO(You Only Look Once) v2 사물 검출기를 훈련시키는 방법을 다룹니다.

딥러닝은 강건한 사물 검출기를 훈련시키는 데 사용할 수 있는 강력한 머신러닝 기법입니다. Faster R-CNN과 YOLO(You Only Look Once) 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개의 영상을 포함하는 소규모의 차량 데이터셋을 사용합니다. 각 영상에는 차량에 대해 레이블 지정된 건수가 한 건 또는 두 건 있습니다. 작은 데이터셋은 YOLO v2 훈련 절차를 살펴보기에 유용하지만, 실전에서 강건한 검출기를 훈련시키려면 레이블이 지정된 영상이 더 많이 필요합니다. 차량 영상의 압축을 풀고 차량 실측 데이터를 불러옵니다.

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

차량 데이터는 2열 테이블에 저장되어 있습니다. 첫 번째 열은 영상 파일 경로를 포함하고, 두 번째 열은 차량 경계 상자를 포함합니다.

% 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),:);

imageDatastoreboxLabelDatastore를 사용하여 훈련과 평가 과정에서 영상 및 레이블 데이터를 불러오기 위한 데이터저장소를 만듭니다.

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 객체 검출 신경망은 2개의 하위 신경망으로 구성됩니다. 하나의 특징 추출 신경망이 있고, 그 뒤에 검출 신경망이 옵니다. 특징 추출 신경망은 일반적으로 사전 훈련된 CNN입니다(자세한 내용은 사전 훈련된 심층 신경망 참조). 이 예제에서는 특징 추출에 ResNet-50을 사용합니다. 응용 사례의 요구 사항에 따라 MobileNet v2나 ResNet-18과 같은 여타 사전 훈련된 신경망도 사용할 수 있습니다. 검출 하위 신경망은 특징 추출 신경망에 비해 규모가 작은 CNN으로, 몇 개의 컨벌루션 계층과 YOLO v2 전용 계층으로 구성됩니다.

yolov2Layers (Computer Vision Toolbox) 함수를 사용하여, 사전 훈련된 ResNet-50 특징 추출 신경망이 주어졌을 때 자동으로 YOLO v2 객체 검출 신경망을 만듭니다. yolov2Layers를 사용할 때는 YOLO v2 신경망을 파라미터화하는 다음과 같은 몇 개의 입력값을 지정해야 합니다.

  • 신경망 입력 크기

  • 앵커 상자

  • 특징 추출 신경망

먼저 신경망 입력 크기와 클래스 개수를 지정합니다. 신경망 입력 크기를 선택할 때는 신경망 자체에서 요구되는 최소 크기, 훈련 영상의 크기, 그리고 선택한 크기에서 데이터를 처리할 때 발생하는 계산 비용을 고려해야 합니다. 가능하다면, 훈련 영상의 크기와 가깝고 신경망에서 요구되는 입력 크기보다 큰 신경망 입력 크기를 선택하십시오. 예제를 실행하는 데 소요되는 계산 비용을 줄이려면 신경망을 실행하는 데 필요한 최소 크기인 [224 224 3]으로 신경망 입력 크기를 지정하십시오.

inputSize = [224 224 3];

검출할 사물 클래스의 개수를 정의합니다.

numClasses = width(vehicleDataset)-1;

이 예제에서 사용되는 훈련 영상은 224x224보다 크고 크기가 다양하므로 훈련 전 전처리 단계에서 영상을 크기 조정해야 합니다.

다음으로, estimateAnchorBoxes (Computer Vision Toolbox)를 사용하여 훈련 데이터의 사물 크기를 기반으로 앵커 상자를 추정합니다. 훈련 전 이루어지는 영상 크기 조정을 고려하기 위해 앵커 상자 추정에 사용하는 훈련 데이터를 크기 조정하십시오. transform을 사용하여 훈련 데이터를 전처리한 후에 앵커 상자의 개수를 정의하고 앵커 상자를 추정합니다. 지원 함수 preprocessData를 사용하여 훈련 데이터를 신경망의 입력 영상 크기로 크기 조정합니다.

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

   145   126
    91    86
   161   132
    41    34
    67    64
   136   111
    33    23

meanIoU = 0.8651

앵커 상자 선택에 관한 자세한 내용은 Estimate Anchor Boxes From Training Data (Computer Vision Toolbox)(Computer Vision Toolbox™) 및 Anchor Boxes for Object Detection (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 Learning Toolbox™의 심층 신경망 디자이너를 사용하여 신경망을 시각화할 수 있습니다.

YOLO v2 신경망 아키텍처를 더욱 세부적으로 제어해야 하는 경우에는 심층 신경망 디자이너를 사용하여 YOLO v2 검출 신경망을 직접 설계하십시오. 자세한 내용은 Design a YOLO v2 Detection Network (Computer Vision Toolbox) 항목을 참조하십시오.

데이터 증대

데이터 증대는 훈련 중에 원본 데이터를 무작위로 변환함으로써 신경망 정확도를 개선하는 데 사용됩니다. 데이터 증대를 사용하면 레이블이 지정된 훈련 샘플의 개수를 늘리지 않고도 훈련 데이터에 다양성을 더할 수 있습니다.

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

doTraining이 true인 경우, trainYOLOv2ObjectDetector (Computer Vision Toolbox) 함수를 사용하여 YOLO v2 사물 검출기를 훈련시키십시오. 그렇지 않은 경우에는 사전 훈련된 신경망을 불러오십시오.

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

이 예제는 12GB의 메모리가 탑재된 NVIDIA™ Titan X GPU에서 검증되었습니다. GPU 메모리가 이보다 적으면 메모리 부족이 발생할 수 있습니다. 메모리 부족이 발생할 경우 trainingOptions 함수를 사용하여 'MiniBatchSize'를 줄이십시오. 이 설정을 사용하여 이 신경망을 훈련시키는 데 약 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))

코드 생성

검출기의 훈련과 평가를 마친 후에는 GPU Coder™를 사용하여 yolov2ObjectDetector에 대한 코드를 생성할 수 있습니다. 자세한 내용은 Code Generation for Object Detection by Using 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);

% 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.
scale = targetSize(1:2)./size(data{1},[1 2]);
data{1} = imresize(data{1},targetSize(1:2));
data{2} = bboxresize(data{2},scale);
end

참고 문헌

[1] Redmon, Joseph, and Ali Farhadi. "YOLO9000: Better, Faster, Stronger." 2017 IEEE Conference on Computer Vision and Pattern Recognition (CVPR). IEEE, 2017.