orient_express 2.0__tar.gz → 2.1__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.0/README.md → orient_express-2.1/PKG-INFO +123 -0
- orient_express-2.0/PKG-INFO → orient_express-2.1/README.md +94 -18
- {orient_express-2.0 → orient_express-2.1}/orient_express/predictors/__init__.py +21 -7
- {orient_express-2.0 → orient_express-2.1}/orient_express/predictors/classification.py +1 -1
- {orient_express-2.0 → orient_express-2.1}/orient_express/predictors/instance_segmentation.py +2 -2
- orient_express-2.1/orient_express/predictors/multi_label_classification.py +68 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/predictors/predictor.py +14 -3
- {orient_express-2.0 → orient_express-2.1}/orient_express/vertex.py +2 -3
- {orient_express-2.0 → orient_express-2.1}/pyproject.toml +11 -17
- {orient_express-2.0 → orient_express-2.1}/orient_express/__init__.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/deployment.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/model_wrapper.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/predictors/object_detection.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/predictors/semantic_segmentation.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/sklearn_pipeline.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/utils/colors.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/utils/gs.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/utils/image_processor.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/utils/paths.py +0 -0
- {orient_express-2.0 → orient_express-2.1}/orient_express/utils/retry.py +0 -0
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: orient_express
|
|
3
|
+
Version: 2.1
|
|
4
|
+
Summary: A library to simplify model deployment to Vertex AI
|
|
5
|
+
Author: Alexey Zankevich
|
|
6
|
+
Author-email: alex.zankevich@shiftsmart.com
|
|
7
|
+
Requires-Python: >=3.10,<3.13
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
+
Requires-Dist: Pillow (==10.0.1)
|
|
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)
|
|
17
|
+
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
|
+
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)
|
|
22
|
+
Requires-Dist: pyyaml (>=6.0,<7.0)
|
|
23
|
+
Requires-Dist: scikit-learn (==1.5.2)
|
|
24
|
+
Requires-Dist: torch (>=2.5.0,<3.0.0)
|
|
25
|
+
Requires-Dist: torchvision (>=0.20.0,<0.21.0)
|
|
26
|
+
Requires-Dist: xgboost (==2.1.2)
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
1
29
|
# Orient Express
|
|
2
30
|
|
|
3
31
|
A library to accelerate model deployments to Vertex AI directly from colab notebooks
|
|
@@ -18,6 +46,16 @@ Both workflows handle versioning, artifact storage in GCS, and integration with
|
|
|
18
46
|
pip install orient_express
|
|
19
47
|
```
|
|
20
48
|
|
|
49
|
+
For local development:
|
|
50
|
+
```bash
|
|
51
|
+
pip install -e .
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or with Poetry:
|
|
55
|
+
```bash
|
|
56
|
+
poetry install
|
|
57
|
+
```
|
|
58
|
+
|
|
21
59
|
## Workflows
|
|
22
60
|
|
|
23
61
|
### ONNX Image Model Workflow
|
|
@@ -137,6 +175,43 @@ local_predictor = vertex_model.get_local_predictor()
|
|
|
137
175
|
predictions = local_predictor.predict(X_test)
|
|
138
176
|
```
|
|
139
177
|
|
|
178
|
+
## ONNX Runtime and Device Support
|
|
179
|
+
|
|
180
|
+
### Platform Support Matrix
|
|
181
|
+
|
|
182
|
+
| Platform | Architecture | ONNX Runtime Package | CUDA Available |
|
|
183
|
+
|----------|--------------|---------------------|----------------|
|
|
184
|
+
| Linux | x86_64 | onnxruntime-gpu | Yes |
|
|
185
|
+
| Linux | aarch64 | onnxruntime | No |
|
|
186
|
+
| Windows | x64 (AMD64) | onnxruntime-gpu | Yes |
|
|
187
|
+
| Windows | ARM64 | onnxruntime | No |
|
|
188
|
+
| macOS | x86_64 | onnxruntime | No |
|
|
189
|
+
| macOS | arm64 | onnxruntime | No |
|
|
190
|
+
|
|
191
|
+
The appropriate package is installed automatically based on your platform.
|
|
192
|
+
|
|
193
|
+
### Selecting CPU vs CUDA Execution
|
|
194
|
+
|
|
195
|
+
When loading a predictor, use the `device` parameter to specify the execution provider:
|
|
196
|
+
```python
|
|
197
|
+
from orient_express.predictors import ObjectDetectionPredictor
|
|
198
|
+
|
|
199
|
+
# CPU inference (works on all platforms)
|
|
200
|
+
predictor = ObjectDetectionPredictor("/path/to/model", classes, device="cpu")
|
|
201
|
+
|
|
202
|
+
# CUDA inference (requires Linux x64 or Windows x64 with CUDA drivers)
|
|
203
|
+
predictor = ObjectDetectionPredictor("/path/to/model", classes, device="cuda")
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
When using a Vertex AI model:
|
|
207
|
+
```python
|
|
208
|
+
# CPU inference
|
|
209
|
+
predictor = model.get_local_predictor(device="cpu")
|
|
210
|
+
|
|
211
|
+
# CUDA inference
|
|
212
|
+
predictor = model.get_local_predictor(device="cuda")
|
|
213
|
+
```
|
|
214
|
+
|
|
140
215
|
### Pinning Model Versions
|
|
141
216
|
|
|
142
217
|
By default, `get_vertex_model` returns the most recently updated version. To pin to a specific version:
|
|
@@ -213,6 +288,53 @@ class ClassificationPrediction:
|
|
|
213
288
|
|
|
214
289
|
</details>
|
|
215
290
|
|
|
291
|
+
### MultiLabelClassificationPredictor
|
|
292
|
+
|
|
293
|
+
<details>
|
|
294
|
+
<summary>Click to expand</summary>
|
|
295
|
+
|
|
296
|
+
For image multi-label classification models that output a set of binary class probabilities.
|
|
297
|
+
|
|
298
|
+
#### ONNX Graph Requirements
|
|
299
|
+
|
|
300
|
+
| | |
|
|
301
|
+
| ----------- | ------------------------------------------------------------ |
|
|
302
|
+
| **Inputs** | `images`: `[batch, height, width, 3]` uint8 RGB |
|
|
303
|
+
| **Outputs** | `scores`: `[batch, num_classes]` float32 class probabilities |
|
|
304
|
+
|
|
305
|
+
The graph must handle normalization internally. No target_sizes input is needed.
|
|
306
|
+
|
|
307
|
+
#### Usage
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
from orient_express.predictors import MultiLabelClassificationPredictor
|
|
311
|
+
|
|
312
|
+
predictor = MultiLabelClassificationPredictor(
|
|
313
|
+
onnx_path="classifier.onnx",
|
|
314
|
+
classes={1: "contains_cat", 2: "contains_dog", 3: "contains_bird"}
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
predictions = predictor.predict(images, confidence=0.5)
|
|
318
|
+
# Returns: list[MultiLabelClassificationPrediction]
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
#### Output Structure
|
|
322
|
+
|
|
323
|
+
```python
|
|
324
|
+
@dataclass
|
|
325
|
+
class MultiLabelClassificationPrediction:
|
|
326
|
+
classes: list[str] # Predicted class names based on confidence threshold
|
|
327
|
+
class_scores: dict[str, float] # Scores for all classes
|
|
328
|
+
|
|
329
|
+
# to_dict() output:
|
|
330
|
+
{
|
|
331
|
+
"classes": ["contains_cat", "contains_bird"],
|
|
332
|
+
"class_scores": {"contains_cat": 0.95, "contains_dog": 0.03, "contains_bird": 0.82}
|
|
333
|
+
}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
</details>
|
|
337
|
+
|
|
216
338
|
### BoundingBoxPredictor
|
|
217
339
|
|
|
218
340
|
<details>
|
|
@@ -650,3 +772,4 @@ python deploy.py --run-type scheduled
|
|
|
650
772
|
```
|
|
651
773
|
|
|
652
774
|
</details>
|
|
775
|
+
|
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: orient_express
|
|
3
|
-
Version: 2.0
|
|
4
|
-
Summary: A library to simplify model deployment to Vertex AI
|
|
5
|
-
Author: Alexey Zankevich
|
|
6
|
-
Author-email: alex.zankevich@shiftsmart.com
|
|
7
|
-
Requires-Python: >=3.10,<3.13
|
|
8
|
-
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
10
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
11
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
12
|
-
Requires-Dist: google-cloud-aiplatform
|
|
13
|
-
Requires-Dist: google-cloud-storage
|
|
14
|
-
Requires-Dist: pandas
|
|
15
|
-
Requires-Dist: pyyaml (>=6.0,<7.0)
|
|
16
|
-
Description-Content-Type: text/markdown
|
|
17
|
-
|
|
18
1
|
# Orient Express
|
|
19
2
|
|
|
20
3
|
A library to accelerate model deployments to Vertex AI directly from colab notebooks
|
|
@@ -35,6 +18,16 @@ Both workflows handle versioning, artifact storage in GCS, and integration with
|
|
|
35
18
|
pip install orient_express
|
|
36
19
|
```
|
|
37
20
|
|
|
21
|
+
For local development:
|
|
22
|
+
```bash
|
|
23
|
+
pip install -e .
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Or with Poetry:
|
|
27
|
+
```bash
|
|
28
|
+
poetry install
|
|
29
|
+
```
|
|
30
|
+
|
|
38
31
|
## Workflows
|
|
39
32
|
|
|
40
33
|
### ONNX Image Model Workflow
|
|
@@ -154,6 +147,43 @@ local_predictor = vertex_model.get_local_predictor()
|
|
|
154
147
|
predictions = local_predictor.predict(X_test)
|
|
155
148
|
```
|
|
156
149
|
|
|
150
|
+
## ONNX Runtime and Device Support
|
|
151
|
+
|
|
152
|
+
### Platform Support Matrix
|
|
153
|
+
|
|
154
|
+
| Platform | Architecture | ONNX Runtime Package | CUDA Available |
|
|
155
|
+
|----------|--------------|---------------------|----------------|
|
|
156
|
+
| Linux | x86_64 | onnxruntime-gpu | Yes |
|
|
157
|
+
| Linux | aarch64 | onnxruntime | No |
|
|
158
|
+
| Windows | x64 (AMD64) | onnxruntime-gpu | Yes |
|
|
159
|
+
| Windows | ARM64 | onnxruntime | No |
|
|
160
|
+
| macOS | x86_64 | onnxruntime | No |
|
|
161
|
+
| macOS | arm64 | onnxruntime | No |
|
|
162
|
+
|
|
163
|
+
The appropriate package is installed automatically based on your platform.
|
|
164
|
+
|
|
165
|
+
### Selecting CPU vs CUDA Execution
|
|
166
|
+
|
|
167
|
+
When loading a predictor, use the `device` parameter to specify the execution provider:
|
|
168
|
+
```python
|
|
169
|
+
from orient_express.predictors import ObjectDetectionPredictor
|
|
170
|
+
|
|
171
|
+
# CPU inference (works on all platforms)
|
|
172
|
+
predictor = ObjectDetectionPredictor("/path/to/model", classes, device="cpu")
|
|
173
|
+
|
|
174
|
+
# CUDA inference (requires Linux x64 or Windows x64 with CUDA drivers)
|
|
175
|
+
predictor = ObjectDetectionPredictor("/path/to/model", classes, device="cuda")
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
When using a Vertex AI model:
|
|
179
|
+
```python
|
|
180
|
+
# CPU inference
|
|
181
|
+
predictor = model.get_local_predictor(device="cpu")
|
|
182
|
+
|
|
183
|
+
# CUDA inference
|
|
184
|
+
predictor = model.get_local_predictor(device="cuda")
|
|
185
|
+
```
|
|
186
|
+
|
|
157
187
|
### Pinning Model Versions
|
|
158
188
|
|
|
159
189
|
By default, `get_vertex_model` returns the most recently updated version. To pin to a specific version:
|
|
@@ -230,6 +260,53 @@ class ClassificationPrediction:
|
|
|
230
260
|
|
|
231
261
|
</details>
|
|
232
262
|
|
|
263
|
+
### MultiLabelClassificationPredictor
|
|
264
|
+
|
|
265
|
+
<details>
|
|
266
|
+
<summary>Click to expand</summary>
|
|
267
|
+
|
|
268
|
+
For image multi-label classification models that output a set of binary class probabilities.
|
|
269
|
+
|
|
270
|
+
#### ONNX Graph Requirements
|
|
271
|
+
|
|
272
|
+
| | |
|
|
273
|
+
| ----------- | ------------------------------------------------------------ |
|
|
274
|
+
| **Inputs** | `images`: `[batch, height, width, 3]` uint8 RGB |
|
|
275
|
+
| **Outputs** | `scores`: `[batch, num_classes]` float32 class probabilities |
|
|
276
|
+
|
|
277
|
+
The graph must handle normalization internally. No target_sizes input is needed.
|
|
278
|
+
|
|
279
|
+
#### Usage
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
from orient_express.predictors import MultiLabelClassificationPredictor
|
|
283
|
+
|
|
284
|
+
predictor = MultiLabelClassificationPredictor(
|
|
285
|
+
onnx_path="classifier.onnx",
|
|
286
|
+
classes={1: "contains_cat", 2: "contains_dog", 3: "contains_bird"}
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
predictions = predictor.predict(images, confidence=0.5)
|
|
290
|
+
# Returns: list[MultiLabelClassificationPrediction]
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
#### Output Structure
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
@dataclass
|
|
297
|
+
class MultiLabelClassificationPrediction:
|
|
298
|
+
classes: list[str] # Predicted class names based on confidence threshold
|
|
299
|
+
class_scores: dict[str, float] # Scores for all classes
|
|
300
|
+
|
|
301
|
+
# to_dict() output:
|
|
302
|
+
{
|
|
303
|
+
"classes": ["contains_cat", "contains_bird"],
|
|
304
|
+
"class_scores": {"contains_cat": 0.95, "contains_dog": 0.03, "contains_bird": 0.82}
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
</details>
|
|
309
|
+
|
|
233
310
|
### BoundingBoxPredictor
|
|
234
311
|
|
|
235
312
|
<details>
|
|
@@ -667,4 +744,3 @@ python deploy.py --run-type scheduled
|
|
|
667
744
|
```
|
|
668
745
|
|
|
669
746
|
</details>
|
|
670
|
-
|
|
@@ -17,9 +17,13 @@ from .semantic_segmentation import (
|
|
|
17
17
|
SemanticSegmentationPrediction,
|
|
18
18
|
)
|
|
19
19
|
from .classification import ClassificationPredictor, ClassificationPrediction
|
|
20
|
+
from .multi_label_classification import (
|
|
21
|
+
MultiLabelClassificationPredictor,
|
|
22
|
+
MultiLabelClassificationPrediction,
|
|
23
|
+
)
|
|
20
24
|
|
|
21
25
|
|
|
22
|
-
def get_predictor(dir: str):
|
|
26
|
+
def get_predictor(dir: str, device: str = "cpu"):
|
|
23
27
|
downloaded_files = os.listdir(dir)
|
|
24
28
|
metadata_path = get_metadata_path(dir)
|
|
25
29
|
if not os.path.exists(metadata_path):
|
|
@@ -43,20 +47,30 @@ def get_predictor(dir: str):
|
|
|
43
47
|
joblib_path = os.path.join(dir, metadata["model_file"])
|
|
44
48
|
return joblib.load(joblib_path)
|
|
45
49
|
elif model_type == InstanceSegmentationPredictor.model_type:
|
|
46
|
-
return load_image_predictor(
|
|
50
|
+
return load_image_predictor(
|
|
51
|
+
InstanceSegmentationPredictor, dir, metadata, device
|
|
52
|
+
)
|
|
47
53
|
elif model_type == BoundingBoxPredictor.model_type:
|
|
48
|
-
return load_image_predictor(BoundingBoxPredictor, dir, metadata)
|
|
54
|
+
return load_image_predictor(BoundingBoxPredictor, dir, metadata, device)
|
|
49
55
|
elif model_type == SemanticSegmentationPredictor.model_type:
|
|
50
|
-
return load_image_predictor(
|
|
56
|
+
return load_image_predictor(
|
|
57
|
+
SemanticSegmentationPredictor, dir, metadata, device
|
|
58
|
+
)
|
|
51
59
|
elif model_type == ClassificationPredictor.model_type:
|
|
52
|
-
return load_image_predictor(ClassificationPredictor, dir, metadata)
|
|
60
|
+
return load_image_predictor(ClassificationPredictor, dir, metadata, device)
|
|
61
|
+
elif model_type == MultiLabelClassificationPredictor.model_type:
|
|
62
|
+
return load_image_predictor(
|
|
63
|
+
MultiLabelClassificationPredictor, dir, metadata, device
|
|
64
|
+
)
|
|
53
65
|
else:
|
|
54
66
|
raise Exception(f"Unknown model_type '{model_type}'")
|
|
55
67
|
|
|
56
68
|
|
|
57
|
-
def load_image_predictor(
|
|
69
|
+
def load_image_predictor(
|
|
70
|
+
model_type: type[ImagePredictor], dir: str, metadata: dict, device: str = "cpu"
|
|
71
|
+
):
|
|
58
72
|
onnx_path = os.path.join(dir, metadata["model_file"])
|
|
59
73
|
if "classes" not in metadata:
|
|
60
74
|
raise Exception("No classes defined in metadata.yaml")
|
|
61
75
|
classes = metadata["classes"]
|
|
62
|
-
return model_type(onnx_path, classes)
|
|
76
|
+
return model_type(onnx_path, classes, device)
|
{orient_express-2.0 → orient_express-2.1}/orient_express/predictors/instance_segmentation.py
RENAMED
|
@@ -166,8 +166,8 @@ class InstanceSegmentationPredictor(ImagePredictor):
|
|
|
166
166
|
centroid_x = int((prediction.bbox[0] + prediction.bbox[2]) / 2)
|
|
167
167
|
centroid_y = int((prediction.bbox[1] + prediction.bbox[3]) / 2)
|
|
168
168
|
# Put the object count in the center of the bbox
|
|
169
|
-
font_scale =
|
|
170
|
-
font_thickness =
|
|
169
|
+
font_scale = 6
|
|
170
|
+
font_thickness = 12
|
|
171
171
|
text = str(index)
|
|
172
172
|
text_size = cv2.getTextSize(
|
|
173
173
|
text, cv2.FONT_HERSHEY_SIMPLEX, font_scale, font_thickness
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
import cv2
|
|
4
|
+
import numpy as np
|
|
5
|
+
from PIL import Image
|
|
6
|
+
|
|
7
|
+
from .predictor import OnnxSessionWrapper, ImagePredictor
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass
|
|
11
|
+
class MultiLabelClassificationPrediction:
|
|
12
|
+
classes: list[str]
|
|
13
|
+
class_scores: dict[str, float]
|
|
14
|
+
|
|
15
|
+
def to_dict(self):
|
|
16
|
+
return {
|
|
17
|
+
"classes": self.classes,
|
|
18
|
+
"class_scores": self.class_scores,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class OnnxMultiLabelClassifier(OnnxSessionWrapper):
|
|
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)
|
|
29
|
+
|
|
30
|
+
input_dict = {self.input_names[0]: images_array}
|
|
31
|
+
|
|
32
|
+
scores = self.session.run(None, input_dict)[0]
|
|
33
|
+
return scores
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class MultiLabelClassificationPredictor(ImagePredictor):
|
|
37
|
+
model_type = "multi-label-classification-onnx"
|
|
38
|
+
backend_model = OnnxMultiLabelClassifier
|
|
39
|
+
|
|
40
|
+
def predict(
|
|
41
|
+
self, images: list[Image.Image], confidence: float
|
|
42
|
+
) -> list[MultiLabelClassificationPrediction]:
|
|
43
|
+
if not images:
|
|
44
|
+
return []
|
|
45
|
+
raw_outputs = self.model(images)
|
|
46
|
+
outputs = []
|
|
47
|
+
for class_scores in raw_outputs:
|
|
48
|
+
classes = []
|
|
49
|
+
# self.classes is 1-indexed
|
|
50
|
+
for idx, score in enumerate(class_scores):
|
|
51
|
+
if score > confidence:
|
|
52
|
+
classes.append(self.classes.get(idx + 1, "Unknown"))
|
|
53
|
+
outputs.append(
|
|
54
|
+
MultiLabelClassificationPrediction(
|
|
55
|
+
classes=classes,
|
|
56
|
+
class_scores={
|
|
57
|
+
# self.classes is 1-indexed
|
|
58
|
+
clss: float(class_scores[class_idx - 1])
|
|
59
|
+
for class_idx, clss in self.classes.items()
|
|
60
|
+
},
|
|
61
|
+
)
|
|
62
|
+
)
|
|
63
|
+
return outputs
|
|
64
|
+
|
|
65
|
+
def get_annotated_image(
|
|
66
|
+
self, image: Image.Image, predictions: MultiLabelClassificationPrediction
|
|
67
|
+
):
|
|
68
|
+
return None
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import os
|
|
2
2
|
from abc import ABC, abstractmethod
|
|
3
|
+
import warnings
|
|
3
4
|
|
|
4
5
|
import yaml
|
|
5
6
|
import onnxruntime as ort
|
|
@@ -34,8 +35,8 @@ class ImagePredictor(Predictor):
|
|
|
34
35
|
backend_model: type
|
|
35
36
|
prediction_type: type
|
|
36
37
|
|
|
37
|
-
def __init__(self, model_path: str, classes: dict[int, str]):
|
|
38
|
-
self.model = self.backend_model(model_path)
|
|
38
|
+
def __init__(self, model_path: str, classes: dict[int, str], device: str = "cpu"):
|
|
39
|
+
self.model = self.backend_model(model_path, device)
|
|
39
40
|
self.color_scheme = generate_color_scheme(list(classes.values()))
|
|
40
41
|
self.classes = classes
|
|
41
42
|
self.model_path = model_path
|
|
@@ -63,7 +64,7 @@ class ImagePredictor(Predictor):
|
|
|
63
64
|
|
|
64
65
|
|
|
65
66
|
class OnnxSessionWrapper:
|
|
66
|
-
def __init__(self, onnx_path,
|
|
67
|
+
def __init__(self, onnx_path: str, device: str = "cpu"):
|
|
67
68
|
session_options = ort.SessionOptions()
|
|
68
69
|
session_options.graph_optimization_level = (
|
|
69
70
|
ort.GraphOptimizationLevel.ORT_ENABLE_ALL
|
|
@@ -72,6 +73,16 @@ class OnnxSessionWrapper:
|
|
|
72
73
|
session_options.enable_cpu_mem_arena = True
|
|
73
74
|
session_options.enable_mem_reuse = True
|
|
74
75
|
|
|
76
|
+
if device == "cpu":
|
|
77
|
+
providers = ["CPUExecutionProvider"]
|
|
78
|
+
elif device == "cuda":
|
|
79
|
+
providers = ["CUDAExecutionProvider"]
|
|
80
|
+
else:
|
|
81
|
+
warnings.warn(
|
|
82
|
+
f"Unknown device '{device}'. Defaulting to CPU. Supported devices: 'cpu', 'cuda'."
|
|
83
|
+
)
|
|
84
|
+
providers = ["CPUExecutionProvider"]
|
|
85
|
+
|
|
75
86
|
self.session = ort.InferenceSession(
|
|
76
87
|
onnx_path, providers=providers, sess_options=session_options
|
|
77
88
|
)
|
|
@@ -7,7 +7,6 @@ from google.cloud import storage, aiplatform
|
|
|
7
7
|
|
|
8
8
|
from .predictors import get_predictor, Predictor
|
|
9
9
|
|
|
10
|
-
|
|
11
10
|
ARTIFACT_DIR = os.path.join(os.path.dirname(__file__), "artifacts")
|
|
12
11
|
_vertex_initialized = False
|
|
13
12
|
|
|
@@ -77,10 +76,10 @@ class VertexModel:
|
|
|
77
76
|
predictions = self.endpoint.predict(instances=instances, parameters=parameters)
|
|
78
77
|
return predictions.predictions
|
|
79
78
|
|
|
80
|
-
def get_local_predictor(self):
|
|
79
|
+
def get_local_predictor(self, device: str = "cpu"):
|
|
81
80
|
dir = os.path.join(ARTIFACT_DIR, self.model_name + "-" + str(self.version))
|
|
82
81
|
self.download_artifacts(dir)
|
|
83
|
-
return get_predictor(dir)
|
|
82
|
+
return get_predictor(dir, device)
|
|
84
83
|
|
|
85
84
|
def download_artifacts(self, dir: str):
|
|
86
85
|
download_artifacts(dir, self.vertex_model.gca_resource.artifact_uri)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "orient_express"
|
|
3
|
-
version = "2.
|
|
3
|
+
version = "2.1"
|
|
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"
|
|
@@ -12,23 +12,7 @@ google-cloud-storage = "*"
|
|
|
12
12
|
pandas = "*"
|
|
13
13
|
pyyaml = "^6.0"
|
|
14
14
|
|
|
15
|
-
[tool.poetry.group.dev.dependencies]
|
|
16
|
-
black = "24.10.0"
|
|
17
|
-
pytest = "8.3.3"
|
|
18
|
-
scikit-learn = "1.5.2"
|
|
19
|
-
xgboost = "2.1.2"
|
|
20
|
-
|
|
21
|
-
[tool.poetry.group.xgboost-scikit-learn.dependencies]
|
|
22
|
-
scikit-learn = "1.5.2"
|
|
23
15
|
kserve = "0.16.0"
|
|
24
|
-
python-json-logger = "2.0.7"
|
|
25
|
-
gcsfs = "^2024.10.0"
|
|
26
|
-
|
|
27
|
-
[tool.poetry.group.image-onnx.dependencies]
|
|
28
|
-
onnxruntime = "^1.20" # no gpu for now
|
|
29
|
-
kserve = "0.16.0"
|
|
30
|
-
# torch = "^2.5.0"
|
|
31
|
-
# torchvision = "^0.20.0"
|
|
32
16
|
torch = {version = "^2.5.0", source = "pytorch-cpu"}
|
|
33
17
|
torchvision = {version = "^0.20.0", source = "pytorch-cpu"}
|
|
34
18
|
opencv-python-headless = "4.11.0.86"
|
|
@@ -36,6 +20,16 @@ Pillow = "10.0.1"
|
|
|
36
20
|
python-json-logger = "2.0.7"
|
|
37
21
|
gcsfs = "^2024.10.0"
|
|
38
22
|
|
|
23
|
+
scikit-learn = "1.5.2"
|
|
24
|
+
xgboost = "2.1.2"
|
|
25
|
+
|
|
26
|
+
onnxruntime-gpu = {version = "^1.20", markers = "sys_platform == 'linux' and platform_machine == 'x86_64' or sys_platform == 'win32' and platform_machine == 'AMD64'"}
|
|
27
|
+
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
|
+
|
|
29
|
+
[tool.poetry.group.dev.dependencies]
|
|
30
|
+
black = "24.10.0"
|
|
31
|
+
pytest = "8.3.3"
|
|
32
|
+
|
|
39
33
|
[build-system]
|
|
40
34
|
requires = ["poetry-core"]
|
|
41
35
|
build-backend = "poetry.core.masonry.api"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{orient_express-2.0 → orient_express-2.1}/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
|