Main Content

深層学習を使用したハイパースペクトル イメージの分類

この例では、分類用のカスタム スペクトル畳み込みニューラル ネットワーク (CSCNN) を使用してハイパースペクトル イメージを分類する方法を説明します。

この例では、Image Processing Toolbox™ Hyperspectral Imaging Library が必要となります。Image Processing Toolbox Hyperspectral Imaging Library はアドオン エクスプローラーからインストールできます。アドオンのインストールの詳細については、アドオンの取得と管理を参照してください。Image Processing Toolbox Hyperspectral Imaging Library は MATLAB® Online™ および MATLAB® Mobile™ ではサポートされないため、デスクトップの MATLAB® が必要となります。

ハイパースペクトル イメージングでは、可視スペクトルを含む紫外線から遠赤外線までの範囲のさまざまな波長でオブジェクトの空間特徴およびスペクトル特徴を測定します。可視スペクトルの赤、緑、青の部分を感知する 3 種類のセンサーのみを使用するカラー イメージングと異なり、ハイパースペクトル イメージは多数のチャネルを含むことができます。このため、ハイパースペクトル イメージでは、RGB イメージでは同一に見えるオブジェクトの違いを有効にすることができます。

この例では、材質ごとに異なるスペクトル シグネチャに基づいて 16 種類の植生と地形を分類する学習を行う CSCNN を使用します。この例では、CSCNN を学習させる方法を説明しますが、分類の実行に使用できる事前学習済みのネットワークも提供します。

CSCNN_diagram_image.PNG

ハイパースペクトル データセットの読み込み

この例では、Image Processing Toolbox™ Hyperspectral Imaging Library に含まれているインディアン パイン データセットを使用します。このデータセットは、サイズ 145×145 ピクセル、カラー チャネル数 220 のハイパースペクトル イメージ 1 つで構成されます。また、このデータセットには、16 個のクラス (アルファルファ、トウモロコシ、牧草、ススキノキ、石造鉄造高層建築など) を持つグラウンド トゥルース ラベル イメージも含まれます。

関数hypercubeを使用してハイパースペクトル イメージを読み取ります。

hcube = hypercube("indian_pines.dat");

関数colorizeを使用してイメージのフォールス カラー バージョンを可視化します。

rgbImg = colorize(hcube,method="rgb");
imshow(rgbImg)

Figure contains an axes object. The axes object contains an object of type image.

グラウンド トゥルース ラベルを読み込み、クラスの数を指定します。

gtLabel = load("indian_pines_gt.mat");
gtLabel = gtLabel.indian_pines_gt;
numClasses = 16;

学習データの前処理

関数hyperpcaを使用してスペクトル バンドの数を 30 まで減らします。この関数は、主成分分析 (PCA) を実行し、最もユニークなシグネチャを持つスペクトル バンドを選択します。

dimReduction = 30;
imageData = hyperpca(hcube,dimReduction);

イメージ データを正規化します。

sd = std(imageData,[],3);
imageData = imageData./sd;

補助関数 createImagePatchesFromHypercube を使用してハイパースペクトル イメージを、サイズ 25×25 ピクセル、チャネル数 30 のパッチに分割します。この関数は、この例にサポート ファイルとして添付されています。また、この関数は、パッチごとにラベルを 1 つ返します。これは、中心ピクセルのラベルです。

windowSize = 25;
inputSize = [windowSize windowSize dimReduction];
[allPatches,allLabels] = createImagePatchesFromHypercube(imageData,gtLabel,windowSize);

indianPineDataTransposed = permute(allPatches,[2 3 4 1]);
dsAllPatches = augmentedImageDatastore(inputSize,indianPineDataTransposed,allLabels);

このデータセット内のすべてのキューブがラベルをもっているわけではありません。しかし、ネットワークの学習には、ラベル付けされたデータが必要です。学習用にはラベル付けされたキューブのみを選択します。ラベル付けされて使用可能なパッチがいくつあるかを数えます。

patchesLabeled = allPatches(allLabels>0,:,:,:);
patchLabels = allLabels(allLabels>0);
numCubes = size(patchesLabeled,1);

数値ラベルを categorical に変換します。

patchLabels = categorical(patchLabels);

パッチをランダムに学習用とテスト用のデータセットに分割します。

[trainingIdx,valIdx,testIdx] = dividerand(numCubes,0.3,0,0.7);
dataInputTrain = patchesLabeled(trainingIdx,:,:,:);
dataLabelTrain = patchLabels(trainingIdx,1);
dataInputTest = patchesLabeled(testIdx,:,:,:);
dataLabelTest = patchLabels(testIdx,1);

入力データを転置します。

dataInputTransposeTrain = permute(dataInputTrain,[2 3 4 1]); 
dataInputTransposeTest = permute(dataInputTest,[2 3 4 1]);

学習データとテスト データのバッチを読み取るデータストアを作成します。

dsTrain = augmentedImageDatastore(inputSize,dataInputTransposeTrain,dataLabelTrain);
dsTest = augmentedImageDatastore(inputSize,dataInputTransposeTest,dataLabelTest);

CSCNN 分類ネットワークの作成

CSCNN アーキテクチャを定義します。

layers = [
    image3dInputLayer(inputSize,Name="Input",Normalization="None")
    convolution3dLayer([3 3 7],8,Name="conv3d_1")
    reluLayer(Name="Relu_1")
    convolution3dLayer([3 3 5],16,Name="conv3d_2")
    reluLayer(Name="Relu_2")
    convolution3dLayer([3 3 3],32,Name="conv3d_3")
    reluLayer(Name="Relu_3")
    convolution3dLayer([3 3 1],8,Name="conv3d_4")
    reluLayer(Name="Relu_4")
    fullyConnectedLayer(256,Name="fc1")
    reluLayer(Name="Relu_5")
    dropoutLayer(0.4,Name="drop_1")
    fullyConnectedLayer(128,Name="fc2")
    dropoutLayer(0.4,Name="drop_2")
    fullyConnectedLayer(numClasses,Name="fc3")
    softmaxLayer(Name="softmax")];
net = dlnetwork(layers);

ディープ ネットワーク デザイナーを使用してネットワークを可視化します。

deepNetworkDesigner(net)

学習オプションの指定

必要なネットワーク パラメーターを指定します。この例では、初期学習率を 0.001、バッチ サイズを 256 とし、Adam 最適化を使用してネットワークに 100 エポック学習させます。

numEpochs = 100;
miniBatchSize = 256;
initLearningRate = 0.001;
momentum = 0.9;
learningRateFactor = 0.01;

options = trainingOptions("adam", ...
    InitialLearnRate=initLearningRate, ...
    LearnRateSchedule="piecewise", ...
    LearnRateDropPeriod=30, ...
    LearnRateDropFactor=learningRateFactor, ...
    MaxEpochs=numEpochs, ...
    MiniBatchSize=miniBatchSize, ...
    GradientThresholdMethod="l2norm", ...
    GradientThreshold=0.01, ...
    VerboseFrequency=100, ...
    ValidationData=dsTest, ...
    ValidationFrequency=100);

ネットワークの学習

この例では既定で、インディアン パイン データセット用の事前学習済み分類器がダウンロードされます。この事前学習済みのネットワークを使用することで、学習の完了を待たずに インディアン パイン データセットを分類できます。

ネットワークに学習させるには、次のコードで変数 doTrainingtrue に設定します。関数trainnet (Deep Learning Toolbox)を使用してニューラル ネットワークに学習させます。分類には、クロスエントロピー損失を使用します。既定では、関数 trainnet は利用可能な GPU がある場合にそれを使用します。GPU での学習には、Parallel Computing Toolbox™ ライセンスとサポートされている GPU デバイスが必要です。サポートされているデバイスについては、GPU 計算の要件 (Parallel Computing Toolbox)を参照してください。そうでない場合、関数 trainnet は CPU を使用します。実行環境を指定するには、ExecutionEnvironment 学習オプションを使用します。

doTraining = false;
if doTraining
    net = trainnet(dsTrain,net,"crossentropy",options);
    modelDateTime = string(datetime("now",Format="yyyy-MM-dd-HH-mm-ss"));
    save("trainedIndianPinesCSCNN-"+modelDateTime+".mat","net");
else
    dataDir = pwd;
    trainedNetwork_url = "https://ssd.mathworks.com/supportfiles/" + ...
        "image/data/trainedIndianPinesCSCNN_v2.mat";
    downloadTrainedNetwork(trainedNetwork_url,pwd);
    load(fullfile(dataDir,"trainedIndianPinesCSCNN_v2.mat"));
end
Downloading pretrained network.
This can take several minutes to download...
Done.

学習済み CSCNN を使用したハイパースペクトル イメージの分類

テスト データセットに対する分類の精度を計算します。ここでの精度は、すべてのクラスにおいて正しいピクセル分類が行われる割合です。

scores = minibatchpredict(net,dsTest);
predictionTest = scores2label(scores,categories(dataLabelTest));

accuracy = sum(predictionTest == dataLabelTest)/numel(dataLabelTest);
disp("Accuracy of the test data = "+accuracy)
Accuracy of the test data = 0.99805

ラベル付けされた学習用パッチ内のピクセル、ラベル付けされたテスト用パッチ内のピクセル、およびラベル付けされていないピクセルを含む、すべてのイメージ ピクセルを分類することによって、完全なイメージを再構成します。

predScores = minibatchpredict(net,dsAllPatches);
prediction = scores2label(predScores,categories(dataLabelTest));
prediction = double(prediction);

ネットワークの学習はラベル付けされたパッチのみで行われます。このため、ラベル付けされていないピクセルの予測された分類は意味をもちません。ラベル付けされていないパッチを検索し、そのラベルを 0 に設定します。

patchesUnlabeled = find(allLabels==0);
prediction(patchesUnlabeled) = 0;

分類されたピクセルを、グラウンド トゥルース イメージの次元に合うように形状変更します。

[m,n,d] = size(imageData);
indianPinesPrediction = reshape(prediction,[n m]);
indianPinesPrediction = indianPinesPrediction';

グラウンド トゥルースと、予測された分類を表示します。

cmap = parula(numClasses);

figure
tiledlayout(1,2,TileSpacing="Tight")
nexttile
imshow(gtLabel,cmap)
title("Ground Truth Classification")

nexttile
imshow(indianPinesPrediction,cmap)
colorbar
title("Predicted Classification")

Figure contains 2 axes objects. Axes object 1 with title Ground Truth Classification contains an object of type image. Axes object 2 with title Predicted Classification contains an object of type image.

誤分類されたピクセルを強調するため、グラウンド トゥルースと予測ラベルの合成イメージを表示します。灰色のピクセルは同一のラベルを、色付きのピクセルは異なるラベルを示します。

figure
imshowpair(gtLabel,indianPinesPrediction)

Figure contains an axes object. The axes object contains an object of type image.

参考

| | | (Deep Learning Toolbox) | | (Deep Learning Toolbox) | (Deep Learning Toolbox) | (Deep Learning Toolbox)

関連するトピック