赞
踩
ODConv的代码https://github.com/OSVAI/ODConv/blob/main/modules/odconv.py
ODConv引入了一种多维注意机制,该机制采用并行策略,可以沿核空间的所有四个维度学习卷积核的不同注意。
当kernel_size(图中k)等于1并且kernel_num(图中k_num)等于1时,ODConv架构图
ODConv的代码,得先看懂Attention这个类
- class ODConv2d(nn.Module):
- def __init__(self, in_planes, out_planes, kernel_size, stride=1, padding=0, dilation=1, groups=1,
- reduction=0.0625, kernel_num=4):
- super(ODConv2d, self).__init__()
- self.in_planes = in_planes
- self.out_planes = out_planes
- self.kernel_size = kernel_size
- self.stride = stride
- self.padding = padding
- self.dilation = dilation
- self.groups = groups
- self.kernel_num = kernel_num
- self.attention = Attention(in_planes, out_planes, kernel_size, groups=groups,
- reduction=reduction, kernel_num=kernel_num)
- self.weight = nn.Parameter(torch.randn(kernel_num, out_planes, in_planes//groups, kernel_size, kernel_size),
- requires_grad=True)
- self._initialize_weights()
-
- if self.kernel_size == 1 and self.kernel_num == 1:
- self._forward_impl = self._forward_impl_pw1x
- else:
- self._forward_impl = self._forward_impl_common
-
- def _initialize_weights(self):
- for i in range(self.kernel_num):
- nn.init.kaiming_normal_(self.weight[i], mode='fan_out', nonlinearity='relu')
-
- def update_temperature(self, temperature):
- self.attention.update_temperature(temperature)
-
- def _forward_impl_common(self, x):
- # Multiplying channel attention (or filter attention) to weights and feature maps are equivalent,
- # while we observe that when using the latter method the models will run faster with less gpu memory cost.
- channel_attention, filter_attention, spatial_attention, kernel_attention = self.attention(x)
- batch_size, in_planes, height, width = x.size()
- x = x * channel_attention
- x = x.reshape(1, -1, height, width)
- aggregate_weight = spatial_attention * kernel_attention * self.weight.unsqueeze(dim=0)
- aggregate_weight = torch.sum(aggregate_weight, dim=1).view(
- [-1, self.in_planes // self.groups, self.kernel_size, self.kernel_size])
- output = F.conv2d(x, weight=aggregate_weight, bias=None, stride=self.stride, padding=self.padding,
- dilation=self.dilation, groups=self.groups * batch_size)
- output = output.view(batch_size, self.out_planes, output.size(-2), output.size(-1))
- output = output * filter_attention
- return output
-
- def _forward_impl_pw1x(self, x):
- channel_attention, filter_attention, spatial_attention, kernel_attention = self.attention(x)
- x = x * channel_attention
- output = F.conv2d(x, weight=self.weight.squeeze(dim=0), bias=None, stride=self.stride, padding=self.padding,
- dilation=self.dilation, groups=self.groups)
- output = output * filter_attention
- return output
-
- def forward(self, x):
- return self._forward_impl(x)
结合Attention这个类的代码看更清楚,图中橙色的Conv2d的bias=True
- class Attention(nn.Module):
- def __init__(self, in_planes, out_planes, kernel_size, groups=1, reduction=0.0625, kernel_num=4, min_channel=16):
- super(Attention, self).__init__()
- attention_channel = max(int(in_planes * reduction), min_channel)
- self.kernel_size = kernel_size
- self.kernel_num = kernel_num
- self.temperature = 1.0
-
- self.avgpool = nn.AdaptiveAvgPool2d(1)
- self.fc = nn.Conv2d(in_planes, attention_channel, 1, bias=False)
- self.bn = nn.BatchNorm2d(attention_channel)
- self.relu = nn.ReLU(inplace=True)
-
- self.channel_fc = nn.Conv2d(attention_channel, in_planes, 1, bias=True)
- self.func_channel = self.get_channel_attention
-
- if in_planes == groups and in_planes == out_planes: # depth-wise convolution
- self.func_filter = self.skip
- else:
- self.filter_fc = nn.Conv2d(attention_channel, out_planes, 1, bias=True)
- self.func_filter = self.get_filter_attention
-
- if kernel_size == 1: # point-wise convolution
- self.func_spatial = self.skip
- else:
- self.spatial_fc = nn.Conv2d(attention_channel, kernel_size * kernel_size, 1, bias=True)
- self.func_spatial = self.get_spatial_attention
-
- if kernel_num == 1:
- self.func_kernel = self.skip
- else:
- self.kernel_fc = nn.Conv2d(attention_channel, kernel_num, 1, bias=True)
- self.func_kernel = self.get_kernel_attention
-
- self._initialize_weights()
-
- def _initialize_weights(self):
- for m in self.modules():
- if isinstance(m, nn.Conv2d):
- nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
- if m.bias is not None:
- nn.init.constant_(m.bias, 0)
- if isinstance(m, nn.BatchNorm2d):
- nn.init.constant_(m.weight, 1)
- nn.init.constant_(m.bias, 0)
-
- def update_temperature(self, temperature):
- self.temperature = temperature
-
- @staticmethod
- def skip(_):
- return 1.0
-
- def get_channel_attention(self, x):
- channel_attention = torch.sigmoid(self.channel_fc(x).view(x.size(0), -1, 1, 1) / self.temperature)
- return channel_attention
-
- def get_filter_attention(self, x):
- filter_attention = torch.sigmoid(self.filter_fc(x).view(x.size(0), -1, 1, 1) / self.temperature)
- return filter_attention
-
- def get_spatial_attention(self, x):
- spatial_attention = self.spatial_fc(x).view(x.size(0), 1, 1, 1, self.kernel_size, self.kernel_size)
- spatial_attention = torch.sigmoid(spatial_attention / self.temperature)
- return spatial_attention
-
- def get_kernel_attention(self, x):
- kernel_attention = self.kernel_fc(x).view(x.size(0), -1, 1, 1, 1, 1)
- kernel_attention = F.softmax(kernel_attention / self.temperature, dim=1)
- return kernel_attention
-
- def forward(self, x):
- x = self.avgpool(x)
- x = self.fc(x)
- x = self.bn(x)
- x = self.relu(x)
- return self.func_channel(x), self.func_filter(x), self.func_spatial(x), self.func_kernel(x)
当in_planes == groups 并且 in_planes == out_planes时(即depth-wise convolution),filter_attention不起作用(即等于1);当kernel_size=1时,spatial_attention不起作用(即等于1);当kernel_num=1时,kernel_attention不起作用(即等于1)。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。