第2章 神经网络计算
本章简要介绍神经网络的计算,特别是卷积神经网络,重点介绍理解和使用MatConvNet所需的概念。
2.1 概述
神经网络(NN)是将数据x(例如图像)映射到输出矢量y(例如图像标签)的函数。函数g = fL◦…◦f1是一系列简单函数fl的组合,称为计算块或图层。令x1,x2,…,xL为网络中每一层的输出,令x0 = x表示网络输入。通过应用具有参数wl的函数fl,从先前的输出xl-1计算每个中间输出xl = fl(xl-1;w1)。
在卷积神经网络(CNN)中,数据具有空间结构:每个xl∈RHl×Wl×Cl是3D阵列或张量,其中前两个维度Hl(高度)和Wl(宽度)被解释为空间维度,第三个维度Cl被解释为特征通道的数量。因此,张量xl表示Cl维特征向量的Hl×Wl视场,且每个空间位置一个。张量中的第四维Nl绑定单个批次中打包的多个数据样本以进行高效并行处理。批中的数据样本数量Nl称为批次基数。由于函数fl像线性卷积一样,是局部和平移不变的算子(即非线性滤波器),因此该网络称为卷积。
也可以构想具有两个以上空间维度的CNN,其中附加维度可以表示音量或时间。事实上,一般来说,神经网络中的数据格式几乎没有先验限制。许多有用的NN包含卷积层的混合层以及处理诸如文本字符串等其他数据类型的层,或者执行不严格符合CNN假设的其他操作。
MatConvNet的matlab /目录中包含各种层,如vl_nnconv(卷积)、vl_nnconvt(卷积转置或反卷积)、vl_nnpool(最大和平均池化)、vl_nnrelu(ReLU**)、vl_nnsigmoid(sigmoid**)、vl_nnsoftmax (softmax操作符)、vl_nnloss(分类对数损失)、vl_nnbnorm(批量归一化)、vl_nnspnorm(空间归一化)、vl_nnnormalize(局部响应规范化- LRN)或vl_nnpdist(p-距离)。有足够的层可以实现许多有趣的先进网络,甚至可以从其他工具箱(如Caffe)导入它们。
神经网络常被用作分类器或回归器。在例子中1.1,输出y = f(x)是一个概率向量,每个对于1000个可能的图像标签(狗,猫,三叶虫,…)中的一个。如果y是图像x的真标签,可以用一个损失函数来测量CNN的性能,它对分类错误进行惩罚。然后,可以调整或学习CNN参数,以最小化标注样本图像大数据集上的平均损失。
学习通常使用随机梯度下降(SGD)的变体。虽然这是一种有效的方法(对于这类问题),但网络可能包含数百万个参数,需要对数百万个图像进行训练;因此,如第1.4节所述,效率在Matlab设计中至关重要。SGD还需要计算CNN导数,如下一节所述。
2.2 网络结构
在最简单的情况下,NN中的层按顺序排列;然而,更复杂的相互连接也是可能的,事实上在很多情况下非常有用。本节讨论这些配置,并引入一个图形符号来使它们可视化。
2.2.1 序列
首先考虑网络中的计算块f。这可以被示意性地表示为以接收数据x和参数w作为输入并以生成数据y作为输出的框:
如上所示,简单情况下计算块由f1 → f2 → ··· → fL序列串联,遵循如下结构:
给定一个输入x0, 评估网络是简单的从左到右的评估所有块,它定义了一组函数xL = f(x0;w1,…,wL)。
2.2.2 有向无环图
不局限于一个接一个地连接层。实际上,评估一个NN的唯一要求是,当一个层必须被评估时,它的所有输入都被评估过。这是完全可能的,当层之间的互连形成有向无环图或简称为DAG时。
为了使DAG可视化,为网络变量引入额外的节点很有用,如图2.1的例子。这里框表示函数,圆圈表示变量(参数被视为一种特殊的变量)。在这个例子中,x0和x4是CNN的输入,x6和x7是输出。函数可以接受任意数量的输入(例如f3和f5取两个)并且具有任意数量的输出(例如f4有两个)。这个图有几个值得注意的属性:
- 图形是双方的,即箭头始终从框到圆,从圆到框。
- 函数可以有任意数量的输入或输出;变量和参数可以有任意数量的输出(具有多个输出的参数在不同层之间共享);变量至多有一个输入并且无参数。
- 没有输入箭头和参数的变量不由网络计算,但必须在评估之前设置,即它们是输入。任何变量(甚至参数)都可以用作输出,尽管这些通常是没有输出箭头的变量。
- 由于该图是非循环的,因此可以通过对函数进行排序并逐个计算它们来计算CNN(例如,按照f1、f2、f3、f4、f5的顺序评估函数)。
2.3 反向传播计算导数
学习NN需要计算与网络参数相关损失的导数。导数使用称为反向传播的算法进行计算,该算法是导数链式法则的有效实现。首先,讨论单层的导数,然后讨论整个网络。
2.3.1张量函数的导数
在CNN中,一个层是一个函数y = f(x),其中输入x∈RH×W×C和输出y∈RH’×W’×C’是张量。函数f的导数包含每个输出分量yi’j’k’相对于每个输入分量xijk的导数,对于自然排列在6维张量中的总共H’×W’×C’×H×W×C个元素。不将导数表示为张量,而通过将输入和输出张量堆积到矢量中来切换到矩阵符号通常很有用。这由vec操作符完成,该操作符按照字典顺序访问张量的每个元素并生成一个向量:
通过堆积输入和输出,每层f可以被重新解释为矢量函数vec f,其导数是传统雅可比矩阵:
张量函数导数的这种表示法取自[7],并在整个文档中使用。虽然很容易将张量函数的导数表示为矩阵,但这些矩阵通常非常大。 即使对于中等数据大小(例如H = H’ = W = W’ = 32且C = C’ = 128),雅可比行列式中也存在H’W’C’HWC ≈ 17×109个元素。单精度存储需要68 GB的空间。反向传播算法的目的是计算学习所需的导数,而不产生巨大的内存成本。
2.3.2 函数组的导数
为了理解反向传播,首先考虑一个简单的CNN终止损失函数:
目标是计算相对于每个网络参数wl的损失值xL(输出)的梯度:
其中在由输入x0和当前参数值确定的工作点处计算导数。注意,因为网络输出xl是标量,所以目标导数df / d(vec wl)T具有与参数矢量wl相同数量,这是适度的。但是,如上所述,中间雅可比因子具有难以管理的尺寸。为了避免显式计算这些因素,可以按照以下步骤进行操作。通过将最后一层的输出乘以张量pL-1开始(注意,这个张量就像变量xL一样是一个标量):
在第二行中,左边的最后两个因子已经相乘,得到一个与变量xL-1具有相同大小的新张量pL-1。因此pL-1可以显式存储。然后通过从左到右乘以几个因子来重复该构造,获得张量序列pL-2,…,pl直到获得期望的导数。请注意,这样做时,内存中不会存储大的张量。这个过程被称为反向传播。通常,张量pl从pl+1作为乘积获得:
实施反向传播的关键是能够计算这些导数,而不需要明确计算和存储第二个因素,即大雅可比矩阵。由于计算导数是线性运算,因此该乘积可以解释为沿方向pl+1投影层的导数:
这里<·,·>表示张量之间的内积,这就产生了一个标量。因此,导数(2.2)不需要使用vec符号,并产生一个与预期的xl具有相同大小的张量pl。为了实现反向传播,CNN工具箱提供了每个层f的实现,它们提供:l 一种前向模式,计算给定输入x和参数w的层的输出y = f(x; w)。l 反向模式,计算投影导数
除了输入x和参数w之外,给定一个与y相同大小的张量p。以一个例子来最好地说明这一点。考虑一个像卷积运算符这样的层f由MatConvNet vl_nnconv命令执行。在“前进”模式中,调用函数y = vl_nnconv(x,w,[])将滤波器w应用到输入x并获得输出y。在“后退”模式中,调用[dx,dw] = vl_nnconv(x,w,[],p)。如上解释,dx、dw和p分别与x、w和y具有相同的大小。大的计算Jacobian封装在函数调用中,并且从不显式执行。
2.3.3反向传播网络
在本节中,提供反向传播的示意图,并说明如何通过“反转”NN计算图来实现反向传播。投影梯度公式(2.2)可以看作是下面小网络的导数:
在反向传播的上下文中,将投影p想象为从变量y到损失的网络其余部分的“线性化”可能是有用的。投影导数也可以作为一个新层(dx,dw)= df(x,w,p),通过计算微型网络的导数,可以反向运行:
通过构造(参见方程(2.2)),函数df在参数p下是线性的。使用这种表示法,向前和向后通过原始网络可以被重写为评估包含原始网络的BP反向的扩展网络(在图中以蓝色表示):
2.3.4 DAG中的反向传播
假设DAG具有单个输出变量xL,并且不失一般性的假定,所有变量根据DAG结构按计算顺序(x0; x1,…,xL-1,xL)排序。 此外,为了简化符号,假设该列表包含数据变量和参数变量,因为本节讨论的区别是有限的。可以通过将x0,…,xl-1固定为某个任意值并删除所有进入它们的DAG层,将第一个变量有效地转换为输入,从而在该序列中的任意点切割DAG。然后,DAG的其余部分定义一个函数hl,它将这些输入变量映射到输出xL:
接下来,证明DAG中的反向传播迭代地计算所有函数h1,…,hL关于其所有参数的投影导数。反向传播通过将变量(dx0,…,dxl-1)初始化为与(x0,…,xl-1)大小相同的零张量来开始。接下来计算下式的投影导数
这里πl表示计算变量xl的值的fπl层的索引。最多只有一个这样的层,或者如果xl是原始NN的输入或参数,则不存在。在第一种情况下,该层可能依赖于序列中xl之前的任何变量,因此一般有:
在反向传播开始时,由于xL-1和xL之间没有中间变量,所以函数hL与最后一层fπl相同。因此,hL的投影导数与fπl的投影导数相同,得到方程式
在这里,为了与其他迭代保持一致,使用dxl被初始化为零来累积值而不是存储它们。实际上,更新操作只需要对变量xl进行,这些变量是实际输入到fπl的变量,这通常是DAG中所有变量的一小部分。更新之后,每个dxt包含函数hL相对于相应变量的投影导数:
根据这些信息,反向传播的下一次迭代更新变量以包含hL-1的投影导数。通常,给定hl+1的导数,反向传播通过使用关系
对这个表达式应用链规则,对于所有的0≤t≤l-1:
这将生成更新方程
次,只需对fπl的实际输入变量xt进行显式更新。特别是,如果xl是原始神经网络的数据输入或参数,则xl不依赖于任何其他变量或参数,而fπl是空函数(即无参数的函数)。在这种情况下,更新不做任何事情。迭代L-l+1完成后,后向传播保持:
注意,变量xt(l≤t≤L-1)的导数没有更新,因为hl不依赖于这些变量中的任何一个。因此,在所有L迭代完成后,反向传播终止于
如上所示,函数hl是通过变换变量x0,…,xl-1到输入从原始网络f中获得。如果xl-1已经是f的输入(数据或参数),那么导数dxl-1也适用于f。反向传播可概括如下:
给定:具有单输出xL的DAG神经网络f,所有输入变量(包括参数)的值和投影pL的值(通常xL是标量并且pL = pL = 1):
- 根据DAG按照计算顺序(x0,x1,…,xL)对所有变量进行排序。
- 通过网络执行前向传递以计算所有中间变量值。
- 将(dx0,…,dxL-1)初始化为与相应变量大小相同的空张量。
- 对于l = L,L-1,…,2,1:
a)找出评估变量xl的层xl =fπl(x0,…,xl-1)的索引πl。如果没有这样的层(因为xl是网络的输入或参数),则转到下一个迭代。
b)使用公式更新变量: 为了有效地做到这一点,可以根据需要使用fπl层的“后向模式”计算投影到dxl上的导数。
2.3.5 DAG反向传播网络
就像序列一样,DAG中的反向传播可以实现为相应的BP反向DAG。
构建反转的DAG:
- 对于每个层fl和变量/参数xt和wl,创建相应的层dfl和变量/参数dxt和dwl。
- 如果变量xt(或参数wl)是fl的输入,那么它也是dfl的输入。
- 如果变量xt(或参数wl)是fl的输入,那么变量dxt(或参数dwl)是dfl的输出。
- 在上一步中,如果变量xt(或参数wl)输入到f中的两个或更多层,则dxt将是反转网络中两个或更多层的输出,从而产生冲突。为了解决这些冲突,可插入一个叠加层(对应于BP更新方程(2.3)中的求和)。
图2.2给出了与图2.1的DAG对应的BP网络。