ドキュメンテーション

最新のリリースでは、このページがまだ翻訳されていません。 このページの最新版は英語でご覧になれます。

複数の入力があるカスタム深層学習層の定義

目的の分類または回帰問題に必要な層が Deep Learning Toolbox™ に用意されていない場合、この例を指針として使用して独自のカスタム層を定義できます。組み込まれている層の一覧については、深層学習層の一覧を参照してください。

カスタム深層学習層を定義するために、この例で提供するテンプレートを使用できます。この例では、次のステップで説明を進めます。

  1. 層の命名 – MATLAB® で使用できるように層に名前を付けます。

  2. 層のプロパティの宣言 – 層のプロパティと、学習中にどのパラメーターが学習されるかを指定します。

  3. コンストラクター関数の作成 (オプション) – 層の構築とそのプロパティ初期化の方法を指定します。コンストラクター関数を指定しない場合、作成時に NameDescription、および Type の各プロパティは [] で初期化され、層の入力および出力の数は 1 に設定されます。

  4. 順方向関数の作成 – 予測時および学習時に層経由でデータを順方向にパス (順伝播) する方法を指定します。

  5. 逆方向関数の作成 – 入力データおよび学習可能なパラメーターにおける損失の微分を指定します (逆伝播)。

この例では、複数の入力があり、学習可能なパラメーターを含む層である重み付き加算層を作成し、畳み込みニューラル ネットワークで使用する方法を説明します。重み付き加算層は、複数のニューラル ネットワーク層からの入力を要素単位でスケーリングして加算します。

学習可能なパラメーターを含む層のテンプレート

学習可能なパラメーターを含む層のテンプレートを MATLAB の新しいファイルにコピーします。このテンプレートは、学習可能なパラメーターを含む層の構造の概要を示しており、層の動作を定義する関数を含んでいます。

classdef myLayer < nnet.layer.Layer

    properties
        % (Optional) Layer properties.

        % Layer properties go here.
    end

    properties (Learnable)
        % (Optional) Layer learnable parameters.

        % Layer learnable parameters go here.
    end
    
    methods
        function layer = myLayer()
            % (Optional) Create a myLayer.
            % This function must have the same name as the class.

            % Layer constructor function goes here.
        end
        
        function [Z1, …, Zm] = predict(layer, X1, …, Xn)
            % Forward input data through the layer at prediction time and
            % output the result.
            %
            % Inputs:
            %         layer       - Layer to forward propagate through
            %         X1, ..., Xn - Input data
            % Outputs:
            %         Z1, ..., Zm - Outputs of layer forward function
            
            % Layer forward function for prediction goes here.
        end

        function [Z1, …, Zm, memory] = forward(layer, X1, …, Xn)
            % (Optional) Forward input data through the layer at training
            % time and output the result and a memory value.
            %
            % Inputs:
            %         layer       - Layer to forward propagate through
            %         X1, ..., Xn - Input data
            % Outputs:
            %         Z1, ..., Zm - Outputs of layer forward function
            %         memory      - Memory value for backward propagation

            % Layer forward function for training goes here.
        end

        function [dLdX1, …, dLdXn, dLdW1, …, dLdWk] = ...
                backward(layer, X1, …, Xn, Z1, …, Zm, dLdZ1, …, dLdZm, memory)
            % Backward propagate the derivative of the loss function through 
            % the layer.
            %
            % Inputs:
            %         layer             - Layer to backward propagate through
            %         X1, ..., Xn       - Input data
            %         Z1, ..., Zm       - Outputs of layer forward function            
            %         dLdZ1, ..., dLdZm - Gradients propagated from the next layers
            %         memory            - Memory value from forward function
            % Outputs:
            %         dLdX1, ..., dLdXn - Derivatives of the loss with respect to the
            %                             inputs
            %         dLdW1, ..., dLdWk - Derivatives of the loss with respect to each
            %                             learnable parameter
            
            % Layer backward function goes here.
        end
    end
end

層の命名

まず、層に名前を付けます。クラス ファイルの最初の行で、既存の名前 myLayerweightedAdditionLayer に置き換えます。

classdef weightedAdditionLayer < nnet.layer.Layer
    ...
end

次に、コンストラクター関数 myLayer (methods セクションの最初の関数) の名前を層と同じ名前に変更します。

    methods
        function layer = weightedAdditionLayer()           
            ...
        end

        ...
     end

層の保存

層のクラス ファイルを weightedAdditionLayer.m という名前の新しいファイルに保存します。このファイル名は層の名前に一致しなければなりません。この層を使用するには、このファイルを現在のフォルダーまたは MATLAB パス上のフォルダーに保存しなければなりません。

プロパティおよび学習可能なパラメーターの宣言

層のプロパティを properties セクションで宣言し、学習可能なパラメーターを properties (Learnable) セクションにリストすることによって宣言します。

既定では、カスタム中間層には次のプロパティがあります。

Property説明
Name 層の名前。文字ベクトルまたは string スカラーとして指定します。層グラフに層を含めるには、空ではない一意の層の名前を指定しなければなりません。この層が含まれる系列ネットワークに学習させて Name'' に設定すると、学習時に層に名前が自動的に割り当てられます。
Description

層についての 1 行の説明。文字ベクトルまたは string スカラーとして指定します。この説明は、層が Layer 配列に表示されるときに表示されます。層の説明を指定しない場合、層のクラス名が表示されます。

Type層のタイプ。文字ベクトルまたは string スカラーとして指定します。Type の値は、層が Layer 配列に表示されるときに表示されます。層のタイプを指定しない場合、層のクラス名が表示されます。
NumInputs層の入力の数。正の整数として指定します。この値を指定しない場合、NumInputsInputNames の名前の数に自動的に設定されます。既定値は 1 です。
InputNames層の入力の名前。文字ベクトルの cell 配列として指定します。この値を指定せず、NumInputs が 1 より大きい場合、InputNames{'in1',...,'inN'} に自動的に設定されます。ここで、N = NumInputs です。既定値は {'in'} です。
NumOutputs層の出力の数。正の整数として指定します。この値を指定しない場合、NumOutputsOutputNames の名前の数に自動的に設定されます。既定値は 1 です。
OutputNames層の出力の名前。文字ベクトルの cell 配列として指定します。この値を指定せず、NumOutputs が 1 より大きい場合、OutputNames{'out1',...,'outM'} に自動的に設定されます。ここで、M = NumOutputs です。既定値は {'out'} です。

層にその他のプロパティがない場合は、properties セクションを省略できます。

ヒント

複数の入力がある層を作成する場合、層のコンストラクターで NumInputs または InputNames のいずれかを設定しなければなりません。複数の出力がある層を作成する場合、層のコンストラクターで NumOutputs または OutputNames のいずれかを設定しなければなりません。

重み付き加算層には追加のプロパティが必要ないため、properties セクションは削除できます。

重み付き加算層には、唯一の学習可能なパラメーターとして重みがあります。この学習可能なパラメーターを properties (Learnable) セクションで宣言し、パラメーター Weights を呼び出します。

    properties (Learnable)
        % Layer learnable parameters
            
        % Scaling coefficients
        Weights
    end

コンストラクター関数の作成

層を構築する関数を作成し、層のプロパティを初期化します。層を作成するために必要な変数をコンストラクター関数への入力として指定します。

重み付き加算層のコンストラクター関数に必要な 2 つの入力は、層への入力の数と層の名前です。この層への入力の数は学習可能なパラメーター Weights のサイズを指定します。numInputs および name という名前の 2 つの入力引数を関数 weightedAdditionLayer に指定します。関数の構文を説明するコメントを関数の上部に追加します。

        function layer = weightedAdditionLayer(numInputs,name)
            % layer = weightedAdditionLayer(numInputs,name) creates a
            % weighted addition layer and specifies the number of inputs
            % and the layer name.
            
            ...
        end

層のプロパティの初期化

コンストラクター関数に学習可能なパラメーターを含め、層のプロパティを初期化します。コメント % Layer constructor function goes here を、層のプロパティを初期化するコードに置き換えます。

NumInputs プロパティを入力引数 numInputs に設定します。

            % Set number of inputs.
            layer.NumInputs = numInputs;

Name プロパティを入力引数 name に設定します。

            % Set layer name.
            layer.Name = name;

層の Description プロパティを設定して、層に 1 行の説明を指定します。層のタイプとサイズの説明を設定します。

            % Set layer description.
            layer.Description = "Weighted addition of " + numInputs + ...
                " inputs";

重み付き加算層は、層の各入力に Weights の対応する係数を乗算し、結果の値を加算します。学習可能なパラメーター Weights を 1 行 numInputs 列のランダム ベクトルに初期化します。Weights は層オブジェクトのプロパティであるため、ベクトルを layer.Weights に割り当てなければなりません。

            % Initialize layer weights
            layer.Weights = rand(1,numInputs);

完成したコンストラクター関数を表示します。

        function layer = weightedAdditionLayer(numInputs,name) 
            % layer = weightedAdditionLayer(numInputs,name) creates a
            % weighted addition layer and specifies the number of inputs
            % and the layer name.

            % Set number of inputs.
            layer.NumInputs = numInputs;

            % Set layer name.
            layer.Name = name;

            % Set layer description.
            layer.Description = "Weighted addition of " + numInputs +  ... 
                " inputs";
        
            % Initialize layer weights.
            layer.Weights = rand(1,numInputs); 
        end

このコンストラクター関数を使用すると、コマンド weightedAdditionLayer(3,'add') により 3 つの入力を持ち、名前が 'add' の重み付き加算層が作成されます。

順方向関数の作成

予測時と学習時に使用する層の順方向関数を作成します。

"予測時" に層経由でデータを順伝播させて結果を出力する、predict という名前の関数を作成します。

predict の構文は、以下のとおりです。

[Z1,…,Zm] = predict(layer,X1,…,Xn)
ここで、X1,…,Xnn 個の層入力、Z1,…,Zmm 個の層出力です。値 n および m は、層の NumInputs プロパティおよび NumOutputs プロパティに対応しなければなりません。

ヒント

predict への入力の数が変化する可能性がある場合、X1,…,Xn ではなく varargin を使用します。この場合、varargin は入力の cell 配列です。ここで、varargin{i}Xi に対応します。出力の数が変化する可能性がある場合、Z1,…,Zm ではなく varargout を使用します。この場合、varargout は出力の cell 配列です。ここで、varargout{j}Zj に対応します。

重み付き加算層の出力は 1 つのみで入力は可変数であるため、重み付き加算層の predict の構文は Z = predict(layer,varargin) になります。ここで、NumInputs 以下の正の整数 i について varargin{i}Xi に対応します。

既定では、層は学習時に predict を順方向関数として使用します。学習時に別の順方向関数を使用する、または逆方向関数に必要な値を保持するには、forward という名前の関数も作成しなければなりません。

入力の次元は、データのタイプと結合層の出力によって異なります。

層入力入力サイズ観察値の次元
2 次元イメージh x w x c x N。ここで、h、w、および c は、それぞれイメージの高さ、幅、およびチャネル数に対応します。N は観測値の数です。4
3 次元イメージh x w x D x c x N。ここで、h、w、D、および c は、それぞれ 3 次元イメージの高さ、幅、深さ、およびチャネル数に対応します。N は観測値の数です。5
ベクトル シーケンスc x N x S。ここで、c はシーケンスの特徴の数、N は観測値の数、S はシーケンス長です。2
2 次元イメージ シーケンスh x w x c x N x S。ここで、h、w、および c は、それぞれイメージの高さ、幅、およびチャネル数に対応します。N は観測値の数、S はシーケンス長です。4
3 次元イメージ シーケンスh x w x d x c x N x S。ここで、h、w、d、および c は、それぞれ 3 次元イメージの高さ、幅、深さ、およびチャネル数に対応します。N は観測値の数、S はシーケンス長です。5

関数 forward"学習時" に層経由でデータを順伝播させ、メモリ値も出力します。

forward の構文は、以下のとおりです。

[Z1,…,Zm,memory] = forward(layer,X1,…,Xn)
ここで、X1,…,Xnn 個の層入力、Z1,…,Zmm 個の層出力、memory は層のメモリです。

ヒント

forward への入力の数が変化する可能性がある場合、X1,…,Xn ではなく varargin を使用します。この場合、varargin は入力の cell 配列です。ここで、varargin{i}Xi に対応します。出力の数が変化する可能性がある場合、Z1,…,Zm ではなく varargout を使用します。この場合、varargout は出力の cell 配列です。ここで、j=1,…,NumOutputs について varargout{j}Zj に対応し、varargout{NumOutputs+1}memory に対応します。

重み付き加算層の順方向関数は次のとおりです。

f(X(1),,X(n))=i=1nWiX(i)

ここで、X(1), …, X(n) は層の入力に対応します。W1,…,Wn は層の重みです。

順方向関数を predict に実装します。predict で、出力 Zf(X(1),,X(n)) に対応します。重み付き加算層では、学習にメモリまたは別の順方向関数が必要ないため、クラス ファイルから関数 forward を削除できます。関数の構文を説明するコメントを関数の上部に追加します。

ヒント

zeros のような関数を使用して配列を事前に割り当てる場合、これらの配列のデータ型が層関数の入力と一致していることを確認しなければなりません。別の配列と同じデータ型のゼロの配列を作成するには、zeros'like' オプションを使用します。たとえば、配列 X と同じデータ型でサイズが sz のゼロの配列を初期化するには、Z = zeros(sz,'like',X) を使用します。

        function Z = predict(layer, varargin)
            % Z = predict(layer, X1, ..., Xn) forwards the input data X1,
            % ..., Xn through the layer and outputs the result Z.
            
            X = varargin;
            W = layer.Weights;
            
            % Initialize output
            X1 = X{1};
            sz = size(X1);
            Z = zeros(sz,'like',X1);
            
            % Weighted addition
            for i = 1:layer.NumInputs
                Z = Z + W(i)*X{i};
            end
        end

逆方向関数の作成

入力データおよび学習可能なパラメーターについて、損失の微分を関数 backward に実装します。

backward の構文は、以下のとおりです。

[dLdX1,…,dLdXn,dLdW1,…,dLdWk] = backward(layer,X1,…,Xn,Z1,…,Zm,dLdZ1,…,dLdZm,memory)
ここで、X1,…,Xnn 個の層入力、Z1,…,Zmforwardm 個の出力、dLdZ1,…,dLdZm は次の層から逆伝播された勾配、memoryforward のメモリ出力です。出力において、dLdX1,…,dLdXn は層入力についての損失の微分で、dLdW1,…,dLdWkk 個の学習可能なパラメーターについての損失の微分です。順方向パスと逆方向パスの間に使用されない変数が保存されることを防いでメモリ使用量を削減するには、対応する入力引数を ~ に置き換えます。

ヒント

backward への入力の数が変化する可能性がある場合、layer の後に入力引数ではなく varargin を使用します。この場合、varargin は入力の cell 配列です。ここで、i=1,…,NumInputs について varargin{i}Xi に対応し、j=1,…,NumOutputs について varargin{NumInputs+j} および varargin{NumInputs+NumOutputs+j} はそれぞれ Zj および dLdZj に対応し、varargin{end}memory に対応します。

出力の数が変化する可能性がある場合、出力引数ではなく varargout を使用します。この場合、varargout は出力の cell 配列です。ここで、i=1,…,NumInputs について varargout{i}dLdXit=1,…,k について varargout{NumInputs+t}dLdWt に対応します。k は学習可能なパラメーターの数です。

重み付き加算層の出力および学習可能なパラメーターはそれぞれ 1 つで入力は可変数であるため、重み付き加算層の backward の構文は varargout = backward(layer, varargin) になります。この場合、NumInputs 以下の正の整数 i について varargin{i}Xi に対応し、varargin{NumInputs+1}Z に対応し、varargin{NumInputs+2}dLdZ に対応します。出力において、NumIntputs 以下の正の整数 i について varargout{i}dLdXi に対応し、varargout{NumInputs+1}dLdW に対応します。

X1,...,XnZ の次元は順方向関数の場合と同じです。dLdZ の次元は Z の次元と同じです。dLdX1,...,dLdXn の次元およびデータ型は X1,...,Xn の次元およびデータ型と同じです。dLdW の次元およびデータ型は、学習可能なパラメーター W の次元およびデータ型と同じです。

逆方向パスの間に、層は対応する微分を使用して学習可能なパラメーターを自動的に更新します。

ネットワークにカスタム層を含めるには、層の順方向関数は、前の層の出力を受け取り、次の層で想定されるサイズの配列を順伝播しなければなりません。同様に、backward は、順方向関数の対応する出力と同じサイズの入力を受け取り、同じサイズの微分を逆伝播しなければなりません。

重み付き加算層の場合、各入力についての損失の微分は次のとおりです。

LXk(i)=jLZjZjXk(i),

ここで、k は各 X(i) に線形に付けたインデックスであり、Z=f(X(1),,X(n)), L/Z は次の層から伝播された勾配、j は Z に線形に付けたインデックスです。活性化の微分は次のとおりです。

ZX(i)=Wi.

それぞれの学習可能なパラメーター Wi についての損失の微分は次のとおりです。

LWi=jLZjZjWi,

ここで、j は Z の要素に線形に付けたインデックスです。活性化の勾配は次のとおりです。

ZWi=X(i).

逆方向関数を backward に実装し、関数の構文を説明するコメントを関数の上部に追加します。

        function varargout = backward(layer, varargin)
            % [dLdX1,…,dLdXn,dLdW] = backward(layer,X1,…,Xn,Z,dLdZ,~)
            % backward propagates the derivative of the loss function
            % through the layer.
            
            numInputs = layer.NumInputs;
            W = layer.Weights;
            X = varargin(1:numInputs);
            dLdZ = varargin{numInputs+2};
            
            % Calculate derivatives
            dLdX = cell(1,numInputs);
            dLdW = zeros(1,numInputs,'like',W);
            for i = 1:numInputs                
                dLdX{i} = dLdZ * W(i);
                dLdW(i) = sum(dLdZ .* X{i},'all');
            end
            
            % Pack output arguments.
            varargout(1:numInputs) = dLdX;
            varargout{numInputs+1} = dLdW;
        end

完成した層

完成した層のクラス ファイルを表示します。

classdef weightedAdditionLayer < nnet.layer.Layer
    % Example custom weighted addition layer.

    properties (Learnable)
        % Layer learnable parameters
            
        % Scaling coefficients
        Weights
    end
    
    methods
        function layer = weightedAdditionLayer(numInputs,name) 
            % layer = weightedAdditionLayer(numInputs,name) creates a
            % weighted addition layer and specifies the number of inputs
            % and the layer name.

            % Set number of inputs.
            layer.NumInputs = numInputs;

            % Set layer name.
            layer.Name = name;

            % Set layer description.
            layer.Description = "Weighted addition of " + numInputs +  ... 
                " inputs";
        
            % Initialize layer weights.
            layer.Weights = rand(1,numInputs); 
        end
        
        function Z = predict(layer, varargin)
            % Z = predict(layer, X1, ..., Xn) forwards the input data X1,
            % ..., Xn through the layer and outputs the result Z.
            
            X = varargin;
            W = layer.Weights;
            
            % Initialize output
            X1 = X{1};
            sz = size(X1);
            Z = zeros(sz,'like',X1);
            
            % Weighted addition
            for i = 1:layer.NumInputs
                Z = Z + W(i)*X{i};
            end
        end
        
        function varargout = backward(layer, varargin)
            % [dLdX1,…,dLdXn,dLdW] = backward(layer,X1,…,Xn,Z,dLdZ,~)
            % backward propagates the derivative of the loss function
            % through the layer.
            
            numInputs = layer.NumInputs;
            W = layer.Weights;
            X = varargin(1:numInputs);
            dLdZ = varargin{numInputs+2};
            
            % Calculate derivatives
            dLdX = cell(1,numInputs);
            dLdW = zeros(1,numInputs,'like',W);
            for i = 1:numInputs                
                dLdX{i} = dLdZ * W(i);
                dLdW(i) = sum(dLdZ .* X{i},'all');
            end
            
            % Pack output arguments.
            varargout(1:numInputs) = dLdX;
            varargout{numInputs+1} = dLdW;
        end
    end
end

複数の入力がある層の有効性のチェック

カスタム層 weightedAdditionLayer について層の有効性をチェックします。

カスタム重み付き加算層を定義します。この層を作成するには、ファイル weightedAdditionLayer.m を現在のフォルダーに保存します。

層のインスタンスを作成し、checkLayer を使用してその有効性をチェックします。層への各入力における 1 つの観測値の典型的なサイズになるように有効な入力サイズを指定します。層には 4 次元配列を入力する必要があり、最初の 3 つの次元は前の層の出力における高さ、幅、およびチャネル数に対応し、4 番目の次元は観測値に対応します。

観測値の入力の典型的なサイズを指定し、'ObservationDimension' を 4 に設定します。

layer = weightedAdditionLayer(2,'add');
validInputSize = {[24 24 20],[24 24 20]};
checkLayer(layer,validInputSize,'ObservationDimension',4)
Skipping GPU tests. No compatible GPU device found.
 
Running nnet.checklayer.TestCase
.......... ........
Done nnet.checklayer.TestCase
__________

Test Summary:
	 18 Passed, 0 Failed, 0 Incomplete, 6 Skipped.
	 Time elapsed: 258.5616 seconds.

ここでは、関数で層に関する問題はまったく検出されていません。

ネットワークでのカスタム重み付き加算層の使用

Deep Learning Toolbox では、カスタム層を他の層と同じように使用できます。この節では、前に作成した重み付き加算層を使用した数字分類用ネットワークを作成し、学習させる方法を説明します。

例の学習データを読み込みます。

[XTrain,YTrain] = digitTrain4DArrayData;

カスタム重み付き加算層を定義します。この層を作成するには、ファイル weightedAdditionLayer.m を現在のフォルダーに保存します。

カスタム層 weightedAdditionLayer を含む層グラフを作成します。

layers = [
    imageInputLayer([28 28 1],'Name','in')
    convolution2dLayer(5,20,'Name','conv1')
    reluLayer('Name','relu1')
    convolution2dLayer(3,20,'Padding',1,'Name','conv2')
    reluLayer('Name','relu2')
    convolution2dLayer(3,20,'Padding',1,'Name','conv3')
    reluLayer('Name','relu3')
    weightedAdditionLayer(2,'add')
    fullyConnectedLayer(10,'Name','fc')
    softmaxLayer('Name','softmax')
    classificationLayer('Name','classoutput')];

lgraph = layerGraph(layers);
lgraph = connectLayers(lgraph, 'relu1', 'add/in2');

学習オプションを設定し、ネットワークに学習させます。

options = trainingOptions('adam','MaxEpochs',10);
net = trainNetwork(XTrain,YTrain,lgraph,options);
Training on single CPU.
Initializing input data normalization.
|========================================================================================|
|  Epoch  |  Iteration  |  Time Elapsed  |  Mini-batch  |  Mini-batch  |  Base Learning  |
|         |             |   (hh:mm:ss)   |   Accuracy   |     Loss     |      Rate       |
|========================================================================================|
|       1 |           1 |       00:00:00 |        7.81% |       2.3117 |          0.0010 |
|       2 |          50 |       00:00:19 |       78.91% |       0.6958 |          0.0010 |
|       3 |         100 |       00:00:36 |       91.41% |       0.2488 |          0.0010 |
|       4 |         150 |       00:00:57 |       96.09% |       0.0999 |          0.0010 |
|       6 |         200 |       00:01:15 |       99.22% |       0.0305 |          0.0010 |
|       7 |         250 |       00:01:32 |       98.44% |       0.0585 |          0.0010 |
|       8 |         300 |       00:01:48 |      100.00% |       0.0218 |          0.0010 |
|       9 |         350 |       00:02:08 |       99.22% |       0.0161 |          0.0010 |
|      10 |         390 |       00:02:23 |      100.00% |       0.0090 |          0.0010 |
|========================================================================================|

重み付き加算層によって学習された重みを表示します。

net.Layers(8).Weights
ans = 1x2 single row vector

    1.0095    0.9917

新しいデータについて予測を行い、精度を計算することによって、ネットワーク性能を評価します。

[XTest,YTest] = digitTest4DArrayData;
YPred = classify(net,XTest);
accuracy = sum(YTest==YPred)/numel(YTest)
accuracy = 0.9882

参考

| |

関連するトピック