rec_mv1_enhance.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import torch
  2. import torch.nn as nn
  3. import torch.nn.functional as F
  4. from openrec.modeling.common import Activation
  5. class ConvBNLayer(nn.Module):
  6. def __init__(
  7. self,
  8. num_channels,
  9. filter_size,
  10. num_filters,
  11. stride,
  12. padding,
  13. num_groups=1,
  14. act='hard_swish',
  15. ):
  16. super(ConvBNLayer, self).__init__()
  17. self.act = act
  18. self._conv = nn.Conv2d(
  19. in_channels=num_channels,
  20. out_channels=num_filters,
  21. kernel_size=filter_size,
  22. stride=stride,
  23. padding=padding,
  24. groups=num_groups,
  25. bias=False,
  26. )
  27. self._batch_norm = nn.BatchNorm2d(num_filters, )
  28. if self.act is not None:
  29. self._act = Activation(act_type=act, inplace=True)
  30. def forward(self, inputs):
  31. y = self._conv(inputs)
  32. y = self._batch_norm(y)
  33. if self.act is not None:
  34. y = self._act(y)
  35. return y
  36. class DepthwiseSeparable(nn.Module):
  37. def __init__(
  38. self,
  39. num_channels,
  40. num_filters1,
  41. num_filters2,
  42. num_groups,
  43. stride,
  44. scale,
  45. dw_size=3,
  46. padding=1,
  47. use_se=False,
  48. ):
  49. super(DepthwiseSeparable, self).__init__()
  50. self._depthwise_conv = ConvBNLayer(
  51. num_channels=num_channels,
  52. num_filters=int(num_filters1 * scale),
  53. filter_size=dw_size,
  54. stride=stride,
  55. padding=padding,
  56. num_groups=int(num_groups * scale),
  57. )
  58. self._se = None
  59. if use_se:
  60. self._se = SEModule(int(num_filters1 * scale))
  61. self._pointwise_conv = ConvBNLayer(
  62. num_channels=int(num_filters1 * scale),
  63. filter_size=1,
  64. num_filters=int(num_filters2 * scale),
  65. stride=1,
  66. padding=0,
  67. )
  68. def forward(self, inputs):
  69. y = self._depthwise_conv(inputs)
  70. if self._se is not None:
  71. y = self._se(y)
  72. y = self._pointwise_conv(y)
  73. return y
  74. class MobileNetV1Enhance(nn.Module):
  75. def __init__(self,
  76. in_channels=3,
  77. scale=0.5,
  78. last_conv_stride=1,
  79. last_pool_type='max',
  80. **kwargs):
  81. super().__init__()
  82. self.scale = scale
  83. self.block_list = []
  84. self.conv1 = ConvBNLayer(
  85. num_channels=in_channels,
  86. filter_size=3,
  87. num_filters=int(32 * scale),
  88. stride=2,
  89. padding=1,
  90. )
  91. conv2_1 = DepthwiseSeparable(
  92. num_channels=int(32 * scale),
  93. num_filters1=32,
  94. num_filters2=64,
  95. num_groups=32,
  96. stride=1,
  97. scale=scale,
  98. )
  99. self.block_list.append(conv2_1)
  100. conv2_2 = DepthwiseSeparable(
  101. num_channels=int(64 * scale),
  102. num_filters1=64,
  103. num_filters2=128,
  104. num_groups=64,
  105. stride=1,
  106. scale=scale,
  107. )
  108. self.block_list.append(conv2_2)
  109. conv3_1 = DepthwiseSeparable(
  110. num_channels=int(128 * scale),
  111. num_filters1=128,
  112. num_filters2=128,
  113. num_groups=128,
  114. stride=1,
  115. scale=scale,
  116. )
  117. self.block_list.append(conv3_1)
  118. conv3_2 = DepthwiseSeparable(
  119. num_channels=int(128 * scale),
  120. num_filters1=128,
  121. num_filters2=256,
  122. num_groups=128,
  123. stride=(2, 1),
  124. scale=scale,
  125. )
  126. self.block_list.append(conv3_2)
  127. conv4_1 = DepthwiseSeparable(
  128. num_channels=int(256 * scale),
  129. num_filters1=256,
  130. num_filters2=256,
  131. num_groups=256,
  132. stride=1,
  133. scale=scale,
  134. )
  135. self.block_list.append(conv4_1)
  136. conv4_2 = DepthwiseSeparable(
  137. num_channels=int(256 * scale),
  138. num_filters1=256,
  139. num_filters2=512,
  140. num_groups=256,
  141. stride=(2, 1),
  142. scale=scale,
  143. )
  144. self.block_list.append(conv4_2)
  145. for _ in range(5):
  146. conv5 = DepthwiseSeparable(
  147. num_channels=int(512 * scale),
  148. num_filters1=512,
  149. num_filters2=512,
  150. num_groups=512,
  151. stride=1,
  152. dw_size=5,
  153. padding=2,
  154. scale=scale,
  155. use_se=False,
  156. )
  157. self.block_list.append(conv5)
  158. conv5_6 = DepthwiseSeparable(
  159. num_channels=int(512 * scale),
  160. num_filters1=512,
  161. num_filters2=1024,
  162. num_groups=512,
  163. stride=(2, 1),
  164. dw_size=5,
  165. padding=2,
  166. scale=scale,
  167. use_se=True,
  168. )
  169. self.block_list.append(conv5_6)
  170. conv6 = DepthwiseSeparable(
  171. num_channels=int(1024 * scale),
  172. num_filters1=1024,
  173. num_filters2=1024,
  174. num_groups=1024,
  175. stride=last_conv_stride,
  176. dw_size=5,
  177. padding=2,
  178. use_se=True,
  179. scale=scale,
  180. )
  181. self.block_list.append(conv6)
  182. self.block_list = nn.Sequential(*self.block_list)
  183. if last_pool_type == 'avg':
  184. self.pool = nn.AvgPool2d(kernel_size=2, stride=2, padding=0)
  185. else:
  186. self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
  187. self.out_channels = int(1024 * scale)
  188. def forward(self, inputs):
  189. y = self.conv1(inputs)
  190. y = self.block_list(y)
  191. y = self.pool(y)
  192. return y
  193. def hardsigmoid(x):
  194. return F.relu6(x + 3.0, inplace=True) / 6.0
  195. class SEModule(nn.Module):
  196. def __init__(self, channel, reduction=4):
  197. super(SEModule, self).__init__()
  198. self.avg_pool = nn.AdaptiveAvgPool2d(1)
  199. self.conv1 = nn.Conv2d(
  200. in_channels=channel,
  201. out_channels=channel // reduction,
  202. kernel_size=1,
  203. stride=1,
  204. padding=0,
  205. bias=True,
  206. )
  207. self.conv2 = nn.Conv2d(
  208. in_channels=channel // reduction,
  209. out_channels=channel,
  210. kernel_size=1,
  211. stride=1,
  212. padding=0,
  213. bias=True,
  214. )
  215. def forward(self, inputs):
  216. outputs = self.avg_pool(inputs)
  217. outputs = self.conv1(outputs)
  218. outputs = F.relu(outputs)
  219. outputs = self.conv2(outputs)
  220. outputs = hardsigmoid(outputs)
  221. x = torch.mul(inputs, outputs)
  222. return x