Main Content

dlgradient

自動微分を使用したカスタム学習ループの勾配の計算

説明

dlgradient 関数は自動微分を使用して微分を計算します。

ヒント

ほとんどの深層学習タスクでは、事前学習済みのニューラル ネットワークを使用して独自のデータに適応させることができます。転移学習を使用して、畳み込みニューラル ネットワークの再学習を行い、新しい一連のイメージを分類する方法を示す例については、Retrain Neural Network to Classify New Imagesを参照してください。または、関数 trainnet と関数 trainingOptions を使用してニューラル ネットワークを作成し、これにゼロから学習させることができます。

タスクに必要な学習オプションが関数 trainingOptions に用意されていない場合、自動微分を使用してカスタム学習ループを作成できます。詳細については、カスタム学習ループを使用したネットワークの学習を参照してください。

タスクに必要な損失関数が関数 trainnet に用意されていない場合、カスタム損失関数を関数ハンドルとして trainnet に指定できます。損失関数が予測とターゲットよりも多くの入力を必要とする場合 (たとえば、損失関数がニューラル ネットワークまたは追加の入力にアクセスする必要がある場合)、カスタム学習ループを使用してモデルに学習させます。詳細については、カスタム学習ループを使用したネットワークの学習を参照してください。

タスクに必要な層が Deep Learning Toolbox™ に用意されていない場合、カスタム層を作成できます。詳細については、カスタム深層学習層の定義を参照してください。層のネットワークとして指定できないモデルの場合は、モデルを関数として定義できます。詳細については、モデル関数を使用したネットワークの学習を参照してください。

どのタスクでどの学習手法を使用するかについての詳細は、MATLAB による深層学習モデルの学習を参照してください。

[dydx1,...,dydxk] = dlgradient(y,x1,...,xk) は、変数 x1xk に対する y の勾配を返します。

dlfeval に渡された関数の内部から dlgradient を呼び出します。自動微分を使用した勾配の計算Deep Learning Toolbox での自動微分の使用を参照してください。

[dydx1,...,dydxk] = dlgradient(y,x1,...,xk,Name,Value) は、勾配を返し、1 つ以上の名前と値のペアを使用して追加のオプションを指定します。たとえば、dydx = dlgradient(y,x,'RetainData',true) は、後続の dlgradient の呼び出しで再利用できるように、勾配の中間値を保持します。この構文を使用すると時間を節約できますが、より多くのメモリが使用されます。詳細については、ヒントを参照してください。

すべて折りたたむ

Rosenbrock 関数は、最適化の標準的なテスト関数です。補助関数 rosenbrock.m は、関数の値を計算し、自動微分を使用してその勾配を計算します。

type rosenbrock.m
function [y,dydx] = rosenbrock(x)

y = 100*(x(2) - x(1).^2).^2 + (1 - x(1)).^2;
dydx = dlgradient(y,x);

end

[–1,2] における Rosenbrock 関数とその勾配を評価するには、その点の dlarray を作成してから、関数ハンドル @rosenbrock を指定して dlfeval を呼び出します。

x0 = dlarray([-1,2]);
[fval,gradval] = dlfeval(@rosenbrock,x0)
fval = 
  1x1 dlarray

   104

gradval = 
  1x2 dlarray

   396   200

または、2 つの入力 x1 および x2 をもつ関数として Rosenbrock 関数を定義します。

type rosenbrock2.m
function [y,dydx1,dydx2] = rosenbrock2(x1,x2)

y = 100*(x2 - x1.^2).^2 + (1 - x1).^2;
[dydx1,dydx2] = dlgradient(y,x1,x2);

end

入力 –1 および 2 を表す 2 つの dlarray 引数を指定して dlfeval を呼び出し、rosenbrock2 を評価します。

x1 = dlarray(-1);
x2 = dlarray(2);
[fval,dydx1,dydx2] = dlfeval(@rosenbrock2,x1,x2)
fval = 
  1x1 dlarray

   104

dydx1 = 
  1x1 dlarray

   396

dydx2 = 
  1x1 dlarray

   200

単位正方形内のいくつかの点について、Rosenbrock 関数の勾配をプロットします。まず、関数の評価点と出力を表す配列を初期化します。

[X1 X2] = meshgrid(linspace(0,1,10));
X1 = dlarray(X1(:));
X2 = dlarray(X2(:));
Y = dlarray(zeros(size(X1)));
DYDX1 = Y;
DYDX2 = Y;

ループ内で関数を評価します。quiver を使用して結果をプロットします。

for i = 1:length(X1)
    [Y(i),DYDX1(i),DYDX2(i)] = dlfeval(@rosenbrock2,X1(i),X2(i));
end
quiver(extractdata(X1),extractdata(X2),extractdata(DYDX1),extractdata(DYDX2))
xlabel('x1')
ylabel('x2')

Figure contains an axes object. The axes object with xlabel x1, ylabel x2 contains an object of type quiver.

dlgradient および dlfeval を使用して、複素数を含む関数の値と勾配を計算します。複素勾配を計算することも、勾配を実数のみに限定することもできます。

この例の最後にリストされている関数 complexFun を定義します。この関数は、以下の複素式を実装します。

f(x)=(2+3i)x

この例の最後にリストされている関数 gradFun を定義します。この関数は、complexFun を呼び出し、dlgradient を使用して入力に対する結果の勾配を計算します。自動微分の場合、微分する値 (入力に基づいて計算される関数の値) は実数のスカラーでなければなりません。そのため、この関数は、勾配を計算する前に結果の実数部の合計を取ります。この関数は、関数値の実数部と勾配を返します。勾配は複素数となる場合があります。

範囲が -2 ~ 2 および -2i ~ 2i である複素平面上のサンプル点を定義し、dlarray に変換します。

functionRes = linspace(-2,2,100);
x = functionRes + 1i*functionRes.';
x = dlarray(x);

各サンプル点について、関数値と勾配を計算します。

[y, grad] = dlfeval(@gradFun,x);
y = extractdata(y);

勾配を表示するサンプル点を定義します。

gradientRes = linspace(-2,2,11);
xGrad = gradientRes + 1i*gradientRes.';

これらのサンプル点の勾配値を抽出します。

[~,gradPlot] = dlfeval(@gradFun,dlarray(xGrad));
gradPlot = extractdata(gradPlot);

結果をプロットします。imagesc を使用して、複素平面上に関数の値を表示します。quiver を使用して、勾配の向きと大きさを表示します。

imagesc([-2,2],[-2,2],y);
axis xy
colorbar
hold on
quiver(real(xGrad),imag(xGrad),real(gradPlot),imag(gradPlot),"k");
xlabel("Real")
ylabel("Imaginary")
title("Real Value and Gradient","Re$(f(x)) = $ Re$((2+3i)x)$","interpreter","latex")

この関数の勾配は、複素平面全体で同じになっています。自動微分によって計算された勾配の値を抽出します。

grad(1,1)
ans = 
  1×1 dlarray

   2.0000 - 3.0000i

検証すると、この関数の複素微分は次の値となることがわかります。

df(x)dx=2+3i

ただし、関数 Re(f(x)) は解析的ではないため、複素微分は定義されません。MATLAB の自動微分の場合、微分する値は常に実数でなければならないため、複素解析関数を使用することはできません。代わりに、このプロットで示されているように、返された勾配が最急上昇方向を向くように微分が計算されます。これは、関数 Re(f(x)):C R を関数 Re(f(xR+ixI)):R × R R と解釈することで実現されます。

function y = complexFun(x)
    y = (2+3i)*x;    
end

function [y,grad] = gradFun(x)
    y = complexFun(x);
    y = real(y);

    grad = dlgradient(sum(y,"all"),x);
end

入力引数

すべて折りたたむ

微分する値。スカラー dlarray オブジェクトとして指定します。微分の場合、y は、dlarray 入力のトレースされた関数でなければならず (トレースされた dlarrayを参照)、dlarray をサポートしている関数で構成されていなければなりません (dlarray をサポートする関数の一覧を参照)。

名前と値のオプション 'AllowComplex'true に設定されている場合でも、微分する変数は実数でなければなりません。

例: 100*(x(2) - x(1).^2).^2 + (1 - x(1)).^2

例: relu(X)

データ型: single | double | logical

関数内の変数。dlarray オブジェクトか、dlarray オブジェクトを含む cell 配列、構造体、table、またはそれらの引数の再帰的な組み合わせとして指定します。たとえば、dlarray オブジェクトを含む構造体を格納した cell 配列を含む cell 配列を引数として指定できます。

x1,...,xk を table として指定する場合、次の変数を table に含めなければなりません。

  • Layer — 層の名前。string スカラーとして指定します。

  • Parameter — パラメーター名。string スカラーとして指定します。

  • Value — パラメーターの値。dlarray を含む cell 配列として指定します。

例: dlarray([1 2;3 4])

データ型: single | double | logical | struct | cell
複素数のサポート: あり

名前と値の引数

オプションの引数のペアを Name1=Value1,...,NameN=ValueN として指定します。ここで、Name は引数名で、Value は対応する値です。名前と値の引数は他の引数の後に指定しなければなりませんが、ペアの順序は重要ではありません。

R2021a より前では、コンマを使用して名前と値をそれぞれ区切り、Name を引用符で囲みます。

例: dydx = dlgradient(y,x,'RetainData',true) は、後続の dlgradient の呼び出しで再利用できるように、勾配の中間値を保持します。

勾配計算に使用されるデータを保持するためのフラグ。次のいずれかの値として指定します。

  • false または 0 — 勾配計算に使用されるデータを保持しません。

  • true または 1dydx1,...,dydxk の勾配を計算するために使用されるデータを保持します。dlgradient をさらに呼び出すときに、これらの値を再計算せずに再利用できます。dlfeval 関数が評価を完了すると、ソフトウェアはこれらの値を破棄します。このオプションは、dlfeval 呼び出しに複数の dlgradient 関数呼び出しが含まれている場合にのみ役立ちます。複数の dlgradient 呼び出しが同じトレースの一部を使用する場合、メモリ使用量は増えますが、かかる時間を節約できます。

EnableHigherDerivativestrue の場合、ソフトウェアは勾配の計算に使用されるデータを保持するため、RetainData 引数は効果がありません。

例: dydx = dlgradient(y,x,'RetainData',true)

データ型: logical

高次微分を有効にするフラグ。次のいずれかとして指定します。

  • true — 高次微分を有効にします。自動微分を使用して微分を計算する関数 (dlgradientdljacobiandldivergence、および dllaplacian など) をさらに呼び出したときに、返された勾配を計算で使用できるように、バックワード パスがトレースされます。

  • false — 高次微分を無効にします。バックワード パスはトレースされません。1 次微分のみを計算する必要がある場合はこのオプションを使用してください。このオプションを使用すると、通常、処理時間が短縮され、メモリ使用量が節約されます。

AcceleratedFunction オブジェクト内で dlgradient 関数を使用している場合、既定値は true となります。そうでない場合、既定値は false となります。

EnableHigherDerivativestrue の場合、中間値は保持されるため、RetainData 引数は効果がありません。

高次微分の計算を必要とするモデルに学習させる方法を示す例については、Wasserstein GAN with Gradient Penalty (WGAN-GP) の学習を参照してください。

関数内の複素変数と複素勾配を許可するフラグ。次のいずれかとして指定します。

  • true — 関数内の複素変数と複素勾配を許可します。関数内の変数を複素数として指定できます。すべての変数が実数であっても、勾配が複素数となる場合があります。微分する変数は実数でなければなりません。

  • false — 複素変数と複素勾配を許可しません。微分する変数および関数内の変数は実数でなければなりません。勾配は常に実数となります。ただし、中間値は複素数となる場合があります。

名前と値のオプション 'AllowComplex'true に設定されている場合でも、微分する変数は実数でなければなりません。

データ型: logical

出力引数

すべて折りたたむ

勾配。dlarray オブジェクトか、dlarray オブジェクトを含む cell 配列、構造体、table、またはそれらの引数の再帰的な組み合わせとして返されます。dydx1,...,dydxk のサイズおよびデータ型は、関連する入力引数 x1,…,xk のサイズおよびデータ型と同じです。

制限

  • カスタム逆方向関数をもつカスタム層が含まれる dlnetwork オブジェクトを使用している場合、関数 dlgradient は高次微分の計算をサポートしません。

  • 以下の層が含まれる dlnetwork オブジェクトを使用している場合、関数 dlgradient は高次微分の計算をサポートしません。

    • gruLayer

    • lstmLayer

    • bilstmLayer

  • 関数 dlgradient は、以下の関数に依存する高次微分の計算をサポートしません。

    • gru

    • lstm

    • embed

    • prod

    • interp1

詳細

すべて折りたたむ

トレースされた dlarray

dlarray は、関数の計算時、実行したステップを "トレース" として内部的に記録します。これにより、リバース モードの自動微分を行うことができます。このトレースは dlfeval 呼び出し内で実行されます。自動微分の背景を参照してください。

ヒント

  • dlgradient は関数の内部で呼び出さなければなりません。勾配の数値を取得するには、dlfeval を使用して関数を評価しなければなりません。また、関数の引数は dlarray でなければなりません。Deep Learning Toolbox での自動微分の使用を参照してください。

  • 勾配を正しく評価するため、引数 y には dlarray をサポートしている関数のみを使用しなければなりません。dlarray をサポートする関数の一覧を参照してください。

  • 名前と値のペアの引数 'RetainData'true に設定すると、微分の計算後、直ちにトレースが消去されず、関数 dlfeval の呼び出し中はトレースが保持されます。この保持により、同じ dlfeval 呼び出し内の後続の dlgradient 呼び出しが高速になりますが、より多くのメモリが使用されます。たとえば、敵対的ネットワークに学習させる場合、'RetainData' を設定すると、学習中に 2 つのネットワーク間でデータと関数が共有されるため、便利です。敵対的生成ネットワーク (GAN) の学習を参照してください。

  • 1 次微分のみを計算する必要がある場合は、'EnableHigherDerivatives' オプションが false になっていることを確認してください。これにより、通常、処理時間が短縮され、メモリ使用量が節約されます。

  • 複素勾配はウィルティンガーの微分を使用して計算されます。勾配は、微分する関数の実数部が増加する向きで定義されます。これは、関数が複素数であっても微分する変数 (損失など) は実数でなければならないためです。

拡張機能

バージョン履歴

R2019b で導入