CNN中如何将1x1xC维度特征图转换为NxNxC维度的特征图?
问题描述
搭建CNN模型时遇到特征图维度调整问题:需要将1x1xC维度的特征图转换为NxNxC维度,具体场景如下:
调用迁移学习的DenseNet121作为基础模型,其输出维度为(None, 8, 8, 1024),将该输出传入自定义的BAM_Channel_Attention通道注意力函数处理,相关代码如下:
image_size = 256 #image size which is input shape of the densenet121 base_model=get_base_model('densenet121',image_size) #calling densenet121 using transfer learning base_in=base_model.input #base_in.shape = (None, 256, 256, 3) base_out=base_model.output #base_out.shape = (None, 8, 8, 1024) #function which performs attention which is to be added on the densenet121 def BAM_Channel_Attention(inputs): shape=K.int_shape(inputs) x=tf.keras.layers.AveragePooling2D(pool_size=(shape[1],shape[2]))(inputs) dense = layers.Dense(1280, activation="relu")(x) reduction = Conv2D(shape[3]/16,1, padding='same')(dense) dense = layers.Dense(1280, activation="relu")(reduction) out = tf.keras.layers.BatchNormalization()(dense) return out
上述函数的调用代码如下:
#calling the attention function with the output of the densenet121 x=BAM_Channel_Attention(base_out) # print(x.shape)
运行代码后得到的输出为(None, 1, 1, 1280),需要将1x1x1280的特征图转换为8x8x1280维度的特征图。
解决方案
- 方法1:使用UpSampling2D层实现上采样(最便捷)
直接在通道注意力函数末尾添加上采样层,自动适配输入的空间维度,无需硬编码8这个参数:
def BAM_Channel_Attention(inputs): shape=K.int_shape(inputs) x=tf.keras.layers.AveragePooling2D(pool_size=(shape[1],shape[2]))(inputs) dense = layers.Dense(1280, activation="relu")(x) reduction = Conv2D(shape[3]/16,1, padding='same')(dense) dense = layers.Dense(1280, activation="relu")(reduction) out = tf.keras.layers.BatchNormalization()(dense) # 新增上采样逻辑,将1x1的特征图放大到和输入一致的空间尺寸 out = tf.keras.layers.UpSampling2D(size=(shape[1], shape[2]), interpolation='nearest')(out) return out
interpolation参数可根据需求选nearest(最近邻插值,不改变注意力权重数值,通道注意力场景推荐)或bilinear(双线性插值)。
- 方法2:使用tf.tile手动复制张量
如果需要更底层的维度控制,可以用张量复制操作实现:
def BAM_Channel_Attention(inputs): shape=K.int_shape(inputs) x=tf.keras.layers.AveragePooling2D(pool_size=(shape[1],shape[2]))(inputs) dense = layers.Dense(1280, activation="relu")(x) reduction = Conv2D(shape[3]/16,1, padding='same')(dense) dense = layers.Dense(1280, activation="relu")(reduction) out = tf.keras.layers.BatchNormalization()(dense) # 分别对batch、高、宽、通道维度设置复制倍数,空间维度复制对应倍数即可 out = tf.tile(out, multiples=[1, shape[1], shape[2], 1]) return out
- 方法3:利用TensorFlow广播机制(注意力加权场景最优)
如果后续需要将该通道注意力权重和原始DenseNet输出的8x8x1024特征图做加权,无需手动扩展维度,框架自带的广播机制会自动适配:
channel_att_weight = BAM_Channel_Attention(base_out) # 直接逐元素相乘,1x1x1280的权重会自动广播为8x8x1280再做运算 weighted_feature = base_out * channel_att_weight
注意该场景下需要保证注意力输出的通道数和原始特征图通道数一致,你当前代码输出的通道数为1280,和原始DenseNet输出的1024不一致,可调整Dense层的输出维度对齐。
内容的提问来源于stack exchange,提问作者arvind okram
相关产品推荐
相关产品推荐

