主要内容

dlgradient

使用自动微分计算自定义训练循环的梯度

说明

dlgradient 函数使用自动微分来计算导数。

提示

对于大多数深度学习任务,您可以使用预训练神经网络,并使其适应您自己的数据。有关说明如何使用迁移学习来重新训练卷积神经网络以对一组新图像进行分类的示例,请参阅重新训练神经网络以对新图像进行分类。您也可以使用 trainnettrainingOptions 函数从头创建和训练神经网络。

如果 trainingOptions 函数没有提供您的任务所需的训练选项,则您可以使用自动微分创建自定义训练循环。要了解详细信息,请参阅使用自定义训练循环训练网络

如果 trainnet 函数没有提供您的任务所需的损失函数,您可以将 trainnet 的自定义损失函数指定为函数句柄。对于需要比预测值和目标值更多输入的损失函数(例如,需要访问神经网络或额外输入的损失函数),请使用自定义训练循环来训练模型。要了解详细信息,请参阅使用自定义训练循环训练网络

如果 Deep Learning Toolbox™ 没有提供您的任务所需的层,则您可以创建一个自定义层。要了解详细信息,请参阅定义自定义深度学习层。对于无法指定为由层组成的网络的模型,可以将模型定义为函数。要了解详细信息,请参阅Train Network Using Model Function

有关对哪项任务使用哪种训练方法的详细信息,请参阅Train Deep Learning Model in MATLAB

[dydx1,...,dydxk] = dlgradient(y,x1,...,xk) 返回 y 关于变量 x1xk 的梯度。

从传递给 dlfeval 的函数内部调用 dlgradient。请参阅使用自动微分计算梯度Use Automatic Differentiation In Deep Learning Toolbox

示例

[dydx1,...,dydxk] = dlgradient(y,x1,...,xk,Name,Value) 返回梯度并使用一个或多个名称-值对组指定其他选项。例如,dydx = dlgradient(y,x,'RetainData',true) 会导致梯度保留中间值,以供在后续 dlgradient 调用中重用。此语法可以节省时间,但会使用更多内存。有关详细信息,请参阅提示

示例

全部折叠

罗森布罗克函数是用于优化的标准测试函数。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] 处的罗森布罗克函数值及其梯度,请创建该点的 dlarray,然后在函数句柄 @rosenbrock 上调用 dlfeval

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

   104

gradval = 
  1×2 dlarray

   396   200

或者,将罗森布罗克函数定义为具有两个输入(x1 和 x2)的函数。

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

调用 dlfeval 来对表示输入 –12 的两个 dlarray 参量计算 rosenbrock2

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

   104

dydx1 = 
  1×1 dlarray

   396

dydx2 = 
  1×1 dlarray

   200

绘制单位正方形中多个点的罗森布罗克函数梯度图。首先,初始化表示计算点和函数输出的数组。

[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.

使用 dlgradientdlfeval 计算涉及复数的函数的值和梯度。您可以计算复数梯度,也可以将梯度仅限为实数。

定义在此示例末尾列出的 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 支持的函数组成(请参阅List of Functions with dlarray Support)。

即使名称-值选项 'AllowComplex' 设置为 true,要微分的变量也必须是实数。

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

示例: relu(X)

数据类型: single | double | logical

函数中的变量,指定为 dlarray 对象、包含 dlarray 对象的元胞数组、结构体或表,或这些参量的任意递归组合。例如,参量可以是一个元胞数组,其中包含一个含有结构体的元胞数组,而该结构体包含 dlarray 对象。

如果将 x1,...,xk 指定为表,则该表必须包含以下变量:

  • Layer - 层名称,指定为字符串标量。

  • Parameter - 参数名称,指定为字符串标量。

  • Value - 参数的值,指定为包含 dlarray 的元胞数组。

示例: 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 调用中重用

保留用于计算梯度的数据的标志,指定为下列值之一:

  • false0 - 不保留用于计算梯度的数据。

  • true1 - 保留用于在 dydx1,...,dydxk 中计算梯度的数据。对 dlgradient 的后续调用可以重用这些值,而无需重新计算它们。当 dlfeval 函数完成计算后,软件会丢弃这些值。仅当 dlfeval 调用包含多个 dlgradient 函数调用时,此选项才有用。当多个 dlgradient 调用使用相同跟踪的某些部分时,可以节省时间,但代价是使用额外的内存。

EnableHigherDerivativestrue 时,软件会保留用于计算梯度的数据,并且 RetainData 参量不起作用。

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

数据类型: logical

启用高阶导数的标志,指定为下列值之一:

  • 数值或逻辑 1 (true) - 启用高阶导数。跟踪后向传导,以便返回的值可用于后续调用使用自动微分计算导数的函数(例如,dlgradientdljacobiandldivergencedllaplacian)的进一步计算。

  • 数值或逻辑 0 (false) - 禁用高阶导数。不跟踪后向传导。当您只想计算一阶导数时,此选项通常更快并且需要的内存更少。

AcceleratedFunction 对象内使用 dlgradient 函数时,默认值为 true。否则,默认值为 false

如果 EnableHigherDerivativestrue,则保留中间值,并且 RetainData 参量不起作用。

有关如何训练需要计算高阶导数的模型的示例,请参阅Train Wasserstein GAN with Gradient Penalty (WGAN-GP)

允许在函数中使用复数变量和复数梯度的标志,指定为下列值之一:

  • true - 允许在函数中使用复数变量和复数梯度。函数中的变量可以指定为复数。即使所有变量都是实数,梯度也可能是复数。要微分的变量必须是实数。

  • false - 不允许使用复数变量和复数梯度。要微分的变量和函数中的任何变量都必须是实数。梯度始终是实数。中间值仍可以是复数。

即使名称-值选项 'AllowComplex' 设置为 true,要微分的变量也必须是实数。

数据类型: logical

输出参量

全部折叠

梯度,以 dlarray 对象、包含 dlarray 对象的元胞数组、结构体或表,或这些参量的任意递归组合的形式返回。dydx1,...,dydxk 的大小和数据类型与关联的输入变量 x1,…,xk 的大小和数据类型相同。

限制

  • 当使用的 dlnetwork 对象包含具有自定义后向函数的自定义层时,dlgradient 函数不支持计算高阶导数。

  • 当使用包含以下层的 dlnetwork 对象时,dlgradient 函数不支持计算高阶导数:

    • gruLayer

    • lstmLayer

    • bilstmLayer

  • dlgradient 函数不支持计算依赖于以下函数的高阶导数:

    • gru

    • lstm

    • embed

    • prod

    • interp1

详细信息

全部折叠

提示

  • dlgradient 调用必须在函数内部。要获取梯度的数值,您必须使用 dlfeval 计算函数,并且函数的参量必须是 dlarray。请参阅Use Automatic Differentiation In Deep Learning Toolbox

  • 为了能够正确计算梯度,y 参量必须仅使用 dlarray 支持的函数。请参阅List of Functions with dlarray Support

  • 如果将 'RetainData' 名称-值对组参量设置为 true,则软件会在 dlfeval 函数调用期间保留跟踪,而不是在导数计算后立即擦除跟踪。这种保留可以加快同一 dlfeval 调用中后续 dlgradient 调用的执行速度,但使用的内存更多。例如,在训练对抗网络时,'RetainData' 设置很有用,因为两个网络在训练期间共享数据和函数。请参阅训练生成对抗网络 (GAN)

  • 当您只需要计算一阶导数时,请确保 'EnableHigherDerivatives' 选项为 false,因为这通常速度更快并且需要的内存更少。

  • 复数梯度是使用 Wirtinger 导数计算的。梯度沿着要微分的函数的实部增加的方向定义。这是因为即使函数是复数函数,要微分的变量(例如损失)也必须是实数。

  • 要加快对深度学习函数(例如模型函数和模型损失函数)的调用,可以使用 dlaccelerate 函数。该函数返回一个 AcceleratedFunction 对象,该对象自动优化、缓存和重用跟踪。

扩展功能

全部展开

版本历史记录

在 R2019b 中推出