mirror of
				https://github.com/KevinMidboe/immich.git
				synced 2025-10-29 17:40:28 +00:00 
			
		
		
		
	* model cache * fixed revalidation when using cache namespace * fixed ttl not being set, added lock
		
			
				
	
	
		
			118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			118 lines
		
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
import torch
 | 
						|
from insightface.app import FaceAnalysis
 | 
						|
from pathlib import Path
 | 
						|
import os
 | 
						|
 | 
						|
from transformers import pipeline, Pipeline
 | 
						|
from sentence_transformers import SentenceTransformer
 | 
						|
from typing import Any
 | 
						|
import cv2 as cv
 | 
						|
 | 
						|
cache_folder = os.getenv("MACHINE_LEARNING_CACHE_FOLDER", "/cache")
 | 
						|
device = "cuda" if torch.cuda.is_available() else "cpu"
 | 
						|
 | 
						|
 | 
						|
def get_model(model_name: str, model_type: str, **model_kwargs):
 | 
						|
    """
 | 
						|
    Instantiates the specified model.
 | 
						|
 | 
						|
    Args:
 | 
						|
        model_name: Name of model in the model hub used for the task.
 | 
						|
        model_type: Model type or task, which determines which model zoo is used.
 | 
						|
            `facial-recognition` uses Insightface, while all other models use the HF Model Hub.
 | 
						|
 | 
						|
            Options:
 | 
						|
                `image-classification`, `clip`,`facial-recognition`, `tokenizer`, `processor`
 | 
						|
 | 
						|
    Returns:
 | 
						|
        model: The requested model.
 | 
						|
    """
 | 
						|
 | 
						|
    cache_dir = _get_cache_dir(model_name, model_type)
 | 
						|
    match model_type:
 | 
						|
        case "facial-recognition":
 | 
						|
            model = _load_facial_recognition(
 | 
						|
                model_name, cache_dir=cache_dir, **model_kwargs
 | 
						|
            )
 | 
						|
        case "clip":
 | 
						|
            model = SentenceTransformer(
 | 
						|
                model_name, cache_folder=cache_dir, **model_kwargs
 | 
						|
            )
 | 
						|
        case _:
 | 
						|
            model = pipeline(
 | 
						|
                model_type,
 | 
						|
                model_name,
 | 
						|
                model_kwargs={"cache_dir": cache_dir, **model_kwargs},
 | 
						|
            )
 | 
						|
 | 
						|
    return model
 | 
						|
 | 
						|
 | 
						|
def run_classification(
 | 
						|
    model: Pipeline, image_path: str, min_score: float | None = None
 | 
						|
):
 | 
						|
    predictions: list[dict[str, Any]] = model(image_path)  # type: ignore
 | 
						|
    result = {
 | 
						|
        tag
 | 
						|
        for pred in predictions
 | 
						|
        for tag in pred["label"].split(", ")
 | 
						|
        if min_score is None or pred["score"] >= min_score
 | 
						|
    }
 | 
						|
 | 
						|
    return list(result)
 | 
						|
 | 
						|
 | 
						|
def run_facial_recognition(
 | 
						|
    model: FaceAnalysis, image_path: str
 | 
						|
) -> list[dict[str, Any]]:
 | 
						|
    img = cv.imread(image_path)
 | 
						|
    height, width, _ = img.shape
 | 
						|
    results = []
 | 
						|
    faces = model.get(img)
 | 
						|
 | 
						|
    for face in faces:
 | 
						|
        x1, y1, x2, y2 = face.bbox
 | 
						|
 | 
						|
        results.append(
 | 
						|
            {
 | 
						|
                "imageWidth": width,
 | 
						|
                "imageHeight": height,
 | 
						|
                "boundingBox": {
 | 
						|
                    "x1": round(x1),
 | 
						|
                    "y1": round(y1),
 | 
						|
                    "x2": round(x2),
 | 
						|
                    "y2": round(y2),
 | 
						|
                },
 | 
						|
                "score": face.det_score.item(),
 | 
						|
                "embedding": face.normed_embedding.tolist(),
 | 
						|
            }
 | 
						|
        )
 | 
						|
    return results
 | 
						|
 | 
						|
 | 
						|
def _load_facial_recognition(
 | 
						|
    model_name: str,
 | 
						|
    min_face_score: float | None = None,
 | 
						|
    cache_dir: Path | str | None = None,
 | 
						|
    **model_kwargs,
 | 
						|
):
 | 
						|
    if cache_dir is None:
 | 
						|
        cache_dir = _get_cache_dir(model_name, "facial-recognition")
 | 
						|
    if isinstance(cache_dir, Path):
 | 
						|
        cache_dir = cache_dir.as_posix()
 | 
						|
    if min_face_score is None:
 | 
						|
        min_face_score = float(os.getenv("MACHINE_LEARNING_MIN_FACE_SCORE", 0.7))
 | 
						|
 | 
						|
    model = FaceAnalysis(
 | 
						|
        name=model_name,
 | 
						|
        root=cache_dir,
 | 
						|
        allowed_modules=["detection", "recognition"],
 | 
						|
        **model_kwargs,
 | 
						|
    )
 | 
						|
    model.prepare(ctx_id=0, det_thresh=min_face_score, det_size=(640, 640))
 | 
						|
    return model
 | 
						|
 | 
						|
 | 
						|
def _get_cache_dir(model_name: str, model_type: str) -> Path:
 | 
						|
    return Path(cache_folder, device, model_type, model_name)
 |