定义具有可学习参数的自定义深度学习层
如果深度学习工具箱™没有为您的任务提供所需的层,那么您可以使用此示例作为指导定义自己的自定义层。有关内置层的列表,请参见深度学习层列表.
要定义自定义深度学习层,您可以使用本例中提供的模板,该模板将带您完成以下步骤:
命名层-给层一个名字,这样你可以在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%……& nnet.layer. formatable…%(可选)& nnet.layer.Acceleratable %(可选)属性%(可选)图层属性。在这里声明层属性。结束属性(可学的)%(可选)层可学习参数。在这里声明可学习参数。结束属性(状态)%(可选)层状态参数。在这里声明状态参数。结束属性(可学的,状态)%(可选)嵌套dlnetwork对象,两者都可学习%参数和状态参数。在这里用可学习和状态参数声明嵌套网络。结束方法函数图层= myLayer()(可选)创建myLayer。此函数必须与类名称相同。在这里定义层构造函数。结束函数图层=初始化(图层,布局)(可选)初始化层可学习和状态参数。%%的输入:% layer -初始化的层% layout -数据布局,指定为networkDataLayout%的对象%%输出:% layer -初始化层%% -对于有多个输入的图层,将layout替换为% layout1,…,layoutN, where N is the number of inputs.定义层初始化函数。结束函数[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%……& nnet.layer. formatable…%(可选)& nnet.layer.Acceleratable %(可选)...结束
如果没有指定反向函数,则默认情况下,层函数接收无格式dlarray
对象作为输入。指定该层接收格式化dlarray
对象作为格式化的输入和输出dlarray
对象,也继承自nnet.layer.Formattable
类在定义自定义层时。
该层函数支持加速,因此也继承自金宝appnnet.layer.Acceleratable
.有关加速自定义层函数的详细信息,请参见自定义层函数加速.该层不需要可格式化的输入,因此删除可选的输入nnet.layer.Formattable
超类。
classdefpreluLayer < nnet.layer.Layer...& nnet.layer.Acceleratable...结束
接下来,重命名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层构造函数需要一个可选参数(层名)。指定一个名为arg游戏
在preluLayer
函数,该函数对应于可选的名称-值实参。在函数的顶部添加注释,解释函数的语法。
函数图层= preluLayer(args)创建一个PReLU层。%% layer = preluLayer(Name= Name)还指定%层名...结束
初始化图层属性
在构造函数中初始化层属性。替换注释%层构造函数在这里
使用初始化层属性的代码。不要在构造函数中初始化可学习或状态参数,在初始化
函数来代替。
类解析输入参数参数
块,并设置的名字
财产。
参数arg游戏。的名字="";结束设置层名。层。Name =arg游戏。的名字;
属性为该层提供一行描述描述
层的属性。设置描述描述层的类型。
设置层描述。层。描述=“PReLU”;
查看完成的构造函数。
函数图层= preluLayer(args)创建一个PReLU层。%% layer = preluLayer(Name= Name)还指定%层名。参数arg游戏。的名字="";结束设置层名。层。Name =arg游戏。的名字;设置层描述。层。描述=“PReLU”;结束
使用这个构造函数,命令preluLayer (Name = " prelu ")
创建一个PReLU层“prelu”
.
命令功能
创建在软件初始化网络时初始化可学习层和状态参数的函数。确保该函数仅在属性为空时初始化可学习参数和状态参数,否则当您从MAT文件加载网络时,软件可能会覆盖。
初始化可学习参数α
,生成与输入数据通道数相同的随机向量。
因为在网络准备好使用之前,输入数据的大小是未知的,所以必须创建一个initialize函数,使用初始化可学习参数和状态参数networkDataLayout
软件提供给函数的对象。网络数据布局对象包含有关预期输入数据的大小和格式的信息。创建一个initialize函数,使用大小和格式信息初始化可学习参数和状态参数,使它们具有正确的大小。
可学习参数α
具有与输入观测数据相同的维度数,其中通道维度与输入数据的通道维度大小相同,其余维度为单维度。创建一个初始化
函数从输入中提取大小和格式信息networkDataLayout
对象初始化可学习参数α
有相同数量的通道。
函数图层=初始化(图层,布局)% layer = initialize(layer,layout)初始化图层%可学习参数使用指定的输入布局。跳过非空参数的初始化。如果~ isempty (layer.Alpha)返回结束输入数据大小。sz = layout.Size;Ndims =数字(sz);查找通道数。Idx = finddim(布局,“C”);numChannels = sz(idx);初始化Alpha。szAlpha = ones(1,ndims);szAlpha(idx) = numChannels;层。α=rand(szAlpha);结束
创建正向函数
创建在预测时间和训练时间使用的层正向函数。
创建一个名为预测
在层中向前传播数据预测的时间并输出结果。
的预测
函数语法取决于层的类型。
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
对象预测
函数使用适当的层操作进行预测。如果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…& nnet.layer.Acceleratable自定义PReLU层示例。属性(可学的)%层可学习参数%结垢系数α结束方法函数图层= preluLayer(args)创建一个PReLU层。%% layer = preluLayer(Name= Name)还指定%层名。参数arg游戏。的名字="";结束设置层名。层。Name =arg游戏。的名字;设置层描述。层。描述=“PReLU”;结束函数图层=初始化(图层,布局)% layer = initialize(layer,layout)初始化图层%可学习参数使用指定的输入布局。跳过非空参数的初始化。如果~ isempty (layer.Alpha)返回结束输入数据大小。sz = layout.Size;Ndims =数字(sz);查找通道数。Idx = finddim(布局,“C”);numChannels = sz(idx);初始化Alpha。szAlpha = ones(1,ndims);szAlpha(idx) = numChannels;层。α=rand(szAlpha);结束函数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计算要求(并行计算工具箱).有关在MATLAB中使用gpu的更多信息,请参见MATLAB中的GPU计算(并行计算工具箱).
本例中用到的MATLAB函数预测
所有的支金宝app持dlarray
对象,所以该层是GPU兼容的。
检查自定义层使用的有效性checkLayer
检查自定义层的层有效性preluLayer
.
自定义层preluLayer
,作为支持文件附在此示例后面,它对输入数据应用PReLU操作。金宝app要访问此层,请将此示例作为活动脚本打开。
创建该层的一个实例。
图层= preluLayer;
因为层有一个自定义的初始化函数,初始化层使用networkDataFormat
对象,该对象指定对层的典型输入的单个观察的预期输入大小和格式。
指定有效的输入大小[24 24 20]
,其中尺寸对应于前一层输出的高度、宽度和通道数。
validInputSize = [24 24 20];layout = networkDataLayout(validInputSize,“SSC”);图层=初始化(图层,布局);
检查层有效性使用checkLayer
.将有效的输入大小指定为用于初始化层的大小。当您通过网络传递数据时,该层需要4-D阵列输入,其中前三个维度对应于前一层输出的高度、宽度和通道数量,第四个维度对应于观测值。
指定观测值输入的典型大小,并设置ObservationDimension
选项4。
checkLayer(层、validInputSize ObservationDimension = 4)
跳过GPU测试。没有找到兼容的GPU设备。跳过代码生成兼容性测试。要检查代码生成层的有效性,请指定'CheckCodegenCompatibility'和'ObservationDimension'选项。运行nnet.checklayer.TestLayerWithoutBackward .......... ........完成nnet.checklayer.TestLayerWithoutBackward __________测试总结:18通过,0失败,0不完整,10跳过。时间流逝:0.22352秒。
该函数不检测该层的任何问题。
在网络中包含自定义层
您可以像使用“深度学习工具箱”中的任何其他层一样使用自定义层。本节展示如何使用前面创建的PReLU层创建和训练用于数字分类的网络。
加载示例训练数据。
[XTrain,YTrain] = digitTrain4DArrayData;
创建一个包含自定义层的层数组preluLayer
,附上实例作为支持文件。金宝app要访问此层,请将此示例作为活动脚本打开。
layers = [imageInputLayer([28 28 1]) convolution2dLayer(5,20) batchNormalizationLayer preluLayer fullyConnectedLayer(10) softmaxLayer classificationLayer];
设置训练选项,训练网络。
选项= trainingOptions(“亚当”, MaxEpochs = 10);net = trainNetwork(XTrain,YTrain,图层,选项);
单CPU训练。初始化输入数据规范化。|========================================================================================| | 时代| |迭代时间| Mini-batch | Mini-batch |基地学习 | | | | ( hh: mm: ss) | | |丧失准确性 | |========================================================================================| | 1 | 1 |就是9.38% | | 2.8873 | 0.0010 | | 2 | 50 | 00:00:02 | 79.69% | 0.7222 | 0.0010 | | 3 | 100 | 00:00:05 | 86.72% | 0.4213 | 0.0010 | | 150 | | 00:00:08 | 94.53% | 0.2129 | 0.0010 ||6 | 200 | 00:00:11 | 94.53% | 0.1884 | 0.0010 | | 7 | 250 | 00:00:14 | 100.00% | 0.0847 | 0.0010 | | 8 | 300 | 00:00:17 | 100.00% | 0.0470 | 0.0010 | | 9 | 350 | 00:00:19 | 100.00% | 0.0299 | 0.0010 | | 10 | 390 | 00:00:21 | 100.00% | 0.0375 | 0.0010 | |========================================================================================| Training finished: Max epochs completed.
通过对新数据的预测和计算精度来评估网络性能。
[XTest,YTest] = digitTest4DArrayData;YPred = category (net,XTest);accuracy = mean(YTest==YPred)
准确度= 0.9534
参考文献
[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
|networkDataLayout