Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/tensorflow_addons/metrics/hamming.py: 38%

29 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 Hamming distance and loss.""" 

16 

17import tensorflow as tf 

18from tensorflow_addons.metrics.utils import MeanMetricWrapper 

19from tensorflow_addons.utils.types import FloatTensorLike, TensorLike, AcceptableDTypes 

20 

21from typeguard import typechecked 

22from typing import Union, Optional 

23 

24 

25def hamming_distance(actuals: TensorLike, predictions: TensorLike) -> tf.Tensor: 

26 """Computes hamming distance. 

27 

28 Hamming distance is for comparing two binary strings. 

29 It is the number of bit positions in which two bits 

30 are different. 

31 

32 Args: 

33 actuals: actual target value. 

34 predictions: predicted value. 

35 

36 Returns: 

37 hamming distance: float. 

38 

39 Usage: 

40 

41 >>> y_true = np.array([1, 1, 0, 0, 1, 0, 1, 0, 0, 1], dtype=np.int32) 

42 >>> y_pred = np.array([1, 0, 0, 0, 1, 0, 0, 1, 0, 1], dtype=np.int32) 

43 >>> hamming_distance(y_true, y_pred).numpy() 

44 0.3 

45 

46 """ 

47 result = tf.not_equal(actuals, predictions) 

48 not_eq = tf.reduce_sum(tf.cast(result, tf.float32)) 

49 ham_distance = tf.math.divide_no_nan(not_eq, len(result)) 

50 return ham_distance 

51 

52 

53def hamming_loss_fn( 

54 y_true: TensorLike, 

55 y_pred: TensorLike, 

56 threshold: Union[FloatTensorLike, None], 

57 mode: str, 

58) -> tf.Tensor: 

59 """Computes hamming loss. 

60 

61 Hamming loss is the fraction of wrong labels to the total number 

62 of labels. 

63 

64 In multi-class classification, hamming loss is calculated as the 

65 hamming distance between `y_true` and `y_pred`. 

66 In multi-label classification, hamming loss penalizes only the 

67 individual labels. 

68 

69 Args: 

70 y_true: actual target value. 

71 y_pred: predicted target value. 

72 threshold: Elements of `y_pred` greater than threshold are 

73 converted to be 1, and the rest 0. If threshold is 

74 None, the argmax is converted to 1, and the rest 0. 

75 mode: multi-class or multi-label. 

76 

77 Returns: 

78 hamming loss: float. 

79 """ 

80 if mode not in ["multiclass", "multilabel"]: 

81 raise TypeError("mode must be either multiclass or multilabel]") 

82 

83 if threshold is None: 

84 threshold = tf.reduce_max(y_pred, axis=-1, keepdims=True) 

85 # make sure [0, 0, 0] doesn't become [1, 1, 1] 

86 # Use abs(x) > eps, instead of x != 0 to check for zero 

87 y_pred = tf.logical_and(y_pred >= threshold, tf.abs(y_pred) > 1e-12) 

88 else: 

89 y_pred = y_pred > threshold 

90 

91 y_true = tf.cast(y_true, tf.int32) 

92 y_pred = tf.cast(y_pred, tf.int32) 

93 

94 if mode == "multiclass": 

95 nonzero = tf.cast(tf.math.count_nonzero(y_true * y_pred, axis=-1), tf.float32) 

96 return 1.0 - nonzero 

97 

98 else: 

99 nonzero = tf.cast(tf.math.count_nonzero(y_true - y_pred, axis=-1), tf.float32) 

100 return nonzero / y_true.get_shape()[-1] 

101 

102 

103class HammingLoss(MeanMetricWrapper): 

104 """Computes hamming loss. 

105 

106 Hamming loss is the fraction of wrong labels to the total number 

107 of labels. 

108 

109 In multi-class classification, hamming loss is calculated as the 

110 hamming distance between `y_true` and `y_pred`. 

111 In multi-label classification, hamming loss penalizes only the 

112 individual labels. 

113 

114 Args: 

115 threshold: Elements of `y_pred` greater than threshold are 

116 converted to be 1, and the rest 0. If threshold is 

117 None, the argmax is converted to 1, and the rest 0. 

118 mode: multi-class or multi-label. 

119 name: (Optional) string name of the metric instance. 

120 dtype: (Optional) data type of the metric result. 

121 

122 Usage: 

123 

124 >>> # multi-class hamming loss 

125 >>> metric = HammingLoss(mode='multiclass', threshold=0.6) 

126 >>> y_true = np.array([[1.0, 0.0, 0.0, 0.0], 

127 ... [0.0, 0.0, 1.0, 0.0], 

128 ... [0.0, 0.0, 0.0, 1.0], 

129 ... [0.0, 1.0, 0.0, 0.0]], dtype=np.float32) 

130 >>> y_pred = np.array([[0.8, 0.1, 0.1, 0.0], 

131 ... [0.2, 0.0, 0.8, 0.0], 

132 ... [0.05, 0.05, 0.1, 0.8], 

133 ... [1.0, 0.0, 0.0, 0.0]], dtype=np.float32) 

134 >>> metric.update_state(y_true, y_pred) 

135 <tf.Variable 'UnreadVariable' shape=() dtype=float32, numpy=4.0> 

136 >>> metric.result().numpy() 

137 0.25 

138 >>> # multi-label hamming loss 

139 >>> metric = HammingLoss(mode='multilabel', threshold=0.8) 

140 >>> y_true = np.array([[1, 0, 1, 0], 

141 ... [0, 1, 0, 1], 

142 ... [0, 0, 0, 1]], dtype=np.int32) 

143 >>> y_pred = np.array([[0.82, 0.5, 0.90, 0], 

144 ... [0, 1, 0.4, 0.98], 

145 ... [0.89, 0.79, 0, 0.3]], dtype=np.float32) 

146 >>> metric.update_state(y_true, y_pred) 

147 <tf.Variable 'UnreadVariable' shape=() dtype=float32, numpy=3.0> 

148 >>> metric.result().numpy() 

149 0.16666667 

150 """ 

151 

152 @typechecked 

153 def __init__( 

154 self, 

155 mode: str, 

156 name: str = "hamming_loss", 

157 threshold: Optional[FloatTensorLike] = None, 

158 dtype: AcceptableDTypes = None, 

159 **kwargs, 

160 ): 

161 super().__init__( 

162 hamming_loss_fn, name=name, dtype=dtype, mode=mode, threshold=threshold 

163 )