LoginSignup
6
7

More than 3 years have passed since last update.

5.6.2.7ディープラーニング:SSDによる物体検出

Posted at

目次へのリンク

MATLABによる画像処理・コンピュータービジョン入門目次

概要

このデモではSSD(Single Shot Multibox Detector)による物体検出器の学習および推論を行います。

実行には下記のToolboxが必要になります。

  • MATLAB R2020a 以降
  • Image Processing Toolbox
  • Computer Vision Toolbox
  • Deep Learning Toolbox
  • Parallel Computing Toolbox (NVIDIA GPUでの学習・推論の高速化)

この例ではバックボーンのネットワークとしてResNet50を使用します。

ResNet50の読み込みには無償のアドオンをインストールが必要です。 (※[ホーム]-[アドオン]からインストール)

対応ファイル

さらにGPUコード生成を通してNVIDIA Jetson Nanoへの実装を行います。

GPU実装には下記のToolboxが必要です。

CUDAコードのビルドはターゲット上で行うためホスト側にNVIDIA GPUやCUDA Toolkitなどは不要です。

初期化

code
clear; close all force; clc; rng('default');

車両検出器用の学習データセットをロード

同梱の車両検出用のラベリング済み学習データセットを展開します。

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

学習データとテスト用データに分割

学習用データ(60%)とテスト用データ(40%)に分割

code
rng(0); % 乱数シードを実行毎に固定にする(同じ結果を再現できるように)
shuffledIndices = randperm(height(vehicleDataset));
idx = floor(0.6 * length(shuffledIndices) );
trainingData = vehicleDataset(shuffledIndices(1:idx),:);
testData = vehicleDataset(shuffledIndices(idx+1:end),:);

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

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

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

SSDネットワークを定義

ResNet50をベースにSSDのネットワークを定義します。

code
% 入力画像サイズ
inputSize = [300 300 3];

% クラス数(今回は車両のみなので1個)
numClasses = width(vehicleDataset)-1;

% SSDネットワークの作成(ベースはvgg16, resnet50, resnet101が使用可能)
lgraph = ssdLayers(inputSize, numClasses, 'resnet50');

% プロットする
figure('Units','normalized','Position',[0.1 0.1 0.8 0.8]);
plot(lgraph);

figure_0.png

データの水増しと前処理

反転やシフトなどのデータ拡張(水増し、augmentation)を学習時に適用し、検出器の汎用性を高めます。

その後、ネットワークの入力に合わせてリサイズを行います。

code
% データの水増し(反転・移動)
augmentedTrainingData = transform(trainingData,@augmentData);
% 前処理(リサイズ)
preprocessedTrainingData = transform(augmentedTrainingData,@(data)preprocessData(data,inputSize));

学習オプションを指定

学習率は初期値は0.1とし、30エポックごとに0.8かけて小さくしていきます。

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

SSDネットワークの学習

学習を実行します。(GPUがない場合は数十時間かかります。)

code
doTraining = false;
if doTraining
    [detector, info] = trainSSDObjectDetector(preprocessedTrainingData,lgraph,options);
    save('ssdResNet50VehicleExample_20a','detector');
else
    % 学習済みモデルは以下でダウンロード可能
    if ~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
    pretrained = load('ssdResNet50VehicleExample_20a.mat');
    detector = pretrained.detector;
end

テスト画像の読み込みと学習済みSSDによる検出

テストデータから1枚画像を読み込み、検出を実行します。

実行結果を可視化し、目視で確認します。

code
data = read(testData); % テストデータから1枚読み込み
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)

figure_1.png

テストデータセットを使い検出器の性能評価

テストデータセット全体を使って検出器の性能を評価します。

テストデータの真値と検出結果を使ってPR曲線を計算します。

今回はIoU(どれぐらい真値のバウンディングボックスと検出結果のバウンディングボックスが重なるか)が

0.5以上の検出を対象します。

code
% テストデータに前処理適用(ただし、データの拡張は行わない)
preprocessedTestData = transform(testData,@(data)preprocessData(data,inputSize));

% 全てのテストデータに検出器をかける (スコアが0.4以上のものを検出結果として出力)
detectionResults = detect(detector, preprocessedTestData, 'Threshold', 0.4);

% 平均精度, 再現率, 適合率を計算
[ap,recall,precision] = evaluateDetectionPrecision(detectionResults, preprocessedTestData);

% PR曲線を表示
figure
plot(recall,precision)
xlabel('Recall')
ylabel('Precision')
grid on
title(sprintf('Average Precision = %.2f',ap))
axis([0 1 0 1]);

figure_2.png

学習したSSDをNVIDIA Jetson Nano向けにCUDAコード生成

学習したSSDの検出器をNVIDIA Jetson Nanoに実装します。GPU実装には下記のToolboxが必要です。

Jetson実装に関連するハードウェアやソフトウェアの設定は上記のアドオンのヘルプをご覧ください。

セットアップが完了していないと下記は実行できないのでご注意ください。

Jetsonに接続

jetsonコマンドでJetsonに接続します。

code
hwobj = jetson('192.168.55.1','nvidia','nvidia')
output
Checking for CUDA availability on the Target...
Checking for 'nvcc' in the target system path...
Checking for cuDNN library availability on the Target...
Checking for TensorRT library availability on the Target...
Checking for prerequisite libraries is complete.
Gathering hardware details...
Checking for third-party library availability on the Target...
Gathering hardware details is complete.
 Board name         : NVIDIA Jetson TX1
 CUDA Version       : 10.0
 cuDNN Version      : 7.3
 TensorRT Version   : 5.0
 GStreamer Version  : 1.14.5
 V4L2 Version       : 1.14.2-1
 SDL Version        : 1.2
 Available Webcams  : Microsoft® LifeCam Cinema(TM)
 Available GPUs     : NVIDIA Tegra X1
hwobj = 
  jetson のプロパティ:

       DeviceAddress: '192.168.55.1'
                Port: 22
           BoardName: 'NVIDIA Jetson TX1'
         CUDAVersion: '10.0'
        cuDNNVersion: '7.3'
     TensorRTVersion: '5.0'
          SDLVersion: '1.2'
         V4L2Version: '1.14.2-1'
    GStreamerVersion: '1.14.5'
             GPUInfo: [1x1 struct]
          WebcamList: {'Microsoft® LifeCam Cinema(TM)'}

Jetson Nanoのカメラに映すテスト画像を表示

画像をディスプレイに最大サイズで表示します。

code
data = read(testData);
I = data{1,1};
figure;
set(gcf,'Visible','on','units','normalized','outerposition',[0 0 1 1]);
imshow(I)

figure_3.png

Jetsonに接続されているカメラで画像取得

表示している車両画像を取り込みます。

code
clear cam display;
cam = hwobj.webcam; % カメラデバイスを取得
img = snapshot(cam); % 1枚画像取得
display = hwobj.imageDisplay; % ディスプレイを取得
figure;
display.image(img); % ディスプレイに表示

figure_5.png

車両検出のプログラムを作成

code
type vehicleDetection.m

MATLAB上で作成した車両検出プログラムを実行

Jetsonのカメラから画像をMATLAB上に取り込んで処理します。

まだ、Jetson上でプログラムが動いているわけではないことに注意してください。

code
vehicleDetection

CUDA Cをコード生成しJetsonでビルド

Jetson Nano向けにCUDAコードを生成し、ビルドします。

クロスコンパイルではなくターゲット上でのコンパイルのためCUDA ToolkitはホストPCには不要です。

SSDの推論はTensorRTをバックエンドとして使用します。

code
cfg = coder.gpuConfig('exe');
cfg.Hardware = coder.hardware('NVIDIA Jetson');
cfg.Hardware.BuildDir = '~/remoteBuildDir';
cfg.GenerateExampleMain = 'GenerateCodeAndCompile';
cfg.GenerateReport = true;
cfg.LaunchReport = true;
codegen('-config ',cfg,'vehicleDetection','-report','-v');

Jetson上でアルゴリズム実行

ビルドしたJetson Nano上の実行ファイルを実行します。

code
clear hwobj cam display;
hwobj = jetson
output
Checking for CUDA availability on the Target...
Checking for 'nvcc' in the target system path...
Checking for cuDNN library availability on the Target...
Checking for TensorRT library availability on the Target...
Checking for prerequisite libraries is complete.
Gathering hardware details...
Checking for third-party library availability on the Target...
Gathering hardware details is complete.
 Board name         : NVIDIA Jetson TX1
 CUDA Version       : 10.0
 cuDNN Version      : 7.3
 TensorRT Version   : 5.0
 GStreamer Version  : 1.14.5
 V4L2 Version       : 1.14.2-1
 SDL Version        : 1.2
 Available Webcams  : Microsoft® LifeCam Cinema(TM)
 Available GPUs     : NVIDIA Tegra X1
hwobj = 
  jetson のプロパティ:

       DeviceAddress: '192.168.55.1'
                Port: 22
           BoardName: 'NVIDIA Jetson TX1'
         CUDAVersion: '10.0'
        cuDNNVersion: '7.3'
     TensorRTVersion: '5.0'
          SDLVersion: '1.2'
         V4L2Version: '1.14.2-1'
    GStreamerVersion: '1.14.5'
             GPUInfo: [1x1 struct]
          WebcamList: {'Microsoft® LifeCam Cinema(TM)'}

code
hwobj.setDisplayEnvironment('0.0');
pid = hwobj.runApplication('vehicleDetection');
output
### Launching the executable on the target...
Executable launched successfully with process ID 10988.
Displaying the simple runtime log for the executable...

Note: For the complete log, run the following command in the MATLAB command window:
system(hwobj,'cat /home/nvidia/remoteBuildDir/MATLAB_ws/R2020a/C/IPCV_Eval_Kit/demo_files/vehicleDetection.log')

下記のような実行結果が得られます。(Jetson Nano上の実行結果をVNCを使ってキャプチャ)

image_0.png

今回はバックボーンがResNet50のためJetson Nano上で数fps程度の速度しか得られません。

Mobilenet v2などをバックボーンにするとより軽量で高速な検出器が学習できます。

実行中のプロセスを停止

code
% hwobj.killProcess(pid);

まとめ

SSDによる物体検出器の学習、推論およびGPUコード生成について紹介しました。

参考

謝辞

本記事は @eigs さんのlivescript2markdownを使わせていただいてます。

目次へのリンク

MATLABによる画像処理・コンピュータービジョン入門目次

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7