fcos_loss.py 8.8 KB

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