fcos_loss.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. from __future__ import absolute_import
  15. from __future__ import division
  16. from __future__ import print_function
  17. from paddle import fluid
  18. from paddle.fluid.param_attr import ParamAttr
  19. from ppdet.core.workspace import register, serializable
  20. INF = 1e8
  21. __all__ = ['FCOSLoss']
  22. @register
  23. @serializable
  24. class FCOSLoss(object):
  25. """
  26. FCOSLoss
  27. Args:
  28. loss_alpha (float): alpha in focal loss
  29. loss_gamma (float): gamma in focal loss
  30. iou_loss_type(str): location loss type, IoU/GIoU/LINEAR_IoU
  31. reg_weights(float): weight for location loss
  32. """
  33. def __init__(self,
  34. loss_alpha=0.25,
  35. loss_gamma=2.0,
  36. iou_loss_type="IoU",
  37. reg_weights=1.0):
  38. self.loss_alpha = loss_alpha
  39. self.loss_gamma = loss_gamma
  40. self.iou_loss_type = iou_loss_type
  41. self.reg_weights = reg_weights
  42. def __flatten_tensor(self, input, channel_first=False):
  43. """
  44. Flatten a Tensor
  45. Args:
  46. input (Variables): Input Tensor
  47. channel_first(bool): if true the dimension order of
  48. Tensor is [N, C, H, W], otherwise is [N, H, W, C]
  49. Return:
  50. input_channel_last (Variables): The flattened Tensor in channel_last style
  51. """
  52. if channel_first:
  53. input_channel_last = fluid.layers.transpose(
  54. input, perm=[0, 2, 3, 1])
  55. else:
  56. input_channel_last = input
  57. input_channel_last = fluid.layers.flatten(input_channel_last, axis=3)
  58. return input_channel_last
  59. def __iou_loss(self, pred, targets, positive_mask, weights=None):
  60. """
  61. Calculate the loss for location prediction
  62. Args:
  63. pred (Variables): bounding boxes prediction
  64. targets (Variables): targets for positive samples
  65. positive_mask (Variables): mask of positive samples
  66. weights (Variables): weights for each positive samples
  67. Return:
  68. loss (Varialbes): location loss
  69. """
  70. plw = fluid.layers.elementwise_mul(pred[:, 0], positive_mask, axis=0)
  71. pth = fluid.layers.elementwise_mul(pred[:, 1], positive_mask, axis=0)
  72. prw = fluid.layers.elementwise_mul(pred[:, 2], positive_mask, axis=0)
  73. pbh = fluid.layers.elementwise_mul(pred[:, 3], positive_mask, axis=0)
  74. tlw = fluid.layers.elementwise_mul(targets[:, 0], positive_mask, axis=0)
  75. tth = fluid.layers.elementwise_mul(targets[:, 1], positive_mask, axis=0)
  76. trw = fluid.layers.elementwise_mul(targets[:, 2], positive_mask, axis=0)
  77. tbh = fluid.layers.elementwise_mul(targets[:, 3], positive_mask, axis=0)
  78. tlw.stop_gradient = True
  79. trw.stop_gradient = True
  80. tth.stop_gradient = True
  81. tbh.stop_gradient = True
  82. area_target = (tlw + trw) * (tth + tbh)
  83. area_predict = (plw + prw) * (pth + pbh)
  84. ilw = fluid.layers.elementwise_min(plw, tlw)
  85. irw = fluid.layers.elementwise_min(prw, trw)
  86. ith = fluid.layers.elementwise_min(pth, tth)
  87. ibh = fluid.layers.elementwise_min(pbh, tbh)
  88. clw = fluid.layers.elementwise_max(plw, tlw)
  89. crw = fluid.layers.elementwise_max(prw, trw)
  90. cth = fluid.layers.elementwise_max(pth, tth)
  91. cbh = fluid.layers.elementwise_max(pbh, tbh)
  92. area_inter = (ilw + irw) * (ith + ibh)
  93. ious = (area_inter + 1.0) / (
  94. area_predict + area_target - area_inter + 1.0)
  95. ious = fluid.layers.elementwise_mul(ious, positive_mask, axis=0)
  96. if self.iou_loss_type.lower() == "linear_iou":
  97. loss = 1.0 - ious
  98. elif self.iou_loss_type.lower() == "giou":
  99. area_uniou = area_predict + area_target - area_inter
  100. area_circum = (clw + crw) * (cth + cbh) + 1e-7
  101. giou = ious - (area_circum - area_uniou) / area_circum
  102. loss = 1.0 - giou
  103. elif self.iou_loss_type.lower() == "iou":
  104. loss = 0.0 - fluid.layers.log(ious)
  105. else:
  106. raise KeyError
  107. if weights is not None:
  108. loss = loss * weights
  109. return loss
  110. def __call__(self, cls_logits, bboxes_reg, centerness, tag_labels,
  111. tag_bboxes, tag_center):
  112. """
  113. Calculate the loss for classification, location and centerness
  114. Args:
  115. cls_logits (list): list of Variables, which is predicted
  116. score for all anchor points with shape [N, M, C]
  117. bboxes_reg (list): list of Variables, which is predicted
  118. offsets for all anchor points with shape [N, M, 4]
  119. centerness (list): list of Variables, which is predicted
  120. centerness for all anchor points with shape [N, M, 1]
  121. tag_labels (list): list of Variables, which is category
  122. targets for each anchor point
  123. tag_bboxes (list): list of Variables, which is bounding
  124. boxes targets for positive samples
  125. tag_center (list): list of Variables, which is centerness
  126. targets for positive samples
  127. Return:
  128. loss (dict): loss composed by classification loss, bounding box
  129. """
  130. cls_logits_flatten_list = []
  131. bboxes_reg_flatten_list = []
  132. centerness_flatten_list = []
  133. tag_labels_flatten_list = []
  134. tag_bboxes_flatten_list = []
  135. tag_center_flatten_list = []
  136. num_lvl = len(cls_logits)
  137. for lvl in range(num_lvl):
  138. cls_logits_flatten_list.append(
  139. self.__flatten_tensor(cls_logits[num_lvl - 1 - lvl], True))
  140. bboxes_reg_flatten_list.append(
  141. self.__flatten_tensor(bboxes_reg[num_lvl - 1 - lvl], True))
  142. centerness_flatten_list.append(
  143. self.__flatten_tensor(centerness[num_lvl - 1 - lvl], True))
  144. tag_labels_flatten_list.append(
  145. self.__flatten_tensor(tag_labels[lvl], False))
  146. tag_bboxes_flatten_list.append(
  147. self.__flatten_tensor(tag_bboxes[lvl], False))
  148. tag_center_flatten_list.append(
  149. self.__flatten_tensor(tag_center[lvl], False))
  150. cls_logits_flatten = fluid.layers.concat(
  151. cls_logits_flatten_list, axis=0)
  152. bboxes_reg_flatten = fluid.layers.concat(
  153. bboxes_reg_flatten_list, axis=0)
  154. centerness_flatten = fluid.layers.concat(
  155. centerness_flatten_list, axis=0)
  156. tag_labels_flatten = fluid.layers.concat(
  157. tag_labels_flatten_list, axis=0)
  158. tag_bboxes_flatten = fluid.layers.concat(
  159. tag_bboxes_flatten_list, axis=0)
  160. tag_center_flatten = fluid.layers.concat(
  161. tag_center_flatten_list, axis=0)
  162. tag_labels_flatten.stop_gradient = True
  163. tag_bboxes_flatten.stop_gradient = True
  164. tag_center_flatten.stop_gradient = True
  165. mask_positive = tag_labels_flatten > 0
  166. mask_positive.stop_gradient = True
  167. mask_positive_float = fluid.layers.cast(mask_positive, dtype="float32")
  168. mask_positive_float.stop_gradient = True
  169. num_positive_fp32 = fluid.layers.reduce_sum(mask_positive_float)
  170. num_positive_int32 = fluid.layers.cast(num_positive_fp32, dtype="int32")
  171. num_positive_int32 = num_positive_int32 * 0 + 1
  172. num_positive_fp32.stop_gradient = True
  173. num_positive_int32.stop_gradient = True
  174. normalize_sum = fluid.layers.sum(tag_center_flatten)
  175. normalize_sum.stop_gradient = True
  176. normalize_sum = fluid.layers.reduce_sum(mask_positive_float *
  177. normalize_sum)
  178. normalize_sum.stop_gradient = True
  179. cls_loss = fluid.layers.sigmoid_focal_loss(
  180. cls_logits_flatten, tag_labels_flatten,
  181. num_positive_int32) / num_positive_fp32
  182. reg_loss = self.__iou_loss(bboxes_reg_flatten, tag_bboxes_flatten,
  183. mask_positive_float, tag_center_flatten)
  184. reg_loss = fluid.layers.elementwise_mul(
  185. reg_loss, mask_positive_float, axis=0) / normalize_sum
  186. ctn_loss = fluid.layers.sigmoid_cross_entropy_with_logits(
  187. x=centerness_flatten, label=tag_center_flatten)
  188. ctn_loss = fluid.layers.elementwise_mul(
  189. ctn_loss, mask_positive_float, axis=0) / num_positive_fp32
  190. loss_all = {
  191. "loss_centerness": fluid.layers.reduce_sum(ctn_loss),
  192. "loss_cls": fluid.layers.reduce_sum(cls_loss),
  193. "loss_box": fluid.layers.reduce_sum(reg_loss)
  194. }
  195. return loss_all