摘 要
深度学习是机器学习的一个重要分支,可用于图像分类及目标识别等,其中Resnet网络由于其自身的优势,所以应用较为广泛,在此基础上,我们提出了一个新的算法,用于训练Resnet网络。
由于Resnet网络结构可以看作是逐层增强的结构,其本身结构解决了深度学习中的退化问题,故结合Boosting的原理,我们提出了一个基于Boosting理论,同时完整保留Resnet网络本身优点的训练算法。我们在Resnet网络每一层的输出处引入一个线性的全连接层,使之分别相对于一个弱的分类器。此时,仅仅要求训练浅层的网络便可达到所需效果,继承了Resnet网络的优点的同时,使得网络可以达到更深同时又不影响准确率。
总而言之,我们提供了一个弱学习环境以及Boosting理论,在此条件下,利用新的算法对Resnet网络进行训练。
关键词:深度学习; Resnet网络; Boosting理论
4.2 Cifar10-对于Resnet网络及Resnet-Boosting网络的训练及测试 12
4.2.1 数据集为Cifar10 网络为Resnet网络,未做任何改变 12
4.2.2 数据集为Cifar10 网络为Resnet-Boosting网络 13
4.3 Cifar100-对于Resnet网络及Resnet-Boosting网络的训练及测试 15
4.3.1 数据集为Cifar100 网络为Resnet网络,未做任何改变 15
目前深度学习应用较为广泛,其是对人类大脑中的神经网络进行模拟,从而实现对于输入数据(图像、文本等)的处理,因此随着深度学习的不断发展以及我们所需处理的数据量的增大,可以看出在进行图像分类及目标识别的应用中,深度学习的应用至关重要,非线性网络变得更加有利,可以从输入数据中得到更多有利信息。
许多实践证明,当我们要进行图像分类及目标识别的任务时,往往需要较深的网络结构来完成,但是随着网络深度的增加,会引起梯度爆炸或者消失的问题,通常可采用正则化的方法有效解决此问题,但随之会引起网络退化问题,准确率并没有像预期中一样直线上升,而是在某一点处达到饱和值之后准确率便不再增加,甚至会随着层数继续增加准确率反而会下降,即网络出现了退化问题。针对这个情况人们提出了Resnet网络,在网络结构中引入了快捷方式将输入同时引入至输出,最终学习输出与输入之间的差值,构成了残差的结构,使得每一次仅用学习残差的部分,成功解决了退化问题,故Resnet网络的应用比较广泛[1]。
对于Boosting思想的学习及应用,让我们深刻理解Boosting不是单一的某个算法,而是一族可以通过相应地加权将若干个弱学习器提升为较强学习器的算法[2]。可以理解为当出现某一个问题时,仅仅听取某一位专家的意见会有些片面,不能考虑更多地影响因素,所以我们可以采取让许多位专家同时为某一个问题进行分析,当然每位专家都有其自身特点及关注点,最终将多个专家的意见进行综合,从而得到一个更加全面、正确的处理方案。
在此思想的基础上,由于Resnet网络可以看成是逐层增强的结果[3],所以我们可以将两者结合在一起,将构成Resnet网络的每一个残差块都对应于一个弱分类器,此时所有残差块的顺序增强便可以对应于许多弱分类器结合从而得到一个强分类器的结果,故我们提出了基于Boosting思想下Resnet网络的理解及训练,得到了一个新的训练算法。
对深度网络进行训练是近几年比较活跃的研究领域,其中最主要的挑战在于损失函数的高度非凸性,解决这个优化问题的方法主要有两个:一是选择损失函数及网络结构具有较好的几何特性,另一个则是改进网络的学习过程。
许多作者之前用不同的方法研究过网络模型和增强技术,2006年Bengio等人提出了一种单隐层凸神经网络以及一种学习线性分类器权重的梯度增强的算法,但这种方法并没有推广至含有多个隐藏层的深层网络[4]。ShalevShwartz于2014年提出了一种自增强算法,其实现了整个网络准确率的提升[5]。
其中AdaNet的作者通过Boosting类型的算法实现神经层的集合,并通过在泛化界上进行优化。其使用了传统的Boosting框架实现弱分类器的集成。在AdaNet算法中,每一个较低层的特征都必须输入到一个分类器中,所以最顶层的分类器必须连接到底层的每一个分类器上,使得结构无比混乱、密密麻麻[6]。
与AdaNet网络相类似,此处我们同样利用Boosting的思想,对Resnet网络进行逐残差块的训练[7],我们在Resnet网络的每一层的输出处引入一个线性的全连接层,最终将得到的所有的输出采用简单的求和实现统一,以此实现对于特征的增强,实现网络结构的简洁。更关注于Resnet网络结构本身,提出一个新的用于训练Resnet网络的算法,同时对深度Resnet网络的误差提供了保障。
在进行训练及测试的时候,实现每一个epoch的训练便进行一次测试,并记录每一次测试所得到的分类准确率,经过不断的训练及测试,以观测结果。在不同的数据集上实现对比实验,通过在每一种数据集的基础上,保持其他参数变量的统一,仅改变网络的结构,实验论证,得到实验结果根据准确率随遍历次数的变化观察设计网络对于准确率是否有所提升。
本文主要是在Resnet网络的基础下,结合Boosting的思想进行改进,故整体的论文框架可以分为如下几个部分:
- 摘要。用于提炼文章精髓,在有限的字数范围内讲解文章的主要内容及思路,方便读者阅读理解。
- 绪论。分为4个小部分,通过介绍研究的背景及意义,使读者充分了解相关的背景;同时介绍相关的研究现状及本文的方法,体现出本文方法的改进之处及具体改进方案。
- 相关技术。由于本文是在Resnet网络的基础上,基于Boosting的思想进行改进,所以首先对Resnet网络的结构、特点以及Boosting算法的定义、工作机制有初步的学习理解。
- 改进算法。此部分通过具体的网络构架及相应算法的改进方案,对于本文提出的算法进行详细的描述。
- 实验验证。通过在不同的数据集上对于本身的Resnet网络及改进的网络针对图像的分类准确率进行实验验证,观察本文的网络对于分类的准确率是否有所提升。
- 总结与展望。对于本文设计的算法及所做的实验进行总结,并提出存在的不足以及未来将如何改进。
- 参考文献。本文所有引用的概念及他人的思想均在此标明。
Resnet 网络是在之前的VGG网络结构的基础上添加了快捷方式,这样每次学习的便仅仅是残差的部分。即每个 Resnet 网络都由许多残差块堆积而成,其中每一个残差块都由一个神经网络模型和一个快捷方式构成。
一个残差块的结构如图2.1所示:
图 2.1: A Residual Block of ResNet
第T层残差块的输出为:
其中X为网络的输入,
代表第T层的卷积层,
代表T-1层的最终输出。
假设Resnet网络共有T层,那么第T层即网络的最终输出等于所有底层残差块输出的总和,因此Resnet网络可以理解为逐步增强的结果,则最终输出的表达式如式(2.2)所示:
式
表示从分类器输出到标签的映射。
通过引入快捷方式,使得每次仅仅学习输出与输入之间的差值,即使在较深的网络中,梯度也可以通过短路径很好地传递,有效地解决了网络的梯度消失的问题,使得Resnet网络可以更好地应用于更深的网络中[8]。
Boosting是一族算法,它的目的在于提高弱学习算法的效果。其关键的思想是为弱分类器选择训练集,使得在每次调用数据时都能获取新的信息。弱学习算法最终将多个弱分类器组合成一个预测能力强的强分类器[9]。
其可以理解为,当出现一个问题时,仅仅采用一个专家的意见是片面的,其可能考虑不周全,所以采用多个专家同时对这个问题给予意见的方法,此时由于每个专家的特点不同,对于问题的观察角度不同,则将所有专家的观点综合而来会更加全面,最终得到一个更好的解决方案,这样可以有效的解决提高方案的正确性、对问题的理解更加清晰,得到最优的解决方案,从而达到我们期望的最好结果。
Boosting的工作流程大致为:对初始提供的数据集进行训练,得到一个学习器,根据学习器的结果表现(即其分类的准确率),相应地对数据进行处理,即对于做错的数据,改变它相应地权重,使得其在后续的训练中得到更多的关注。就这样周而复始,使得所有的数据都可以实现正确处理,直至学习器的数目达到了我们预先指定的值之后,再将得到的所有学习器进行加权结合[10],如图2.2所
式:
图2.2 Boosting的工作机制
Boosting思想中的弱分类器并不真的表示它的分类效果很差,而是它仅对一部分的分类效果更好,那么相对于其他不擅长的部分便理解为较弱的分类器,所以将许多个弱分类器结合在一起,使他们各司其职,分别对自己擅长的部分做处理,完成对所有数据的一个较好地处理,最终得到对所有数据有很好的分类效果[11]。
通过对Resnet网络的学习,可以知道Resnet网络是在VGG网络的基础上进行改进的,可以有效地解决深度网络存在的退化问题,同时其结构使得网络的梯度在较深网络中仍能正常传递不会存在梯度弥散的现象。其设定了当出现feature map大小降低一半时,feature map的数量则增加一倍,以此来保持网络的复杂度。
但是其也存在不足,当进行训练时,训练的时间会比较长,所以我们提出了新的算法来缓解这个缺陷,但同时保持Resnet网络本身的优点不变,从而提升网络的性能及效果。
我们在对Resnet网络结构进行理解时,了解到整个网络是由许多个残差块构成,输入经第一个残差块后传递给下一个残差块,逐步传递,同时学习到的特征也是逐个残差块的传递,最终网络的输出是所有残差块的总和,可以将其看做是逐层增强的效果,理解到这里我们可以想到Boosting的基本定义及应用,将许多弱的算法通过结合得到一个效果更强的算法[11],故将Boosting应用于Resnet网络上,实现逐个残差块增强的效果。将Resnet网络每一层的输出通过全连接层引出,再用Boosting的思想,使得在应用Boosting思想提升分类器效果的同时,保留了Resnet网络本身的优点。
我们在Resnet网络的基础上改变网络的结构,使其拥有更好地性能。在Resnet网络的每一层的输出处引入一个线性的全连接层,将得到的结果通过全连接层引出来,此时相当于我们将提取好的特征拿了出来,在后续的网络中便不用再对已经分类好的数据进行处理。即在每一层中将分类效果很好的类别先提取出来,随后将剩下的再次进行训练测试,直到达到较好的结果,这样的好处在于使得训练的时间变短、结构简单,在后续的网络中所要训练提取的特征变少,则准确率得到了提升[12]。
对于Resnet网络及Boosting的基础知识有了初步学习及理解后,提出了新的网络结构,我们将Boosting的思想应用于Resnet网络中,用于提高图像分类的准确率[13]。
我们通常在构建Resnet网络时,根据其网络特点首先要构造残差块结构,我们已知Resnet网络共有5种结构,分别为Resnet18、Resnet34、Resnet50、Resnet101、Resnet152。他们都有自己的网络构架,大体上都是统一的,只是在具体的层中有所不同。本文采用的是Resnet18,故此时仅仅利用Basicblock来搭建网络,由图3.1可以知道具体的网络构架。
图3.1:Resnet网络的基本结构
如图3.1所示:我们可知Resnet网络由6部分组成,首先是一个由7*7的卷积构成,命名为conv1。随后首先进行一个3*3的最大池化,接下来的四层均为每一层都是有两个Basicblock的卷积层,命名为conv_2、conv_3、conv_4、conv_5。最后即为一个全连接层,命名为fc。此时构成一个Resnet18的网络结构。
我们利用Boosting的思想对网络结构进行改进[14],具体的构建方法为:在conv1、conv_2、conv_3、conv_4四个层的输出处分别引入一个线性的全连接层,利用Python中的nn.linear()函数实现。得到4个全连接层结果为y1、y2、y3、y4。在引入四个全连接层时,需要利用a.reshape()函数先对结果进行处理,改变所得结果的矩阵形状,使之与全连接层的参数保持匹配,随后得到全连接层的结果。
将整体的结构改进方案用图示表示出来,如下图所示:
图3.2:基于 Boosting的图像分类算法设计的结构图
由图3.2可以看出,设计的网络结构实现了Resnet网络的逐个残差块的增强,最终所有的全连接层的输出结果的求和即为Resnet网络的最终输出[15]。
网路的Loss即为在定义了损失函数Criterion之后,计算网络的输出与真实的标签之间的误差,从而得到损失值Loss。可以理解为本身图像的标签是我们所希望得到的,在网络没有任何损失时应得到的结果,而实际中输入在经过网络之后得到的输出与本身图像的标签相对比,其差值并不为零即为此网络造成的损失,对于图像分类而言,即为观察图像的分类是否正确[16]。我们希望Loss越小越好,故在得到Loss后,需要进行反向传播,改变相应的参数,使得网络的Loss不断减小,直到达到我们的标准或是完成所有的训练次数。本文使用的pytorch完成实验验证,则通过Loss.backward()函数完成误差的反向传播,pytorch的内在机制可以实现自动求导得到每个参数的梯度。
故在实现了网络结构的重新构建后,对网络进行训练时,针对Loss我们需要相应地改变。先分别计算出网络最终输出Output及每一个全连接层的输出与标签之间的Loss,最终的Total_Loss是由4个全连接计算得到的Loss与本身网络输出Outputs与标签Label之间计算得到的Loss之和,随后进行Loss的反向传递。此时的损失函数我们选择nn.CrossEntropyLoss( )函数,即交叉熵,用于多分类问题,随后pytorch会实现自动求导得到参数的梯度,在不断的训练过程中,Loss会不断减小。
预测即为在进行训练及测试过程中,通过已知的自变量给出相应的因变量,而分类的定义可以理解为用已知的一部分属性去预测另一部分属性,两者的本质是相同的[17]。
我们在设计的分类网络的训练及测试过程中,预测值不再是采用原来的网络输出Outputs的最大值,而是应用Boosting的思想,需要采用网络的最终输出Outputs以及每一个引出的全连接层的输出y1,y2,y3,y4的和,并通过torch.max()函数得到Outputs+y1+y2+y3+y4的最大值,以此作为网络的预测值。
注意:由于修改了网络的结构,所以网络的输出除了Output外还有引入的线性全连接层的输出,则无论在训练还是测试时,都需要将所有的输出值进行输出,例如语句:Outputs ,y1 ,y2 ,y3 ,y4 = net(inputs)此时输出的Outputs ,y1 ,y2 ,y3 ,y4均为一个tensor,可以在后续进行相应的处理,如果只写成Outputs = net(inputs)则pytorch 会自行将所有的输出均放在一个Tuple中。那么在进行后续的预测及计算时,便会出现格式不匹配的问题。故在网络的输出中,无论其个别输出在后续的程序中是否被用到,都要将所有的输出值进行正确的输出。