注意⼒机制的两种模块SEblock和CBAM模块1.SENet模块
def SE_moudle(input_xs,reduction_ratio = 16.):
shape = _shape().as_list()
_module = tf.reduce_mean(input_xs,[1,2])
#第⼀个Den:shape[-1]/reduction_ratio:即把input_channel再除以reduction_ratio,使channel下降到指定维度数
_module = tf.keras.layers.Den(shape[-1]/reduction_ratio,lu)(_module)
#第⼆个Den:重新回升到与input_channel相同的原始维度数
_module = tf.keras.layers.Den(shape[-1], lu)(_module)
_module = tf.nn.sigmoid(_module)
_module = tf.reshape(_module,[-1,1,1,shape[-1]])
out_ys = tf.multiply(input_xs,_module)
return out_ys
2.加载SENet模块的Resnet
def identity_block(input_xs, out_dim, with_shortcut_conv_BN=Fal):
if with_shortcut_conv_BN:普通外科医生
pass
el:
#返回与input的形状和内容均相同的张量,即shortcut等同于input_xs
shortcut = tf.identity(input_xs)
#input输⼊的channel数
input_channel = _shape().as_list()[-1]
#如果输⼊的channel数不等于输出的channel数的话
if input_channel != out_dim:
#求输出的channel数减去输⼊的channel数的绝对值,作为pad填充值
pad_shape = tf.abs(out_dim - input_channel)
#name="padding"表⽰给该填充操作赋予名称为"padding"。使⽤了默认参数mode='CONSTANT'和constant_values=0,表⽰填充默认值0。 #第⼆个参数为paddings填充的形状:即分别的批量维度、⾼、宽的维度上都不作填充,在channel维度上填充pad_shape//2的数量。
shortcut = tf.pad(shortcut, [[0, 0], [0, 0], [0, 0], [pad_shape // 2, pad_shape // 2]], name="padding")
#残差卷积块中的3个Conv2D卷积的卷积核⼤⼩分别为1x1、3x3、1x1
conv = tf.keras.layers.Conv2D(filters=out_dim // 4, kernel_size=1, padding="SAME", lu)(input_xs)
conv = tf.keras.layers.BatchNormalization()(conv)
conv = tf.keras.layers.Conv2D(filters=out_dim // 4, kernel_size=3, padding="SAME", lu)(conv)
孤独之旅教学设计
conv = tf.keras.layers.BatchNormalization()(conv)山药炖排骨
conv = tf.keras.layers.Conv2D(filters=out_dim // 4, kernel_size=1, padding="SAME", lu)(conv)
conv = tf.keras.layers.BatchNormalization()(conv)硬盘坏了数据恢复
#下⾯开始加载SENet模块
#返回的为[批量维度、⾼、宽、channel维度]
shape = _shape().as_list()
#默认参数为keepdims=Fal的话,不会再保留运算所在的维度。设置keepdims=True的话,会保留运算所在的维度为1。
#[批量维度、⾼、宽、channel维度]经过reduce_mean后转换为[批量维度、channel维度]
_module = tf.reduce_mean(conv, [1, 2])
#第⼀个Den:shape[-1]/reduction_ratio:即把input_channel再除以reduction_ratio,使channel下
降到指定维度数
_module = tf.keras.layers.Den(shape[-1] / 16, lu)(_module)
#第⼆个Den:重新回升到与input_channel相同的原始维度数
_module = tf.keras.layers.Den(shape[-1], lu)(_module)
_module = tf.nn.sigmoid(_module)
#把[批量维度、channel维度]重新转换为[批量维度、⾼、宽、channel维度],即[批量维度、1、1、channel维度]
_module = tf.reshape(_module, [-1, 1, 1, shape[-1]])
#multiply元素乘法:SENet模块输出值_module 和残差卷积输出conv(即SENet模块输⼊值conv)
_module = tf.multiply(conv, _module)
#残差连接:对残差的原始输⼊shortcut(即input_xs) 与 SENet模块输出值_module 进⾏求和
output_ys = tf.add(shortcut, _module)
output_ys = lu(output_ys)
return output_ys
3. CBAM模块
def cbam_module(input_xs, reduction_ratio=0.5):
生气勃勃#分别获取批量⼤⼩、通道数,通道数作为隐藏层的神经元数量
batch_size, hidden_num = _shape().as_list()[0], _shape().as_list()[3]
### 第⼀步:Channel Attention 模块 ###
#1.默认参数为keepdims=Fal的话,不会再保留运算所在的维度。设置keepdims=True的话,会保留运算所在的维度为1。
被你抛弃
# 连续两次的reduce_max/reduce_mean,实际都是先将[批量维度、⾼、宽、channel维度]转换为[批量维度、1、宽、channel维度],
# 再转换为[批量维度、1、1、channel维度]。
#2.⾸先对Channel Attention 模块的输⼊数据分别进⾏全局池化(reduce_max)和平均池化(reduce_mean)两种操作。
maxpool_channel = tf.reduce_duce_max(input_xs, axis=1, keepdims=True), axis=2, keepdims=True)
avgpool_channel = tf.reduce_duce_mean(input_xs, axis=1, keepdims=True), axis=2, keepdims=True)
maxpool_channel = tf.keras.layers.Flatten()(maxpool_channel)
avgpool_channel = tf.keras.layers.Flatten()(avgpool_channel)
#使⽤2个连续的全连接层对全局池化(reduce_max)后的特征进⾏提取。
#reduction_ratio为0.5,即第1个全连接层的神经元数量为输⼊数据的输⼊数据的通道数的⼀半,然后第2个全连接层神经元数量重新恢复为输⼊数据的通道数
mlp_1_max = tf.keras.layers.Den(units=int(hidden_num * reduction_ratio), lu)(maxpool_channel)
mlp_2_max = tf.keras.layers.Den(units=hidden_num)(mlp_1_max)
#[批量维度、1、1、channel维度],此处的隐藏层的神经元数量hidden_num等于输⼊数据的通道数
mlp_2_max = tf.reshape(mlp_2_max, [-1, 1, 1, hidden_num])
#使⽤2个连续的全连接层对平均池化(reduce_mean)后的特征进⾏提取。
#reduction_ratio为0.5,即第1个全连接层的神经元数量为输⼊数据的输⼊数据的通道数的⼀半,然后第2个全连接层神经元数量重新恢复为输⼊数据的通道数
mlp_1_avg = tf.keras.layers.Den(units=int(hidden_num * reduction_ratio), lu)(avgpool_channel)
mlp_2_avg = tf.keras.layers.Den(units=hidden_num, lu)(mlp_1_avg)
#[批量维度、1、1、channel维度],此处的隐藏层的神经元数量hidden_num等于输⼊数据的通道数
mlp_2_avg = tf.reshape(mlp_2_avg, [-1, 1, 1, hidden_num])
#把“对全局池化(reduce_max)提取后的”特征和“对平均池化(reduce_mean)提取后的”特征进⾏求和,
然后通过sigmoid激活归⼀化到0到1之间
channel_attention = tf.nn.sigmoid(mlp_2_max + mlp_2_avg)
#把“通过sigmoid激活归⼀化的”值和Channel Attention 模块的输⼊数据进⾏内积计算,其最终计算结果值作为后⾯的Spatial Attention 模块的输⼊
channel_refined_feature = input_xs * channel_attention
### 第⼆步:Spatial Attention 模块 ###
#1.⾸先把Channel Attention 模块的输出作为Spatial Attention 模块的输⼊,然后对输⼊数据分别进⾏全局池化(reduce_max)和平均池化(reduce_mean)两种操作。 #2.默认参数为keepdims=Fal的话,不会再保留运算所在的维度。设置keepdims=True的话,会保留运算所在的维度为1。
#3.全局池化(reduce_max):把[批量维度、⾼、宽、channel维度]转换为[批量维度、⾼、宽、1]
maxpool_spatial = tf.reduce_max(channel_refined_feature, axis=3, keepdims=True)
#平均池化(reduce_mean):把[批量维度、⾼、宽、channel维度]转换为[批量维度、⾼、宽、1]
wps邮件合并avgpool_spatial = tf.reduce_mean(channel_refined_feature, axis=3, keepdims=True)
#把全局池化(reduce_max)和平均池化(reduce_mean)后的数据在channel维度上进⾏合并,最终转换为[批量维度、⾼、宽、2]
max_avg_pool_spatial = tf.concat([maxpool_spatial, avgpool_spatial], axis=3)
#⽬的是将数据的维度降维为1,以便后⾯的sigmoid激活归⼀化计算
conv_layer = tf.keras.layers.Conv2D(filters=1, kernel_size=(3, 3), padding="same", activation=None)(max_avg_pool_spatial)
#通过sigmoid激活归⼀化到0到1之间
spatial_attention = tf.nn.sigmoid(conv_layer)
#将Spatial Attention 模块的输出channel_refined_feature 和Spatial Attention 模块的输出spatial_attention 进⾏内积计算,
#其最终计算结果值作为CBAM注意⼒机制模块的输出值。
refined_feature = channel_refined_feature * spatial_attention
#将CBAM注意⼒机制模块的输⼊值input_xs和输出值refined_feature进⾏求和得出最终的结果
output_layer = refined_feature + input_xs
return output_layer
4.加载了CBAM模块的Resnet
def identity_block(input_xs, out_dim, with_shortcut_conv_BN=Fal):
layer_depth=20 #层的深度
if with_shortcut_conv_BN:
pass
el:
#返回与input的形状和内容均相同的张量,即shortcut等同于input_xs
shortcut = tf.identity(input_xs)
#input输⼊的channel数
input_channel = _shape().as_list()[-1]
#如果输⼊的channel数不等于输出的channel数的话
if input_channel != out_dim:
#求输出的channel数减去输⼊的channel数的绝对值,作为pad填充值
pad_shape = tf.abs(out_dim - input_channel)
#name="padding"表⽰给该填充操作赋予名称为"padding"。使⽤了默认参数mode='CONSTANT'和constant_values=0,表⽰填充默认值0。 #第⼆个参数为paddings填充的形状:即分别的批量维度、⾼、宽的维度上都不作填充,在channel维度上填充pad_shape//2的数量。
威德尔海
shortcut = tf.pad(shortcut, [[0, 0], [0, 0], [0, 0], [pad_shape // 2, pad_shape // 2]], name="padding")
#残差卷积块中的3个Conv2D卷积的卷积核⼤⼩分别为1x1、3x3、1x1
conv = tf.keras.layers.Conv2D(filters=out_dim // 4, kernel_size=1, padding="SAME", lu)(input_xs)
conv = tf.keras.layers.BatchNormalization()(conv)
conv = tf.keras.layers.Conv2D(filters=out_dim // 4, kernel_size=3, padding="SAME", lu)(conv)
conv = tf.keras.layers.BatchNormalization()(conv)
conv = tf.keras.layers.Conv2D(filters=out_dim // 4, kernel_size=1, padding="SAME", lu)(conv)
conv = tf.keras.layers.BatchNormalization()(conv)
conv = v2d(conv, out_dim, [1, 1], strides=[1, 1], kernel_initializer=tf.variance_scaling_initializer,
bias_s_initializer, name="conv{}_2_1x1".format(str(layer_depth)))
conv = tf.layers.batch_normalization(conv)
# ResNet中加载的CBAM模块
conv = cbam_module(conv)
#残差连接:对残差的原始输⼊shortcut(即input_xs) 与 CBAM模块输出值conv进⾏求和
output_ys = shortcut + conv
output_ys = lu(output_ys)
return output_ys