主要内容

定义具有多个输入的自定义深度学习层

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

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

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

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

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

  4. 创建初始化函数(可选)-指定软件初始化网络时如何初始化可学习参数和状态参数。如果没有指定初始化函数,则软件在初始化网络时不会初始化参数。

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

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

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

这个例子展示了如何创建一个加权加法层,这是一个具有多个输入和可学习参数的层,并在卷积神经网络中使用它。加权加法层按元素扩展并添加来自多个神经网络层的输入。

中间层模板

在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状态参数的%。在这里定义层反向函数。结束结束结束

命名层和指定超类

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

classdefweightedAdditionLayer < nnet.layer.Layer%……& nnet.layer. formatable…%(可选)& nnet.layer.Acceleratable %(可选)...结束

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

该层函数支持加速,因此也继承自金宝appnnet.layer.Acceleratable.有关加速自定义层函数的详细信息,请参见自定义层函数加速.该层不需要可格式化的输入,因此删除可选的输入nnet.layer.Formattable超类。

classdefweightedAdditionLayer < nnet.layer.Layer...& nnet.layer.Acceleratable...结束

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

方法函数layer = weightedAdditionLayer()…结束...结束

保存图层

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

声明属性和可学习参数

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

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

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

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

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

类型

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

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

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

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

提示

如果您正在创建具有多个输入的层,则必须设置NumInputsInputNames层构造函数中的属性。如果您正在创建具有多个输出的层,则必须设置NumOutputsOutputNames层构造函数中的属性。

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

加权加法层只有一个可学习参数,即权重。方法中声明此可学习参数属性(可学的)节并调用该参数权重

属性(可学的)%层可学习参数比例系数权重结束

创建构造函数

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

加权加法层构造函数需要两个输入:层的输入数量和层名。该层的输入数量指定了可学习参数的大小权重.指定两个名为numInputs而且名字weightedAdditionLayer函数。在函数的顶部添加注释,解释函数的语法。

函数layer = weightedAdditionLayer(numInputs,name)% layer = weightedAdditionLayer(numInputs,name)创建一个%加权加法层,并指定输入的数量%和层名。...结束

初始化图层属性

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

设置NumInputs属性设置为输入参数numInputs

设置输入数量。层。NumInputs = numInputs;

设置名字属性设置为输入参数名字

设置层名。层。名字=名字;

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

设置层描述。层。描述=加权加法+ numInputs +...“输入”

加权加法层将每一层输入乘以中相应的系数权重并将结果值相加。初始化可学习参数权重是一个大小为1 × -的随机向量numInputs权重是层对象的属性,所以你必须分配矢量层。Weights

初始化层权重层。Weights = rand(1,numInputs);

查看完成的构造函数。

函数layer = weightedAdditionLayer(numInputs,name)% layer = weightedAdditionLayer(numInputs,name)创建一个%加权加法层,并指定输入的数量%和层名。设置输入数量。层。NumInputs = numInputs;设置层名。层。名字=名字;设置层描述。层。描述=加权加法+ numInputs +...“输入”初始化层权重。层。Weights = rand(1,numInputs);结束

使用这个构造函数,命令“添加”weightedAdditionLayer (3)创建带有三个输入和名称的加权加法层“添加”

由于构造函数不需要来自层输入数据的信息来初始化可学习参数,因此定义初始化功能是可选的。对于需要来自输入数据的信息来初始化可学习参数的层,例如,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对象预测函数使用适当的层操作进行预测。如果dlnetwork具有状态参数,则还返回网络状态。

由于加权加法层只有一个输出和可变数量的输入,因此预测对于加权加法层是Z = predict(图层,varargin),在那里变长度输入宗量{我}对应于西对于正整数小于或等于NumInputs

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

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

层的输入 输入的大小 观察维度
特征向量 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对象向前函数使用适当的层操作进行训练。

加权加法层的正向函数为

f X 1 ... X n 1 n W X

在哪里X(1)、……X(n)对应于层输入和W1、……Wn是层权值。

中实现转发函数预测.在预测,输出Z对应于 f X 1 ... X n .加权加法层不需要内存或不同的前向函数进行训练,因此可以删除向前函数。在函数的顶部添加注释,解释函数的语法。

提示

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

函数Z = predict(图层,varargin)% Z = predict(层,X1,…,Xn)转发输入数据X1,%……,Xn通过层并输出结果Z.X = varargin;W = layer.Weights;初始化输出X1 = x {1};sz = size(X1);Z = 0 (sz,“喜欢”X1);加权加法I = 1:层。NumInputsZ=Z+ W(i)*X{i};结束结束

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

完成一层

查看完成的层类文件。

classdefweightedAdditionLayer < nnet.layer.Layer…& nnet.layer.Acceleratable自定义加权加法层示例。属性(可学的)%层可学习参数比例系数权重结束方法函数layer = weightedAdditionLayer(numInputs,name)% layer = weightedAdditionLayer(numInputs,name)创建一个%加权加法层,并指定输入的数量%和层名。设置输入数量。层。NumInputs = numInputs;设置层名。层。名字=名字;设置层描述。层。描述=加权加法+ numInputs +...“输入”初始化层权重。层。Weights = rand(1,numInputs);结束函数Z = predict(图层,varargin)% Z = predict(层,X1,…,Xn)转发输入数据X1,%……,Xn通过层并输出结果Z.X = varargin;W = layer.Weights;初始化输出X1 = x {1};sz = size(X1);Z = 0 (sz,“喜欢”X1);加权加法I = 1:层。NumInputsZ=Z+ W(i)*X{i};结束结束结束结束

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兼容的。

多输入层有效性检查

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

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

指定观察值和集合的典型输入大小“ObservationDimension”4。

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

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

在网络中使用自定义加权加法层

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

加载示例训练数据。

[XTrain,TTrain] = digitTrain4DArrayData;

创建一个包括自定义层的层图weightedAdditionLayer,作为支持文件附在本例中。金宝app

图层= [imageInputLayer([28 28 1]) convolution2dLayer(5,20) relullayer (“名字”“relu1”20岁的)convolution2dLayer (3“填充”,1) relullayer卷积2dlayer (3,20,“填充”,1) relullayer加权附加层(2)“添加”) fullyConnectedLayer(10) softmaxLayer classificationLayer];lgraph = layerGraph(图层);lgraph = connectLayers(“relu1”“添加/ in2”);

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

选项= trainingOptions(“亚当”“MaxEpochs”10);net = trainNetwork(XTrain,TTrain,lgraph,options);
单CPU训练。初始化输入数据规范化。|========================================================================================| | 时代| |迭代时间| Mini-batch | Mini-batch |基地学习  | | | | ( hh: mm: ss) | | |丧失准确性  | |========================================================================================| | 1 | 1 |就是12.50% | | 2.2951 | 0.0010 | | 2 | 50 | 00:00:08 | 72.66% | 0.7877 | 0.0010 | | 3 | 100 | 00:00:14 | 89.84% | 0.2988 | 0.0010 | | 150 | | 00:00:22 | | 0.1525 | 0.0010 95.31%| | 6 | 200 | 00:00:28 | 99.22% | 0.0387 | 0.0010 | | 250 | | 00:00:34 | 99.22% | 0.0316 | 0.0010 | | 300 | | 00:00:40 | 100.00% | 0.0092 | 0.0010 | | 350 | | 00:00:48 | 99.22% | 0.0359 | 0.0010 | | 390 | | 00:00:52 | | 0.0061 | 0.0010 100.00%  | |========================================================================================| 培训完成:马克思时代完成。

查看加权加法层学习到的权重。

net.Layers .Weights (8)
ans =1x2单行向量1.0219 - 0.9999

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

[XTest,TTest] = digitTest4DArrayData;YPred = category (net,XTest);精度=平均值(TTest==YPred)
准确度= 0.9876

另请参阅

||||||||||

相关的话题