dhvani / core /custom_runner.py
aaronmphilip's picture
Deploy DHVANI inference backend
21132b7 verified
Raw
History Blame Contribute Delete
2.85 kB
"""DHVANI proprietary custom model runner."""
from __future__ import annotations
import json
import logging
from pathlib import Path
import numpy as np
import torch
from core.config import SAMPLE_RATE, custom_model_path
from core.dhvani_head import BACKBONE_ID, DhvaniCustomModel, MAX_SAMPLES
logger = logging.getLogger("dhvani.custom")
class CustomDhvaniDetector:
"""Loads models/dhvani-custom.pt trained via training/train_dhvani_head.py."""
def __init__(self, checkpoint_path: str | None = None, device: str | None = None) -> None:
self.device = device or ("cuda" if torch.cuda.is_available() else "cpu")
self.checkpoint_path = checkpoint_path or custom_model_path()
self._model: DhvaniCustomModel | None = None
self._backbone_id = BACKBONE_ID
self._fake_label_index = 1
self._metadata: dict = {}
@property
def enabled(self) -> bool:
return bool(self.checkpoint_path) and Path(self.checkpoint_path).exists()
def load(self) -> None:
if not self.enabled:
return
if self._model is not None:
return
logger.info("Loading DHVANI custom model from %s", self.checkpoint_path)
payload = torch.load(self.checkpoint_path, map_location="cpu", weights_only=False)
self._backbone_id = payload.get("backbone_id", self._backbone_id)
self._fake_label_index = int(payload.get("fake_label_index", 1))
self._metadata = {k: v for k, v in payload.items() if k != "head_state_dict"}
self._model = DhvaniCustomModel(backbone_id=self._backbone_id)
self._model.head.load_state_dict(payload["head_state_dict"])
self._model.to(self.device)
self._model.eval()
@property
def loaded(self) -> bool:
return self._model is not None
@property
def model_id(self) -> str:
version = self._metadata.get("version", "")
if version:
return str(version)
return "dhvani-custom-head"
@property
def version(self) -> str:
return str(self._metadata.get("version", "unknown"))
@property
def metadata(self) -> dict:
return dict(self._metadata)
def fake_probability(self, waveform: np.ndarray) -> float:
if not self.enabled:
return 0.0
self.load()
assert self._model is not None
if waveform.size > MAX_SAMPLES:
waveform = waveform[:MAX_SAMPLES]
if waveform.size < SAMPLE_RATE:
waveform = np.pad(waveform, (0, SAMPLE_RATE - waveform.size))
tensor = torch.from_numpy(waveform.astype(np.float32)).unsqueeze(0).to(self.device)
with torch.no_grad():
logits = self._model(tensor)
probs = torch.softmax(logits, dim=-1).cpu().numpy()[0]
return float(probs[self._fake_label_index])