YOLOv5改进系列(27)——添加SCConv注意力卷积(CVPR 2023|即插即用的高效卷积模块)

时间:2025-04-02 09:14:28
  • # ScConv
  • def autopad(k, p=None, d=1): # kernel, padding, dilation
  • # Pad to 'same' shape outputs
  • if d > 1:
  • k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k] # actual kernel-size
  • if p is None:
  • p = k // 2 if isinstance(k, int) else [x // 2 for x in k] # auto-pad
  • return p
  • class Conv():
  • # Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)
  • default_act = () # default activation
  • def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
  • super().__init__()
  • = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
  • = nn.BatchNorm2d(c2)
  • = self.default_act if act is True else act if isinstance(act, ) else ()
  • def forward(self, x):
  • return (((x)))
  • def forward_fuse(self, x):
  • return ((x))
  • class GroupBatchnorm2d():
  • def __init__(self, c_num:int,
  • group_num:int = 16,
  • eps:float = 1e-10
  • ):
  • super(GroupBatchnorm2d,self).__init__()
  • assert c_num >= group_num
  • self.group_num = group_num
  • = ( (c_num, 1, 1) )
  • = ( (c_num, 1, 1) )
  • = eps
  • def forward(self, x):
  • N, C, H, W = ()
  • x = ( N, self.group_num, -1 )
  • mean = ( dim = 2, keepdim = True )
  • std = ( dim = 2, keepdim = True )
  • x = (x - mean) / (std+)
  • x = (N, C, H, W)
  • return x * +
  • class SRU():
  • def __init__(self,
  • oup_channels:int,
  • group_num:int = 16,
  • gate_treshold:float = 0.5
  • ):
  • super().__init__()
  • = GroupBatchnorm2d( oup_channels, group_num = group_num )
  • self.gate_treshold = gate_treshold
  • = ()
  • def forward(self,x):
  • gn_x = (x)
  • w_gamma = (,dim=0)
  • reweigts = ( gn_x * w_gamma )
  • # Gate
  • info_mask = w_gamma>self.gate_treshold
  • noninfo_mask= w_gamma<=self.gate_treshold
  • x_1 = info_mask*reweigts * x
  • x_2 = noninfo_mask*reweigts * x
  • x = (x_1,x_2)
  • return x
  • def reconstruct(self,x_1,x_2):
  • x_11,x_12 = (x_1, x_1.size(1)//2, dim=1)
  • x_21,x_22 = (x_2, x_2.size(1)//2, dim=1)
  • return ([ x_11+x_22, x_12+x_21 ],dim=1)
  • class CRU():
  • '''
  • alpha: 0<alpha<1
  • '''
  • def __init__(self,
  • op_channel:int,
  • alpha:float = 1/2,
  • squeeze_radio:int = 2 ,
  • group_size:int = 2,
  • group_kernel_size:int = 3,
  • ):
  • super().__init__()
  • self.up_channel = up_channel = int(alpha*op_channel)
  • self.low_channel = low_channel = op_channel-up_channel
  • self.squeeze1 = nn.Conv2d(up_channel,up_channel//squeeze_radio,kernel_size=1,bias=False)
  • self.squeeze2 = nn.Conv2d(low_channel,low_channel//squeeze_radio,kernel_size=1,bias=False)
  • #up
  • = nn.Conv2d(up_channel//squeeze_radio, op_channel,kernel_size=group_kernel_size, stride=1,padding=group_kernel_size//2, groups = group_size)
  • self.PWC1 = nn.Conv2d(up_channel//squeeze_radio, op_channel,kernel_size=1, bias=False)
  • #low
  • self.PWC2 = nn.Conv2d(low_channel//squeeze_radio, op_channel-low_channel//squeeze_radio,kernel_size=1, bias=False)
  • = nn.AdaptiveAvgPool2d(1)
  • def forward(self,x):
  • # Split
  • up,low = (x,[self.up_channel,self.low_channel],dim=1)
  • up,low = self.squeeze1(up),self.squeeze2(low)
  • # Transform
  • Y1 = (up) + self.PWC1(up)
  • Y2 = ( [self.PWC2(low), low], dim= 1 )
  • # Fuse
  • out = ( [Y1,Y2], dim= 1 )
  • out = ( (out), dim=1 ) * out
  • out1,out2 = (out,(1)//2,dim=1)
  • return out1+out2
  • class ScConv():
  • def __init__(self,
  • op_channel:int,
  • group_num:int = 16,
  • gate_treshold:float = 0.5,
  • alpha:float = 1/2,
  • squeeze_radio:int = 2 ,
  • group_size:int = 2,
  • group_kernel_size:int = 3,
  • ):
  • super().__init__()
  • = SRU( op_channel,
  • group_num = group_num,
  • gate_treshold = gate_treshold )
  • = CRU( op_channel,
  • alpha = alpha,
  • squeeze_radio = squeeze_radio ,
  • group_size = group_size ,
  • group_kernel_size = group_kernel_size )
  • def forward(self,x):
  • x = (x)
  • x = (x)
  • return x
  • class C3_ScConv():
  • # CSP Bottleneck with 3 convolutions
  • def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
  • super().__init__()
  • c_ = int(c2 * e) # hidden channels
  • self.cv1 = Conv(c1, c_, 1, 1)
  • self.cv2 = Conv(c1, c_, 1, 1)
  • self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2)
  • = (*(ScConv(c_) for _ in range(n)))
  • def forward(self, x):
  • return self.cv3((((self.cv1(x)), self.cv2(x)), 1))
  • if __name__ == '__main__':
  • x = (1,32,16,16)
  • model = ScConv(32)
  • print(model(x).shape)