text: import math
  
  import torch
  import torch.nn.functional as F
  import torch.utils.model_zoo as model_zoo
  from torch import nn
  from torch.nn import Parameter
  # import pdb
  import numpy as np
  
  
  class Conv2d_cd(nn.Module):
      def __init__(self, in_channels, out_channels, kernel_size=3, stride=1,
                   padding=1, dilation=1, groups=1, bias=False, theta=0.7):
  
          super(Conv2d_cd, self).__init__() 
          self.conv = nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding, dilation=dilation, groups=groups, bias=bias)
          self.theta = theta
  
      def forward(self, x):
          out_normal = self.conv(x)
  
          if math.fabs(self.theta - 0.0) < 1e-8:
              return out_normal 
          else:
              #pdb.set_trace()
              [C_out,C_in, kernel_size,kernel_size] = self.conv.weight.shape
              kernel_diff = self.conv.weight.sum(2).sum(2)
              kernel_diff = kernel_diff[:, :, None, None]
              out_diff = F.conv2d(input=x, weight=kernel_diff, bias=self.conv.bias, stride=self.conv.stride, padding=0, dilation=self.conv.dilation, groups=self.conv.groups)
  
              return out_normal - self.theta * out_diff
  
  
  class SpatialAttention(nn.Module):
      def __init__(self, kernel = 3):
          super(SpatialAttention, self).__init__()
  
  
          self.conv1 = nn.Conv2d(2, 1, kernel_size=kernel, padding=kernel//2, bias=False)
          self.sigmoid = nn.Sigmoid()
  
      def forward(self, x):
          avg_out = torch.mean(x, dim=1, keepdim=True)
          max_out, _ = torch.max(x, dim=1, keepdim=True)
          x = torch.cat([avg_out, max_out], dim=1)
          x = self.conv1(x)
          
          return self.sigmoid(x)
  
  
  
  		
  
  class get_model(nn.Module):
  
      def __init__(self, basic_conv=Conv2d_cd, theta=0.7 ):   
          super(get_model, self).__init__()
          
          
          self.conv1 = nn.Sequential(
              basic_conv(3, 80, kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(80),
              nn.ReLU(),    
              
          )
          
          self.Block1 = nn.Sequential(
              basic_conv(80, 160, kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(160),
              nn.ReLU(),  
              
              basic_conv(160, int(160*1.6), kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(int(160*1.6)),
              nn.ReLU(),  
              basic_conv(int(160*1.6), 160, kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(160),
              nn.ReLU(), 
              
              nn.MaxPool2d(kernel_size=3, stride=2, padding=1),
              
          )
          
          self.Block2 = nn.Sequential(
              basic_conv(160, int(160*1.2), kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(int(160*1.2)),
              nn.ReLU(),  
              basic_conv(int(160*1.2), 160, kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(160),
              nn.ReLU(),  
              basic_conv(160, int(160*1.4), kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(int(160*1.4)),
              nn.ReLU(),  
              basic_conv(int(160*1.4), 160, kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(160),
              nn.ReLU(),  
              
              nn.MaxPool2d(kernel_size=3, stride=2, padding=1),
          )
          
          self.Block3 = nn.Sequential(
              basic_conv(160, 160, kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(160),
              nn.ReLU(), 
              basic_conv(160, int(160*1.2), kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(int(160*1.2)),
              nn.ReLU(),  
              basic_conv(int(160*1.2), 160, kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(160),
              nn.ReLU(), 
              nn.MaxPool2d(kernel_size=3, stride=2, padding=1),
          )
          
          # Original
          
          self.lastconv1 = nn.Sequential(
              basic_conv(160*3, 160, kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.BatchNorm2d(160),
              nn.ReLU(),
              basic_conv(160, 1, kernel_size=3, stride=1, padding=1, bias=False, theta= theta),
              nn.ReLU(),    
          )
          
        
          self.sa1 = SpatialAttention(kernel = 7)
          self.sa2 = SpatialAttention(kernel = 5)
          self.sa3 = SpatialAttention(kernel = 3)
          
          self.fc1 = nn.Linear(1024,1024)
          self.fc2 = nn.Linear(1024,2)
          
          self.downsample32x32 = nn.Upsample(size=(32, 32), mode='bilinear')
  
   
      def forward(self, x):	    	# x [3, 256, 256]
          
          # x_input = x
          x = self.conv1(x)		   
          
          x = self.Block1(x)	    	    	
          attention1 = self.sa1(x)
          attention1 = attention1 * x
          attention1 = self.downsample32x32(attention1)   
          
          x = self.Block2(x)	    
          attention2 = self.sa2(x)  
          attention2 = attention2 * x
          attention2 = self.downsample32x32(attention2)  
          
          x = self.Block3(x)	    
          attention3 = self.sa3(x)  
          attention3 = attention3 * x	
          attention3 = self.downsample32x32(attention3)   
          
          x = torch.cat((attention1,attention2,attention3), dim=1)    
          
          #pdb.set_trace()
          
          # map_x = self.lastconv1(x)
          
          # map_x = map_x.squeeze(1)
          x = self.lastconv1(x)
          x = x.view(x.size(0),-1)
          x = self.fc1(x)
          x = self.fc2(x)
          # return map_x, x_concat, attention1, attention2, attention3, x_input
          return x
  
  
  def get_loss():
      return nn.BCEWithLogitsLoss()
  def get_npoints():
      return None
  def predeal(data):
      for i in range(data.shape[1]):
          data[:,i] /= data[:,i].max()
      data = torch.Tensor(data[:,:3])
      return data.float().permute(1,0).cuda().view(1,data.shape[1],data.shape[0])
  def resdeal(data):
      # data = nn.sigmoid(data)
      ans = torch.argmax(data, dim=1).float()
      return ans
  