Skip to content

Commit e70adff

Browse files
authored
Release 0.4.3 version with sentence-transformers fixes (#81)
* Pin `0.4.3dev0` version for upcoming release * Fix `sentence-transformers` unit tests * Move `peft` out of core dependencies `peft` requires `torch` as a mandatory dependency, so adding `peft` as a core dependency means that `torch` will be installed i.e. even when `pip install -e ".[quality]"` which slows things a bit, since `torch` installation takes time; and in some cases is not needed, so moving `peft` into the `torch` extra makes the most sense for the moment (not final). * Fix `trust_remote_code` propagation for `sentence-transformers` * Add missing return type-hint * Fix `test__load_repository_from_gcs` to rely on `create_anonymous_client` * Fix `kwargs` propagation for `sentence-transformers` * Bump version to 0.4.3
1 parent 6777c55 commit e70adff

File tree

4 files changed

+63
-22
lines changed

4 files changed

+63
-22
lines changed

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
# We don't declare our dependency on transformers here because we build with
66
# different packages for different variants
77

8-
VERSION = "0.4.2"
8+
VERSION = "0.4.3"
99

1010
# Ubuntu packages
1111
# libsndfile1-dev: torchaudio requires the development version of the libsndfile package which can be installed via a system package manager. On Ubuntu it can be installed as follows: apt install libsndfile1-dev
@@ -15,7 +15,6 @@
1515
install_requires = [
1616
"transformers[sklearn,sentencepiece,audio,vision,sentencepiece]==4.44.0",
1717
"huggingface_hub[hf_transfer]==0.24.5",
18-
"peft==0.12.0",
1918
# vision
2019
"Pillow",
2120
"librosa",
@@ -34,7 +33,9 @@
3433

3534
extras["st"] = ["sentence_transformers==2.7.0"]
3635
extras["diffusers"] = ["diffusers==0.30.0", "accelerate==0.33.0"]
37-
extras["torch"] = ["torch==2.2.2", "torchvision", "torchaudio"]
36+
# Includes `peft` as PEFT requires `torch` so having `peft` as a core dependency
37+
# means that `torch` will be installed even if the `torch` extra is not specified.
38+
extras["torch"] = ["torch==2.2.2", "torchvision", "torchaudio", "peft==0.12.0"]
3839
extras["test"] = [
3940
"pytest==7.2.1",
4041
"pytest-xdist",

src/huggingface_inference_toolkit/sentence_transformers_utils.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,30 @@ def is_sentence_transformers_available():
1212

1313

1414
class SentenceSimilarityPipeline:
15-
def __init__(self, model_dir: str, device: str = None): # needs "cuda" for GPU
16-
self.model = SentenceTransformer(model_dir, device=device)
15+
def __init__(self, model_dir: str, device: str = None, **kwargs): # needs "cuda" for GPU
16+
self.model = SentenceTransformer(model_dir, device=device, **kwargs)
1717

1818
def __call__(self, inputs=None):
19-
embeddings1 = self.model.encode(inputs["source_sentence"], convert_to_tensor=True)
19+
embeddings1 = self.model.encode(
20+
inputs["source_sentence"], convert_to_tensor=True
21+
)
2022
embeddings2 = self.model.encode(inputs["sentences"], convert_to_tensor=True)
2123
similarities = util.pytorch_cos_sim(embeddings1, embeddings2).tolist()[0]
2224
return {"similarities": similarities}
2325

2426

2527
class SentenceEmbeddingPipeline:
26-
def __init__(self, model_dir: str, device: str = None): # needs "cuda" for GPU
27-
self.model = SentenceTransformer(model_dir, device=device)
28+
def __init__(self, model_dir: str, device: str = None, **kwargs): # needs "cuda" for GPU
29+
self.model = SentenceTransformer(model_dir, device=device, **kwargs)
2830

2931
def __call__(self, inputs):
3032
embeddings = self.model.encode(inputs).tolist()
3133
return {"embeddings": embeddings}
3234

3335

3436
class RankingPipeline:
35-
def __init__(self, model_dir: str, device: str = None): # needs "cuda" for GPU
36-
self.model = CrossEncoder(model_dir, device=device)
37+
def __init__(self, model_dir: str, device: str = None, **kwargs): # needs "cuda" for GPU
38+
self.model = CrossEncoder(model_dir, device=device, **kwargs)
3739

3840
def __call__(self, inputs):
3941
scores = self.model.predict(inputs).tolist()
@@ -47,12 +49,16 @@ def __call__(self, inputs):
4749
}
4850

4951

50-
def get_sentence_transformers_pipeline(
51-
task=None,
52-
model_dir=None,
53-
device=-1,
54-
**kwargs
55-
):
52+
def get_sentence_transformers_pipeline(task=None, model_dir=None, device=-1, **kwargs):
5653
device = "cuda" if device == 0 else "cpu"
57-
pipeline = SENTENCE_TRANSFORMERS_TASKS[task](model_dir=model_dir, device=device, **kwargs)
58-
return pipeline
54+
55+
kwargs.pop("tokenizer", None)
56+
kwargs.pop("framework", None)
57+
58+
if task not in SENTENCE_TRANSFORMERS_TASKS:
59+
raise ValueError(
60+
f"Unknown task {task}. Available tasks are: {', '.join(SENTENCE_TRANSFORMERS_TASKS.keys())}"
61+
)
62+
return SENTENCE_TRANSFORMERS_TASKS[task](
63+
model_dir=model_dir, device=device, **kwargs
64+
)

src/huggingface_inference_toolkit/vertex_ai_utils.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99

1010
# copied from https://github.com/googleapis/python-aiplatform/blob/94d838d8cfe1599bc2d706e66080c05108821986/google/cloud/aiplatform/utils/prediction_utils.py#L121
11-
def _load_repository_from_gcs(artifact_uri: str, target_dir: Union[str, Path] = "/tmp"):
11+
def _load_repository_from_gcs(
12+
artifact_uri: str, target_dir: Union[str, Path] = "/tmp"
13+
) -> str:
1214
"""
1315
Load files from GCS path to target_dir
1416
"""

tests/unit/test_vertex_ai_utils.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
from pathlib import Path
22

3-
from huggingface_inference_toolkit.vertex_ai_utils import _load_repository_from_gcs
4-
53

64
def test__load_repository_from_gcs():
7-
"""Tests the `_load_repository_from_gcs` function against a public artifact URI.
5+
"""Tests the `_load_repository_from_gcs` function against a public artifact URI. But the
6+
function is overriden since the client needs to be anonymous temporarily, as we're testing
7+
against a publicly accessible artifact.
88
99
References:
1010
- https://cloud.google.com/storage/docs/public-datasets/era5
@@ -14,6 +14,38 @@ def test__load_repository_from_gcs():
1414
public_artifact_uri = (
1515
"gs://gcp-public-data-arco-era5/raw/date-variable-static/2021/12/31/soil_type"
1616
)
17+
18+
def _load_repository_from_gcs(artifact_uri: str, target_dir: Path) -> str:
19+
"""Temporarily override of the `_load_repository_from_gcs` function."""
20+
import re
21+
22+
from google.cloud import storage
23+
from huggingface_inference_toolkit.vertex_ai_utils import GCS_URI_PREFIX
24+
25+
if isinstance(target_dir, str):
26+
target_dir = Path(target_dir)
27+
28+
if artifact_uri.startswith(GCS_URI_PREFIX):
29+
matches = re.match(f"{GCS_URI_PREFIX}(.*?)/(.*)", artifact_uri)
30+
bucket_name, prefix = matches.groups() # type: ignore
31+
32+
gcs_client = storage.Client.create_anonymous_client()
33+
blobs = gcs_client.list_blobs(bucket_name, prefix=prefix)
34+
for blob in blobs:
35+
name_without_prefix = blob.name[len(prefix) :]
36+
name_without_prefix = (
37+
name_without_prefix[1:]
38+
if name_without_prefix.startswith("/")
39+
else name_without_prefix
40+
)
41+
file_split = name_without_prefix.split("/")
42+
directory = target_dir / Path(*file_split[0:-1])
43+
directory.mkdir(parents=True, exist_ok=True)
44+
if name_without_prefix and not name_without_prefix.endswith("/"):
45+
blob.download_to_filename(target_dir / name_without_prefix)
46+
47+
return str(target_dir.absolute())
48+
1749
target_dir = Path.cwd() / "target"
1850
target_dir_path = _load_repository_from_gcs(
1951
artifact_uri=public_artifact_uri, target_dir=target_dir

0 commit comments

Comments
 (0)