Main Content

カスタム層の逆方向関数の指定

目的のタスクに必要な層が Deep Learning Toolbox™ に用意されていない場合、独自のカスタム層を定義できます。組み込み層の一覧については、深層学習層の一覧を参照してください。

学習可能なパラメーターを含むカスタム深層学習層の定義の例は、カスタム SReLU 層を作成する方法を示しており、次の手順を実行します。

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

  2. 層のプロパティの宣言 — 層のプロパティ (学習可能なパラメーターや状態パラメーターなど) を指定します。

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

  4. 初期化関数の作成 (オプション) — ネットワークの初期化時に学習可能なパラメーターと状態パラメーターを初期化する方法を指定します。初期化関数を指定しない場合、ネットワークの初期化時にパラメーターは初期化されません。

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

  6. リセット ステート関数の作成 (オプション) — 状態パラメーターをリセットする方法を指定します。

  7. 逆方向関数の作成 (オプション) — 入力データおよび学習可能なパラメーターにおける損失の微分を指定します (逆伝播)。逆方向関数を指定しない場合、順方向関数は dlarray オブジェクトをサポートしなければなりません。

順方向関数が dlarray オブジェクトをサポートする関数のみを使用する場合、逆方向関数の作成はオプションです。この場合、ソフトウェアは自動微分を使用して微分を自動的に求めます。dlarray オブジェクトをサポートしている関数の一覧については、dlarray をサポートする関数の一覧を参照してください。dlarray オブジェクトをサポートしない関数を使用する場合、または逆方向関数に特定のアルゴリズムを使用する場合、この例を参考にしてカスタム逆方向関数を定義できます。

カスタム層の作成

学習可能なパラメーターを含むカスタム深層学習層の定義の例では、SReLU 層の作成方法を示します。SReLU 層は、しきい値処理演算を実行します。ここで、層は各チャネルについて、区間外の値をスケーリングします。区間しきい値とスケーリング係数は学習可能なパラメーターです。[1]

SReLU 演算は次で与えられます。

f(xi)={til+ail(xitil)if xitilxiif til<xi<tirtir+air(xitir)if tirxi

ここで、xi はチャネル i の入力、tli と tri はそれぞれチャネル i の左と右のしきい値、ali と ari はそれぞれチャネル i の左と右のスケーリング係数です。これらのしきい値とスケーリング係数は学習可能なパラメーターとなり、学習時にその層によって学習されます。

学習可能なパラメーターを含むカスタム深層学習層の定義の例で作成された層を表示します。この層には関数 backward がありません。

classdef sreluLayer < nnet.layer.Layer ...
        & nnet.layer.Acceleratable
    % Example custom SReLU layer.

    properties (Learnable)
    % Layer learnable parameters
    
        LeftSlope
        RightSlope
        LeftThreshold
        RightThreshold
    end

    methods
        function layer = sreluLayer(args) 
            % layer = sreluLayer creates a SReLU layer.
            %
            % layer = sreluLayer(Name=name) also specifies the
            % layer name.
    
            arguments
                args.Name = "";
            end
    
            % Set layer name.
            layer.Name = args.Name;

            % Set layer description.
            layer.Description = "SReLU";
        end

        function layer = initialize(layer,layout)
            % layer = initialize(layer,layout) initializes the layer
            % learnable parameters using the specified input layout.

            % Find number of channels.
            idx = finddim(layout,"C");
            numChannels = layout.Size(idx);

            % Initialize empty learnable parameters.
            sz = ones(1,numel(layout.Size);
            sz(idx) = numChannels;
            
            if isempty(layer.LeftSlope)
                layer.LeftSlope = rand(sz);
            end
            
            if isempty(layer.RightSlope)
                layer.RightSlope = rand(sz);
            end
            
            if isempty(layer.LeftThreshold)
                layer.LeftThreshold = rand(sz);
            end
            
            if isempty(layer.RightThreshold)
                layer.RightThreshold = rand(sz);
            end
        end

        function Y = predict(layer, X)
            % Y = predict(layer, X) forwards the input data X through the
            % layer and outputs the result Y.
            
            tl = layer.LeftThreshold;
            al = layer.LeftSlope;
            tr = layer.RightThreshold;
            ar = layer.RightSlope;
            
            Y = (X <= tl) .* (tl + al.*(X-tl)) ...
                + ((tl < X) & (X < tr)) .* X ...
                + (tr <= X) .* (tr + ar.*(X-tr));
        end
    end
end

逆方向関数の作成

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

関数 backward の構文は、層のタイプによって異なります。

  • dLdX = backward(layer,X,Y,dLdY,memory) は、層入力についての損失の微分 dLdX を返します。この場合、layer は 1 つの入力と 1 つの出力をもちます。Y は順方向関数の出力に対応し、dLdYY についての損失の微分に対応します。関数の入力 memory は、順方向関数のメモリ出力に対応します。

  • [dLdX,dLdW] = backward(layer,X,Y,dLdY,memory) は、学習可能なパラメーターについての損失の微分 dLdW も返します。この場合、layer は 1 つの学習可能なパラメーターをもちます。

  • [dLdX,dLdSin] = backward(layer,X,Y,dLdY,dLdSout,memory) は、状態入力についての損失の微分 dLdSin も返します。この場合、layer は 1 つの状態パラメーターをもちます。dLdSout は層の状態出力についての損失の微分に対応します。

  • [dLdX,dLdW,dLdSin] = backward(layer,X,Y,dLdY,dLdSout,memory) は、学習可能なパラメーターについての損失の微分 dLdW、および層の状態入力についての損失の微分 dLdSin も返します。この場合、layer は 1 つの状態パラメーターと 1 つの学習可能なパラメーターをもちます。

複数の入力、複数の出力、複数の学習可能なパラメーター、または複数の状態パラメーターを使用して、層の構文を調整できます。

  • 複数の入力をもつ層の場合、XdLdX をそれぞれ X1,...,XNdLdX1,...,dLdXN に置き換えます。ここで、N は入力の数です。

  • 複数の出力をもつ層の場合、YdLdY をそれぞれ Y1,...,YMdLdY1,...,dLdYM に置き換えます。ここで、M は出力の数です。

  • 複数の学習可能なパラメーターをもつ層の場合、dLdWdLdW1,...,dLdWP に置き換えます。ここで、P は学習可能なパラメーターの数です。

  • 複数の状態パラメーターをもつ層の場合、dLdSindLdSout をそれぞれ dLdSin1,...,dLdSinKdLdSout1,...,dLdSoutK に置き換えます。ここで、K は状態パラメーターの数です。

フォワード パスとバックワード パスの間に使用されない変数が保存されることを防いでメモリ使用量を削減するには、対応する入力引数を ~ に置き換えます。

ヒント

backward への入力の数が変化する可能性がある場合、layer の後に入力引数ではなく varargin を使用します。この場合、varargin は入力の cell 配列になります。ここで、最初の N 個の要素は N 個の層入力に対応し、その次の M 個の要素は M 個の層出力に対応し、その次の M 個の要素は M 個の層出力についての損失の微分に対応し、その次の K 個の要素は K 個の状態出力についての損失に関する K 個の微分に対応し、最後の要素は memory に対応します。

出力の数が変化する可能性がある場合、出力引数ではなく varargout を使用します。この場合、varargout は出力の cell 配列になります。ここで、最初の N 個の要素は N 個の層入力についての損失に関する N 個の微分に対応し、その次の P 個の要素は P 個の学習可能なパラメーターについての損失の微分に対応し、その次の K 個の要素は K 個の状態入力についての損失の微分に対応します。

SReLU 層には 1 つの入力、1 つの出力、および 4 つの学習可能なパラメーターしかなく、層の順方向関数やメモリ値の出力を必要としないため、SReLU 層の backward の構文は [dLdX,dLdLS,dLdRS,dldLT,dldRT] = backward(layer,X,~,dLdY,~) になります。X の次元は、順方向関数の場合と同じです。dLdY の次元は、順方向関数の出力 Y の次元と同じです。dLdX の次元およびデータ型は、X の次元およびデータ型と同じです。dLdLSdLdRSdldLTdldRT の次元およびデータ型は、それぞれ学習可能なパラメーター LeftSlopeRightSlopeLeftThresholdRightThreshold の次元およびデータ型と同じです。

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

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

入力データについての損失の微分は次のとおりです。

Lxi=Lf(xi)f(xi)xi

ここで、L/f(xi) は次の層から伝播された勾配であり、活性化の微分は次のとおりです。

f(xi)xi={ailif xitil1if til<xi<tirairif tirxi.

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

Ltil=jLf(xij)f(xij)tjl

ここで、i はチャネルのインデックス、j は残りの要素のインデックスです。また、活性化の勾配は次のとおりです。

f(xi)til={1ailif xitil0if til<xi<tir0if tirxi.

同様に、他の学習可能なパラメーターについての勾配は次のようになります。

f(xi)tir={0if xitil0if til<xi<tir1airif tirxif(xi)ail={xitilif xitil0if til<xi<tir0if tirxif(xi)air={0if xitil0if til<xi<tirxitirif tirxi

これらの微分を返す逆方向関数を作成します。

        function [dLdX,dLdLS,dLdRS,dLdLT,dLdRT] = backward(layer,X,~,dLdY,~)
            % [dLdX,dLdLS,dLdRS,dLdLT,dLdRT] = backward(layer,X,~,dLdY,~)
            % backward propagates the derivative of the loss function
            % through the layer.
            % Inputs:
            %         layer - Layer to backward propagate through
            %         X     - Input data
            %         dLdY  - Gradient propagated from the deeper layer
            % Outputs:
            %         dLdX  - Derivative of the loss with respect to the
            %                 input data
            %         dLdLS - Derivative of the loss with respect to the
            %                 learnable parameter LeftScale
            %         dLdRS - Derivative of the loss with respect to the
            %                 learnable parameter RightScale
            %         dLdLT - Derivative of the loss with respect to the
            %                 learnable parameter LeftThreshold
            %         dLdRT - Derivative of the loss with respect to the
            %                 learnable parameter RightThreshold

            ndims = numel(dims(X));
            idxC = finddim(X,"C");

            X = stripdims(X);
            dLdY = stripdims(dLdY);

            tl = layer.LeftThreshold;
            al = layer.LeftSlope;
            tr = layer.RightThreshold;
            ar = layer.RightSlope;

            dYdX = (X <= tl) .* al ...
                + (X > tl  & X < tr) ...
                + (X >= tr) .* ar;
            
            idx = setdiff(1:ndims,idxC);
            dLdLT = sum(dLdY .* (X <= tl) .* (1 - al),idx);
            dLdRT = sum(dLdY .* (tr <= X) .* (1 - ar),idx);
            dLdLS = sum(dLdY .* (X <= tl) .* (X - tl),idx);
            dLdRS = sum(dLdY .* (tr <= X) .* (X - tr),idx);
        end

層の完成

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

classdef sreluLayer < nnet.layer.Layer
    % Example custom SReLU layer.

    properties (Learnable)
    % Layer learnable parameters
    
        LeftSlope
        RightSlope
        LeftThreshold
        RightThreshold
    end
    
    methods
        function layer = sreluLayer(args) 
            % layer = sreluLayer creates a SReLU layer.
            %
            % layer = sreluLayer(Name=name) also specifies the
            % layer name.
    
            arguments
                args.Name = "";
            end
    
            % Set layer name.
            layer.Name = args.Name;

            % Set layer description.
            layer.Description = "SReLU";
        end

        function layer = initialize(layer,layout)
            % layer = initialize(layer,layout) initializes the layer
            % learnable parameters using the specified input layout.

            % Find number of channels.
            idx = finddim(layout,"C");
            numChannels = layout.Size(idx);

            % Initialize empty learnable parameters.
            sz = ones(1,numel(layout.Size);
            sz(idx) = numChannels;
            
            if isempty(layer.LeftSlope)
                layer.LeftSlope = rand(sz);
            end
            
            if isempty(layer.RightSlope)
                layer.RightSlope = rand(sz);
            end
            
            if isempty(layer.LeftThreshold)
                layer.LeftThreshold = rand(sz);
            end
            
            if isempty(layer.RightThreshold)
                layer.RightThreshold = rand(sz);
            end
        end

        function Y = predict(layer, X)
            % Y = predict(layer, X) forwards the input data X through the
            % layer and outputs the result Y.
            
            tl = layer.LeftThreshold;
            al = layer.LeftSlope;
            tr = layer.RightThreshold;
            ar = layer.RightSlope;
            
            Y = (X <= tl) .* (tl + al.*(X-tl)) ...
                + ((tl < X) & (X < tr)) .* X ...
                + (tr <= X) .* (tr + ar.*(X-tr));
        end
        
        function [dLdX,dLdLS,dLdRS,dLdLT,dLdRT] = backward(layer,X,~,dLdY,~)
            % [dLdX,dLdLS,dLdRS,dLdLT,dLdRT] = backward(layer,X,~,dLdY,~)
            % backward propagates the derivative of the loss function
            % through the layer.
            % Inputs:
            %         layer - Layer to backward propagate through
            %         X     - Input data
            %         dLdY  - Gradient propagated from the deeper layer
            % Outputs:
            %         dLdX  - Derivative of the loss with respect to the
            %                 input data
            %         dLdLS - Derivative of the loss with respect to the
            %                 learnable parameter LeftScale
            %         dLdRS - Derivative of the loss with respect to the
            %                 learnable parameter RightScale
            %         dLdLT - Derivative of the loss with respect to the
            %                 learnable parameter LeftThreshold
            %         dLdRT - Derivative of the loss with respect to the
            %                 learnable parameter RightThreshold

            ndims = numel(dims(X));
            idxC = finddim(X,"C");

            X = stripdims(X);
            dLdY = stripdims(dLdY);

            tl = layer.LeftThreshold;
            al = layer.LeftSlope;
            tr = layer.RightThreshold;
            ar = layer.RightSlope;

            dYdX = (X <= tl) .* al ...
                + (X > tl  & X < tr) ...
                + (X >= tr) .* ar;
            
            idx = setdiff(1:ndims,idxC);
            dLdLT = sum(dLdY .* (X <= tl) .* (1 - al),idx);
            dLdRT = sum(dLdY .* (tr <= X) .* (1 - ar),idx);
            dLdLS = sum(dLdY .* (X <= tl) .* (X - tl),idx);
            dLdRS = sum(dLdY .* (tr <= X) .* (X - tr),idx);
        end
    end
end

GPU 互換性

層の順方向関数が dlarray オブジェクトを完全にサポートしている場合、層は GPU 互換です。そうでない場合、GPU 互換にするには、層関数が入力をサポートし、gpuArray (Parallel Computing Toolbox) 型の出力を返さなければなりません。

多くの MATLAB 組み込み関数が入力引数 gpuArray (Parallel Computing Toolbox) および dlarray をサポートしています。dlarray オブジェクトをサポートしている関数の一覧については、dlarray をサポートする関数の一覧を参照してください。GPU で実行される関数の一覧については、GPU での MATLAB 関数の実行 (Parallel Computing Toolbox)を参照してください。深層学習に GPU を使用するには、サポートされている GPU デバイスもなければなりません。サポートされているデバイスについては、GPU 計算の要件 (Parallel Computing Toolbox)を参照してください。MATLAB での GPU の使用の詳細は、MATLAB での GPU 計算 (Parallel Computing Toolbox)を参照してください。

参照

[1] Hu, Xiaobin, Peifeng Niu, Jianmei Wang, and Xinxin Zhang. “A Dynamic Rectified Linear Activation Units.” IEEE Access 7 (2019): 180409–16. https://doi.org/10.1109/ACCESS.2019.2959036.

参考

| | | | | | | | | | | |

関連するトピック