SENet结构笔记

Squeeze-and-Excitation

 

结构:全局池化加一个bottleneck结构。squeeze就是一个全局池化输出1*1*通道数。Excite就是两个全连接层中间夹一个ReLU,后面加一个sigmoid,通过调整输出通道数量整体构成一个bottleneck结构。

squeeze-and-excitation blocks

1.得到指定维度的输出U

Ftr:将输入X转换为shape=H*W*C的特征图U, Ftr定义为卷积操作。(对应到resnet中这一部分可以理解为一系列的卷积+激活+bn操作,目的是得到变化后的特征U)

2.squeeze操作

目的:获取channel dependencies。squeeze这里执行了global average pooling,从而将h和w维度置为1,来得到C维向量z,z中每一个值:

ps.

global pooling是pooling的滑窗size和整张feature map的size一样大。这样,每个 W×H×C 的feature map输入就会被转化为 1×1×C 输出。因此,其实也等同于每个位置权重都为 1/(W×H) 的FC层操作。global pooling 在滑窗内的具体pooling方法可以是任意的,所以就会被细分为global avg poolingglobal max pooling等。

由于传统的pooling太过粗暴,操作复杂,目前业界已经逐渐放弃了对pooling的使用。
替代方案 如下:

    • 采用 Global Pooling 以简化计算;
    • 增大conv的 stride 以免去附加的pooling操作

3.excitation操作

目的:fully capture channel-wise dependencies。

这里 δ是relu,增加非线性。W1的shape=C/r *C,W2的shape= C * C/r,可以理解为先对通道降维再升维,来减少参数计算。这里选用了两个FC层,具体就是a dimensionality-reduction(第一个fc) --relu (激活)-- a dimensionality-increasing layer(第二个fc)+sigmoid层(得到0-1间的分数),最终输出原channel维度大小的向量。

tensorflow实现版本:

def squeeze_excite_block(inputs, ratio=8):
init = inputs
channel_axis = -1
filters = init.shape[channel_axis]
se_shape = (1, 1, filters)

se = GlobalAveragePooling2D()(init)
se = Reshape(se_shape)(se)
se = Dense(filters // ratio, activation='relu', kernel_initializer='he_normal', use_bias=False)(se)
se = Dense(filters, activation='sigmoid', kernel_initializer='he_normal', use_bias=False)(se)

x = Multiply()([init, se])
return x
posted @ 2020-11-17 16:17  葡萄成熟时啊  阅读(546)  评论(0)    收藏  举报