定义具有可学习参数的自定义深度学习层
如果深度学习工具箱™没有为您的任务提供所需的层,那么您可以使用此示例作为指导定义自己的自定义层。有关内置层的列表,请参见深度学习层列表.
要定义自定义深度学习层,您可以使用本例中提供的模板,该模板将带您完成以下步骤:
命名层-给层一个名字,这样你可以在MATLAB中使用它®.
声明层属性——指定层的属性,包括可学习参数和状态参数。
创建一个构造函数(可选)-指定如何构造层并初始化其属性。如果没有指定构造函数,则在创建时,软件将初始化构造函数
名字
,描述
,类型
属性与[]
并设置层输入和输出的数量为1。创建前向函数——指定数据在预测时间和训练时间如何通过层向前传递(前向传播)。
创建重置状态函数(可选)-指定如何重置状态参数。
创建反向函数(可选)——指定损失相对于输入数据和可学习参数的导数(反向传播)。如果没有指定向后函数,则向前函数必须支持金宝app
dlarray
对象。
在定义层函数时,可以使用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状态参数的%。在这里定义层反向函数。结束结束结束
命名层和指定超类
首先,给图层起一个名字。在类文件的第一行中,替换现有的名称myLayer
与preluLayer
.
classdefpreluLayer < nnet.layer.Layer可格式化(可选)...结束
如果没有指定反向函数,则默认情况下,层函数接收无格式dlarray
对象作为输入。指定该层接收格式化dlarray
对象作为格式化的输入和输出dlarray
对象,也继承自nnet.layer.Formattable
类在定义自定义层时。
该层不需要可格式化的输入,因此删除可选的输入nnet.layer.Formattable
超类。
classdefpreluLayer < nnet.layer.Layer...结束
接下来,重命名myLayer
构造函数中的第一个函数方法
Section),使其具有与层相同的名称。
方法函数图层= preluLayer()…结束...结束
保存图层
保存层类文件在一个新的文件名为preluLayer.m
.文件名必须与层名匹配。要使用该层,必须将文件保存在当前文件夹或MATLAB路径下的文件夹中。
声明属性和可学习参数
属性中声明层属性属性
方法中列出可学习参数,并声明这些参数属性(可学的)
部分。
默认情况下,自定义中间层具有这些属性。中不声明这些属性属性
部分。
财产 | 描述 |
---|---|
名字 |
层名,指定为字符向量或字符串标量。为层 数组输入时,trainNetwork ,assembleNetwork ,layerGraph ,dlnetwork 函数自动为层分配名称名字 设置为” . |
描述 |
层的单行描述,指定为字符串标量或字符向量。控件中显示该层时,将显示此描述 如果您没有指定层描述,那么软件将显示层类名称。 |
类型 |
层的类型,指定为字符向量或字符串标量。的价值 如果您没有指定层类型,那么软件将显示层类名称。 |
NumInputs |
层的输入数量,指定为正整数。如果您不指定这个值,那么软件将自动设置NumInputs 到InputNames .缺省值为1。 |
InputNames |
输入层的名称,指定为字符向量的单元格数组。如果不指定此值和NumInputs 大于1,则软件自动设置InputNames 来{“三机”,…,“客栈”} ,在那里N 等于NumInputs .默认值为{'在'} . |
NumOutputs |
层的输出数量,指定为正整数。如果您不指定这个值,那么软件将自动设置NumOutputs 到OutputNames .缺省值为1。 |
OutputNames |
输出层的名称,指定为字符向量的单元格数组。如果不指定此值和NumOutputs 大于1,则软件自动设置OutputNames 来{着干活,…,“outM”} ,在那里米 等于NumOutputs .默认值为{“出”} . |
如果该层没有其他属性,则可以省略属性
部分。
提示
如果您正在创建具有多个输入的层,则必须设置NumInputs
或InputNames
层构造函数中的属性。如果您正在创建具有多个输出的层,则必须设置NumOutputs
或OutputNames
层构造函数中的属性。有关示例,请参见定义具有多个输入的自定义深度学习层.
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)
还输出更新后的状态参数状态
,在那里层
只有一个状态参数。
您可以调整具有多个输入,多个输出或多个状态参数的层的语法:
对于有多个输入的层,替换
X
与X1,…,XN
,在那里N
是输入的数量。的NumInputs
属性必须匹配N
.对于有多个输出的层,替换
Z
与Z1,…,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,在那里h,w,c分别对应图像的高度、宽度和通道数,和N是观测的数量。 | 4 |
三维图像 | h——- - - - - -w——- - - - - -d——- - - - - -c——- - - - - -N,在那里h,w,d,c分别对应三维图像的高度、宽度、深度和通道数,和N是观测的数量。 | 5 |
向量序列 | c——- - - - - -N——- - - - - -年代,在那里c是序列特征的数量,N是观察数,和年代是序列长度。 | 2 |
二维图像序列 | h——- - - - - -w——- - - - - -c——- - - - - -N——- - - - - -年代,在那里h,w,c分别对应图像的高度、宽度和通道数,N是观察数,和年代是序列长度。 | 4 |
三维图像序列 | h——- - - - - -w——- - - - - -d——- - - - - -c——- - - - - -N——- - - - - -年代,在那里h,w,d,c分别对应三维图像的高、宽、深、通道数,N是观察数,和年代是序列长度。 | 5 |
对于输出序列的层,这些层可以输出任意长度的序列或输出没有时间维度的数据。方法训练输出序列的网络时,请注意trainNetwork
函数时,输入和输出序列的长度必须匹配。
的向前
函数通过的层向前传播数据培训时间并且还输出一个内存值。
的向前
函数语法取决于层的类型:
Z =向前(层,X)
转发输入数据X
通过层并输出结果Z
,在那里层
只有一个输入,一个输出。[Z,状态]= forward(层,X)
还输出更新后的状态参数状态
,在那里层
只有一个状态参数。[__,memory] = forward(layer,X)
还返回自定义的内存值落后的
函数使用前面的任何语法。如果该层同时有一个自定义向前
函数和自定义落后的
函数,则forward函数必须返回一个内存值。
您可以调整具有多个输入,多个输出或多个状态参数的层的语法:
对于有多个输入的层,替换
X
与X1,…,XN
,在那里N
是输入的数量。的NumInputs
属性必须匹配N
.对于有多个输出的层,替换
Z
与Z1,…,ZM评选
,在那里米
是输出的数量。的NumOutputs
属性必须匹配米
.对于具有多个状态参数的层,替换
状态
与state1,…,stateK
,在那里K
是状态参数的个数。
提示
如果层的输入数量可以变化,那么使用变长度输入宗量
而不是X1,…,XN
.在这种情况下,变长度输入宗量
是单元格数组的输入,在哪里变长度输入宗量{我}
对应于西
.
如果输出的数量可以变化,那么使用varargout
而不是Z1,…,锌
.在这种情况下,varargout
是单元格数组的输出,在哪里varargout {j}
对应于Zj
.
提示
如果自定义层有dlnetwork
对象获取可学习参数,然后在向前
函数的自定义层,使用向前
的功能dlnetwork
对象。使用dlnetwork
对象向前
功能确保软件使用正确的层操作进行训练。
PReLU操作由
在哪里 输入是非线性激活吗f频道我, 是控制负部分斜率的系数。下标我在 表示非线性激活在不同通道上可能不同。
在预测
.在预测
,输入X
对应于x在方程中。输出Z
对应于
.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。
另请参阅
functionLayer
|checkLayer
|setLearnRateFactor
|setL2Factor
|getLearnRateFactor
|getL2Factor
|findPlaceholderLayers
|replaceLayer
|assembleNetwork
|PlaceholderLayer