Main Content

SOLOv2 を使用したインスタンス セグメンテーションの実行

この例では、深層学習 SOLOv2 ネットワークを使用して、ビン内のランダムに回転する機械部品のオブジェクト インスタンスをセグメント化する方法を示します。

インスタンス セグメンテーションは、オブジェクトを検出して位置を推定すると同時に、検出された各インスタンスのセグメンテーション マップを生成するコンピューター ビジョン技術です。SOLOv2 を使用したインスタンス セグメンテーションの詳細については、Get Started with SOLOv2 for Instance Segmentationを参照してください。

この例では、最初に、単一のクラスを検出できる事前学習済みの SOLOv2 ネットワークを使用してインスタンスのセグメンテーションを実行する方法を示します。次に、オプションで転移学習を使用して SOLOv2 ネットワークの構成および学習を行い、予測結果を評価できます。

事前学習済み SOLOv2 ネットワークのダウンロード

既定では、この例では、補助関数 downloadTrainedNetwork を使用して、SOLOv2 インスタンス セグメンテーション ネットワークの事前学習済みバージョンをダウンロードします。補助関数は、この例にサポート ファイルとして添付されています。事前学習済みのネットワークを使用することで、学習の完了を待たずに例全体を実行できます。

trainedSOLOv2_url = "https://ssd.mathworks.com/supportfiles/vision/data/trainedSOLOv2BinDataset.zip";
downloadTrainedNetwork(trainedSOLOv2_url,pwd);
Downloading pretrained network.
This can take several minutes to download...
Done.
load("trainedSOLOv2.mat");

ビン ピッキング データセットのダウンロード

この例では、ビン ピッキング データ セットを使用します。データ セットには、Simulink® ソフトウェアで生成された 3 次元パイプ コネクタの 150 個のイメージが格納されています。データは、さまざまな視角やさまざまなライティング条件での、ビン内にランダムな向きで置かれた機械部品のイメージで構成されています。データ セットには、すべてのイメージ内のすべてのオブジェクトについてインスタンス マスク情報が含まれており、すべての種類の機械部品が 1 つのクラスに結合されています。

データ セットの場所として dataDir を指定します。補助関数 downloadBinObjectData を使用してデータ セットをダウンロードします。この関数は、この例にサポート ファイルとして添付されています。

dataDir = fullfile(tempdir,"BinDataset");
dataset_url = "https://ssd.mathworks.com/supportfiles/vision/data/binDataset.zip";
downloadBinObjectData(dataset_url,dataDir);
Downloading Bin Object Dataset.
This can take several minutes to download...
Done.

インスタンス セグメンテーションの実行

データ セットからサンプル イメージを読み取ります。

sampleImage = imread("testBinDataImage.png");

関数segmentObjectsを使用して、各オブジェクト インスタンスのマスク、ラベル、および信頼度スコアを予測します。

[masks,labels,scores] = segmentObjects(net,sampleImage,Threshold=0.4);

関数insertObjectMaskを使用して、イメージの上にインスタンス マスクを重ねて表示します。関数linesを使用してカラーマップを指定し、各オブジェクト インスタンスが異なる色で表示されるようにします。補助関数 getBoxFromMask を使用して、セグメント化された各オブジェクト インスタンスに対応する境界ボックスを生成し、確率スコアをラベルとしてイメージ上に重ね合わせます。

maskColors = lines(numel(labels));
overlayedMasks = insertObjectMask(sampleImage,masks,MaskColor=maskColors);
imshow(overlayedMasks)
boxes = getBoxFromMask(masks);
showShape("rectangle",boxes,Label="Scores: "+num2str(scores),LabelOpacity=0.4);

学習用データの準備

MAT ファイルから注釈データを読み取るファイル データストアを作成します。この例にサポート ファイルとして添付されている関数 matReaderBinData を使用し、MAT ファイルを解析して、対応する学習データを、イメージ データ、境界ボックス、オブジェクト マスク、およびラベルを格納する 1 行 4 列の cell 配列として返します。

annsDir = fullfile(dataDir,"synthetic_parts_dataset","annotations");
ds = fileDatastore(annsDir,FileExtensions=".mat",ReadFcn=@(x)matReaderBinData(x,dataDir));

データの分割

この例の再現性を向上させるには、グローバルな乱数の状態を既定の状態に設定します。

rng("default");

データを学習セット、検証セット、テスト セットに分割します。イメージの総数が比較的少ないため、データの比較的大部分 (70%) を学習に割り当てます。検証用に 15% を割り当て、残りをテスト用に割り当てます。

numImages = length(ds.Files);
numTrain = floor(0.7*numImages);
numVal = floor(0.15*numImages);

shuffledIndices = randperm(numImages);
trainDS = subset(ds,shuffledIndices(1:numTrain));
valDS   = subset(ds,shuffledIndices(numTrain+1:numTrain+numVal));
testDS  = subset(ds,shuffledIndices(numTrain+numVal+1:end));

学習データの可視化

ファイル データストアの学習サブセットからサンプル イメージを読み取って、学習用のグラウンド トゥルース データをプレビューします。

gsSample = preview(trainDS);
gsImg = gsSample{1};
boxes = gsSample{2};
labels = gsSample{3};
masks  = gsSample{4};

関数 insertObjectMasks を使用してインスタンス マスクおよび対応する境界ボックスとラベルをサンプル イメージに重ね合わせることにより、グラウンド トゥルース データを可視化します。

overlayedMasks = insertObjectMask(gsImg,masks,Opacity=0.5);
imshow(overlayedMasks)
showShape("rectangle",boxes,Label=string(labels),Color="green");

SOLOv2 ネットワーク アーキテクチャの定義

solov2オブジェクトを使用して、SOLOv2 インスタンス セグメンテーション モデルを作成します。COCO データ セットで学習させた事前学習済み SOLOv2 インスタンス セグメンテーション ネットワークの名前を指定します。クラス名、推定アンカー ボックス、およびネットワーク入力サイズを指定します。オプションの名前と値の引数 InputSize を使用して入力サイズを指定し、すべてのイメージのサイズが変更されるようにします。

networkToTrain = solov2("resnet50-coco","Object",InputSize=[736 1280 3]);

学習オプションの指定

関数trainingOptions (Deep Learning Toolbox)を使用してネットワーク学習オプションを指定します。SGDM ソルバーを使用して、インスタンス セグメンテーション ネットワークに 5 エポック学習させます。エポックごとの学習率低下係数を 0.99 に指定します。最初の反復で確実に勾配が収束するようにするには、名前と値の引数 GradientThreshold35 に設定します。名前と値の引数 ValidationData を検証データ valDS として指定します。

options = trainingOptions("sgdm", ...
    InitialLearnRate=0.0005, ...
    LearnRateSchedule="piecewise", ...
    LearnRateDropPeriod=1, ...
    LearnRateDropFactor=0.99, ...
    Momentum=0.9, ...
    MaxEpochs=5, ...
    MiniBatchSize=4, ...
    ExecutionEnvironment="auto", ...
    VerboseFrequency=5, ...
    Plots="training-progress", ...
    ResetInputNormalization=false, ...
    ValidationData=valDS, ...
    ValidationFrequency=25, ...
    GradientThreshold=35, ...
    OutputNetwork="best-validation-loss");

SOLOv2 ネットワークの学習

ネットワークに学習させるには、変数 doTrainingtrue に設定します。関数trainSOLOV2を使用してネットワークに学習させます。事前学習済みのバックボーン ネットワークから抽出された特徴を再利用してデータ セットの検出ヘッドを最適化するには、名前と値の引数 FreezeSubNetwork を指定して、特徴抽出サブネットワークを凍結します。

可能であれば、1 つ以上の GPU で学習を行います。GPU を使用するには、Parallel Computing Toolbox™ ライセンスと CUDA® 対応の NVIDIA® GPU が必要です。詳細については、GPU 計算の要件 (Parallel Computing Toolbox)を参照してください。学習には 24 GB のメモリを搭載した NVIDIA Titan RTX™ で約 15 分を要します。

doTraining = false;
if doTraining       
    net = trainSOLOV2(trainDS,networkToTrain,options,FreezeSubNetwork="backbone");
    modelDateTime = string(datetime("now",Format="yyyy-MM-dd-HH-mm-ss"));
    save(fullfile(tempdir,"trainedSOLOv2"+modelDateTime+".mat"), ...
        "net");
else
    load("trainedSOLOv2.mat");
end

学習済みの SOLOv2 ネットワークの評価

平均適合率を測定して、学習済みの SOLOv2 ネットワークを評価します。適合率は、ネットワークがオブジェクトを正しく分類する能力を定量化したものです。

すべてのテスト イメージのインスタンスのマスクを検出します。

resultsDS = segmentObjects(net,testDS,Threshold=0.1);
Running SoloV2 network
--------------------------
* Processed 23 images.

関数evaluateInstanceSegmentationを使用して、平均適合率 (AP) メトリクスおよび平均適合率の平均 (mAP) メトリクスを計算します。この例では、オブジェクトが 1 つのクラスにのみ存在するため、AP と mAP は同じになります。

metrics = evaluateInstanceSegmentation(resultsDS,testDS,0.5);
display(metrics.DatasetMetrics)
  1×3 table

    NumObjects      mAP          AP    
    __________    _______    __________

       184        0.98784    {[0.9878]}

すべてのテスト イメージのメトリクスを表示して、期待どおりに実行されていないイメージを特定します。

display(metrics.ImageMetrics)
  23×3 table

          NumObjects      mAP          AP    
          __________    _______    __________

    1         8               1    {[     1]}
    2         8               1    {[     1]}
    3         8               1    {[     1]}
    4         8               1    {[     1]}
    5         8               1    {[     1]}
    6         8               1    {[     1]}
    7         8               1    {[     1]}
    8         8               1    {[     1]}
    9         8               1    {[     1]}
    10        8               1    {[     1]}
    11        8               1    {[     1]}
    12        8               1    {[     1]}
    13        8               1    {[     1]}
    14        8               1    {[     1]}
    15        8               1    {[     1]}
    16        8         0.85938    {[0.8594]}
    17        8         0.85938    {[0.8594]}
    18        8               1    {[     1]}
    19        8               1    {[     1]}
    20        8               1    {[     1]}
    21        8               1    {[     1]}
    22        8               1    {[     1]}
    23        8               1    {[     1]}

適合率/再現率 (PR) 曲線は、さまざまなレベルの再現率におけるインスタンス セグメンテーション モデルの適合率を示しています。すべてのレベルの再現率で適合率が 1 になるのが理想的です。関数 evaluateInstanceSegmentation の出力から、適合率、再現率、平均適合率のメトリクスを抽出します。

precision = metrics.ClassMetrics.Precision;
recall = metrics.ClassMetrics.Recall;
averagePrecision = metrics.ClassMetrics.AP;

テスト データの PR 曲線をプロットします。

figure
plot(recall{1},precision{1})
title(sprintf("Average Precision for Single Class Instance Segmentation: " + "%.2f",averagePrecision{1}))
xlabel("Recall")
ylabel("Precision")
grid on

サポート関数

関数 getBoxFromMask は、インスタンス マスクを境界ボックスに変換します。

function boxes = getBoxFromMask(masks)

for idx  = 1:size(masks,3)
    mask = masks(:,:,idx);
    [ptsR, ptsC] = find(mask);

    minR = min(ptsR);
    maxR = max(ptsR);
    minC = min(ptsC);
    maxC = max(ptsC);
    
    boxes(idx,:) = [minC minR maxC-minC maxR-minR];

end
end

参考

| | | |

関連するトピック