このページの翻訳は最新ではありません。ここをクリックして、英語の最新版を参照してください。
コード生成用のカスタム深層学習層の定義
目的の分類または回帰問題に必要な層が Deep Learning Toolbox™ に用意されていない場合、この例を指針として使用して独自のカスタム層を定義できます。組み込まれている層の一覧については、深層学習層の一覧を参照してください。
カスタム深層学習層を定義するために、この例で提供するテンプレートを使用できます。この例では、次のステップで説明を進めます。
層の命名 – MATLAB® で使用できるように層に名前を付けます。
層のプロパティの宣言 – 層のプロパティと、学習中にどのパラメーターが学習されるかを指定します。
コンストラクター関数の作成 (オプション) – 層の構築とそのプロパティ初期化の方法を指定します。コンストラクター関数を指定しない場合、作成時に
Name
、Description
、およびType
の各プロパティは[]
で初期化され、層の入力および出力の数は 1 に設定されます。順方向関数の作成 – 予測時および学習時に層経由でデータを順方向にパス (順伝播) する方法を指定します。
逆方向関数の作成 (オプション) – 入力データおよび学習可能なパラメーターにおける損失の微分を指定します (逆伝播)。逆方向関数を指定しない場合、順方向関数は
dlarray
オブジェクトをサポートしなければなりません。
コード生成をサポートするカスタム層を作成するには、次のことが必要です。
層は層の定義でプラグマ
%#codegen
を指定しなければなりません。predict
の入力は次のようになっていなければなりません。次元が一致している。各入力の次元の数が同じでなければなりません。
バッチ サイズが一致している。各入力のバッチ サイズが同じでなければなりません。
predict
の出力の次元とバッチ サイズが層の入力と一致していなければなりません。非スカラーのプロパティは、single 配列、double 配列、または文字配列でなければなりません。
スカラーのプロパティは、数値型、logical 型、または string 型でなければなりません。
コード生成では、2 次元イメージ入力または特徴入力のみで中間層がサポートされます。コード生成は、状態プロパティ (属性が State
であるプロパティ) をもつ層をサポートしません。
この例では、学習可能なパラメーターを含む層である PReLU 層[1]を作成し、畳み込みニューラル ネットワークで使用する方法を説明します。PReLU 層はしきい値処理を実行します。各チャネルについて、入力値がゼロよりも小さい場合は、学習時に得られたスカラーによって乗算されます。0 より小さい値の場合、PReLU 層は入力の各チャネルにスケーリング係数 を適用します。これらの係数は学習可能なパラメーターとなり、学習時にその層によって学習されます。
[1] から抜粋した次の図は、ReLU 層の関数と PReLU 層の関数を比較したものです。
学習可能なパラメーターを含む層のテンプレート
学習可能なパラメーターを含む層のテンプレートを MATLAB の新しいファイルにコピーします。このテンプレートは、学習可能なパラメーターを含む層の構造の概要を示しており、層の動作を定義する関数を含んでいます。
classdef myLayer < nnet.layer.Layer % & nnet.layer.Formattable (Optional) 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 custom backward propagation % Layer forward function for training goes here. end function [dLdX1, …, dLdXn, dLdW1, …, dLdWk] = ... backward(layer, X1, …, Xn, Z1, …, Zm, dLdZ1, …, dLdZm, memory) % (Optional) 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
層の命名
まず、層に名前を付けます。クラス ファイルの最初の行で、既存の名前 myLayer
を codegenPreluLayer
に置き換え、層を説明するコメントを追加します。
classdef codegenPreluLayer < nnet.layer.Layer % Example custom PReLU layer with codegen support. ... end
次に、コンストラクター関数 myLayer
(methods
セクションの最初の関数) の名前を層と同じ名前に変更します。
methods function layer = codegenPreluLayer() ... end ... end
層の保存
層のクラス ファイルを codegenPreluLayer.m
という名前の新しいファイルに保存します。このファイル名は層の名前に一致しなければなりません。この層を使用するには、このファイルを現在のフォルダーまたは MATLAB パス上のフォルダーに保存しなければなりません。
コード生成プラグマの指定
この層のコードを生成することを示すため、層の定義に %#codegen
命令 (プラグマ) を追加します。この命令は、MATLAB コード アナライザーに対し、コード生成時のエラーの原因となる違反を診断して修正するのに役立つ情報を提供するよう指示します。
classdef codegenPreluLayer < nnet.layer.Layer % Example custom PReLU layer with codegen support. %#codegen ... end
プロパティおよび学習可能なパラメーターの宣言
層のプロパティを properties
セクションで宣言し、学習可能なパラメーターを properties (Learnable)
セクションにリストすることによって宣言します。
既定では、カスタム中間層に次のプロパティがあります。
Property | 説明 |
---|---|
Name | 層の名前。文字ベクトルまたは string スカラーとして指定します。Layer 配列入力の場合、関数 trainNetwork 、assembleNetwork 、layerGraph 、および dlnetwork では、Name に '' が設定され、層の名前が自動的に割り当てられます。 |
Description | 層についての 1 行の説明。string スカラーまたは文字ベクトルとして指定します。この説明は、層が 層の説明を指定しない場合、層のクラス名が表示されます。 |
Type | 層のタイプ。文字ベクトルまたは string スカラーとして指定します。 層のタイプを指定しない場合、層のクラス名が表示されます。 |
NumInputs | 層の入力の数。正の整数として指定します。この値を指定しない場合、NumInputs は InputNames の名前の数に自動的に設定されます。既定値は 1 です。 |
InputNames | 層の入力の名前。文字ベクトルの cell 配列として指定します。この値を指定せず、NumInputs が 1 より大きい場合、InputNames は {'in1',...,'inN'} に自動的に設定されます。ここで、N = NumInputs です。既定値は {'in'} です。 |
NumOutputs | 層の出力の数。正の整数として指定します。この値を指定しない場合、NumOutputs は OutputNames の名前の数に自動的に設定されます。既定値は 1 です。 |
OutputNames | 層の出力の名前。文字ベクトルの cell 配列として指定します。この値を指定せず、NumOutputs が 1 より大きい場合、OutputNames は {'out1',...,'outM'} に自動的に設定されます。ここで、M = NumOutputs です。既定値は {'out'} です。 |
層にその他のプロパティがない場合は、properties
セクションを省略できます。
ヒント
複数の入力がある層を作成する場合、層のコンストラクターで NumInputs
と InputNames
のいずれかのプロパティを設定しなければなりません。複数の出力がある層を作成している場合、層のコンストラクターで NumOutputs
と OutputNames
のいずれかのプロパティを設定しなければなりません。例については、複数の入力があるカスタム深層学習層の定義を参照してください。
コード生成をサポートするには、次のことが必要です。
非スカラーのプロパティは、single 配列、double 配列、または文字配列でなければなりません。
スカラーのプロパティは、数値型、logical 型、または string 型でなければなりません。
PReLU 層には追加のプロパティが必要ないため、properties
セクションは削除できます。
PReLU 層には、唯一の学習可能なパラメーターとしてスケーリング係数 a があります。この学習可能なパラメーターを properties (Learnable)
セクションで宣言し、パラメーター Alpha
を呼び出します。
properties (Learnable)
% Layer learnable parameters
% Scaling coefficient
Alpha
end
コンストラクター関数の作成
層を構築する関数を作成し、層のプロパティを初期化します。層を作成するために必要な変数をコンストラクター関数への入力として指定します。
PReLU 層のコンストラクター関数に必要な 2 つの入力引数は、想定される入力データのチャネル数と層の名前です。チャネルの数は学習可能なパラメーター Alpha
のサイズを指定します。numChannels
および name
という名前の 2 つの入力引数を関数 codegenPreluLayer
に指定します。関数の構文を説明するコメントを関数の上部に追加します。
function layer = codegenPreluLayer(numChannels, name) % layer = codegenPreluLayer(numChannels) creates a PReLU layer with % numChannels channels and specifies the layer name. ... end
コード生成では arguments
ブロックがサポートされていません。
層のプロパティの初期化
コンストラクター関数に学習可能なパラメーターを含め、層のプロパティを初期化します。コメント % Layer constructor function goes here
を、層のプロパティを初期化するコードに置き換えます。
Name
プロパティを入力引数 name
に設定します。
% Set layer name.
layer.Name = name;
層の Description
プロパティを設定して、層に 1 行の説明を指定します。層のタイプとサイズの説明を設定します。
% Set layer description. layer.Description = "PReLU with " + numChannels + " channels";
PReLU 層の場合、入力値が負であれば、層は入力の各チャネルに Alpha
の対応するチャネルを乗算します。学習可能なパラメーター Alpha
をサイズ 1 x 1 x numChannels
のランダム ベクトルとして初期化します。3 つ目の次元をサイズ numChannels
に指定することで、層は順方向関数で入力の要素単位の乗算を使用できます。Alpha
は層オブジェクトのプロパティであるため、ベクトルを layer.Alpha
に割り当てなければなりません。
% Initialize scaling coefficient.
layer.Alpha = rand([1 1 numChannels]);
完成したコンストラクター関数を表示します。
function layer = codegenPreluLayer(numChannels, name)
% layer = codegenPreluLayer(numChannels, name) creates a PReLU
% layer for 2-D image input with numChannels channels and specifies
% the layer name.
% Set layer name.
layer.Name = name;
% Set layer description.
layer.Description = "PReLU with " + numChannels + " channels";
% Initialize scaling coefficient.
layer.Alpha = rand([1 1 numChannels]);
end
このコンストラクター関数を使用すると、コマンド codegenPreluLayer(3,'prelu')
により 3 つのチャネルを持ち、名前が 'prelu'
の PReLU 層が作成されます。
順方向関数の作成
予測時と学習時に使用する層の順方向関数を作成します。
"予測時" に層経由でデータを順伝播させて結果を出力する、predict
という名前の関数を作成します。
predict
の構文は [Z1,…,Zm] = predict(layer,X1,…,Xn)
です。ここで、X1,…,Xn
は n
個の層入力、Z1,…,Zm
は m
個の層出力です。値 n
および m
は、層の NumInputs
プロパティおよび NumOutputs
プロパティに対応しなければなりません。
ヒント
predict
への入力の数が変化する可能性がある場合、X1,…,Xn
ではなく varargin
を使用します。この場合、varargin
は入力の cell 配列です。ここで、varargin{i}
は Xi
に対応します。出力の数が変化する可能性がある場合、Z1,…,Zm
ではなく varargout
を使用します。この場合、varargout
は出力の cell 配列です。ここで、varargout{j}
は Zj
に対応します。
PReLU 層の入力および出力はそれぞれ 1 つのみであるため、PReLU 層の predict
の構文は Z = predict(layer,X)
になります。
コード生成では、2 次元イメージ入力のみでカスタム中間層がサポートされます。入力は、h x w x c x N の配列です。ここで、h、w、および c は、それぞれイメージの高さ、幅、およびチャネル数に対応します。N は観測値の数です。観測値の次元は 4 です。
コード生成のサポートでは、層入力すべての次元数およびバッチ サイズは同じでなければなりません。
既定では、層は学習時に predict
を順方向関数として使用します。学習時に別の順方向関数を使用する、またはカスタム逆方向関数に必要な値を保持するには、forward
という名前の関数も作成しなければなりません。ソフトウェアは関数 forward
のコードを生成しませんが、コード生成の互換性がなければなりません。
関数 forward
は "学習時" に層経由でデータを順伝播させ、メモリ値も出力します。
forward
の構文は [Z1,…,Zm,memory] = forward(layer,X1,…,Xn)
です。ここで、X1,…,Xn
は n
個の層入力、Z1,…,Zm
は m
個の層出力、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
に対応します。
PReLU 演算は次の式で表されます。
ここで、 はチャネル i の非線形活性化 f の入力、 は負の部分の勾配を制御する係数です。 の添字 i は、別のチャネルでは非線形活性化が変わる場合があることを示しています。
この演算を predict
に実装します。predict
では、入力 X
がこの方程式の x に対応します。出力 Z
は に対応します。
関数の構文を説明するコメントを関数の上部に追加します。
ヒント
zeros
のような関数を使用して配列を事前に割り当てる場合、これらの配列のデータ型が層関数の入力と一致していることを確認しなければなりません。別の配列と同じデータ型のゼロの配列を作成するには、zeros
の 'like'
オプションを使用します。たとえば、配列 X
と同じデータ型でサイズが sz
のゼロの配列を初期化するには、Z = zeros(sz,'like',X)
を使用します。
順方向関数が dlarray
入力を完全にサポートしている場合、関数 backward
の実装はオプションです。コード生成のサポートでは、関数 predict
が数値入力もサポートしなければなりません。
PReLU 演算の出力を計算する 1 つの方法は、次のコードを使用することです。
Z = max(X,0) + layer.Alpha .* min(0,X);
.*
演算を使用した暗黙的な拡張がサポートされないため、代わりに関数 bsxfun
を使用できます。Z = max(X,0) + bsxfun(@times, layer.Alpha, min(0,X));
bsxfun
では dlarray
入力がサポートされません。コード生成と dlarray
入力の両方をサポートする関数 predict
を実装するには、if
ステートメントと関数 isdlarray
を使用して、入力タイプに合う適切なコードを選択してください。 function Z = predict(layer, X)
% Z = predict(layer, X) forwards the input data X through the
% layer and outputs the result Z.
if isdlarray(X)
Z = max(X,0) + layer.Alpha .* min(0,X);
else
Z = max(X,0) + bsxfun(@times, layer.Alpha, min(0,X));
end
end
関数 predict
は dlarray
オブジェクトを完全にサポートするため、関数 backward
の定義はオプションです。dlarray
オブジェクトをサポートしている関数の一覧については、dlarray をサポートする関数の一覧を参照してください。
完成した層
完成した層のクラス ファイルを表示します。
classdef codegenPreluLayer < nnet.layer.Layer % Example custom PReLU layer with codegen support. %#codegen properties (Learnable) % Layer learnable parameters % Scaling coefficient Alpha end methods function layer = codegenPreluLayer(numChannels, name) % layer = codegenPreluLayer(numChannels, name) creates a PReLU % layer for 2-D image input with numChannels channels and specifies % the layer name. % Set layer name. layer.Name = name; % Set layer description. layer.Description = "PReLU with " + numChannels + " channels"; % Initialize scaling coefficient. layer.Alpha = rand([1 1 numChannels]); end function Z = predict(layer, X) % Z = predict(layer, X) forwards the input data X through the % layer and outputs the result Z. if isdlarray(X) Z = max(X,0) + layer.Alpha .* min(0,X); else Z = max(X,0) + bsxfun(@times, layer.Alpha, min(0,X)); end end end end
コード生成の互換性に関するカスタム層のチェック
カスタム層 codegenPreluLayer
について、コード生成の互換性をチェックします。
この例にサポート ファイルとして添付されているカスタム層 codegenPreluLayer
は、入力データに PReLU 演算を適用します。この層にアクセスするには、この例をライブ スクリプトとして開きます。
層のインスタンスを作成し、checkLayer
を使用してその有効性をチェックします。層への典型的な入力における 1 つの観測値のサイズとして、有効な入力サイズを指定します。層には 4 次元配列を入力する必要があり、最初の 3 つの次元は前の層の出力における高さ、幅、およびチャネル数に対応し、4 番目の次元は観測値に対応します。
観測値の入力の典型的なサイズを指定し、'ObservationDimension'
オプションを 4 に設定します。コード生成の互換性をチェックするには、CheckCodegenCompatibility
オプションを true
に設定します。関数 checkLayer
は、関数がコード生成と互換性があるかどうかをチェックしません。カスタム層定義がコード生成でサポートされているかどうかをチェックするには、まず "コード生成の準備状態" アプリを使用します。詳細については、コード生成の準備状態ツールを使ったコードのチェック (MATLAB Coder)を参照してください。
layer = codegenPreluLayer(20,"prelu");
validInputSize = [24 24 20];
checkLayer(layer,validInputSize,ObservationDimension=4,CheckCodegenCompatibility=true)
Skipping GPU tests. No compatible GPU device found. Running nnet.checklayer.TestLayerWithoutBackward .......... .......... ... Done nnet.checklayer.TestLayerWithoutBackward __________ Test Summary: 23 Passed, 0 Failed, 0 Incomplete, 5 Skipped. Time elapsed: 0.79448 seconds.
この関数によって層に関する問題は検出されていません。
参照
[1] "Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification." In 2015 IEEE International Conference on Computer Vision (ICCV), 1026–34. Santiago, Chile: IEEE, 2015. https://doi.org/10.1109/ICCV.2015.123.