Main Content

定义自定义深度学习层

提示

本主题说明如何针对您的问题定义自定义深度学习层。有关 Deep Learning Toolbox™ 中的内置层的列表,请参阅深度学习层列表

如果 Deep Learning Toolbox 没有提供您的任务所需的层,您可以使用本主题作为指南来定义自己的自定义层。定义自定义层后,您可以自动检查该层是否有效,是否与 GPU 兼容,以及是否输出正确定义的梯度。

神经网络层架构

在训练过程中,软件在网络中以迭代方式执行前向传导和后向传导。

在网络的前向传导过程中,每个层获取前面各层的输出,应用一个函数,然后将结果输出(正向传播)到后面各层。有状态的层(如 LSTM 层)也会更新层状态。

层可以有多个输入或输出。例如,层可以从多个前面的层中获取 X1、…、XN,并将输出 Y1、…、YM 正向传播到后续各层。

在执行网络的前向传导结束时,软件计算预测值和目标值之间的损失 L。

在网络的后向传导过程中,每个层都接受损失关于该层的输出的导数,计算损失 L 关于输入的导数,然后反向传播结果。如果层具有可学习参数,则该层还会计算层权重(可学习参数)的导数。该软件使用权重的导数来更新可学习参数。为了节省计算量,前向函数可以使用可选的内存输出与后向函数共享信息。

下图说明通过深度神经网络的数据流,重点显示通过具有单个输入 X、单个输出 Y 和可学习参数 W 的层的数据流。

Network diagram showing the flow of data through a neural network during training.

自定义层模板

要定义自定义层,请使用此类定义模板。此模板提供了自定义层类定义的结构。其大致内容如下:

  • 可选的 properties 块,用于定义层属性、可学习参数和状态参数。有关详细信息,请参阅自定义层属性

  • 层构造函数。

  • predict 函数和可选的 forward 函数。有关详细信息,请参阅前向函数

  • 可选的 resetState 函数,用于设置具有状态属性的层。有关详细信息,请参阅重置状态函数

  • 可选的 backward 函数。有关详细信息,请参阅后向函数

classdef myLayer < nnet.layer.Layer % ...
        % & nnet.layer.Formattable ... % (Optional) 
        % & nnet.layer.Acceleratable % (Optional)

    properties
        % (Optional) Layer properties.

        % Declare layer properties here.
    end

    properties (Learnable)
        % (Optional) Layer learnable parameters.

        % Declare learnable parameters here.
    end

    properties (State)
        % (Optional) Layer state parameters.

        % Declare state parameters here.
    end

    properties (Learnable, State)
        % (Optional) Nested dlnetwork objects with both learnable
        % parameters and state parameters.

        % Declare nested networks with learnable and state parameters here.
    end

    methods
        function layer = myLayer()
            % (Optional) Create a myLayer.
            % This function must have the same name as the class.

            % Define layer constructor function here.
        end

        function layer = initialize(layer,layout)
            % (Optional) Initialize layer learnable and state parameters.
            %
            % Inputs:
            %         layer  - Layer to initialize
            %         layout - Data layout, specified as a networkDataLayout
            %                  object
            %
            % Outputs:
            %         layer - Initialized layer
            %
            %  - For layers with multiple inputs, replace layout with 
            %    layout1,...,layoutN, where N is the number of inputs.
            
            % Define layer initialization function here.
        end
        

        function [Y,state] = predict(layer,X)
            % Forward input data through the layer at prediction time and
            % output the result and updated state.
            %
            % Inputs:
            %         layer - Layer to forward propagate through 
            %         X     - Input data
            % Outputs:
            %         Y     - Output of layer forward function
            %         state - (Optional) Updated layer state
            %
            %  - For layers with multiple inputs, replace X with X1,...,XN, 
            %    where N is the number of inputs.
            %  - For layers with multiple outputs, replace Y with 
            %    Y1,...,YM, where M is the number of outputs.
            %  - For layers with multiple state parameters, replace state 
            %    with state1,...,stateK, where K is the number of state 
            %    parameters.

            % Define layer predict function here.
        end

        function [Y,state,memory] = forward(layer,X)
            % (Optional) Forward input data through the layer at training
            % time and output the result, the updated state, and a memory
            % value.
            %
            % Inputs:
            %         layer - Layer to forward propagate through 
            %         X     - Layer input data
            % Outputs:
            %         Y      - Output of layer forward function 
            %         state  - (Optional) Updated layer state 
            %         memory - (Optional) Memory value for custom backward
            %                  function
            %
            %  - For layers with multiple inputs, replace X with X1,...,XN, 
            %    where N is the number of inputs.
            %  - For layers with multiple outputs, replace Y with 
            %    Y1,...,YM, where M is the number of outputs.
            %  - For layers with multiple state parameters, replace state 
            %    with state1,...,stateK, where K is the number of state 
            %    parameters.

            % Define layer forward function here.
        end

        function layer = resetState(layer)
            % (Optional) Reset layer state.

            % Define reset state function here.
        end

        function [dLdX,dLdW,dLdSin] = backward(layer,X,Y,dLdY,dLdSout,memory)
            % (Optional) Backward propagate the derivative of the loss
            % function through the layer.
            %
            % Inputs:
            %         layer   - Layer to backward propagate through 
            %         X       - Layer input data 
            %         Y       - Layer output data 
            %         dLdY    - Derivative of loss with respect to layer 
            %                   output
            %         dLdSout - (Optional) Derivative of loss with respect 
            %                   to state output
            %         memory  - Memory value from forward function
            % Outputs:
            %         dLdX   - Derivative of loss with respect to layer input
            %         dLdW   - (Optional) Derivative of loss with respect to
            %                  learnable parameter 
            %         dLdSin - (Optional) Derivative of loss with respect to 
            %                  state input
            %
            %  - For layers with state parameters, the backward syntax must
            %    include both dLdSout and dLdSin, or neither.
            %  - For layers with multiple inputs, replace X and dLdX with
            %    X1,...,XN and dLdX1,...,dLdXN, respectively, where N is
            %    the number of inputs.
            %  - For layers with multiple outputs, replace Y and dLdY with
            %    Y1,...,YM and dLdY,...,dLdYM, respectively, where M is the
            %    number of outputs.
            %  - For layers with multiple learnable parameters, replace 
            %    dLdW with dLdW1,...,dLdWP, where P is the number of 
            %    learnable parameters.
            %  - For layers with multiple state parameters, replace dLdSin
            %    and dLdSout with dLdSin1,...,dLdSinK and 
            %    dLdSout1,...,dldSoutK, respectively, where K is the number
            %    of state parameters.

            % Define layer backward function here.
        end
    end
end

格式化的输入和输出

通过使用 dlarray 对象,您可以标注维度,从而简化高维数据的处理。例如,您可以分别使用 "S""T""C""B" 标签来标记哪些维度对应于空间维度、时间维度、通道维度和批量维度。对于未指定的维度和其他维度,请使用 "U" 标签。对于在特定维度上操作的 dlarray 对象函数,您可以通过直接格式化 dlarray 对象或使用 DataFormat 选项来指定维度标签。

通过在自定义层中使用格式化的 dlarray 对象,您也可以定义输入和输出具有不同格式的层,例如置换、添加或删除维度的层。例如,您可以定义一个层,该层将格式为 "SSCB"(空间、空间、通道、批量)的小批量图像作为输入,并将格式为 "CBT"(通道、批量、时间)的小批量序列作为输出。通过使用格式化的 dlarray 对象,您还可以定义可对不同输入格式的数据进行操作的层,例如,支持格式为 "SSCB"(空间、空间、通道、批量)和 "CBT"(通道、批量、时间)的输入的层。

如果未指定后向函数,则默认情况下,层函数接收未格式化的 dlarray 对象作为输入。要指定该层接收格式化的 dlarray 对象作为输入,并输出格式化的 dlarray 对象,请在定义该自定义层时也指定从 nnet.layer.Formattable 类继承。

有关如何定义具有格式化输入的自定义层的示例,请参阅Define Custom Deep Learning Layer with Formatted Inputs

自定义层加速

如果在定义自定义层时未指定后向函数,该软件会使用自动微分自动确定梯度。

当在不使用后向函数的情况下训练具有自定义层的网络时,该软件会跟踪自定义层前向函数的每个输入 dlarray 对象,以确定用于自动微分的计算图。此跟踪过程可能会花费一些时间,最终可能会重新计算相同的跟踪。通过优化、缓存和重用跟踪,您可以在训练网络时加快梯度计算的速度。该软件还可以在训练后重用这些跟踪来加速网络预测。

跟踪取决于层输入的大小、格式和基础数据类型。也就是说,层会针对缓存中不包含大小、格式或基础数据类型的输入触发新跟踪。任何输入,如果只是值与先前缓存的跟踪不同,则不会触发新跟踪。

要指示自定义层支持加速,请在定义自定义层时也指示从 nnet.layer.Acceleratable 类继承。当自定义层从 nnet.layer.Acceleratable 继承时,该软件会在通过 dlnetwork 对象传递数据时自动缓存跟踪。

例如,要指示自定义层 myLayer 支持加速,请使用以下语法

classdef myLayer < nnet.layer.Layer & nnet.layer.Acceleratable
    ...
end

加速注意事项

基于缓存跟踪的性质,并非所有函数都支持加速。

缓存过程可以缓存您可能期望更改或取决于外部因素的值或代码结构。加速符合以下条件的自定义层时必须小心:

  • 生成随机数。

  • 使用 if 语句和 while 循环,其条件取决于 dlarray 对象的值。

由于缓存过程需要额外的计算,在某些情况下,加速会导致代码运行时间较长。当该软件花费时间创建不经常重用的新缓存时,可能就会出现这种情况。例如,当您向函数传递具有不同序列长度的多个小批量时,该软件会针对每个唯一序列长度触发新跟踪。

当自定义层加速导致速度变慢时,您可以通过以下方式禁用自定义层加速:删除 Acceleratable 类,或通过将 Acceleration 选项设置为 "none" 来禁用 dlnetwork 对象函数 predictforward 的加速。

有关为自定义层启用加速支持的详细信息,请参阅Custom Layer Function Acceleration

自定义层属性

在类定义的 properties 部分声明层属性。

默认情况下,自定义层具有下列属性。请不要在 properties 部分中声明这些属性。

属性说明
Name层名称,指定为字符向量或字符串标量。对于 Layer 数组输入,trainnetdlnetwork 函数会自动为层指定名称 ""
Description

层的单行描述,指定为字符串标量或字符向量。当层显示在 Layer 数组中时,会出现此描述。

如果没有指定层描述,则软件将显示层类名。

Type

层的类型,指定为字符向量或字符串标量。当层显示在 Layer 数组中时,会显示 Type 的值。

如果没有指定层类型,则软件将显示层类名。

NumInputs层的输入的数量,指定为正整数。如果您未指定此值,软件会自动将 NumInputs 设置为 InputNames 中的名称的数量。默认值为 1。
InputNames层的输入名称,指定为字符向量元胞数组。如果您未指定此值并且 NumInputs 大于 1,则软件会自动将 InputNames 设置为 {'in1',...,'inN'},其中 N 等于 NumInputs。默认值为 {'in'}
NumOutputs层的输出的数量,指定为正整数。如果您未指定此值,软件会自动将 NumOutputs 设置为 OutputNames 中的名称的数量。默认值为 1。
OutputNames层的输出名称,指定为字符向量元胞数组。如果您未指定此值并且 NumOutputs 大于 1,则软件会自动将 OutputNames 设置为 {'out1',...,'outM'},其中 M 等于 NumOutputs。默认值为 {'out'}

如果层没有其他属性,则您可以省略 properties 部分。

提示

如果要创建一个具有多个输入的层,则必须在层构造函数中设置 NumInputsInputNames 属性。如果要创建一个具有多个输出的层,则必须在层构造函数中设置 NumOutputsOutputNames 属性。有关示例,请参阅Define Custom Deep Learning Layer with Multiple Inputs

可学习参数

在类定义的 properties (Learnable) 部分声明层可学习参数。

您可以将数值数组或 dlnetwork 对象指定为可学习参数。如果 dlnetwork 对象同时具有可学习参数和状态参数(例如,包含 LSTM 层的 dlnetwork 对象),您必须在 properties (Learnable, State) 部分中指定它。如果层没有可学习参数,则可以省略带有 Learnable 属性的 properties 部分。

您也可以指定可学习参数的学习率因子和 L2 因子。默认情况下,每个可学习参数的学习率因子和 L2 因子都设置为 1。对于内置层和自定义层,可以使用以下函数设置和获取学习率因子和 L2 正则化因子。

函数说明
setLearnRateFactor设置可学习参数的学习率因子。
setL2Factor设置可学习参数的 L2 正则化因子。
getLearnRateFactor获取可学习参数的学习率因子。
getL2Factor获取可学习参数的 L2 正则化因子。

要指定可学习参数的学习率因子和 L2 因子,请分别使用语法 layer = setLearnRateFactor(layer,parameterName,value)layer = setL2Factor(layer,parameterName,value)

要获得可学习参数的学习率因子和 L2 因子的值,请分别使用语法 getLearnRateFactor(layer,parameterName)getL2Factor(layer,parameterName)

例如,此语法将可学习参数 "Alpha" 的学习率因子设置为 0.1

layer = setLearnRateFactor(layer,"Alpha",0.1);

状态参数

对于有状态层,如循环层,请在类定义的 properties (State) 部分中声明层状态参数。如果可学习参数是同时具有可学习参数和状态参数的 dlnetwork 对象(例如,包含 LSTM 层的 dlnetwork 对象),则您必须在 properties (Learnable, State) 部分中指定对应的属性。如果层没有状态参数,则可以省略具有 State 属性的 properties 部分。

如果层有状态参数,则前向函数必须同时返回更新后的层状态。有关详细信息,请参阅前向函数

要指定自定义重置状态函数,请在类定义中包含语法为 layer = resetState(layer) 的函数。有关详细信息,请参阅重置状态函数

不支持使用 trainnet 函数对包含具有状态参数的自定义层的网络进行并行训练。使用具有状态参数的自定义层训练网络时,ExecutionEnvironment 训练选项必须为 "auto""gpu""cpu"

可学习参数和状态参数初始化

您可以指定在层构造函数或自定义 initialize 函数中初始化层的可学习参数和状态参数:

  • 如果可学习参数或状态参数初始化不需要来自层输入的大小信息,例如,加权相加层的可学习权重是大小与层输入数匹配的向量,则您可以在层构造函数中初始化权重。有关示例,请参阅Define Custom Deep Learning Layer with Multiple Inputs

  • 如果可学习参数或状态参数初始化需要来自层输入的大小信息,例如,SReLU 层的可学习权重是大小与输入数据的通道数匹配的向量,则您可以在利用输入数据布局相关信息的自定义初始化函数中初始化权重。有关示例,请参阅Define Custom Deep Learning Layer with Learnable Parameters

前向函数

一些层在训练期间的行为和其在预测期间的行为是不同的。例如,丢弃层仅在训练期间执行丢弃,在预测期间不起作用。层使用 predictforward 函数来执行前向传导。如果前向传导在预测时间进行,则该层使用 predict 函数。如果前向传导在训练时进行,则该层使用 forward 函数。如果不需要对预测时间和训练时间使用两个不同函数,则可以省略 forward 函数。执行此操作时,该层在训练时使用 predict

如果层具有状态参数,则前向函数还必须以数值数组形式返回更新后的层状态参数。

如果您同时定义自定义 forward 函数和自定义 backward 函数,则前向函数必须返回 memory 输出。

predict 函数语法取决于层的类型。

  • Y = predict(layer,X) 通过层对输入数据 X 进行前向传播处理并输出结果 Y,其中 layer 只有一个输入和一个输出。

  • [Y,state] = predict(layer,X) 还输出更新后的状态参数 state,其中 layer 只有一个状态参数。

您可以针对具有多个输入、多个输出或多个状态参数的层调整语法:

  • 对于具有多个输入的层,请将 X 替换为 X1,...,XN,其中 N 是输入的数量。NumInputs 属性必须与 N 匹配。

  • 对于具有多个输出的层,请将 Y 替换为 Y1,...,YM,其中 M 是输出的数量。NumOutputs 属性必须与 M 匹配。

  • 对于具有多个状态参数的层,请将 state 替换为 state1,...,stateK,其中 K 是状态参数的数量。

提示

如果该层的输入的数量可能变化,则使用 varargin 代替 X1,…,XN。在本例中,varargin 是由输入组成的元胞数组,其中 varargin{i} 对应于 Xi

如果输出的数量可能变化,则使用 varargout 代替 Y1,…,YM。在本例中,varargout 是由输出组成的元胞数组,其中 varargout{j} 对应于 Yj

提示

如果自定义层具有一个作为可学习参数的 dlnetwork 对象,则在自定义层的 predict 函数中,应对 dlnetwork 使用 predict 函数。在执行此操作时,dlnetwork 对象 predict 函数使用适当的层运算进行预测。如果 dlnetwork 具有状态参数,则同时返回网络状态。

forward 函数语法取决于层的类型:

  • Y = forward(layer,X) 通过层对输入数据 X 进行前向传播处理并输出结果 Y,其中 layer 只有一个输入和一个输出。

  • [Y,state] = forward(layer,X) 还输出更新后的状态参数 state,其中 layer 只有一个状态参数。

  • [__,memory] = forward(layer,X) 还使用上述任一语法返回自定义 backward 函数的内存值。如果层同时具有自定义 forward 函数和自定义 backward 函数,则前向函数必须返回内存值。

您可以针对具有多个输入、多个输出或多个状态参数的层调整语法:

  • 对于具有多个输入的层,请将 X 替换为 X1,...,XN,其中 N 是输入的数量。NumInputs 属性必须与 N 匹配。

  • 对于具有多个输出的层,请将 Y 替换为 Y1,...,YM,其中 M 是输出的数量。NumOutputs 属性必须与 M 匹配。

  • 对于具有多个状态参数的层,请将 state 替换为 state1,...,stateK,其中 K 是状态参数的数量。

提示

如果该层的输入的数量可能变化,则使用 varargin 代替 X1,…,XN。在本例中,varargin 是由输入组成的元胞数组,其中 varargin{i} 对应于 Xi

如果输出的数量可能变化,则使用 varargout 代替 Y1,…,YM。在本例中,varargout 是由输出组成的元胞数组,其中 varargout{j} 对应于 Yj

提示

如果自定义层具有一个作为可学习参数的 dlnetwork 对象,则在自定义层的 forward 函数中,应对 dlnetwork 对象使用 forward 函数。在执行此操作时,dlnetwork 对象 forward 函数使用适当的层运算进行训练。

输入的维度取决于数据的类型和所连接层的输出。

层输入示例
形状数据格式
二维图像

h×w×c×N 数值数组,其中 h、w、c 和 N 分别是图像的高度、宽度、通道数和观测值数量。

"SSCB"
三维图像h×w×d×c×N 数值数组,其中 h、w、d、c 和 N 分别是图像的高度、宽度、深度、通道数和图像观测值数量。"SSSCB"
向量序列

c×N×s 矩阵,其中 c 是序列的特征数,N 是序列观测值数量,而 s 是序列长度。

"CBT"
二维图像序列

h×w×c×N×s 数组,其中 h、w 和 c 分别对应于图像的高度、宽度和通道数,N 是图像序列观测值数量,而 s 是序列长度。

"SSCBT"
三维图像序列

h×w×d×c×N×s 数组,其中 h、w、d 和 c 分别对应于图像的高度、宽度、深度和通道数量,N 是图像序列观测值数量,而 s 是序列长度。

"SSSCBT"
特征c×N 数组,其中 c 是特征数量,而 N 是观测值数量。"CB"

对于输出序列的层,层可以输出任意长度的序列或输出无时间维度的数据。

自定义层前向函数的输出可以是复数值。 (自 R2024a 起)如果该层输出复数值数据,则在神经网络中使用自定义层时,必须确保后续层或损失函数支持复数值输入。在自定义层的 predictforward 函数中使用复数会导致复数型可学习参数。要训练具有复数值可学习参数的模型,请使用带有 "sgdm""adam""rmsprop" 求解器(这些求解器使用 trainingOptions 函数来指定)的 trainnet 函数,或使用包含 sgdmupdateadamupdatermspropupdate 函数的自定义训练循环。

在 R2024a 之前: 自定义层前向函数的输出不能为复数。如果自定义层的 predictforward 函数包含复数,请在返回输出之前将所有输出转换为实数值。在自定义层的 predictforward 函数中使用复数会导致复数型可学习参数。如果您使用的是自动微分(换句话说,您没有为自定义层编写后向函数),则在函数计算开始时,请将所有可学习参数转换为实数值。这样做可以确保自动微分算法不会输出复数值梯度。

重置状态函数

默认情况下,dlnetwork 对象的 resetState 函数对具有状态参数的自定义层不起作用。要为网络对象定义 resetState 函数的层行为,请在重置状态参数的层定义中定义可选层 resetState 函数。

resetState 函数必须具有语法 layer = resetState(layer),其中返回的层具有重置状态属性。

resetState 函数不能设置除可学习属性和状态属性之外的任何层属性。如果该函数设置了其他层属性,则可能会出现意外的层行为。 (自 R2023a 起)

后向函数

层后向函数计算损失关于输入数据的导数,然后将结果输出(反向传播)到前一层。如果层具有可学习参数(例如,层权重),则 backward 还计算可学习参数的导数。当您使用 trainnet 函数时,层会在后向传导过程中使用这些导数自动更新可学习参数。

定义后向函数是可选的。如果未指定后向函数,并且层前向函数支持 dlarray 对象,则软件会使用自动微分自动确定后向函数。有关支持 dlarray 对象的函数列表,请参阅List of Functions with dlarray Support。当您需要执行以下操作时,请定义一个自定义后向函数:

  • 使用特定算法来计算导数。

  • 在前向函数中使用不支持 dlarray 对象的操作。

具有可学习 dlnetwork 对象的自定义层不支持自定义后向函数。

要定义一个自定义后向函数,请创建名为 backward 的函数。

backward 函数语法取决于层的类型。

  • dLdX = backward(layer,X,Y,dLdY,memory) 返回损失关于层输入的导数 dLdX,其中 layer 只有一个输入和一个输出。Y 对应于前向函数输出,而 dLdY 对应于损失关于 Y 的导数。函数输入 memory 对应于前向函数的内存输出。

  • [dLdX,dLdW] = backward(layer,X,Y,dLdY,memory) 还返回损失关于可学习参数的导数 dLdW,其中 layer 只有一个可学习参数。

  • [dLdX,dLdSin] = backward(layer,X,Y,dLdY,dLdSout,memory) 还返回损失关于状态输入的导数 dLdSin,其中 layer 只有一个状态参数,而 dLdSout 对应于损失关于层状态输出的导数。

  • [dLdX,dLdW,dLdSin] = backward(layer,X,Y,dLdY,dLdSout,memory) 还返回损失关于可学习参数的导数 dLdW,并返回损失关于层状态输入的导数 dLdSin,其中 layer 只有一个状态参数和一个可学习参数。

您可以针对具有多个输入、多个输出、多个可学习参数或多个状态参数的层调整语法:

  • 对于具有多个输入的层,分别用 X1,...,XNdLdX1,...,dLdXN 替换 XdLdX,其中 N 是输入的数量。

  • 对于具有多个输出的层,分别用 Y1,...,YMdLdY1,...,dLdYM 替换 YdLdY,其中 M 是输出的数量。

  • 对于具有多个可学习参数的层,将 dLdW 替换为 dLdW1,...,dLdWP,其中 P 是可学习参数的数量。

  • 对于具有多个状态参数的层,分别用 dLdSin1,...,dLdSinKdLdSout1,...,dLdSoutK 替换 dLdSindLdSout,其中 K 是状态参数的数量。

要通过防止在前向和后向传导之间保存未使用的变量来减少内存使用量,请用 ~ 替换对应的输入参量。

提示

如果 backward 的输入数量可能变化,则使用 varargin 代替 layer 后的输入参量。在这种情况下,varargin 是由输入组成的元胞数组,其中前 N 个元素对应于 N 个层输入,接下来的 M 个元素对应于 M 个层输出,接下来的 M 个元素对应于损失关于 M 个层输出的导数,接下来的 K 个元素对应于损失关于 K 个状态输出的 K 个导数,最后一个元素对应于 memory

如果输出的数量可能变化,则使用 varargout 代替输出参量。在这种情况下,varargout 是由输出组成的元胞数组,其中前 N 个元素对应于损失关于 N 个层输入的 N 个导数,接下来的 P 个元素对应于损失关于 P 个可学习参数的导数,接下来的 K 个元素对应于损失关于 K 个状态输入的导数。

XY 的值与前向函数中的对应值相同。dLdY 的维度与 Y 的维度相同。

dLdX 的维度和数据类型与 X 的维度和数据类型相同。dLdW 的维度和数据类型与 W 的维度和数据类型相同。

要计算损失关于输入数据的导数,可以使用链式法则计算损失关于输出数据的导数以及输出数据关于输入数据的导数:

LX(i)=jLYjYjX(i)

LWi=jLYjYjWi

当使用 trainnet 函数时,层会在后向传导过程中使用导数 dLdW 自动更新可学习参数。

有关如何定义自定义后向函数的示例,请参阅Specify Custom Layer Backward Function

自定义层后向函数的输出可以是复数值。 (自 R2024a 起)使用复数值梯度可能会导致可学习参数为复数值。要训练具有复数值可学习参数的模型,请使用带有 "sgdm""adam""rmsprop" 求解器(这些求解器使用 trainingOptions 函数来指定)的 trainnet 函数,或使用包含 sgdmupdateadamupdatermspropupdate 函数的自定义训练循环。

在 R2024a 之前: 自定义层后向函数的输出不能为复数。如果您的后向函数涉及复数,则请在返回输出之前将后向函数的所有输出转换为实数值。

GPU 兼容性

如果层前向函数完全支持 dlarray 对象,则该层与 GPU 兼容。否则,为了与 GPU 兼容,层函数必须支持 gpuArray (Parallel Computing Toolbox) 类型的输入并返回其输出。

许多 MATLAB® 内置函数支持 gpuArray (Parallel Computing Toolbox)dlarray 输入参量。有关支持 dlarray 对象的函数列表,请参阅List of Functions with dlarray Support。有关在 GPU 上执行的函数的列表,请参阅Run MATLAB Functions on a GPU (Parallel Computing Toolbox)要使用 GPU 进行深度学习,您还必须拥有支持的 GPU 设备。有关受支持设备的信息,请参阅GPU Computing Requirements (Parallel Computing Toolbox)有关在 MATLAB 中使用 GPU 的详细信息,请参阅GPU Computing in MATLAB (Parallel Computing Toolbox)

代码生成兼容性

要创建支持代码生成的自定义层,需要满足以下要求:

  • 层必须在层定义中指定 pragma 指令 %#codegen

  • 层前向函数的输入和输出必须具有相同的批量大小。

  • 非标量属性的类型必须为单精度、双精度或字符数组。

  • 标量属性的类型必须为数值、逻辑值或字符串。

纯 C/C++/CUDA 的代码生成(当 DeepLearningConfigTargetLibrary 选项为 "none" 时)支持输入仅包含空间、通道、批量和时间维度的自定义层。否则,代码生成仅支持包含二维图像或特征输入的自定义层。代码生成不支持具有状态属性(具有特性 State 的属性)的自定义层。

有关如何创建支持代码生成的自定义层的示例,请参阅Define Custom Deep Learning Layer for Code Generation

网络合成

要创建本身定义神经网络的自定义层,您可以在层定义的 properties (Learnable) 部分中将 dlnetwork 对象声明为可学习参数。这种方法称为网络合成。您可以使用网络合成来实现以下目的:

  • 创建一个具有控制流的网络,例如,网络的一部分可以根据输入数据而动态变化。

  • 创建一个具有循环的网络,例如,网络的某些部分将输出反馈到自身。

  • 实现权重共享,例如,在不同数据需要通过相同层的网络(如孪生神经网络或生成对抗网络 (GAN))中执行此操作。

对于同时具有可学习参数和状态参数的嵌套网络(例如,具有批量归一化或 LSTM 层的网络),请在层定义的 properties (Learnable, State) 部分中声明网络。

检查层的有效性

如果您创建自定义深度学习层,则可以使用 checkLayer 函数来检查该层是否有效。该函数检查层的有效性、GPU 兼容性、正确定义的梯度和代码生成兼容性。要检查层是否有效,请运行以下命令:

checkLayer(layer,layout)
layer 是层的实例,而 layoutnetworkDataLayout 对象,该对象指定层输入的有效大小和数据格式。要检查多个观测值,请使用 ObservationDimension 选项。要运行代码生成兼容性检查,请将 CheckCodegenCompatibility 选项设置为 1 (true)。对于较大的输入大小,梯度检查的运行时间较长。为了加快检查速度,请指定较小的有效输入大小。

有关详细信息,请参阅Check Custom Layer Validity

使用 checkLayer 检查自定义层的有效性

检查自定义层 sreluLayer 的层有效性。

自定义层 sreluLayer 作为支持文件附加到此示例中,该层会将 SReLU 运算应用于输入数据。要访问此层,请以实时脚本形式打开此示例。

创建层的一个实例。

layer = sreluLayer;

创建一个 networkDataFormat 对象,该对象指定层的典型输入的预期输入大小和格式。指定有效的输入大小 [24 24 20 128],其中维度对应于前一层输出的高度、宽度、通道数和观测值数量。将格式指定为 "SSCB"(空间、空间、通道、批量)。

validInputSize = [24 24 20 128];
layout = networkDataLayout(validInputSize,"SSCB");

使用 checkLayer 检查层的有效性。

checkLayer(layer,layout)
Skipping GPU tests. No compatible GPU device found.
 
Skipping code generation compatibility tests. To check validity of the layer for code generation, specify the CheckCodegenCompatibility and ObservationDimension options.
 
Running nnet.checklayer.TestLayerWithoutBackward
.......... ..........
Done nnet.checklayer.TestLayerWithoutBackward
__________

Test Summary:
	 20 Passed, 0 Failed, 0 Incomplete, 14 Skipped.
	 Time elapsed: 0.28208 seconds.

该函数对层进行检查时未发现任何问题。

另请参阅

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

相关主题