smartpool-examples 0.1.6__tar.gz → 0.1.7__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.
- {smartpool_examples-0.1.6/smartpool_examples.egg-info → smartpool_examples-0.1.7}/PKG-INFO +2 -2
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/pyproject.toml +2 -2
- smartpool_examples-0.1.7/smartpool_examples/__init__.py +1 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/count_prime/__main__.py +24 -4
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/__main__.py +1 -1
- smartpool_examples-0.1.7/smartpool_examples/onnx_infer/__main__.py +158 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/onnx_infer/config.py +2 -6
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/onnx_infer/data_utils.py +60 -22
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/onnx_infer/inference.py +133 -130
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7/smartpool_examples.egg-info}/PKG-INFO +2 -2
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples.egg-info/requires.txt +1 -1
- smartpool_examples-0.1.6/smartpool_examples/onnx_infer/__init__.py +0 -0
- smartpool_examples-0.1.6/smartpool_examples/onnx_infer/__main__.py +0 -88
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/LICENSE +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/README.md +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/setup.cfg +0 -0
- {smartpool_examples-0.1.6/smartpool_examples → smartpool_examples-0.1.7/smartpool_examples/count_prime}/__init__.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/count_prime/count_prime.py +0 -0
- {smartpool_examples-0.1.6/smartpool_examples/count_prime → smartpool_examples-0.1.7/smartpool_examples/cross_validation}/__init__.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/config.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/data_utils.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/model_utils.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/models/LeNet5.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/models/MLP.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/models/ModernCNN.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/models/ResNeXt.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/models/ResNeXtV2.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/models/ResNet.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/models/ResNetV2.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/models/__init__.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/visualization.py +0 -0
- {smartpool_examples-0.1.6/smartpool_examples/cross_validation → smartpool_examples-0.1.7/smartpool_examples/onnx_infer}/__init__.py +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples.egg-info/SOURCES.txt +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples.egg-info/dependency_links.txt +0 -0
- {smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smartpool-examples
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Examples for smartpool.
|
|
5
5
|
Author-email: "王炳辉 (Bing-Hui WANG)" <binghui.wang@foxmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -11,7 +11,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: pysmartpool>=0.1.
|
|
14
|
+
Requires-Dist: pysmartpool>=0.1.7
|
|
15
15
|
Requires-Dist: matplotlib
|
|
16
16
|
Requires-Dist: scikit-learn
|
|
17
17
|
Requires-Dist: numpy
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "smartpool-examples"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.7"
|
|
8
8
|
description = "Examples for smartpool."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -17,7 +17,7 @@ classifiers = [
|
|
|
17
17
|
"Operating System :: OS Independent",
|
|
18
18
|
]
|
|
19
19
|
dependencies = [
|
|
20
|
-
"pysmartpool>=0.1.
|
|
20
|
+
"pysmartpool>=0.1.7",
|
|
21
21
|
"matplotlib",
|
|
22
22
|
"scikit-learn",
|
|
23
23
|
"numpy",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.7"
|
{smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/count_prime/__main__.py
RENAMED
|
@@ -8,12 +8,28 @@ if __name__ == "__main__":
|
|
|
8
8
|
target_folder = os.path.abspath(self_folder + "/../../../smartpool").replace("\\", "/")
|
|
9
9
|
sys.path.append(target_folder)
|
|
10
10
|
|
|
11
|
+
import typer
|
|
11
12
|
from count_prime import count_prime
|
|
12
13
|
|
|
13
|
-
from smartpool import ProcessPool
|
|
14
|
+
from smartpool import InterpreterPool, ProcessPool, ThreadPool
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
app = typer.Typer()
|
|
17
|
+
|
|
18
|
+
POOL_MAP = {
|
|
19
|
+
"ThreadPool": ThreadPool,
|
|
20
|
+
"ProcessPool": ProcessPool,
|
|
21
|
+
"InterpreterPool": InterpreterPool,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@app.command()
|
|
26
|
+
def main(pool: str = typer.Option("ProcessPool", "--pool", help="Pool type to use")):
|
|
27
|
+
pool_cls = POOL_MAP.get(pool)
|
|
28
|
+
if pool_cls is None:
|
|
29
|
+
print(f"Unknown pool: {pool}. Choose from {list(POOL_MAP.keys())}")
|
|
30
|
+
raise typer.Exit(code=1)
|
|
31
|
+
|
|
32
|
+
print(f"Use {pool} to count prime numbers lower than 10000.")
|
|
17
33
|
print(f"See source code at folder {self_folder}")
|
|
18
34
|
|
|
19
35
|
tasks = []
|
|
@@ -23,7 +39,7 @@ if __name__ == "__main__":
|
|
|
23
39
|
tasks.append((start, stop))
|
|
24
40
|
start = stop
|
|
25
41
|
|
|
26
|
-
with
|
|
42
|
+
with pool_cls() as pool:
|
|
27
43
|
futures = []
|
|
28
44
|
for task in tasks:
|
|
29
45
|
future = pool.submit(count_prime, args=task)
|
|
@@ -31,3 +47,7 @@ if __name__ == "__main__":
|
|
|
31
47
|
|
|
32
48
|
total_primes_count = sum(future.result() for future in futures)
|
|
33
49
|
print(total_primes_count)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
if __name__ == "__main__":
|
|
53
|
+
app()
|
|
@@ -47,8 +47,8 @@ def main(
|
|
|
47
47
|
help="max number of workers to use, 0 to use all available cores"
|
|
48
48
|
)
|
|
49
49
|
):
|
|
50
|
-
import os
|
|
51
50
|
import importlib
|
|
51
|
+
import os
|
|
52
52
|
os.environ["RAY_ACCEL_ENV_VAR_OVERRIDE_ON_ZERO"] = "0"
|
|
53
53
|
|
|
54
54
|
print(f"Use {pool} to do 5-fold cross validatation for 7 deep learning models for handwritten digit recognition task.")
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
if __name__ == "__main__":
|
|
2
|
+
import os
|
|
3
|
+
import sys
|
|
4
|
+
self_folder = os.path.dirname(os.path.abspath(__file__)).replace("\\", "/")
|
|
5
|
+
target_folder = os.path.abspath(self_folder + "/../../../smartpool").replace("\\", "/")
|
|
6
|
+
sys.path.append(target_folder)
|
|
7
|
+
|
|
8
|
+
import typer
|
|
9
|
+
|
|
10
|
+
app = typer.Typer(help="Use smartpool to do YOLOv8n ONNX inference on COCO val2017 with real-time progress.")
|
|
11
|
+
|
|
12
|
+
@app.command()
|
|
13
|
+
def main(
|
|
14
|
+
thread_pool_max_workers: int = typer.Option(
|
|
15
|
+
4,
|
|
16
|
+
"--thread_pool_max_workers",
|
|
17
|
+
help="max number of thread pool (for preprocess and postprocess) workers to use, 0 to use all available cores"
|
|
18
|
+
),
|
|
19
|
+
session_pool_max_workers: int = typer.Option(
|
|
20
|
+
0,
|
|
21
|
+
"--session_pool_max_workers",
|
|
22
|
+
help="max number of infer session pool workers to use, 0 to use all available cores"
|
|
23
|
+
),
|
|
24
|
+
):
|
|
25
|
+
import os
|
|
26
|
+
|
|
27
|
+
print("Use `python -m smartpool_examples.onnx_infer --help` to see all options.")
|
|
28
|
+
print(f"See source code at folder {os.path.dirname(os.path.abspath(__file__))}")
|
|
29
|
+
print()
|
|
30
|
+
|
|
31
|
+
try:
|
|
32
|
+
import onnxruntime
|
|
33
|
+
except ImportError:
|
|
34
|
+
print("ONNX Runtime is not installed. Follow https://onnxruntime.ai/docs/install/ instructions to install ONNX Runtime.")
|
|
35
|
+
exit(1)
|
|
36
|
+
|
|
37
|
+
import queue
|
|
38
|
+
import time
|
|
39
|
+
from functools import partial
|
|
40
|
+
|
|
41
|
+
from rich.console import Group
|
|
42
|
+
from rich.live import Live
|
|
43
|
+
from rich.progress import (
|
|
44
|
+
BarColumn,
|
|
45
|
+
Progress,
|
|
46
|
+
TextColumn,
|
|
47
|
+
TimeRemainingColumn,
|
|
48
|
+
)
|
|
49
|
+
from rich.text import Text
|
|
50
|
+
|
|
51
|
+
from smartpool import DataSize, GPUInfo, InferSessionPool, Resource, ThreadPool
|
|
52
|
+
|
|
53
|
+
self_folder = os.path.dirname(os.path.abspath(__file__)).replace("\\", "/")
|
|
54
|
+
sys.path.append(self_folder)
|
|
55
|
+
|
|
56
|
+
from concurrent.futures import Future
|
|
57
|
+
|
|
58
|
+
from config import DATASET_DIR, MODEL_PATH, OUTPUT_DIR
|
|
59
|
+
from data_utils import download_dataset, download_model
|
|
60
|
+
from inference import postprocess, preprocess
|
|
61
|
+
|
|
62
|
+
download_model()
|
|
63
|
+
download_dataset()
|
|
64
|
+
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
65
|
+
|
|
66
|
+
image_paths = sorted(DATASET_DIR.glob("*.jpg"))
|
|
67
|
+
model_path_str = str(MODEL_PATH.resolve())
|
|
68
|
+
output_dir_str = str(OUTPUT_DIR.resolve())
|
|
69
|
+
|
|
70
|
+
thread_pool = ThreadPool(max_workers=thread_pool_max_workers)
|
|
71
|
+
infer_session_pool = InferSessionPool(model_path_str, max_workers=session_pool_max_workers)
|
|
72
|
+
|
|
73
|
+
cpu_res = Resource(
|
|
74
|
+
cpu_cores_in_python=1,
|
|
75
|
+
cpu_cores_out_of_python=1,
|
|
76
|
+
cpu_mem=81*DataSize.MB
|
|
77
|
+
)
|
|
78
|
+
gpu_res = Resource(
|
|
79
|
+
cpu_cores_in_python=1,
|
|
80
|
+
cpu_cores_out_of_python=1,
|
|
81
|
+
cpu_mem=200*DataSize.MB,
|
|
82
|
+
gpu_cores=100,
|
|
83
|
+
gpu_mem=200*DataSize.MB
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
result_queue = queue.Queue()
|
|
87
|
+
|
|
88
|
+
with Progress(
|
|
89
|
+
TextColumn("[progress.description]{task.description}"),
|
|
90
|
+
BarColumn(),
|
|
91
|
+
TextColumn("{task.completed}/{task.total}"),
|
|
92
|
+
TimeRemainingColumn(),
|
|
93
|
+
) as progress, Live(refresh_per_second=4) as live:
|
|
94
|
+
n_tasks = len(image_paths)
|
|
95
|
+
preprocess_submit_progress_task = progress.add_task("preprocess submit", total=n_tasks)
|
|
96
|
+
preprocess_done_progress_task = progress.add_task("preprocess done", total=n_tasks)
|
|
97
|
+
infer_submit_progress_task = progress.add_task("infer submit", total=n_tasks)
|
|
98
|
+
infer_done_progress_task = progress.add_task("infer done", total=n_tasks)
|
|
99
|
+
postprocess_submit_progress_task = progress.add_task("postprocess submit", total=n_tasks)
|
|
100
|
+
postprocess_done_progress_task = progress.add_task("postprocess done", total=n_tasks)
|
|
101
|
+
|
|
102
|
+
def update_task_count():
|
|
103
|
+
lines = []
|
|
104
|
+
for provider in GPUInfo.supported_onnx_providers():
|
|
105
|
+
lines.append(Text(f"task count infer with {provider}: {infer_session_pool.task_count_with_provider(provider)}"))
|
|
106
|
+
live.update(Group(*lines))
|
|
107
|
+
|
|
108
|
+
def postprocess_done_callback(postprocess_future: Future):
|
|
109
|
+
update_task_count()
|
|
110
|
+
postprocess_future.result()
|
|
111
|
+
progress.update(postprocess_done_progress_task, advance=1)
|
|
112
|
+
result_queue.put(1)
|
|
113
|
+
|
|
114
|
+
def infer_done_callback(image_path, img, scale, pad, infer_future: Future):
|
|
115
|
+
update_task_count()
|
|
116
|
+
outputs = infer_future.result()[0]
|
|
117
|
+
progress.update(infer_done_progress_task, advance=1)
|
|
118
|
+
|
|
119
|
+
output_path = output_dir_str + "/" + os.path.basename(image_path)
|
|
120
|
+
postprocess_future: Future = thread_pool.submit(
|
|
121
|
+
postprocess,
|
|
122
|
+
args=(img, outputs, output_path, scale, pad),
|
|
123
|
+
cpu_mode_res=cpu_res
|
|
124
|
+
)
|
|
125
|
+
progress.update(postprocess_submit_progress_task, advance=1)
|
|
126
|
+
postprocess_future.add_done_callback(postprocess_done_callback)
|
|
127
|
+
|
|
128
|
+
def preprocess_done_callback(image_path, preprocess_future: Future):
|
|
129
|
+
update_task_count()
|
|
130
|
+
progress.update(preprocess_done_progress_task, advance=1)
|
|
131
|
+
img, blob, scale, pad = preprocess_future.result()
|
|
132
|
+
infer_future: Future = infer_session_pool.submit(args=(blob,), cpu_mode_res=cpu_res, gpu_mode_res=gpu_res)
|
|
133
|
+
progress.update(infer_submit_progress_task, advance=1)
|
|
134
|
+
infer_future.add_done_callback(partial(infer_done_callback, image_path, img, scale, pad))
|
|
135
|
+
|
|
136
|
+
for image_path in image_paths:
|
|
137
|
+
update_task_count()
|
|
138
|
+
image_path = str(image_path)
|
|
139
|
+
preprocess_future: Future = thread_pool.submit(
|
|
140
|
+
preprocess,
|
|
141
|
+
args=(image_path,),
|
|
142
|
+
cpu_mode_res=cpu_res
|
|
143
|
+
)
|
|
144
|
+
progress.update(preprocess_submit_progress_task, advance=1)
|
|
145
|
+
preprocess_future.add_done_callback(partial(preprocess_done_callback, image_path))
|
|
146
|
+
|
|
147
|
+
start_time = time.perf_counter()
|
|
148
|
+
|
|
149
|
+
for _ in range(n_tasks):
|
|
150
|
+
result_queue.get()
|
|
151
|
+
|
|
152
|
+
elapsed = time.perf_counter() - start_time
|
|
153
|
+
print(f"\ninference completed in {elapsed:.2f} seconds")
|
|
154
|
+
print(f"Output: {OUTPUT_DIR.resolve()}")
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
if __name__ == "__main__":
|
|
158
|
+
app()
|
{smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/onnx_infer/config.py
RENAMED
|
@@ -8,12 +8,8 @@ OUTPUT_DIR = PACKAGE_DIR / "data" / "output"
|
|
|
8
8
|
MODEL_URL = "https://hf-mirror.com/Kalray/yolov8/resolve/main/yolov8n.onnx"
|
|
9
9
|
MODEL_PATH = MODEL_DIR / "yolov8n.onnx"
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
"000000000139", "000000000285", "000000000632", "000000000724", "000000000776",
|
|
14
|
-
"000000000785", "000000000802", "000000000872", "000000001000", "000000001268",
|
|
15
|
-
"000000001296", "000000001353", "000000001490", "000000001503", "000000001532",
|
|
16
|
-
"000000001584", "000000001675", "000000001818", "000000096001", "000000202001",
|
|
11
|
+
COCO_ZIP_URLS = [
|
|
12
|
+
"http://images.cocodataset.org/zips/val2017.zip",
|
|
17
13
|
]
|
|
18
14
|
|
|
19
15
|
COCO_CLASSES = [
|
{smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/onnx_infer/data_utils.py
RENAMED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
+
import contextlib
|
|
1
2
|
import time
|
|
2
3
|
import urllib.error
|
|
3
4
|
import urllib.request
|
|
5
|
+
import zipfile
|
|
4
6
|
from pathlib import Path
|
|
5
7
|
|
|
6
|
-
from config import
|
|
7
|
-
COCO_IMAGE_IDS,
|
|
8
|
-
COCO_IMAGE_URL,
|
|
9
|
-
DATASET_DIR,
|
|
10
|
-
MODEL_PATH,
|
|
11
|
-
MODEL_URL,
|
|
12
|
-
)
|
|
8
|
+
from config import COCO_ZIP_URLS, DATASET_DIR, MODEL_PATH, MODEL_URL
|
|
13
9
|
from rich.progress import (
|
|
14
10
|
BarColumn,
|
|
15
11
|
DownloadColumn,
|
|
@@ -27,7 +23,7 @@ def download_file(url: str, dest: Path, desc: str = "", max_retries: int = 3):
|
|
|
27
23
|
for attempt in range(1, max_retries + 1):
|
|
28
24
|
try:
|
|
29
25
|
req = urllib.request.Request(url, method="GET")
|
|
30
|
-
resp = urllib.request.urlopen(req, timeout=
|
|
26
|
+
resp = urllib.request.urlopen(req, timeout=120)
|
|
31
27
|
total = int(resp.headers.get("Content-Length", 0))
|
|
32
28
|
chunk_size = 8192
|
|
33
29
|
with Progress(
|
|
@@ -48,6 +44,13 @@ def download_file(url: str, dest: Path, desc: str = "", max_retries: int = 3):
|
|
|
48
44
|
pbar.update(task, advance=len(chunk))
|
|
49
45
|
tmp.rename(dest)
|
|
50
46
|
return
|
|
47
|
+
except urllib.error.HTTPError as e:
|
|
48
|
+
if e.code == 404:
|
|
49
|
+
raise
|
|
50
|
+
last_err = e
|
|
51
|
+
if attempt < max_retries:
|
|
52
|
+
delay = 2 ** attempt
|
|
53
|
+
time.sleep(delay)
|
|
51
54
|
except (urllib.error.URLError, TimeoutError, OSError) as e:
|
|
52
55
|
last_err = e
|
|
53
56
|
if attempt < max_retries:
|
|
@@ -56,23 +59,58 @@ def download_file(url: str, dest: Path, desc: str = "", max_retries: int = 3):
|
|
|
56
59
|
raise last_err
|
|
57
60
|
|
|
58
61
|
|
|
62
|
+
def _count_images():
|
|
63
|
+
return len(list(DATASET_DIR.rglob("*.jpg")))
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _flatten_images():
|
|
67
|
+
for p in list(DATASET_DIR.rglob("*.jpg")):
|
|
68
|
+
if p.parent is not DATASET_DIR:
|
|
69
|
+
p.replace(DATASET_DIR / p.name)
|
|
70
|
+
for p in list(DATASET_DIR.iterdir()):
|
|
71
|
+
if p.is_dir() and p.name != "val2017":
|
|
72
|
+
for f in list(p.rglob("*")):
|
|
73
|
+
if f.is_file():
|
|
74
|
+
f.unlink()
|
|
75
|
+
|
|
76
|
+
with contextlib.suppress(OSError):
|
|
77
|
+
p.rmdir()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def download_dataset():
|
|
81
|
+
DATASET_DIR.mkdir(parents=True, exist_ok=True)
|
|
82
|
+
|
|
83
|
+
_flatten_images()
|
|
84
|
+
if _count_images() > 4000:
|
|
85
|
+
print(f"[SKIP DOWNLOAD] Dataset exists ({_count_images()} images)")
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
print("[DOWNLOAD] val2017.zip (~1GB) ...")
|
|
89
|
+
zip_path = DATASET_DIR / "val2017.zip"
|
|
90
|
+
|
|
91
|
+
for url in COCO_ZIP_URLS:
|
|
92
|
+
try:
|
|
93
|
+
download_file(url, zip_path, "COCO val2017")
|
|
94
|
+
break
|
|
95
|
+
except Exception:
|
|
96
|
+
print(f" mirror failed: {url}")
|
|
97
|
+
continue
|
|
98
|
+
else:
|
|
99
|
+
raise RuntimeError("all mirrors failed")
|
|
100
|
+
|
|
101
|
+
print(f"[EXTRACT] val2017.zip -> {DATASET_DIR} ...")
|
|
102
|
+
with zipfile.ZipFile(zip_path) as zf:
|
|
103
|
+
zf.extractall(DATASET_DIR)
|
|
104
|
+
|
|
105
|
+
zip_path.unlink()
|
|
106
|
+
_flatten_images()
|
|
107
|
+
n = _count_images()
|
|
108
|
+
print(f"[DONE] {n} images ready")
|
|
109
|
+
|
|
110
|
+
|
|
59
111
|
def download_model():
|
|
60
112
|
if MODEL_PATH.exists():
|
|
61
113
|
print(f"[SKIP DOWNLOAD] Model {MODEL_PATH.name} exists")
|
|
62
114
|
return
|
|
63
115
|
print("[DOWNLOAD] YOLOv8n ONNX...")
|
|
64
116
|
download_file(MODEL_URL, MODEL_PATH, "YOLOv8n")
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
def download_dataset():
|
|
68
|
-
DATASET_DIR.mkdir(parents=True, exist_ok=True)
|
|
69
|
-
existing = {p.stem for p in DATASET_DIR.glob("*.jpg")}
|
|
70
|
-
to_dl = [iid for iid in COCO_IMAGE_IDS if iid not in existing]
|
|
71
|
-
if not to_dl:
|
|
72
|
-
print(f"[SKIP DOWNLOAD] Dataset exists ({len(COCO_IMAGE_IDS)} images)")
|
|
73
|
-
return
|
|
74
|
-
print(f"[DOWNLOAD] {len(to_dl)} COCO images...")
|
|
75
|
-
for iid in to_dl:
|
|
76
|
-
url = COCO_IMAGE_URL.format(iid)
|
|
77
|
-
dest = DATASET_DIR / f"{iid}.jpg"
|
|
78
|
-
download_file(url, dest, f"COCO {iid}")
|
{smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/onnx_infer/inference.py
RENAMED
|
@@ -1,130 +1,133 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
img,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
]
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
]
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
from concurrent.futures import Future
|
|
5
|
+
from typing import TYPE_CHECKING, Dict, List, Tuple
|
|
6
|
+
|
|
7
|
+
import cv2
|
|
8
|
+
import numpy as np
|
|
9
|
+
from config import COCO_CLASSES
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from smartpool import InferSessionPool, Resource
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def letterbox(img: np.ndarray, new_shape=(640, 640), color=(114, 114, 114)):
|
|
16
|
+
shape = img.shape[:2]
|
|
17
|
+
r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])
|
|
18
|
+
new_unpad = (int(round(shape[1] * r)), int(round(shape[0] * r)))
|
|
19
|
+
dw = new_shape[1] - new_unpad[0]
|
|
20
|
+
dh = new_shape[0] - new_unpad[1]
|
|
21
|
+
dw, dh = dw / 2, dh / 2
|
|
22
|
+
top = int(round(dh - 0.1))
|
|
23
|
+
bottom = int(round(dh + 0.1))
|
|
24
|
+
left = int(round(dw - 0.1))
|
|
25
|
+
right = int(round(dw + 0.1))
|
|
26
|
+
img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)
|
|
27
|
+
img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)
|
|
28
|
+
return img, r, (left, top)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def preprocess(image_path: str):
|
|
32
|
+
img = cv2.imread(image_path)
|
|
33
|
+
if img is None:
|
|
34
|
+
raise ValueError(f"failed to read image: {image_path}")
|
|
35
|
+
|
|
36
|
+
blob, scale, pad = letterbox(img)
|
|
37
|
+
blob = blob.astype(np.float32) / 255.0
|
|
38
|
+
blob = np.ascontiguousarray(blob.transpose(2, 0, 1)[np.newaxis, ...])
|
|
39
|
+
return img, blob, scale, pad
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def nms(boxes: np.ndarray, scores: np.ndarray, iou_threshold: float = 0.5):
|
|
43
|
+
if len(boxes) == 0:
|
|
44
|
+
return []
|
|
45
|
+
x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]
|
|
46
|
+
areas = (x2 - x1) * (y2 - y1)
|
|
47
|
+
order = scores.argsort()[::-1]
|
|
48
|
+
keep = []
|
|
49
|
+
while order.size > 0:
|
|
50
|
+
i = order[0]
|
|
51
|
+
keep.append(i)
|
|
52
|
+
xx1 = np.maximum(x1[i], x1[order[1:]])
|
|
53
|
+
yy1 = np.maximum(y1[i], y1[order[1:]])
|
|
54
|
+
xx2 = np.minimum(x2[i], x2[order[1:]])
|
|
55
|
+
yy2 = np.minimum(y2[i], y2[order[1:]])
|
|
56
|
+
w = np.maximum(0.0, xx2 - xx1)
|
|
57
|
+
h = np.maximum(0.0, yy2 - yy1)
|
|
58
|
+
inter = w * h
|
|
59
|
+
iou = inter / (areas[i] + areas[order[1:]] - inter)
|
|
60
|
+
inds = np.where(iou <= iou_threshold)[0]
|
|
61
|
+
order = order[inds + 1]
|
|
62
|
+
return keep
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def draw_detections(src_img: np.ndarray, output_path: str, detections: List[Dict]):
|
|
66
|
+
colors = [
|
|
67
|
+
(56, 56, 255), (151, 157, 255), (31, 112, 255), (29, 178, 255),
|
|
68
|
+
(49, 210, 207), (10, 249, 72), (23, 204, 146), (134, 219, 61),
|
|
69
|
+
(52, 147, 26), (187, 135, 1), (132, 145, 137), (168, 229, 11),
|
|
70
|
+
]
|
|
71
|
+
for det in detections:
|
|
72
|
+
x1, y1, x2, y2 = map(int, det["bbox"])
|
|
73
|
+
cls_id = det["class_id"]
|
|
74
|
+
score = det["score"]
|
|
75
|
+
color = colors[cls_id % len(colors)]
|
|
76
|
+
label = f"{COCO_CLASSES[cls_id]} {score:.2f}"
|
|
77
|
+
cv2.rectangle(src_img, (x1, y1), (x2, y2), color, 2)
|
|
78
|
+
(tw, th), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
|
|
79
|
+
cv2.rectangle(src_img, (x1, y1 - th - 4), (x1 + tw, y1), color, -1)
|
|
80
|
+
cv2.putText(src_img, label, (x1, y1 - 2), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
|
81
|
+
|
|
82
|
+
cv2.imwrite(output_path, src_img)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def postprocess(
|
|
86
|
+
src_img:np.ndarray, output: np.ndarray, output_path:str,
|
|
87
|
+
scale: float, pad: Tuple[int, int], conf_thresh: float = 0.5,
|
|
88
|
+
iou_thresh: float = 0.5
|
|
89
|
+
):
|
|
90
|
+
orig_shape = (src_img.shape[0], src_img.shape[1])
|
|
91
|
+
predictions = np.squeeze(output).T
|
|
92
|
+
box_data = predictions[:, :4]
|
|
93
|
+
class_scores = predictions[:, 4:]
|
|
94
|
+
scores = class_scores.max(axis=1)
|
|
95
|
+
class_ids = class_scores.argmax(axis=1)
|
|
96
|
+
mask = scores > conf_thresh
|
|
97
|
+
if not mask.any():
|
|
98
|
+
return []
|
|
99
|
+
boxes = box_data[mask]
|
|
100
|
+
scores = scores[mask]
|
|
101
|
+
class_ids = class_ids[mask]
|
|
102
|
+
|
|
103
|
+
boxes_xyxy = np.zeros_like(boxes)
|
|
104
|
+
boxes_xyxy[:, 0] = boxes[:, 0] - boxes[:, 2] / 2
|
|
105
|
+
boxes_xyxy[:, 1] = boxes[:, 1] - boxes[:, 3] / 2
|
|
106
|
+
boxes_xyxy[:, 2] = boxes[:, 0] + boxes[:, 2] / 2
|
|
107
|
+
boxes_xyxy[:, 3] = boxes[:, 1] + boxes[:, 3] / 2
|
|
108
|
+
|
|
109
|
+
keep = nms(boxes_xyxy, scores, iou_thresh)
|
|
110
|
+
if not keep:
|
|
111
|
+
return []
|
|
112
|
+
|
|
113
|
+
boxes_xyxy = boxes_xyxy[keep]
|
|
114
|
+
scores = scores[keep]
|
|
115
|
+
class_ids = class_ids[keep]
|
|
116
|
+
|
|
117
|
+
left, top = pad
|
|
118
|
+
boxes_xyxy = (boxes_xyxy - np.array([left, top, left, top])) / scale
|
|
119
|
+
boxes_xyxy = np.clip(boxes_xyxy, 0, [orig_shape[1], orig_shape[0], orig_shape[1], orig_shape[0]])
|
|
120
|
+
|
|
121
|
+
detections: List[Dict] = [
|
|
122
|
+
{"bbox": boxes_xyxy[i].tolist(), "score": float(scores[i]), "class_id": int(class_ids[i])}
|
|
123
|
+
for i in range(len(boxes_xyxy))
|
|
124
|
+
]
|
|
125
|
+
|
|
126
|
+
draw_detections(src_img, output_path, detections)
|
|
127
|
+
|
|
128
|
+
def infer_task(image_path:str, output_dir_path:str, infer_session_pool: InferSessionPool, cpu_res: Resource, gpu_res: Resource)->None:
|
|
129
|
+
img, blob, scale, pad = preprocess(image_path)
|
|
130
|
+
infer_future: Future = infer_session_pool.submit(args=(blob,), cpu_mode_res=cpu_res, gpu_mode_res=gpu_res)
|
|
131
|
+
outputs = infer_future.result()[0]
|
|
132
|
+
output_path = output_dir_path + "/" + os.path.basename(image_path)
|
|
133
|
+
postprocess(img, outputs, output_path, scale, pad)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: smartpool-examples
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Examples for smartpool.
|
|
5
5
|
Author-email: "王炳辉 (Bing-Hui WANG)" <binghui.wang@foxmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -11,7 +11,7 @@ Classifier: License :: OSI Approved :: MIT License
|
|
|
11
11
|
Classifier: Operating System :: OS Independent
|
|
12
12
|
Description-Content-Type: text/markdown
|
|
13
13
|
License-File: LICENSE
|
|
14
|
-
Requires-Dist: pysmartpool>=0.1.
|
|
14
|
+
Requires-Dist: pysmartpool>=0.1.7
|
|
15
15
|
Requires-Dist: matplotlib
|
|
16
16
|
Requires-Dist: scikit-learn
|
|
17
17
|
Requires-Dist: numpy
|
|
File without changes
|
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
if __name__ == "__main__":
|
|
2
|
-
import os
|
|
3
|
-
import sys
|
|
4
|
-
self_folder = os.path.dirname(os.path.abspath(__file__)).replace("\\", "/")
|
|
5
|
-
target_folder = os.path.abspath(self_folder + "/../../../smartpool").replace("\\", "/")
|
|
6
|
-
sys.path.append(target_folder)
|
|
7
|
-
|
|
8
|
-
import os
|
|
9
|
-
import time
|
|
10
|
-
from concurrent.futures import as_completed
|
|
11
|
-
|
|
12
|
-
import typer
|
|
13
|
-
from rich.progress import (
|
|
14
|
-
BarColumn,
|
|
15
|
-
Progress,
|
|
16
|
-
TextColumn,
|
|
17
|
-
TimeRemainingColumn,
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
from smartpool import InferSessionPool, Resource, ThreadPool
|
|
21
|
-
|
|
22
|
-
app = typer.Typer(help="Use smartpool to do YOLOv8n ONNX inference on COCO val2017 with real-time progress.")
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@app.command()
|
|
26
|
-
def main(
|
|
27
|
-
max_workers: int = typer.Option(
|
|
28
|
-
0,
|
|
29
|
-
"--max_workers",
|
|
30
|
-
help="max number of workers to use, 0 to use all available cores"
|
|
31
|
-
),
|
|
32
|
-
):
|
|
33
|
-
self_folder = os.path.dirname(os.path.abspath(__file__)).replace("\\", "/")
|
|
34
|
-
sys.path.append(self_folder)
|
|
35
|
-
|
|
36
|
-
from config import DATASET_DIR, MODEL_PATH, OUTPUT_DIR
|
|
37
|
-
from data_utils import download_dataset, download_model
|
|
38
|
-
from inference import infer_task
|
|
39
|
-
|
|
40
|
-
print("Use `python -m smartpool_examples.onnx_infer --help` to see all options.")
|
|
41
|
-
print(f"See source code at folder {os.path.dirname(os.path.abspath(__file__))}")
|
|
42
|
-
print()
|
|
43
|
-
|
|
44
|
-
download_model()
|
|
45
|
-
download_dataset()
|
|
46
|
-
OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
|
|
47
|
-
|
|
48
|
-
image_paths = sorted(DATASET_DIR.glob("*.jpg"))
|
|
49
|
-
cpu_res = Resource(cpu_cores_in_python=1, cpu_mem=2*1024**3)
|
|
50
|
-
|
|
51
|
-
model_path_str = str(MODEL_PATH.resolve())
|
|
52
|
-
output_dir_str = str(OUTPUT_DIR.resolve())
|
|
53
|
-
n_workers = max_workers
|
|
54
|
-
|
|
55
|
-
print(f"\nSubmit {len(image_paths)} tasks to ThreadPool({n_workers})...")
|
|
56
|
-
thread_pool = ThreadPool(max_workers=n_workers)
|
|
57
|
-
infer_session_pool = InferSessionPool(max_workers=n_workers)
|
|
58
|
-
infer_session_pool.print_info = True
|
|
59
|
-
|
|
60
|
-
futures = []
|
|
61
|
-
for path in image_paths:
|
|
62
|
-
future = thread_pool.submit(
|
|
63
|
-
infer_task,
|
|
64
|
-
args=(str(path), model_path_str, output_dir_str, infer_session_pool),
|
|
65
|
-
cpu_mode_res=cpu_res
|
|
66
|
-
)
|
|
67
|
-
futures.append(future)
|
|
68
|
-
|
|
69
|
-
start_time = time.perf_counter()
|
|
70
|
-
with Progress(
|
|
71
|
-
TextColumn("[progress.description]{task.description}"),
|
|
72
|
-
BarColumn(),
|
|
73
|
-
TextColumn("{task.completed}/{task.total}"),
|
|
74
|
-
TimeRemainingColumn(),
|
|
75
|
-
) as progress:
|
|
76
|
-
task = progress.add_task("infer", total=len(futures))
|
|
77
|
-
for f in as_completed(futures):
|
|
78
|
-
f.result()
|
|
79
|
-
progress.update(task, advance=1)
|
|
80
|
-
progress.update(task, description=f"infer [{progress.tasks[0].completed}/{progress.tasks[0].total}]")
|
|
81
|
-
|
|
82
|
-
elapsed = time.perf_counter() - start_time
|
|
83
|
-
print(f"\ninference completed in {elapsed:.2f} seconds")
|
|
84
|
-
print(f"Output: {OUTPUT_DIR.resolve()}")
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if __name__ == "__main__":
|
|
88
|
-
app()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/count_prime/count_prime.py
RENAMED
|
File without changes
|
|
File without changes
|
{smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples/cross_validation/config.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{smartpool_examples-0.1.6 → smartpool_examples-0.1.7}/smartpool_examples.egg-info/top_level.txt
RENAMED
|
File without changes
|