カスタム層の逆方向関数の指定
目的のタスクに必要な層が Deep Learning Toolbox™ に用意されていない場合、独自のカスタム層を定義できます。組み込み層の一覧については、深層学習層の一覧を参照してください。
学習可能なパラメーターを含むカスタム深層学習層の定義の例は、カスタム SReLU 層を作成する方法を示しており、次の手順を実行します。
層の命名 — MATLAB® で使用できるように層に名前を付けます。
層のプロパティの宣言 — 層のプロパティ (学習可能なパラメーターや状態パラメーターなど) を指定します。
コンストラクター関数の作成 (オプション) — 層を構築してそのプロパティを初期化する方法を指定します。コンストラクター関数を指定しない場合、作成時に
Name
、Description
、およびType
の各プロパティは[]
で初期化され、層の入力および出力の数は1
に設定されます。初期化関数の作成 (オプション) — ネットワークの初期化時に学習可能なパラメーターと状態パラメーターを初期化する方法を指定します。初期化関数を指定しない場合、ネットワークの初期化時にパラメーターは初期化されません。
順方向関数の作成 — 予測時および学習時に層経由でデータを順方向にパス (順伝播) する方法を指定します。
リセット ステート関数の作成 (オプション) — 状態パラメーターをリセットする方法を指定します。
逆方向関数の作成 (オプション) — 入力データおよび学習可能なパラメーターにおける損失の微分を指定します (逆伝播)。逆方向関数を指定しない場合、順方向関数は
dlarray
オブジェクトをサポートしなければなりません。
順方向関数が dlarray
オブジェクトをサポートする関数のみを使用する場合、逆方向関数の作成はオプションです。この場合、ソフトウェアは自動微分を使用して微分を自動的に求めます。dlarray
オブジェクトをサポートしている関数の一覧については、dlarray をサポートする関数の一覧を参照してください。dlarray
オブジェクトをサポートしない関数を使用する場合、または逆方向関数に特定のアルゴリズムを使用する場合、この例を参考にしてカスタム逆方向関数を定義できます。
カスタム層の作成
学習可能なパラメーターを含むカスタム深層学習層の定義の例では、SReLU 層の作成方法を示します。SReLU 層は、しきい値処理演算を実行します。ここで、層は各チャネルについて、区間外の値をスケーリングします。区間しきい値とスケーリング係数は学習可能なパラメーターです。[1]
SReLU 演算は次で与えられます。
ここで、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
は順方向関数の出力に対応し、dLdY
はY
についての損失の微分に対応します。関数の入力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 つの学習可能なパラメーターをもちます。
複数の入力、複数の出力、複数の学習可能なパラメーター、または複数の状態パラメーターを使用して、層の構文を調整できます。
複数の入力をもつ層の場合、
X
とdLdX
をそれぞれX1,...,XN
とdLdX1,...,dLdXN
に置き換えます。ここで、N
は入力の数です。複数の出力をもつ層の場合、
Y
とdLdY
をそれぞれY1,...,YM
とdLdY1,...,dLdYM
に置き換えます。ここで、M
は出力の数です。複数の学習可能なパラメーターをもつ層の場合、
dLdW
をdLdW1,...,dLdWP
に置き換えます。ここで、P
は学習可能なパラメーターの数です。複数の状態パラメーターをもつ層の場合、
dLdSin
とdLdSout
をそれぞれdLdSin1,...,dLdSinK
とdLdSout1,...,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
の次元およびデータ型と同じです。dLdLS
、dLdRS
、dldLT
、dldRT
の次元およびデータ型は、それぞれ学習可能なパラメーター LeftSlope
、RightSlope
、LeftThreshold
、RightThreshold
の次元およびデータ型と同じです。
バックワード パスの間に、層は対応する微分を使用して、学習可能なパラメーターを自動的に更新します。
カスタム層をネットワークに含めるには、層の順方向関数が前の層の出力を受け入れ、次の層で期待されるサイズの配列を順伝播しなければなりません。同様に、層が関数 backward
を指定する場合、順方向関数の対応する出力と同じサイズの入力を受け入れ、同じサイズの微分を逆伝播しなければなりません。
入力データについての損失の微分は次のとおりです。
ここで、 は次の層から伝播された勾配であり、活性化の微分は次のとおりです。
学習可能なパラメーター tli についての損失の微分は次のとおりです。
ここで、i はチャネルのインデックス、j は残りの要素のインデックスです。また、活性化の勾配は次のとおりです。
同様に、他の学習可能なパラメーターについての勾配は次のようになります。
これらの微分を返す逆方向関数を作成します。
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.
参考
trainnet
| trainingOptions
| dlnetwork
| functionLayer
| checkLayer
| setLearnRateFactor
| setL2Factor
| getLearnRateFactor
| getL2Factor
| findPlaceholderLayers
| replaceLayer
| PlaceholderLayer
| networkDataLayout