def test_smooth( self, value: float, smooth_nr: float, smooth_dr: float, expected: float, ): """ Test values in extreme cases where numerator/denominator are all zero. :param value: value for input. :param smooth_nr: constant for numerator. :param smooth_dr: constant for denominator. :param expected: target value. """ shape = (1, 10) y_true = tf.ones(shape=shape) * value y_pred = tf.ones(shape=shape) * value got = label.DiceScore(smooth_nr=smooth_nr, smooth_dr=smooth_dr).call( y_true, y_pred, ) expected = tf.constant(expected) assert is_equal_tf(got[0], expected)
def test_background_weight_err(self, background_weight: float): """ Test the error message when using wrong background weight. :param background_weight: weight for background class. """ with pytest.raises(ValueError) as err_info: label.DiceScore(background_weight=background_weight) assert "The background weight for Dice Score must be within [0, 1]" in str( err_info.value)
def test_get_config(self): got = label.DiceScore().get_config() expected = dict( binary=False, neg_weight=0.0, scales=None, kernel="gaussian", reduction=tf.keras.losses.Reduction.SUM, name="DiceScore", ) assert got == expected
def test_call(self, y_true, y_pred, binary, neg_weight, scales, expected): expected = np.array([expected] * self.shape[0]) # call returns (batch, ) got = label.DiceScore(binary=binary, neg_weight=neg_weight, scales=scales).call(y_true=y_true, y_pred=y_pred) assert is_equal_tf(got, expected) got = label.DiceLoss(binary=binary, neg_weight=neg_weight, scales=scales).call(y_true=y_true, y_pred=y_pred) assert is_equal_tf(got, -expected)
def test_get_config(self): got = label.DiceScore().get_config() expected = dict( binary=False, background_weight=0.0, smooth_nr=1e-5, smooth_dr=1e-5, reduction=tf.keras.losses.Reduction.AUTO, name="DiceScore", ) assert got == expected
def calculate_metrics( fixed_image: tf.Tensor, fixed_label: (tf.Tensor, None), pred_fixed_image: (tf.Tensor, None), pred_fixed_label: (tf.Tensor, None), fixed_grid_ref: tf.Tensor, sample_index: int, ) -> dict: """ Calculate image/label based metrics. :param fixed_image: shape=(batch, f_dim1, f_dim2, f_dim3) :param fixed_label: shape=(batch, f_dim1, f_dim2, f_dim3) or None :param pred_fixed_image: shape=(batch, f_dim1, f_dim2, f_dim3) :param pred_fixed_label: shape=(batch, f_dim1, f_dim2, f_dim3) or None :param fixed_grid_ref: shape=(1, f_dim1, f_dim2, f_dim3, 3) :param sample_index: int, :return: dictionary of metrics """ if pred_fixed_image is not None: y_true = fixed_image[sample_index:(sample_index + 1), :, :, :] y_pred = pred_fixed_image[sample_index:(sample_index + 1), :, :, :] y_true = tf.expand_dims(y_true, axis=4) y_pred = tf.expand_dims(y_pred, axis=4) ssd = image_loss.SumSquaredDifference()(y_true=y_true, y_pred=y_pred).numpy() else: ssd = None if fixed_label is not None and pred_fixed_label is not None: y_true = fixed_label[sample_index:(sample_index + 1), :, :, :] y_pred = pred_fixed_label[sample_index:(sample_index + 1), :, :, :] dice = label_loss.DiceScore(binary=True)(y_true=y_true, y_pred=y_pred).numpy() tre = label_loss.compute_centroid_distance( y_true=y_true, y_pred=y_pred, grid=fixed_grid_ref[0, :, :, :, :]).numpy()[0] else: dice = None tre = None return dict(image_ssd=ssd, label_binary_dice=dice, label_tre=tre)
def test_exact_value(self, binary: bool, background_weight: float, shape: Tuple): """ Test dice score by comparing at ground truth values. :param binary: if project labels to binary values. :param background_weight: the weight of background class. :param shape: shape of input. """ # init shape = (1, ) + shape # add batch axis foreground_weight = 1 - background_weight tf.random.set_seed(0) y_true = tf.random.uniform(shape=shape) y_pred = tf.random.uniform(shape=shape) # obtained value got = label.DiceScore( binary=binary, background_weight=background_weight, ).call(y_true=y_true, y_pred=y_pred) # expected value flatten = tf.keras.layers.Flatten() y_true = flatten(y_true) y_pred = flatten(y_pred) if binary: y_true = tf.cast(y_true >= 0.5, dtype=y_true.dtype) y_pred = tf.cast(y_pred >= 0.5, dtype=y_pred.dtype) num = foreground_weight * tf.reduce_sum( y_true * y_pred, axis=1) + background_weight * tf.reduce_sum( (1 - y_true) * (1 - y_pred), axis=1) num *= 2 denom = foreground_weight * tf.reduce_sum( y_true + y_pred, axis=1) + background_weight * tf.reduce_sum( (1 - y_true) + (1 - y_pred), axis=1) expected = (num + EPS) / (denom + EPS) assert is_equal_tf(got, expected)