【tf学习笔记2】tensorflow2.3张量中None占位符问题-搭建注意力模块SE-Net

0.引言

目前,向神经网络中引入注意力机制以提高网络表达效果的技术已经日益成熟,尤其是数字图像处理领域,涉及到注意力机制的文章更是数不胜数。我使用tensorflow2.3keras API
搭建注意力模块SE-Net的时候,需要对张量进行尺寸变化,由于我对tensorflow2的模型训练机制不够深入了解,出现了关于None占位符的问题,下面基于SE-Net进行详细介绍。

1.SE-Net简介

SE-Net是一款非常经典的注意力机制,模块结构如下:
在这里插入图片描述
该模块作用是:通过学习的方式来自动获取到每个特征通道的重要程度,然后依照这个重要程度去提升有用的特征并抑制对当前任务用处不大的特征,这又叫做“特征重标定”策略。此处参考(https://blog.csdn.net/qq_38251616/article/details/125141128)
简单来说:就是把每个通道的权重也作为一组超参数送进网络中去学习,这组超参数是由Fsq(·)得到的,如图1x1xC2向量即为通道权重向量,再经过一系列处理,与原张量进行相乘(对应元素相乘),即对C2个通道种每个通道赋予权重如图所示:右边五颜六色那个张量就是经过通道加权的张量。
总结:SE-Net注意力模块作用是:进行张量通道权重的学习,刻画每个通道的重要性。

2. 代码实现

使用tensorflow2.3中keras框架进行搭建SE-Net block,代码如下:

class SE_Att(Model):
    def __init__(self, C): 
        super(SE_Att, self).__init__()
        self.ratio = 16
        self.un = C
        self.p = GlobalAveragePooling2D(data_format='channels_last')
        self.f1 = Dense(units=self.un // self.ratio, use_bias=False, activation='relu')
        self.f2 = Dense(units=self.un, use_bias=False, activation='sigmoid')

    def call(self, x):
        # x:N H W C
        N, H, W, C = x.shape
        context = self.p(x)  # N C
        # 全局池化[N,1,1,C]
        context = self.f1(context)
        context = self.f2(context)
        context = tf.reshape(context, shape=(None, 1, 1, C))  # 语句0 用-1表示None
        y = x * context
        return y

3.错误分析

错误提示:TypeError: Failed to convert object of type <class ‘tuple’> to Tensor. Contents: (None, 1, 1, 128). Consider casting elements to a supported type.

出现问题的地方在上述代码语句0,reshape中形参shape不能接受含有None的元组。但是None在tensorflow中表示一个占位符,指定该维度下为任意正值,常常用于图像处理时batch的占位,例如张量(None,64,64,3)表示任意张64x64x3大小的图片
我们使用**-1来替换 tf.reshape(context, shape=(None, 1, 1, C))中的None**即可。
所以-1实际上就表示了张量在此维度出可以接受任何值。

4.代码纠错

语句0处改为:

context = tf.reshape(context, shape=(-1, 1, 1, C)) 

修改后,模块可以在网络中正常运行,监控每时刻的输出输入张量大小,均与理论一致。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是使用TensorFlow 2实现SE注意力模块的代码: ```python import tensorflow as tf from tensorflow.keras import layers class SELayer(layers.Layer): def __init__(self, reduction=16): super(SELayer, self).__init__() self.reduction = reduction def build(self, input_shape): self.channel_axis = -1 channel = input_shape[self.channel_axis] self.avg_pool = layers.GlobalAveragePooling2D() self.fc1 = layers.Dense(channel // self.reduction, activation='relu', kernel_initializer='he_normal', use_bias=True) self.fc2 = layers.Dense(channel, activation='sigmoid', kernel_initializer='he_normal', use_bias=True) def call(self, inputs): x = self.avg_pool(inputs) x = self.fc1(x) x = self.fc2(x) x = layers.Reshape((1, 1, -1))(x) x = inputs * x return x ``` 这段代码实现了一个SE注意力模块,它包括一个全局平均池化层、两个全连接层和一个重塑层,其 reduction 参数指定压缩比例。在 build 方法,我们获取输入张量的通道数,创建全局平均池化层、两个全连接层,并设置它们的激活函数、初始化方式和使用偏置。在 call 方法,我们将输入张量进行全局平均池化,然后通过两个全连接层得到一个权重向量,并将其重塑为跟输入张量相同的形状,最后将输入张量乘以权重向量,得到加权后的输出。 如果你想使用这个SE注意力模块,可以在你的模型将它作为一个层来使用,比如: ```python inputs = layers.Input(shape=(28, 28, 128)) x = layers.Conv2D(filters=512, kernel_size=3, strides=1, padding='same', activation='relu')(inputs) x = SELayer()(x) x = layers.Conv2D(filters=256, kernel_size=3, strides=1, padding='same', activation='relu')(x) x = SELayer()(x) outputs = layers.Conv2D(filters=10, kernel_size=1, strides=1, padding='valid', activation='softmax')(x) model = tf.keras.Model(inputs=inputs, outputs=outputs) ``` 这里先定义了一个输入张量 inputs,然后接一个卷积层、一个SE注意力模块、一个卷积层、一个SE注意力模块,最后接一个卷积层作为输出张量。注意,SE注意力模块要放在卷积层之后,因为它需要先对通道数进行压缩后才能进行加权。最后通过 tf.keras.Model 创建一个模型实例。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值