From cb1358d9ffc6fc68d4d3ce498e39b6751a4ee817 Mon Sep 17 00:00:00 2001 From: "A. Unique TensorFlower" Date: Wed, 26 Feb 2020 14:46:05 -0800 Subject: [PATCH] Implement RecallAtPrecision metric (in analogy to PrecisionAtRecall). There are two differences: * Since precision is not monotonous function of recall, there might be multiple operating ranges with the required precision - the point with the maximal recall is selected. * For some score-label-distributions the required precision might not be achievable at all, in this case 0.0 for recall is returned. PiperOrigin-RevId: 297456035 Change-Id: Ie79e20014735c753282d1cd7699bd7475df15878 --- tensorflow/python/keras/metrics.py | 85 ++++++- .../keras/metrics_confusion_matrix_test.py | 119 ++++++++- tensorflow/python/keras/metrics_test.py | 30 +++ ...w.keras.metrics.-recall-at-precision.pbtxt | 232 ++++++++++++++++++ .../golden/v1/tensorflow.keras.metrics.pbtxt | 4 + ...w.keras.metrics.-recall-at-precision.pbtxt | 232 ++++++++++++++++++ .../golden/v2/tensorflow.keras.metrics.pbtxt | 4 + ...sorflow.metrics.-recall-at-precision.pbtxt | 232 ++++++++++++++++++ .../api/golden/v2/tensorflow.metrics.pbtxt | 4 + 9 files changed, 939 insertions(+), 3 deletions(-) create mode 100644 tensorflow/tools/api/golden/v1/tensorflow.keras.metrics.-recall-at-precision.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-recall-at-precision.pbtxt create mode 100644 tensorflow/tools/api/golden/v2/tensorflow.metrics.-recall-at-precision.pbtxt diff --git a/tensorflow/python/keras/metrics.py b/tensorflow/python/keras/metrics.py index e5610309bec..81abaabbe32 100644 --- a/tensorflow/python/keras/metrics.py +++ b/tensorflow/python/keras/metrics.py @@ -1684,7 +1684,7 @@ class PrecisionAtRecall(SensitivitySpecificityBase): model.compile( 'sgd', loss='mse', - metrics=[tf.keras.metrics.PrecisionAtRecall()]) + metrics=[tf.keras.metrics.PrecisionAtRecall(recall=0.8)]) ``` """ @@ -1730,6 +1730,89 @@ class PrecisionAtRecall(SensitivitySpecificityBase): return dict(list(base_config.items()) + list(config.items())) +@keras_export('keras.metrics.RecallAtPrecision') +class RecallAtPrecision(SensitivitySpecificityBase): + """Computes the maximally achievable recall at a required precision. + + For a given score-label-distribution the required precision might not + be achievable, in this case 0.0 is returned as recall. + + This metric creates four local variables, `true_positives`, `true_negatives`, + `false_positives` and `false_negatives` that are used to compute the + recall at the given precision. The threshold for the given precision + value is computed and used to evaluate the corresponding recall. + + If `sample_weight` is `None`, weights default to 1. + Use `sample_weight` of 0 to mask values. + + Usage: + + >>> m = tf.keras.metrics.RecallAtPrecision(0.8, num_thresholds=1) + >>> _ = m.update_state([0, 0, 1, 1], [0, 0.5, 0.3, 0.9]) + >>> m.result().numpy() + 0.5 + + >>> m.reset_states() + >>> _ = m.update_state([0, 0, 1, 1], [0, 0.5, 0.3, 0.9], + ... sample_weight=[1, 0, 0, 1]) + >>> m.result().numpy() + 1.0 + + Usage with tf.keras API: + + ```python + model = tf.keras.Model(inputs, outputs) + model.compile( + 'sgd', + loss='mse', + metrics=[tf.keras.metrics.RecallAtPrecision(precision=0.8)]) + ``` + """ + + def __init__(self, precision, num_thresholds=200, name=None, dtype=None): + """Creates a `RecallAtPrecision` instance. + + Args: + precision: A scalar value in range `[0, 1]`. + num_thresholds: (Optional) Defaults to 200. The number of thresholds to + use for matching the given precision. + name: (Optional) string name of the metric instance. + dtype: (Optional) data type of the metric result. + """ + if precision < 0 or precision > 1: + raise ValueError('`precision` must be in the range [0, 1].') + self.precision = precision + self.num_thresholds = num_thresholds + super(RecallAtPrecision, self).__init__( + value=precision, + num_thresholds=num_thresholds, + name=name, + dtype=dtype) + + def result(self): + # Calculate precision and recall at all the thresholds. + # All recalls are computed, because they are not a monotoneous function of + # precision and we want to search for the highest feasible recall. + precisions = math_ops.div_no_nan( + self.true_positives, self.true_positives + self.false_positives) + recalls = math_ops.div_no_nan( + self.true_positives, self.true_positives + self.false_negatives) + # Find best recall where the precision is as good as required. + feasible = array_ops.where(math_ops.greater_equal(precisions, self.value)) + feasible_exists = math_ops.greater(array_ops.size(feasible), 0) + best_recall = control_flow_ops.cond( + feasible_exists, + lambda: math_ops.reduce_max(array_ops.gather(recalls, feasible)), + lambda: 0.0) + return best_recall + + def get_config(self): + config = {'num_thresholds': self.num_thresholds, + 'precision': self.precision} + base_config = super(RecallAtPrecision, self).get_config() + return dict(list(base_config.items()) + list(config.items())) + + @keras_export('keras.metrics.AUC') class AUC(Metric): """Computes the approximate AUC (Area under the curve) via a Riemann sum. diff --git a/tensorflow/python/keras/metrics_confusion_matrix_test.py b/tensorflow/python/keras/metrics_confusion_matrix_test.py index 70f8a9bdcc4..36b1e98a8f9 100644 --- a/tensorflow/python/keras/metrics_confusion_matrix_test.py +++ b/tensorflow/python/keras/metrics_confusion_matrix_test.py @@ -957,9 +957,9 @@ class PrecisionAtRecallTest(test.TestCase, parameterized.TestCase): self.evaluate(update_op) # Then verify idempotency. - initial_specificity = self.evaluate(s_obj.result()) + initial_precision = self.evaluate(s_obj.result()) for _ in range(10): - self.assertAlmostEqual(initial_specificity, self.evaluate(s_obj.result()), + self.assertAlmostEqual(initial_precision, self.evaluate(s_obj.result()), 1e-3) def test_unweighted_all_correct(self): @@ -1018,6 +1018,121 @@ class PrecisionAtRecallTest(test.TestCase, parameterized.TestCase): metrics.PrecisionAtRecall(0.4, num_thresholds=-1) +@test_util.run_all_in_graph_and_eager_modes +class RecallAtPrecisionTest(test.TestCase, parameterized.TestCase): + + def test_config(self): + s_obj = metrics.RecallAtPrecision( + 0.4, num_thresholds=100, name='recall_at_precision_1') + self.assertEqual(s_obj.name, 'recall_at_precision_1') + self.assertLen(s_obj.variables, 4) + self.assertEqual(s_obj.precision, 0.4) + self.assertEqual(s_obj.num_thresholds, 100) + + # Check save and restore config + s_obj2 = metrics.RecallAtPrecision.from_config(s_obj.get_config()) + self.assertEqual(s_obj2.name, 'recall_at_precision_1') + self.assertLen(s_obj2.variables, 4) + self.assertEqual(s_obj2.precision, 0.4) + self.assertEqual(s_obj2.num_thresholds, 100) + + def test_value_is_idempotent(self): + s_obj = metrics.RecallAtPrecision(0.7) + y_pred = random_ops.random_uniform((10, 3), + maxval=1, + dtype=dtypes.float32, + seed=1) + y_true = random_ops.random_uniform((10, 3), + maxval=2, + dtype=dtypes.int64, + seed=1) + update_op = s_obj.update_state(y_true, y_pred) + self.evaluate(variables.variables_initializer(s_obj.variables)) + + # Run several updates. + for _ in range(10): + self.evaluate(update_op) + + # Then verify idempotency. + initial_recall = self.evaluate(s_obj.result()) + for _ in range(10): + self.assertAlmostEqual(initial_recall, self.evaluate(s_obj.result()), + 1e-3) + + def test_unweighted_all_correct(self): + s_obj = metrics.RecallAtPrecision(0.7) + inputs = np.random.randint(0, 2, size=(100, 1)) + y_pred = constant_op.constant(inputs, dtype=dtypes.float32) + y_true = constant_op.constant(inputs) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + self.assertAlmostEqual(1, self.evaluate(result)) + + def test_unweighted_high_precision(self): + s_obj = metrics.RecallAtPrecision(0.75) + pred_values = [ + 0.05, 0.1, 0.2, 0.3, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.9, 0.95 + ] + label_values = [0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1] + # precisions: [1/2, 6/11, 1/2, 5/9, 5/8, 5/7, 2/3, 3/5, 3/5, 2/3, 1/2, 1]. + # recalls: [1, 1, 5/6, 5/6, 5/6, 5/6, 2/3, 1/2, 1/2, 1/3, 1/6, 1/6]. + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = constant_op.constant(label_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + # The precision 0.75 can be reached at thresholds 0.4<=t<0.45. + self.assertAlmostEqual(0.5, self.evaluate(result)) + + def test_unweighted_low_precision(self): + s_obj = metrics.RecallAtPrecision(2.0 / 3) + pred_values = [ + 0.05, 0.1, 0.2, 0.3, 0.3, 0.35, 0.4, 0.45, 0.5, 0.6, 0.9, 0.95 + ] + label_values = [0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1] + # precisions: [1/2, 6/11, 1/2, 5/9, 5/8, 5/7, 2/3, 3/5, 3/5, 2/3, 1/2, 1]. + # recalls: [1, 1, 5/6, 5/6, 5/6, 5/6, 2/3, 1/2, 1/2, 1/3, 1/6, 1/6]. + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = constant_op.constant(label_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + # The precision 5/7 can be reached at thresholds 00.3<=t<0.35. + self.assertAlmostEqual(5. / 6, self.evaluate(result)) + + @parameterized.parameters([dtypes.bool, dtypes.int32, dtypes.float32]) + def test_weighted(self, label_dtype): + s_obj = metrics.RecallAtPrecision(0.75) + pred_values = [0.1, 0.2, 0.3, 0.5, 0.6, 0.9, 0.9] + label_values = [0, 1, 0, 0, 0, 1, 1] + weight_values = [1, 2, 1, 2, 1, 2, 1] + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = math_ops.cast(label_values, dtype=label_dtype) + weights = constant_op.constant(weight_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred, sample_weight=weights) + self.assertAlmostEqual(0.6, self.evaluate(result)) + + def test_unachievable_precision(self): + s_obj = metrics.RecallAtPrecision(2.0 / 3) + pred_values = [0.1, 0.2, 0.3, 0.9] + label_values = [1, 1, 0, 0] + y_pred = constant_op.constant(pred_values, dtype=dtypes.float32) + y_true = constant_op.constant(label_values) + self.evaluate(variables.variables_initializer(s_obj.variables)) + result = s_obj(y_true, y_pred) + # The highest possible precision is 1/2 which is below the required + # value, expect 0 recall. + self.assertAlmostEqual(0, self.evaluate(result)) + + def test_invalid_sensitivity(self): + with self.assertRaisesRegexp(ValueError, + r'`precision` must be in the range \[0, 1\].'): + metrics.RecallAtPrecision(-1) + + def test_invalid_num_thresholds(self): + with self.assertRaisesRegexp(ValueError, '`num_thresholds` must be > 0.'): + metrics.RecallAtPrecision(0.4, num_thresholds=-1) + + @test_util.run_all_in_graph_and_eager_modes class AUCTest(test.TestCase): diff --git a/tensorflow/python/keras/metrics_test.py b/tensorflow/python/keras/metrics_test.py index 930045b5ab7..27a17bfdd02 100644 --- a/tensorflow/python/keras/metrics_test.py +++ b/tensorflow/python/keras/metrics_test.py @@ -2094,6 +2094,36 @@ class ResetStatesTest(keras_parameterized.TestCase): self.assertEqual(self.evaluate(s_obj.false_negatives), 25.) self.assertEqual(self.evaluate(s_obj.true_negatives), 25.) + def test_reset_states_precision_at_recall(self): + s_obj = metrics.PrecisionAtRecall(recall=0.5, num_thresholds=1) + model = _get_model([s_obj]) + x = np.concatenate((np.ones((25, 4)), np.zeros((25, 4)), np.zeros((25, 4)), + np.ones((25, 4)))) + y = np.concatenate((np.ones((25, 1)), np.zeros((25, 1)), np.ones((25, 1)), + np.zeros((25, 1)))) + + for _ in range(2): + model.evaluate(x, y) + self.assertEqual(self.evaluate(s_obj.true_positives), 25.) + self.assertEqual(self.evaluate(s_obj.false_positives), 25.) + self.assertEqual(self.evaluate(s_obj.false_negatives), 25.) + self.assertEqual(self.evaluate(s_obj.true_negatives), 25.) + + def test_reset_states_recall_at_precision(self): + s_obj = metrics.RecallAtPrecision(precision=0.5, num_thresholds=1) + model = _get_model([s_obj]) + x = np.concatenate((np.ones((25, 4)), np.zeros((25, 4)), np.zeros((25, 4)), + np.ones((25, 4)))) + y = np.concatenate((np.ones((25, 1)), np.zeros((25, 1)), np.ones((25, 1)), + np.zeros((25, 1)))) + + for _ in range(2): + model.evaluate(x, y) + self.assertEqual(self.evaluate(s_obj.true_positives), 25.) + self.assertEqual(self.evaluate(s_obj.false_positives), 25.) + self.assertEqual(self.evaluate(s_obj.false_negatives), 25.) + self.assertEqual(self.evaluate(s_obj.true_negatives), 25.) + def test_reset_states_auc(self): auc_obj = metrics.AUC(num_thresholds=3) model = _get_model([auc_obj]) diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.metrics.-recall-at-precision.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.metrics.-recall-at-precision.pbtxt new file mode 100644 index 00000000000..a5f143ca664 --- /dev/null +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.metrics.-recall-at-precision.pbtxt @@ -0,0 +1,232 @@ +path: "tensorflow.keras.metrics.RecallAtPrecision" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "dynamic" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "input_spec" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "metrics" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "name_scope" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "stateful" + mtype: "" + } + member { + name: "submodules" + mtype: "" + } + member { + name: "trainable" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'precision\', \'num_thresholds\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'200\', \'None\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\', \'dtype\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "compute_output_signature" + argspec: "args=[\'self\', \'input_signature\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "with_name_scope" + argspec: "args=[\'cls\', \'method\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v1/tensorflow.keras.metrics.pbtxt b/tensorflow/tools/api/golden/v1/tensorflow.keras.metrics.pbtxt index c4481a9233e..2b09ccc48a2 100644 --- a/tensorflow/tools/api/golden/v1/tensorflow.keras.metrics.pbtxt +++ b/tensorflow/tools/api/golden/v1/tensorflow.keras.metrics.pbtxt @@ -104,6 +104,10 @@ tf_module { name: "Recall" mtype: "" } + member { + name: "RecallAtPrecision" + mtype: "" + } member { name: "RootMeanSquaredError" mtype: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-recall-at-precision.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-recall-at-precision.pbtxt new file mode 100644 index 00000000000..a5f143ca664 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.-recall-at-precision.pbtxt @@ -0,0 +1,232 @@ +path: "tensorflow.keras.metrics.RecallAtPrecision" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "dynamic" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "input_spec" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "metrics" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "name_scope" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "stateful" + mtype: "" + } + member { + name: "submodules" + mtype: "" + } + member { + name: "trainable" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'precision\', \'num_thresholds\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'200\', \'None\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\', \'dtype\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "compute_output_signature" + argspec: "args=[\'self\', \'input_signature\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "with_name_scope" + argspec: "args=[\'cls\', \'method\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.pbtxt index def1eb51bde..1b4976294ed 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.keras.metrics.pbtxt @@ -104,6 +104,10 @@ tf_module { name: "Recall" mtype: "" } + member { + name: "RecallAtPrecision" + mtype: "" + } member { name: "RootMeanSquaredError" mtype: "" diff --git a/tensorflow/tools/api/golden/v2/tensorflow.metrics.-recall-at-precision.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-recall-at-precision.pbtxt new file mode 100644 index 00000000000..62ea36e01a2 --- /dev/null +++ b/tensorflow/tools/api/golden/v2/tensorflow.metrics.-recall-at-precision.pbtxt @@ -0,0 +1,232 @@ +path: "tensorflow.metrics.RecallAtPrecision" +tf_class { + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + is_instance: "" + member { + name: "activity_regularizer" + mtype: "" + } + member { + name: "dtype" + mtype: "" + } + member { + name: "dynamic" + mtype: "" + } + member { + name: "inbound_nodes" + mtype: "" + } + member { + name: "input" + mtype: "" + } + member { + name: "input_mask" + mtype: "" + } + member { + name: "input_shape" + mtype: "" + } + member { + name: "input_spec" + mtype: "" + } + member { + name: "losses" + mtype: "" + } + member { + name: "metrics" + mtype: "" + } + member { + name: "name" + mtype: "" + } + member { + name: "name_scope" + mtype: "" + } + member { + name: "non_trainable_variables" + mtype: "" + } + member { + name: "non_trainable_weights" + mtype: "" + } + member { + name: "outbound_nodes" + mtype: "" + } + member { + name: "output" + mtype: "" + } + member { + name: "output_mask" + mtype: "" + } + member { + name: "output_shape" + mtype: "" + } + member { + name: "stateful" + mtype: "" + } + member { + name: "submodules" + mtype: "" + } + member { + name: "trainable" + mtype: "" + } + member { + name: "trainable_variables" + mtype: "" + } + member { + name: "trainable_weights" + mtype: "" + } + member { + name: "updates" + mtype: "" + } + member { + name: "variables" + mtype: "" + } + member { + name: "weights" + mtype: "" + } + member_method { + name: "__init__" + argspec: "args=[\'self\', \'precision\', \'num_thresholds\', \'name\', \'dtype\'], varargs=None, keywords=None, defaults=[\'200\', \'None\', \'None\'], " + } + member_method { + name: "add_loss" + argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_metric" + argspec: "args=[\'self\', \'value\', \'aggregation\', \'name\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], " + } + member_method { + name: "add_update" + argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "add_variable" + argspec: "args=[\'self\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "add_weight" + argspec: "args=[\'self\', \'name\', \'shape\', \'aggregation\', \'synchronization\', \'initializer\', \'dtype\'], varargs=None, keywords=None, defaults=[\'()\', \'VariableAggregation.SUM\', \'VariableSynchronization.ON_READ\', \'None\', \'None\'], " + } + member_method { + name: "apply" + argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None" + } + member_method { + name: "build" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "call" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=kwargs, defaults=None" + } + member_method { + name: "compute_mask" + argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "compute_output_shape" + argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "compute_output_signature" + argspec: "args=[\'self\', \'input_signature\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "count_params" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "from_config" + argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_config" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_input_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_losses_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_mask_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_output_shape_at" + argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_updates_for" + argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "get_weights" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "reset_states" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "result" + argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "set_weights" + argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None" + } + member_method { + name: "update_state" + argspec: "args=[\'self\', \'y_true\', \'y_pred\', \'sample_weight\'], varargs=None, keywords=None, defaults=[\'None\'], " + } + member_method { + name: "with_name_scope" + argspec: "args=[\'cls\', \'method\'], varargs=None, keywords=None, defaults=None" + } +} diff --git a/tensorflow/tools/api/golden/v2/tensorflow.metrics.pbtxt b/tensorflow/tools/api/golden/v2/tensorflow.metrics.pbtxt index 5bd57dd7618..eb0fc81133a 100644 --- a/tensorflow/tools/api/golden/v2/tensorflow.metrics.pbtxt +++ b/tensorflow/tools/api/golden/v2/tensorflow.metrics.pbtxt @@ -104,6 +104,10 @@ tf_module { name: "Recall" mtype: "" } + member { + name: "RecallAtPrecision" + mtype: "" + } member { name: "RootMeanSquaredError" mtype: ""