Source code for apache_beam.ml.anomaly.detectors.offline

#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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 Any
from typing import Optional
from typing import SupportsFloat
from typing import SupportsInt
from typing import TypeVar

import apache_beam as beam
from apache_beam.ml.anomaly.base import AnomalyDetector
from apache_beam.ml.anomaly.base import AnomalyPrediction
from apache_beam.ml.anomaly.specifiable import specifiable
from apache_beam.ml.inference.base import KeyedModelHandler
from apache_beam.ml.inference.base import PredictionResult
from apache_beam.ml.inference.base import PredictionT

KeyT = TypeVar('KeyT')


[docs] @specifiable class OfflineDetector(AnomalyDetector): """A offline anomaly detector that uses a provided model handler for scoring. Args: keyed_model_handler: The model handler to use for inference. Requires a `KeyModelHandler[Any, Row, PredictionT, Any]` instance. run_inference_args: Optional arguments to pass to RunInference **kwargs: Additional keyword arguments to pass to the base AnomalyDetector class. """
[docs] @staticmethod def score_prediction_adapter( keyed_prediction: tuple[KeyT, PredictionResult] ) -> tuple[KeyT, AnomalyPrediction]: """Extracts a float score from `PredictionResult.inference` and wraps it. Takes a keyed `PredictionResult` from common ModelHandler output, assumes its `inference` attribute is a float-convertible score, and returns the key paired with an `AnomalyPrediction` containing that float score. Args: keyed_prediction: tuple of `(key, PredictionResult)`. `PredictionResult` must have an `inference` attribute supporting float conversion. Returns: tuple of `(key, AnomalyPrediction)` with the extracted score. Raises: AssertionError: If `PredictionResult.inference` doesn't support float(). """ key, prediction = keyed_prediction score = prediction.inference assert isinstance(score, SupportsFloat) return key, AnomalyPrediction(score=float(score))
[docs] @staticmethod def label_prediction_adapter( keyed_prediction: tuple[KeyT, PredictionResult] ) -> tuple[KeyT, AnomalyPrediction]: """Extracts an integer label from `PredictionResult.inference` and wraps it. Takes a keyed `PredictionResult`, assumes its `inference` attribute is an integer-convertible label, and returns the key paired with an `AnomalyPrediction` containing that integer label. Args: keyed_prediction: tuple of `(key, PredictionResult)`. `PredictionResult` must have an `inference` attribute supporting int conversion. Returns: tuple of `(key, AnomalyPrediction)` with the extracted label. Raises: AssertionError: If `PredictionResult.inference` doesn't support int(). """ key, prediction = keyed_prediction label = prediction.inference assert isinstance(label, SupportsInt) return key, AnomalyPrediction(label=int(label))
def __init__( self, keyed_model_handler: KeyedModelHandler[Any, beam.Row, PredictionT, Any], run_inference_args: Optional[dict[str, Any]] = None, **kwargs): super().__init__(**kwargs) # TODO: validate the model handler type self._keyed_model_handler = keyed_model_handler self._run_inference_args = run_inference_args or {} # always override model_identifier with model_id from the detector self._run_inference_args["model_identifier"] = self._model_id
[docs] def learn_one(self, x: beam.Row) -> None: """Not implemented since OfflineDetector invokes RunInference directly.""" raise NotImplementedError
[docs] def score_one(self, x: beam.Row) -> Optional[float]: """Not implemented since OfflineDetector invokes RunInference directly.""" raise NotImplementedError