Code Duplication    Length = 98-98 lines in 2 locations

test/unit/test_loss_label.py 2 locations

@@ 214-311 (lines=98) @@
211
        assert got == expected
212
213
214
class TestJaccardIndex:
215
    @pytest.mark.parametrize(
216
        ("value", "smooth_nr", "smooth_dr", "expected"),
217
        [
218
            (0, 1e-5, 1e-5, 1),
219
            (0, 0, 1e-5, 0),
220
            (0, 1e-5, 0, np.inf),
221
            (0, 0, 0, np.nan),
222
            (0, 1e-7, 1e-7, 1),
223
            (1, 1e-5, 1e-5, 1),
224
            (1, 0, 1e-5, 1),
225
            (1, 1e-5, 0, 1),
226
            (1, 0, 0, 1),
227
            (1, 1e-7, 1e-7, 1),
228
        ],
229
    )
230
    def test_smooth(
231
        self,
232
        value: float,
233
        smooth_nr: float,
234
        smooth_dr: float,
235
        expected: float,
236
    ):
237
        """
238
        Test values in extreme cases where numerator/denominator are all zero.
239
240
        :param value: value for input.
241
        :param smooth_nr: constant for numerator.
242
        :param smooth_dr: constant for denominator.
243
        :param expected: target value.
244
        """
245
        shape = (1, 10)
246
        y_true = tf.ones(shape=shape) * value
247
        y_pred = tf.ones(shape=shape) * value
248
249
        got = label.JaccardIndex(smooth_nr=smooth_nr, smooth_dr=smooth_dr)._call(
250
            y_true,
251
            y_pred,
252
        )
253
        expected = tf.constant(expected)
254
        assert is_equal_tf(got[0], expected)
255
256
    @pytest.mark.parametrize("binary", [True, False])
257
    @pytest.mark.parametrize("background_weight", [0.0, 0.1, 0.5, 1.0])
258
    @pytest.mark.parametrize("shape", [(1,), (10,), (100,), (2, 3), (2, 3, 4)])
259
    def test_exact_value(self, binary: bool, background_weight: float, shape: Tuple):
260
        """
261
        Test Jaccard index by comparing at ground truth values.
262
263
        :param binary: if project labels to binary values.
264
        :param background_weight: the weight of background class.
265
        :param shape: shape of input.
266
        """
267
        # init
268
        shape = (1,) + shape  # add batch axis
269
        foreground_weight = 1 - background_weight
270
        tf.random.set_seed(0)
271
        y_true = tf.random.uniform(shape=shape)
272
        y_pred = tf.random.uniform(shape=shape)
273
274
        # obtained value
275
        got = label.JaccardIndex(
276
            binary=binary,
277
            background_weight=background_weight,
278
        ).call(y_true=y_true, y_pred=y_pred)
279
280
        # expected value
281
        flatten = tf.keras.layers.Flatten()
282
        y_true = flatten(y_true)
283
        y_pred = flatten(y_pred)
284
        if binary:
285
            y_true = tf.cast(y_true >= 0.5, dtype=y_true.dtype)
286
            y_pred = tf.cast(y_pred >= 0.5, dtype=y_pred.dtype)
287
288
        num = foreground_weight * tf.reduce_sum(
289
            y_true * y_pred, axis=1
290
        ) + background_weight * tf.reduce_sum((1 - y_true) * (1 - y_pred), axis=1)
291
        denom = foreground_weight * tf.reduce_sum(
292
            y_true + y_pred, axis=1
293
        ) + background_weight * tf.reduce_sum((1 - y_true) + (1 - y_pred), axis=1)
294
        denom = denom - num
295
        expected = (num + EPS) / (denom + EPS)
296
297
        assert is_equal_tf(got, expected)
298
299
    def test_get_config(self):
300
        got = label.JaccardIndex().get_config()
301
        expected = dict(
302
            binary=False,
303
            background_weight=0.0,
304
            smooth_nr=1e-5,
305
            smooth_dr=1e-5,
306
            scales=None,
307
            kernel="gaussian",
308
            reduction=tf.keras.losses.Reduction.SUM,
309
            name="JaccardIndex",
310
        )
311
        assert got == expected
312
313
314
def test_foreground_prop_binary():
@@ 37-134 (lines=98) @@
34
        assert got == expected
35
36
37
class TestDiceScore:
38
    @pytest.mark.parametrize(
39
        ("value", "smooth_nr", "smooth_dr", "expected"),
40
        [
41
            (0, 1e-5, 1e-5, 1),
42
            (0, 0, 1e-5, 0),
43
            (0, 1e-5, 0, np.inf),
44
            (0, 0, 0, np.nan),
45
            (0, 1e-7, 1e-7, 1),
46
            (1, 1e-5, 1e-5, 1),
47
            (1, 0, 1e-5, 1),
48
            (1, 1e-5, 0, 1),
49
            (1, 0, 0, 1),
50
            (1, 1e-7, 1e-7, 1),
51
        ],
52
    )
53
    def test_smooth(
54
        self,
55
        value: float,
56
        smooth_nr: float,
57
        smooth_dr: float,
58
        expected: float,
59
    ):
60
        """
61
        Test values in extreme cases where numerator/denominator are all zero.
62
63
        :param value: value for input.
64
        :param smooth_nr: constant for numerator.
65
        :param smooth_dr: constant for denominator.
66
        :param expected: target value.
67
        """
68
        shape = (1, 10)
69
        y_true = tf.ones(shape=shape) * value
70
        y_pred = tf.ones(shape=shape) * value
71
72
        got = label.DiceScore(smooth_nr=smooth_nr, smooth_dr=smooth_dr)._call(
73
            y_true,
74
            y_pred,
75
        )
76
        expected = tf.constant(expected)
77
        assert is_equal_tf(got[0], expected)
78
79
    @pytest.mark.parametrize("binary", [True, False])
80
    @pytest.mark.parametrize("background_weight", [0.0, 0.1, 0.5, 1.0])
81
    @pytest.mark.parametrize("shape", [(1,), (10,), (100,), (2, 3), (2, 3, 4)])
82
    def test_exact_value(self, binary: bool, background_weight: float, shape: Tuple):
83
        """
84
        Test dice score by comparing at ground truth values.
85
86
        :param binary: if project labels to binary values.
87
        :param background_weight: the weight of background class.
88
        :param shape: shape of input.
89
        """
90
        # init
91
        shape = (1,) + shape  # add batch axis
92
        foreground_weight = 1 - background_weight
93
        tf.random.set_seed(0)
94
        y_true = tf.random.uniform(shape=shape)
95
        y_pred = tf.random.uniform(shape=shape)
96
97
        # obtained value
98
        got = label.DiceScore(
99
            binary=binary,
100
            background_weight=background_weight,
101
        ).call(y_true=y_true, y_pred=y_pred)
102
103
        # expected value
104
        flatten = tf.keras.layers.Flatten()
105
        y_true = flatten(y_true)
106
        y_pred = flatten(y_pred)
107
        if binary:
108
            y_true = tf.cast(y_true >= 0.5, dtype=y_true.dtype)
109
            y_pred = tf.cast(y_pred >= 0.5, dtype=y_pred.dtype)
110
111
        num = foreground_weight * tf.reduce_sum(
112
            y_true * y_pred, axis=1
113
        ) + background_weight * tf.reduce_sum((1 - y_true) * (1 - y_pred), axis=1)
114
        num *= 2
115
        denom = foreground_weight * tf.reduce_sum(
116
            y_true + y_pred, axis=1
117
        ) + background_weight * tf.reduce_sum((1 - y_true) + (1 - y_pred), axis=1)
118
        expected = (num + EPS) / (denom + EPS)
119
120
        assert is_equal_tf(got, expected)
121
122
    def test_get_config(self):
123
        got = label.DiceScore().get_config()
124
        expected = dict(
125
            binary=False,
126
            background_weight=0.0,
127
            smooth_nr=1e-5,
128
            smooth_dr=1e-5,
129
            scales=None,
130
            kernel="gaussian",
131
            reduction=tf.keras.losses.Reduction.SUM,
132
            name="DiceScore",
133
        )
134
        assert got == expected
135
136
137
class TestCrossEntropy: