3939
4040
4141from .create_act import create_act_layer
42+ from .helpers import make_divisible
4243
4344
4445class EcaModule (nn .Module ):
@@ -56,21 +57,36 @@ class EcaModule(nn.Module):
5657 act_layer: optional non-linearity after conv, enables conv bias, this is an experiment
5758 gate_layer: gating non-linearity to use
5859 """
59- def __init__ (self , channels = None , kernel_size = 3 , gamma = 2 , beta = 1 , act_layer = None , gate_layer = 'sigmoid' ):
60+ def __init__ (
61+ self , channels = None , kernel_size = 3 , gamma = 2 , beta = 1 , act_layer = None , gate_layer = 'sigmoid' ,
62+ rd_ratio = 1 / 8 , rd_channels = None , rd_divisor = 8 , use_mlp = False ):
6063 super (EcaModule , self ).__init__ ()
6164 if channels is not None :
6265 t = int (abs (math .log (channels , 2 ) + beta ) / gamma )
6366 kernel_size = max (t if t % 2 else t + 1 , 3 )
6467 assert kernel_size % 2 == 1
65- has_act = act_layer is not None
66- self .conv = nn .Conv1d (1 , 1 , kernel_size = kernel_size , padding = (kernel_size - 1 ) // 2 , bias = has_act )
67- self .act = create_act_layer (act_layer ) if has_act else nn .Identity ()
68+ padding = (kernel_size - 1 ) // 2
69+ if use_mlp :
70+ # NOTE 'mlp' mode is a timm experiment, not in paper
71+ assert channels is not None
72+ if rd_channels is None :
73+ rd_channels = make_divisible (channels * rd_ratio , divisor = rd_divisor )
74+ act_layer = act_layer or nn .ReLU
75+ self .conv = nn .Conv1d (1 , rd_channels , kernel_size = 1 , padding = 0 , bias = True )
76+ self .act = create_act_layer (act_layer )
77+ self .conv2 = nn .Conv1d (rd_channels , 1 , kernel_size = kernel_size , padding = padding , bias = True )
78+ else :
79+ self .conv = nn .Conv1d (1 , 1 , kernel_size = kernel_size , padding = padding , bias = False )
80+ self .act = None
81+ self .conv2 = None
6882 self .gate = create_act_layer (gate_layer )
6983
7084 def forward (self , x ):
7185 y = x .mean ((2 , 3 )).view (x .shape [0 ], 1 , - 1 ) # view for 1d conv
7286 y = self .conv (y )
73- y = self .act (y ) # NOTE: usually a no-op, added for experimentation
87+ if self .conv2 is not None :
88+ y = self .act (y )
89+ y = self .conv2 (y )
7490 y = self .gate (y ).view (x .shape [0 ], - 1 , 1 , 1 )
7591 return x * y .expand_as (x )
7692
@@ -115,15 +131,13 @@ def __init__(self, channels=None, kernel_size=3, gamma=2, beta=1, act_layer=None
115131 # implement manual circular padding
116132 self .padding = (kernel_size - 1 ) // 2
117133 self .conv = nn .Conv1d (1 , 1 , kernel_size = kernel_size , padding = 0 , bias = has_act )
118- self .act = create_act_layer (act_layer ) if has_act else nn .Identity ()
119134 self .gate = create_act_layer (gate_layer )
120135
121136 def forward (self , x ):
122137 y = x .mean ((2 , 3 )).view (x .shape [0 ], 1 , - 1 )
123138 # Manually implement circular padding, F.pad does not seemed to be bugged
124139 y = F .pad (y , (self .padding , self .padding ), mode = 'circular' )
125140 y = self .conv (y )
126- y = self .act (y ) # NOTE: usually a no-op, added for experimentation
127141 y = self .gate (y ).view (x .shape [0 ], - 1 , 1 , 1 )
128142 return x * y .expand_as (x )
129143
0 commit comments