Main Content

活性化層の比較

この例では、ReLU 活性化層、leaky ReLU 活性化層、ELU 活性化層、Swish 活性化層を使用してネットワークの学習精度を比較する方法を説明します。

深層学習ニューラル ネットワークの学習では、ReLU 演算や Swish 演算などの非線形活性化関数を使用する必要があります。一部の活性化層では、計算に多くの時間をかけると学習パフォーマンスを向上できます。ニューラル ネットワークに学習させる場合、さまざまな活性化層を使用して学習が改善されるかどうかを試すことができます。

この例では、与えられたイメージの検証セットに対して ReLU 活性化層、leaky ReLU 活性化層、ELU 活性化層、Swish 活性化層を使用して、SqueezeNet ニューラル ネットワークに学習させるときの検証精度を比較する方法を説明します。

データの読み込み

Flowers データ セットをダウンロードします。

url = "http://download.tensorflow.org/example_images/flower_photos.tgz";
downloadFolder = tempdir;
filename = fullfile(downloadFolder,"flower_dataset.tgz");

dataFolder = fullfile(downloadFolder,"flower_photos");
if ~exist(dataFolder,"dir")
    fprintf("Downloading Flowers data set (218 MB)... ")
    websave(filename,url);
    untar(filename,downloadFolder)
    fprintf("Done.\n")
end

学習用データの準備

関数 imageDatastore を使用してデータをイメージ データストアとして読み込み、イメージ データが格納されているフォルダーを指定します。

imds = imageDatastore(dataFolder, ...
    IncludeSubfolders=true, ...
    LabelSource="foldernames");

学習データのクラスの数を表示します。

numClasses = numel(categories(imds.Labels))
numClasses = 5

データストアを分割して、学習セットの各カテゴリに 80% のイメージが含まれ、検証セットに各ラベルの残りのイメージが含まれるようにします。

[imdsTrain,imdsValidation] = splitEachLabel(imds,0.80,"randomize");

拡張オプションを指定して、学習イメージが格納された拡張イメージ データストアを作成します。

  • 横軸方向にイメージをランダムに反転します。

  • 最大 20% までイメージをランダムにスケーリングします。

  • 最大 45 度までイメージをランダムに回転します。

  • 最大 3 ピクセルまでイメージをランダムに平行移動します。

  • イメージのサイズをネットワークの入力サイズ (227 行 227 列) に変更します。

imageAugmenter = imageDataAugmenter( ...
    RandXReflection=true, ...
    RandScale=[0.8 1.2], ...
    RandRotation=[-45,45], ...
    RandXTranslation=[-3 3], ...
    RandYTranslation=[-3 3]);

augimdsTrain = augmentedImageDatastore([227 227],imdsTrain,DataAugmentation=imageAugmenter);

イメージのサイズをネットワークの入力サイズに変更した検証データ用に拡張イメージ データストアを作成します。この検証データには、その他のイメージ変換を適用しません。

augimdsValidation = augmentedImageDatastore([227 227],imdsValidation);

カスタム プロット関数の作成

複数のネットワークに学習させる場合に、各ネットワークの検証精度を同じ軸上で監視するには、OutputFcn 学習オプションを使用し、与えられた学習情報でプロットを更新する関数を指定できます。

学習プロセスから情報構造体を受け取ってアニメーションの線のプロットを更新する関数を作成します。この例のプロット関数の節にリストされている関数 updatePlot は、情報構造体を入力として受け取り、指定されたアニメーションの線を更新します。

学習オプションの指定

学習オプションを指定します。

  • ミニバッチ サイズを 128 として、学習を 60 エポック行います。

  • 各エポックでデータをシャッフルします。

  • ホールドアウトされた検証セットを使用して、エポックごとにニューラル ネットワークを 1 回検証します。

miniBatchSize = 128;
numObservationsTrain = numel(imdsTrain.Files);
numIterationsPerEpoch = floor(numObservationsTrain / miniBatchSize);

options = trainingOptions("adam", ...
    MiniBatchSize=miniBatchSize, ...
    MaxEpochs=60, ...
    Shuffle="every-epoch", ...
    ValidationData=augimdsValidation, ...
    ValidationFrequency=numIterationsPerEpoch, ...
    Metrics="accuracy", ...
    Verbose=false);

ニューラル ネットワークの学習

各タイプの活性化層 (ReLU、leaky ReLU、ELU、および Swish) について、SqueezeNet ネットワークの学習を行います。

活性化層のタイプを指定します。

activationLayerTypes = ["relu" "leaky-relu" "elu" "swish"];

関数 colororder で指定された色を使用してアニメーションの線を作成し、カスタマイズされた学習進行状況プロットを初期化します。

figure

colors = colororder;

for i = 1:numel(activationLayerTypes)
    line(i) = animatedline(Color=colors(i,:));
end

ylim([0 100])

legend(activationLayerTypes,Location="southeast");

xlabel("Iteration")
ylabel("Accuracy")
title("Validation Accuracy")
grid on

各タイプの活性化層をループ処理し、ニューラル ネットワークに学習させます。各タイプの活性化層について、以下を行います。

  • 活性化層を作成する関数ハンドル activationLayer を作成します。

  • 重みのない SqueezeNet ネットワークを新たに作成し、関数ハンドル activationLayer を使用して活性化層 (ReLU 層) を目的のタイプの活性化層に置き換えます。

  • ニューラル ネットワークの最終の畳み込み層を、入力データのクラスの数を指定するものに置き換えます。

  • 学習オプション オブジェクトの OutputFcn プロパティを、関数 updatePlot を表す関数ハンドルに設定し、活性化層のタイプに対応したアニメーションの線を使用して、検証精度のプロットを更新します。

  • 関数 trainNetwork を使用してネットワークに学習させ、その時間を計測します。

for i = 1:numel(activationLayerTypes)
    activationLayerType = activationLayerTypes(i);
    
    % Determine activation layer type.
    switch activationLayerType
        case "relu"
            activationLayer = @reluLayer;
        case "leaky-relu"
            activationLayer = @leakyReluLayer;
        case "elu"
            activationLayer = @eluLayer;
        case "swish"
            activationLayer = @swishLayer;
    end
    
    % Create SqueezeNet with correct number of classes.
    net{i} = imagePretrainedNetwork("squeezenet",NumClasses=numClasses,Weights="none");
    
    % Replace activation layers.
    if activationLayerType ~= "relu"
        layers = net{i}.Layers;
        for j = 1:numel(layers)
            if isa(layers(j),"nnet.cnn.layer.ReLULayer")
                layerName = layers(j).Name;
                layer = activationLayer(Name=activationLayerType+"_new_"+j);
                net{i} = replaceLayer(net{i},layerName,layer);
            end
        end
    end
    
    % Specify custom plot function.
    options.OutputFcn = @(info) updatePlot(info,line(i));
    
    % Train the network.
    start = tic;
    [net{i},info{i}] = trainnet(augimdsTrain,net{i},"crossentropy",options);
    elapsed(i) = toc(start);
end

学習時間を棒グラフで表示します。

figure
bar(categorical(activationLayerTypes),elapsed)
title("Training Time")
ylabel("Time (seconds)")

この場合、どの活性化層を使用しても最終的な検証精度はあまり変わりません。ELU 層を使用すると、他の活性化層と比べて多くの計算時間が必要になります。

プロット関数

関数 updatePlot は、情報構造体 info を入力として受け取り、指定されたアニメーションの線 line を使用して検証プロットを更新します。この関数は、logical 値 stopFlag を常に false で返します。そのため、このプロット関数によって学習が早期に停止することは決してありません。

function stopFlag = updatePlot(info,line)

if ~isempty(info.ValidationAccuracy)
    addpoints(line,info.Iteration,info.ValidationAccuracy);
    drawnow limitrate
end
stopFlag = false;
end

参考

| | | | |

関連するトピック