doum
4 天以前 ce44d803b73a65b2cc31db5bcc662139029463d3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# -*- coding: utf-8 -*-
import json
import logging
import os
from typing import List, Optional, Tuple
 
import numpy as np
import onnxruntime as ort
from PIL import Image
 
logger = logging.getLogger(__name__)
 
IMAGENET_MEAN = np.array([0.485, 0.456, 0.406], dtype=np.float32)
IMAGENET_STD = np.array([0.229, 0.224, 0.225], dtype=np.float32)
 
 
class OnnxClassifier:
    def __init__(self, model_path: str, image_size: int = 224):
        self.image_size = image_size
        self.session: Optional[ort.InferenceSession] = None
        if model_path and os.path.isfile(model_path):
            self.session = ort.InferenceSession(
                model_path,
                providers=["CPUExecutionProvider"],
            )
            logger.info("加载 ONNX: %s", model_path)
 
    @property
    def loaded(self) -> bool:
        return self.session is not None
 
    def preprocess(self, image_path: str) -> np.ndarray:
        img = Image.open(image_path).convert("RGB").resize((self.image_size, self.image_size))
        arr = np.array(img).astype(np.float32) / 255.0
        arr = (arr - IMAGENET_MEAN) / IMAGENET_STD
        return arr.transpose(2, 0, 1)[None]
 
    def predict_batch(self, image_paths: List[str], batch_size: int = 16) -> List[float]:
        if not self.session:
            return [0.0] * len(image_paths)
        scores = []
        for i in range(0, len(image_paths), batch_size):
            batch_paths = image_paths[i : i + batch_size]
            batch = np.concatenate([self.preprocess(p) for p in batch_paths], axis=0)
            logits = self.session.run(None, {"input": batch})[0]
            for logit in logits:
                scores.append(float(1.0 / (1.0 + np.exp(-logit[0]))))
        return scores
 
 
class ModelRegistry:
    def __init__(self, model_dir: str):
        self.model_dir = model_dir
        self.version = "unknown"
        self.image_size = 224
        self.storefront: Optional[OnnxClassifier] = None
        self.handover: Optional[OnnxClassifier] = None
        self._load()
 
    def _load(self):
        version_path = os.path.join(self.model_dir, "version.json")
        sf_name = ho_name = None
        if os.path.isfile(version_path):
            with open(version_path, encoding="utf-8") as f:
                meta = json.load(f)
            self.version = meta.get("model_version", "1.0.0")
            self.image_size = int(meta.get("image_size", 224))
            sf_name = meta.get("storefront_model")
            ho_name = meta.get("handover_model")
 
        def resolve(name: str, fallback: str) -> str:
            if name:
                path = os.path.join(self.model_dir, name)
                if os.path.isfile(path):
                    return path
            for suffix in (f"{fallback}_int8.onnx", f"{fallback}.onnx"):
                path = os.path.join(self.model_dir, suffix)
                if os.path.isfile(path):
                    return path
            return ""
 
        sf_path = resolve(sf_name, "storefront")
        ho_path = resolve(ho_name, "handover")
        self.storefront = OnnxClassifier(sf_path, self.image_size) if sf_path else OnnxClassifier("", self.image_size)
        self.handover = OnnxClassifier(ho_path, self.image_size) if ho_path else OnnxClassifier("", self.image_size)
 
    @property
    def ready(self) -> bool:
        return self.storefront.loaded and self.handover.loaded
 
 
def score_frames(
    registry: ModelRegistry,
    frames: List[Tuple[float, str]],
) -> Tuple[List[Tuple[float, float]], List[Tuple[float, float]]]:
    times = [f[0] for f in frames]
    paths = [f[1] for f in frames]
    sf_scores = registry.storefront.predict_batch(paths)
    ho_scores = registry.handover.predict_batch(paths)
    return list(zip(times, sf_scores)), list(zip(times, ho_scores))