Spaces:
Running
Running
| 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") | |