活性化層の比較
この例では、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
参考
trainnet
| trainingOptions
| dlnetwork
| reluLayer
| leakyReluLayer
| swishLayer