Implementação do mecanismo de atenção CBAM

1. Introdução ao CBAM

Artigo: CBAM: Convolutional Block Attention
Module
propõe um módulo de atenção simples, mas eficaz, CBAM, dado um mapa de recursos intermediário, inferir o peso da atenção ao longo das duas dimensões do espaço e do canal e, em seguida, multiplicá-lo com o mapa de recursos original Faça ajustes adaptáveis ​​aos recursos. Como o CBAM é um módulo leve de uso geral, ele pode ser perfeitamente integrado em qualquer arquitetura CNN com sobrecarga adicional insignificante e pode ser treinado de ponta a ponta junto com o CNN básico. Depois de integrar o CBAM em diferentes modelos em diferentes conjuntos de dados de classificação e detecção, o desempenho do modelo foi aprimorado de forma consistente, demonstrando sua ampla aplicabilidade.
O CBAM pode ser dividido em duas partes: módulo de canal de atenção e módulo de atenção espacial, conforme figura abaixo.
Insira a descrição da imagem aqui

  • Módulo de atenção do canal: preste atenção a quais recursos são significativos.
    Insira um mapa de recursos F como H W C (na verdade, pode haver lote, ou seja, NHWC). Primeiro, execute um agrupamento máximo de espaço global e um agrupamento médio para obter dois Um descritor 1 1 C. Em seguida, envie-os para MLP (contendo uma camada oculta), o número de neurônios na primeira camada é C / r, e o número de neurônios na segunda camada é C. Essa rede neural é compartilhada (não sei se é compartilhada entre dois descritores ou duas camadas de redes neurais, que deveriam ser a última). Em seguida, aplique a adição de elemento a dois vetores de saída e obtenha o coeficiente de peso Mc por meio da função sigmóide. Finalmente, multiplique Mc pelo traço original F para obter um novo traço F '
  • Módulo de atenção espacial: Preste atenção para onde as características são significativas.
    Insira o mapa de características F'as H W C (também pode ter lote). Primeiro, dois descritores de H W 1 são obtidos por meio de pool médio de canal e pooling máximo . E emendado por canal. Em seguida, através de uma camada convolucional 7 * 7 e função de ativação sigmóide, o coeficiente de peso Ms é obtido. Finalmente, multiplique Ms e F'para obter o recurso de atenção final.

2. Implementação do código

Depois de ler o processo acima, é fácil entender a implementação do código.Aqui estão duas partes do código. Um é para se referir ao código do blogger , e o outro é Github: kobiso / CBAM-tensorflow .
Código um:

def combined_static_and_dynamic_shape(tensor):
    """Returns a list containing static and dynamic values for the dimensions.  Returns a list of static 
    and dynamic values for shape dimensions. This is  useful to preserve static shapes when available in reshape operation.  
    Args:    tensor: A tensor of any type.  
    Returns:    A list of size tensor.shape.ndims containing integers or a scalar tensor.  """
    static_tensor_shape = tensor.shape.as_list()
    dynamic_tensor_shape = tf.shape(tensor)
    combined_shape = []
    for index, dim in enumerate(static_tensor_shape):
        if dim is not None:
            combined_shape.append(dim)
        else:
            combined_shape.append(dynamic_tensor_shape[index])
    return combined_shape


def convolutional_block_attention_module(feature_map, index, reduction_ratio = 0.5):
    """CBAM:convolutional block attention module
    Args:
        feature_map:input feature map
        index:the index of the module
        reduction_ratio:output units number of first MLP layer:reduction_ratio * feature map
    Return:
        feature map with channel and spatial attention"""

    with tf.variable_scope("cbam_%s" % (index)):
        feature_map_shape = combined_static_and_dynamic_shape(feature_map)
        # channel attention module
        channel_avg_weights = tf.nn.avg_pool(value=feature_map,
                                             ksize=[1, feature_map_shape[1], feature_map_shape[2], 1],
                                             strides=[1, 1, 1, 1],
                                             padding='VALID')  # global average pool
        channel_max_weights = tf.nn.max_pool(value=feature_map,
                                             ksize=[1, feature_map_shape[1], feature_map_shape[2], 1],
                                             strides=[1, 1, 1, 1],
                                             padding='VALID')
        channel_avg_reshape = tf.reshape(channel_avg_weights,
                                         [feature_map_shape[0], 1, feature_map_shape[3]])
        channel_max_reshape = tf.reshape(channel_max_weights,
                                         [feature_map_shape[0], 1, feature_map_shape[3]])
        channel_w_reshape = tf.concat([channel_avg_reshape, channel_max_reshape], axis=1)

        fc_1 = tf.layers.dense(inputs=channel_w_reshape,
                               units=feature_map_shape[3] * reduction_ratio,
                               name="fc_1",
                               activation=tf.nn.relu)
        fc_2 = tf.layers.dense(inputs=fc_1,
                               units=feature_map_shape[3],
                               name="fc_2",
                               activation=None)
        channel_attention = tf.reduce_sum(fc_2, axis=1, name="channel_attention_sum")
        channel_attention = tf.nn.sigmoid(channel_attention)
        channel_attention = tf.reshape(channel_attention,
                                       shape=[feature_map_shape[0], 1, 1, feature_map_shape[3]])
        feature_map_with_channel_attention = tf.multiply(feature_map, channel_attention)
        # saptial attention module
        # 通道平均池化,格式NWHC
        channel_wise_avg_pooling = tf.reduce_mean(feature_map_with_channel_attention, axis=3)
        channel_wise_avg_pooling = tf.reshape(channel_wise_avg_pooling,
                                              shape=[feature_map_shape[0], feature_map_shape[1],
                                                     feature_map_shape[2], 1]) # shape=[batch, H, W, 1]
        # 通道最大池化
        channel_wise_max_pooling = tf.reduce_max(feature_map_with_channel_attention, axis=3)
        channel_wise_max_pooling = tf.reshape(channel_wise_max_pooling,
                                              shape=[feature_map_shape[0], feature_map_shape[1],
                                                     feature_map_shape[2], 1])
        # 按通道拼接
        channel_wise_pooling = tf.concat([channel_wise_avg_pooling, channel_wise_max_pooling], axis=3)
        spatial_attention = slim.conv2d(channel_wise_pooling, 1, [7, 7],
                                        padding='SAME',
                                        activation_fn=tf.nn.sigmoid,
                                        scope="spatial_attention_conv")
        feature_map_with_attention = tf.multiply(feature_map_with_channel_attention, spatial_attention)
        return feature_map_with_attention

Quando este código é implementado no módulo de atenção do canal, os dois descritores 1 1 C são emendados primeiro e depois inseridos no MLP, e os pesos das duas camadas MLP não são compartilhados, o que parece um pouco problemático. Outro código será colocado no próximo blog devido ao limite de palavras.
Coloquei este módulo em uma das minhas redes neurais de quatro camadas para classificação MNIST manuscrita, mas não acho que a precisão tenha melhorado muito e, intuitivamente, sinto que funciona mais lentamente. No artigo, inserindo CBAM em algumas redes grandes, eu sinto que a melhoria de desempenho não é particularmente grande. . .

Acho que você gosta

Origin blog.csdn.net/qq_43265072/article/details/106057548
Recomendado
Clasificación