import torch import torch.nn as nn import torch.nn.functional as F import pdb class attention1d(nn.Module): def __init__(self, in_planes, ratios, K, temperature, init_weight=True): super(attention1d, self).__init__() assert temperature%3==1 self.avgpool = nn.AdaptiveAvgPool1d(1) if in_planes!=3: hidden_planes = int(in_planes*ratios)+1 else: hidden_planes = K self.fc1 = nn.Conv1d(in_planes, hidden_planes, 1, bias=False) # self.bn = nn.BatchNorm2d(hidden_planes) self.fc2 = nn.Conv1d(hidden_planes, K, 1, bias=True) self.temperature = temperature if init_weight: self._initialize_weights() def _initialize_weights(self): for m in self.modules(): if isinstance(m, nn.Conv1d): 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 updata_temperature(self): if self.temperature!=1: self.temperature -=3 print('Change temperature to:', str(self.temperature)) def forward(self, x): x = self.avgpool(x) x = self.fc1(x) x = F.relu(x) x = self.fc2(x).view(x.size(0), -1) return F.softmax(x/self.temperature, 1) class Dynamic_conv1d(nn.Module): def __init__(self, in_planes, out_planes, kernel_size, ratio=0.25, stride=1, padding=0, dilation=1, groups=1, bias=True, K=4,temperature=34, init_weight=True): super(Dynamic_conv1d, self).__init__() assert in_planes%groups==0 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.bias = bias self.K = K self.attention = attention1d(in_planes, ratio, K, temperature) self.weight = nn.Parameter(torch.randn(K, out_planes, in_planes//groups, kernel_size), requires_grad=True) if bias: self.bias = nn.Parameter(torch.Tensor(K, out_planes)) else: self.bias = None if init_weight: self._initialize_weights() #TODO 初始化 def _initialize_weights(self): for i in range(self.K): nn.init.kaiming_uniform_(self.weight[i]) def update_temperature(self): self.attention.updata_temperature() def forward(self, x):#将batch视作维度变量,进行组卷积,因为组卷积的权重是不同的,动态卷积的权重也是不同的 softmax_attention = self.attention(x) batch_size, in_planes, height = x.size() x = x.view(1, -1, height, )# 变化成一个维度进行组卷积 weight = self.weight.view(self.K, -1) # 动态卷积的权重的生成, 生成的是batch_size个卷积参数(每个参数不同) aggregate_weight = torch.mm(softmax_attention, weight).view(-1, self.in_planes, self.kernel_size,) if self.bias is not None: aggregate_bias = torch.mm(softmax_attention, self.bias).view(-1) output = F.conv1d(x, weight=aggregate_weight, bias=aggregate_bias, stride=self.stride, padding=self.padding, dilation=self.dilation, groups=self.groups*batch_size) else: output = F.conv1d(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(-1)) return output class attention2d(nn.Module): def __init__(self, in_planes, ratios, K, temperature, init_weight=True): super(attention2d, self).__init__() assert temperature%3==1 self.avgpool = nn.AdaptiveAvgPool2d(1) if in_planes!=3: hidden_planes = int(in_planes*ratios)+1 else: hidden_planes = K self.fc1 = nn.Conv2d(in_planes, hidden_planes, 1, bias=False) # self.bn = nn.BatchNorm2d(hidden_planes) self.fc2 = nn.Conv2d(hidden_planes, K, 1, bias=True) self.temperature = temperature if init_weight: 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 updata_temperature(self): if self.temperature!=1: self.temperature -=3 print('Change temperature to:', str(self.temperature)) def forward(self, x): x = self.avgpool(x) x = self.fc1(x) x = F.relu(x) x = self.fc2(x).view(x.size(0), -1) return F.softmax(x/self.temperature, 1) class Dynamic_deepwise_conv2d(nn.Module): def __init__(self, in_planes, out_planes, kernel_size, ratio=0.25, stride=1, padding=0, dilation=1, groups=1, bias=True, K=4,temperature=34, init_weight=True): super(Dynamic_deepwise_conv2d, self).__init__() assert in_planes%groups==0 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.bias = bias self.K = K self.attention = attention2d(in_planes, ratio, K, temperature) self.weight = nn.Parameter(torch.randn(K, out_planes, in_planes//groups, kernel_size, kernel_size), requires_grad=True) if bias: self.bias = nn.Parameter(torch.Tensor(K, out_planes)) else: self.bias = None if init_weight: self._initialize_weights() #TODO 初始化 def _initialize_weights(self): for i in range(self.K): nn.init.kaiming_uniform_(self.weight[i]) def update_temperature(self): self.attention.updata_temperature() def forward(self, x, y):#将batch视作维度变量,进行组卷积,因为组卷积的权重是不同的,动态卷积的权重也是不同的 softmax_attention = self.attention(x) batch_size, in_planes, height, width = x.size() y = y.view(1, -1, height, width)# 变化成一个维度进行组卷积 weight = self.weight.view(self.K, -1) # 动态卷积的权重的生成, 生成的是batch_size个卷积参数(每个参数不同) aggregate_weight = torch.mm(softmax_attention, weight).view(-1, 1, self.kernel_size, self.kernel_size) if self.bias is not None: aggregate_bias = torch.mm(softmax_attention, self.bias).view(-1) output = F.conv2d(y, weight=aggregate_weight, bias=aggregate_bias, stride=self.stride, padding=self.padding, dilation=self.dilation, groups=self.groups*batch_size) else: output = F.conv2d(y, 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)) return output class Dynamic_conv2d(nn.Module): def __init__(self, in_planes, out_planes, kernel_size, ratio=0.25, stride=1, padding=0, dilation=1, groups=1, bias=True, K=4,temperature=34, init_weight=True): super(Dynamic_conv2d, self).__init__() assert in_planes%groups==0 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.bias = bias self.K = K self.attention = attention2d(in_planes, ratio, K, temperature) self.weight = nn.Parameter(torch.randn(K, out_planes, in_planes//groups, kernel_size, kernel_size), requires_grad=True) if bias: self.bias = nn.Parameter(torch.Tensor(K, out_planes)) else: self.bias = None if init_weight: self._initialize_weights() #TODO 初始化 def _initialize_weights(self): for i in range(self.K): nn.init.kaiming_uniform_(self.weight[i]) def update_temperature(self): self.attention.updata_temperature() def forward(self, x,y):#将batch视作维度变量,进行组卷积,因为组卷积的权重是不同的,动态卷积的权重也是不同的 softmax_attention = self.attention(x) batch_size, in_planes, height, width = x.size() y = y.view(1, -1, height, width)# 变化成一个维度进行组卷积 weight = self.weight.view(self.K, -1) # 动态卷积的权重的生成, 生成的是batch_size个卷积参数(每个参数不同) aggregate_weight = torch.mm(softmax_attention, weight).view(-1, self.in_planes, self.kernel_size, self.kernel_size) if self.bias is not None: aggregate_bias = torch.mm(softmax_attention, self.bias).view(-1) output = F.conv2d(y, weight=aggregate_weight, bias=aggregate_bias, stride=self.stride, padding=self.padding, dilation=self.dilation, groups=self.groups*batch_size) else: output = F.conv2d(y, 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)) return output class attention3d(nn.Module): def __init__(self, in_planes, ratios, K, temperature): super(attention3d, self).__init__() assert temperature%3==1 self.avgpool = nn.AdaptiveAvgPool3d(1) if in_planes != 3: hidden_planes = int(in_planes * ratios)+1 else: hidden_planes = K self.fc1 = nn.Conv3d(in_planes, hidden_planes, 1, bias=False) self.fc2 = nn.Conv3d(hidden_planes, K, 1, bias=False) self.temperature = temperature def updata_temperature(self): if self.temperature!=1: self.temperature -=3 print('Change temperature to:', str(self.temperature)) def forward(self, x): x = self.avgpool(x) x = self.fc1(x) x = F.relu(x) x = self.fc2(x).view(x.size(0), -1) return F.softmax(x / self.temperature, 1) class Dynamic_conv3d(nn.Module): def __init__(self, in_planes, out_planes, kernel_size, ratio=0.25, stride=1, padding=0, dilation=1, groups=1, bias=True, K=4, temperature=34): super(Dynamic_conv3d, self).__init__() assert in_planes%groups==0 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.bias = bias self.K = K self.attention = attention3d(in_planes, ratio, K, temperature) self.weight = nn.Parameter(torch.randn(K, out_planes, in_planes//groups, kernel_size, kernel_size, kernel_size), requires_grad=True) if bias: self.bias = nn.Parameter(torch.Tensor(K, out_planes)) else: self.bias = None #TODO 初始化 # nn.init.kaiming_uniform_(self.weight, ) def update_temperature(self): self.attention.updata_temperature() def forward(self, x):#将batch视作维度变量,进行组卷积,因为组卷积的权重是不同的,动态卷积的权重也是不同的 softmax_attention = self.attention(x) batch_size, in_planes, depth, height, width = x.size() x = x.view(1, -1, depth, height, width)# 变化成一个维度进行组卷积 weight = self.weight.view(self.K, -1) # 动态卷积的权重的生成, 生成的是batch_size个卷积参数(每个参数不同) aggregate_weight = torch.mm(softmax_attention, weight).view(-1, self.in_planes, self.kernel_size, self.kernel_size, self.kernel_size) if self.bias is not None: aggregate_bias = torch.mm(softmax_attention, self.bias).view(-1) output = F.conv3d(x, weight=aggregate_weight, bias=aggregate_bias, stride=self.stride, padding=self.padding, dilation=self.dilation, groups=self.groups*batch_size) else: output = F.conv3d(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(-3), output.size(-2), output.size(-1)) return output if __name__ == '__main__': x = torch.randn(12, 256, 64, 64) y = torch.randn(12, 256, 64, 64) model = Dynamic_conv2d(in_planes=256, out_planes=256, kernel_size=3, ratio=0.25, padding=1,groups=1) x = x.to('cuda:0') y = y.to('cuda:0') model.to('cuda') # model.attention.cuda() print(model(x,y).shape) # nn.Conv3d() # print(model(x).shape) # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # model.update_temperature() # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape) # print(model(x).shape)