SE-Inception v3架构的模型搭建(keras代码实现)

首先,先上SENet架构的原理图:(这里r=16)
SE-Inception v3架构的模型搭建(keras代码实现)
SE-Inception v3架构的模型搭建(keras代码实现)
图是将SE模块嵌入到Inception结构的一个示例。方框旁边的维度信息代表该层的输出。这里我们使用global average pooling作为Squeeze操作。紧接着两个Fully Connected 层组成一个Bottleneck结构去建模通道间的相关性,并输出和输入特征同样数目的权重。我们首先将特征维度降低到输入的1/16,然后经过ReLu**后再通过一个Fully Connected 层升回到原来的维度。 这样做比直接用一个Fully Connected层的好处在于:

  • 具有更多的非线性,可以更好地拟合通道间复杂的相关性;
  • 极大地减少了参数量和计算量。然后通过一个Sigmoid的门获得0~1之间归一化的权重,最后通过一个Scale的操作来将归一化后的权重加权到每个通道的特征上;

SENet架构(Squeeze And Excitation),无非就是Squeeze操作和Excitation操作:

  • 首先是Squeeze操作,我们顺着空间维度来进行特征压缩,将每个二维的特征通道变成一个实数,这个实数某种程度上具有全局的感受野,并且输出的维度和输入的特征通道数相匹配。它表征着在特征通道上响应的全局分布,而且使得靠近输入的层也可以获得全局的感受野,这一点在很多任务中都是非常有用的。
  • 其次是Excitation操作,它是一个类似于循环神经网络中门的机制。通过参数 来为每个特征通道生成权重,其中参数 被学习用来显式地建模特征通道间的相关性。
  • 最后是一个Reweight的操作,我们将Excitation的输出的权重看做是进过特征选择后的每个特征通道的重要性,然后通过乘法逐通道加权到先前的特征上,完成在通道维度上的对原始特征的重标定。

接下来是代码实现:

def build_model(nb_classes, input_shape=(256,256,3)):
    inputs_dim = Input(input_shape)
    x = InceptionV3(include_top=False,
                weights='imagenet',
                input_tensor=None,
                input_shape=(256, 256, 3),
                pooling=max)(inputs_dim)

    squeeze = GlobalAveragePooling2D()(x)

    excitation = Dense(units=2048 // 16)(squeeze)
    excitation = Activation('relu')(excitation)
    excitation = Dense(units=2048)(excitation)
    excitation = Activation('sigmoid')(excitation)
    excitation = Reshape((1, 1, 2048))(excitation)

    scale = multiply([x, excitation])

    x = GlobalAveragePooling2D()(scale)
    dp_1 = Dropout(0.3)(x)
    fc2 = Dense(nb_classes)(dp_1)
    fc2 = Activation('sigmoid')(fc2) #此处注意,为sigmoid函数
    model = Model(inputs=inputs_dim, outputs=fc2)
    return model

if __name__ == '__main__':
	model =build_model(nb_classes, input_shape=(im_size1, im_size2, channels))
	opt = Adam(lr=2*1e-5)
    model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])
    model.fit()