@@ -1,6 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
from typing import Sequence
|
||||
|
||||
from app.ml.feature_store import FeatureVector
|
||||
@@ -10,6 +12,15 @@ from app.ml.training import TrainedArtifact, TrainingPipeline
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class PredictionResult:
|
||||
artifact_id: str
|
||||
sensor_id: str
|
||||
predictions: dict[str, float]
|
||||
confidence: float
|
||||
model_type: str
|
||||
|
||||
|
||||
class Predictor:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -24,15 +35,45 @@ class Predictor:
|
||||
self._pipeline = pipeline
|
||||
self._registry = registry
|
||||
|
||||
def predict(self, artifact_id: str, entity: FeatureVector) -> str:
|
||||
def predict(self, artifact_id: str, entity: FeatureVector) -> PredictionResult:
|
||||
artifact = self._get_artifact(artifact_id)
|
||||
if entity.sensor_id not in artifact.supported_sensors:
|
||||
raise ValueError(
|
||||
f"Sensor '{entity.sensor_id}' wird vom Modell '{artifact_id}' nicht unterstützt."
|
||||
)
|
||||
return f"{artifact_id}:{entity.sensor_id}:{entity.values}"
|
||||
sensor_models = artifact.feature_models.get(entity.sensor_id, {})
|
||||
if not sensor_models:
|
||||
raise ValueError(f"Modell '{artifact_id}' enthält keine statistischen Parameter.")
|
||||
|
||||
def predict_batch(self, artifact_id: str, entities: Sequence[FeatureVector]) -> list[str]:
|
||||
feature_names = sorted(set(sensor_models).intersection(entity.values))
|
||||
if not feature_names:
|
||||
raise ValueError(
|
||||
f"Keine Eingabemerkmale werden vom Modell '{artifact_id}' unterstützt."
|
||||
)
|
||||
|
||||
predictions: dict[str, float] = {}
|
||||
confidences: list[float] = []
|
||||
for feature_name in feature_names:
|
||||
model = sensor_models[feature_name]
|
||||
current_value = float(entity.values[feature_name])
|
||||
if not math.isfinite(current_value):
|
||||
raise ValueError("Vorhersagewerte müssen endlich sein.")
|
||||
predictions[feature_name] = model.forecast(current_value)
|
||||
confidences.append(model.confidence)
|
||||
|
||||
return PredictionResult(
|
||||
artifact_id=artifact_id,
|
||||
sensor_id=entity.sensor_id,
|
||||
predictions=predictions,
|
||||
confidence=sum(confidences) / len(confidences),
|
||||
model_type=artifact.model_type,
|
||||
)
|
||||
|
||||
def predict_batch(
|
||||
self,
|
||||
artifact_id: str,
|
||||
entities: Sequence[FeatureVector],
|
||||
) -> list[PredictionResult]:
|
||||
return [self.predict(artifact_id, entity) for entity in entities]
|
||||
|
||||
@staticmethod
|
||||
@@ -47,4 +88,4 @@ class Predictor:
|
||||
return self._registry.load_artifact(artifact_id)
|
||||
if self._pipeline is not None:
|
||||
return self._pipeline.export(artifact_id)
|
||||
raise RuntimeError("Predictor nicht initialisiert.")
|
||||
raise RuntimeError("Predictor nicht initialisiert.")
|
||||
|
||||
Reference in New Issue
Block a user