darknet.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. # Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
  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. import paddle
  15. import paddle.nn as nn
  16. import paddle.nn.functional as F
  17. from ppdet.core.workspace import register, serializable
  18. from ppdet.modeling.ops import batch_norm, mish
  19. from ..shape_spec import ShapeSpec
  20. __all__ = ['DarkNet', 'ConvBNLayer']
  21. class ConvBNLayer(nn.Layer):
  22. def __init__(self,
  23. ch_in,
  24. ch_out,
  25. filter_size=3,
  26. stride=1,
  27. groups=1,
  28. padding=0,
  29. norm_type='bn',
  30. norm_decay=0.,
  31. act="leaky",
  32. freeze_norm=False,
  33. data_format='NCHW',
  34. name=''):
  35. """
  36. conv + bn + activation layer
  37. Args:
  38. ch_in (int): input channel
  39. ch_out (int): output channel
  40. filter_size (int): filter size, default 3
  41. stride (int): stride, default 1
  42. groups (int): number of groups of conv layer, default 1
  43. padding (int): padding size, default 0
  44. norm_type (str): batch norm type, default bn
  45. norm_decay (str): decay for weight and bias of batch norm layer, default 0.
  46. act (str): activation function type, default 'leaky', which means leaky_relu
  47. freeze_norm (bool): whether to freeze norm, default False
  48. data_format (str): data format, NCHW or NHWC
  49. """
  50. super(ConvBNLayer, self).__init__()
  51. self.conv = nn.Conv2D(
  52. in_channels=ch_in,
  53. out_channels=ch_out,
  54. kernel_size=filter_size,
  55. stride=stride,
  56. padding=padding,
  57. groups=groups,
  58. data_format=data_format,
  59. bias_attr=False)
  60. self.batch_norm = batch_norm(
  61. ch_out,
  62. norm_type=norm_type,
  63. norm_decay=norm_decay,
  64. freeze_norm=freeze_norm,
  65. data_format=data_format)
  66. self.act = act
  67. def forward(self, inputs):
  68. out = self.conv(inputs)
  69. out = self.batch_norm(out)
  70. if self.act == 'leaky':
  71. out = F.leaky_relu(out, 0.1)
  72. else:
  73. out = getattr(F, self.act)(out)
  74. return out
  75. class DownSample(nn.Layer):
  76. def __init__(self,
  77. ch_in,
  78. ch_out,
  79. filter_size=3,
  80. stride=2,
  81. padding=1,
  82. norm_type='bn',
  83. norm_decay=0.,
  84. freeze_norm=False,
  85. data_format='NCHW'):
  86. """
  87. downsample layer
  88. Args:
  89. ch_in (int): input channel
  90. ch_out (int): output channel
  91. filter_size (int): filter size, default 3
  92. stride (int): stride, default 2
  93. padding (int): padding size, default 1
  94. norm_type (str): batch norm type, default bn
  95. norm_decay (str): decay for weight and bias of batch norm layer, default 0.
  96. freeze_norm (bool): whether to freeze norm, default False
  97. data_format (str): data format, NCHW or NHWC
  98. """
  99. super(DownSample, self).__init__()
  100. self.conv_bn_layer = ConvBNLayer(
  101. ch_in=ch_in,
  102. ch_out=ch_out,
  103. filter_size=filter_size,
  104. stride=stride,
  105. padding=padding,
  106. norm_type=norm_type,
  107. norm_decay=norm_decay,
  108. freeze_norm=freeze_norm,
  109. data_format=data_format)
  110. self.ch_out = ch_out
  111. def forward(self, inputs):
  112. out = self.conv_bn_layer(inputs)
  113. return out
  114. class BasicBlock(nn.Layer):
  115. def __init__(self,
  116. ch_in,
  117. ch_out,
  118. norm_type='bn',
  119. norm_decay=0.,
  120. freeze_norm=False,
  121. data_format='NCHW'):
  122. """
  123. BasicBlock layer of DarkNet
  124. Args:
  125. ch_in (int): input channel
  126. ch_out (int): output channel
  127. norm_type (str): batch norm type, default bn
  128. norm_decay (str): decay for weight and bias of batch norm layer, default 0.
  129. freeze_norm (bool): whether to freeze norm, default False
  130. data_format (str): data format, NCHW or NHWC
  131. """
  132. super(BasicBlock, self).__init__()
  133. assert ch_in == ch_out and (ch_in % 2) == 0, \
  134. f"ch_in and ch_out should be the same even int, but the input \'ch_in is {ch_in}, \'ch_out is {ch_out}"
  135. # example:
  136. # --------------{conv1} --> {conv2}
  137. # channel route: 10-->5 --> 5-->10
  138. self.conv1 = ConvBNLayer(
  139. ch_in=ch_in,
  140. ch_out=int(ch_out / 2),
  141. filter_size=1,
  142. stride=1,
  143. padding=0,
  144. norm_type=norm_type,
  145. norm_decay=norm_decay,
  146. freeze_norm=freeze_norm,
  147. data_format=data_format)
  148. self.conv2 = ConvBNLayer(
  149. ch_in=int(ch_out / 2),
  150. ch_out=ch_out,
  151. filter_size=3,
  152. stride=1,
  153. padding=1,
  154. norm_type=norm_type,
  155. norm_decay=norm_decay,
  156. freeze_norm=freeze_norm,
  157. data_format=data_format)
  158. def forward(self, inputs):
  159. conv1 = self.conv1(inputs)
  160. conv2 = self.conv2(conv1)
  161. out = paddle.add(x=inputs, y=conv2)
  162. return out
  163. class Blocks(nn.Layer):
  164. def __init__(self,
  165. ch_in,
  166. ch_out,
  167. count,
  168. norm_type='bn',
  169. norm_decay=0.,
  170. freeze_norm=False,
  171. name=None,
  172. data_format='NCHW'):
  173. """
  174. Blocks layer, which consist of some BaickBlock layers
  175. Args:
  176. ch_in (int): input channel
  177. ch_out (int): output channel
  178. count (int): number of BasicBlock layer
  179. norm_type (str): batch norm type, default bn
  180. norm_decay (str): decay for weight and bias of batch norm layer, default 0.
  181. freeze_norm (bool): whether to freeze norm, default False
  182. name (str): layer name
  183. data_format (str): data format, NCHW or NHWC
  184. """
  185. super(Blocks, self).__init__()
  186. self.basicblock0 = BasicBlock(
  187. ch_in,
  188. ch_out,
  189. norm_type=norm_type,
  190. norm_decay=norm_decay,
  191. freeze_norm=freeze_norm,
  192. data_format=data_format)
  193. self.res_out_list = []
  194. for i in range(1, count):
  195. block_name = '{}.{}'.format(name, i)
  196. res_out = self.add_sublayer(
  197. block_name,
  198. BasicBlock(
  199. ch_out,
  200. ch_out,
  201. norm_type=norm_type,
  202. norm_decay=norm_decay,
  203. freeze_norm=freeze_norm,
  204. data_format=data_format))
  205. self.res_out_list.append(res_out)
  206. self.ch_out = ch_out
  207. def forward(self, inputs):
  208. y = self.basicblock0(inputs)
  209. for basic_block_i in self.res_out_list:
  210. y = basic_block_i(y)
  211. return y
  212. DarkNet_cfg = {53: ([1, 2, 8, 8, 4])}
  213. @register
  214. @serializable
  215. class DarkNet(nn.Layer):
  216. __shared__ = ['norm_type', 'data_format']
  217. def __init__(self,
  218. depth=53,
  219. freeze_at=-1,
  220. return_idx=[2, 3, 4],
  221. num_stages=5,
  222. norm_type='bn',
  223. norm_decay=0.,
  224. freeze_norm=False,
  225. data_format='NCHW'):
  226. """
  227. Darknet, see https://pjreddie.com/darknet/yolo/
  228. Args:
  229. depth (int): depth of network
  230. freeze_at (int): freeze the backbone at which stage
  231. filter_size (int): filter size, default 3
  232. return_idx (list): index of stages whose feature maps are returned
  233. norm_type (str): batch norm type, default bn
  234. norm_decay (str): decay for weight and bias of batch norm layer, default 0.
  235. data_format (str): data format, NCHW or NHWC
  236. """
  237. super(DarkNet, self).__init__()
  238. self.depth = depth
  239. self.freeze_at = freeze_at
  240. self.return_idx = return_idx
  241. self.num_stages = num_stages
  242. self.stages = DarkNet_cfg[self.depth][0:num_stages]
  243. self.conv0 = ConvBNLayer(
  244. ch_in=3,
  245. ch_out=32,
  246. filter_size=3,
  247. stride=1,
  248. padding=1,
  249. norm_type=norm_type,
  250. norm_decay=norm_decay,
  251. freeze_norm=freeze_norm,
  252. data_format=data_format)
  253. self.downsample0 = DownSample(
  254. ch_in=32,
  255. ch_out=32 * 2,
  256. norm_type=norm_type,
  257. norm_decay=norm_decay,
  258. freeze_norm=freeze_norm,
  259. data_format=data_format)
  260. self._out_channels = []
  261. self.darknet_conv_block_list = []
  262. self.downsample_list = []
  263. ch_in = [64, 128, 256, 512, 1024]
  264. for i, stage in enumerate(self.stages):
  265. name = 'stage.{}'.format(i)
  266. conv_block = self.add_sublayer(
  267. name,
  268. Blocks(
  269. int(ch_in[i]),
  270. int(ch_in[i]),
  271. stage,
  272. norm_type=norm_type,
  273. norm_decay=norm_decay,
  274. freeze_norm=freeze_norm,
  275. data_format=data_format,
  276. name=name))
  277. self.darknet_conv_block_list.append(conv_block)
  278. if i in return_idx:
  279. self._out_channels.append(int(ch_in[i]))
  280. for i in range(num_stages - 1):
  281. down_name = 'stage.{}.downsample'.format(i)
  282. downsample = self.add_sublayer(
  283. down_name,
  284. DownSample(
  285. ch_in=int(ch_in[i]),
  286. ch_out=int(ch_in[i + 1]),
  287. norm_type=norm_type,
  288. norm_decay=norm_decay,
  289. freeze_norm=freeze_norm,
  290. data_format=data_format))
  291. self.downsample_list.append(downsample)
  292. def forward(self, inputs):
  293. x = inputs['image']
  294. out = self.conv0(x)
  295. out = self.downsample0(out)
  296. blocks = []
  297. for i, conv_block_i in enumerate(self.darknet_conv_block_list):
  298. out = conv_block_i(out)
  299. if i == self.freeze_at:
  300. out.stop_gradient = True
  301. if i in self.return_idx:
  302. blocks.append(out)
  303. if i < self.num_stages - 1:
  304. out = self.downsample_list[i](out)
  305. return blocks
  306. @property
  307. def out_shape(self):
  308. return [ShapeSpec(channels=c) for c in self._out_channels]