Main Content

このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。

次元削減のためのシャム ネットワークの学習

この例では、次元削減を使用して手書きの数字を比較するシャム ネットワークの学習方法を説明します。

シャム ネットワークは深層学習ネットワークの一種で、同じアーキテクチャをもち、同じパラメーターと重みを共有する、2 つ以上の同一のサブネットワークを使用します。シャム ネットワークは通常、比較可能な 2 つの事例の関係性を見つけることに関わるタスクに使用されます。シャム ネットワークの一般的な使用例には、顔認識、シグネチャ検証 [1]、またはパラフレーズ識別 [2] などがあります。学習中に重みを共有することで学習させるパラメーターが少なくなり、比較的少量の学習データで良い結果が得られるため、シャム ネットワークはこれらのタスクにおいて良好に動作します。

シャム ネットワークは特に、クラスの数が多く、各クラスの観測値が少ない場合に役立ちます。このような場合、イメージをこれらのクラスに分類するよう深層畳み込みニューラル ネットワークに学習させるだけの十分なデータがありません。代わりに、シャム ネットワークによって 2 つのイメージが同じクラスに属するかどうかを判定することができます。ネットワークは、学習データの次元を削減し、距離ベースのコスト関数を使用してクラス間を区別することでこれを行います。

この例ではシャム ネットワークを使用して、手書きの数字のイメージ コレクションについて次元削減を行います。シャム アーキテクチャは、同じクラスのイメージを低次元空間の近傍点にマッピングすることで次元削減を行います。その後、低次元特徴の表現を使用して、テスト イメージに最も類似したイメージをデータセットから抽出します。この例の学習データは、サイズ 28 x 28 x 1 のイメージで、初期の特徴次元は 784 です。シャム ネットワークは、入力イメージの次元を 2 つの特徴に削減して、同一ラベルのイメージに対して類似の低次元特徴を出力するように学習を行います。

シャム ネットワークを使用すると、類似のイメージを直接比較して識別することもできます。例については、シャム ネットワークの学習とイメージの比較を参照してください。

学習データの読み込みと前処理

手書きの数字のイメージで構成される学習データを読み込みます。関数 digitTrain4DArrayData は、数字のイメージとそのラベルを読み込みます。

[XTrain,YTrain] = digitTrain4DArrayData;

XTrain は、サイズが 28 x 28 のシングル チャネル イメージ 5000 個を含む、28 x 28 x 1 x 5000 の配列です。各ピクセルは 0 から 1 の間の値です。YTrain は、各観測値のラベルが含まれる categorical ベクトルで、ラベルは手書きの数字に対応する 0 から 9 の数字です。

ランダムに選択したイメージを表示します。

perm = randperm(numel(YTrain), 9);
imshow(imtile(XTrain(:,:,:,perm),"ThumbnailSize",[100 100]));

類似イメージと非類似イメージのペアの作成

ネットワークに学習させるには、データを類似イメージまたは非類似イメージのペアにグループ化しなければなりません。ここで、類似イメージは同じラベルをもつイメージ、非類似イメージは異なるラベルをもつイメージとして定義されます。関数 getSiameseBatch (この例のサポート関数の節で定義) は、類似イメージまたは非類似イメージのランダム化されたペアである pairImage1 pairImage2 を作成します。また、この関数は、イメージのペアが互いに類似か非類似かを識別するラベル pairLabel を返します。イメージの類似ペアの場合は pairLabel = 1、非類似ペアの場合は pairLabel = 0 になります。

一例として、5 つのイメージのペアをもつ、典型的な小さいセットを作成します。

batchSize = 10;
[pairImage1,pairImage2,pairLabel] = getSiameseBatch(XTrain,YTrain,batchSize);

生成されたイメージのペアを表示します。

for i = 1:batchSize
subplot(2,5,i)
imshow([pairImage1(:,:,:,i) pairImage2(:,:,:,i)]);
if pairLabel(i) == 1
    s = "similar";
else
    s = "dissimilar";
end
title(s)
end

この例では、学習ループの反復ごとに、イメージのペア 180 個から成る新しいバッチが作成されます。これにより、類似ペアと非類似ペアの比率がほぼ等しい大量のランダムなイメージのペアでネットワークに学習させることができます。

ネットワーク アーキテクチャの定義

シャム ネットワークのアーキテクチャを次の図に示します。

この例では、2 つの同一のサブネットワークが ReLU 層をもつ一連の全結合層として定義されます。28 x 28 x 1 のイメージを受け取り、低次元特徴表現として使用される 2 つの特徴ベクトルを出力するネットワークを作成します。ネットワークは、入力イメージの次元を 2 に削減します。これにより、初期の 784 の次元よりもプロットと可視化を簡単に行えるようになります。

最初の 2 つの全結合層では、出力サイズに 1024 を指定し、He の重みの初期化子を使用します。

最終の全結合層では、出力サイズに 2 を指定し、He の重みの初期化子を使用します。

layers = [
    imageInputLayer([28 28],'Name','input1','Normalization','none')
    fullyConnectedLayer(1024,'Name','fc1','WeightsInitializer','he')
    reluLayer('Name','relu1')
    fullyConnectedLayer(1024,'Name','fc2','WeightsInitializer','he')
    reluLayer('Name','relu2')
    fullyConnectedLayer(2,'Name','fc3','WeightsInitializer','he')];

lgraph = layerGraph(layers);

カスタム学習ループを使用してネットワークに学習させ、自動微分を有効にするには、層グラフを dlnetwork オブジェクトに変換します。

dlnet = dlnetwork(lgraph);

モデル勾配関数の定義

関数 modelGradients (この例のサポート関数の節で定義) を作成します。関数 modelGradients は、シャム dlnetwork オブジェクトの dlnetand と、ミニバッチ入力データ dlX1 および dlX2 とそのラベル pairLabels を受け取ります。関数は損失値と、ネットワークの学習可能なパラメーターについての損失の勾配を返します。

シャム ネットワークの目的は、各イメージについて、類似イメージの場合は類似し、非類似イメージの場合は明確に異なるような特徴ベクトルを出力することです。このようにして、ネットワークは 2 つの入力を区別することができます。

最後の全結合層の出力と、pairImage1 および pairImage2 からの特徴ベクトル features1 および features1 との間の対比損失をそれぞれ求めます。ペアの対比損失は [3] で与えられます。

loss=12yd2+12(1-y)max(margin-d,0)2,

ここで、y はペア ラベルの値 (類似イメージの場合は y=1、非類似イメージの場合は y=0) で、d は 2 つの特徴ベクトル f1f2 のユークリッド距離 d=f1-f22 です。

margin パラメーターは制約のために使用されます。ペア内の 2 つのイメージが非類似の場合は、両者の距離が少なくとも margin でなければならず、そうでないと損失が発生します。

対比損失には項が 2 つありますが、与えられたイメージ ペアについて非ゼロになり得るのは、どちらか 1 つだけです。類似イメージの場合は、第 1 項が非ゼロになることができ、イメージの特徴 f1f2 の間の距離を減らすことで最小化されます。非類似イメージの場合は、第 2 項が非ゼロになることができ、イメージの特徴間の距離を増やすことで、少なくとも margin の距離まで最小化されます。margin の値が小さいほど、損失が発生する前に非類似ペアがどれだけ近くなり得るかの制約が緩くなります。

学習オプションの指定

学習中に使用する margin の値を指定します。

margin = 0.3;

学習中に使用するオプションを指定します。3000 回反復して学習させます。

numIterations = 3000;
miniBatchSize = 180;

ADAM 最適化のオプションを指定します。

  • 学習率を 0.0001 に設定します。

  • 最後の平均勾配と最後の平均 2 乗勾配減衰率を [] に初期化します。

  • 勾配の減衰係数を 0.9 に、2 乗勾配の減衰係数を 0.99 に設定。

learningRate = 1e-4;
trailingAvg = [];
trailingAvgSq = [];
gradDecay = 0.9;
gradDecaySq = 0.99;

GPU が利用できる場合、GPU で学習を行います。GPU を使用するには、Parallel Computing Toolbox™ とサポートされている GPU デバイスが必要です。サポートされているデバイスについては、リリース別の GPU サポート (Parallel Computing Toolbox)を参照してください。GPU が使用可能で、関連するデータを GPU に配置できるかどうかを自動的に検出するには、executionEnvironment の値を "auto" に設定します。GPU がない場合や、学習に GPU を使用しない場合は、executionEnvironment の値を "cpu" に設定します。学習に必ず GPU を使用するには、executionEnvironment の値を "gpu" に設定します。

executionEnvironment = "auto";

学習の進行状況を監視するには、それぞれの反復の後で学習の損失をプロットできます。"training-progress" を含む変数 plots を作成します。学習の進行状況をプロットしない場合は、この値を "none" に設定します。

plots = "training-progress";

学習損失の進行状況をプロットするためのプロット パラメーターを初期化します。

plotRatio = 16/9;

if plots == "training-progress"
    trainingPlot = figure;
    trainingPlot.Position(3) = plotRatio*trainingPlot.Position(4);
    trainingPlot.Visible = 'on';
    
    trainingPlotAxes = gca;
    
    lineLossTrain = animatedline(trainingPlotAxes);
    xlabel(trainingPlotAxes,"Iteration")
    ylabel(trainingPlotAxes,"Loss")
    title(trainingPlotAxes,"Loss During Training")
end

次元削減におけるネットワークの性能を評価するために、各反復の後でテスト データのセットについて低次元特徴を計算してプロットします。学習データと類似した手書きの数字のイメージで構成されるテスト データを読み込みます。テスト データを dlarray に変換し、次元ラベルを 'SSCB' (spatial、spatial、channel、batch) に指定します。GPU を使用している場合は、テスト データを gpuArray に変換します。

[XTest,YTest] = digitTest4DArrayData;
dlXTest = dlarray(single(XTest),'SSCB');

% If training on a GPU, then convert data to gpuArray.
if (executionEnvironment == "auto" && canUseGPU) || executionEnvironment == "gpu"
    dlXTest = gpuArray(dlXTest);           
end 

テスト データの低次元特徴プロットのためにプロット パラメーターを初期化します。

dimensionPlot = figure;
dimensionPlot.Position(3) = plotRatio*dimensionPlot.Position(4);
dimensionPlot.Visible = 'on';

dimensionPlotAxes = gca;

uniqueGroups = unique(YTest);
colors = hsv(length(uniqueGroups));

反復の合計回数を追跡するためのカウンターを初期化します。

iteration = 1;

モデルの学習

カスタム学習ループを使用してモデルに学習させます。学習データ全体をループ処理し、各反復でネットワーク パラメーターを更新します。

それぞれの反復で次を行います。

  • イメージ ペアのバッチの作成の節で定義されている関数 getSiameseBatch を使用して、イメージ ペアとラベルのバッチを抽出。

  • 基となる型が singledlarray オブジェクトにイメージ データを変換し、次元ラベルを 'SSCB' (spatial、spatial、channel、batch) に指定。

  • GPU で学習する場合、イメージ データを gpuArray オブジェクトに変換。

  • 関数 dlfeval および modelGradients を使用してモデルの勾配を評価します。

  • 関数 adamupdate を使用してネットワーク パラメーターを更新。

% Loop over mini-batches.
for iteration = 1:numIterations
    
    % Extract mini-batch of image pairs and pair labels
    [X1,X2,pairLabels] = getSiameseBatch(XTrain,YTrain,miniBatchSize);
    
    % Convert mini-batch of data to dlarray. Specify the dimension labels
    % 'SSCB' (spatial, spatial, channel, batch) for image data
    dlX1 = dlarray(single(X1),'SSCB');
    dlX2 = dlarray(single(X2),'SSCB');
    
    % If training on a GPU, then convert data to gpuArray.
    if (executionEnvironment == "auto" && canUseGPU) || executionEnvironment == "gpu"
        dlX1 = gpuArray(dlX1);
        dlX2 = gpuArray(dlX2);
    end       
    
    % Evaluate the model gradients and the generator state using
    % dlfeval and the modelGradients function listed at the end of the
    % example.
    [gradients,loss] = dlfeval(@modelGradients,dlnet,dlX1,dlX2,pairLabels,margin);
    lossValue = double(gather(extractdata(loss)));
    
    % Update the Siamese network parameters.
    [dlnet.Learnables,trailingAvg,trailingAvgSq] = ...
        adamupdate(dlnet.Learnables,gradients, ...
        trailingAvg,trailingAvgSq,iteration,learningRate,gradDecay,gradDecaySq);
    
    % Update the training loss progress plot.
    if plots == "training-progress"
        addpoints(lineLossTrain,iteration,lossValue);
    end
            
    % Update the reduced-feature plot of the test data.        
    % Compute reduced features of the test data:
    dlFTest = predict(dlnet,dlXTest);
    FTest = extractdata(dlFTest);
       
    figure(dimensionPlot);
    for k = 1:length(uniqueGroups)
        % Get indices of each image in test data with the same numeric 
        % label (defined by the unique group):
        ind = YTest==uniqueGroups(k);
        % Plot this group:
        plot(dimensionPlotAxes,gather(FTest(1,ind)'),gather(FTest(2,ind)'),'.','color',...
            colors(k,:));
        hold on
    end
    
    legend(uniqueGroups)
    
    % Update title of reduced-feature plot with training progress information.
    title(dimensionPlotAxes,"2-D Feature Representation of Digits Images. Iteration = " +...
        iteration);
    legend(dimensionPlotAxes,'Location','eastoutside');
    xlabel(dimensionPlotAxes,"Feature 1")
    ylabel(dimensionPlotAxes,"Feature 2")
    
    hold off    
    drawnow    
end

ネットワークは、各イメージを 2 次元ベクトルとして表すことを学習しました。テスト データの低次元特徴プロットからわかるように、2 次元表現では類似した数字のイメージが互いに近くに集まっています。

学習済みネットワークを使用した類似イメージの検出

学習済みネットワークを使用して、互いに似ているイメージの集合をグループから検出することが可能です。この場合、テスト データをイメージのグループとして使用します。イメージのグループを dlarray オブジェクトと gpuArray オブジェクト (GPU を使用している場合) に変換します。

groupX = XTest;

dlGroupX = dlarray(single(groupX),'SSCB');

if (executionEnvironment == "auto" && canUseGPU) || executionEnvironment == "gpu"
    dlGroupX = gpuArray(dlGroupX);           
end 

グループからテスト イメージを 1 つ抽出して表示します。テスト イメージをグループから削除して、類似イメージのセットに出現しないようにします。

testIdx = randi(5000);
testImg = dlGroupX(:,:,:,testIdx);

trialImgDisp = extractdata(testImg);

figure
imshow(trialImgDisp, 'InitialMagnification', 500);

dlGroupX(:,:,:,testIdx) = [];

predict を使用してテスト イメージの低次元特徴を求めます。

trialF = predict(dlnet,testImg);

学習済みネットワークを使用して、グループ内の各イメージについて 2 次元の低次元特徴表現を求めます。

FGroupX = predict(dlnet,dlGroupX);

低次元特徴表現を使用して、ユークリッド距離計量を用いてテスト イメージに最も近いイメージをグループ内から 9 個見つけます。イメージを表示します。

distances = vecnorm(extractdata(trialF - FGroupX));
[~,idx] = sort(distances);
sortedImages = groupX(:,:,:,idx);

figure
imshow(imtile(sortedImages(:,:,:,1:9)), 'InitialMagnification', 500);

イメージの次元を削減することで、ネットワークは、テスト イメージに類似したイメージを識別できます。低次元特徴表現によって、ネットワークによる類似イメージと非類似イメージの識別が可能になります。シャム ネットワークは顔認識やシグネチャ認識のコンテキストでよく使用されます。たとえば、顔のイメージを入力として受け取り、データベースからよく似ている顔のセットを返すように、シャム ネットワークに学習させることができます。

サポート関数

モデル勾配関数

関数 modelGradients は、シャム dlnetwork のオブジェクト dlnet、ミニバッチ入力データ X1X2 のペア、およびラベル pairLabels を受け取ります。この関数は、ネットワーク内の学習可能なパラメーターについての損失の勾配と、ペアになっているイメージの次元低特徴間の対比損失を返します。この例において、関数 modelGradients については、モデル勾配関数の定義の節で説明されています。

function [gradients, loss] = modelGradients(net,X1,X2,pairLabel,margin)
% The modelGradients function calculates the contrastive loss between the
% paired images and returns the loss and the gradients of the loss with 
% respect to the network learnable parameters

    % Pass first half of image pairs forward through the network
    F1 = forward(net,X1);
    % Pass second set of image pairs forward through the network
    F2 = forward(net,X2);
    
    % Calculate contrastive loss
    loss = contrastiveLoss(F1,F2,pairLabel,margin);
    
    % Calculate gradients of the loss with respect to the network learnable
    % parameters
    gradients = dlgradient(loss, net.Learnables);

end

function loss = contrastiveLoss(F1,F2,pairLabel,margin)
% The contrastiveLoss function calculates the contrastive loss between
% the reduced features of the paired images 
    
    % Define small value to prevent taking square root of 0
    delta = 1e-6;
    
    % Find Euclidean distance metric
    distances = sqrt(sum((F1 - F2).^2,1) + delta);
    
    % label(i) = 1 if features1(:,i) and features2(:,i) are features
    % for similar images, and 0 otherwise
    lossSimilar = pairLabel.*(distances.^2);
 
    lossDissimilar = (1 - pairLabel).*(max(margin - distances, 0).^2);
    
    loss = 0.5*sum(lossSimilar + lossDissimilar,'all');
end

イメージ ペアのバッチの作成

次の関数は、ラベルに基づいて類似または非類似のイメージのランダム化されたペアを作成します。この例では、関数 getSiameseBatch について類似イメージと非類似イメージのペアの作成の節で紹介されています

function [X1,X2,pairLabels] = getSiameseBatch(X,Y,miniBatchSize)
% getSiameseBatch returns a randomly selected batch of paired images. 
% On average, this function produces a balanced set of similar and 
% dissimilar pairs.
    pairLabels = zeros(1, miniBatchSize);
    imgSize = size(X(:,:,:,1));
    X1 = zeros([imgSize 1 miniBatchSize]);
    X2 = zeros([imgSize 1 miniBatchSize]);
    
    for i = 1:miniBatchSize
        choice = rand(1);
        if choice < 0.5
            [pairIdx1, pairIdx2, pairLabels(i)] = getSimilarPair(Y);
        else
            [pairIdx1, pairIdx2, pairLabels(i)] = getDissimilarPair(Y);
        end
        X1(:,:,:,i) = X(:,:,:,pairIdx1);
        X2(:,:,:,i) = X(:,:,:,pairIdx2);
    end
    
end

function [pairIdx1,pairIdx2,pairLabel] = getSimilarPair(classLabel)
% getSimilarPair returns a random pair of indices for images
% that are in the same class and the similar pair label = 1.

    % Find all unique classes.
    classes = unique(classLabel);
    
    % Choose a class randomly which will be used to get a similar pair.
    classChoice = randi(numel(classes));
    
    % Find the indices of all the observations from the chosen class.
    idxs = find(classLabel==classes(classChoice));
    
    % Randomly choose two different images from the chosen class.
    pairIdxChoice = randperm(numel(idxs),2);
    pairIdx1 = idxs(pairIdxChoice(1));
    pairIdx2 = idxs(pairIdxChoice(2));
    pairLabel = 1;
end

function  [pairIdx1,pairIdx2,pairLabel] = getDissimilarPair(classLabel)
% getDissimilarPair returns a random pair of indices for images
% that are in different classes and the dissimilar pair label = 0.

    % Find all unique classes.
    classes = unique(classLabel);
    
    % Choose two different classes randomly which will be used to get a dissimilar pair.
    classesChoice = randperm(numel(classes), 2);
    
    % Find the indices of all the observations from the first and second classes.
    idxs1 = find(classLabel==classes(classesChoice(1)));
    idxs2 = find(classLabel==classes(classesChoice(2)));
    
    % Randomly choose one image from each class.
    pairIdx1Choice = randi(numel(idxs1));
    pairIdx2Choice = randi(numel(idxs2));
    pairIdx1 = idxs1(pairIdx1Choice);
    pairIdx2 = idxs2(pairIdx2Choice);
    pairLabel = 0;
end

参考文献

[1] Bromley, J., I. Guyon, Y. LeCunn, E. Säckinger, and R. Shah."Signature Verification using a "Siamese" Time Delay Neural Network." In Proceedings of the 6th International Conference on Neural Information Processing Systems (NIPS 1993), 1994, pp737-744. Available at Signature Verification using a "Siamese" Time Delay Neural Network on the NIPS Proceedings website.

[2] Wenpeg, Y., and H Schütze. "Convolutional Neural Network for Paraphrase Identification." In Proceedings of 2015 Conference of the North American Cahapter of the ACL, 2015, pp901-911.Available at Convolutional Neural Network for Paraphrase Identification on the ACL Anthology website.

[3] Hadsell, R., S. Chopra, and Y. LeCunn. "Dimensionality Reduction by Learning an Invariant Mapping." In Proceedings of the 2006 IEEE Computer Society Conference on Computer Vision and Pattern Recognition (CVPR 2006), 2006, pp1735-1742.

参考

| | | |

関連するトピック