ppyoloe.py 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. # Copyright (c) 2022 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 paddle
  18. import copy
  19. from ppdet.core.workspace import register, create
  20. from .meta_arch import BaseArch
  21. __all__ = ['PPYOLOE', 'PPYOLOEWithAuxHead']
  22. # PP-YOLOE and PP-YOLOE+ are recommended to use this architecture
  23. # PP-YOLOE and PP-YOLOE+ can also use the same architecture of YOLOv3 in yolo.py
  24. @register
  25. class PPYOLOE(BaseArch):
  26. __category__ = 'architecture'
  27. __inject__ = ['post_process']
  28. def __init__(self,
  29. backbone='CSPResNet',
  30. neck='CustomCSPPAN',
  31. yolo_head='PPYOLOEHead',
  32. post_process='BBoxPostProcess',
  33. for_mot=False):
  34. """
  35. PPYOLOE network, see https://arxiv.org/abs/2203.16250
  36. Args:
  37. backbone (nn.Layer): backbone instance
  38. neck (nn.Layer): neck instance
  39. yolo_head (nn.Layer): anchor_head instance
  40. post_process (object): `BBoxPostProcess` instance
  41. for_mot (bool): whether return other features for multi-object tracking
  42. models, default False in pure object detection models.
  43. """
  44. super(PPYOLOE, self).__init__()
  45. self.backbone = backbone
  46. self.neck = neck
  47. self.yolo_head = yolo_head
  48. self.post_process = post_process
  49. self.for_mot = for_mot
  50. @classmethod
  51. def from_config(cls, cfg, *args, **kwargs):
  52. # backbone
  53. backbone = create(cfg['backbone'])
  54. # fpn
  55. kwargs = {'input_shape': backbone.out_shape}
  56. neck = create(cfg['neck'], **kwargs)
  57. # head
  58. kwargs = {'input_shape': neck.out_shape}
  59. yolo_head = create(cfg['yolo_head'], **kwargs)
  60. return {
  61. 'backbone': backbone,
  62. 'neck': neck,
  63. "yolo_head": yolo_head,
  64. }
  65. def _forward(self):
  66. body_feats = self.backbone(self.inputs)
  67. neck_feats = self.neck(body_feats, self.for_mot)
  68. if self.training:
  69. yolo_losses = self.yolo_head(neck_feats, self.inputs)
  70. return yolo_losses
  71. else:
  72. yolo_head_outs = self.yolo_head(neck_feats)
  73. if self.post_process is not None:
  74. bbox, bbox_num = self.post_process(
  75. yolo_head_outs, self.yolo_head.mask_anchors,
  76. self.inputs['im_shape'], self.inputs['scale_factor'])
  77. else:
  78. bbox, bbox_num = self.yolo_head.post_process(
  79. yolo_head_outs, self.inputs['scale_factor'])
  80. output = {'bbox': bbox, 'bbox_num': bbox_num}
  81. return output
  82. def get_loss(self):
  83. return self._forward()
  84. def get_pred(self):
  85. return self._forward()
  86. @register
  87. class PPYOLOEWithAuxHead(BaseArch):
  88. __category__ = 'architecture'
  89. __inject__ = ['post_process']
  90. def __init__(self,
  91. backbone='CSPResNet',
  92. neck='CustomCSPPAN',
  93. yolo_head='PPYOLOEHead',
  94. aux_head='SimpleConvHead',
  95. post_process='BBoxPostProcess',
  96. for_mot=False,
  97. detach_epoch=5):
  98. """
  99. PPYOLOE network, see https://arxiv.org/abs/2203.16250
  100. Args:
  101. backbone (nn.Layer): backbone instance
  102. neck (nn.Layer): neck instance
  103. yolo_head (nn.Layer): anchor_head instance
  104. post_process (object): `BBoxPostProcess` instance
  105. for_mot (bool): whether return other features for multi-object tracking
  106. models, default False in pure object detection models.
  107. """
  108. super(PPYOLOEWithAuxHead, self).__init__()
  109. self.backbone = backbone
  110. self.neck = neck
  111. self.aux_neck = copy.deepcopy(self.neck)
  112. self.yolo_head = yolo_head
  113. self.aux_head = aux_head
  114. self.post_process = post_process
  115. self.for_mot = for_mot
  116. self.detach_epoch = detach_epoch
  117. @classmethod
  118. def from_config(cls, cfg, *args, **kwargs):
  119. # backbone
  120. backbone = create(cfg['backbone'])
  121. # fpn
  122. kwargs = {'input_shape': backbone.out_shape}
  123. neck = create(cfg['neck'], **kwargs)
  124. aux_neck = copy.deepcopy(neck)
  125. # head
  126. kwargs = {'input_shape': neck.out_shape}
  127. yolo_head = create(cfg['yolo_head'], **kwargs)
  128. aux_head = create(cfg['aux_head'], **kwargs)
  129. return {
  130. 'backbone': backbone,
  131. 'neck': neck,
  132. "yolo_head": yolo_head,
  133. 'aux_head': aux_head,
  134. }
  135. def _forward(self):
  136. body_feats = self.backbone(self.inputs)
  137. neck_feats = self.neck(body_feats, self.for_mot)
  138. if self.training:
  139. if self.inputs['epoch_id'] >= self.detach_epoch:
  140. aux_neck_feats = self.aux_neck([f.detach() for f in body_feats])
  141. dual_neck_feats = (paddle.concat(
  142. [f.detach(), aux_f], axis=1) for f, aux_f in
  143. zip(neck_feats, aux_neck_feats))
  144. else:
  145. aux_neck_feats = self.aux_neck(body_feats)
  146. dual_neck_feats = (paddle.concat(
  147. [f, aux_f], axis=1) for f, aux_f in
  148. zip(neck_feats, aux_neck_feats))
  149. aux_cls_scores, aux_bbox_preds = self.aux_head(dual_neck_feats)
  150. loss = self.yolo_head(
  151. neck_feats,
  152. self.inputs,
  153. aux_pred=[aux_cls_scores, aux_bbox_preds])
  154. return loss
  155. else:
  156. yolo_head_outs = self.yolo_head(neck_feats)
  157. if self.post_process is not None:
  158. bbox, bbox_num = self.post_process(
  159. yolo_head_outs, self.yolo_head.mask_anchors,
  160. self.inputs['im_shape'], self.inputs['scale_factor'])
  161. else:
  162. bbox, bbox_num = self.yolo_head.post_process(
  163. yolo_head_outs, self.inputs['scale_factor'])
  164. output = {'bbox': bbox, 'bbox_num': bbox_num}
  165. return output
  166. def get_loss(self):
  167. return self._forward()
  168. def get_pred(self):
  169. return self._forward()