det_pp_lcnet.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. # copyright (c) 2021 PaddlePaddle Authors. All Rights Reserve.
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. from __future__ import absolute_import, division, print_function
  15. import os
  16. import paddle
  17. import paddle.nn as nn
  18. from paddle import ParamAttr
  19. from paddle.nn import AdaptiveAvgPool2D, BatchNorm, Conv2D, Dropout, Linear
  20. from paddle.regularizer import L2Decay
  21. from paddle.nn.initializer import KaimingNormal
  22. from paddle.utils.download import get_path_from_url
  23. MODEL_URLS = {
  24. "PPLCNet_x0.25":
  25. "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x0_25_pretrained.pdparams",
  26. "PPLCNet_x0.35":
  27. "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x0_35_pretrained.pdparams",
  28. "PPLCNet_x0.5":
  29. "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x0_5_pretrained.pdparams",
  30. "PPLCNet_x0.75":
  31. "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x0_75_pretrained.pdparams",
  32. "PPLCNet_x1.0":
  33. "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x1_0_pretrained.pdparams",
  34. "PPLCNet_x1.5":
  35. "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x1_5_pretrained.pdparams",
  36. "PPLCNet_x2.0":
  37. "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x2_0_pretrained.pdparams",
  38. "PPLCNet_x2.5":
  39. "https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPLCNet_x2_5_pretrained.pdparams"
  40. }
  41. MODEL_STAGES_PATTERN = {
  42. "PPLCNet": ["blocks2", "blocks3", "blocks4", "blocks5", "blocks6"]
  43. }
  44. __all__ = list(MODEL_URLS.keys())
  45. # Each element(list) represents a depthwise block, which is composed of k, in_c, out_c, s, use_se.
  46. # k: kernel_size
  47. # in_c: input channel number in depthwise block
  48. # out_c: output channel number in depthwise block
  49. # s: stride in depthwise block
  50. # use_se: whether to use SE block
  51. NET_CONFIG = {
  52. "blocks2":
  53. # k, in_c, out_c, s, use_se
  54. [[3, 16, 32, 1, False]],
  55. "blocks3": [[3, 32, 64, 2, False], [3, 64, 64, 1, False]],
  56. "blocks4": [[3, 64, 128, 2, False], [3, 128, 128, 1, False]],
  57. "blocks5":
  58. [[3, 128, 256, 2, False], [5, 256, 256, 1, False], [5, 256, 256, 1, False],
  59. [5, 256, 256, 1, False], [5, 256, 256, 1, False], [5, 256, 256, 1, False]],
  60. "blocks6": [[5, 256, 512, 2, True], [5, 512, 512, 1, True]]
  61. }
  62. def make_divisible(v, divisor=8, min_value=None):
  63. if min_value is None:
  64. min_value = divisor
  65. new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
  66. if new_v < 0.9 * v:
  67. new_v += divisor
  68. return new_v
  69. class ConvBNLayer(nn.Layer):
  70. def __init__(self,
  71. num_channels,
  72. filter_size,
  73. num_filters,
  74. stride,
  75. num_groups=1):
  76. super().__init__()
  77. self.conv = Conv2D(
  78. in_channels=num_channels,
  79. out_channels=num_filters,
  80. kernel_size=filter_size,
  81. stride=stride,
  82. padding=(filter_size - 1) // 2,
  83. groups=num_groups,
  84. weight_attr=ParamAttr(initializer=KaimingNormal()),
  85. bias_attr=False)
  86. self.bn = BatchNorm(
  87. num_filters,
  88. param_attr=ParamAttr(regularizer=L2Decay(0.0)),
  89. bias_attr=ParamAttr(regularizer=L2Decay(0.0)))
  90. self.hardswish = nn.Hardswish()
  91. def forward(self, x):
  92. x = self.conv(x)
  93. x = self.bn(x)
  94. x = self.hardswish(x)
  95. return x
  96. class DepthwiseSeparable(nn.Layer):
  97. def __init__(self,
  98. num_channels,
  99. num_filters,
  100. stride,
  101. dw_size=3,
  102. use_se=False):
  103. super().__init__()
  104. self.use_se = use_se
  105. self.dw_conv = ConvBNLayer(
  106. num_channels=num_channels,
  107. num_filters=num_channels,
  108. filter_size=dw_size,
  109. stride=stride,
  110. num_groups=num_channels)
  111. if use_se:
  112. self.se = SEModule(num_channels)
  113. self.pw_conv = ConvBNLayer(
  114. num_channels=num_channels,
  115. filter_size=1,
  116. num_filters=num_filters,
  117. stride=1)
  118. def forward(self, x):
  119. x = self.dw_conv(x)
  120. if self.use_se:
  121. x = self.se(x)
  122. x = self.pw_conv(x)
  123. return x
  124. class SEModule(nn.Layer):
  125. def __init__(self, channel, reduction=4):
  126. super().__init__()
  127. self.avg_pool = AdaptiveAvgPool2D(1)
  128. self.conv1 = Conv2D(
  129. in_channels=channel,
  130. out_channels=channel // reduction,
  131. kernel_size=1,
  132. stride=1,
  133. padding=0)
  134. self.relu = nn.ReLU()
  135. self.conv2 = Conv2D(
  136. in_channels=channel // reduction,
  137. out_channels=channel,
  138. kernel_size=1,
  139. stride=1,
  140. padding=0)
  141. self.hardsigmoid = nn.Hardsigmoid()
  142. def forward(self, x):
  143. identity = x
  144. x = self.avg_pool(x)
  145. x = self.conv1(x)
  146. x = self.relu(x)
  147. x = self.conv2(x)
  148. x = self.hardsigmoid(x)
  149. x = paddle.multiply(x=identity, y=x)
  150. return x
  151. class PPLCNet(nn.Layer):
  152. def __init__(self,
  153. in_channels=3,
  154. scale=1.0,
  155. pretrained=False,
  156. use_ssld=False):
  157. super().__init__()
  158. self.out_channels = [
  159. int(NET_CONFIG["blocks3"][-1][2] * scale),
  160. int(NET_CONFIG["blocks4"][-1][2] * scale),
  161. int(NET_CONFIG["blocks5"][-1][2] * scale),
  162. int(NET_CONFIG["blocks6"][-1][2] * scale)
  163. ]
  164. self.scale = scale
  165. self.conv1 = ConvBNLayer(
  166. num_channels=in_channels,
  167. filter_size=3,
  168. num_filters=make_divisible(16 * scale),
  169. stride=2)
  170. self.blocks2 = nn.Sequential(* [
  171. DepthwiseSeparable(
  172. num_channels=make_divisible(in_c * scale),
  173. num_filters=make_divisible(out_c * scale),
  174. dw_size=k,
  175. stride=s,
  176. use_se=se)
  177. for i, (k, in_c, out_c, s, se) in enumerate(NET_CONFIG["blocks2"])
  178. ])
  179. self.blocks3 = nn.Sequential(* [
  180. DepthwiseSeparable(
  181. num_channels=make_divisible(in_c * scale),
  182. num_filters=make_divisible(out_c * scale),
  183. dw_size=k,
  184. stride=s,
  185. use_se=se)
  186. for i, (k, in_c, out_c, s, se) in enumerate(NET_CONFIG["blocks3"])
  187. ])
  188. self.blocks4 = nn.Sequential(* [
  189. DepthwiseSeparable(
  190. num_channels=make_divisible(in_c * scale),
  191. num_filters=make_divisible(out_c * scale),
  192. dw_size=k,
  193. stride=s,
  194. use_se=se)
  195. for i, (k, in_c, out_c, s, se) in enumerate(NET_CONFIG["blocks4"])
  196. ])
  197. self.blocks5 = nn.Sequential(* [
  198. DepthwiseSeparable(
  199. num_channels=make_divisible(in_c * scale),
  200. num_filters=make_divisible(out_c * scale),
  201. dw_size=k,
  202. stride=s,
  203. use_se=se)
  204. for i, (k, in_c, out_c, s, se) in enumerate(NET_CONFIG["blocks5"])
  205. ])
  206. self.blocks6 = nn.Sequential(* [
  207. DepthwiseSeparable(
  208. num_channels=make_divisible(in_c * scale),
  209. num_filters=make_divisible(out_c * scale),
  210. dw_size=k,
  211. stride=s,
  212. use_se=se)
  213. for i, (k, in_c, out_c, s, se) in enumerate(NET_CONFIG["blocks6"])
  214. ])
  215. if pretrained:
  216. self._load_pretrained(
  217. MODEL_URLS['PPLCNet_x{}'.format(scale)], use_ssld=use_ssld)
  218. def forward(self, x):
  219. outs = []
  220. x = self.conv1(x)
  221. x = self.blocks2(x)
  222. x = self.blocks3(x)
  223. outs.append(x)
  224. x = self.blocks4(x)
  225. outs.append(x)
  226. x = self.blocks5(x)
  227. outs.append(x)
  228. x = self.blocks6(x)
  229. outs.append(x)
  230. return outs
  231. def _load_pretrained(self, pretrained_url, use_ssld=False):
  232. if use_ssld:
  233. pretrained_url = pretrained_url.replace("_pretrained",
  234. "_ssld_pretrained")
  235. print(pretrained_url)
  236. local_weight_path = get_path_from_url(
  237. pretrained_url, os.path.expanduser("~/.paddleclas/weights"))
  238. param_state_dict = paddle.load(local_weight_path)
  239. self.set_dict(param_state_dict)
  240. return