有没有没睡的出来聊聊喜欢bn的,来聊聊

?关注公众号“AI算法修炼营”選择“星标”公众号。精选作品第一时间送达。

前面基础积累系列的文章讲了ResNet网络及其变体,具体可以参考文章:ResNet通过前层与后层嘚“短路连接”(Shortcuts),加强了前后层之间的信息流通在一定程度上缓解了梯度消失现象,从而可以将神经网络搭建得很深更进一步,這次的主角DenseNet最大化了这种前后层信息交流通过建立前面所有层与后面层的密集连接,实现了特征在通道维度上的复用使其可以在参数與计算量更少的情况下实现比ResNet更优的性能。

所作该作者在思想上借鉴了ResNet和Inception的网络。ResNet解决了网络深的时候梯度消失问题它是从深度方向研究的。宽度方向是GoogleNet的InceptionDenseNet作者是从feature入手,通过对feature的极致利用能达到更好的效果和减少参数

当CNN的层数变深时,输出到输入的路径就会变嘚更长这就会出现一个问题:梯度经过这么长的路径反向传播回输入的时候很可能就会消失,那有没有没睡的出来聊聊一种方法可以让网絡又深梯度又不会消失?

DenseNet提出了一种很简单的方法,DenseNet直接通过将前面所有层与后面的层建立密集连接来对特征进行重用来解决这个问题连接方式可以看下面这张图:

DenseNet的结构有如下两个特性:

1)神经网络一般需要使用池化等操作缩小特征图尺寸来提取语义特征,而Dense Block需要保持每一個Block内的特征图尺寸一致来直接进行Concatnate操作因此DenseNet被分成了多个Block。Block的数量一般为4

2)两个相邻的Dense Block之间的部分被称为Transition层,具体包括BN、ReLU、1×1卷积、2×2平均池化操作1×1卷积的作用是降维,起到压缩模型的作用而平均池化则是降低特征图的尺寸,使feature maps的尺寸减半

关于Block,有以下4个细节需要注意:

1、每一个Bottleneck输出的特征通道数是相同的例如这里的32。同时可以看到经过Concatnate操作后的通道数是按32的增长量增加的,因此这个32也被稱为GrowthRate

2、这里1×1卷积的作用是固定输出通道数,达到降维的作用当几十个Bottleneck相连接时,Concatnate后的通道数会增加到上千如果不增加1×1的卷积来降维,后续3×3卷积所需的参数量会急剧增加1×1卷积的通道数通常是GrowthRate的4倍。

3、特征传递方式是直接将前面所有层的特征Concatnate后传到下一层而鈈是前面层都要有一个箭头指向后面的所有层,这与具体代码实现是一致的

4、Block采用了激活函数在前、卷积层在后的顺序,这与一般的网絡上是不同的

  • 通过Concatnate操作使得大量的特征被复用,每个层独有的特征图的通道是较少的因此相比ResNet, DenseNet参数更少且计算更高效。与传统CNNs相比参數更少(尽管看上去相反)因为其不需要学习冗余特征。
  • 改善了整个网络中的information flow和梯度使得训练更为容易
  • 密集连接具有正则化效果,能降低訓练集size较小的任务的过拟合现象密集连接的特殊网络,使得每一层都会接受其后所有层的梯度而不是像普通卷积链式的反传,因此一萣程度上解决了梯度消失的问题

DenseNet的不足在于由于需要进行多次Concatnate操作,数据需要被复制多次显存容易增加得很快,需要一定的显存优化技术另外,DenseNet是一种更为特殊的网络ResNet则相对一般化一些,因此ResNet的应用范围更广泛

据此,实现DenseBlock模块内部是密集连接方式(输入特征数線性增长):

此外,实现Transition层它主要是一个卷积层和一个池化层:

最后我们实现DenseNet网络:

Pelee:目标检测轻量级网络

PeleeNet借鉴了DenseNet的级联模式和主要步驟,被用于解决存储和计算能力受限的情况在ImageNet数据集上,PeleeNet只有MobileNet模型的66%,并且比MobileNet精度更高PeleeNet作为backbone实现SSD能够在VOC2007数据集上达到76.4%的mAP。文章总体上参栲DenseNet的设计思路提出了三个核心模块进行改进,有一定参考价值

上边左边(a)图是DenseNet中设计的基本模块,其中k、4k代表filter的个数右边(b)图代表PeleeNet中设計的基本模块,除了将原本的主干分支的filter减半(主干分支感受野为3x3)还添加了一个新的分支,在新的分支中使用了两个3x3的卷积这个分支感受野为5x5。这样就提取得到的特征就不只是单一尺度能够同时兼顾小目标和大目标。

这个模块设计受Inceptionv4和DSOD的启发想要设计一个计算代价比較小的模块。ResNet和DenseNet在第一层都是用的是一个7x7、stride为2的卷积层浅层网络的作用是提取图像的边缘、纹理等信息。Stem Block的设计就是打算以比较小的代價取代7x7的卷积该结构可以有效的提升特征表达能力且不会增加额外的计算开销,比其他的方法(增加通道或增加增长率)都要好

具体結构,先使用strided 3x3卷积进行快速降维然后用了两分支的结构,一个分支用strided 3x3卷积, 另一个分支使用了一个maxpool

这一部分和组合池化非常相似,stem block使用叻strided 3x3卷积和最大值池化两种的优势引申而来的池化策略(组合池化使用的是最大值池化和均值池化)可以丰富特征层。

  • 瓶颈层设置动态变化的通道数

在DenseNet中有一个超参数k-growth rate, 用于控制各个卷积层通道个数,在DenseNet的瓶颈层中将其固定为增长率的4倍,DenseNet中前几个稠密层的瓶颈通道数比输叺通道数多很多,这也意味着对这些层来说瓶颈层增加了计算开销

为了维持结构的一致性PeleeNet仍然给所有稠密层添加了瓶颈层,但是数量是依据输入形式而动态调整的来保证通道数量不会超过输入通道数。将瓶颈层的通道个数根据输入的形状动态调整节约了28.5%的计算消耗。

在DenseNet中过渡层是用于将特征图空间分辨率缩小的,并且过渡层中通道数会小于前一层的通道数在PeleeNet中将过渡层和前一层通道数设置为┅样的数值。

为了提高速度采用了conv+bn+relu的组合(而不是DenseNet中的预激活组合(conv+relu+bn)),post-activation中,在推断阶段所有的BN层可以和卷积层合并可以促进模型推理加速。為了弥补这个改变给准确度带来的负面影响使用更浅更宽的网络结构,在最后一个dense block后添加一个1x1的卷积层来获得更强的特征表达能力

整個网络由一个stem block和四阶特征提取器构成。除了最后一个阶段的每个阶段的最后一层都是步长为2的平均池化四阶段结构是一般大型模型设计嘚通用结构。

尽管ShuffleNet使用三阶段的结构并在每个阶段的开始都压缩了特征图大小,尽管这样可以提升计算速度但是本文认为前面的阶段對视觉任务尤为重要,且过早的减小特征图大小会损坏特征表达能力因此仍然使用四阶段结构,前两阶段的层数是专门控制在一个可接受的范围内的

VoVNet:考虑成本和效率

DenseNet在目标检测任务上表现很好。因为它通过聚合不同感受野特征层的方式保留了中间特征层的信息。但昰ResNet是目标检测模型最常用的backbone,DenseNet其实比ResNet提取特征能力更强而且其参数更少,计算量(FLOPs)也更少用于目标检测虽然效果好,但是速度较慢这主要是因为DenseNet中密集连接所导致的高内存访问成本和能耗。VoVNet就是为了解决DenseNet这一问题基于VoVNet的目标检测模型性能超越基于DenseNet的模型,速度吔更快相比ResNet也是性能更好。

除了FLOPs和模型大小外还需要考虑其他因素对能耗和模型推理速度的影响。这里考虑两个重要的因素:内存访問成本(Memory Access CostMAC)和GPU计算效率。

对于CNN来说内存访问比计算对能耗贡献还大,如果网络中间特征比较大甚至在同等模型大小下内存访问成本會增加,所以要充分考虑CNN层的MAC在ShuffleNetV2论文中给出计算卷积层MAC的方法:

这里的 分别为卷积核大小,特征高和框以及输入和输出的通道数。卷積层的计算量如果固定的话,那么有:

根据均值不等式可以知道当输入和输出的channel数相同时MAC才取下界,此时的设计是最高效的。

GPU计算的优勢在于并行计算机制这意味着当要计算的tensor较大时会充分发挥GPU的计算能力。如果将一个较大的卷积层拆分成几个小的卷积层尽管效果是楿同的,但是却是GPU计算低效的所以如果功效一样,尽量采用较少的层比如MobileNet中采用深度可分离卷积(depthwise conv+1x1 conv)虽然降低了FLOPs,但是因为额外的1x1卷積而不利于GPU运算效率相比FLOPs,我们更应该关注的指标是FlOPs per Second即用总的FLOPs除以总的GPU推理时间:Flops/s指标,这个指标越高说明GPU利用越高效

Block密集连接会聚合前面所有的layer,这导致每个layer的输入channel数线性增长受限于FLOPs和模型参数,每层layer的输出channel数是固定大小这带来的问题就是输入和输出channel数不一致,此时的MAC不是最优的另外,由于输入channel数较大DenseNet采用了1x1卷积层先压缩特征,这个额外层的引入对GPU高效计算不利所以,虽然DenseNet的FLOPs和模型参数嘟不大但是推理却并不高效,当输入较大时往往需要更多的显存和推理时间

DenseNet的一大问题就是密集连接太重了,而且每个layer都会聚合前面層的特征其实造成的是特征冗余,而且从模型weights的L1范数会发现中间层对最后的分类层贡献较少这不难理解,因为后面的特征其实已经学習到了这些中间层的核心信息这种信息冗余反而是可以优化的方向。

OSA只在最后一次性聚合前面所有的layer这一改动将会解决DenseNet的问题,因为烸个layer的输入channel数是固定的这里可以让输出channel数和输入一致而取得最小的MAC,而且也不再需要1x1卷积层来压缩特征所以OSA模块是GPU计算高效的。

Block类似嘚参数大小和计算量此时OSA模块的输出将更大。最终发现在CIFAR-10数据集上acc仅比DenseNet下降了1.2%但是如果将OSA模块的层数降至5,而提升layer的通道数为43会发現与DenseNet-40模型效果相当。这说明DenseNet中很多中间特征可能是冗余的尽管OSA模块性能没有提升,但是MAC低且计算更高效这对于目标检测非常重要,因為检测模型一般的输入都是较大的

1)添加了输入到输出的残差连接网络,解除了随着网络深度叠加带来的性能饱和与梯度问题;

2)在输絀的内部添加了一个channel上的attention模块eSE原始的SE模块中使用两个FC去进行channel权重映射,但是为了减少计算量通常会将FC中的channel给剪裁一些(小于输入的channel)這就引入了一些信息的损失,为此文章直接将两个FC替换为了一个FC


扫描上方微信号,进入学习群
目标检测、图像分割、自动驾驶、机器囚、面试经验。
福利满满名额已不多…

前面基础积累系列的文章讲了ResNet網络及其变体,具体可以参考文章:ResNet通过前层与后层的“短路连接”(Shortcuts),加强了前后层之间的信息流通在一定程度上缓解了梯度消夨现象,从而可以将神经网络搭建得很深更进一步,这次的主角DenseNet最大化了这种前后层信息交流通过建立前面所有层与后面层的密集连接,实现了特征在通道维度上的复用使其可以在参数与计算量更少的情况下实现比ResNet更优的性能。

1)添加了输入到输出的残差连接网络解除了随着网络深度叠加带来的性能饱和与梯度问题;

2)在输出的内部添加了一个channel上的attention模块eSE。原始的SE模块中使用两个FC去进行channel权重映射但昰为了减少计算量通常会将FC中的channel给剪裁一些(小于输入的channel),这就引入了一些信息的损失为此文章直接将两个FC替换为了一个FC

包含 N 个样本每个样本通道数为 C,高为 H宽为 W。

对其求均值和方差时将在 N、H、W上操作,而保留通道 C 的维度具体来说,就是把第1个样本的第1个通道加上第2个样本第1个通道 ...... 加上第 N 个样本第1个通道,求平均得到通道 1 的均值(注意是除以 N×H×W 而不是单纯除以 N,最后得到的是一个代表这个 batch 第1个通道平均值的數字而不是一个 H×W 的矩阵)。

求通道 1 的方差也是同理对所有通道都施加一遍这个操作,就得到了所有通道的均值和方差具体公式为:

类比为一摞书,这摞书总共有 N 本每本有 C 页,每页有 H 行每行 W 个字符。BN 求均值时相当于把这些书按页码一一对应地加起来(例如第1本書第36页,第2本书第36页......)再除以每个页码下的字符总数:N×H×W,因此可以把 BN 看成求“平均书”的操作(注意这个“平均书”每页只有一个芓)求标准差时也是同理。

我们可以在 pytorch 下自己写一个 BN 看看和官方的版本是否一致,以检验上述理解是否正确:

BN使得网络中每层输入数據的分布相对稳定加速模型学习速度

BN通过规范化与线性变换使得每一层网络的输入数据的均值与方差都在一定范围内,使得后一层网络鈈必不断去适应底层网络中输入的变化从而实现了网络中层与层之间的解耦,允许每一层进行独立学习有利于提高整个神经网络的学習速度。当学习率设置太高时会使得参数更新步伐过大,容易出现震荡和不收敛但是使用BN的网络将不会受到参数数值大小的影响。

BN使嘚模型对网络中的参数不那么敏感简化调参过程,使得网络学习更加稳定

在神经网络中我们经常会谨慎地采用一些权重初始化方法(唎如Xavier)或者合适的学习率来保证网络稳定训练。

BN允许网络使用饱和性激活函数(例如sigmoidtanh等),缓解梯度消失问题

在不使用BN层的时候由于網络的深度与复杂性,很容易使得底层网络变化累积到上层网络中导致模型的训练很容易进入到激活函数的梯度饱和区;通过normalize操作可以讓激活函数的输入数据落在梯度非饱和区,缓解梯度消失的问题;另外通过自适应学习 与又让数据保留更多的原始信息 BN具有一定的正则囮效果

Normalization中,由于我们使用mini-batch的均值与方差作为对整体训练样本均值与方差的估计尽管每一个batch中的数据都是从总体样本中抽样得到,但不同mini-batch嘚均值与方差会有所不同这就为网络的学习过程中增加了随机噪音,与Dropout通过关闭神经元给网络训练带来噪音类似在一定程度上对模型起到了正则化的效果。另外原作者通过也证明了网络加入BN后,可以丢弃Dropout模型也同样具有很好的泛化效果。

局限1:如果Batch Size太小则BN效果明顯下降。

Size比较小则任务效果有明显的下降那么多小算是太小呢?图10给出了在ImageNet数据集下做分类任务时使用ResNet的时候模型性能随着BatchSize变化时的性能变化情况,可以看出当BatchSize小于8的时候开始对分类效果有明显负面影响之所以会这样,是因为在小的BatchSize意味着数据样本少因而得不到有效统计量,也就是说噪音太大这个很好理解,这就类似于我们国家统计局在做年均收入调查的时候正好把你和马云放到一个Batch里算平均收入,那么当你为下个月房租发愁之际突然听到你所在组平均年薪1亿美金时,你是什么心情那小Mini-Batch里其它训练实例就是啥心情。

BN的Batch Size大小設置是由调参师自己定的调参师只要把Batch Size大小设置大些就可以避免上述问题。但是有些任务比较特殊要求batch size必须不能太大,在这种情形下普通的BN就无能为力了。比如BN无法应用在Online Learning中因为在线模型是单实例更新模型参数的,难以组织起Mini-Batch结构

局限2:对于有些像素级图片生成任务来说,BN效果不佳;

对于图片分类等任务只要能够找出关键特征,就能正确分类这算是一种粗粒度的任务,在这种情形下通常BN是有積极效果的但是对于有些输入输出都是图片的像素级别图片生成任务,比如图片风格转换等应用场景使用BN会带来负面效果,这很可能昰因为在Mini-Batch内多张无关的图片之间计算统计量弱化了单张图片本身特有的一些细节信息。

局限3:RNN等动态网络使用BN效果不佳且使用起来不方便

对于RNN来说尽管其结构看上去是个静态网络,但在实际运行展开时是个动态网络结构因为输入的Sequence序列是不定长的,这源自同一个Mini-Batch中的訓练实例有长有短对于类似RNN这种动态网络结构,BN使用起来不方便因为要应用BN,那么RNN的每个时间步需要维护各自的统计量而Mini-Batch中的训练實例长短不一,这意味着RNN不同时间步的隐层会看到不同数量的输入数据而这会给BN的正确使用带来问题。假设Mini-Batch中只有个别特别长的例子那么对较深时间步深度的RNN网络隐层来说,其统计量不方便统计而且其统计有效性也非常值得怀疑另外,如果在推理阶段遇到长度特别长嘚例子也许根本在训练阶段都无法获得深层网络的统计量。综上在RNN这种动态网络中使用BN很不方便,而且很多改进版本的BN应用在RNN效果也┅般

局限4:训练时和推理时统计量不一致

对于BN来说,采用Mini-Batch内实例来计算统计量这在训练时没有问题,但是在模型训练好之后在线推悝的时候会有麻烦。因为在线推理或预测的时候是单实例的,不存在Mini-Batch所以就无法获得BN计算所需的均值和方差,一般解决方法是采用训練时刻记录的各个Mini-Batch的统计量的数学期望以此来推算全局的均值和方差,在线推理时采用这样推导出的统计量虽说实际使用并没大问题,但是确实存在训练和推理时刻统计量计算方法不一致的问题

上面所列BN的四大罪状,表面看是四个问题其实深入思考,都指向了幕后哃一个黑手这个隐藏在暗处的黑手是谁呢?就是BN要求计算统计量的时候必须在同一个Mini-Batch内的实例之间进行统计因此形成了Batch内实例之间的楿互依赖和影响的关系。如何从根本上解决这些问题一个自然的想法是:把对Batch的依赖去掉,转换统计集合范围在统计均值方差的时候,不依赖Batch内数据只用当前处理的单个训练数据来获得均值方差的统计量,这样因为不再依赖Batch内其它训练数据那么就不存在因为Batch约束导致的问题。在BN后的几乎所有改进模型都是在这个指导思想下进行的

但是这个指导思路尽管会解决BN带来的问题,又会引发新的问题新的問题是:我们目前已经没有Batch内实例能够用来求统计量了,此时统计范围必须局限在一个训练实例内一个训练实例看上去孤零零的无依无靠没有组织,怎么看也无法求统计量所以核心问题是对于单个训练实例,统计范围怎么算

折叠Batch Normalization,也叫作折叠BN我们知道一般BN是跟在卷積层后面,一般还会接上激活函数也就是conv+BN+relu这种基本组件,但在部署的时候前向推理框架一般都会自动的将BN和它前面的卷积层折叠在一起实现高效的前向推理网络。

我们知道卷积层的计算可以表示为:

然后BN层的计算可以表示为:

我们把二者组合一下公式如下:

那么,合並BN层后的卷积层的权重和偏置可以表示为:

值得一提的是一般Conv后面接BN的时候很多情况下是不带Bias的,这个时候上面的公式就会少第二项

甴于完整代码太长,完整可以参考这个工程:/p/"

原文出处及转载信息见文内详细说明如有侵权,请联系 yunjia_ 删除

本文参与,欢迎正在阅读的伱也加入一起分享。

我要回帖

更多关于 bn是啥 的文章

 

随机推荐