darknet.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. # Copyright (c) 2019 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. from __future__ import absolute_import
  15. from __future__ import division
  16. from __future__ import print_function
  17. import six
  18. import math
  19. from collections import OrderedDict
  20. from paddle import fluid
  21. from paddle.fluid.param_attr import ParamAttr
  22. from paddle.fluid.regularizer import L2Decay
  23. class DarkNet(object):
  24. """
  25. DarkNet, see https://pjreddie.com/darknet/yolo/
  26. Args:
  27. depth (int): network depth, currently only darknet 53 is supported
  28. norm_type (str): normalization type, 'bn' and 'sync_bn' are supported
  29. norm_decay (float): weight decay for normalization layer weights
  30. """
  31. def __init__(self,
  32. depth=53,
  33. num_classes=None,
  34. norm_type='bn',
  35. norm_decay=0.,
  36. bn_act='leaky',
  37. weight_prefix_name=''):
  38. assert depth in [53], "unsupported depth value"
  39. self.depth = depth
  40. self.num_classes = num_classes
  41. self.norm_type = norm_type
  42. self.norm_decay = norm_decay
  43. self.depth_cfg = {53: ([1, 2, 8, 8, 4], self.basicblock)}
  44. self.bn_act = bn_act
  45. self.prefix_name = weight_prefix_name
  46. def _conv_norm(self,
  47. input,
  48. ch_out,
  49. filter_size,
  50. stride,
  51. padding,
  52. act='leaky',
  53. name=None):
  54. conv = fluid.layers.conv2d(
  55. input=input,
  56. num_filters=ch_out,
  57. filter_size=filter_size,
  58. stride=stride,
  59. padding=padding,
  60. act=None,
  61. param_attr=ParamAttr(name=name + ".conv.weights"),
  62. bias_attr=False)
  63. bn_name = name + ".bn"
  64. bn_param_attr = ParamAttr(
  65. regularizer=L2Decay(float(self.norm_decay)),
  66. name=bn_name + '.scale')
  67. bn_bias_attr = ParamAttr(
  68. regularizer=L2Decay(float(self.norm_decay)),
  69. name=bn_name + '.offset')
  70. out = fluid.layers.batch_norm(
  71. input=conv,
  72. param_attr=bn_param_attr,
  73. bias_attr=bn_bias_attr,
  74. moving_mean_name=bn_name + '.mean',
  75. moving_variance_name=bn_name + '.var')
  76. # leaky relu here has `alpha` as 0.1, can not be set by
  77. # `act` param in fluid.layers.batch_norm above.
  78. if act == 'leaky':
  79. out = fluid.layers.leaky_relu(x=out, alpha=0.1)
  80. if act == 'relu':
  81. out = fluid.layers.relu(x=out)
  82. return out
  83. def _downsample(self,
  84. input,
  85. ch_out,
  86. filter_size=3,
  87. stride=2,
  88. padding=1,
  89. name=None):
  90. return self._conv_norm(
  91. input,
  92. ch_out=ch_out,
  93. filter_size=filter_size,
  94. stride=stride,
  95. padding=padding,
  96. act=self.bn_act,
  97. name=name)
  98. def basicblock(self, input, ch_out, name=None):
  99. conv1 = self._conv_norm(
  100. input,
  101. ch_out=ch_out,
  102. filter_size=1,
  103. stride=1,
  104. padding=0,
  105. act=self.bn_act,
  106. name=name + ".0")
  107. conv2 = self._conv_norm(
  108. conv1,
  109. ch_out=ch_out * 2,
  110. filter_size=3,
  111. stride=1,
  112. padding=1,
  113. act=self.bn_act,
  114. name=name + ".1")
  115. out = fluid.layers.elementwise_add(x=input, y=conv2, act=None)
  116. return out
  117. def layer_warp(self, block_func, input, ch_out, count, name=None):
  118. out = block_func(input, ch_out=ch_out, name='{}.0'.format(name))
  119. for j in six.moves.xrange(1, count):
  120. out = block_func(out, ch_out=ch_out, name='{}.{}'.format(name, j))
  121. return out
  122. def __call__(self, input):
  123. """
  124. Get the backbone of DarkNet, that is output for the 5 stages.
  125. Args:
  126. input (Variable): input variable.
  127. Returns:
  128. The last variables of each stage.
  129. """
  130. stages, block_func = self.depth_cfg[self.depth]
  131. stages = stages[0:5]
  132. conv = self._conv_norm(
  133. input=input,
  134. ch_out=32,
  135. filter_size=3,
  136. stride=1,
  137. padding=1,
  138. act=self.bn_act,
  139. name=self.prefix_name + "yolo_input")
  140. downsample_ = self._downsample(
  141. input=conv,
  142. ch_out=conv.shape[1] * 2,
  143. name=self.prefix_name + "yolo_input.downsample")
  144. blocks = []
  145. for i, stage in enumerate(stages):
  146. block = self.layer_warp(
  147. block_func=block_func,
  148. input=downsample_,
  149. ch_out=32 * 2**i,
  150. count=stage,
  151. name=self.prefix_name + "stage.{}".format(i))
  152. blocks.append(block)
  153. if i < len(stages) - 1: # do not downsaple in the last stage
  154. downsample_ = self._downsample(
  155. input=block,
  156. ch_out=block.shape[1] * 2,
  157. name=self.prefix_name + "stage.{}.downsample".format(i))
  158. if self.num_classes is not None:
  159. pool = fluid.layers.pool2d(
  160. input=blocks[-1], pool_type='avg', global_pooling=True)
  161. stdv = 1.0 / math.sqrt(pool.shape[1] * 1.0)
  162. out = fluid.layers.fc(
  163. input=pool,
  164. size=self.num_classes,
  165. param_attr=ParamAttr(
  166. initializer=fluid.initializer.Uniform(-stdv, stdv),
  167. name='fc_weights'),
  168. bias_attr=ParamAttr(name='fc_offset'))
  169. return OrderedDict([('logits', out)])
  170. return blocks