Bottleneck块
Bottleneck模块的思想是通过1×1卷积先减少维度再增加维度,启到减少参数降低运算量的作用。
def bottleneck_module(x, out_dim, ratio=4):
conv = Conv2D(filters=out_dim // ratio, kernel_size=1)(x)
conv = Conv2D(filters=out_dim // ratio, kernel_size=3)(conv)
conv = Conv2D(filters=out_dim, kernel_size=1)(conv)
return conv
Inception块
Inception模块的思想是并行使用不同类型的卷积核,进行多特征融合,同时引入Bottleneck思想采用1×1的卷积先对特征通道降维减少计算量。
def inception_module(x, out_dim, ratio=4):
conv1_1 = Conv2D(filters=out_dim, kernel_size=1)(x)
conv3_3 = Conv2D(filters=out_dim // ratio, kernel_size=1)(x)
conv3_3 = Conv2D(filters=out_dim, kernel_size=3)(conv3_3)
conv5_5 = Conv2D(filters=out_dim // ratio, kernel_size=1)(x)
conv5_5 = Conv2D(filters=out_dim, kernel_size=5)(conv5_5)
maxpool = GlobalMaxPooling2D(kernel_size=3, strider=1)(x)
maxpool = Conv2D(out_dim, kernel_size=1)(maxpool)
return convatenate([conv1_1, conv3_3, conv5_5, maxpool])
ResNet块
ResNet模块的思想是通过跳跃结构解决深度网络退化问题,并在改进版本中引入Bottleneck思想。
def resnet_module(x, out_dim):
conv = Conv2D(filters=out_dim, kernel_size=3)(x)
conv = Conv2D(filters=out_dim, kernel_size=3)(conv)
result = add([x, conv])
return result
ResNeXt块
ResNeXt模块的思想是Inception+ResNet+Group convolution,对于所有的输入通道,将它们分成组。卷积只在组中进行,不会跨组。可以发现,每个组会学到不同的特征,提高了权值的效率。。打破deeper或者wider改善网络性能的常规思路,引入新的维度cardinality。左边是ResNet结构,可以看作是两个branch的网络,其中一个branch则是identity mapping。此时,对于ResNet来说,该网络的cardinality为2。而右边则是ResNeXt结构,可以看作是32个branch组成的网络。右边的ResNeXt结构则很容易让我们想起GooLeNet上的Inception,在Inception网络中,有个重要的策略则是split-transform-merge. 对输入进行split成a few lower-dimention embeding(1x1),然后在通过(3x3或5x5)的卷积核进行transformed,最后由concatenation来进行merge。
def resnext_module(x, out_dim=32, ratio=2, c=4):
l = []
for i in range(c):
conv = Conv2D(filters=out_dim // (c * ratio), kernel_size=1)(x)
conv = Conv2D(filters=out_dim // (c * ratio), kernel_size=3)(conv)
conv = Conv2D(conv, out_dim, kernel_size=1)
l.append(conv)
conv = add(l)
return add([x, conv])
DenseNet块
Dense块是残差块的一种极端的版本,每一个卷积层都会得到该模块中之前的所有卷积层的输出。第一,我们将输入的激活加到一个列表中,然后进入一个循环,遍历这模块的深度。每个卷积的输出都会加到这个列表中,所以下面的循环会得到越来越多的输入特征图,直到到达预定的深度。
def dense_module(x, out_dim=32, d=5):
l = x
for i in range(d):
conv = Conv2D(out_dim=32)(l)
l = concatenate([l, conv])
return l
SENet块
SENet核心思想:通过显式地建模卷积特征通道之间的相互依赖性自适应地重新校准通道的特征响应来提高网络的表示能力。由输入X得到输出U以后,对U的每个通道进行全局平均池化得到通道描述子(Squeeze),再利用两层FC得到每个通道的权重值,对U按通道进行重新加权得到最终输出(Excitation),这个过程称之为feature recalibration,通过引入attention重新加权,可以得到抑制无效特征,提升有效特征的权重,并很容易地和现有网络结合,提升现有网络性能,而计算量不会增加太多。
def squeeze_excitation_module(x, out_dim, ratio=16):
squeeze = GlobalAveragePooling2D()(x)
excitation = Dense(units=out_dim // ratio)(squeeze)
excitation = Activation(excitation)
excitation = Dense(units=out_dim)(excitation)
excitation = Activation(excitation, 'sigmoid')
excitation = Reshape((1, 1, out_dim))(excitation)
scale = multiply([x, excitation])
return scale
每个学习到的滤波器都对局部感受野进行操作,因此变换输出U的每个单元都无法利用该区域之外的上下文信息,在网络较低层次上其感受野尺寸很小,该问题尤为严重。故如图红色框标记的Squeeze操作,采用全局平均池化使得网络低层也能利用全局信息。紫色框标注的Excitation操作引入两个全连接层(都是1*1的conv层),即降维层参数为W1,降维比例为r,然后经过一个ReLU,然后是一个参数为W2的升维层。最后得到1*1*C的实数数列结合U通过Scale操作得到最终的输出。