ML-005 vorbereiten: Registry, API-Routen und kompatibler Predictor
This commit is contained in:
@@ -1,21 +1,31 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from functools import lru_cache
|
||||
from typing import Sequence
|
||||
|
||||
from app.ml.feature_store import FeatureVector
|
||||
from app.ml.training import TrainingPipeline, TrainedArtifact
|
||||
from app.ml.registry.model_registry import ModelRegistry
|
||||
from app.ml.training import TrainedArtifact, TrainingPipeline
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Predictor:
|
||||
def __init__(self, pipeline: TrainingPipeline) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
pipeline: TrainingPipeline | None = None,
|
||||
registry: ModelRegistry | None = None,
|
||||
) -> None:
|
||||
if isinstance(pipeline, ModelRegistry) and registry is None:
|
||||
registry = pipeline
|
||||
pipeline = None
|
||||
if pipeline is None and registry is None:
|
||||
raise ValueError("Predictor erfordert TrainingPipeline oder ModelRegistry.")
|
||||
self._pipeline = pipeline
|
||||
self._registry = registry
|
||||
|
||||
def predict(self, artifact_id: str, entity: FeatureVector) -> str:
|
||||
artifact = self._pipeline.export(artifact_id)
|
||||
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."
|
||||
@@ -30,4 +40,11 @@ class Predictor:
|
||||
artifacts = list(pipeline._artifacts)
|
||||
if not artifacts:
|
||||
raise ValueError("Kein trainiertes Modell gefunden.")
|
||||
return pipeline.export(artifacts[-1])
|
||||
return pipeline.export(artifacts[-1])
|
||||
|
||||
def _get_artifact(self, artifact_id: str) -> TrainedArtifact:
|
||||
if self._registry is not None:
|
||||
return self._registry.load_artifact(artifact_id)
|
||||
if self._pipeline is not None:
|
||||
return self._pipeline.export(artifact_id)
|
||||
raise RuntimeError("Predictor nicht initialisiert.")
|
||||
3
app/ml/registry/__init__.py
Normal file
3
app/ml/registry/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .model_registry import ModelRegistry
|
||||
|
||||
__all__ = ["ModelRegistry"]
|
||||
37
app/ml/registry/model_registry.py
Normal file
37
app/ml/registry/model_registry.py
Normal file
@@ -0,0 +1,37 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Iterable
|
||||
|
||||
from app.ml.training import TrainedArtifact
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ModelRegistry:
|
||||
def __init__(self, root: str | Path) -> None:
|
||||
self._root = Path(root)
|
||||
self._root.mkdir(parents=True, exist_ok=True)
|
||||
self._artifacts: dict[str, TrainedArtifact] = {}
|
||||
|
||||
def register(self, artifact: TrainedArtifact) -> TrainedArtifact:
|
||||
self._artifacts[artifact.artifact_id] = artifact
|
||||
self._persist(artifact)
|
||||
return artifact
|
||||
|
||||
def load_artifact(self, artifact_id: str) -> TrainedArtifact:
|
||||
if artifact_id not in self._artifacts:
|
||||
raise KeyError(f"Artifact '{artifact_id}' nicht registriert.")
|
||||
return self._artifacts[artifact_id]
|
||||
|
||||
def list_models(self) -> Iterable[TrainedArtifact]:
|
||||
return list(self._artifacts.values())
|
||||
|
||||
def _persist(self, artifact: TrainedArtifact) -> None:
|
||||
target = self._root / f"{artifact.artifact_id}.json"
|
||||
target.write_text(
|
||||
f"{artifact.artifact_id}\t{','.join(artifact.supported_sensors)}\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
logger.info("Modell gespeichert: %s", target)
|
||||
Reference in New Issue
Block a user