主要内容

定义具有可学习参数的自定义深度学习层

如果深度学习工具箱™没有为您的任务提供所需的层,那么您可以使用此示例作为指导定义自己的自定义层。有关内置层的列表,请参见深度学习层列表

要定义自定义深度学习层,您可以使用本例中提供的模板,该模板将带您完成以下步骤:

  1. 命名层-给层一个名字,这样你可以在MATLAB中使用它®

  2. 声明层属性——指定层的属性,包括可学习参数和状态参数。

  3. 创建一个构造函数(可选)-指定如何构造层并初始化其属性。如果没有指定构造函数,则在创建时,软件将初始化构造函数名字描述,类型属性与[]并设置层输入和输出的数量为1。

  4. 创建前向函数——指定数据在预测时间和训练时间如何通过层向前传递(前向传播)。

  5. 创建重置状态函数(可选)-指定如何重置状态参数。

  6. 创建反向函数(可选)——指定损失相对于输入数据和可学习参数的导数(反向传播)。如果没有指定向后函数,则向前函数必须支持金宝appdlarray对象。

在定义层函数时,可以使用dlarray对象。使用dlarray对象允许您标记维度,从而更容易处理高维数据。属性标记哪些维度对应于空间、时间、通道和批处理维度“S”“T”“C”,“B”标签,分别。对于未指定的维度和其他维度,使用“U”标签。为dlarray对象的函数在特定维度上操作时,可以通过格式化dlarray对象,或者使用DataFormat选择。

使用格式化的dlarray自定义层中的对象还允许您定义输入和输出具有不同格式的层,例如排列、添加或删除维度的层。例如,您可以定义一个层,将带有格式的小批量图像作为输入“SSCB”(空间,空间,通道,批),并输出一个带格式的小批序列“认知行为治疗”(通道,批次,时间)。使用格式化的dlarray对象还允许您定义可以对具有不同输入格式的数据进行操作的层,例如,支持具有格式的输入的层金宝app“SSCB”(空间,空间,通道,批)和“认知行为治疗”(通道,批次,时间)。

dlarray对象还支持自动区分。金宝app这意味着如果您的前向功能完全支持金宝appdlarray对象,然后定义反向函数是可选的。

以启用对使用格式化金宝appdlarray对象中自定义层转发函数,也继承自nnet.layer.Formattable类在定义自定义层时。有关示例,请参见定义带有格式化输入的自定义深度学习层

这个例子展示了如何创建一个PReLU层,这是一个具有可学习参数的层,并在卷积神经网络中使用它。PReLU层执行阈值操作,其中对于每个通道,任何小于零的输入值都乘以在训练时学习到的标量。[1]对于小于零的值,PReLU层应用缩放系数 α 输入的每个通道。这些系数形成了一个可学习的参数,该层在训练过程中学习。

这个数字来自[1]比较ReLU和PReLU层功能。

中间层模板

在MATLAB中将中间层模板复制到一个新文件中。这个模板概括了中间层类定义的结构。概述:

  • 可选属性用于层属性、可学习参数和状态参数的块。

  • 层构造函数。

  • 预测函数和可选的向前函数。

  • 可选resetState具有状态属性的层的函数。

  • 可选落后的函数。

classdefmyLayer < nnet.layer.Layer可格式化(可选)属性%(可选)图层属性。在这里声明层属性。结束属性(可学的)%(可选)层可学习参数。在这里声明可学习参数。结束属性(状态)%(可选)层状态参数。在这里声明状态参数。结束属性(可学的,状态)%(可选)嵌套dlnetwork对象,两者都可学习%参数和状态。在这里用可学习和状态参数声明嵌套网络。结束方法函数图层= myLayer()(可选)创建myLayer。此函数必须与类名称相同。在这里定义层构造函数。结束函数[Z,状态]=预测(层,X)在预测时间通过层转发输入数据%输出结果和更新状态。%的输入:% layer -向前传播的层% X -输入数据%输出:% Z -层正向函数的输出% state -(可选)更新后的层状态。% -对于有多个输入的层,将X替换为X1,…,XN,%,其中N是输入的数量。% -对于有多个输出的层,将Z替换为% Z1,…,Z米,在那里米我s the number of outputs.% -对于有多个状态参数的层,替换state% with state1,…,状态K,在那里K我s the number of state%的参数。定义层预测函数。结束函数[Z,状态,内存]= forward(层,X)%(可选)训练时通过层向前输入数据并输出结果、更新状态和内存%值。%的输入:% layer -向前传播的层% X -层输入数据%输出:% Z -层正向函数的输出% state -(可选)更新后的层状态% memory -(可选)自定义向后内存值%的功能% -对于有多个输入的层,将X替换为X1,…,XN,%,其中N是输入的数量。% -对于有多个输出的层,将Z替换为% Z1,…,Z米,在那里米我s the number of outputs.% -对于有多个状态参数的层,替换state% with state1,…,状态K,在那里K我s the number of state%的参数。在这里定义层正向函数。结束函数图层= resetState(图层)%(可选)重置层状态。此处定义重置状态函数。结束函数[dLdX,dLdW,dLdSin] = backward(layer,X,Z,dLdZ,dLdSout,memory)%(可选)反向传播损失的导数%函数通过层。%的输入:% layer -向后传播的层% X -层输入数据% Z -层输出数据% dLdZ -损失对层的导数%输出% dLdSout -(可选)关于损失的导数状态输出百分比% memory -前向函数的内存值%输出:% dLdX -损失对层输入的导数% dLdW -(可选)损失的导数%可学习参数% dLdSin -(可选)损失的导数%状态输入% -对于带有状态参数的层,向后语法必须%包括dLdSout和dLdSin,或两者都不包括。% -对于有多个输入的层,将X和dLdX替换为% X1,…,XN而且dLdX1,...,dLdXN, respectively, where N is输入数量的%。% -对于有多个输出的层,将Z和dlZ替换为% Z1,…,Z米而且dLdZ,...,dLdZM, respectively, where M is the输出数的%。% -对于有多个可学习参数的层,替换% dLdW with dLdW1,…,dLdWP, where P is the number of%可学习参数。% -对于有多个状态参数的层,替换dLdSin% and dLdSout with dLdSin1,…、dLdSinK和% dLdSout1,…dldSoutK, respectively, where K is the number状态参数的%。在这里定义层反向函数。结束结束结束

命名层和指定超类

首先,给图层起一个名字。在类文件的第一行中,替换现有的名称myLayerpreluLayer

classdefpreluLayer < nnet.layer.Layer可格式化(可选)...结束

如果没有指定反向函数,则默认情况下,层函数接收无格式dlarray对象作为输入。指定该层接收格式化dlarray对象作为格式化的输入和输出dlarray对象,也继承自nnet.layer.Formattable类在定义自定义层时。

该层不需要可格式化的输入,因此删除可选的输入nnet.layer.Formattable超类。

classdefpreluLayer < nnet.layer.Layer...结束

接下来,重命名myLayer构造函数中的第一个函数方法Section),使其具有与层相同的名称。

方法函数图层= preluLayer()…结束...结束

保存图层

保存层类文件在一个新的文件名为preluLayer.m.文件名必须与层名匹配。要使用该层,必须将文件保存在当前文件夹或MATLAB路径下的文件夹中。

声明属性和可学习参数

属性中声明层属性属性方法中列出可学习参数,并声明这些参数属性(可学的)部分。

默认情况下,自定义中间层具有这些属性。中不声明这些属性属性部分。

财产 描述
名字 层名,指定为字符向量或字符串标量。为数组输入时,trainNetworkassembleNetworklayerGraph,dlnetwork函数自动为层分配名称名字设置为
描述

层的单行描述,指定为字符串标量或字符向量。控件中显示该层时,将显示此描述数组中。

如果您没有指定层描述,那么软件将显示层类名称。

类型

层的类型,指定为字符向量或字符串标量。的价值类型控件中显示该层时显示数组中。

如果您没有指定层类型,那么软件将显示层类名称。

NumInputs 层的输入数量,指定为正整数。如果您不指定这个值,那么软件将自动设置NumInputsInputNames.缺省值为1。
InputNames 输入层的名称,指定为字符向量的单元格数组。如果不指定此值和NumInputs大于1,则软件自动设置InputNames{“三机”,…,“客栈”},在那里N等于NumInputs.默认值为{'在'}
NumOutputs 层的输出数量,指定为正整数。如果您不指定这个值,那么软件将自动设置NumOutputsOutputNames.缺省值为1。
OutputNames 输出层的名称,指定为字符向量的单元格数组。如果不指定此值和NumOutputs大于1,则软件自动设置OutputNames{着干活,…,“outM”},在那里等于NumOutputs.默认值为{“出”}

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

提示

如果您正在创建具有多个输入的层,则必须设置NumInputsInputNames层构造函数中的属性。如果您正在创建具有多个输出的层,则必须设置NumOutputsOutputNames层构造函数中的属性。有关示例,请参见定义具有多个输入的自定义深度学习层

PReLU层不需要任何附加属性,因此可以删除属性部分。

PReLU层只有一个可学习参数,即缩放系数一个.方法中声明此可学习参数属性(可学的)节并调用该参数α

属性(可学的)%层可学习参数%结垢系数α结束

创建构造函数

创建构造层和初始化层属性的函数。指定创建该层所需的任何变量作为构造函数的输入。

PReLU层构造函数需要一个输入参数(通道数)和一个可选参数(层名)。通道的数量指定了可学习参数的大小α.指定两个名为numChannels而且arg游戏preluLayer函数,分别对应于通道数和可选输入参数。在函数的顶部添加注释,解释函数的语法。

函数图层= preluLayer(numChannels,args)% layer = preluLayer(numChannels)创建一个PReLU层%使用numChannels通道。% layer = preluLayer(numChannels,Name= Name)还指定%层名...结束

初始化图层属性

初始化图层属性,包括构造函数中的可学习参数。替换注释%层构造函数在这里使用初始化层属性的代码。

类解析输入参数参数块,并设置名字财产。

参数numChannels参数。Name =""结束设置层名。层。Name =arg游戏.N一个me;

属性为该层提供一行描述描述层的属性。设置描述描述层的类型和它的大小。

设置层描述。层。描述=“PReLU with”+ numChannels +“通道”

对于PReLU层,当输入值为负值时,该层将输入的每个通道乘以对应的通道α.初始化可学习参数α是一个大小为1乘1乘-的随机向量numChannels.第三个维度指定为sizenumChannels,该层可以使用forward函数中输入的逐元素乘法。α是层对象的属性,所以你必须分配矢量层。α

初始化缩放系数。层。α=rand([1 1 numChannels]);

查看完成的构造函数。

函数图层= preluLayer(numChannels,args)% layer = preluLayer(numChannels)创建一个PReLU层%使用numChannels通道。% layer = preluLayer(numChannels,Name= Name)还指定%层名。参数numChannels参数。Name =""结束设置层名。层。Name =name;设置层描述。层。描述=“PReLU with”+ numChannels +“通道”初始化缩放系数。层。α=rand([1 1 numChannels]);结束

使用这个构造函数,命令preluLayer (Name = " prelu ")创建一个PReLU层,有三个通道和名称“prelu”

创建正向函数

创建在预测时间和训练时间使用的层正向函数。

创建一个名为预测在层中向前传播数据预测的时间并输出结果。

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

  • Z = predict(图层,X)转发输入数据X通过层并输出结果Z,在那里只有一个输入,一个输出。

  • [Z,状态]=预测(层,X)还输出更新后的状态参数状态,在那里只有一个状态参数。

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

  • 对于有多个输入的层,替换XX1,…,XN,在那里N是输入的数量。的NumInputs属性必须匹配N

  • 对于有多个输出的层,替换ZZ1,…,ZM评选,在那里是输出的数量。的NumOutputs属性必须匹配

  • 对于具有多个状态参数的层,替换状态state1,…,stateK,在那里K是状态参数的个数。

提示

如果层的输入数量可以变化,那么使用变长度输入宗量而不是X1,…,XN.在这种情况下,变长度输入宗量是单元格数组的输入,在哪里变长度输入宗量{我}对应于西

如果输出的数量可以变化,那么使用varargout而不是Z1,…,锌.在这种情况下,varargout是单元格数组的输出,在哪里varargout {j}对应于Zj

提示

如果自定义层有dlnetwork对象获取可学习参数,然后在预测函数的自定义层,使用预测函数为dlnetwork.使用dlnetwork对象预测功能确保软件使用正确的层操作进行预测。

因为PReLU层只有一个输入和一个输出,所以预测对于PReLU层是Z = predict(图层,X)

默认情况下,该层使用预测为训练时的正向函数。若要在训练时使用不同的前向函数,或保留自定义后向函数所需的值,还必须创建名为向前

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

层的输入 输入的大小 观察维度
特征向量 c——- - - - - -N,在那里c对应于通道数和N是观测的数量。 2
二维图像 h——- - - - - -w——- - - - - -c——- - - - - -N,在那里hw,c分别对应图像的高度、宽度和通道数,和N是观测的数量。 4
三维图像 h——- - - - - -w——- - - - - -d——- - - - - -c——- - - - - -N,在那里hwd,c分别对应三维图像的高度、宽度、深度和通道数,和N是观测的数量。 5
向量序列 c——- - - - - -N——- - - - - -年代,在那里c是序列特征的数量,N是观察数,和年代是序列长度。 2
二维图像序列 h——- - - - - -w——- - - - - -c——- - - - - -N——- - - - - -年代,在那里hw,c分别对应图像的高度、宽度和通道数,N是观察数,和年代是序列长度。 4
三维图像序列 h——- - - - - -w——- - - - - -d——- - - - - -c——- - - - - -N——- - - - - -年代,在那里hwd,c分别对应三维图像的高、宽、深、通道数,N是观察数,和年代是序列长度。 5

对于输出序列的层,这些层可以输出任意长度的序列或输出没有时间维度的数据。方法训练输出序列的网络时,请注意trainNetwork函数时,输入和输出序列的长度必须匹配。

向前函数通过的层向前传播数据培训时间并且还输出一个内存值。

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

  • Z =向前(层,X)转发输入数据X通过层并输出结果Z,在那里只有一个输入,一个输出。

  • [Z,状态]= forward(层,X)还输出更新后的状态参数状态,在那里只有一个状态参数。

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

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

  • 对于有多个输入的层,替换XX1,…,XN,在那里N是输入的数量。的NumInputs属性必须匹配N

  • 对于有多个输出的层,替换ZZ1,…,ZM评选,在那里是输出的数量。的NumOutputs属性必须匹配

  • 对于具有多个状态参数的层,替换状态state1,…,stateK,在那里K是状态参数的个数。

提示

如果层的输入数量可以变化,那么使用变长度输入宗量而不是X1,…,XN.在这种情况下,变长度输入宗量是单元格数组的输入,在哪里变长度输入宗量{我}对应于西

如果输出的数量可以变化,那么使用varargout而不是Z1,…,锌.在这种情况下,varargout是单元格数组的输出,在哪里varargout {j}对应于Zj

提示

如果自定义层有dlnetwork对象获取可学习参数,然后在向前函数的自定义层,使用向前的功能dlnetwork对象。使用dlnetwork对象向前功能确保软件使用正确的层操作进行训练。

PReLU操作由

f x x 如果 x > 0 α x 如果 x 0

在哪里 x 输入是非线性激活吗f频道, α 是控制负部分斜率的系数。下标 α 表示非线性激活在不同通道上可能不同。

预测.在预测,输入X对应于x在方程中。输出Z对应于 f x .PReLU层不需要内存或不同的前向函数进行训练,因此可以删除向前函数。在函数的顶部添加注释,解释函数的语法。

提示

如果使用函数来预分配数组0,则必须保证这些数组的数据类型与层函数输入一致。若要创建与另一个数组具有相同数据类型的零数组,请使用“喜欢”选择0.例如,初始化一个大小为0的数组深圳使用与数组相同的数据类型X,使用Z = 0 (sz,"like",X)

函数Z = predict(图层,X)% Z = predict(layer, X)将输入数据X通过并输出结果Z。Z = max(X,0) +层。* min(0,X);结束

因为预测函数只使用支持的函数金宝appdlarray对象,定义落后的功能是可选的。获取支持的函数列表金宝appdlarray对象,看到支持dlarray的函数列表金宝app

完成一层

查看完成的层类文件。

classdefpreluLayer < nnet.layer.Layer自定义PReLU层示例。属性(可学的)%层可学习参数%结垢系数α结束方法函数图层= preluLayer(numChannels,args)% layer = preluLayer(numChannels)创建一个PReLU层%使用numChannels通道。% layer = preluLayer(numChannels,Name= Name)还指定%层名。参数numChannels参数。Name =""结束设置层名。层。Name =name;设置层描述。层。描述=“PReLU with”+ numChannels +“通道”初始化缩放系数。层。α=rand([1 1 numChannels]);结束函数Z = predict(图层,X)% Z = predict(layer, X)将输入数据X通过并输出结果Z。Z = max(X,0) +层。* min(0,X);结束结束结束

GPU的兼容性

如果层转发功能完全支持金宝appdlarray对象,那么该层是GPU兼容的。否则,为了与GPU兼容,层函数必须支持类型的输入和返回输出金宝appgpuArray(并行计算工具箱)

许多MATLAB内置函数支持金宝appgpuArray(并行计算工具箱)而且dlarray输入参数。获取支持的函数列表金宝appdlarray对象,看到支持dlarray的函数列表金宝app.有关在GPU上执行的函数的列表,请参见在图形处理器上运行MATLAB函数(并行计算工具箱)要使用GPU进行深度学习,还必须有支持GPU的设备。金宝app有关受支持设备的信息,请参见金宝appGPU支金宝app持版本(并行计算工具箱)有关在MATLAB中使用gpu的更多信息,请参见MATLAB中的GPU计算(并行计算工具箱)

本例中用到的MATLAB函数预测所有的支金宝app持dlarray对象,所以该层是GPU兼容的。

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

检查自定义层的层有效性preluLayer

自定义层preluLayer,作为支持文件附在此示例后面,它对输入数据应用PReLU操作。金宝app要访问此层,请将此示例作为活动脚本打开。

创建一个层的实例,并检查它的有效性使用checkLayer.将有效的输入大小指定为该层的典型输入的单个观察值的大小。该层期望4-D阵列输入,其中前三个维度对应于前一层输出的高度、宽度和通道数量,第四个维度对应于观测结果。

指定观测值输入的典型大小,并设置ObservationDimension选项4。

图层= preluLayer(20);validInputSize = [24 24 20];checkLayer(层、validInputSize ObservationDimension = 4)
跳过GPU测试。没有找到兼容的GPU设备。跳过代码生成兼容性测试。要检查代码生成层的有效性,请指定'CheckCodegenCompatibility'和'ObservationDimension'选项。运行nnet.checklayer.TestLayerWithoutBackward .......... ........完成nnet.checklayer.TestLayerWithoutBackward __________测试总结:18通过,0失败,0不完整,10跳过。时间:1.9312秒。

在这里,函数不会检测到该层的任何问题。

在网络中包含自定义层

您可以像使用“深度学习工具箱”中的任何其他层一样使用自定义层。本节展示如何使用前面创建的PReLU层创建和训练用于数字分类的网络。

加载示例训练数据。

[XTrain,YTrain] = digitTrain4DArrayData;

创建一个包含自定义层的层数组preluLayer,附上实例作为支持文件。金宝app要访问此层,请将此示例作为活动脚本打开。

layers = [imageInputLayer([28 28 1]) convolution2dLayer(5,20) batchNormalizationLayer preluLayer(20) fullyConnectedLayer(10) softmaxLayer classificationLayer];

设置训练选项,训练网络。

选项= trainingOptions(“亚当”, MaxEpochs = 10);net = trainNetwork(XTrain,YTrain,图层,选项);
单CPU训练。初始化输入数据规范化。|========================================================================================| | 时代| |迭代时间| Mini-batch | Mini-batch |基地学习  | | | | ( hh: mm: ss) | | |丧失准确性  | |========================================================================================| | 1 | 1 |就是10.94% | | 3.0526 | 0.0010 | | 2 | 50 | 00:00:08 | 71.88% | 0.8377 | 0.0010 | | 3 | 100 | 00:00:16 | 85.94% | 0.4878 | 0.0010 | | 150 | | 00:00:23 | | 0.4068 | 0.0010 88.28%| | 6 | 200 | 00:00:32 | 96.09% | 0.1691 | 0.0010 | | 250 | | 00:00:43 | 96.88% | 0.1369 | 0.0010 | | 300 | | 00:00:53 | 99.22% | 0.0744 | 0.0010 | | 350 | | 00:01:01 | 99.22% | 0.0589 | 0.0010 | | 390 | | 00:01:07 | | 0.0469 | 0.0010 100.00%  | |========================================================================================| 培训完成:马克思时代完成。

通过对新数据的预测和计算精度来评估网络性能。

[XTest,YTest] = digitTest4DArrayData;YPred = category (net,XTest);accuracy = mean(YTest==YPred)
准确度= 0.9178

参考文献

[1]“深入研究整流器:在ImageNet分类上超越人类水平的性能。”2015年IEEE计算机视觉国际会议(ICCV)1026 - 34。圣地亚哥,智利:IEEE, 2015。https://doi.org/10.1109/ICCV.2015.123。

另请参阅

|||||||||

相关的话题