Repository: tensorflow/addons

Issue:
RSquare TypeError: tf__update_state() got an unexpected keyword argument 'sample_weight'
**System information**
- OS Platform and Distribution (e.g., Linux Ubuntu 16.04):  ubuntu 18.04
- TensorFlow version and how it was installed (source or binary): 2.1.0  binary (conda)
- TensorFlow-Addons version and how it was installed (source or binary): 0.8.3 binary(pip)
- Python version:  3.7.6
- Is GPU used? (yes/no): yes

**Describe the bug**

The code goes wrong when I add "tfa.metrics.RSquare(dtype=tf.float32)" to model metrics.
The exception is  "TypeError: tf__update_state() got an unexpected keyword argument 'sample_weight'"

And I don't see "sample_weight" parameter , what been added shown in #564 , of update_state() function in class RSquare in addons version 0.8.3.

Are there something wrong with my installed tensorflow and addons package?


**Code to reproduce the issue**

Usage in my code:
``` python
model.compile(
        loss='mse',
        optimizer=optimizer,
        metrics=['mae', 'mse', tfa.metrics.RSquare(dtype=tf.float32)]
    )
```

**Other info / logs**

Include any logs or source code that would be helpful to diagnose the problem. If including tracebacks, please include the full traceback. Large logs and files should be attached.



Discussion:
@lotest #564 was not merged, that's why you don't see `sample_weight` being available. The problem here is that some of the metrics in TFA do not take a `sample_weight` argument because they don't use it. It's a problem though because Keras will automatically pass sample weights when the user declare them.  A good fix would be to add `sample_weights` in all metrics and enforce that the argument is present. And if the tensor is not used during the computation, then just raise a warning.

This is linked to #992 , we lack some unified tests. This will become easier once we switch to pytest for testing.

Resolving patch:
diff --git a/tensorflow_addons/metrics/multilabel_confusion_matrix.py b/tensorflow_addons/metrics/multilabel_confusion_matrix.py
--- a/tensorflow_addons/metrics/multilabel_confusion_matrix.py
+++ b/tensorflow_addons/metrics/multilabel_confusion_matrix.py
@@ -14,6 +14,8 @@
 # ==============================================================================
 """Implements Multi-label confusion matrix scores."""
 
+import warnings
+
 import tensorflow as tf
 from tensorflow.keras.metrics import Metric
 import numpy as np
@@ -104,7 +106,14 @@ def __init__(
             dtype=self.dtype,
         )
 
-    def update_state(self, y_true, y_pred):
+    def update_state(self, y_true, y_pred, sample_weight=None):
+        if sample_weight is not None:
+            warnings.warn(
+                "`sample_weight` is not None. Be aware that MultiLabelConfusionMatrix "
+                "does not take `sample_weight` into account when computing the metric "
+                "value."
+            )
+
         y_true = tf.cast(y_true, tf.int32)
         y_pred = tf.cast(y_pred, tf.int32)
         # true positive
diff --git a/tensorflow_addons/metrics/r_square.py b/tensorflow_addons/metrics/r_square.py
--- a/tensorflow_addons/metrics/r_square.py
+++ b/tensorflow_addons/metrics/r_square.py
@@ -14,6 +14,8 @@
 # ==============================================================================
 """Implements R^2 scores."""
 
+import warnings
+
 import tensorflow as tf
 from tensorflow.keras.metrics import Metric
 
@@ -53,7 +55,13 @@ def __init__(
         self.res = self.add_weight("residual", initializer="zeros")
         self.count = self.add_weight("count", initializer="zeros")
 
-    def update_state(self, y_true, y_pred):
+    def update_state(self, y_true, y_pred, sample_weight=None):
+        if sample_weight is not None:
+            warnings.warn(
+                "`sample_weight` is not None. Be aware that RSquare "
+                "does not take `sample_weight` into account when computing the metric "
+                "value."
+            )
         y_true = tf.convert_to_tensor(y_true, tf.float32)
         y_pred = tf.convert_to_tensor(y_pred, tf.float32)
         self.squared_sum.assign_add(tf.reduce_sum(y_true ** 2))


Test patch:
diff --git a/tensorflow_addons/metrics/metrics_test.py b/tensorflow_addons/metrics/metrics_test.py
new file mode 100644
--- /dev/null
+++ b/tensorflow_addons/metrics/metrics_test.py
@@ -0,0 +1,42 @@
+# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+# ==============================================================================
+import unittest
+import inspect
+
+from tensorflow.keras.metrics import Metric
+from tensorflow_addons import metrics
+
+
+class MetricsTests(unittest.TestCase):
+    def test_update_state_signature(self):
+        for name, obj in inspect.getmembers(metrics):
+            if inspect.isclass(obj) and issubclass(obj, Metric):
+                check_update_state_signature(obj)
+
+
+def check_update_state_signature(metric_class):
+    update_state_signature = inspect.signature(metric_class.update_state)
+    for expected_parameter in ["y_true", "y_pred", "sample_weight"]:
+        if expected_parameter not in update_state_signature.parameters.keys():
+            raise ValueError(
+                "Class {} is missing the parameter {} in the `update_state` "
+                "method. If the method doesn't use this argument, declare "
+                "it anyway and raise a UserWarning if it is "
+                "not None.".format(metric_class.__name__, expected_parameter)
+            )
+
+
+if __name__ == "__main__":
+    unittest.main()