Main Content

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

image-to-image 回帰用のデータストアの準備

この例では、ImageDatastore の関数 transform および combine を使用して image-to-image 回帰ネットワークの学習用のデータストアを準備する方法を説明します。

この例では、ノイズ除去ネットワークの学習に適したパイプラインを使用してデータの前処理を行う方法を説明します。その後、前処理したノイズ データを使用して、シンプルな畳み込み自己符号化器ネットワークにイメージ ノイズを削除することを学習させます。

前処理パイプラインを使用したデータの準備

この例では、入力イメージの各ピクセルが 0 または 1 (それぞれ黒および白) に設定されているごま塩ノイズ モデルを使用します。ノイズを含むイメージはネットワーク入力となります。初期状態のイメージは予測されるネットワーク応答となります。ネットワークはごま塩ノイズを検出して削除することを学習します。

数字のデータセット内の初期状態のイメージを imageDatastore として読み込みます。データストアには、0 ~ 9 の数字から成る 10,000 個の合成イメージが格納されています。イメージは、さまざまなフォントを使用して作成された数字のイメージにランダム変換を適用して生成されたものです。数字のイメージはそれぞれ 28 x 28 ピクセルです。データストアには、カテゴリごとに同じ数のイメージが含まれます。

digitDatasetPath = fullfile(matlabroot,"toolbox","nnet", ...
    "nndemos","nndatasets","DigitDataset");
imds = imageDatastore(digitDatasetPath, ...
    IncludeSubfolders=true,LabelSource="foldernames");

大きい読み込みサイズを指定して、ファイル I/O のコストを最小化します。

imds.ReadSize = 500;

学習前に関数 shuffle を使用して数字データをシャッフルします。

imds = shuffle(imds);

関数 splitEachLabel を使用して、imds を学習、検証、およびテスト用の初期状態のイメージが含まれる 3 つのイメージ データストアに分割します。

[imdsTrain,imdsVal,imdsTest] = splitEachLabel(imds,0.95,0.025);

関数 transform を使用して、ネットワーク入力として使用する、各入力イメージのノイズを含むバージョンを作成します。関数 transform は、基になるデータストアからデータを読み取り、補助関数 addNoise (この例の最後に定義) に定義されている演算を使用してデータを処理します。関数 transform の出力は TransformedDatastore です。

dsTrainNoisy = transform(imdsTrain,@addNoise);
dsValNoisy = transform(imdsVal,@addNoise);
dsTestNoisy = transform(imdsTest,@addNoise);

関数 combine を使用して、ノイズを含むイメージと初期状態のイメージを組み合わせて trainNetwork にデータを供給する単一のデータストアにします。このデータストアの組み合わせは、データのバッチを trainNetwork で期待される 2 列の cell 配列に読み取ります。関数 combine の出力は CombinedDatastore です。

dsTrain = combine(dsTrainNoisy,imdsTrain);
dsVal = combine(dsValNoisy,imdsVal);
dsTest = combine(dsTestNoisy,imdsTest);

関数 transform を使用して、入力データストアと応答データストアの両方に共通する追加の前処理演算を実行します。補助関数 commonPreprocessing (この例の最後に定義) は、ネットワークの入力サイズに一致するように入力イメージと応答イメージのサイズを 32 行 32 列ピクセルに変更し、各イメージのデータを [0, 1] の範囲に正規化します。

dsTrain = transform(dsTrain,@commonPreprocessing);
dsVal = transform(dsVal,@commonPreprocessing);
dsTest = transform(dsTest,@commonPreprocessing);

最後に、関数 transform を使用してランダム化された拡張を学習セットに追加します。補助関数 augmentImages (この例の最後に定義) は、ランダムな 90 度の回転をデータに適用します。ネットワーク入力とそれに対応する予測される応答に同一の回転が適用されます。

dsTrain = transform(dsTrain,@augmentImages);

拡張は過適合を抑え、学習済みネットワークに存在する回転のロバスト性を高めます。検証データセットまたはテスト データセットにはランダム化された拡張は不要です。

前処理したデータのプレビュー

学習データの準備に必要な前処理演算はいくつかあるため、学習前に前処理したデータをプレビューして正しいことを確認します。関数 preview を使用してデータをプレビューします。

関数 montage (Image Processing Toolbox) を使用して、ノイズを含むイメージと初期状態のイメージのペアの例を可視化します。学習データは正しいようです。左列の入力イメージにはごま塩ノイズが見られます。ノイズが追加されている点を除き、入力イメージと応答イメージは同じです。入力イメージと応答イメージにはランダムな 90 度の回転が同じ方法で適用されています。

exampleData = preview(dsTrain);
inputs = exampleData(:,1);
responses = exampleData(:,2);
minibatch = cat(2,inputs,responses);
montage(minibatch',Size=[8 2])
title("Inputs (Left) and Responses (Right)")

畳み込み自己符号化器ネットワークの定義

畳み込み自己符号化器は、イメージのノイズ除去を行うための一般的なアーキテクチャです。畳み込み自己符号化器は、符号化器と復号化器という 2 つの段階で構成されます。符号化器は、元の入力イメージを圧縮して潜在表現にします。この潜在表現では、元の入力イメージより幅と高さが小さくなっている一方で、空間位置あたりの特徴マップ数が多いという点で深度が大きくなっています。圧縮された潜在表現は、元のイメージの高周波数の特徴を復元する際に空間分解能がいくらか低下しますが、元のイメージの符号化でノイズ アーティファクトを含めないように学習しています。復号化器は、符号化された信号を繰り返しアップサンプリングして、元の幅、高さ、チャネル数に戻します。符号化器はノイズを除去するため、復号化された最終的なイメージに含まれるノイズ アーティファクトは少なくなります。

この例では、以下を含む Deep Learning Toolbox™ の層を使用して畳み込み自己符号化器ネットワークを定義します。

イメージ入力層を作成します。係数 2 によるダウンサンプリングとアップサンプリングに関連するパディングの問題を簡略化するには、入力サイズに 32 行 32 列を選択します。これは、32 が 2、4、および 8 できれいに割り切れるためです。

imageLayer = imageInputLayer([32,32,1]);

符号化層を作成します。符号化器でのダウンサンプリングは、プール サイズ 2 およびストライド 2 で最大プーリングを行うことによって実行できます。

encodingLayers = [ ...
    convolution2dLayer(3,8,Padding="same"), ...
    reluLayer, ...
    maxPooling2dLayer(2,Padding="same",Stride=2), ...
    convolution2dLayer(3,16,Padding="same"), ...
    reluLayer, ...
    maxPooling2dLayer(2,Padding="same",Stride=2), ...
    convolution2dLayer(3,32,Padding="same"), ...
    reluLayer, ...
    maxPooling2dLayer(2,Padding="same",Stride=2)];

復号化層を作成します。復号化器は、ストライドが 2 の転置畳み込み層を使用して、符号化された信号を係数 2 でアップサンプリングします。ネットワークは clippedReluLayer を最終的な活性化層として使用して、出力の範囲を [0, 1] にします。

decodingLayers = [ ...
    transposedConv2dLayer(2,32,Stride=2), ...
    reluLayer, ...
    transposedConv2dLayer(2,16,Stride=2), ...
    reluLayer, ...
    transposedConv2dLayer(2,8,Stride=2), ...
    reluLayer, ...
    convolution2dLayer(1,1,Padding="same"), ...
    clippedReluLayer(1.0), ...
    regressionLayer];    

イメージ入力層、符号化層、および復号化層を連結して、畳み込み自己符号化器ネットワーク アーキテクチャを形成します。

layers = [imageLayer,encodingLayers,decodingLayers];

学習オプションの定義

Adam 最適化を使用してネットワークに学習させます。関数 trainingOptions を使用してハイパーパラメーター設定を指定します。学習を 50 エポック行います。

options = trainingOptions("adam", ...
    MaxEpochs=50, ...
    MiniBatchSize=imds.ReadSize, ...
    ValidationData=dsVal, ...
    ValidationPatience=5, ...
    Plots="training-progress", ...
    OutputNetwork="best-validation-loss", ...
    Verbose=false);

ネットワークの学習

データ ソースおよび学習オプションが構成されたので、関数 trainNetwork を使用して畳み込み自己符号化器ネットワークに学習させます。

GPU が利用できる場合、GPU で学習を行います。GPU を使用するには、Parallel Computing Toolbox™、および CUDA® 対応の NVIDIA® GPU が必要です。詳細については、GPU 計算の要件 (Parallel Computing Toolbox)を参照してください。学習には NVIDIA Titan XP で約 15 分を要します。

net = trainNetwork(dsTrain,layers,options);
modelDateTime = string(datetime("now",Format="yyyy-MM-dd-HH-mm-ss"));
save("trainedImageToImageRegressionNet-"+modelDateTime+".mat","net");    

ノイズ除去ネットワークの性能の評価

関数 predict を使用して、テスト セットから出力イメージを取得します。

ypred = predict(net,dsTest);

関数 preview を使用して、ノイズを含むイメージと初期状態のイメージのペアをテスト セットから取得します。

testBatch = preview(dsTest);

サンプル入力イメージと、ネットワークからの関連する予測出力を可視化して、ノイズ除去がどれだけ適切に機能しているかを把握します。予測どおり、ネットワークからの出力イメージでは、入力イメージのノイズ アーティファクトの大部分が除去されています。符号化および復号化プロセスの結果、ノイズ除去後のイメージは少し不鮮明になっています。

idx = 1;
y = ypred(:,:,:,idx);
x = testBatch{idx,1};
ref = testBatch{idx,2};
montage({x,y})

ピーク S/N 比 (PSNR) を解析することによって、ネットワークの性能を評価します。

psnrNoisy = psnr(x,ref)
psnrNoisy = single
    19.6457
psnrDenoised = psnr(y,ref)
psnrDenoised = single
    20.6994

予想どおり、出力イメージの PSNR は、ノイズを含む入力イメージより高くなっています。

サポート関数

補助関数 addNoise は、関数 imnoise (Image Processing Toolbox) を使用してイメージにごま塩ノイズを追加します。関数 addNoise では、入力データの形式がイメージ データの cell 配列であることが必要です。これは、ImageDatastore の関数 read によって返されるデータの形式と一致します。

function dataOut = addNoise(data)

    dataOut = data;
    for idx = 1:size(data,1)
       dataOut{idx} = imnoise(data{idx},"salt & pepper");
    end

end

補助関数 commonPreprocessing は、学習セット、検証セット、およびテスト セットに共通する前処理を定義します。この補助関数は以下の前処理手順を実行します。

  1. イメージ データをデータ型 single に変換する。

  2. 関数imresizeを使用して、入力層のサイズに一致するようにイメージ データのサイズを変更する。

  3. 関数 rescale を使用してデータを [0, 1] の範囲に正規化する。

この補助関数では、入力データの形式がイメージ データの 2 列の cell 配列であることが必要です。これは、CombinedDatastore の関数 read によって返されるデータの形式と一致します。

function dataOut = commonPreprocessing(data)

    dataOut = cell(size(data));
    for col = 1:size(data,2)
        for idx = 1:size(data,1)
            temp = single(data{idx,col});
            temp = imresize(temp,[32,32]);
            temp = rescale(temp);
            dataOut{idx,col} = temp;
        end
    end
end

補助関数 augmentImages は、関数 rot90 を使用してランダムな 90 度の回転をデータに追加します。ネットワーク入力とそれに対応する予測される応答に同一の回転が適用されます。この関数では、入力データの形式がイメージ データの 2 列の cell 配列であることが必要です。これは、CombinedDatastore の関数 read によって返されるデータの形式と一致します。

function dataOut = augmentImages(data)

    dataOut = cell(size(data));
    for idx = 1:size(data,1)
        rot90Val = randi(4,1,1)-1;
        dataOut(idx,:) = {rot90(data{idx,1},rot90Val), ...
            rot90(data{idx,2},rot90Val)};
    end
end

参考

| | | |

関連する例

詳細