主要内容

定义用于代码生成的自定义深度学习层

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

要定义一个自定义的深度学习层,你可以使用本例中提供的模板,它将带你通过以下步骤:

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

  2. 声明层属性-指定层的属性和哪些参数是在训练中学习的。

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

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

  5. 创建向后函数(可选)—指定损失相对于输入数据和可学习参数的导数(向后传播)。如果不指定向后函数,则向前函数必须支持万博1manbetxdlarray对象。

要创建一个支持代码生成的自定义层:万博1manbetx

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

  • 的输入预测必须:

    • 一致的维度。每个输入必须具有相同数量的维度。

    • 批量大小一致。每个输入必须具有相同的批大小。

  • 的输出预测尺寸和批大小必须与层输入一致。

  • 非标量属性必须具有单、双或字符数组类型。

  • 标量属性必须具有数字、逻辑或字符串类型。

代码生成只支持带有二维图像输入的万博1manbetx中间层。

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

这图[1]比较ReLU和PReLU层函数。

带有可学习参数模板的图层

复制层与可学习的参数模板到一个新的文件在MATLAB。此模板概述了具有可学习参数的层的结构,并包括定义层行为的函数。

classdefmyLayer < nnet.layer.Layer% & net.layer. format(可选)属性%(可选)图层属性。%图层属性到这里。结束属性(可学的)%(可选)层可学习参数。%图层学习参数到这里。结束方法函数层= myLayer ()%(可选)创建一个myLayer。%该函数必须与类名相同。%层构造函数在这里。结束函数[Z1,…,Zm] = predict(layer, X1,…,Xn)%在预测时间通过层转发输入数据%输出结果。%的输入:% layer -要转发的层% X1,…,Xn- Input data%输出:% Z1,…,Z米- Outputs of layer forward function%用于预测的层前向函数在这里。结束函数(Z1,…,Zm评选、内存)=前进(层,X1,…,Xn)%(可选)在训练时通过层转发输入数据%时间并输出结果和一个内存值。%的输入:% layer -要转发的层% X1,…,Xn- Input data%输出:% Z1,…,Z米- Outputs of layer forward function% memory -自定义向后传播的内存值%用于训练的图层正向功能在这里。结束函数[dLdX1,…,dLdXn, dLdW1,…,dLdWk] =...向后(层,X1,…,Xn Z1,…,Zm评选,dLdZ1,…,dLdZm,内存)%(可选)反向传播损失的导数%函数通过层。%的输入:%图层-图层向后传播通过% X1,…,Xn- Input data% Z1,…,Z米- Outputs of layer forward function% dLdZ1,…,dLdZm - Gradients propagated from the next layers% memory - forward函数的内存值%输出:% dLdX1,…,dLdXn - Derivatives of the loss with respect to the%的输入% dLdW1,…,dLdWk - Derivatives of the loss with respect to each%可学的参数%图层向后函数在这里。结束结束结束

名字层

首先,给图层命名。在类文件的第一行中,替换现有的名称myLayercodegenPreluLayer并添加一个注释来描述这个层。

classdefcodegenPreluLayer < nnet.layer.Layer%示例自定义PReLU层与代码生成支持。万博1manbetx...结束

接下来,重命名myLayer函数中的第一个函数方法Section),以便它与图层具有相同的名称。

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

保存层

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

指定代码生成Pragma

添加% # codegen指令(或pragma)到层定义,以指示您打算为该层生成代码。添加此指令将指示MATLAB代码分析器帮助您诊断和修复在代码生成期间导致错误的违规。

classdefcodegenPreluLayer < nnet.layer.Layer%示例自定义PReLU层与代码生成支持。万博1manbetx% # codegen...结束

声明属性和可学习参数

属性中声明图层属性属性节中列出可学习参数并声明它们属性(可学的)部分。

默认情况下,自定义中间层有这些属性。

财产 描述
的名字 层名,指定为字符向量或字符串标量。若要在层图中包含层,必须指定非空的唯一层名。如果你用层和的名字被设置为'',然后软件在训练时自动为该层分配一个名称。
描述

层的一行描述,指定为字符向量或字符串标量。该描述出现在层显示在数组中。如果不指定层描述,则软件将显示层类名称。

类型 层的类型,指定为字符向量或字符串标量。的价值类型当层显示在数组中。如果不指定层类型,则软件将显示层类名称。
NumInputs 层的输入数,指定为正整数。如果您不指定此值,则软件将自动设置NumInputs到名字的数量InputNames.默认值为1。
InputNames 输入图层名称,指定为字符向量单元格数组。如果不指定该值和NumInputs大于1,则软件自动设置InputNames{“三机”,…,“客栈”},在那里N等于NumInputs.默认值为{'在'}
NumOutputs 层的输出数,指定为正整数。如果您不指定此值,则软件将自动设置NumOutputs到名字的数量OutputNames.默认值为1。
OutputNames 层的输出名称,指定为字符向量的单元格数组。如果不指定该值和NumOutputs大于1,则软件自动设置OutputNames{着干活,…,“outM”},在那里等于NumOutputs.默认值为{“出”}

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

提示

如果你正在创建一个有多个输入的图层,那么你必须设置NumInputsInputNames属性在层构造函数中。如果你正在创建一个有多个输出的图层,那么你必须设置NumOutputsOutputNames属性在层构造函数中。例如,请参见定义自定义深度学习层与多个输入

要支持万博1manbetx代码生成:

  • 非标量属性必须具有单、双或字符数组类型。

  • 标量属性必须为数字或具有逻辑或字符串类型。

PReLU层不需要任何额外的属性,所以您可以删除属性部分。

PReLU层只有一个可学习的参数,缩放系数一个.属性中声明这个可学习参数属性(可学的)分段并调用参数α

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

创建构造函数

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

PReLU层构造函数需要两个输入参数:预期输入数据的通道数量和层名。通道的数量指定了可学习参数的大小α.指定两个命名的输入参数numChannels的名字codegenPreluLayer函数。在函数的顶部添加注释,解释函数的语法。

函数layer = codegenPreluLayer(numChannels, name)% layer = codegenPreluLayer(numChannels)创建一个PReLU层% numChannels通道并指定层名。...结束

不支持代码生成万博1manbetx参数块。

初始化层属性

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

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

%设置图层名称。层。的名字=的名字;

给层一个单行描述通过设置描述属性的层。将描述设置为描述图层的类型和大小。

%设置图层描述。层。描述=“PReLU与“+ numChannels +“通道”

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

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

查看已完成的构造函数。

函数layer = codegenPreluLayer(numChannels, name)% layer = codegenPreluLayer(numChannels, name)创建一个PReLU% layer用于使用numChannels通道和指定的2-D图像输入%层名。%设置图层名称。层。的名字=的名字;%设置图层描述。层。描述=“PReLU与“+ numChannels +“通道”%初始化缩放系数。层。α=rand([1 1 numChannels]);结束

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

创建向前函数

创建用于预测时间和训练时间的层前向函数。

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

的语法预测(Z1,…,Zm评选)=预测(层,X1,…,Xn),在那里X1,…,Xnn层的输入和Z1,…,Zm评选层输出。的值n必须对应于NumInputsNumOutputs层的属性。

提示

如果输入的数量预测可以变化,然后使用变长度输入宗量而不是X1,…,Xn.在这种情况下,变长度输入宗量输入的单元格数组在哪里变长度输入宗量{我}对应于西.如果输出的数量可以变化,则使用varargout而不是Z1,…,Zm评选.在这种情况下,varargout输出的单元格数组在哪里varargout {j}对应于Zj

因为PReLU层只有一个输入和一个输出,for的语法预测对于PReLU层是Z =预测(层,X)

代码生成只支持2-D图像输入的自万博1manbetx定义中间层。的输入是h——- - - - - -w——- - - - - -c——- - - - - -N数组,hw,c分别对应图像的高度、宽度和通道数量,和N为观察次数。观察维度为4。

对于代码生成支持,所有层输入必须具有相同万博1manbetx的维数和批大小。

默认情况下,该层使用预测作为训练时的正向函数。要在训练时使用不同的前向函数,或保留自定义后向函数所需的值,还必须创建名为向前.该软件不生成代码向前函数,但必须与代码生成兼容。

向前函数将数据向前传播到层培训时间并输出一个内存值。

的语法向前(Z1,…,Zm评选、内存)=前进(层,X1,…,Xn),在那里X1,…,Xnn层的输入,Z1,…,Zm评选层的输出,内存是记忆层。

提示

如果输入的数量向前可以变化,然后使用变长度输入宗量而不是X1,…,Xn.在这种情况下,变长度输入宗量输入的单元格数组在哪里变长度输入宗量{我}对应于西.如果输出的数量可以变化,则使用varargout而不是Z1,…,Zm评选.在这种情况下,varargout输出的单元格数组在哪里varargout {j}对应于Zjj= 1,…,NumOutputsvarargout {NumOutputs + 1}对应于内存

PReLU运算由

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

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

预测.在预测,输入X对应于x在方程。输出Z对应于 f x

在函数的顶部添加注释,解释函数的语法。

提示

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

实现落后的当forward函数完全支持时,函数是可选的万博1manbetxdlarray输入。对于代码生成支持,万博1manbetx预测函数还必须支持数字输入。万博1manbetx

计算PReLU操作的输出的一种方法是使用以下代码。

Z = max(X,0) +图层。α。*分钟(0,X);
因为代码生成不支持通过万博1manbetx.*操作时,可以使用bsxfun函数来代替。
Z = max(X,0) + bsxfun(@times,图层。α,最小值(0,X));
然而,bsxfun不支持万博1manbetxdlarray输入。来实现预测函数,它支持代码生成和万博1manbetxdlarray输入,使用一个如果声明的isdlarray函数选择输入类型的适当代码。

函数Z =预测(层,X)% Z = predict(layer, X)将输入数据X通过%层并输出结果Z。如果isdlarray(X) Z = max(X,0) + layer。α。*分钟(0,X);其他的Z = max(X,0) + bsxfun(@times,图层。α,最小值(0,X));结束结束

因为预测功能完全支持万博1manbetxdlarray对象,定义落后的函数是可选的。获取支持的函数列表万博1manbetxdlarray对象,看到支持dlarray的函数列表万博1manbetx

完成一层

查看已完成的层类文件。

classdefcodegenPreluLayer < nnet.layer.Layer%示例自定义PReLU层与代码生成支持。万博1manbetx% # codegen属性(可学的)%层可学习的参数%比例系数α结束方法函数layer = codegenPreluLayer(numChannels, name)% layer = codegenPreluLayer(numChannels, name)创建一个PReLU% layer用于使用numChannels通道和指定的2-D图像输入%层名。%设置图层名称。层。的名字=的名字;%设置图层描述。层。描述=“PReLU与“+ numChannels +“通道”%初始化缩放系数。层。α=rand([1 1 numChannels]);结束函数Z =预测(层,X)% Z = predict(layer, X)将输入数据X通过%层并输出结果Z。如果isdlarray(X) Z = max(X,0) + layer。α。*分钟(0,X);其他的Z = max(X,0) + bsxfun(@times,图层。α,最小值(0,X));结束结束结束结束

检查代码生成兼容性层

检查自定义层的代码生成兼容性codegenPreluLayer

定义一个具有代码生成支持的自定义PReLU层。万博1manbetx要创建这个图层,保存文件codegenPreluLayer.m在当前文件夹中。

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

指定观察输入的典型大小,并设置“ObservationDimension”选项4。要检查代码生成兼容性,请设置“CheckCodegenCompatibility”选项真正的

层= codegenPreluLayer (20,“prelu”);validInputSize = [24 24 20];validInputSize checkLayer(层,“ObservationDimension”4“CheckCodegenCompatibility”,真正的)
跳过GPU测试。没有找到兼容的GPU设备。运行nnet.checklayer.TestLayerWithoutBackward .......... ........完成nnet.checklayer.TestLayerWithoutBackward __________测试摘要:18通过,0失败,0不完整,4跳过。时间:0.77122秒。

该函数不检测层的任何问题。

参考文献

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

另请参阅

|

相关的话题