Python 理解并实施要素式注意模块

Python 理解并实施要素式注意模块,python,tensorflow,machine-learning,keras,deep-learning,Python,Tensorflow,Machine Learning,Keras,Deep Learning,请对您的想法添加最低限度的评论,以便我可以改进我的查询。谢谢 我试图理解并实施一项关于的研究工作,包括 - channel-wise attention (a) - element-wise attention (b) - scale-wise attention (c) 该机制在DenseNet模型中进行了实验集成。整个模型图的拱形为。通道方向的注意模块只是挤压和激发块。这将进一步向元素方向的注意力模块提供sigmoid输出。下面是这些模块的更精确的功能流程图(a、b和c) 理

请对您的想法添加最低限度的评论,以便我可以改进我的查询。谢谢


我试图理解并实施一项关于的研究工作,包括

- channel-wise attention  (a)
- element-wise attention  (b)
- scale-wise attention    (c)
该机制在
DenseNet
模型中进行了实验集成。整个模型图的拱形为。通道方向的注意模块只是挤压和激发块。这将进一步向元素方向的注意力模块提供
sigmoid
输出。下面是这些模块的更精确的功能流程图(
a
b
c


理论 在大多数情况下,我能够理解并实现它,但在
元素方面的注意部分(上图中的部分
b
)有点不知所措。这就是我需要你帮助的地方

这里有一个关于这个话题的小理论,让你大致了解这一切。请注意,该论文现在不能公开访问,但在发布初期,在出版商页面上可以免费获取,当时我保存了它。公平地说,我要和你们分享。无论如何,从论文(第4.3节)可以看出:

因此首先在所有函数中,
f(att)
函数(在第一个就地图中,左中间部分或
b
)由三个卷积层组成,其中512内核为
1x1
512内核为
3x3
C
内核为
1x1
。这里
C
是分类器的编号。并通过
Softmax
激活

接下来,它适用于
通道方向的
注意模块,我们提到的是一个
SENet
模块,并给出了一个
sigmoid
概率分数,即
X(CA)
。因此,通过函数
f(att)
,我们得到
C
softmax
概率分数,每个分数与
sigmoid
输出相乘,最后生成特征图
A
(根据上图的等式4

Second,有一个
C
线性分类器,实现为
1x1
-
C
内核卷积层。该层还应用于
SENet
模块的输出,即
X(CA)
,以像素为单位应用于每个特征向量。最后,它给出了特征图
S
(方程式5如下图所示)的输出

而第三个,他们将每个信心分数(S
)乘以相应的注意力元素A。这个乘法是故意的。他们这样做是为了防止不必要的关注特征图。为了使其有效,他们还使用
加权交叉熵
损失函数来最小化分类基本真相得分向量之间的损失

我的查询


主要是在网络的中间没有适当的最小化策略。我希望有人能给我一个适当的理解,并详细实施上述文件(第4.3节)中提出的“要素注意机制”


实施 以下是入门的最低代码。我想应该够了。这是肤浅的实现,但与原始的元素模块有太多的距离。我不知道如何正确地实施它。现在,我希望它作为一个层,应该可以插入和播放任何模型。我尝试使用MNIST和一个简单的
Conv
net

总之,对于MNIST,我们应该有一个包含
频道和
元素注意模型的网络,然后是最后一个10单位
softmax
层。例如:

Net: Conv2D - Attentions-Module - GAP - Softmax(10)
注意力模块由两部分组成:
频道部分和
元素部分,以及
元素部分也应具有
Softmax
,该模块将加权
CE
损失函数最小化到
基本真理部分和
得分向量部分(根据上面已经描述过的文件)。该模块还将加权特征映射传递到连续层。为了更清楚,这里有一个简单的示意图,说明我们正在寻找的内容

好的,对于
通道方面的
注意,它应该给我们一个单一的概率分数(
sigmoid
),为了简单起见,现在让我们使用一个假层:

class FakeSE(tf.keras.layers.Layer):
    def __init__(self):
        super(Block, self).__init__()
        # conv layer
        self.conv = tf.keras.layers.Conv2D(10, padding='same',
                                           kernel_size=3)
    def call(self, input_tensor, training=False):
        x = self.conv(input_tensor)
        return tf.math.sigmoid(x)
对于元素方面的注意部分,以下是迄今为止失败的尝试:

class ElementWiseAttention(tf.keras.layers.Layer):
    def __init__(self):
        # for simplicity the f(attn) function here has 2 convolution instead of 3
        # self.conv1, and self.conv2
        self.conv1 = tf.keras.layers.Conv2D(16, 
                                            kernel_size=1, 
                                            strides=1, padding='same',
                                            use_bias=True, activation=tf.nn.silu)

        self.conv2 = tf.keras.layers.Conv2D(10, 
                                            kernel_size=1, 
                                            strides=1, padding='same',
                                            use_bias=False, activation=tf.keras.activations.softmax)
        
        # fake SENet or channel-wise attention module 
        self.cam = FakeSE()
        
        # a linear layer 
        self.linear = tf.keras.layers.Conv2D(10,
                                           kernel_size=1,
                                           strides=1, padding='same',
                                           use_bias=True, activation=None)
        
        super(ElementWiseAttention, self).__init__()
    
    def call(self, inputs):
        # 2 stacked conv layer (in paper, it's 3. we set 2 for simplicity)
        # this is the f(att)
        x = self.conv1(inputs)
        x = self.conv2(x)
        
        # this is the A = f(att)*X(CA)
        camx = self.cam(x)*x
        
        # this is S = X(CA)*Linear_Classifier
        linx = self.cam(self.linear(inputs))

        # element-wise multiply to prevent unnecessary attention
        # suppose to minimize with weighted cross entorpy loss 
        out = tf.multiply(camx, linx)
        
        return out
上面这一层是感兴趣的。如果我正确理解了纸上的单词,这一层不仅应该最小化加权损失函数到
gt
score\u向量
,还应该生成一些加权特征图(
2D

跑 这是玩具数据


(x_train, y_train), (_, _) = tf.keras.datasets.mnist.load_data()
x_train = np.expand_dims(x_train, axis=-1)
x_train = x_train.astype('float32') / 255
x_train = tf.image.resize(x_train, [32,32]) # if we want to resize 
y_train = tf.keras.utils.to_categorical(y_train , num_classes=10) 

# Model 
input = tf.keras.Input(shape=(32,32,1))
efnet = tf.keras.applications.DenseNet121(weights=None,
                                             include_top = False, 
                                             input_tensor = input)
em =  ElementWiseAttention()(efnet.output)
# Now that we apply global max pooling.
gap = tf.keras.layers.GlobalMaxPooling2D()(em)

# classification layer.
output = tf.keras.layers.Dense(10, activation='softmax')(gap)

# bind all
func_model = tf.keras.Model(efnet.input, output)
func_model.compile(
          loss      = tf.keras.losses.CategoricalCrossentropy(),
          metrics   = tf.keras.metrics.CategoricalAccuracy(),
          optimizer = tf.keras.optimizers.Adam())
# fit 
func_model.fit(x_train, y_train, batch_size=32, epochs=3, verbose = 1)
理解元素级注意 当论文介绍他们的方法时,他们说:

注意模块旨在利用疾病之间的关系 标签和(1)诊断特定功能通道(2) 图像上的诊断特定位置(即胸部区域 异常)和(3)特征图的诊断特定比例

(1) (2),(3)对应于通道型注意、元素型注意、尺度型注意

我们可以看出,元素式注意用于处理疾病位置和体重信息,即:在图像上的每个位置,疾病发生的可能性有多大,,正如本文介绍元素式注意时再次提到的:<
import tensorflow as tf
import numpy as np

ALPHA = 1/16
C = 10
D = 128

class ChannelWiseAttention(tf.keras.layers.Layer):
    def __init__(self):
        super(ChannelWiseAttention, self).__init__()

        # squeeze
        self.gap = tf.keras.layers.GlobalAveragePooling2D()
        
        # excitation
        self.fc0 = tf.keras.layers.Dense(int(ALPHA * D), use_bias=False, activation=tf.nn.relu)
        
        self.fc1 = tf.keras.layers.Dense(D, use_bias=False, activation=tf.nn.sigmoid)

        # reshape so we can do channel-wise multiplication
        self.rs = tf.keras.layers.Reshape((1, 1, D))

    def call(self, inputs):
        # calculate channel-wise attention vector
        z = self.gap(inputs)
        u = self.fc0(z)
        u = self.fc1(u)
        u = self.rs(u)
        return u * inputs

class ElementWiseAttention(tf.keras.layers.Layer):
    def __init__(self):
        super(ElementWiseAttention, self).__init__()

        # f(att)
        self.conv0 = tf.keras.layers.Conv2D(512, 
                                            kernel_size=1, 
                                            strides=1, padding='same',
                                            use_bias=True, activation=tf.nn.relu)
        
        self.conv1 = tf.keras.layers.Conv2D(512, 
                                            kernel_size=3, 
                                            strides=1, padding='same',
                                            use_bias=True, activation=tf.nn.relu)

        self.conv2 = tf.keras.layers.Conv2D(C, 
                                            kernel_size=1, 
                                            strides=1, padding='same',
                                            use_bias=False, activation=tf.keras.activations.softmax)
        
        # linear classifier
        self.linear = tf.keras.layers.Conv2D(C,
                                           kernel_size=1,
                                           strides=1, padding='same',
                                           use_bias=True, activation=None)
        
        # for calculate score vector to training element-wise attention module
        self.gap = tf.keras.layers.GlobalAveragePooling2D()
        self.sfm = tf.keras.layers.Softmax()

    def call(self, inputs):
        # f(att)
        a = self.conv0(inputs)
        a = self.conv1(a)
        a = self.conv2(a)
        
        # confidence score
        s = self.linear(inputs)

        # element-wise multiply to prevent unnecessary attention 
        m = s * a
        # using to minimize with weighted cross entorpy loss
        y_hat = self.gap(m)
        # could also using sigmoid like in paper
        out = self.sfm(y_hat)

        return m, out

(x_train, y_train), (_, _) = tf.keras.datasets.mnist.load_data()
x_train = np.expand_dims(x_train, axis=-1)
x_train = x_train.astype('float32') / 255
x_train = tf.image.resize(x_train, [32,32]) # if we want to resize 
y_train = tf.keras.utils.to_categorical(y_train , num_classes=10) 

# Model 
input = tf.keras.Input(shape=(32,32,1))
efnet = tf.keras.applications.DenseNet121(weights=None,
                                             include_top = False, 
                                             input_tensor = input)

xca = ChannelWiseAttention()(efnet.get_layer("conv3_block1_0_bn").output)
m, output =  ElementWiseAttention()(xca)

# bind all
func_model = tf.keras.Model(efnet.input, output)
func_model.compile(
          loss      = tf.keras.losses.CategoricalCrossentropy(),
          metrics   = tf.keras.metrics.CategoricalAccuracy(),
          optimizer = tf.keras.optimizers.Adam())
# fit 
func_model.fit(x_train, y_train, batch_size=64, epochs=3, verbose = 1)