Repository: tensorflow/addons

Issue:
 ValueError: Tensor conversion requested dtype float32 for Tensor with dtype uint8 when using losses.SigmoidFocalCrossEntropy
**System information**
- OS Platform and Distribution (e.g., Linux Ubuntu 16.04): Ubuntu 20.04
- TensorFlow version and how it was installed (source or binary): 2.4.0, pip
- TensorFlow-Addons version and how it was installed (source or binary): 0.11.2, pip
- Python version: 3.8
- Is GPU used? (yes/no): yes

```
ValueError: in user code:

    /home/eck/software/anaconda3/envs/hk2/lib/python3.8/site-packages/tensorflow/python/keras/engine/training.py:805 train_function  *
        return step_function(self, iterator)
    /home/eck/software/anaconda3/envs/hk2/lib/python3.8/site-packages/tensorflow_addons/utils/keras_utils.py:61 call  *
        return self.fn(y_true, y_pred, **self._fn_kwargs)
    /home/eck/software/anaconda3/envs/hk2/lib/python3.8/site-packages/tensorflow_addons/losses/focal_loss.py:122 sigmoid_focal_crossentropy  *
        y_true = tf.convert_to_tensor(y_true, dtype=y_pred.dtype)
    /home/eck/software/anaconda3/envs/hk2/lib/python3.8/site-packages/tensorflow/python/util/dispatch.py:201 wrapper  **
        return target(*args, **kwargs)
    /home/eck/software/anaconda3/envs/hk2/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:1404 convert_to_tensor_v2_with_dispatch
        return convert_to_tensor_v2(
    /home/eck/software/anaconda3/envs/hk2/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:1410 convert_to_tensor_v2
        return convert_to_tensor(
    /home/eck/software/anaconda3/envs/hk2/lib/python3.8/site-packages/tensorflow/python/profiler/trace.py:163 wrapped
        return func(*args, **kwargs)
    /home/eck/software/anaconda3/envs/hk2/lib/python3.8/site-packages/tensorflow/python/framework/ops.py:1507 convert_to_tensor
        raise ValueError(

    ValueError: Tensor conversion requested dtype float32 for Tensor with dtype uint8: <tf.Tensor 'y_true:0' shape=(None, None, None, 1) dtype=uint8>
```


When y_true had dtype of uint8 and y_pred had dtype float32, `tf.conver_to_tensor(y_true, y_pred.dtype)` in focal loss function failed.

Is it intended that y_true and y_pred have the same dtype when passed to the loss function? Do I need to convert y_true into float32 tensor in data processing step?







Discussion:
Hi @Crispy13, thanks for the report. That's a bug. It should be `tf.cast(y_true, y_pred.dtype)` instead of `convert_to_tensor`.

Resolving patch:
diff --git a/tensorflow_addons/losses/focal_loss.py b/tensorflow_addons/losses/focal_loss.py
--- a/tensorflow_addons/losses/focal_loss.py
+++ b/tensorflow_addons/losses/focal_loss.py
@@ -112,10 +112,10 @@ def sigmoid_focal_crossentropy(
         same shape as `y_true`; otherwise, it is scalar.
     """
     if gamma and gamma < 0:
-        raise ValueError("Value of gamma should be greater than or equal to zero")
+        raise ValueError("Value of gamma should be greater than or equal to zero.")
 
     y_pred = tf.convert_to_tensor(y_pred)
-    y_true = tf.convert_to_tensor(y_true, dtype=y_pred.dtype)
+    y_true = tf.cast(y_true, dtype=y_pred.dtype)
 
     # Get the cross_entropy for each entry
     ce = K.binary_crossentropy(y_true, y_pred, from_logits=from_logits)
@@ -131,11 +131,11 @@ def sigmoid_focal_crossentropy(
     modulating_factor = 1.0
 
     if alpha:
-        alpha = tf.convert_to_tensor(alpha, dtype=K.floatx())
+        alpha = tf.cast(alpha, dtype=y_true.dtype)
         alpha_factor = y_true * alpha + (1 - y_true) * (1 - alpha)
 
     if gamma:
-        gamma = tf.convert_to_tensor(gamma, dtype=K.floatx())
+        gamma = tf.cast(gamma, dtype=y_true.dtype)
         modulating_factor = tf.pow((1.0 - p_t), gamma)
 
     # compute the final loss and return


Test patch:
diff --git a/tensorflow_addons/losses/tests/focal_loss_test.py b/tensorflow_addons/losses/tests/focal_loss_test.py
--- a/tensorflow_addons/losses/tests/focal_loss_test.py
+++ b/tensorflow_addons/losses/tests/focal_loss_test.py
@@ -18,73 +18,18 @@
 import pytest
 import numpy as np
 import tensorflow as tf
-import tensorflow.keras.backend as K
-from tensorflow_addons.losses import (
-    sigmoid_focal_crossentropy,
-    SigmoidFocalCrossEntropy,
-)
+
+from tensorflow_addons.losses import focal_loss
 
 
 def test_config():
-    bce_obj = SigmoidFocalCrossEntropy(
+    bce_obj = focal_loss.SigmoidFocalCrossEntropy(
         reduction=tf.keras.losses.Reduction.NONE, name="sigmoid_focal_crossentropy"
     )
     assert bce_obj.name == "sigmoid_focal_crossentropy"
     assert bce_obj.reduction == tf.keras.losses.Reduction.NONE
 
 
-def to_logit(prob):
-    logit = np.log(prob / (1.0 - prob))
-    return logit
-
-
-# Test with logits
-def test_with_logits():
-    # predictiions represented as logits
-    prediction_tensor = tf.constant(
-        [
-            [to_logit(0.97)],
-            [to_logit(0.91)],
-            [to_logit(0.73)],
-            [to_logit(0.27)],
-            [to_logit(0.09)],
-            [to_logit(0.03)],
-        ],
-        tf.float32,
-    )
-    # Ground truth
-    target_tensor = tf.constant([[1], [1], [1], [0], [0], [0]], tf.float32)
-
-    fl = sigmoid_focal_crossentropy(
-        y_true=target_tensor,
-        y_pred=prediction_tensor,
-        from_logits=True,
-        alpha=None,
-        gamma=None,
-    )
-    bce = tf.reduce_sum(
-        K.binary_crossentropy(target_tensor, prediction_tensor, from_logits=True),
-        axis=-1,
-    )
-
-    # When alpha and gamma are None, it should be equal to BCE
-    np.testing.assert_allclose(fl, bce)
-
-    # When gamma==2.0
-    fl = sigmoid_focal_crossentropy(
-        y_true=target_tensor,
-        y_pred=prediction_tensor,
-        from_logits=True,
-        alpha=None,
-        gamma=2.0,
-    )
-
-    # order_of_ratio = np.power(10, np.floor(np.log10(bce/FL)))
-    order_of_ratio = tf.pow(10.0, tf.math.floor(log10(bce / fl)))
-    pow_values = tf.constant([1000, 100, 10, 10, 100, 1000])
-    np.testing.assert_allclose(order_of_ratio, pow_values)
-
-
 def test_keras_model_compile():
     model = tf.keras.models.Sequential(
         [
@@ -95,37 +40,31 @@ def test_keras_model_compile():
     model.compile(loss="Addons>sigmoid_focal_crossentropy")
 
 
-def log10(x):
-    numerator = tf.math.log(x)
-    denominator = tf.math.log(tf.constant(10, dtype=numerator.dtype))
-    return numerator / denominator
-
-
-# Test without logits
 @pytest.mark.usefixtures("maybe_run_functions_eagerly")
-def test_without_logits():
-    # predictiions represented as logits
-    prediction_tensor = tf.constant(
-        [[0.97], [0.91], [0.73], [0.27], [0.09], [0.03]], tf.float32
-    )
-    # Ground truth
-    target_tensor = tf.constant([[1], [1], [1], [0], [0], [0]], tf.float32)
-
-    fl = sigmoid_focal_crossentropy(
-        y_true=target_tensor, y_pred=prediction_tensor, alpha=None, gamma=None
-    )
-    bce = tf.reduce_sum(
-        K.binary_crossentropy(target_tensor, prediction_tensor), axis=-1
-    )
-
-    # When alpha and gamma are None, it should be equal to BCE
-    assert np.allclose(fl, bce)
-
-    # When gamma==2.0
-    fl = sigmoid_focal_crossentropy(
-        y_true=target_tensor, y_pred=prediction_tensor, alpha=None, gamma=2.0
+@pytest.mark.parametrize("y_pred_dtype", [np.float16, np.float32, np.float64])
+@pytest.mark.parametrize("y_true_dtype", [np.float32, np.uint8])
+@pytest.mark.parametrize("from_logits", [True, False])
+def test_without_logits(y_pred_dtype, y_true_dtype, from_logits):
+    y_pred = np.asarray([[0.97], [0.91], [0.73], [0.27], [0.09], [0.03]]).astype(
+        y_pred_dtype
     )
+    y_true = np.asarray([[1], [1], [1], [0], [0], [0]]).astype(y_true_dtype)
+    if from_logits:
+        y_pred = np.log(y_pred / (1.0 - y_pred))
+
+    # When alpha and gamma are None, the result is equal to BCE.
+    fl = focal_loss.sigmoid_focal_crossentropy(
+        y_true=y_true, y_pred=y_pred, alpha=None, gamma=None, from_logits=from_logits
+    ).numpy()
+    bce = tf.keras.losses.binary_crossentropy(
+        y_true, y_pred, from_logits=from_logits
+    ).numpy()
+    np.testing.assert_allclose(fl, bce)
 
-    order_of_ratio = tf.pow(10.0, tf.math.floor(log10(bce / fl)))
-    pow_values = tf.constant([1000, 100, 10, 10, 100, 1000])
-    assert np.allclose(order_of_ratio, pow_values)
+    # When gamma is 2.0.
+    fl = focal_loss.sigmoid_focal_crossentropy(
+        y_true=y_true, y_pred=y_pred, alpha=None, gamma=2.0, from_logits=from_logits
+    ).numpy()
+    order_of_ratio = np.power(10.0, np.floor(np.log10(bce / fl)))
+    pow_values = np.asarray([1000, 100, 10, 10, 100, 1000])
+    np.testing.assert_allclose(order_of_ratio, pow_values)