orient_express 2.1__tar.gz → 2.1.2__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.
Files changed (20) hide show
  1. {orient_express-2.1 → orient_express-2.1.2}/PKG-INFO +8 -10
  2. {orient_express-2.1 → orient_express-2.1.2}/orient_express/predictors/classification.py +1 -5
  3. {orient_express-2.1 → orient_express-2.1.2}/orient_express/predictors/instance_segmentation.py +15 -22
  4. {orient_express-2.1 → orient_express-2.1.2}/orient_express/predictors/multi_label_classification.py +1 -5
  5. {orient_express-2.1 → orient_express-2.1.2}/orient_express/predictors/object_detection.py +11 -18
  6. {orient_express-2.1 → orient_express-2.1.2}/orient_express/predictors/predictor.py +14 -1
  7. {orient_express-2.1 → orient_express-2.1.2}/orient_express/predictors/semantic_segmentation.py +6 -13
  8. {orient_express-2.1 → orient_express-2.1.2}/orient_express/utils/image_processor.py +9 -1
  9. {orient_express-2.1 → orient_express-2.1.2}/pyproject.toml +10 -13
  10. {orient_express-2.1 → orient_express-2.1.2}/README.md +0 -0
  11. {orient_express-2.1 → orient_express-2.1.2}/orient_express/__init__.py +0 -0
  12. {orient_express-2.1 → orient_express-2.1.2}/orient_express/deployment.py +0 -0
  13. {orient_express-2.1 → orient_express-2.1.2}/orient_express/model_wrapper.py +0 -0
  14. {orient_express-2.1 → orient_express-2.1.2}/orient_express/predictors/__init__.py +0 -0
  15. {orient_express-2.1 → orient_express-2.1.2}/orient_express/sklearn_pipeline.py +0 -0
  16. {orient_express-2.1 → orient_express-2.1.2}/orient_express/utils/colors.py +0 -0
  17. {orient_express-2.1 → orient_express-2.1.2}/orient_express/utils/gs.py +0 -0
  18. {orient_express-2.1 → orient_express-2.1.2}/orient_express/utils/paths.py +0 -0
  19. {orient_express-2.1 → orient_express-2.1.2}/orient_express/utils/retry.py +0 -0
  20. {orient_express-2.1 → orient_express-2.1.2}/orient_express/vertex.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: orient_express
3
- Version: 2.1
3
+ Version: 2.1.2
4
4
  Summary: A library to simplify model deployment to Vertex AI
5
5
  Author: Alexey Zankevich
6
6
  Author-email: alex.zankevich@shiftsmart.com
@@ -9,21 +9,19 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.10
10
10
  Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
- Requires-Dist: Pillow (==10.0.1)
12
+ Requires-Dist: Pillow (>=10.0.1)
13
13
  Requires-Dist: gcsfs (>=2024.10.0,<2025.0.0)
14
- Requires-Dist: google-cloud-aiplatform
15
- Requires-Dist: google-cloud-storage
16
- Requires-Dist: kserve (==0.16.0)
14
+ Requires-Dist: google-cloud-aiplatform (>=1.0,<2.0)
15
+ Requires-Dist: google-cloud-storage (>=3.0,<4.0)
17
16
  Requires-Dist: onnxruntime (>=1.20,<2.0) ; sys_platform == "darwin" or platform_machine == "aarch64" or platform_machine == "arm64" or sys_platform == "win32" and platform_machine == "ARM64"
18
17
  Requires-Dist: onnxruntime-gpu (>=1.20,<2.0) ; sys_platform == "linux" and platform_machine == "x86_64" or sys_platform == "win32" and platform_machine == "AMD64"
19
- Requires-Dist: opencv-python-headless (==4.11.0.86)
20
- Requires-Dist: pandas
21
- Requires-Dist: python-json-logger (==2.0.7)
18
+ Requires-Dist: opencv-python-headless (>=4.11.0,<5.0.0)
19
+ Requires-Dist: pandas (>=2.0,<3.0)
22
20
  Requires-Dist: pyyaml (>=6.0,<7.0)
23
- Requires-Dist: scikit-learn (==1.5.2)
21
+ Requires-Dist: scikit-learn (>=1.5.0,<2.0.0)
24
22
  Requires-Dist: torch (>=2.5.0,<3.0.0)
25
23
  Requires-Dist: torchvision (>=0.20.0,<0.21.0)
26
- Requires-Dist: xgboost (==2.1.2)
24
+ Requires-Dist: xgboost (>=2.0.0,<3.0.0)
27
25
  Description-Content-Type: text/markdown
28
26
 
29
27
  # Orient Express
@@ -23,11 +23,7 @@ class ClassificationPrediction:
23
23
 
24
24
  class OnnxClassifier(OnnxSessionWrapper):
25
25
  def __call__(self, pil_images: list[Image.Image]):
26
- images = [
27
- cv2.resize(np.array(pil_img), (self.resolution, self.resolution))
28
- for pil_img in pil_images
29
- ]
30
- images_array = np.array(images)
26
+ images_array = self.collate_images(pil_images)
31
27
 
32
28
  input_dict = {self.input_names[0]: images_array}
33
29
 
@@ -35,13 +35,19 @@ class InstanceSegmentationPrediction:
35
35
 
36
36
 
37
37
  class OnnxInstanceSegmentation(OnnxSessionWrapper):
38
- def preprocess(self, pil_images: list[Image.Image]):
39
- sizes = [[pil_img.size[1], pil_img.size[0]] for pil_img in pil_images]
40
- images = [
41
- cv2.resize(np.array(pil_img), (self.resolution, self.resolution))
42
- for pil_img in pil_images
43
- ]
44
- return np.array(images), np.array(sizes, dtype=np.float32)
38
+ def __call__(self, pil_images: list[Image.Image], confidence: float = 0.5):
39
+ images_array = self.collate_images(pil_images)
40
+ target_sizes_array = self.collate_sizes(pil_images)
41
+
42
+ input_dict = {
43
+ self.input_names[0]: images_array,
44
+ self.input_names[1]: target_sizes_array,
45
+ }
46
+
47
+ boxes, scores, labels, masks = self.session.run(None, input_dict)
48
+ return self.postprocess(
49
+ boxes, scores, labels, masks, target_sizes_array, confidence
50
+ )
45
51
 
46
52
  def postprocess(
47
53
  self,
@@ -92,19 +98,6 @@ class OnnxInstanceSegmentation(OnnxSessionWrapper):
92
98
 
93
99
  return results
94
100
 
95
- def __call__(self, pil_images: list[Image.Image], confidence: float = 0.5):
96
- images_array, target_sizes_array = self.preprocess(pil_images)
97
-
98
- input_dict = {
99
- self.input_names[0]: images_array,
100
- self.input_names[1]: target_sizes_array,
101
- }
102
-
103
- boxes, scores, labels, masks = self.session.run(None, input_dict)
104
- return self.postprocess(
105
- boxes, scores, labels, masks, target_sizes_array, confidence
106
- )
107
-
108
101
 
109
102
  class InstanceSegmentationPredictor(ImagePredictor):
110
103
  model_type = "instance-segmentation-onnx"
@@ -166,8 +159,8 @@ class InstanceSegmentationPredictor(ImagePredictor):
166
159
  centroid_x = int((prediction.bbox[0] + prediction.bbox[2]) / 2)
167
160
  centroid_y = int((prediction.bbox[1] + prediction.bbox[3]) / 2)
168
161
  # Put the object count in the center of the bbox
169
- font_scale = 6
170
- font_thickness = 12
162
+ font_scale = 2
163
+ font_thickness = 4
171
164
  text = str(index)
172
165
  text_size = cv2.getTextSize(
173
166
  text, cv2.FONT_HERSHEY_SIMPLEX, font_scale, font_thickness
@@ -21,11 +21,7 @@ class MultiLabelClassificationPrediction:
21
21
 
22
22
  class OnnxMultiLabelClassifier(OnnxSessionWrapper):
23
23
  def __call__(self, pil_images: list[Image.Image]):
24
- images = [
25
- cv2.resize(np.array(pil_img), (self.resolution, self.resolution))
26
- for pil_img in pil_images
27
- ]
28
- images_array = np.array(images)
24
+ images_array = self.collate_images(pil_images)
29
25
 
30
26
  input_dict = {self.input_names[0]: images_array}
31
27
 
@@ -30,13 +30,17 @@ class BoundingBoxPrediction:
30
30
 
31
31
 
32
32
  class OnnxDetector(OnnxSessionWrapper):
33
- def preprocess(self, pil_images: list[Image.Image]):
34
- sizes = [[pil_img.size[1], pil_img.size[0]] for pil_img in pil_images]
35
- images = [
36
- cv2.resize(np.array(pil_img), (self.resolution, self.resolution))
37
- for pil_img in pil_images
38
- ]
39
- return np.array(images), np.array(sizes, dtype=np.float32)
33
+ def __call__(self, pil_images: list[Image.Image], confidence: float = 0.5):
34
+ images_array = self.collate_images(pil_images)
35
+ target_sizes_array = self.collate_sizes(pil_images)
36
+
37
+ input_dict = {
38
+ self.input_names[0]: images_array,
39
+ self.input_names[1]: target_sizes_array,
40
+ }
41
+
42
+ boxes, scores, labels = self.session.run(None, input_dict)
43
+ return self.postprocess(boxes, scores, labels, confidence)
40
44
 
41
45
  def postprocess(
42
46
  self,
@@ -67,17 +71,6 @@ class OnnxDetector(OnnxSessionWrapper):
67
71
 
68
72
  return results
69
73
 
70
- def __call__(self, pil_images: list[Image.Image], confidence: float = 0.5):
71
- images_array, target_sizes_array = self.preprocess(pil_images)
72
-
73
- input_dict = {
74
- self.input_names[0]: images_array,
75
- self.input_names[1]: target_sizes_array,
76
- }
77
-
78
- boxes, scores, labels = self.session.run(None, input_dict)
79
- return self.postprocess(boxes, scores, labels, confidence)
80
-
81
74
 
82
75
  class BoundingBoxPredictor(ImagePredictor):
83
76
  model_type = "object-detection-onnx"
@@ -4,9 +4,13 @@ import warnings
4
4
 
5
5
  import yaml
6
6
  import onnxruntime as ort
7
+ from PIL import Image
8
+ import cv2
9
+ import numpy as np
7
10
 
8
11
  from ..utils.paths import get_metadata_path
9
12
  from ..utils.colors import generate_color_scheme
13
+ from ..utils.image_processor import image_to_array
10
14
 
11
15
 
12
16
  class Predictor(ABC):
@@ -42,7 +46,7 @@ class ImagePredictor(Predictor):
42
46
  self.model_path = model_path
43
47
 
44
48
  def get_serving_container_image_uri(self):
45
- return "us-west1-docker.pkg.dev/shiftsmart-api/orient-express/image-onnx:v2.1"
49
+ return "us-west1-docker.pkg.dev/shiftsmart-api/orient-express/image-onnx:v2.1.2"
46
50
 
47
51
  def get_serving_container_health_route(self, model_name):
48
52
  return f"/v1/models/{model_name}"
@@ -92,3 +96,12 @@ class OnnxSessionWrapper:
92
96
 
93
97
  input_shape = self.session.get_inputs()[0].shape
94
98
  self.resolution = input_shape[1]
99
+ self.img_size = (self.resolution, self.resolution)
100
+
101
+ def collate_sizes(self, pil_images: list[Image.Image]):
102
+ sizes = [[img.size[1], img.size[0]] for img in pil_images]
103
+ return np.array(sizes, dtype=np.float32)
104
+
105
+ def collate_images(self, pil_images: list[Image.Image]):
106
+ images = [cv2.resize(image_to_array(img), self.img_size) for img in pil_images]
107
+ return np.array(images)
@@ -25,13 +25,12 @@ class SemanticSegmentationPrediction:
25
25
 
26
26
 
27
27
  class OnnxSemanticSegmentation(OnnxSessionWrapper):
28
- def preprocess(self, pil_images: list[Image.Image]):
29
- sizes = [[pil_img.size[1], pil_img.size[0]] for pil_img in pil_images]
30
- images = [
31
- cv2.resize(np.array(pil_img), (self.resolution, self.resolution))
32
- for pil_img in pil_images
33
- ]
34
- return np.array(images), np.array(sizes, dtype=np.float32)
28
+ def __call__(self, pil_images: list[Image.Image]):
29
+ images_array = self.collate_images(pil_images)
30
+ target_sizes_array = self.collate_sizes(pil_images)
31
+ input_dict = {self.input_names[0]: images_array}
32
+ masks = self.session.run(None, input_dict)[0]
33
+ return self.postprocess(masks, target_sizes_array)
35
34
 
36
35
  def postprocess(self, masks: np.ndarray, target_sizes: np.ndarray):
37
36
  results: list[np.ndarray] = []
@@ -55,12 +54,6 @@ class OnnxSemanticSegmentation(OnnxSessionWrapper):
55
54
 
56
55
  return results
57
56
 
58
- def __call__(self, pil_images: list[Image.Image]):
59
- images_array, target_sizes_array = self.preprocess(pil_images)
60
- input_dict = {self.input_names[0]: images_array}
61
- masks = self.session.run(None, input_dict)[0]
62
- return self.postprocess(masks, target_sizes_array)
63
-
64
57
 
65
58
  class SemanticSegmentationPredictor(ImagePredictor):
66
59
  model_type = "semantic-segmentation-onnx"
@@ -82,8 +82,16 @@ def image_to_bytes(image):
82
82
  return buffered.getvalue()
83
83
 
84
84
 
85
+ def base64_to_image(base64_data: str):
86
+ return Image.open(BytesIO(base64.b64decode(base64_data)))
87
+
88
+
89
+ def image_to_array(image: Image.Image):
90
+ return np.array(image.convert("RGB"))
91
+
92
+
85
93
  def pil_to_opencv(image: Image.Image):
86
- return cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR)
94
+ return cv2.cvtColor(image_to_array(image), cv2.COLOR_RGB2BGR)
87
95
 
88
96
 
89
97
  def opencv_to_pil(image: np.ndarray):
@@ -1,34 +1,31 @@
1
1
  [tool.poetry]
2
2
  name = "orient_express"
3
- version = "2.1"
3
+ version = "2.1.2"
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"
7
7
 
8
8
  [tool.poetry.dependencies]
9
9
  python = ">=3.10,<3.13"
10
- google-cloud-aiplatform = "*"
11
- google-cloud-storage = "*"
12
- pandas = "*"
10
+ google-cloud-aiplatform = "^1.0"
11
+ google-cloud-storage = "^3.0"
12
+ pandas = "^2.0"
13
13
  pyyaml = "^6.0"
14
-
15
- kserve = "0.16.0"
16
14
  torch = {version = "^2.5.0", source = "pytorch-cpu"}
17
15
  torchvision = {version = "^0.20.0", source = "pytorch-cpu"}
18
- opencv-python-headless = "4.11.0.86"
19
- Pillow = "10.0.1"
20
- python-json-logger = "2.0.7"
16
+ opencv-python-headless = "^4.11.0"
17
+ Pillow = ">=10.0.1"
21
18
  gcsfs = "^2024.10.0"
22
-
23
- scikit-learn = "1.5.2"
24
- xgboost = "2.1.2"
25
-
19
+ scikit-learn = "^1.5.0"
20
+ xgboost = "^2.0.0"
26
21
  onnxruntime-gpu = {version = "^1.20", markers = "sys_platform == 'linux' and platform_machine == 'x86_64' or sys_platform == 'win32' and platform_machine == 'AMD64'"}
27
22
  onnxruntime = {version = "^1.20", markers = "sys_platform == 'darwin' or platform_machine == 'aarch64' or platform_machine == 'arm64' or sys_platform == 'win32' and platform_machine == 'ARM64'"}
28
23
 
29
24
  [tool.poetry.group.dev.dependencies]
30
25
  black = "24.10.0"
31
26
  pytest = "8.3.3"
27
+ kserve = "^0.16.0"
28
+ python-json-logger = "^4.0.0"
32
29
 
33
30
  [build-system]
34
31
  requires = ["poetry-core"]
File without changes