Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow_addons/losses/giou_loss.py: 25%

51 statements  

« prev     ^ index     » next       coverage.py v7.4.0, created at 2024-01-03 07:57 +0000

1# Copyright 2019 The TensorFlow 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# ============================================================================== 

15"""Implements GIoU loss.""" 

16 

17from typing import Optional 

18 

19import tensorflow as tf 

20from typeguard import typechecked 

21 

22from tensorflow_addons.utils.keras_utils import LossFunctionWrapper 

23from tensorflow_addons.utils.types import TensorLike 

24 

25 

26@tf.keras.utils.register_keras_serializable(package="Addons") 

27class GIoULoss(LossFunctionWrapper): 

28 """Implements the GIoU loss function. 

29 

30 GIoU loss was first introduced in the 

31 [Generalized Intersection over Union: 

32 A Metric and A Loss for Bounding Box Regression] 

33 (https://giou.stanford.edu/GIoU.pdf). 

34 GIoU is an enhancement for models which use IoU in object detection. 

35 

36 Usage: 

37 

38 >>> gl = tfa.losses.GIoULoss() 

39 >>> boxes1 = tf.constant([[4.0, 3.0, 7.0, 5.0], [5.0, 6.0, 10.0, 7.0]]) 

40 >>> boxes2 = tf.constant([[3.0, 4.0, 6.0, 8.0], [14.0, 14.0, 15.0, 15.0]]) 

41 >>> loss = gl(boxes1, boxes2) 

42 >>> loss 

43 <tf.Tensor: shape=(), dtype=float32, numpy=1.5041667> 

44 

45 Usage with `tf.keras` API: 

46 

47 >>> model = tf.keras.Model() 

48 >>> model.compile('sgd', loss=tfa.losses.GIoULoss()) 

49 

50 Args: 

51 mode: one of ['giou', 'iou'], decided to calculate GIoU or IoU loss. 

52 """ 

53 

54 @typechecked 

55 def __init__( 

56 self, 

57 mode: str = "giou", 

58 reduction: str = tf.keras.losses.Reduction.AUTO, 

59 name: Optional[str] = "giou_loss", 

60 ): 

61 super().__init__(giou_loss, name=name, reduction=reduction, mode=mode) 

62 

63 

64@tf.keras.utils.register_keras_serializable(package="Addons") 

65def giou_loss(y_true: TensorLike, y_pred: TensorLike, mode: str = "giou") -> tf.Tensor: 

66 """Implements the GIoU loss function. 

67 

68 GIoU loss was first introduced in the 

69 [Generalized Intersection over Union: 

70 A Metric and A Loss for Bounding Box Regression] 

71 (https://giou.stanford.edu/GIoU.pdf). 

72 GIoU is an enhancement for models which use IoU in object detection. 

73 

74 Args: 

75 y_true: true targets tensor. The coordinates of the each bounding 

76 box in boxes are encoded as [y_min, x_min, y_max, x_max]. 

77 y_pred: predictions tensor. The coordinates of the each bounding 

78 box in boxes are encoded as [y_min, x_min, y_max, x_max]. 

79 mode: one of ['giou', 'iou'], decided to calculate GIoU or IoU loss. 

80 

81 Returns: 

82 GIoU loss float `Tensor`. 

83 """ 

84 if mode not in ["giou", "iou"]: 

85 raise ValueError("Value of mode should be 'iou' or 'giou'") 

86 y_pred = tf.convert_to_tensor(y_pred) 

87 if not y_pred.dtype.is_floating: 

88 y_pred = tf.cast(y_pred, tf.float32) 

89 y_true = tf.cast(y_true, y_pred.dtype) 

90 giou = tf.squeeze(_calculate_giou(y_pred, y_true, mode)) 

91 

92 return 1 - giou 

93 

94 

95def _calculate_giou(b1: TensorLike, b2: TensorLike, mode: str = "giou") -> tf.Tensor: 

96 """ 

97 Args: 

98 b1: bounding box. The coordinates of the each bounding box in boxes are 

99 encoded as [y_min, x_min, y_max, x_max]. 

100 b2: the other bounding box. The coordinates of the each bounding box 

101 in boxes are encoded as [y_min, x_min, y_max, x_max]. 

102 mode: one of ['giou', 'iou'], decided to calculate GIoU or IoU loss. 

103 

104 Returns: 

105 GIoU loss float `Tensor`. 

106 """ 

107 zero = tf.convert_to_tensor(0.0, b1.dtype) 

108 b1_ymin, b1_xmin, b1_ymax, b1_xmax = tf.unstack(b1, 4, axis=-1) 

109 b2_ymin, b2_xmin, b2_ymax, b2_xmax = tf.unstack(b2, 4, axis=-1) 

110 b1_width = tf.maximum(zero, b1_xmax - b1_xmin) 

111 b1_height = tf.maximum(zero, b1_ymax - b1_ymin) 

112 b2_width = tf.maximum(zero, b2_xmax - b2_xmin) 

113 b2_height = tf.maximum(zero, b2_ymax - b2_ymin) 

114 b1_area = b1_width * b1_height 

115 b2_area = b2_width * b2_height 

116 

117 intersect_ymin = tf.maximum(b1_ymin, b2_ymin) 

118 intersect_xmin = tf.maximum(b1_xmin, b2_xmin) 

119 intersect_ymax = tf.minimum(b1_ymax, b2_ymax) 

120 intersect_xmax = tf.minimum(b1_xmax, b2_xmax) 

121 intersect_width = tf.maximum(zero, intersect_xmax - intersect_xmin) 

122 intersect_height = tf.maximum(zero, intersect_ymax - intersect_ymin) 

123 intersect_area = intersect_width * intersect_height 

124 

125 union_area = b1_area + b2_area - intersect_area 

126 iou = tf.math.divide_no_nan(intersect_area, union_area) 

127 if mode == "iou": 

128 return iou 

129 

130 enclose_ymin = tf.minimum(b1_ymin, b2_ymin) 

131 enclose_xmin = tf.minimum(b1_xmin, b2_xmin) 

132 enclose_ymax = tf.maximum(b1_ymax, b2_ymax) 

133 enclose_xmax = tf.maximum(b1_xmax, b2_xmax) 

134 enclose_width = tf.maximum(zero, enclose_xmax - enclose_xmin) 

135 enclose_height = tf.maximum(zero, enclose_ymax - enclose_ymin) 

136 enclose_area = enclose_width * enclose_height 

137 giou = iou - tf.math.divide_no_nan((enclose_area - union_area), enclose_area) 

138 return giou