Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
_embedding_distance.py191 linesDownload Raw Back to _internal
1from __future__ import annotations2 3import logging4from collections.abc import Sequence5from typing import (6    TYPE_CHECKING,7    Any,8    Callable,9    Literal,10    Optional,11    Union,12)13 14from typing_extensions import TypedDict15 16if TYPE_CHECKING:17    import numpy as np  # type: ignore18 19 20logger = logging.getLogger(__name__)21 22Matrix = Union[list[list[float]], list[Any], Any]23 24 25def cosine_similarity(X: Matrix, Y: Matrix) -> np.ndarray:26    """Row-wise cosine similarity between two equal-width matrices."""27    import numpy as np28 29    if len(X) == 0 or len(Y) == 0:30        return np.array([])31 32    X = np.array(X)33    Y = np.array(Y)34    if X.shape[1] != Y.shape[1]:35        raise ValueError(36            f"Number of columns in X and Y must be the same. X has shape {X.shape} "37            f"and Y has shape {Y.shape}."38        )39    try:40        import simsimd as simd  # type: ignore41 42        X = np.array(X, dtype=np.float32)43        Y = np.array(Y, dtype=np.float32)44        Z = 1 - simd.cdist(X, Y, metric="cosine")45        if isinstance(Z, float):46            return np.array([Z])47        return np.array(Z)48    except ImportError:49        logger.debug(50            "Unable to import simsimd, defaulting to NumPy implementation. If you want "51            "to use simsimd please install with `pip install simsimd`."52        )53        X_norm = np.linalg.norm(X, axis=1)54        Y_norm = np.linalg.norm(Y, axis=1)55        # Ignore divide by zero errors run time warnings as those are handled below.56        with np.errstate(divide="ignore", invalid="ignore"):57            similarity = np.dot(X, Y.T) / np.outer(X_norm, Y_norm)58        similarity[np.isnan(similarity) | np.isinf(similarity)] = 0.059        return similarity60 61 62def _get_openai_encoder() -> Callable[[Sequence[str]], Sequence[Sequence[float]]]:63    """Get the OpenAI GPT-3 encoder."""64    try:65        from openai import Client as OpenAIClient66    except ImportError:67        raise ImportError(68            "THe default encoder for the EmbeddingDistance class uses the OpenAI API. "69            "Please either install the openai library with `pip install openai` or "70            "provide a custom encoder function (Callable[[str], Sequence[float]])."71        )72 73    def encode_text(texts: Sequence[str]) -> Sequence[Sequence[float]]:74        client = OpenAIClient()75        response = client.embeddings.create(76            input=list(texts), model="text-embedding-3-small"77        )78        return [d.embedding for d in response.data]79 80    return encode_text81 82 83class EmbeddingConfig(TypedDict, total=False):84    encoder: Callable[[list[str]], Sequence[Sequence[float]]]85    metric: Literal["cosine", "euclidean", "manhattan", "chebyshev", "hamming"]86 87 88class EmbeddingDistance:89    def __init__(90        self,91        config: Optional[EmbeddingConfig] = None,92    ):93        config = config or {}94        self.distance = config.get("metric") or "cosine"95        self.encoder = config.get("encoder") or _get_openai_encoder()96 97    def evaluate(98        self,99        prediction: str,100        reference: str,101    ) -> float:102        try:103            import numpy as np104        except ImportError:105            raise ImportError(106                "The EmbeddingDistance class requires NumPy. Please install it with "107                "`pip install numpy`."108            )109        embeddings = self.encoder([prediction, reference])110        vector = np.array(embeddings)111        return self._compute_distance(vector[0], vector[1]).item()112 113    def _compute_distance(self, a: np.ndarray, b: np.ndarray) -> np.floating:114        if self.distance == "cosine":115            return self._cosine_distance(a, b)  # type: ignore116        elif self.distance == "euclidean":117            return self._euclidean_distance(a, b)118        elif self.distance == "manhattan":119            return self._manhattan_distance(a, b)120        elif self.distance == "chebyshev":121            return self._chebyshev_distance(a, b)122        elif self.distance == "hamming":123            return self._hamming_distance(a, b)124        else:125            raise ValueError(f"Invalid distance metric: {self.distance}")126 127    @staticmethod128    def _cosine_distance(a: np.ndarray, b: np.ndarray) -> np.ndarray:129        """Compute the cosine distance between two vectors.130 131        Args:132            a (np.ndarray): The first vector.133            b (np.ndarray): The second vector.134 135        Returns:136            np.ndarray: The cosine distance.137        """138        return 1.0 - cosine_similarity([a], [b])139 140    @staticmethod141    def _euclidean_distance(a: np.ndarray, b: np.ndarray) -> np.floating:142        """Compute the Euclidean distance between two vectors.143 144        Args:145            a (np.ndarray): The first vector.146            b (np.ndarray): The second vector.147 148        Returns:149            np.floating: The Euclidean distance.150        """151        return np.linalg.norm(a - b)152 153    @staticmethod154    def _manhattan_distance(a: np.ndarray, b: np.ndarray) -> np.floating:155        """Compute the Manhattan distance between two vectors.156 157        Args:158            a (np.ndarray): The first vector.159            b (np.ndarray): The second vector.160 161        Returns:162            np.floating: The Manhattan distance.163        """164        return np.sum(np.abs(a - b))165 166    @staticmethod167    def _chebyshev_distance(a: np.ndarray, b: np.ndarray) -> np.floating:168        """Compute the Chebyshev distance between two vectors.169 170        Args:171            a (np.ndarray): The first vector.172            b (np.ndarray): The second vector.173 174        Returns:175            np.floating: The Chebyshev distance.176        """177        return np.max(np.abs(a - b))178 179    @staticmethod180    def _hamming_distance(a: np.ndarray, b: np.ndarray) -> np.floating:181        """Compute the Hamming distance between two vectors.182 183        Args:184            a (np.ndarray): The first vector.185            b (np.ndarray): The second vector.186 187        Returns:188            np.floating: The Hamming distance.189        """190        return np.mean(a != b)191 
codekingpro/portable-devtools · Team Ai