orient_express 2.1.2__tar.gz → 2.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {orient_express-2.1.2 → orient_express-2.2.0}/PKG-INFO +1 -1
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/predictors/__init__.py +8 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/predictors/classification.py +0 -4
- orient_express-2.2.0/orient_express/predictors/feature_extraction.py +59 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/predictors/multi_label_classification.py +0 -4
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/vertex.py +9 -8
- {orient_express-2.1.2 → orient_express-2.2.0}/pyproject.toml +1 -1
- {orient_express-2.1.2 → orient_express-2.2.0}/README.md +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/__init__.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/deployment.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/model_wrapper.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/predictors/instance_segmentation.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/predictors/object_detection.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/predictors/predictor.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/predictors/semantic_segmentation.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/sklearn_pipeline.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/utils/colors.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/utils/gs.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/utils/image_processor.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/utils/paths.py +0 -0
- {orient_express-2.1.2 → orient_express-2.2.0}/orient_express/utils/retry.py +0 -0
|
@@ -21,6 +21,7 @@ from .multi_label_classification import (
|
|
|
21
21
|
MultiLabelClassificationPredictor,
|
|
22
22
|
MultiLabelClassificationPrediction,
|
|
23
23
|
)
|
|
24
|
+
from .feature_extraction import FeatureExtractionPredictor, FeaturePrediction
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
def get_predictor(dir: str, device: str = "cpu"):
|
|
@@ -62,6 +63,8 @@ def get_predictor(dir: str, device: str = "cpu"):
|
|
|
62
63
|
return load_image_predictor(
|
|
63
64
|
MultiLabelClassificationPredictor, dir, metadata, device
|
|
64
65
|
)
|
|
66
|
+
elif model_type == FeatureExtractionPredictor.model_type:
|
|
67
|
+
return load_feature_extractor(dir, metadata, device)
|
|
65
68
|
else:
|
|
66
69
|
raise Exception(f"Unknown model_type '{model_type}'")
|
|
67
70
|
|
|
@@ -74,3 +77,8 @@ def load_image_predictor(
|
|
|
74
77
|
raise Exception("No classes defined in metadata.yaml")
|
|
75
78
|
classes = metadata["classes"]
|
|
76
79
|
return model_type(onnx_path, classes, device)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def load_feature_extractor(dir: str, metadata: dict, device: str = "cpu"):
|
|
83
|
+
onnx_path = os.path.join(dir, metadata["model_file"])
|
|
84
|
+
return FeatureExtractionPredictor(onnx_path, device)
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
|
|
3
|
-
import cv2
|
|
4
|
-
import numpy as np
|
|
5
3
|
from PIL import Image
|
|
6
4
|
|
|
7
5
|
from .predictor import OnnxSessionWrapper, ImagePredictor
|
|
@@ -24,9 +22,7 @@ class ClassificationPrediction:
|
|
|
24
22
|
class OnnxClassifier(OnnxSessionWrapper):
|
|
25
23
|
def __call__(self, pil_images: list[Image.Image]):
|
|
26
24
|
images_array = self.collate_images(pil_images)
|
|
27
|
-
|
|
28
25
|
input_dict = {self.input_names[0]: images_array}
|
|
29
|
-
|
|
30
26
|
scores = self.session.run(None, input_dict)[0]
|
|
31
27
|
return scores
|
|
32
28
|
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from dataclasses import dataclass
|
|
3
|
+
|
|
4
|
+
import yaml
|
|
5
|
+
import numpy as np
|
|
6
|
+
from PIL import Image
|
|
7
|
+
|
|
8
|
+
from .predictor import OnnxSessionWrapper, ImagePredictor
|
|
9
|
+
from ..utils.paths import get_metadata_path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass
|
|
13
|
+
class FeaturePrediction:
|
|
14
|
+
feature: np.ndarray
|
|
15
|
+
|
|
16
|
+
def to_dict(self):
|
|
17
|
+
return {
|
|
18
|
+
"feature": self.feature.tolist(),
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class OnnxFeatureExtractor(OnnxSessionWrapper):
|
|
23
|
+
def __call__(self, pil_images: list[Image.Image]):
|
|
24
|
+
images_array = self.collate_images(pil_images)
|
|
25
|
+
input_dict = {self.input_names[0]: images_array}
|
|
26
|
+
features = self.session.run(None, input_dict)[0]
|
|
27
|
+
return features
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
class FeatureExtractionPredictor(ImagePredictor):
|
|
31
|
+
model_type = "feature-extraction-onnx"
|
|
32
|
+
backend_model = OnnxFeatureExtractor
|
|
33
|
+
|
|
34
|
+
def __init__(self, model_path: str, device: str = "cpu"):
|
|
35
|
+
self.model = self.backend_model(model_path, device)
|
|
36
|
+
self.model_path = model_path
|
|
37
|
+
|
|
38
|
+
def predict(self, images: list[Image.Image]) -> list[FeaturePrediction]:
|
|
39
|
+
if not images:
|
|
40
|
+
return []
|
|
41
|
+
raw_outputs = self.model(images)
|
|
42
|
+
outputs = []
|
|
43
|
+
for feature in raw_outputs:
|
|
44
|
+
outputs.append(FeaturePrediction(feature=feature))
|
|
45
|
+
return outputs
|
|
46
|
+
|
|
47
|
+
def get_annotated_image(self, image: Image.Image, predictions: FeaturePrediction):
|
|
48
|
+
return None
|
|
49
|
+
|
|
50
|
+
def dump(self, dir: str):
|
|
51
|
+
metadata = {
|
|
52
|
+
"model_type": self.model_type,
|
|
53
|
+
"model_file": os.path.basename(self.model_path),
|
|
54
|
+
}
|
|
55
|
+
metadata_path = get_metadata_path(dir)
|
|
56
|
+
with open(metadata_path, "w") as f:
|
|
57
|
+
yaml.dump(metadata, f)
|
|
58
|
+
# model is already saved in the model_path
|
|
59
|
+
return [metadata_path, self.model_path]
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
|
|
3
|
-
import cv2
|
|
4
|
-
import numpy as np
|
|
5
3
|
from PIL import Image
|
|
6
4
|
|
|
7
5
|
from .predictor import OnnxSessionWrapper, ImagePredictor
|
|
@@ -22,9 +20,7 @@ class MultiLabelClassificationPrediction:
|
|
|
22
20
|
class OnnxMultiLabelClassifier(OnnxSessionWrapper):
|
|
23
21
|
def __call__(self, pil_images: list[Image.Image]):
|
|
24
22
|
images_array = self.collate_images(pil_images)
|
|
25
|
-
|
|
26
23
|
input_dict = {self.input_names[0]: images_array}
|
|
27
|
-
|
|
28
24
|
scores = self.session.run(None, input_dict)[0]
|
|
29
25
|
return scores
|
|
30
26
|
|
|
@@ -76,13 +76,15 @@ class VertexModel:
|
|
|
76
76
|
predictions = self.endpoint.predict(instances=instances, parameters=parameters)
|
|
77
77
|
return predictions.predictions
|
|
78
78
|
|
|
79
|
-
def get_local_predictor(self, device: str = "cpu"):
|
|
79
|
+
def get_local_predictor(self, device: str = "cpu", force_download: bool = False):
|
|
80
80
|
dir = os.path.join(ARTIFACT_DIR, self.model_name + "-" + str(self.version))
|
|
81
|
-
self.download_artifacts(dir)
|
|
81
|
+
self.download_artifacts(dir, force_download=force_download)
|
|
82
82
|
return get_predictor(dir, device)
|
|
83
83
|
|
|
84
|
-
def download_artifacts(self, dir: str):
|
|
85
|
-
download_artifacts(
|
|
84
|
+
def download_artifacts(self, dir: str, force_download: bool = True):
|
|
85
|
+
download_artifacts(
|
|
86
|
+
dir, self.vertex_model.gca_resource.artifact_uri, force_download
|
|
87
|
+
)
|
|
86
88
|
|
|
87
89
|
|
|
88
90
|
def vertex_init(project_name: str, region: str):
|
|
@@ -92,18 +94,17 @@ def vertex_init(project_name: str, region: str):
|
|
|
92
94
|
_vertex_initialized = True
|
|
93
95
|
|
|
94
96
|
|
|
95
|
-
def download_artifacts(dir: str, artifact_uri: str):
|
|
97
|
+
def download_artifacts(dir: str, artifact_uri: str, force_download: bool = True):
|
|
96
98
|
storage_client = storage.Client()
|
|
97
|
-
|
|
98
99
|
bucket_name, artifact_path = artifact_uri.replace("gs://", "").split("/", 1)
|
|
99
100
|
bucket = storage_client.bucket(bucket_name)
|
|
100
|
-
|
|
101
101
|
os.makedirs(dir, exist_ok=True)
|
|
102
|
-
|
|
103
102
|
blobs = bucket.list_blobs(prefix=artifact_path)
|
|
104
103
|
for blob in blobs:
|
|
105
104
|
filename = blob.name.split("/")[-1]
|
|
106
105
|
download_path = os.path.join(dir, filename)
|
|
106
|
+
if not force_download and os.path.exists(download_path):
|
|
107
|
+
continue
|
|
107
108
|
blob.download_to_filename(download_path)
|
|
108
109
|
|
|
109
110
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "orient_express"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.2.0"
|
|
4
4
|
description = "A library to simplify model deployment to Vertex AI"
|
|
5
5
|
authors = ["Alexey Zankevich <alex.zankevich@shiftsmart.com>", "Ian Myers <ian.myers@shiftsmart.com>"]
|
|
6
6
|
readme = "README.md"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{orient_express-2.1.2 → orient_express-2.2.0}/orient_express/predictors/instance_segmentation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{orient_express-2.1.2 → orient_express-2.2.0}/orient_express/predictors/semantic_segmentation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|