# 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)