derm-fastapi-backend / app /services /derm_backbone.py
Daniel Huynh
Deploy FastAPI derm backend to Hugging Face Spaces
cb92718
from pathlib import Path
from typing import Tuple
import numpy as np
import tensorflow as tf
from huggingface_hub import snapshot_download
from app.services.preprocessing import image_bytes_to_tf_string_tensor
class DermFoundationBackbone:
"""
Thin wrapper around the Google Derm Foundation SavedModel.
It converts image bytes into the model's serialized tf.Example input
and returns the 6144-d embedding.
"""
def __init__(
self,
repo_id: str = "google/derm-foundation",
token: str | None = None,
local_files_only: bool = False,
image_size: int = 448,
) -> None:
self.repo_id = repo_id
self.image_size: Tuple[int, int] = (image_size, image_size)
model_path = snapshot_download(
repo_id=repo_id,
token=token,
local_files_only=local_files_only,
)
self.model_path = Path(model_path)
self.model = tf.saved_model.load(str(self.model_path))
self.infer = self.model.signatures["serving_default"]
def image_to_embedding(self, image_bytes: bytes) -> np.ndarray:
"""
Return embedding with shape [1, embedding_dim].
Derm Foundation normally returns key: "embedding".
"""
tf_inputs = image_bytes_to_tf_string_tensor(image_bytes, img_size=self.image_size)
# Your notebook used infer(inputs=tf_inputs). Keep that first.
try:
output = self.infer(inputs=tf_inputs)
except TypeError:
output = self.infer(tf_inputs)
if "embedding" not in output:
available = ", ".join(output.keys())
raise KeyError(f"Expected output key 'embedding'. Available keys: {available}")
return output["embedding"].numpy().astype("float32")