dc6079821b
Docs Tests / Check for file changes (push) Has been cancelled
Docs Tests / Test Documentation (push) Has been cancelled
Docs Tests / Documentation Linting Checks (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.10, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.8, test-policies) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-performance) (push) Has been cancelled
Continuous Integration / Run Tests (windows-2022, 3.9, test-policies) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (ubuntu-24.04, 3.9) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.10) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.8) (push) Has been cancelled
Continuous Integration / Run Flaky Tests (windows-2022, 3.9) (push) Has been cancelled
Continuous Integration / Check for file changes (push) Has been cancelled
Continuous Integration / Wait for docs tests (push) Has been cancelled
Continuous Integration / Code Quality (push) Has been cancelled
Continuous Integration / Check for changelog (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-cli) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-core-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-full-model-training) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-featurizers) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-nlu-predictors) (push) Has been cancelled
Continuous Integration / Run Tests (ubuntu-24.04, 3.10, test-other-unit-tests) (push) Has been cancelled
Continuous Integration / Upload coverage reports to codeclimate (push) Has been cancelled
Continuous Integration / Run Non-Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Run Broker Integration Tests (push) Has been cancelled
Continuous Integration / Run Sequential Integration Tests (push) Has been cancelled
Continuous Integration / Build Docker base images and setup environment (push) Has been cancelled
Continuous Integration / Build Docker (default) (push) Has been cancelled
Continuous Integration / Build Docker (full) (push) Has been cancelled
Continuous Integration / Build Docker (mitie-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-de) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-en) (push) Has been cancelled
Continuous Integration / Build Docker (spacy-it) (push) Has been cancelled
Continuous Integration / Deploy to PyPI (push) Has been cancelled
Continuous Integration / Notify Slack & Publish Release Notes (push) Has been cancelled
Publish Documentation / Evaluate release tag (push) Has been cancelled
Publish Documentation / Prebuild Docs (push) Has been cancelled
Publish Documentation / Preview Docs (push) Has been cancelled
Publish Documentation / Check for file changes (push) Has been cancelled
Publish Documentation / Publish Docs (push) Has been cancelled
Automatic PR Merger / mergepal (push) Has been cancelled
CI Github Actions / Run Tests (push) Has been cancelled
Semgrep / Semgrep Workflow Security Scan (push) Has been cancelled
283 lines
9.8 KiB
Python
283 lines
9.8 KiB
Python
import tensorflow as tf
|
|
from tensorflow.keras import backend as K
|
|
from tensorflow.types.experimental import TensorLike
|
|
from typing import Any, Dict, Optional
|
|
|
|
|
|
# original code taken from
|
|
# https://github.com/tensorflow/addons/blob/f30df4322b5580b3e5946530a60f7126035dd73b/tensorflow_addons/metrics/f_scores.py
|
|
# (modified to our neeeds)
|
|
|
|
|
|
class FBetaScore(tf.keras.metrics.Metric):
|
|
r"""Computes F-Beta score.
|
|
|
|
It is the weighted harmonic mean of precision
|
|
and recall. Output range is `[0, 1]`. Works for
|
|
both multi-class and multi-label classification.
|
|
|
|
$$
|
|
F_{\beta} = (1 + \beta^2) * \frac{\textrm{precision} * \textrm{recall}}
|
|
{(\beta^2 \cdot \textrm{precision}) + \textrm{recall}}
|
|
$$
|
|
|
|
Args:
|
|
num_classes: Number of unique classes in the dataset.
|
|
average: Type of averaging to be performed on data.
|
|
Acceptable values are `None`, `micro`, `macro` and
|
|
`weighted`. Default value is None.
|
|
beta: Determines the weight of precision and recall
|
|
in harmonic mean. Determines the weight given to the
|
|
precision and recall. Default value is 1.
|
|
threshold: Elements of `y_pred` greater than threshold are
|
|
converted to be 1, and the rest 0. If threshold is
|
|
None, the argmax is converted to 1, and the rest 0.
|
|
name: (Optional) String name of the metric instance.
|
|
dtype: (Optional) Data type of the metric result.
|
|
|
|
Returns:
|
|
F-Beta Score: float.
|
|
|
|
Raises:
|
|
ValueError: If the `average` has values other than
|
|
`[None, 'micro', 'macro', 'weighted']`.
|
|
|
|
ValueError: If the `beta` value is less than or equal
|
|
to 0.
|
|
|
|
`average` parameter behavior:
|
|
|
|
None: Scores for each class are returned.
|
|
|
|
micro: True positivies, false positives and
|
|
false negatives are computed globally.
|
|
|
|
macro: True positivies, false positives and
|
|
false negatives are computed for each class
|
|
and their unweighted mean is returned.
|
|
|
|
weighted: Metrics are computed for each class
|
|
and returns the mean weighted by the
|
|
number of true instances in each class.
|
|
|
|
Usage:
|
|
|
|
>>> metric = tfa.metrics.FBetaScore(num_classes=3, beta=2.0, threshold=0.5)
|
|
>>> y_true = np.array([[1, 1, 1],
|
|
... [1, 0, 0],
|
|
... [1, 1, 0]], np.int32)
|
|
>>> y_pred = np.array([[0.2, 0.6, 0.7],
|
|
... [0.2, 0.6, 0.6],
|
|
... [0.6, 0.8, 0.0]], np.float32)
|
|
>>> metric.update_state(y_true, y_pred)
|
|
>>> result = metric.result()
|
|
>>> result.numpy()
|
|
array([0.3846154 , 0.90909094, 0.8333334 ], dtype=float32)
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
num_classes: TensorLike,
|
|
average: Optional[str] = None,
|
|
beta: TensorLike = 1.0,
|
|
threshold: Optional[TensorLike] = None,
|
|
name: str = "fbeta_score",
|
|
dtype: Any = None,
|
|
**kwargs: Any,
|
|
) -> None:
|
|
super().__init__(name=name, dtype=dtype)
|
|
|
|
if average not in (None, "micro", "macro", "weighted"):
|
|
raise ValueError(
|
|
"Unknown average type. Acceptable values "
|
|
"are: [None, 'micro', 'macro', 'weighted']"
|
|
)
|
|
|
|
if not isinstance(beta, float):
|
|
raise TypeError("The value of beta should be a python float")
|
|
|
|
if beta <= 0.0:
|
|
raise ValueError("beta value should be greater than zero")
|
|
|
|
if threshold is not None:
|
|
if not isinstance(threshold, float):
|
|
raise TypeError("The value of threshold should be a python float")
|
|
if threshold > 1.0 or threshold <= 0.0:
|
|
raise ValueError("threshold should be between 0 and 1")
|
|
|
|
self.num_classes = num_classes
|
|
self.average = average
|
|
self.beta = beta
|
|
self.threshold = threshold
|
|
self.axis = None
|
|
self.init_shape = []
|
|
|
|
if self.average != "micro":
|
|
self.axis = 0
|
|
self.init_shape = [self.num_classes]
|
|
|
|
def _zero_wt_init(name: Any) -> Any:
|
|
return self.add_weight(
|
|
name, shape=self.init_shape, initializer="zeros", dtype=self.dtype
|
|
)
|
|
|
|
self.true_positives = _zero_wt_init("true_positives")
|
|
self.false_positives = _zero_wt_init("false_positives")
|
|
self.false_negatives = _zero_wt_init("false_negatives")
|
|
self.weights_intermediate = _zero_wt_init("weights_intermediate")
|
|
|
|
def update_state(
|
|
self,
|
|
y_true: TensorLike,
|
|
y_pred: TensorLike,
|
|
sample_weight: Optional[TensorLike] = None,
|
|
) -> None:
|
|
if self.threshold is None:
|
|
threshold = tf.reduce_max(y_pred, axis=-1, keepdims=True)
|
|
# make sure [0, 0, 0] doesn't become [1, 1, 1]
|
|
# Use abs(x) > eps, instead of x != 0 to check for zero
|
|
y_pred = tf.logical_and(y_pred >= threshold, tf.abs(y_pred) > 1e-12)
|
|
else:
|
|
y_pred = y_pred > self.threshold
|
|
|
|
y_true = tf.cast(y_true, self.dtype)
|
|
y_pred = tf.cast(y_pred, self.dtype)
|
|
|
|
def _weighted_sum(
|
|
val: TensorLike, sample_weight: Optional[TensorLike]
|
|
) -> TensorLike:
|
|
if sample_weight is not None:
|
|
val = tf.math.multiply(val, tf.expand_dims(sample_weight, 1))
|
|
return tf.reduce_sum(val, axis=self.axis)
|
|
|
|
self.true_positives.assign_add(_weighted_sum(y_pred * y_true, sample_weight))
|
|
self.false_positives.assign_add(
|
|
_weighted_sum(y_pred * (1 - y_true), sample_weight)
|
|
)
|
|
self.false_negatives.assign_add(
|
|
_weighted_sum((1 - y_pred) * y_true, sample_weight)
|
|
)
|
|
self.weights_intermediate.assign_add(_weighted_sum(y_true, sample_weight))
|
|
|
|
def result(self) -> TensorLike:
|
|
precision = tf.math.divide_no_nan(
|
|
self.true_positives, self.true_positives + self.false_positives
|
|
)
|
|
recall = tf.math.divide_no_nan(
|
|
self.true_positives, self.true_positives + self.false_negatives
|
|
)
|
|
|
|
mul_value = precision * recall
|
|
add_value = (tf.math.square(self.beta) * precision) + recall
|
|
mean = tf.math.divide_no_nan(mul_value, add_value)
|
|
f1_score = mean * (1 + tf.math.square(self.beta))
|
|
|
|
if self.average == "weighted":
|
|
weights = tf.math.divide_no_nan(
|
|
self.weights_intermediate, tf.reduce_sum(self.weights_intermediate)
|
|
)
|
|
f1_score = tf.reduce_sum(f1_score * weights)
|
|
|
|
elif self.average is not None: # [micro, macro]
|
|
f1_score = tf.reduce_mean(f1_score)
|
|
|
|
return f1_score
|
|
|
|
def get_config(self) -> Dict[str, Any]:
|
|
"""Returns the serializable config of the metric."""
|
|
|
|
config = {
|
|
"num_classes": self.num_classes,
|
|
"average": self.average,
|
|
"beta": self.beta,
|
|
"threshold": self.threshold,
|
|
}
|
|
|
|
base_config = super().get_config()
|
|
return {**base_config, **config}
|
|
|
|
def reset_state(self) -> None:
|
|
reset_value = tf.zeros(self.init_shape, dtype=self.dtype)
|
|
K.batch_set_value([(v, reset_value) for v in self.variables])
|
|
|
|
def reset_states(self) -> None:
|
|
# Backwards compatibility alias of `reset_state`. New classes should
|
|
# only implement `reset_state`.
|
|
# Required in Tensorflow < 2.5.0
|
|
return self.reset_state()
|
|
|
|
|
|
class F1Score(FBetaScore):
|
|
r"""Computes F-1 Score.
|
|
|
|
It is the harmonic mean of precision and recall.
|
|
Output range is `[0, 1]`. Works for both multi-class
|
|
and multi-label classification.
|
|
|
|
$$
|
|
F_1 = 2 \cdot \frac{\textrm{precision} \cdot \textrm{recall}}{\textrm{precision}
|
|
+ \textrm{recall}}
|
|
$$
|
|
|
|
Args:
|
|
num_classes: Number of unique classes in the dataset.
|
|
average: Type of averaging to be performed on data.
|
|
Acceptable values are `None`, `micro`, `macro`
|
|
and `weighted`. Default value is None.
|
|
threshold: Elements of `y_pred` above threshold are
|
|
considered to be 1, and the rest 0. If threshold is
|
|
None, the argmax is converted to 1, and the rest 0.
|
|
name: (Optional) String name of the metric instance.
|
|
dtype: (Optional) Data type of the metric result.
|
|
|
|
Returns:
|
|
F-1 Score: float.
|
|
|
|
Raises:
|
|
ValueError: If the `average` has values other than
|
|
[None, 'micro', 'macro', 'weighted'].
|
|
|
|
`average` parameter behavior:
|
|
None: Scores for each class are returned
|
|
|
|
micro: True positivies, false positives and
|
|
false negatives are computed globally.
|
|
|
|
macro: True positivies, false positives and
|
|
false negatives are computed for each class
|
|
and their unweighted mean is returned.
|
|
|
|
weighted: Metrics are computed for each class
|
|
and returns the mean weighted by the
|
|
number of true instances in each class.
|
|
|
|
Usage:
|
|
|
|
>>> metric = tfa.metrics.F1Score(num_classes=3, threshold=0.5)
|
|
>>> y_true = np.array([[1, 1, 1],
|
|
... [1, 0, 0],
|
|
... [1, 1, 0]], np.int32)
|
|
>>> y_pred = np.array([[0.2, 0.6, 0.7],
|
|
... [0.2, 0.6, 0.6],
|
|
... [0.6, 0.8, 0.0]], np.float32)
|
|
>>> metric.update_state(y_true, y_pred)
|
|
>>> result = metric.result()
|
|
>>> result.numpy()
|
|
array([0.5 , 0.8 , 0.6666667], dtype=float32)
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
num_classes: TensorLike,
|
|
average: str = None,
|
|
threshold: Optional[TensorLike] = None,
|
|
name: str = "f1_score",
|
|
dtype: Any = None,
|
|
):
|
|
super().__init__(num_classes, average, 1.0, threshold, name=name, dtype=dtype)
|
|
|
|
def get_config(self) -> Dict[str, Any]:
|
|
base_config = super().get_config()
|
|
del base_config["beta"]
|
|
return base_config
|