在手写数字识别中加入-CBMA-空间注意力机制-通道注意力机制

 

SE注意力机制复现

本文中利用步长为1,卷积核大小为1的卷积代替多层感知机。

    def build(self, input_shape):
        self.channel = input_shape[-1] #[B,H,W,C]去除通道数
        self.MLP1 = layers.Conv2D(filters=self.channel//self.chanel, kernel_size=1, strides=1, activation="relu")
        self.MLP2 = layers.Conv2D(filters=self.channel, activation="sigmoid", kernel_size=1, strides=1)

 


Squeeze(压缩):通过全局平均池化操作(全局最大池化也行)将输入特征图压缩成一个向量。这个向量具有和输入特征图相同的通道数,但每个通道只有一个值,这个值可以看作是对应通道的特征图的全局平均描述。

 x = layers.GlobalAveragePooling2D()(inputs)
 x = layers.Reshape((1, 1, self.channel))(x)


Excitation(激励):使用一个或多个全连接层(通常是瓶颈结构,即先降维再升维)对这个压缩后的向量进行处理,以生成一个和输入特征图通道数相同的权重向量。这个权重向量中的每个元素表示对应通道的注意力权重,值越大表示该通道越重要。

x = self.MLP1(x)
x = self.MLP2(x)


Scale(缩放):将激励步骤得到的权重向量与原始输入特征图进行逐通道相乘,实现对原始特征图的重新加权。这样,网络就能够更加关注重要的特征通道,而忽略不重要的通道。

x = inputs*x

完整代码:

import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras import layers, Sequential
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape((-1, 28, 28, 1)) / 255.0


y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)

class Se_Block(layers.Layer):
    def __init__(self, reduction=16, way="Max"):
        super(Se_Block,self).__init__()
        self.reduction = reduction
        self.channel = None
        self.MLP1 = None
        self.MLP2 = None
        self.way = way

    def build(self, input_shape):
        self.channel = input_shape[-1] #[B,H,W,C]去除通道数
        self.MLP1 = layers.Conv2D(filters=self.channel//self.channel, kernel_size=1, strides=1, activation="relu")
        self.MLP2 = layers.Conv2D(filters=self.channel, activation="sigmoid", kernel_size=1, strides=1)

    def call(self, inputs, *args, **kwargs):
        if self.way == "Average":
            x = layers.GlobalAveragePooling2D()(inputs)#压缩
            x = layers.Reshape((1, 1, self.channel))(x)
            x = self.MLP1(x)#降维
            x = self.MLP2(x)#升维
        if self.way == "Max":
            x = layers.GlobalMaxPool2D()(inputs)
            x = layers.Reshape((1, 1, self.channel))(x)
            x = self.MLP1(x)#降维
            x = self.MLP2(x)#升维
        if self.way =="combination":
            x1 = layers.GlobalMaxPool2D()(inputs)
            x2 = layers.GlobalAveragePooling2D()(inputs)  # 压缩
            x1 = layers.Reshape((1, 1, self.channel))(x1)
            x2 = layers.Reshape((1, 1, self.channel))(x2)
            x1 = self.MLP1(x1)#降维
            x1 = self.MLP2(x1)#升维
            x2 = self.MLP1(x2)#降维
            x2 = self.MLP2(x2)#升维
            x = x1+x2
        x = inputs*x #scale
        return x




model = Sequential([
    layers.Conv2D(filters=16, kernel_size=3, strides=2, activation='relu', input_shape=(28, 28, 1)),
    Se_Block(way="combination"),
    layers.Flatten(),
    layers.Dense(10, activation="softmax")
])
model.summary()
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train, y_train, epochs=10, batch_size=32)

4f83aba5cfc74c4a93dc662e99bc8930.png

SE模块即插即用,可以随意放置。本文只是简单的实现了一下,所以只用了一层卷积。

 

各个版本se测试,最终可以看出组合版的其实要好一点点。 但是手写数字这个数据集太简单,看不出太大差距。

最大池化:

acbec427738d47c0894df5a03392e238.png

平均池化:

8b65ecc2762e49ca95e89ebfb081a4a6.png

组合版:

33bc45ba576d402bb09fb80d5002dfbe.png

 

 

加上空间注意力机制

cd0f6a715fa144f1bbcd1b8e9a10e1b3.png

有2种实现方式,直接卷积,或着沿着通道维度池化后再卷积。

空间注意力机制

实现第二种方式,第一种太简单了就不实现了。

代码:

import tensorflow as tf
from tensorflow.keras.datasets import mnist
from tensorflow.keras import layers, Sequential
(x_train, y_train), (x_test, y_test) = mnist.load_data()
x_train = x_train.reshape((-1, 28, 28, 1)) / 255.0


y_train = tf.keras.utils.to_categorical(y_train, 10)
y_test = tf.keras.utils.to_categorical(y_test, 10)


class Se_Block(layers.Layer):
    def __init__(self, reduction=16, way="Max"):
        super(Se_Block,self).__init__()
        self.reduction = reduction
        self.channel = None
        self.MLP1 = None
        self.MLP2 = None
        self.way = way

    def build(self, input_shape):
        self.channel = input_shape[-1] #[B,H,W,C]去除通道数
        self.MLP1 = layers.Conv2D(filters=self.channel//self.channel, kernel_size=1, strides=1, activation="relu")
        self.MLP2 = layers.Conv2D(filters=self.channel, activation="sigmoid", kernel_size=1, strides=1)

    def call(self, inputs, *args, **kwargs):
        if self.way == "Average":
            x = layers.GlobalAveragePooling2D()(inputs)#压缩
            x = layers.Reshape((1, 1, self.channel))(x)
            x = self.MLP1(x)#降维
            x = self.MLP2(x)#升维

        if self.way == "Max":
            x = layers.GlobalMaxPool2D()(inputs)
            x = layers.Reshape((1, 1, self.channel))(x)
            x = self.MLP1(x)#降维
            x = self.MLP2(x)#升维

        if self.way =="combination":
            x1 = layers.GlobalMaxPool2D()(inputs)
            x2 = layers.GlobalAveragePooling2D()(inputs)  # 压缩
            x1 = layers.Reshape((1, 1, self.channel))(x1)
            x2 = layers.Reshape((1, 1, self.channel))(x2)
            x1 = self.MLP1(x1)#降维
            x1 = self.MLP2(x1)#升维
            x2 = self.MLP1(x2)#降维
            x2 = self.MLP2(x2)#升维
            x = x1+x2
        x = inputs*x #scale
        return x



class SpatialAttention(layers.Layer):
    def __init__(self):
        super(SpatialAttention, self).__init__()
        self.conv2d = layers.Conv2D(filters=1, strides=1, kernel_size=3, padding="same", activation="sigmoid")

    def call(self, inputs, *args, **kwargs):
        MAX = tf.reduce_max(inputs, axis=-1)#[B,w,h,channel],沿着最后一个维度:通道,取最大值,得到的维度为【B,w,h】
        MAX = tf.expand_dims(MAX, axis=-1)#增加通道维度,[B,h,w,1]

        average = tf.reduce_mean(inputs, axis=-1)#同上述一样
        average = tf.expand_dims(average, axis=-1)

        combine = tf.concat([MAX, average], axis=-1)#[B,h,w,2]

        x = self.conv2d(combine)#[B,h,w,1]
        return inputs*x


model = Sequential([
    layers.Conv2D(filters=16, kernel_size=3, strides=2, activation='relu', input_shape=(28, 28, 1)),
    Se_Block(way="Average"),
    SpatialAttention(),
    layers.Flatten(),
    layers.Dense(10, activation="softmax")
])
model.summary()
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.fit(x_train, y_train, epochs=5, batch_size=32)

7842d54f231d4ebdb9e4fa0f17e354be.png

空间注意力机制与通道注意力机制的三种版本组合就不演示了。

2e0f580d89ac48c9b74580fb3d094252.png

 

  • 19
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
SE注意力机制(Squeeze-and-Excitation)是一种用于增强深度神经网络性能的注意力机制。它通过学习通道间的关系来自适应地调整每个通道的重要性,从而提高网络的表达能力。SE注意力机制主要由两个步骤组成:压缩和激励。 在压缩步骤SE注意力机制通过全局平均池化操作将每个通道的特征图压缩为一个标量值。这个标量值表示了该通道的全局重要性。 在激励步骤SE注意力机制使用一个全连接层将压缩后的特征传递给一个Sigmoid激活函数。这个激活函数将输出一个0到1之间的权重值,用于调整每个通道的特征图。 CBAM注意力机制(Convolutional Block Attention Module)是一种结合空间注意力通道注意力注意力机制。它通过同时考虑特征图的空间通道信息来提高网络的表达能力。 CBAM注意力机制主要由两个模块组成:通道注意力模块和空间注意力模块。 通道注意力模块通过全局平均池化操作将每个通道的特征图压缩为一个标量值,然后使用一个全连接层和Sigmoid激活函数来生成通道注意力权重。这些权重用于调整每个通道的特征图。 空间注意力模块通过使用一个3x3的卷积操作来捕捉特征图的空间信息。然后,通过一个全连接层和Sigmoid激活函数来生成空间注意力权重。这些权重用于调整特征图的每个空间位置。 SE注意力机制和CBAM注意力机制都可以用于增强深度神经网络的性能,但在不同的网络结构和任务可能会有不同的效果。在大多数情况下,直接在网络加入SE注意力机制可以获得性能的提升。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

赵药师

嘿嘿嘿

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值