このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
Complex-YOLO v4 ネットワークを使用した LiDAR オブジェクト検出
この例では、You Only Look Once version 4 (YOLO v4) 深層学習ネットワークを使用して、点群内のオブジェクトを検出する方法を説明します。この例では、次の作業を行います。
YOLO v4 オブジェクト検出ネットワークの学習、検証、テスト用のデータセットを構成。また、点群を鳥瞰ビュー (BEV) イメージに変換するための前処理も実行。
YOLO v4 オブジェクト検出ネットワークの学習で使用するため、学習データからアンカー ボックスを計算。
関数
yolov4ObjectDetector
を使用して YOLO v4 オブジェクト検出器を作成し、関数trainYOLOv4ObjectDetector
を使用して検出器の学習を実行。
Complex-YOLO [1] 法は、点群から変換された鳥瞰ビューの RGB マップ上で直接演算を行うため、LiDAR オブジェクト検出に効果的です。この例では、Complex-YOLO 法を使用して、鳥瞰ビュー フレーム内の 2 次元ボックスの位置と向きの両方を予測できるように YOLO v4 [2] ネットワークに学習させます。次に、2 次元の位置と向きに関する予測を点群に投影し直して、対象オブジェクトの周囲に 3 次元境界ボックスを生成します。
LiDAR データ セットのダウンロード
この例では、2560 個の前処理済みのオーガナイズド点群を含む PandaSet データ セット [3] のサブセットを使用します。各点群は、360 度の視界をカバーし、64 行 1856 列の行列として指定されます。この点群は PCD 形式で保存されており、対応するグラウンド トゥルース データは PandaSetLidarGroundTruth.mat
ファイルに保存されています。このファイルには、3 つのクラス (自動車、トラック、歩行者) の 3 次元境界ボックスの情報が格納されています。このデータ セットのサイズは 5.2 GB です。
この例の終わりに定義されている helperDownloadPandasetData
補助関数を使用して、指定された URL から PandaSet データ セットをダウンロードします。
outputFolder = fullfile(tempdir,'Pandaset'); lidarURL = ['https://ssd.mathworks.com/supportfiles/lidar/data/' ... 'Pandaset_LidarData.tar.gz']; helperDownloadPandasetData(outputFolder,lidarURL);
インターネット接続の速度によっては、ダウンロード プロセスに時間がかかることがあります。このコードは、ダウンロード プロセスが完了するまで、MATLAB® の実行を一時停止します。または、Web ブラウザーを使用してデータ セットをローカル ディスクにダウンロードし、ファイルを抽出することもできます。その場合は、コード内の変数 outputFolder
を、ダウンロードしたファイルの場所に変更します。ダウンロードしたファイルには、Lidar
フォルダー、Cuboids
フォルダー、および semanticLabels
フォルダーが含まれており、それぞれ点群、直方体ラベル情報、セマンティック ラベル情報が格納されています。
データの読み込み
関数pcread
を使用して、指定されたパスから PCD ファイルを読み込むためのファイル データストアを作成します。
path = fullfile(outputFolder,'Lidar'); pcds = fileDatastore(path,'ReadFcn',@(x) pcread(x));
自動車、トラック、および歩行者のオブジェクトの 3 次元境界ボックス ラベルを読み込みます。
gtPath = fullfile(outputFolder,'Cuboids','PandaSetLidarGroundTruth.mat'); data = load(gtPath,'lidarGtLabels'); Labels = timetable2table(data.lidarGtLabels); boxLabels = Labels(:,2:end);
フルビューの点群を表示します。
figure ptCld = read(pcds); ax = pcshow(ptCld.Location); set(ax,'XLim',[-50 50],'YLim',[-40 40]); zoom(ax,2.5); axis off;
点群データからの鳥瞰ビュー イメージの作成
PandaSet データは、フルビューの点群で構成されています。この例では、フルビューの点群を切り取り、標準パラメーターを使用して鳥瞰ビュー イメージに変換します。これらのパラメーターは、ネットワークに渡される入力のサイズを決定します。x 軸、y 軸、および z 軸に沿ってより狭い範囲の点群を選択すると、原点に近いオブジェクトを検出しやすくなります。
xMin = -25.0; xMax = 25.0; yMin = 0.0; yMax = 50.0; zMin = -7.0; zMax = 15.0;
鳥瞰ビュー イメージの次元を定義します。鳥瞰ビュー イメージには任意の次元を設定できますが、preprocessData
補助関数により、ネットワーク入力サイズに合わせてサイズが変更されます。この例では、ネットワーク入力サイズは 608×608 です。
bevHeight = 608; bevWidth = 608;
グリッドの分解能を求めます。
gridW = (yMax - yMin)/bevWidth; gridH = (xMax - xMin)/bevHeight;
グリッド パラメーターを定義します。
gridParams = {{xMin,xMax,yMin,yMax,zMin,zMax},{bevWidth,bevHeight},{gridW,gridH}};
この例にサポート ファイルとして添付されている transformPCtoBEV
補助関数を使用し、学習データを鳥瞰ビュー イメージに変換します。学習データが outputFolder
に既に存在する場合は、writeFiles
を false
に設定できます。
writeFiles = true; if writeFiles transformPCtoBEV(pcds,boxLabels,gridParams,outputFolder); end
学習用データストア オブジェクトの作成
imageDatastore
を使用して鳥瞰ビュー イメージを読み込みます。
dataPath = fullfile(outputFolder,'BEVImages');
imds = imageDatastore(dataPath);
boxLabelDatastore
を使用してグラウンド トゥルース ボックスを読み込みます。
labelPath = fullfile(outputFolder,'Cuboids','BEVGroundTruthLabels.mat'); load(labelPath,'processedLabels'); blds = boxLabelDatastore(processedLabels);
ラベルのないデータを学習データから削除します。
[imds,blds,pcds] = removeEmptyData(imds,blds,pcds);
データ セットを学習セット、検証セット、テスト セットに分割します。データの 60% を学習用に、10% を検証用に、残りを学習済みの検出器のテスト用に選択します。
rng(0); shuffledIndices = randperm(size(imds.Files,1)); idx = floor(0.6 * length(shuffledIndices)); trainingIdx = 1:idx; validationIdx = idx+1 : (idx+1+floor(0.1*length(shuffledIndices))); testIdx = validationIdx(end)+1 : length(shuffledIndices);
imageDatastore
と boxLabelDatastore を使用し、学習中および評価中にイメージとラベル データを読み込むためのデータストアを作成します。
imdsTrain = subset(imds,shuffledIndices(trainingIdx)); bldsTrain = subset(blds,shuffledIndices(trainingIdx)); imdsValidation = subset(imds,shuffledIndices(validationIdx)); bldsValidation = subset(blds,shuffledIndices(validationIdx)); imdsTest = subset(imds,shuffledIndices(testIdx)); bldsTest = subset(blds,shuffledIndices(testIdx));
イメージ データストアとボックス ラベル データストアを組み合わせます。
trainData = combine(imdsTrain,bldsTrain); validationData = combine(imdsValidation,bldsValidation); testData = combine(imdsTest,bldsTest);
この例にサポート ファイルとして添付されている validateInputDataComplexYOLOv4
補助関数を使用し、次のものを検出します。
無効なイメージ形式のサンプル、または NaN を含むサンプル
ゼロ、NaN、Inf を含む境界ボックス、または空の境界ボックス
欠損ラベルまたは非カテゴリカル ラベル
境界ボックスの値は有限の正の値でなければならず、NaN にすることはできません。また、正の高さと幅をもつイメージ境界内に収まらなくてはなりません。
validateInputDataComplexYOLOv4(trainData); validateInputDataComplexYOLOv4(validationData); validateInputDataComplexYOLOv4(testData);
学習データの前処理
学習データを前処理して学習用に準備します。この例の最後にリストされている preprocessData
補助関数によ、入力データに以下の演算が適用されます。
イメージのサイズをネットワーク入力サイズに変更する。
イメージのピクセルを [0 1] の範囲にスケーリングする。
networkInputSize = [608 608 3]; preprocessedTrainingData = transform(trainData,@(data)preprocessData(data,networkInputSize));
前処理された学習データを読み取ります。
data = read(preprocessedTrainingData);
境界ボックスと共にイメージを表示します。
I = data{1,1}; bbox = data{1,2}; labels = data{1,3}; helperDisplayBoxes(I,bbox,labels);
データストアをリセットします。
reset(preprocessedTrainingData);
YOLO v4 オブジェクト検出ネットワークの作成
検出するオブジェクト クラスの名前を指定します。
classNames = {'Car' 'Truck' 'Pedestrain'};
アンカーの数を指定します。
complex-yolov4-pandaset
model
— 9 つのアンカーを指定tiny-complex-yolov4-pandaset
model
— 6 つのアンカーを指定
正確に再現できるように、乱数シードを設定します。estimateAnchorBoxes 関数を使用して、学習データ内のオブジェクトのサイズに基づいてアンカー ボックスを推定します。アンカー ボックスの詳細については、YOLO v4 入門の「アンカー ボックスの指定」セクションを参照してください。
rng(0) numAnchors = 6; [anchors,meanIoU] = estimateAnchorBoxes(trainData,numAnchors)
anchors = 6×2
22 52
10 12
18 7
11 16
24 60
9 9
meanIoU = 0.7789
すべての検出ヘッドで使用する anchorBoxes を指定します。anchorBoxes は、M 行 1 列の cell 配列です。ここで、M は検出ヘッドの数を表します。各検出ヘッドは、アンカーから成る N 行 2 列の行列で構成されます。ここで、N は使用するアンカーの数です。特徴マップのサイズに基づいて、各検出ヘッドの anchorBoxes を選択します。スケールが小さい場合は大きいアンカーを使用し、スケールが大きい場合は小さいアンカーを使用します。これを行うには、より大きいアンカー ボックスが先頭に来るようにアンカーを並べ替えてから、最初の 3 つを最初の検出ヘッドに割り当て、次の 3 つを 2 番目の検出ヘッドに割り当て、最後の 3 つを 3 番目の検出ヘッドに割り当てます。
area = anchors(:, 1).*anchors(:,2);
[~,idx] = sort(area,"descend");
anchors = anchors(idx,:);
anchorBoxes = {anchors(1:3,:)
anchors(4:6,:)
};
yolov4ObjectDetector
関数を使用して YOLO v4 オブジェクト検出器を作成します。COCO データセットで学習させた事前学習済みの YOLO v4 検出ネットワークの名前を指定します。クラス名および推定されるアンカー ボックスを指定します。
modelName = "tiny-yolov4-coco";
detector = yolov4ObjectDetector(modelName,classNames,anchorBoxes,InputSize=networkInputSize);
学習オプションの指定
trainingOptions
を使用してネットワーク学習オプションを指定します。Adam ソルバーを使用して、一定の学習率 0.001 でオブジェクト検出器に 90 エポック学習させます。"ResetInputNormalization
" を false に設定し、"BatchNormalizationStatistics
" を "moving
" に設定する必要があります。"ValidationData
" を検証データに設定し、"ValidationFrequency
" を 1000 に設定します。"ValidationFrequency
" を減らすとデータをより頻繁に検証できますが、学習時間が長くなります。"ExecutionEnvironment
" を使用して、ネットワークの学習に使用するハードウェア リソースを決定します。この既定値は "auto" で、利用可能な場合は GPU が選択され、そうでない場合は CPU が選択されます。"CheckpointPath
" を一時的な場所に設定します。これにより、学習プロセス中に部分的に学習させた検出器を保存できます。停電やシステム障害などで学習が中断された場合に、保存したチェックポイントから学習を再開できます。
options = trainingOptions("adam",... GradientDecayFactor=0.9,... SquaredGradientDecayFactor=0.999,... InitialLearnRate=0.001,... LearnRateSchedule="none",... MiniBatchSize=4,... L2Regularization=0.0005,... MaxEpochs=50,... BatchNormalizationStatistics="moving",... DispatchInBackground=true,... ResetInputNormalization=false,... Shuffle="every-epoch",... VerboseFrequency=100,... ValidationFrequency=1000,... CheckpointPath=tempdir,... ValidationData=validationData);
YOLO v4 オブジェクト検出器の学習
関数 trainYOLOv4ObjectDetector
を使用して YOLO v4 オブジェクト検出器に学習させます。この例は、24 GB のメモリを搭載した NVIDIA™ Titan RTX GPU で実行されます。この設定を使用してこのネットワークに学習させるのに約 6 時間かかりました。学習時間は使用するハードウェアによって異なります。ネットワークに学習させる代わりに、事前学習済みの YOLO v4 オブジェクト検出器を使用することもできます。
downloadPretrainedYOLOv4Detector 補助関数を使用して、事前学習済みの検出器をダウンロードします。doTraining の値を false に設定します。拡張した学習データで検出器に学習させるには、doTraining の値を true に設定します。
doTraining = false; if doTraining [detector,info] = trainYOLOv4ObjectDetector(trainData,detector,options); else % Load pretrained detector for the example. detector = downloadPretrainedComplexYOLOv4(modelName); end
モデルの評価
Computer Vision Toolbox™ には、回転した四角形の平均適合率などの一般的なメトリクスを測定するためのオブジェクト検出器評価関数 (evaluateObjectDetection
) が用意されています。この例では、平均方向類似度 (AOS) メトリクスを使用します。AOS は、回転した四角形の検出における検出器のパフォーマンスを測定するためのメトリクスです。このメトリクスは、検出器が正しい分類を実行できること (適合率) と検出器がすべての関連オブジェクトを検出できること (再現率) を示す単一の数値です。
% Reset the datastore. reset(testData) % Run the detector on images in the test set and collect the results. results = detect(detector,testData,'ExecutionEnvironment','cpu'); % Evaluate the object detector using the average precision metric. metrics = evaluateObjectDetection(results,testData,'AdditionalMetrics','AOS'); metrics.ClassMetrics
ans=3×8 table
NumObjects mAP AP Precision Recall ⋯
学習済み Complex-YOLO v4 を使用したオブジェクトの検出
ネットワークを使用してオブジェクトを検出します。
% Read the datastore. reset(testData) % Read the BEV image from the test data. data = read(testData); I = data{1,1}; % Run the detector. [bboxes,scores,labels] = detect(detector,I); % Display the output. figure helperDisplayBoxes(I,bboxes,labels);
この例にサポート ファイルとして添付されている transferbboxToPointCloud
補助関数を使用して、検出されたボックスを点群に転送します。
lidarTestData = subset(pcds,shuffledIndices(testIdx)); ptCld = read(lidarTestData); [ptCldOut,bboxCuboid] = transferbboxToPointCloud(bboxes,gridParams,ptCld); helperDisplayBoxes(ptCldOut,bboxCuboid,labels);
サポート関数
データの前処理
function data = preprocessData(data,targetSize) % Resize the images and scale the pixels to between 0 and 1. Also scale the % corresponding bounding boxes. for ii = 1:size(data,1) I = data{ii,1}; imgSize = size(I); % Convert an input image with a single channel to three channels. if numel(imgSize) < 3 I = repmat(I,1,1,3); end bboxes = data{ii,2}; I = im2single(imresize(I,targetSize(1:2))); scale = targetSize(1:2)./imgSize(1:2); bboxes = bboxresize(bboxes,scale); data(ii, 1:2) = {I,bboxes}; end end
ユーティリティ関数
function helperDisplayBoxes(obj,bboxes,labels) % Display the boxes over the image and point cloud. figure if ~isa(obj,'pointCloud') imshow(obj) shape = 'rectangle'; else pcshow(obj.Location); shape = 'cuboid'; end showShape(shape,bboxes(labels=='Car',:),... 'Color','green','LineWidth',0.5);hold on; showShape(shape,bboxes(labels=='Truck',:),... 'Color','magenta','LineWidth',0.5); showShape(shape,bboxes(labels=='Pedestrain',:),... 'Color','yellow','LineWidth',0.5); hold off; end function helperDownloadPandasetData(outputFolder,lidarURL) % Download the data set from the given URL to the output folder. lidarDataTarFile = fullfile(outputFolder,'Pandaset_LidarData.tar.gz'); if ~exist(lidarDataTarFile,'file') mkdir(outputFolder); disp('Downloading PandaSet Lidar driving data (5.2 GB)...'); websave(lidarDataTarFile,lidarURL); untar(lidarDataTarFile,outputFolder); end % Extract the file. if (~exist(fullfile(outputFolder,'Lidar'),'dir'))... &&(~exist(fullfile(outputFolder,'Cuboids'),'dir')) untar(lidarDataTarFile,outputFolder); end end
参考文献
[1] Simon, Martin, Stefan Milz, Karl Amende, and Horst-Michael Gross. "Complex-YOLO: Real-Time 3D Object Detection on Point Clouds". ArXiv:1803.06199 [Cs], 24 September 2018. https://arxiv.org/abs/1803.06199.
[2] Bochkovskiy, Alexey, Chien-Yao Wang, and Hong-Yuan Mark Liao. "YOLOv4: Optimal Speed and Accuracy of Object Detection". ArXiv:2004.10934 [Cs, Eess], 22 April 2020. https://arxiv.org/abs/2004.10934.
[3] PandaSet は、Hesai と Scale によって CC-BY-4.0 ライセンスの下で提供されています。
参考
yolov4ObjectDetector
| trainYOLOv4ObjectDetector