Compare commits

...
4 Commits
Author SHA1 Message Date
Anush008 24dd472185 chore: updated model file path 2024-04-17 02:30:02 +05:30
Anush008 221b554228 test: nomic-ai/nomic-embed-text-v1.5-Q 2024-04-17 02:23:24 +05:30
Anush fff693b46d Merge branch 'removed-gcs' into QModels 2024-04-17 02:14:28 +05:30
Anush008 1dbef6b239 feat: Quantized models support 2024-04-17 02:13:58 +05:30
8 changed files with 78 additions and 124 deletions
+1 -89
View File
@@ -1,26 +1,4 @@
from pathlib import Path
from typing import List, Optional, Dict, Any
from huggingface_hub import snapshot_download
from huggingface_hub.utils import RepositoryNotFoundError
from loguru import logger
def locate_model_file(model_dir: Path, file_names: List[str]) -> Path:
"""
Find model path for both TransformerJS style `onnx` subdirectory structure and direct model weights structure used
by Optimum and Qdrant
"""
if not model_dir.is_dir():
raise ValueError(f"Provided model path '{model_dir}' is not a directory.")
for file_name in file_names:
file_paths = [path for path in model_dir.rglob(file_name) if path.is_file()]
if file_paths:
return file_paths[0]
raise ValueError(f"Could not find either of {', '.join(file_names)} in {model_dir}")
from typing import List, Dict, Any
class ModelManagement:
@@ -52,69 +30,3 @@ class ModelManagement:
return model
raise ValueError(f"Model {model_name} is not supported in {cls.__name__}.")
@classmethod
def download_files_from_huggingface(
cls, hf_source_repo: str, cache_dir: Optional[str] = None
) -> str:
"""
Downloads a model from HuggingFace Hub.
Args:
hf_source_repo (str): Name of the model on HuggingFace Hub, e.g. "qdrant/all-MiniLM-L6-v2-onnx".
cache_dir (Optional[str]): The path to the cache directory.
Returns:
Path: The path to the model directory.
"""
return snapshot_download(
repo_id=hf_source_repo,
allow_patterns=[
"*.onnx",
"*.onnx_data",
"config.json",
"tokenizer.json",
"tokenizer_config.json",
"special_tokens_map.json",
],
cache_dir=cache_dir,
)
@classmethod
def download_model(cls, model: Dict[str, Any], cache_dir: Path) -> Path:
"""
Downloads a model from HuggingFace Hub or Google Cloud Storage.
Args:
model (Dict[str, Any]): The model description.
Example:
```
{
"model": "BAAI/bge-base-en-v1.5",
"dim": 768,
"description": "Base English model, v1.5",
"size_in_GB": 0.44,
"sources": {
"hf": "qdrant/bge-base-en-v1.5-onnx-q",
}
}
```
cache_dir (str): The path to the cache directory.
Returns:
Path: The path to the downloaded model directory.
"""
hf_source = model.get("sources", {}).get("hf")
if hf_source:
try:
return Path(
cls.download_files_from_huggingface(hf_source, cache_dir=str(cache_dir))
)
except (EnvironmentError, RepositoryNotFoundError, ValueError) as e:
logger.error(
f"Could not download model from HuggingFace: {e}"
"Falling back to other sources."
)
raise ValueError(f"Could not download model {model['model']} from any source.")
+14 -13
View File
@@ -3,24 +3,25 @@ from pathlib import Path
import numpy as np
from tokenizers import Tokenizer, AddedToken
from huggingface_hub import hf_hub_download
def load_tokenizer(model_dir: Path, max_length: int = 512) -> Tokenizer:
config_path = model_dir / "config.json"
if not config_path.exists():
raise ValueError(f"Could not find config.json in {model_dir}")
def load_tokenizer(repo_id: str, cache_dir: Path, max_length: int = 512) -> Tokenizer:
config_path = hf_hub_download(
repo_id=repo_id, filename="config.json", cache_dir=str(cache_dir)
)
tokenizer_path = model_dir / "tokenizer.json"
if not tokenizer_path.exists():
raise ValueError(f"Could not find tokenizer.json in {model_dir}")
tokenizer_path = hf_hub_download(
repo_id=repo_id, filename="tokenizer.json", cache_dir=str(cache_dir)
)
tokenizer_config_path = model_dir / "tokenizer_config.json"
if not tokenizer_config_path.exists():
raise ValueError(f"Could not find tokenizer_config.json in {model_dir}")
tokenizer_config_path = hf_hub_download(
repo_id=repo_id, filename="tokenizer_config.json", cache_dir=str(cache_dir)
)
tokens_map_path = model_dir / "special_tokens_map.json"
if not tokens_map_path.exists():
raise ValueError(f"Could not find special_tokens_map.json in {model_dir}")
tokens_map_path = hf_hub_download(
repo_id=repo_id, filename="special_tokens_map.json", cache_dir=str(cache_dir)
)
with open(str(config_path)) as config_file:
config = json.load(config_file)
+19 -4
View File
@@ -6,11 +6,12 @@ from typing import Any, Dict, Generic, Iterable, List, Optional, Tuple, Type, Ty
import numpy as np
import onnxruntime as ort
from fastembed.common.model_management import locate_model_file
from fastembed.common.models import load_tokenizer
from fastembed.common.utils import iter_batch
from fastembed.parallel_processor import ParallelWorkerPool, Worker
from huggingface_hub import hf_hub_download
# Holds type of the embedding result
T = TypeVar("T")
@@ -34,8 +35,22 @@ class OnnxModel(Generic[T]):
"""
return onnx_input
def load_onnx_model(self, model_dir: Path, threads: Optional[int], max_length: int) -> None:
model_path = locate_model_file(model_dir, ["model.onnx", "model_optimized.onnx"])
def load_onnx_model(
self, model_description: dict, threads: Optional[int], cache_dir: Path
) -> None:
repo_id = model_description["sources"]["hf"]
model_file = model_description.get("model_file", "model.onnx")
# Some models require additional repo files.
# For eg: intfloat/multilingual-e5-large requires the model.onnx_data file.
# These can be specified within the "additional_files" option when describing the model properties
if additional_files := model_description.get("additional_files"):
for file in additional_files:
hf_hub_download(repo_id=repo_id, filename=file, cache_dir=str(cache_dir))
model_path = hf_hub_download(
repo_id=repo_id, filename=model_file, cache_dir=str(cache_dir)
)
# List of Execution Providers: https://onnxruntime.ai/docs/execution-providers
onnx_providers = ["CPUExecutionProvider"]
@@ -50,7 +65,7 @@ class OnnxModel(Generic[T]):
so.intra_op_num_threads = threads
so.inter_op_num_threads = threads
self.tokenizer = load_tokenizer(model_dir=model_dir, max_length=max_length)
self.tokenizer = load_tokenizer(repo_id, cache_dir)
self.model = ort.InferenceSession(
str(model_path), providers=onnx_providers, sess_options=so
)
+8 -9
View File
@@ -15,6 +15,7 @@ supported_splade_models = [
"sources": {
"hf": "Qdrant/SPLADE_PP_en_v1",
},
"model_file": "model.onnx",
},
{
"model": "prithivida/Splade_PP_en_v1",
@@ -24,6 +25,7 @@ supported_splade_models = [
"sources": {
"hf": "Qdrant/SPLADE_PP_en_v1",
},
"model_file": "model.onnx",
},
]
@@ -77,14 +79,11 @@ class SpladePP(SparseTextEmbeddingBase, OnnxModel[SparseEmbedding]):
super().__init__(model_name, cache_dir, threads, **kwargs)
self.model_name = model_name
self._model_description = self._get_model_description(model_name)
self._cache_dir = define_cache_dir(cache_dir)
self._model_dir = self.download_model(self._model_description, self._cache_dir)
self._max_length = 512
self.load_onnx_model(self._model_dir, self.threads, self._max_length)
self.load_onnx_model(
self._get_model_description(model_name),
threads,
define_cache_dir(cache_dir),
)
def embed(
self,
@@ -110,7 +109,7 @@ class SpladePP(SparseTextEmbeddingBase, OnnxModel[SparseEmbedding]):
"""
yield from self._embed_documents(
model_name=self.model_name,
cache_dir=str(self._cache_dir),
cache_dir=str(self.cache_dir),
documents=documents,
batch_size=batch_size,
parallel=parallel,
+3
View File
@@ -14,6 +14,8 @@ supported_multilingual_e5_models = [
"sources": {
"hf": "qdrant/multilingual-e5-large-onnx",
},
"model_file": "model.onnx",
"additional_files": ["model.onnx_data"],
},
{
"model": "sentence-transformers/paraphrase-multilingual-mpnet-base-v2",
@@ -23,6 +25,7 @@ supported_multilingual_e5_models = [
"sources": {
"hf": "xenova/paraphrase-multilingual-mpnet-base-v2",
},
"model_file": "onnx/model.onnx",
},
]
+2
View File
@@ -13,6 +13,7 @@ supported_jina_models = [
"description": "English embedding model supporting 8192 sequence length",
"size_in_GB": 0.52,
"sources": {"hf": "xenova/jina-embeddings-v2-base-en"},
"model_file": "onnx/model.onnx",
},
{
"model": "jinaai/jina-embeddings-v2-small-en",
@@ -20,6 +21,7 @@ supported_jina_models = [
"description": "English embedding model supporting 8192 sequence length",
"size_in_GB": 0.12,
"sources": {"hf": "xenova/jina-embeddings-v2-small-en"},
"model_file": "onnx/model.onnx",
},
]
+28 -9
View File
@@ -16,6 +16,7 @@ supported_onnx_models = [
"sources": {
"hf": "yashvardhan7/bge-base-en-onnx",
},
"model_file": "onnx/model.onnx",
},
{
"model": "BAAI/bge-base-en-v1.5",
@@ -25,6 +26,7 @@ supported_onnx_models = [
"sources": {
"hf": "qdrant/bge-base-en-v1.5-onnx-q",
},
"model_file": "model_optimized.onnx",
},
{
"model": "BAAI/bge-large-en-v1.5",
@@ -34,6 +36,7 @@ supported_onnx_models = [
"sources": {
"hf": "qdrant/bge-large-en-v1.5-onnx",
},
"model_file": "model.onnx",
},
{
"model": "BAAI/bge-small-en",
@@ -43,6 +46,7 @@ supported_onnx_models = [
"sources": {
"hf": "ggrn/bge-small-en",
},
"model_file": "onnx/model.onnx",
},
{
"model": "BAAI/bge-small-en-v1.5",
@@ -52,6 +56,7 @@ supported_onnx_models = [
"sources": {
"hf": "qdrant/bge-small-en-v1.5-onnx-q",
},
"model_file": "model_optimized.onnx",
},
{
"model": "BAAI/bge-small-zh-v1.5",
@@ -61,6 +66,7 @@ supported_onnx_models = [
"sources": {
"hf": "Xenova/bge-small-zh-v1.5",
},
"model_file": "onnx/model.onnx",
},
{
"model": "sentence-transformers/all-MiniLM-L6-v2",
@@ -70,6 +76,7 @@ supported_onnx_models = [
"sources": {
"hf": "qdrant/all-MiniLM-L6-v2-onnx",
},
"model_file": "model.onnx",
},
{
"model": "sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2",
@@ -79,6 +86,7 @@ supported_onnx_models = [
"sources": {
"hf": "qdrant/paraphrase-multilingual-MiniLM-L12-v2-onnx-Q",
},
"model_file": "model_optimized.onnx",
},
{
"model": "nomic-ai/nomic-embed-text-v1",
@@ -88,6 +96,7 @@ supported_onnx_models = [
"sources": {
"hf": "nomic-ai/nomic-embed-text-v1",
},
"model_file": "onnx/model.onnx",
},
{
"model": "nomic-ai/nomic-embed-text-v1.5",
@@ -97,6 +106,17 @@ supported_onnx_models = [
"sources": {
"hf": "nomic-ai/nomic-embed-text-v1.5",
},
"model_file": "onnx/model.onnx",
},
{
"model": "nomic-ai/nomic-embed-text-v1.5-Q",
"dim": 768,
"description": "Quantized 8192 context length english model",
"size_in_GB": 0.13,
"sources": {
"hf": "nomic-ai/nomic-embed-text-v1.5",
},
"model_file": "onnx/model_quantized.onnx",
},
{
"model": "thenlper/gte-large",
@@ -106,6 +126,7 @@ supported_onnx_models = [
"sources": {
"hf": "qdrant/gte-large-onnx",
},
"model_file": "model.onnx",
},
{
"model": "mixedbread-ai/mxbai-embed-large-v1",
@@ -115,6 +136,7 @@ supported_onnx_models = [
"sources": {
"hf": "mixedbread-ai/mxbai-embed-large-v1",
},
"model_file": "onnx/model.onnx",
},
]
@@ -153,14 +175,11 @@ class OnnxTextEmbedding(TextEmbeddingBase, OnnxModel[np.ndarray]):
super().__init__(model_name, cache_dir, threads, **kwargs)
self.model_name = model_name
self._model_description = self._get_model_description(model_name)
self._cache_dir = define_cache_dir(cache_dir)
self._model_dir = self.download_model(self._model_description, self._cache_dir)
self._max_length = 512
self.load_onnx_model(self._model_dir, self.threads, self._max_length)
self.load_onnx_model(
self._get_model_description(model_name),
threads,
define_cache_dir(cache_dir),
)
def embed(
self,
@@ -186,7 +205,7 @@ class OnnxTextEmbedding(TextEmbeddingBase, OnnxModel[np.ndarray]):
"""
yield from self._embed_documents(
model_name=self.model_name,
cache_dir=str(self._cache_dir),
cache_dir=str(self.cache_dir),
documents=documents,
batch_size=batch_size,
parallel=parallel,
+3
View File
@@ -28,6 +28,9 @@ CANONICAL_VECTOR_VALUES = {
),
"thenlper/gte-large": np.array([-0.01920587, 0.00113156, -0.00708992, -0.00632304, -0.04025577]),
"mixedbread-ai/mxbai-embed-large-v1": np.array([0.02295546, 0.03196154, 0.016512, -0.04031524, -0.0219634]),
"nomic-ai/nomic-embed-text-v1.5-Q": np.array(
[-0.01554983, 0.0129992, -0.17909265, -0.01062993, 0.00512859]
),
}