卷积神经网络架构

从DensNet到CliqueNet,近来在卷积神经网络架构上的探索

卷积神经网络架构一直是计算机视觉领域的研究重点,很多分类、检测和分割等任务都依赖于基本架构提供更好的性能。本文先概览了经典的卷积网络架构及它们的优缺点,其次重点分析了CVPR 去年的最佳论文 DenseNet与今年北大等研究机构提出的 CliqueNet,这篇论文接收为CVPR 2018的Orals/Spotlights。

在微软亚洲研究院主办的 CVPR 2018 中国论文分享会中,我们发现了一篇非常有意思的论文,它介绍了一种新型卷积网络架构,并且相比于 DenseNet 能抽取更加精炼的特征。这种 CliqueNet 不仅有前向的密集型连接,同时还有反向的密集型连接来提炼前面层级的信息。

卷积架构

其实我们已经对各种卷积架构都非常熟悉了,因此这一部分只简要介绍具有代表性的卷积结构与方法。首先第一种当然是 Yann LeCun 在 1998 年提出的 LeNet-5,它奠定了整个卷积神经网络的基础。正如LeCun在LeNet-5原论文中所说,卷积网络结合了三种关键性思想来确保模型对图像的平移、缩放和扭曲具有一定程度的不变性,这三种关键思想即局部感受野、权重共享和空间/时间子采样。其中局部感受野表示卷积核只关注图像的局部特征,而权重共享表示一个卷积核在整张图像上都使用相同的权值,最后的子采样即我们常用的池化操作,它可以精炼抽取的特征。

原论文:GradientBased Learning Applied to Document Recognition

上图是 LeNet-5 架构,它叠加了两个卷积层与池化层来抽取图像特征,然后再将抽取的特征传入两个全连接层以组合所有特征并识别图像类别。虽然LeNet-5很早就提出来了,且架构和现在很多简单的卷积网络非常相似,但当时可能限于计算资源和数据集等条件并没有得到广泛应用。

第一个得到广泛关注与应用的卷积神经网络是2012年提出来的AlexNet,它相比于 LeNet-5 最大的特点是使用更深的卷积网络和 GPU 进行并行运算。如下所示,AlexNet 有5个卷积层和3个最大池化层,它可分为上下两个完全相同的分支,这两个分支在第三个卷积层和全连接层上可以相互交换信息。AlexNet 将卷积分为两个分支主要是因为需要在两块老式 GTX580 GPU上加速训练,且单块 GPU 无法为深度网络提供足够的内存,因此研究者将网络分割为两部分,并馈送到两块 GPU 中。

原论文:ImageNet Classification with Deep Convolutional Neural Networks

AlexNet 还应用了非常多的方法来提升模型性能,包括第一次使用ReLU非线性激活函数、第一次使用Dropout以及大量数据增强实现网络的正则化。除此之外,AlexNet还使用了带动量的随机梯度下降、L2权重衰减以及CNN的集成方法,这些方法现在都成为了卷积网络不可缺少的模块。

到了2014年,牛津大学提出了另一种深度卷积网络VGG-Net,它相比于AlexNet有更小的卷积核和更深的层级。AlexNet前面几层用了11×11和 5×5 的卷积核以在图像上获取更大的感受野,而VGG采用更小的卷积核与更深的网络提升参数效率。一般而言,叠加几个小的卷积核可以获得与大卷积核相同的感受野,而叠加小卷积核使用的参数明显要少于一个大卷积核。此外,叠加小卷积核因为加深了卷积网络,能引入更强的非线性。

原论文:VERY DEEP CONVOLUTIONAL NETWORKS FOR LARGE-SCALE IMAGE RECOGNITION

VGG-Net 的泛化性能较好,常用于图像特征的抽取目标检测候选框生成等。VGG最大的问题就在于参数数量,VGG-19基本上是参数量最多的卷积网络架构。VGG-Net的参数主要出现在后面两个全连接层,每一层都有4096个神经元,可想而至这之间的参数会有多么庞大。

同样在2014年,谷歌提出了 GoogLeNet(或Inception-v1)。该网络共有22层,且包含了非常高效的Inception模块,它同样没有如同VGG-Net那样大量使用全连接网络,因此参数量非常小。GoogLeNet最大的特点就是使用了Inception模块,它的目的是设计一种具有优良局部拓扑结构的网络,即对输入图像并行地执行多个卷积运算或池化操作,并将所有输出结果拼接为一个非常深的特征图。因为1×1、3×3或5×5等不同的卷积运算与池化操作可以获得输入图像的不同信息,并行处理这些运算并结合所有结果将获得更好的图像表征。

原论文:Going Deeper with Convolutions

一般Inception模块的参数虽然少,但很多并行的卷积运算需要很多计算量。直接拼接不同的卷积运算会产生巨量的运算,因此修正的Inception模块每一个卷积分支都会先执行一个1×1的卷积将通道数大大减少,这也相当于对输入数据进行降维而简化运算。此外,GoogLeNet中间多出来的两个分类网络主要是为了向前面的卷积与Inception模块提供额外的梯度进行训练。因为随着网络的加深,梯度无法高效地由后向前传,网络参数也就得不到更新。这样的分支则能减轻深度网络的梯度传播问题,但这种修补并不优美,也不能解决更深网络的学习问题。

最后,何恺明等人于2015年提出来的深度残差网络骤然将网络深度由十几二十层提升到上百层。ResNet 最大的特点即解决了反向传播过程中的梯度消失问题,因此它可以训练非常深的网络而不用像GoogLeNet那样在中间添加分类网络以提供额外的梯度。根据ResNet原论文,设计的出发点即更深的网络相对于较浅的网络不能产生更高的训练误差,因此研究者引入了残差连接以实现这样的能力。

原论文:Deep Residual Learning for Image Recognition

如上黑色曲线,ResNet引入了残差连接。在每一个残差模块上,残差连接会将该模块的输入与输出直接相加。因此在反向传播中,根据残差连接传递的梯度就可以不经过残差模块内部的多个卷积层,因而能为前一层保留足够的梯度信息。此外,每一个残差模块还可以如同Inception模块那样添加1×1卷积而形成瓶颈层。这样的瓶颈结构对输入先执行降维再进行卷积运算,运算完后对卷积结果升维以恢复与输入相同的维度,这样在低维特征上进行计算能节省很多计算量。

DenseNet

ResNet虽然非常高效,但如此深的网络并不是每一层都是有效的。最近一些研究表明ResNet中的很多层级实际上对整体的贡献非常小,即使我们在训练中随机丢弃一些层级也不会有很大的影响。这种卷积层和特征图的冗余将降低模型的参数效率,并加大计算力的需求。为此,Gao Huang等研究者提出了DenseNet,该论文获得了CVPR 2017的最佳论文。

DenseNet的目标是提升网络层级间信息流与梯度流的效率,并提高参数效率。它也如同ResNet那样连接前层特征图与后层特征图,但DenseNet并不会像ResNet那样对两个特征图求和,而是直接将特征图按深度相互拼接在一起。DenseNet最大的特点即每一层的输出都会作为后面所有层的输入,这样最后一层将拼接前面所有层级的输出特征图。这种结构确保了每一层能从损失函数直接访问到梯度,因此可以训练非常深的网络。

原论文:Densely Connected Convolutional Networks

如上所示为Dense Block的结构,特征图X_2在输入 $X_0$ 与 $X_1$ 的条件下执行卷积运算得出,同时 $X_2$ 会作为计算 $X_3$ 和 $X_4$ 的输入。一般对于L层的DenseNet,第l层有l个输入特征图和 L-l 个输出特征图,因此它一共拥有 L(L+1)/2 个连接。这种密集连接型的网络也就形象地称为DenseNet了。

此外,Gao Huang等研究者在原论文表示DenseNet所需要的参数更少,因为它相对于传统卷积网络不需要重新学习冗余的特征图。具体来说,DenseNet的每一层都有非常浅的特征图或非常少的卷积核,例如12、24、32等,因此能节省很多网络参数。

又因为每一层输出的特征图都比较浅,所以每一层都能将前面所有层级的特征图拼接为一个较深的特征图而作为输入,这样每一层也就复用了前面的特征图。特征图的复用能产生更紧凑的模型,且拼接由不同层产生的特征图能提升输入的方差和效率。

形式化来说,若给定一张图像 $x_0$ 馈送到L层的DenseNet中,且 $H_l()$ 表示第l层包含卷积、池化、BN和激活函数等的非线性变换,那么第l层的输出可以表示为 $X_l$ 。对于DenseNet的密集型连接,第l层的输出特征图可以表示为:

$ \mathbf { x } _ { \ell } = H _ { \ell } \left( \left[ \mathbf { x } _ { 0 } , \mathbf { x } _ { 1 } , \dots , \mathbf { x } _ { \ell - 1 } \right] \right) $

其中 $[x_0, x_1, . . . , x_{l−1}]$ 表示从 0 到 l-1 层产生的特征图,为了简化计算,它们会按深度拼接为单个张量。在原论文的实现中,$H_l()$ 为包含了三个模块的复合函数,即先执行批量归一化和 ReLU 激活函数,再执行1个3×3的卷积。

上述方程若想将特征图按深度拼接,那么所有特征图的尺寸就需要相等。一般常用的方法是控制卷积核的移动步幅或添加池化运算,DenseNet将网络分为不同的Dense Block,并在Dense Block之间调整特征图的大小。

如上所示,密集连接块之间的转换层会通过卷积改变特征图深度,通过池化层改变特征图尺寸。在原论文的实现中,转换层先后使用了批量归一化、1×1的逐点卷积和2×2的平均池化。

此外,若Dense Block中的H_l 输出k张特征图,那么第l层的输入特征图就有k_0 + k × (l - 1) 张,其中k_0为输入图像的通道数。由于输入特征图的深度或张数取决于k,DenseNet每一个卷积都有比较浅的特征图,即k值很小。在ImageNet中,DenseNet的k值设为了32。

不过尽管k值比较小,但在后面层级的卷积运算中,输入的特征图深度还是非常深的。因此与ResNet的残差模块和 GoogLeNet 的 Inception 模块一样,DenseNet 同样在 3×3 卷积运算前加入了1×1逐点卷积作为瓶颈层来减少输入特征图的深度。因此我们可以将H_l 由原版的 BN-ReLU-Conv(3×3) 修正为:BN-ReLU-Conv(1× 1)-BN-ReLU-Conv(3×3)。除了加入瓶颈层,DenseBlock间的转换层也可以通过1×1卷积减低特征图的维度。

以下表格是DenseNet在ImageNet数据集上所采用的架构,其中每个卷积层的卷积核数k=32,“conv”层对应于原版H_l或添加了瓶颈层的H_l。

在实践中,很多研究者都表示DenseNet的参数虽然少,但显存占用非常恐怖。这主要是因为大量的特征图拼接操作和BN运算结果都会占用新的显存,不过现在已经有研究者修改代码而降低显存占用。此外,DenseNet的计算量也非常大,很难做到实时语义分割等任务。

CliqueNet

DenseNet 通过复用不同层级的特征图,减少了不同层间的相互依赖性,且最终的预测会利用所有层的信息而提升模型鲁棒性。但是 Yunpeng Chen 等研究者在论文 Dual Path Networks 中表示随着网络深度的增加,DenseNet中的密集型连接路径会线性地增加,因此参数会急剧地增加。这就导致了在不特定优化实现代码的情况下会消耗大量的 GPU 显存。而在北大杨一博等研究者提出来的 CliqueNet 中,每个 Clique Block 只有一张经过提炼的特征图会馈送到下一个 Clique Block,这样就大大增加了参数效率。

CliqueNet 最大的特点是其不仅有前传的部分,同时还能根据后面层级的输出对前面层级的特征图做优化。这种网络架构受到了循环结构与注意力机制的启发,即卷积输出的特征图可重复使用,经过提炼的特征图将注意更重要的信息。在同一个Clique模块内,任意两层间都有前向和反向连接,这也就提升了深度网络中的信息流。

CliqueNet的每一个模块可分为两个阶段,第一个阶段如同DenseNet那样传播,这可以视为预训练过程。而第二个阶段如下图所示每一个卷积运算的输入不仅包括前面所有层的输出特征图,同样还包括后面层级的输出特征图。第二阶段中的循环反馈结构会利用高级视觉信息提炼前面层级的卷积核,因而能实现空间注意力的效果。此外,这两个阶段也可以视为对卷积核权重的交替更新,即先如同常规网络更新一次卷积核,再利用高层抽象信息更新一次卷积核。

如上所示在第一阶段中,若输入0、1、2号特征图的拼接张量,卷积运算可得出特征图3。在第二阶段中,特征图1会根据第一阶段输出的2、3、4号拼接特征图计算得出,我们可将其称为已更新特征图1。第二阶段的特征图3在输入第一阶段的输出特征图4和已更新特征图1、2的情况下得出。

Clique Block中的第一阶段比较好理解,与上文Dense Block的前向传播相同。可能读者对第二阶段的传播过程仍然有些难以理解,不过原论文中给出了一个很好的表达式来描述第2阶段。对于第二阶段中的第i层和第k(k >= 2)个循环,交替更新的表达式为:

$ X _ { i } ^ { ( k ) } = g \left( \sum _ { l < i } W _ { l i } \star X _ { l } ^ { ( k ) } + \sum _ { m > i } W _ { m i } \star X _ { m } ^ { ( k - 1 ) } \right) $

其中 k >= 2,上面Clique Block的展开图k=2。$W × X$ 表示卷积核在输入特征图上做卷积运算,g为非线性激活函数。若 k=2,那么第i层更新后的特征图 $X_{i}^{k}$,可通过拼接前面层级(l<i)已更新的特征图 $W × X^k$ 和后面层级(m>i)前一个循环的特征图 $W × X^{(k-1)}$得出。在这个式子中,加号和累加都表示按特征图深度的拼接运算。

如上所示有两套卷积核,即阶段2中的前向卷积运算与反向卷积运算。反向卷积运算会利用前一阶段的特征图作为输出产生多组新的特征图,并且它们将作为后一阶段前向传播的输入。此外,每一套卷积核参数在不同阶段中是共享的,其它们共同产生一套特征图。

杨一博等研究者还展示了带有五个卷积层的Clique Block传播方式,其中 $W_{ij}$ 表示 $X_i$ 到 $X_j$ 的参数,它可以重复利用和更新,“{}”表示拼接操作。

如上所示,第一阶段的输出特征图都是拼接前面层级的特征图 $X^1$ 并做对应的卷积运算而得出。第二阶段的输出特征图会拼接前面层级更新过的特征图 $X^2$ 与第一阶段的特征图 $X^1$ 而得出。

除了特征图的复用与提炼外,CliqueNet还采用了一种多尺度的特征策略来避免参数的快速增长。具体如下所示我们将每一个Block的输入特征图与输出特征图拼接在一起,并做全局池化以得到一个向量。将所有Block的全局池化结果拼接在一起就能执行最后的预测。由于损失函数是根据所有Block结果计算得出,那么各个Block都能等价地访问梯度信息。

此外,由于每一个 Block 只有第二阶段的输出会作为下一个 Block 的输入,因此 Block 的特征图维度也不会逐渐地增加。

如下所示为 CliqueNet 的关键代码,build_model函数会先构建 3 个 Clique Block,并将它们全局池化的结果传入列表中。最终的特征即使用 tf.concat() 函数将所有池化结果拼接在一起,且在进行一个线性变换后可传入Softmax 函数获得类别的预测概率。

import tensorflow as tf
from utils import *

block_num=3

def build_model(input_images, k, T, label_num, is_train, keep_prob, if_a, if_b, if_c):

current=first_transit(input_images, channels=64, strides=1, with_biase=False)
current_list=[]

## build blocks
for i in range(block_num):
block_feature, transit_feature = loop_block_I_II(current, if_b, channels_per_layer=k, layer_num=T/3, is_train=is_train, keep_prob=keep_prob, block_name='b'+str(i))
if if_c==True:
block_feature=compress(block_feature, is_train=is_train, keep_prob=keep_prob, name='com'+str(i))
current_list.append(global_pool(block_feature, is_train))
if i==block_num-1:
break
current=transition(transit_feature, if_a, is_train=is_train, keep_prob=keep_prob, name='tran'+str(i))


## final feature
final_feature=current_list[0]
for block_id in range(len(current_list)-1):
final_feature=tf.concat((final_feature, current_list[block_id+1]),
axis=3)
feature_length=final_feature.get_shape().as_list()[-1]
print 'final feature length:',feature_length

feature_flatten=tf.reshape(final_feature, [-1, feature_length])
## final_fc
Wfc=tf.get_variable(name='FC_W', shape=[feature_length, label_num], initializer=tf.contrib.layers.xavier_initializer())
bfc=tf.get_variable(name='FC_b', initializer=tf.constant(0.0, shape=[label_num]))

logits=tf.matmul(feature_flatten, Wfc)+bfc
prob=tf.nn.softmax(logits)

return logits, prob

以上的CliqueNet就是北京大学和上海交通大学在CVPR 2018对卷积网络架构的探索,也许还有更多更高效的结构,但这需要研究社区长期的努力。