Main Content

このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。

U-net を使用するセマンティック セグメンテーション ネットワークのコード生成

この例では、深層学習を使用するイメージ セグメンテーション用途のコード生成を説明します。codegen コマンドを使用して、イメージ セグメンテーション用の深層学習ネットワーク U-Net の DAG ネットワーク オブジェクトについて予測を実行する MEX 関数を生成します。

U-Net を使用したイメージのセグメンテーションを codegen コマンドなしで行う同様の例については、深層学習を使用したマルチスペクトル イメージのセマンティック セグメンテーション (Image Processing Toolbox)を参照してください。

サードパーティの必要条件

必須

この例では、CUDA MEX を生成します。以下のサードパーティ要件が適用されます。

  • CUDA® 対応 NVIDIA® GPU および互換性のあるドライバー。

オプション

スタティック ライブラリ、ダイナミック ライブラリ、または実行可能ファイルなどの MEX 以外のビルドについて、この例では以下の要件も適用されます。

GPU 環境の検証

関数coder.checkGpuInstall (GPU Coder)を使用して、この例を実行するのに必要なコンパイラおよびライブラリが正しく設定されていることを検証します。

envCfg = coder.gpuEnvConfig('host');
envCfg.DeepLibTarget = 'cudnn';
envCfg.DeepCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

セグメンテーション ネットワーク

U-Net [1] は、セマンティック イメージ セグメンテーション用に設計された、畳み込みニューラル ネットワーク (CNN) の一種です。U-Net では、最初の一連の畳み込み層に最大プーリング層が点在し、入力イメージの解像度を逐次下げていきます。これらの層に、一連の畳み込み層が続き、その中にアップサンプリング演算処理が点在し、入力イメージの解像度を逐次上げていきます。これらの 2 つの一連の経路を組み合わせると U 字形の図が形成されます。このネットワークは、元は生物医学のイメージ セグメンテーション アプリケーションで予測を実行するために学習および使用されていました。この例は、このネットワークで時間の経過に伴う森林被覆の変化を追跡できることを示しています。環境保護機関は、森林伐採を追跡し、地域の環境的生態学的健全性を評価し資格を与えます。

深層学習ベースのセマンティック セグメンテーションにより、高解像度の航空写真から植被を正確に測定できます。課題の 1 つに、視覚的に類似した特性をもつクラスを切り分けること、たとえば緑のピクセルを草、低木または樹木として区別することがあります。分類の精度を高めるために、一部のデータ セットには各ピクセルに関する追加情報を提供するマルチスペクトル イメージが含まれています。たとえば、ハームリン ビーチ州立公園のデータ セットでは、クラスをより明確に分離する近赤外チャネルでカラー イメージが補完されています。

この例では、各ピクセルを正しく分類するために、事前学習済みの U-Net ネットワークと共にハームリン ビーチ州立公園のデータ [2] を使用します。

使用する U-Net は、次の 18 クラスに属するピクセルをセグメント化するように学習されています。

0. Other Class/Image Border      7. Picnic Table         14. Grass
1. Road Markings                 8. Black Wood Panel     15. Sand
2. Tree                          9. White Wood Panel     16. Water (Lake)
3. Building                     10. Orange Landing Pad   17. Water (Pond)
4. Vehicle (Car, Truck, or Bus) 11. Water Buoy           18. Asphalt (Parking Lot/Walkway)
5. Person                       12. Rocks
6. Lifeguard Chair              13. Other Vegetation

エントリポイント関数 segmentImageUnet

エントリポイント関数 segmentImageUnet.m は、multispectralUnet.mat ファイル内にある multispectralUnet ネットワークを使用して、入力イメージに対してパッチ単位のセマンティック セグメンテーションを実行します。この関数は、ネットワーク オブジェクトを multispectralUnet.mat ファイルから永続変数 mynet に読み込み、以降の予測呼び出しではその永続変数を再利用します。

type('segmentImageUnet.m')
function out = segmentImageUnet(im,patchSize,trainedNet)  
%  OUT = segmentImageUnet(IM,patchSize,trainedNet) returns a semantically
%  segmented image, segmented using the multi-spectral Unet specified in
%  trainedNet. The segmentation is performed over each patch of size
%  patchSize.
%
% Copyright 2019-2022 The MathWorks, Inc.

%#codegen
persistent mynet;

if isempty(mynet)
    mynet = coder.loadDeepLearningNetwork(trainedNet);
end

[height, width, nChannel] = size(im);
patch = coder.nullcopy(zeros([patchSize, nChannel-1]));

% Pad image to have dimensions as multiples of patchSize
padSize = zeros(1,2);
padSize(1) = patchSize(1) - mod(height, patchSize(1));
padSize(2) = patchSize(2) - mod(width, patchSize(2));

im_pad = padarray (im, padSize, 0, 'post');
[height_pad, width_pad, ~] = size(im_pad);

out = zeros([size(im_pad,1), size(im_pad,2)], 'uint8');

for i = 1:patchSize(1):height_pad    
    for j =1:patchSize(2):width_pad        
        for p = 1:nChannel-1              
            patch(:,:,p) = squeeze( im_pad( i:i+patchSize(1)-1,...
                                            j:j+patchSize(2)-1,...
                                            p));            
        end
         
        % Pass in input
        segmentedLabels = activations(mynet, patch, 'Segmentation-Layer');
        
        % Takes the max of each channel (6 total at this point)
        [~,L] = max(segmentedLabels,[],3);
        patch_seg = uint8(L);
        
        % Populate section of output
        out(i:i+patchSize(1)-1, j:j+patchSize(2)-1) = patch_seg;
       
    end
end

% Remove the padding
out = out(1:height, 1:width);

事前学習済みの U-Net ネットワークの取得

この例では、事前学習済みの U-Net ネットワークを含む multispectralUnet MAT ファイルを使用します。このファイルのサイズは約 117 MB です。MathWorks の Web サイトからファイルをダウンロードします。

trainedUnetFile = matlab.internal.examples.downloadSupportFile('vision/data','multispectralUnet.mat');

U-Net は、畳み込み層、最大プーリング層、深さ連結層、ピクセル分類出力層など、58 個の層を含む DAG ネットワークです。

load(trainedUnetFile);
disp(net)
  DAGNetwork with properties:

         Layers: [58×1 nnet.cnn.layer.Layer]
    Connections: [61×2 table]
     InputNames: {'ImageInputLayer'}
    OutputNames: {'Segmentation-Layer'}

ネットワーク アーキテクチャを表示するには、関数analyzeNetworkを使用します。

analyzeNetwork(net);

データの準備

この例では、[2] の高解像度のマルチスペクトル データを使用します。このイメージ セットはニューヨーク州のハームリン ビーチ州立公園の上空でドローンを使用して撮影されました。このデータには、18 個のオブジェクト クラス ラベルの付いた、ラベル付き学習セット、検証セットおよびテスト セットが含まれます。データ ファイルのサイズは~ 3.0 GB です。

補助関数 downloadHamlinBeachMSIData を使用して、データ セットの MAT ファイル バージョンをダウンロードします。この関数は、この例にサポート ファイルとして添付されています。

if ~exist(fullfile(pwd,'data'),'dir')
    url = 'https://home.cis.rit.edu/~cnspci/other/data/rit18_data.mat';
    downloadHamlinBeachMSIData(url,pwd+"/data/");
end

データを MATLAB に読み込んで確認します。

load(fullfile(pwd,'data','rit18_data','rit18_data.mat'));

% Examine data
whos test_data
  Name           Size                         Bytes  Class     Attributes

  test_data      7x12446x7654            1333663576  uint16              

イメージには 7 個のチャネルがあります。RGB カラー チャネルは 3 番目、2 番目、および 1 番目のイメージ チャネルです。次の 3 つのチャネルは、近赤外帯域に対応します。熱の痕跡に基づいて、イメージの異なる成分を強調します。チャネル 7 は有効なセグメンテーション領域を示すマスクです。

マルチスペクトル イメージ データは numChannels x width x height 配列に配置されます。MATLAB では、マルチチャネル イメージは width x height x numChannels 配列に配置されます。チャネルが 3 番目の次元になるようにデータを形状変更するには、補助関数 switchChannelsToThirdPlane を使用します。

test_data  = switchChannelsToThirdPlane(test_data);

% Confirm data has the correct structure (channels last).
whos test_data
  Name               Size                     Bytes  Class     Attributes

  test_data      12446x7654x7            1333663576  uint16              

MEX コード生成の実行

エントリポイント関数 segmentImageUnet.m 用の CUDA コードを生成するには、ターゲット言語を C++ に設定して MEX ターゲットの GPU 構成オブジェクトを作成します。関数 coder.DeepLearningConfig (GPU Coder) を使用して CuDNN 深層学習構成オブジェクトを作成し、それを GPU コード構成オブジェクトの DeepLearningConfig プロパティに割り当てます。入力サイズに 12446×7654×7、パッチ サイズに 1024 行 1024 列を指定して codegen コマンドを実行します。これらの値は全体の test_data のサイズに対応します。パッチ サイズが小さいと推論が速くなります。パッチの計算方法を確認するには、segmentImageUnet エントリポイント関数を確認します。

cfg = coder.gpuConfig('mex');
cfg.ConstantInputs = 'Remove';
cfg.TargetLang = 'C++';
cfg.DeepLearningConfig = coder.DeepLearningConfig('cudnn');
inputArgs = {ones(size(test_data),'uint16'),...
    coder.Constant([1024 1024]),coder.Constant(trainedUnetFile)};

codegen -config cfg segmentImageUnet -args inputArgs -report
Code generation successful: View report

test_data の結果を予測するために生成された MEX の実行

この関数 segmentImageUnet は、テストするデータ (test_data) と、使用するパッチ サイズの次元を含むベクトルを受け取ります。イメージのパッチを受け取り、特定のパッチ内のピクセルを予測してから、すべてのパッチを組み合わせます。テスト データのサイズ (12446×7654×7) を考慮すると、このような大きなイメージはパッチで処理する方が簡単です。

segmentedImage = segmentImageUnet_mex(test_data);

セグメンテーションの有効な部分だけを抽出するには、セグメント化されたイメージにテスト データのマスク チャネルを乗算します。

segmentedImage = uint8(test_data(:,:,7)~=0) .* segmentedImage;

セマンティック セグメンテーションの出力はノイズを含むため、関数 medfilt2 を使用してノイズと散在ピクセルを取り除きます。

segmentedImage = medfilt2(segmentedImage,[5,5]);

U-Net でセグメント化された test_data の表示

次のコード行は、クラス名のベクトルを作成します。

classNames = [ "RoadMarkings","Tree","Building","Vehicle","Person", ...
               "LifeguardChair","PicnicTable","BlackWoodPanel",...
               "WhiteWoodPanel","OrangeLandingPad","Buoy","Rocks",...
               "LowLevelVegetation","Grass_Lawn","Sand_Beach",...
               "Water_Lake","Water_Pond","Asphalt"];

セグメント化された RGB テスト イメージにラベルを重ね合わせ、このセグメンテーション イメージにカラー バーを追加します。

cmap = jet(numel(classNames));
B = labeloverlay(imadjust(test_data(:,:,[3,2,1]),[0 0.6],[0.1 0.9],0.55),...
    segmentedImage,'Transparency',0.8,'Colormap',cmap);
figure
imshow(B)

N = numel(classNames);
ticks = 1/(N*2):1/N:1;
colorbar('TickLabels',cellstr(classNames),'Ticks',ticks,'TickLength',0,...
    'TickLabelInterpreter','none');
colormap(cmap)
title('Segmented Image');

参考文献

[1] Ronneberger, Olaf, Philipp Fischer, and Thomas Brox."U-Net: Convolutional Networks for Biomedical Image Segmentation." arXiv preprint arXiv:1505.04597, 2015.

[2] Kemker, R., C. Salvaggio, and C. Kanan. "High-Resolution Multispectral Dataset for Semantic Segmentation." CoRR, abs/1703.01918, 2017.

[3] Kemker, Ronald, Carl Salvaggio, and Christopher Kanan. "Algorithms for Semantic Segmentation of Multispectral Remote Sensing Imagery Using Deep Learning." ISPRS Journal of Photogrammetry and Remote Sensing, Deep Learning RS Data, 145 (November 1, 2018): 60-77. https://doi.org/10.1016/j.isprsjprs.2018.04.014.