code: # Copyright 2021 The FastEstimator 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 numpy as np
  
  from fastestimator.op.numpyop.univariate import AutoContrast
  
  
  class TestAutoContrast(unittest.TestCase):
      @classmethod
      def setUpClass(cls):
          cls.single_input = [np.random.randint(0, 256, size=(28, 28, 3)).astype(np.uint8)]
          cls.single_output_shape = (28, 28, 3)
          cls.multi_input = [
              np.random.randint(0, 256, size=(28, 28, 3)).astype(np.uint8),
              np.random.randint(0, 256, size=(28, 28, 3)).astype(np.uint8)
          ]
          cls.multi_output_shape = (28, 28, 3)
  
      def test_single_input(self):
          autocontrast = AutoContrast(inputs='x', outputs='x')
          output = autocontrast.forward(data=self.single_input, state={})
          with self.subTest('Check output type'):
              self.assertEqual(type(output), list)
          with self.subTest('Check output image shape'):
              self.assertEqual(output[0].shape, self.single_output_shape)
  
      def test_multi_input(self):
          autocontrast = AutoContrast(inputs='x', outputs='x')
          output = autocontrast.forward(data=self.multi_input, state={})
          with self.subTest('Check output type'):
              self.assertEqual(type(output), list)
          with self.subTest('Check output list length'):
              self.assertEqual(len(output), 2)
          for img_output in output:
              with self.subTest('Check output image shape'):
                  self.assertEqual(img_output.shape, self.multi_output_shape)
   # Copyright 2019 The FastEstimator 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.
  # ==============================================================================
  from typing import Union, Iterable
  
  import numpy as np
  from sklearn.metrics import matthews_corrcoef
  
  from fastestimator.trace.meta._per_ds import per_ds
  from fastestimator.trace.trace import Trace
  from fastestimator.util.data import Any, Data, Dict
  from fastestimator.util.traceability_util import traceable
  from fastestimator.util.util import to_number
  
  
  @per_ds
  @traceable()
  class MCC(Trace):
      """A trace which computes the Matthews Correlation Coefficient for a given set of predictions.
  
      This is a preferable metric to accuracy or F1 score since it automatically corrects for class imbalances and does
      not depend on the choice of target class (https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6941312/). Ideal value is 1,
       a value of 0 means your predictions are completely uncorrelated with the true data. A value less than zero implies
      anti-correlation (you should invert your classifier predictions in order to do better).
  
      Args:
          true_key: Name of the key that corresponds to ground truth in the batch dictionary.
          pred_key: Name of the key that corresponds to predicted score in the batch dictionary.
          mode: What mode(s) to execute this Trace in. For example, "train", "eval", "test", or "infer". To execute
              regardless of mode, pass None. To execute in all modes except for a particular one, you can pass an argument
              like "!infer" or "!train".
          ds_id: What dataset id(s) to execute this Trace in. To execute regardless of ds_id, pass None. To execute in all
              ds_ids except for a particular one, you can pass an argument like "!ds1".
          output_name: What to call the output from this trace (for example in the logger output).
          per_ds: Whether to automatically compute this metric individually for every ds_id it runs on, in addition to
              computing an aggregate across all ds_ids on which it runs. This is automatically False if `output_name`
              contains a "|" character.
          **kwargs: Additional keyword arguments that pass to sklearn.metrics.matthews_corrcoef()
  
      Raises:
          ValueError: One of ["y_true", "y_pred"] argument exists in `kwargs`.
      """
      def __init__(self,
                   true_key: str,
                   pred_key: str,
                   mode: Union[None, str, Iterable[str]] = ("eval", "test"),
                   ds_id: Union[None, str, Iterable[str]] = None,
                   output_name: str = "mcc",
                   per_ds: bool = True,
                   **kwargs) -> None:
          MCC.check_kwargs(kwargs)
          super().__init__(inputs=(true_key, pred_key), mode=mode, outputs=output_name, ds_id=ds_id)
          self.kwargs = kwargs
          self.y_true = []
          self.y_pred = []
          self.per_ds = per_ds
  
      @property
      def true_key(self) -> str:
          return self.inputs[0]
  
      @property
      def pred_key(self) -> str:
          return self.inputs[1]
  
      def on_epoch_begin(self, data: Data) -> None:
          self.y_true = []
          self.y_pred = []
  
      def on_batch_end(self, data: Data) -> None:
          y_true, y_pred = to_number(data[self.true_key]), to_number(data[self.pred_key])
          if y_true.shape[-1] > 1 and y_true.ndim > 1:
              y_true = np.argmax(y_true, axis=-1)
          if y_pred.shape[-1] > 1 and y_pred.ndim > 1:
              y_pred = np.argmax(y_pred, axis=-1)
          else:
              y_pred = np.round(y_pred)
          assert y_pred.size == y_true.size
          self.y_true.extend(y_true)
          self.y_pred.extend(y_pred)
  
      def on_epoch_end(self, data: Data) -> None:
          data.write_with_log(self.outputs[0], matthews_corrcoef(y_true=self.y_true, y_pred=self.y_pred, **self.kwargs))
  
      @staticmethod
      def check_kwargs(kwargs: Dict[str, Any]) -> None:
          """Check if `kwargs` has any blacklist argument and raise an error if it does.
  
          Args:
              kwargs: Keywork arguments to be examined.
  
          Raises:
              ValueError: One of ["y_true", "y_pred"] argument exists in `kwargs`.
          """
          blacklist = ["y_true", "y_pred"]
          illegal_kwarg = [x for x in blacklist if x in kwargs]
          if illegal_kwarg:
              raise ValueError(
                  f"Arguments {illegal_kwarg} cannot exist in kwargs, since FastEstimator will later directly use them in"
                  " sklearn.metrics.matthews_corrcoef()")
   # Copyright 2019 The FastEstimator 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 math
  from typing import Optional, TypeVar
  
  import numpy as np
  import tensorflow as tf
  import torch
  
  from fastestimator.backend._maximum import maximum
  from fastestimator.backend._reduce_sum import reduce_sum
  from fastestimator.backend._reshape import reshape
  from fastestimator.backend._tensor_pow import tensor_pow
  from fastestimator.backend._to_tensor import to_tensor
  from fastestimator.util.util import TENSOR_TO_NP_DTYPE
  
  Tensor = TypeVar('Tensor', tf.Tensor, torch.Tensor, np.ndarray)
  
  
  def iwd(tensor: Tensor,
          power: float = 1.0,
          max_prob: float = 0.95,
          pairwise_distance: float = 1.0,
          eps: Optional[Tensor] = None) -> Tensor:
      """Compute the Inverse Weighted Distance from the given input.
  
      This can be used as an activation function for the final layer of a neural network instead of softmax. For example,
      instead of: model.add(layers.Dense(classes, activation='softmax')), you could use:
      model.add(layers.Dense(classes, activation=lambda x: iwd(tf.nn.sigmoid(x))))
  
      This method can be used with Numpy data:
      ```python
      n = np.array([[0.5]*5, [0]+[1]*4])
      b = fe.backend.iwd(n)  # [[0.2, 0.2, 0.2, 0.2, 0.2], [0.95, 0.0125, 0.0125, 0.0125, 0.0125]]
      ```
  
      This method can be used with TensorFlow tensors:
      ```python
      t = tf.constant([[0.5]*5, [0]+[1]*4])
      b = fe.backend.iwd(n)  # [[0.2, 0.2, 0.2, 0.2, 0.2], [0.95, 0.0125, 0.0125, 0.0125, 0.0125]]
      ```
  
      This method can be used with PyTorch tensors:
      ```python
      p = torch.tensor([[0.5]*5, [0]+[1]*4])
      b = fe.backend.iwd(n)  # [[0.2, 0.2, 0.2, 0.2, 0.2], [0.95, 0.0125, 0.0125, 0.0125, 0.0125]]
      ```
  
      Args:
          tensor: The input value. Should be of shape (Batch, C) where every element in C corresponds to a (non-negative)
              distance to a target class.
          power: The power to raise the inverse distances to. 1.0 results in a fairly intuitive probability output. Larger
              powers can widen regions of certainty, whereas values between 0 and 1 can widen regions of uncertainty.
          max_prob: The maximum probability to assign to a class estimate when it is distance zero away from the target.
              For numerical stability this must be less than 1.0. We have found that using smaller values like 0.95 can
              lead to natural adversarial robustness.
          pairwise_distance: The distance to any other class when the distance to a target class is zero. For example, if
              you have a perfect match for class 'a', what distance should be reported to class 'b'. If you have a metric
              where this isn't constant, just use an approximate expected distance. In that case `max_prob` will only give
              you approximate control over the true maximum probability.
          eps: The numeric stability constant to be used when d approaches zero. If None then it will be computed using
              `max_prob` and `pairwise_distance`. If not None, then `max_prob` and `pairwise_distance` will be ignored.
  
      Returns:
          A probability distribution of shape (Batch, C) where smaller distances from `tensor` correspond to larger
          probabilities.
      """
      if eps is None:
          eps = np.array(pairwise_distance * math.pow((1.0 - max_prob) / (max_prob * (tensor.shape[-1] - 1)), 1 / power),
                         dtype=TENSOR_TO_NP_DTYPE[tensor.dtype])
          eps = to_tensor(
              eps, target_type='torch' if isinstance(tensor, torch.Tensor) else 'tf' if tf.is_tensor(tensor) else 'np')
          if isinstance(eps, torch.Tensor):
              eps = eps.to("cuda:0" if torch.cuda.is_available() else "cpu")
      tensor = maximum(tensor, eps)
      tensor = tensor_pow(1.0 / tensor, power)
      tensor = tensor / reshape(reduce_sum(tensor, axis=-1), shape=[-1, 1])
      return tensor
  
apis: numpy.random.randint
apis: numpy.round numpy.argmax sklearn.metrics.matthews_corrcoef
apis: torch.cuda.is_available tensorflow.is_tensor