BangguWu / ECANet

Code for ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks
MIT License
1.24k stars 197 forks source link

Adaptive Kernel Size not implemented #24

Open varun19299 opened 4 years ago

varun19299 commented 4 years ago

It seems that the implementation under models/ differs from the paper's adaptive setting for k_size, given in Fig 3 of the paper.

Why do the resnet, mobilenet modules not use adaptive kernel sizes?

varun19299 commented 4 years ago

It is a simple addition, but the resnet model seems to use a fixed k_size instead.

ykk648 commented 4 years ago

same question.

ykk648 commented 4 years ago
class EcaLayer(nn.Module):

    def __init__(self, channels, gamma=2, b=1):
        super(EcaLayer, self).__init__()
        self.avg_pool = nn.AdaptiveAvgPool2d(1)

        t = int(abs((math.log(channels, 2) + b) / gamma))
        k_size = t if t % 2 else t + 1
        self.conv = nn.Conv1d(1, 1, kernel_size=k_size, padding=(k_size - 1) // 2, bias=False)

        self.sigmoid = nn.Sigmoid()

    def forward(self, x):
        # feature descriptor on the global spatial information
        y = self.avg_pool(x)

        # Two different branches of ECA module
        y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1)

        # Multi-scale information fusion
        y = self.sigmoid(y)

        return x * y.expand_as(x)
BangguWu commented 4 years ago

Since channel numbers of any architecture (e.g., ResNet and MobileNet) are fixed, we could pre-compute kernel size of 1D convolution according to Eq.12, which was also done in our code.

Although adaptive kernel size according to Eq.12 could achieve further improvement over fixed ones, Eq.12 can be regarded as a guideline to choose kernel size for each channel in general. It indicates high dimensional channels have longer range interaction while low-dimensional ones undergo shorter range interaction. Base on such kind of guideline, we could might as well do some fine-tuning of kernel size in Eq.12, which sometimes bring a little performance gain. It also encourage us to find an optimal mapping function.

xiaomoguhzz commented 4 years ago

i implements the code with pytorch,but found that adaptive kernel size is not easy to implement. we can't decide the right kernel size because it depends on the input channel. when you implements it in forward function,you will get a error Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same add cuda() behind the conv can fix the problem but when i print the module,the conv in the forward function seems not regist in the model. Maybe this is why the author fixed the kernel number image

`class EfficientChannelAttention(nn.Module):

def __init__(self, gamma=2, b=1):
    super(EfficientChannelAttention, self).__init__()
    self.gamma = gamma
    self.b = b
    self.avg_pool = nn.AdaptiveAvgPool2d(1)
    self.sigmoid = nn.Sigmoid()

def forward(self, x):
    N, C, H, W = x.size()
    t = int(abs((log(C, 2) + self.b) / self.gamma))
    k = t if t % 2 else t + 1
    # TODO maybe need to fix ,check it
    conv = nn.Conv1d(1, 1, kernel_size=k, padding=int(k / 2), bias=False).cuda()
    y = self.avg_pool(x)
    y = conv(y.squeeze(-1).transpose(-1, -2))
    y = y.transpose(-1, -2).unsqueeze(-1)
    y = self.sigmoid(y)
    return x * y.expand_as(x)`
varun19299 commented 4 years ago

To clarify:

my application had pre-determined input channel sizes, hence works.

Something like ECA(channel_num=channel_num) for each layer was called.

Can you provide details regarding your implementation?

On 28-Jul-2020, at 3:09 PM, navimelon notifications@github.com wrote:

i implements the code with pytorch,but found that adaptive kernel size is not easy to implement. we can't decide the right kernel size because it depends on the input channel. when you implements it in forward function,you will get a error Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same add cuda() behind the conv can fix the problem but when i print the module,the conv in the forward function seems not regist in the model. Maybe this is why the author fixed the kernel number https://user-images.githubusercontent.com/31958916/88647816-fa6aee00-d0f8-11ea-9320-40fe9a62ac6b.png `class EfficientChannelAttention(nn.Module): """ Args: x:input features with shape [N,C,H,W] gamma:parameters of mapping function b:parameters of mapping function

"""

def init(self, gamma=2, b=1): super(EfficientChannelAttention, self).init() self.gamma = gamma self.b = b self.avg_pool = nn.AdaptiveAvgPool2d(1) self.sigmoid = nn.Sigmoid()

def forward(self, x): N, C, H, W = x.size() t = int(abs((log(C, 2) + self.b) / self.gamma)) k = t if t % 2 else t + 1

TODO maybe need to fix ,check it

conv = nn.Conv1d(1, 1, kernel_size=k, padding=int(k / 2), bias=False).cuda()
y = self.avg_pool(x)
y = conv(y.squeeze(-1).transpose(-1, -2))
y = y.transpose(-1, -2).unsqueeze(-1)
y = self.sigmoid(y)
return x * y.expand_as(x)`

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/BangguWu/ECANet/issues/24#issuecomment-664926242, or unsubscribe https://github.com/notifications/unsubscribe-auth/AFBQJZ36PBARJJGPHC2ES5LR52MG3ANCNFSM4OL2NFLA.

lampardwk commented 4 years ago

@varun19299 Thank you for sharing!Run your code and find that the kernel size corresponding to resnet is 3,5,5,5, while the author set it to 3,3,3,3. What is the reason? Do they affect the end result?

varun19299 commented 4 years ago

I haven't shared any code.

However, @cloisonne 's reply is similar to what I used (https://github.com/BangguWu/ECANet/issues/24#issuecomment-652748916).

@navimelon is trying to dynamically compute the needed kernel size, which doesn't work.

lampardwk commented 4 years ago

thank you! According @cloisonne 's reply ,find that the kernel size corresponding to resnet is 3,5,5,5, while the author set it to 3,3,3,3.What is the reason? Do they affect the end result?

dongsheng1991 commented 3 years ago

i implements the code with pytorch,but found that adaptive kernel size is not easy to implement. we can't decide the right kernel size because it depends on the input channel. when you implements it in forward function,you will get a error Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same add cuda() behind the conv can fix the problem but when i print the module,the conv in the forward function seems not regist in the model. Maybe this is why the author fixed the kernel number image

`class EfficientChannelAttention(nn.Module):

def __init__(self, gamma=2, b=1):
    super(EfficientChannelAttention, self).__init__()
    self.gamma = gamma
    self.b = b
    self.avg_pool = nn.AdaptiveAvgPool2d(1)
    self.sigmoid = nn.Sigmoid()

def forward(self, x):
    N, C, H, W = x.size()
    t = int(abs((log(C, 2) + self.b) / self.gamma))
    k = t if t % 2 else t + 1
    # TODO maybe need to fix ,check it
    conv = nn.Conv1d(1, 1, kernel_size=k, padding=int(k / 2), bias=False).cuda()
    y = self.avg_pool(x)
    y = conv(y.squeeze(-1).transpose(-1, -2))
    y = y.transpose(-1, -2).unsqueeze(-1)
    y = self.sigmoid(y)
    return x * y.expand_as(x)`

conv = nn.Conv1d(1, 1, kernel_size=k, padding=int(k / 2), bias=False).cuda() should be defined in the function init().

xcliang2 commented 3 years ago

thank you! According @cloisonne 's reply ,find that the kernel size corresponding to resnet is 3,5,5,5, while the author set it to 3,3,3,3.What is the reason? Do they affect the end result?

same question

15114218 commented 3 years ago

I meet an error, who can help me? thanks a lot. RuntimeError: The expanded size of the tensor (64) must match the existing size (63) at non-singleton dimension 1. Target sizes: [8, 64, 256, 256]. Tensor sizes: [8, 63, 1, 1]

class eca_layer(nn.Module): """Constructs a ECA module.

Args:
    channel: Number of channels of the input feature map
    k_size: Adaptive selection of kernel size
"""

def __init__(self, k_size, gamma=2, b=1):
    super(eca_layer, self).__init__()
    self.k_size = k_size
    self.gamma = gamma
    self.b = b
    self.avg_pool = nn.AdaptiveAvgPool2d(1)
    self.conv = nn.Conv1d(1, 1, kernel_size=self.k_size, padding=(self.k_size - 1) // 2, bias=False)
    self.sigmoid = nn.Sigmoid()

def forward(self, x):
    b, c, h, w = x.size()
    t = int(abs((math.log(c, 2) + self.b) / self.gamma))
    self.k_size = t if t % 2 else t + 1        
    y = self.avg_pool(x)
    y = self.conv(y.squeeze(-1).transpose(-1, -2)).transpose(-1, -2).unsqueeze(-1)      
    y = self.sigmoid(y)
    return x * y.expand_as(x)