Wanli
commited on
Commit
·
0e997e3
1
Parent(s):
41c69c8
update generate table script (#164)
Browse files- benchmark/README.md +0 -26
- benchmark/color_table.svg +0 -0
- benchmark/generate_table.py +208 -85
- benchmark/table_config.yaml +219 -0
benchmark/README.md
CHANGED
|
@@ -57,32 +57,6 @@ python benchmark.py --all --cfg_overwrite_backend_target 1
|
|
| 57 |
|
| 58 |
Benchmark is done with latest `opencv-python==4.7.0.72` and `opencv-contrib-python==4.7.0.72` on the following platforms. Some models are excluded because of support issues.
|
| 59 |
|
| 60 |
-
|
| 61 |
-
| Model | Task | Input Size | CPU-INTEL (ms) | CPU-RPI (ms) | CPU-RV1126 (ms) | CPU-KVE2 (ms) | CPU-HSX3 (ms) | CPU-AXP (ms) | GPU-JETSON (ms) | NPU-KV3 (ms) | NPU-Ascend310 (ms) | CPU-D1 (ms) |
|
| 62 |
-
| -------------------------------------------------------- | ----------------------------- | ---------- | -------------- | ------------ | --------------- | ------------- | ------------- | ------------ | --------------- | ------------ | ------------------ | ----------- |
|
| 63 |
-
| [YuNet](../models/face_detection_yunet) | Face Detection | 160x120 | 0.72 | 5.43 | 68.89 | 2.47 | 11.04 | 98.16 | 12.18 | 4.04 | 2.24 | 86.69 |
|
| 64 |
-
| [SFace](../models/face_recognition_sface) | Face Recognition | 112x112 | 6.04 | 78.83 | 1550.71 | 33.79 | 140.83 | 2093.12 | 24.88 | 46.25 | 2.66 | --- |
|
| 65 |
-
| [FER](../models/facial_expression_recognition/) | Facial Expression Recognition | 112x112 | 3.16 | 32.53 | 604.36 | 15.99 | 64.96 | 811.32 | 31.07 | 29.80 | 2.19 | --- |
|
| 66 |
-
| [LPD-YuNet](../models/license_plate_detection_yunet/) | License Plate Detection | 320x240 | 8.63 | 167.70 | 3222.92 | 57.57 | 283.75 | 4300.13 | 56.12 | 29.53 | 7.63 | --- |
|
| 67 |
-
| [YOLOX](../models/object_detection_yolox/) | Object Detection | 640x640 | 141.20 | 1805.87 | 38359.93 | 577.93 | 2749.22 | 49994.75 | 388.95 | 420.98 | 28.59 | --- |
|
| 68 |
-
| [NanoDet](../models/object_detection_nanodet/) | Object Detection | 416x416 | 66.03 | 225.10 | 2303.55 | 118.38 | 408.16 | 3360.20 | 64.94 | 116.64 | 20.62 | --- |
|
| 69 |
-
| [DB-IC15](../models/text_detection_db) (EN) | Text Detection | 640x480 | 71.03 | 1862.75 | 49065.03 | 394.77 | 1908.87 | 65681.91 | 208.41 | --- | 17.15 | --- |
|
| 70 |
-
| [DB-TD500](../models/text_detection_db) (EN&CN) | Text Detection | 640x480 | 72.31 | 1878.45 | 49052.24 | 392.52 | 1922.34 | 65630.56 | 210.51 | --- | 17.95 | --- |
|
| 71 |
-
| [CRNN-EN](../models/text_recognition_crnn) | Text Recognition | 100x32 | 20.16 | 278.11 | 2230.12 | 77.51 | 464.58 | 3277.07 | 196.15 | 125.30 | --- | --- |
|
| 72 |
-
| [CRNN-CN](../models/text_recognition_crnn) | Text Recognition | 100x32 | 23.07 | 297.48 | 2244.03 | 82.93 | 495.94 | 3330.69 | 239.76 | 166.79 | --- | --- |
|
| 73 |
-
| [PP-ResNet](../models/image_classification_ppresnet) | Image Classification | 224x224 | 34.71 | 463.93 | 11793.09 | 178.87 | 759.81 | 15753.56 | 98.64 | 75.45 | 6.99 | --- |
|
| 74 |
-
| [MobileNet-V1](../models/image_classification_mobilenet) | Image Classification | 224x224 | 5.90 | 72.33 | 1546.16 | 32.78 | 140.60 | 2091.13 | 33.18 | 145.66\* | 5.15 | --- |
|
| 75 |
-
| [MobileNet-V2](../models/image_classification_mobilenet) | Image Classification | 224x224 | 5.97 | 66.56 | 1166.56 | 28.38 | 122.53 | 1583.25 | 31.92 | 146.31\* | 5.41 | --- |
|
| 76 |
-
| [PP-HumanSeg](../models/human_segmentation_pphumanseg) | Human Segmentation | 192x192 | 8.81 | 73.13 | 1610.78 | 34.58 | 144.23 | 2157.86 | 67.97 | 74.77 | 6.94 | --- |
|
| 77 |
-
| [WeChatQRCode](../models/qrcode_wechatqrcode) | QR Code Detection and Parsing | 100x100 | 1.29 | 5.71 | --- | --- | --- | --- | --- | --- | --- | --- |
|
| 78 |
-
| [DaSiamRPN](../models/object_tracking_dasiamrpn) | Object Tracking | 1280x720 | 29.05 | 712.94 | 14738.64 | 152.78 | 929.63 | 19800.14 | 76.82 | --- | --- | --- |
|
| 79 |
-
| [YoutuReID](../models/person_reid_youtureid) | Person Re-Identification | 128x256 | 30.39 | 625.56 | 11117.07 | 195.67 | 898.23 | 14886.02 | 90.07 | 44.61 | 5.58 | --- |
|
| 80 |
-
| [MP-PalmDet](../models/palm_detection_mediapipe) | Palm Detection | 192x192 | 6.29 | 86.83 | 872.09 | 38.03 | 142.23 | 1191.81 | 83.20 | 33.81 | 5.17 | --- |
|
| 81 |
-
| [MP-HandPose](../models/handpose_estimation_mediapipe) | Hand Pose Estimation | 224x224 | 4.68 | 43.57 | 460.56 | 20.27 | 80.67 | 636.22 | 40.10 | 19.47 | 6.27 | --- |
|
| 82 |
-
| [MP-PersonDet](../models/person_detection_mediapipe) | Person Detection | 224x224 | 13.88 | 98.52 | 1326.56 | 46.07 | 191.41 | 1835.97 | 56.69 | --- | 16.45 | --- |
|
| 83 |
-
|
| 84 |
-
\*: Models are quantized in per-channel mode, which run slower than per-tensor quantized models on NPU.
|
| 85 |
-
|
| 86 |
### Intel 12700K
|
| 87 |
|
| 88 |
Specs: [details](https://www.intel.com/content/www/us/en/products/sku/134594/intel-core-i712700k-processor-25m-cache-up-to-5-00-ghz/specifications.html)
|
|
|
|
| 57 |
|
| 58 |
Benchmark is done with latest `opencv-python==4.7.0.72` and `opencv-contrib-python==4.7.0.72` on the following platforms. Some models are excluded because of support issues.
|
| 59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
### Intel 12700K
|
| 61 |
|
| 62 |
Specs: [details](https://www.intel.com/content/www/us/en/products/sku/134594/intel-core-i712700k-processor-25m-cache-up-to-5-00-ghz/specifications.html)
|
benchmark/color_table.svg
CHANGED
|
|
|
|
benchmark/generate_table.py
CHANGED
|
@@ -2,94 +2,193 @@ import re
|
|
| 2 |
import matplotlib.pyplot as plt
|
| 3 |
import matplotlib as mpl
|
| 4 |
import numpy as np
|
|
|
|
| 5 |
|
| 6 |
-
mpl.use("svg")
|
| 7 |
|
| 8 |
# parse a '.md' file and find a table. return table information
|
| 9 |
-
def parse_table(filepath):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
with open(filepath, "r", encoding="utf-8") as f:
|
| 11 |
content = f.read()
|
| 12 |
lines = content.split("\n")
|
| 13 |
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
for
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
return header, body
|
| 36 |
|
| 37 |
|
| 38 |
-
#
|
| 39 |
-
def
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
d = float(data[i])
|
| 55 |
-
if d > max_data:
|
| 56 |
-
max_data = d
|
| 57 |
-
max_idx = i
|
| 58 |
-
if d < min_data:
|
| 59 |
-
min_data = d
|
| 60 |
-
min_idx = i
|
| 61 |
-
except:
|
| 62 |
-
pass
|
| 63 |
-
|
| 64 |
-
min_list.append(min_idx)
|
| 65 |
-
max_list.append(max_idx)
|
| 66 |
-
|
| 67 |
-
# calculate colors
|
| 68 |
-
color = []
|
| 69 |
-
for t in data:
|
| 70 |
-
try:
|
| 71 |
-
t = (float(t) - min_data) / (max_data - min_data)
|
| 72 |
-
color.append(cmap(t))
|
| 73 |
-
except:
|
| 74 |
-
color.append('white')
|
| 75 |
-
colors.append(color)
|
| 76 |
-
return colors, min_list, max_list
|
| 77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 78 |
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
| 90 |
-
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
fig, axs = plt.subplots(nrows=3, figsize=(10, 0.8))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
gradient = np.linspace(0, 1, 256)
|
| 94 |
gradient = np.vstack((gradient, gradient))
|
| 95 |
axs[0].imshow(gradient, aspect='auto', cmap=cmap)
|
|
@@ -101,6 +200,24 @@ if __name__ == '__main__':
|
|
| 101 |
cellColours=table_colors,
|
| 102 |
cellLoc="left",
|
| 103 |
loc="upper left")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
# adjust table position
|
| 106 |
table_pos = axs[1].get_position()
|
|
@@ -122,24 +239,21 @@ if __name__ == '__main__':
|
|
| 122 |
cell = table.get_celld()[(i + 1, min_list[i])]
|
| 123 |
cell.set_text_props(weight='bold', color='white')
|
| 124 |
|
|
|
|
|
|
|
|
|
|
| 125 |
table_height = 0
|
| 126 |
table_width = 0
|
| 127 |
-
# calculate table height and width
|
| 128 |
for i in range(len(table_texts)):
|
| 129 |
cell = table.get_celld()[(i, 0)]
|
| 130 |
table_height += cell.get_height()
|
| 131 |
for i in range(len(table_texts[0])):
|
| 132 |
cell = table.get_celld()[(0, i)]
|
| 133 |
-
table_width += cell.get_width()
|
| 134 |
|
| 135 |
# add notes for table
|
| 136 |
-
axs[2].text(0, -table_height -
|
| 137 |
-
|
| 138 |
-
# turn off labels
|
| 139 |
-
for ax in axs:
|
| 140 |
-
ax.set_axis_off()
|
| 141 |
-
ax.set_xticks([])
|
| 142 |
-
ax.set_yticks([])
|
| 143 |
|
| 144 |
# adjust color map position to center
|
| 145 |
cm_pos = axs[0].get_position()
|
|
@@ -151,4 +265,13 @@ if __name__ == '__main__':
|
|
| 151 |
])
|
| 152 |
|
| 153 |
plt.rcParams['svg.fonttype'] = 'none'
|
| 154 |
-
plt.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
import matplotlib.pyplot as plt
|
| 3 |
import matplotlib as mpl
|
| 4 |
import numpy as np
|
| 5 |
+
import yaml
|
| 6 |
|
|
|
|
| 7 |
|
| 8 |
# parse a '.md' file and find a table. return table information
|
| 9 |
+
def parse_table(filepath, cfg):
|
| 10 |
+
# parse benchmark data
|
| 11 |
+
def _parse_benchmark_data(lines):
|
| 12 |
+
raw_data = []
|
| 13 |
+
for l in lines:
|
| 14 |
+
l = l.strip()
|
| 15 |
+
# parse each line
|
| 16 |
+
m = re.match(r"(\d+\.?\d*)\s+(\d+\.?\d*)\s+(\d+\.?\d*)\s+\[([^]]*)]\s+(.*)", l)
|
| 17 |
+
if m:
|
| 18 |
+
raw_data.append(m.groups())
|
| 19 |
+
return raw_data
|
| 20 |
+
|
| 21 |
+
# find each cpu, gpu, npu block
|
| 22 |
+
def _find_all_platform_block(lines):
|
| 23 |
+
cur_start = None
|
| 24 |
+
cur_platform = None
|
| 25 |
+
platform_block = dict()
|
| 26 |
+
for i in range(len(lines)):
|
| 27 |
+
l = lines[i].strip()
|
| 28 |
+
# found start and end of a platform
|
| 29 |
+
if l.startswith("CPU") or l.startswith("GPU") or l.startswith("NPU"):
|
| 30 |
+
if cur_platform is not None:
|
| 31 |
+
platform_block[cur_platform] = (cur_start, i)
|
| 32 |
+
cur_platform = l[:-1]
|
| 33 |
+
cur_start = i + 1
|
| 34 |
+
continue
|
| 35 |
+
if cur_platform is not None and i == len(lines) - 1:
|
| 36 |
+
platform_block[cur_platform] = (cur_start, i)
|
| 37 |
+
for key in platform_block:
|
| 38 |
+
r = platform_block[key]
|
| 39 |
+
platform_block[key] = _parse_benchmark_data(lines[r[0]:r[1]])
|
| 40 |
+
|
| 41 |
+
return platform_block
|
| 42 |
+
|
| 43 |
+
# find device block
|
| 44 |
+
def _find_all_device_block(lines, level):
|
| 45 |
+
cur_start = None
|
| 46 |
+
cur_device_name = None
|
| 47 |
+
device_block = dict()
|
| 48 |
+
for i in range(len(lines)):
|
| 49 |
+
l = lines[i].strip()
|
| 50 |
+
m = re.match(r"^(#+)\s+(.*)", l)
|
| 51 |
+
# found start and end of a device
|
| 52 |
+
if m and len(m.group(1)) == level:
|
| 53 |
+
if cur_device_name is not None:
|
| 54 |
+
device_block[cur_device_name] = (cur_start, i)
|
| 55 |
+
cur_device_name = m.group(2)
|
| 56 |
+
cur_start = i + 1
|
| 57 |
+
continue
|
| 58 |
+
if cur_device_name is not None and i == len(lines) - 1:
|
| 59 |
+
device_block[cur_device_name] = (cur_start, i)
|
| 60 |
+
|
| 61 |
+
for key in device_block:
|
| 62 |
+
r = device_block[key]
|
| 63 |
+
device_block[key] = _find_all_platform_block(lines[r[0]:r[1]])
|
| 64 |
+
|
| 65 |
+
return device_block
|
| 66 |
+
|
| 67 |
+
# find detail block
|
| 68 |
+
def _find_detail_block(lines, title, level):
|
| 69 |
+
start = None
|
| 70 |
+
end = len(lines)
|
| 71 |
+
for i in range(len(lines)):
|
| 72 |
+
l = lines[i].strip()
|
| 73 |
+
m = re.match(r"^(#+)\s+(.*)", l)
|
| 74 |
+
# found start of detailed results block
|
| 75 |
+
if m and len(m.group(1)) == level and m.group(2) == title:
|
| 76 |
+
start = i + 1
|
| 77 |
+
continue
|
| 78 |
+
# found end of detailed results block
|
| 79 |
+
if start is not None and m and len(m.group(1)) <= level:
|
| 80 |
+
end = i
|
| 81 |
+
break
|
| 82 |
+
|
| 83 |
+
return _find_all_device_block(lines[start:end], level + 1)
|
| 84 |
+
|
| 85 |
with open(filepath, "r", encoding="utf-8") as f:
|
| 86 |
content = f.read()
|
| 87 |
lines = content.split("\n")
|
| 88 |
|
| 89 |
+
devices = cfg["Devices"]
|
| 90 |
+
models = cfg["Models"]
|
| 91 |
+
# display information of all devices
|
| 92 |
+
devices_display = [x['display_info'] for x in cfg["Devices"]]
|
| 93 |
+
header = ["Model", "Task", "Input Size"] + devices_display
|
| 94 |
+
body = [[x["name"], x["task"], x["input_size"]] + ["---"] * len(devices) for x in models]
|
| 95 |
+
table_raw_data = _find_detail_block(lines, title="Detailed Results", level=2)
|
| 96 |
+
|
| 97 |
+
device_name_header = [f"{x['name']}-{x['platform']}" for x in devices]
|
| 98 |
+
device_name_header = [""] * (len(header) - len(device_name_header)) + device_name_header
|
| 99 |
+
# device name map to model col idx
|
| 100 |
+
device_name_to_col_idx = {k: v for v, k in enumerate(device_name_header)}
|
| 101 |
+
# model name map to model row idx
|
| 102 |
+
model_name_to_row_idx = {k[0]: v for v, k in enumerate(body)}
|
| 103 |
+
# convert raw data to usage data
|
| 104 |
+
for device in devices:
|
| 105 |
+
raw_data = table_raw_data[device["name"]][device["platform"]]
|
| 106 |
+
col_idx = device_name_to_col_idx[f"{device['name']}-{device['platform']}"]
|
| 107 |
+
for model in models:
|
| 108 |
+
# find which row idx of this model
|
| 109 |
+
row_idx = model_name_to_row_idx[model["name"]]
|
| 110 |
+
model_idxs = [i for i in range(len(raw_data)) if model["keyword"] in raw_data[i][-1]]
|
| 111 |
+
if len(model_idxs) > 0:
|
| 112 |
+
# only choose the first one
|
| 113 |
+
model_idx = model_idxs[0]
|
| 114 |
+
# choose mean as value
|
| 115 |
+
body[row_idx][col_idx] = raw_data[model_idx][0]
|
| 116 |
+
# remove used data
|
| 117 |
+
for idx in sorted(model_idxs, reverse=True):
|
| 118 |
+
raw_data.pop(idx)
|
| 119 |
+
|
| 120 |
+
# handle suffix
|
| 121 |
+
for suffix in cfg["Suffixes"]:
|
| 122 |
+
row_idx = model_name_to_row_idx[suffix["model"]]
|
| 123 |
+
col_idx = device_name_to_col_idx[f"{suffix['device']}-{suffix['platform']}"]
|
| 124 |
+
body[row_idx][col_idx] += suffix["str"]
|
| 125 |
+
|
| 126 |
return header, body
|
| 127 |
|
| 128 |
|
| 129 |
+
# render table and save
|
| 130 |
+
def render_table(header, body, save_path, cfg, cmap_type):
|
| 131 |
+
# parse models information and return some data
|
| 132 |
+
def _parse_data(models_info, cmap, cfg):
|
| 133 |
+
min_list = []
|
| 134 |
+
max_list = []
|
| 135 |
+
colors = []
|
| 136 |
+
# model name map to idx
|
| 137 |
+
model_name_to_idx = {k["name"]: v for v, k in enumerate(cfg["Models"])}
|
| 138 |
+
for model in models_info:
|
| 139 |
+
# remove \*
|
| 140 |
+
data = [x.replace("\\*", "") for x in model]
|
| 141 |
+
# get max data
|
| 142 |
+
max_idx = -1
|
| 143 |
+
min_data = 9999999
|
| 144 |
+
min_idx = -1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 145 |
|
| 146 |
+
for i in range(len(data)):
|
| 147 |
+
try:
|
| 148 |
+
d = float(data[i])
|
| 149 |
+
if d < min_data:
|
| 150 |
+
min_data = d
|
| 151 |
+
min_idx = i
|
| 152 |
+
except:
|
| 153 |
+
pass
|
| 154 |
+
# set all bigger than acceptable time to red color
|
| 155 |
+
idx = model_name_to_idx[model[0]]
|
| 156 |
+
acc_time = cfg["Models"][idx]["acceptable_time"]
|
| 157 |
|
| 158 |
+
min_list.append(min_idx)
|
| 159 |
+
max_list.append(max_idx)
|
| 160 |
+
|
| 161 |
+
# calculate colors
|
| 162 |
+
color = []
|
| 163 |
+
for t in data:
|
| 164 |
+
try:
|
| 165 |
+
t = float(t)
|
| 166 |
+
if t > acc_time:
|
| 167 |
+
# all bigger time will be set to red
|
| 168 |
+
color.append(cmap(1.))
|
| 169 |
+
else:
|
| 170 |
+
# sqrt to make the result non-linear
|
| 171 |
+
t = np.sqrt((t - min_data) / (acc_time - min_data))
|
| 172 |
+
color.append(cmap(t))
|
| 173 |
+
except:
|
| 174 |
+
color.append('white')
|
| 175 |
+
colors.append(color)
|
| 176 |
+
return colors, min_list, max_list
|
| 177 |
+
|
| 178 |
+
cmap = mpl.colormaps.get_cmap(cmap_type)
|
| 179 |
+
table_colors, min_list, max_list = _parse_data(body, cmap, cfg)
|
| 180 |
+
table_texts = [header] + body
|
| 181 |
+
table_colors = [['white'] * len(header)] + table_colors
|
| 182 |
+
|
| 183 |
+
# create a figure, base width set to 1000, height set to 80
|
| 184 |
fig, axs = plt.subplots(nrows=3, figsize=(10, 0.8))
|
| 185 |
+
# turn off labels and axis
|
| 186 |
+
for ax in axs:
|
| 187 |
+
ax.set_axis_off()
|
| 188 |
+
ax.set_xticks([])
|
| 189 |
+
ax.set_yticks([])
|
| 190 |
+
|
| 191 |
+
# create and add a color map
|
| 192 |
gradient = np.linspace(0, 1, 256)
|
| 193 |
gradient = np.vstack((gradient, gradient))
|
| 194 |
axs[0].imshow(gradient, aspect='auto', cmap=cmap)
|
|
|
|
| 200 |
cellColours=table_colors,
|
| 201 |
cellLoc="left",
|
| 202 |
loc="upper left")
|
| 203 |
+
# set style of header, each url of hardware
|
| 204 |
+
ori_height = table[0, 0].get_height()
|
| 205 |
+
url_base = 'https://github.com/opencv/opencv_zoo/tree/master/benchmark#'
|
| 206 |
+
hw_urls = [f"{url_base}{x['name'].lower().replace(' ', '-')}" for x in cfg["Devices"]]
|
| 207 |
+
hw_urls = [""] * 3 + hw_urls
|
| 208 |
+
for col in range(len(header)):
|
| 209 |
+
cell = table[0, col]
|
| 210 |
+
cell.set_text_props(ha='center', weight='bold', linespacing=1.5, url=hw_urls[col])
|
| 211 |
+
cell.set_url(hw_urls[col])
|
| 212 |
+
cell.set_height(ori_height * 2.2)
|
| 213 |
+
|
| 214 |
+
url_base = 'https://github.com/opencv/opencv_zoo/tree/master/models/'
|
| 215 |
+
model_urls = [f"{url_base}{x['folder']}" for x in cfg["Models"]]
|
| 216 |
+
model_urls = [""] + model_urls
|
| 217 |
+
for row in range(len(body) + 1):
|
| 218 |
+
cell = table[row, 0]
|
| 219 |
+
cell.set_text_props(url=model_urls[row])
|
| 220 |
+
cell.set_url(model_urls[row])
|
| 221 |
|
| 222 |
# adjust table position
|
| 223 |
table_pos = axs[1].get_position()
|
|
|
|
| 239 |
cell = table.get_celld()[(i + 1, min_list[i])]
|
| 240 |
cell.set_text_props(weight='bold', color='white')
|
| 241 |
|
| 242 |
+
# draw table and trigger changing the column width value
|
| 243 |
+
fig.canvas.draw()
|
| 244 |
+
# calculate table height and width
|
| 245 |
table_height = 0
|
| 246 |
table_width = 0
|
|
|
|
| 247 |
for i in range(len(table_texts)):
|
| 248 |
cell = table.get_celld()[(i, 0)]
|
| 249 |
table_height += cell.get_height()
|
| 250 |
for i in range(len(table_texts[0])):
|
| 251 |
cell = table.get_celld()[(0, i)]
|
| 252 |
+
table_width += cell.get_width()
|
| 253 |
|
| 254 |
# add notes for table
|
| 255 |
+
axs[2].text(0, -table_height - 1, "Units: All data in milliseconds (ms).", va='bottom', ha='left', fontsize=11, transform=axs[1].transAxes)
|
| 256 |
+
axs[2].text(0, -table_height - 2, "\\*: Models are quantized in per-channel mode, which run slower than per-tensor quantized models on NPU.", va='bottom', ha='left', fontsize=11, transform=axs[1].transAxes)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 257 |
|
| 258 |
# adjust color map position to center
|
| 259 |
cm_pos = axs[0].get_position()
|
|
|
|
| 265 |
])
|
| 266 |
|
| 267 |
plt.rcParams['svg.fonttype'] = 'none'
|
| 268 |
+
plt.rcParams['svg.hashsalt'] = '11' # fix hash salt for avoiding id change
|
| 269 |
+
plt.savefig(save_path, format='svg', bbox_inches="tight", pad_inches=0, metadata={'Date': None, 'Creator': None})
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
if __name__ == '__main__':
|
| 273 |
+
with open("table_config.yaml", 'r') as f:
|
| 274 |
+
cfg = yaml.safe_load(f)
|
| 275 |
+
|
| 276 |
+
hw_info, model_info = parse_table("README.md", cfg)
|
| 277 |
+
render_table(hw_info, model_info, "color_table.svg", cfg, "RdYlGn_r")
|
benchmark/table_config.yaml
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# model information
|
| 2 |
+
# - name: model name, used for display
|
| 3 |
+
# task: model task, used for display
|
| 4 |
+
# input_size: input size, used for display
|
| 5 |
+
# folder: which folder the model located in, used for jumping to model detail
|
| 6 |
+
# acceptable_time: maximum acceptable inference time, large ones will be marked red
|
| 7 |
+
# keyword: used to specify this model from all benchmark results
|
| 8 |
+
#
|
| 9 |
+
# device information
|
| 10 |
+
# - name: full device name used to identify the device block, and jump to device detail
|
| 11 |
+
# display_info: device information for display
|
| 12 |
+
# platform: used to identify benchmark result of specific platform
|
| 13 |
+
#
|
| 14 |
+
# suffix information
|
| 15 |
+
# - model: which model
|
| 16 |
+
# device: which device
|
| 17 |
+
# suffix: this suffix will be appended to end of this text
|
| 18 |
+
|
| 19 |
+
Models:
|
| 20 |
+
- name: "YuNet"
|
| 21 |
+
task: "Face Detection"
|
| 22 |
+
input_size: "160x120"
|
| 23 |
+
folder: "face_detection_yunet"
|
| 24 |
+
acceptable_time: 50
|
| 25 |
+
keyword: "face_detection_yunet"
|
| 26 |
+
|
| 27 |
+
- name: "SFace"
|
| 28 |
+
task: "Face Recognition"
|
| 29 |
+
input_size: "112x112"
|
| 30 |
+
folder: "face_recognition_sface"
|
| 31 |
+
acceptable_time: 200
|
| 32 |
+
keyword: "face_recognition_sface"
|
| 33 |
+
|
| 34 |
+
- name: "FER"
|
| 35 |
+
task: "Face Expression Recognition"
|
| 36 |
+
input_size: "112x112"
|
| 37 |
+
folder: "facial_expression_recognition"
|
| 38 |
+
acceptable_time: 200
|
| 39 |
+
keyword: "facial_expression_recognition_mobilefacenet"
|
| 40 |
+
|
| 41 |
+
- name: "LPD_YuNet"
|
| 42 |
+
task: "License Plate Detection"
|
| 43 |
+
input_size: "320x240"
|
| 44 |
+
folder: "license_plate_detection_yunet"
|
| 45 |
+
acceptable_time: 700
|
| 46 |
+
keyword: "license_plate_detection_lpd_yunet"
|
| 47 |
+
|
| 48 |
+
- name: "YOLOX"
|
| 49 |
+
task: "Object Detection"
|
| 50 |
+
input_size: "640x640"
|
| 51 |
+
folder: "object_detection_yolox"
|
| 52 |
+
acceptable_time: 2800
|
| 53 |
+
keyword: "object_detection_yolox"
|
| 54 |
+
|
| 55 |
+
- name: "NanoDet"
|
| 56 |
+
task: "Object Detection"
|
| 57 |
+
input_size: "416x416"
|
| 58 |
+
folder: "object_detection_nanodet"
|
| 59 |
+
acceptable_time: 2000
|
| 60 |
+
keyword: "object_detection_nanodet"
|
| 61 |
+
|
| 62 |
+
- name: "DB-IC15 (EN)"
|
| 63 |
+
task: "Text Detection"
|
| 64 |
+
input_size: "640x480"
|
| 65 |
+
folder: "text_detection_db"
|
| 66 |
+
acceptable_time: 2000
|
| 67 |
+
keyword: "text_detection_DB_IC15_resnet18"
|
| 68 |
+
|
| 69 |
+
- name: "DB-TD500 (EN&CN)"
|
| 70 |
+
task: "Text Detection"
|
| 71 |
+
input_size: "640x480"
|
| 72 |
+
folder: "text_detection_db"
|
| 73 |
+
acceptable_time: 2000
|
| 74 |
+
keyword: "text_detection_DB_TD500_resnet18"
|
| 75 |
+
|
| 76 |
+
- name: "CRNN-EN"
|
| 77 |
+
task: "Text Recognition"
|
| 78 |
+
input_size: "100*32"
|
| 79 |
+
folder: "text_recognition_crnn"
|
| 80 |
+
acceptable_time: 2000
|
| 81 |
+
keyword: "text_recognition_CRNN_EN"
|
| 82 |
+
|
| 83 |
+
- name: "CRNN-CN"
|
| 84 |
+
task: "Text Recognition"
|
| 85 |
+
input_size: "100*32"
|
| 86 |
+
folder: "text_recognition_crnn"
|
| 87 |
+
acceptable_time: 2000
|
| 88 |
+
keyword: "text_recognition_CRNN_CN"
|
| 89 |
+
|
| 90 |
+
- name: "PP-ResNet"
|
| 91 |
+
task: "Image Classification"
|
| 92 |
+
input_size: "224x224"
|
| 93 |
+
folder: "image_classification_ppresnet"
|
| 94 |
+
acceptable_time: 1000
|
| 95 |
+
keyword: "image_classification_ppresnet50"
|
| 96 |
+
|
| 97 |
+
- name: "MobileNet-V1"
|
| 98 |
+
task: "Image Classification"
|
| 99 |
+
input_size: "224x224"
|
| 100 |
+
folder: "image_classification_mobilenet"
|
| 101 |
+
acceptable_time: 500
|
| 102 |
+
keyword: "image_classification_mobilenetv1"
|
| 103 |
+
|
| 104 |
+
- name: "MobileNet-V2"
|
| 105 |
+
task: "Image Classification"
|
| 106 |
+
input_size: "224x224"
|
| 107 |
+
folder: "image_classification_mobilenet"
|
| 108 |
+
acceptable_time: 500
|
| 109 |
+
keyword: "image_classification_mobilenetv2"
|
| 110 |
+
|
| 111 |
+
- name: "PP-HumanSeg"
|
| 112 |
+
task: "Human Segmentation"
|
| 113 |
+
input_size: "192x192"
|
| 114 |
+
folder: "human_segmentation_pphumanseg"
|
| 115 |
+
acceptable_time: 700
|
| 116 |
+
keyword: "human_segmentation_pphumanseg"
|
| 117 |
+
|
| 118 |
+
- name: "WeChatQRCode"
|
| 119 |
+
task: "QR Code Detection and Parsing"
|
| 120 |
+
input_size: "100x100"
|
| 121 |
+
folder: "qrcode_wechatqrcode"
|
| 122 |
+
acceptable_time: 100
|
| 123 |
+
keyword: "WeChatQRCode"
|
| 124 |
+
|
| 125 |
+
- name: "DaSiamRPN"
|
| 126 |
+
task: "Object Tracking"
|
| 127 |
+
input_size: "1280x720"
|
| 128 |
+
folder: "object_tracking_dasiamrpn"
|
| 129 |
+
acceptable_time: 3000
|
| 130 |
+
keyword: "object_tracking_dasiamrpn"
|
| 131 |
+
|
| 132 |
+
- name: "YoutuReID"
|
| 133 |
+
task: "Person Re-Identification"
|
| 134 |
+
input_size: "128x256"
|
| 135 |
+
folder: "person_reid_youtureid"
|
| 136 |
+
acceptable_time: 800
|
| 137 |
+
keyword: "person_reid_youtu"
|
| 138 |
+
|
| 139 |
+
- name: "MP-PalmDet"
|
| 140 |
+
task: "Palm Detection"
|
| 141 |
+
input_size: "192x192"
|
| 142 |
+
folder: "palm_detection_mediapipe"
|
| 143 |
+
acceptable_time: 500
|
| 144 |
+
keyword: "palm_detection_mediapipe"
|
| 145 |
+
|
| 146 |
+
- name: "MP-HandPose"
|
| 147 |
+
task: "Hand Pose Estimation"
|
| 148 |
+
input_size: "224x224"
|
| 149 |
+
folder: "handpose_estimation_mediapipe"
|
| 150 |
+
acceptable_time: 500
|
| 151 |
+
keyword: "handpose_estimation_mediapipe"
|
| 152 |
+
|
| 153 |
+
- name: "MP-PersonDet"
|
| 154 |
+
task: "Person Detection"
|
| 155 |
+
input_size: "224x224"
|
| 156 |
+
folder: "person_detection_mediapipe"
|
| 157 |
+
acceptable_time: 1300
|
| 158 |
+
keyword: "person_detection_mediapipe"
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
Devices:
|
| 162 |
+
- name: "Intel 12700K"
|
| 163 |
+
display_info: "Intel\n12700K\nCPU"
|
| 164 |
+
platform: "CPU"
|
| 165 |
+
|
| 166 |
+
- name: "Rasberry Pi 4B"
|
| 167 |
+
display_info: "Rasberry Pi 4B\nBCM2711\nCPU"
|
| 168 |
+
platform: "CPU"
|
| 169 |
+
|
| 170 |
+
- name: "Toybrick RV1126"
|
| 171 |
+
display_info: "Toybrick\nRV1126\nCPU"
|
| 172 |
+
platform: "CPU"
|
| 173 |
+
|
| 174 |
+
- name: "Khadas Edge2 (with RK3588)"
|
| 175 |
+
display_info: "Khadas Edge2\nRK3588S\nCPU"
|
| 176 |
+
platform: "CPU"
|
| 177 |
+
|
| 178 |
+
- name: "Horizon Sunrise X3 PI"
|
| 179 |
+
display_info: "Horizon Sunrise Pi\nX3\nCPU"
|
| 180 |
+
platform: "CPU"
|
| 181 |
+
|
| 182 |
+
- name: "MAIX-III AX-PI"
|
| 183 |
+
display_info: "MAIX-III AX-Pi\nAX620A\nCPU"
|
| 184 |
+
platform: "CPU"
|
| 185 |
+
|
| 186 |
+
- name: "Jetson Nano B01"
|
| 187 |
+
display_info: "Jetson Nano\nB01\nCPU"
|
| 188 |
+
platform: "CPU"
|
| 189 |
+
|
| 190 |
+
- name: "Khadas VIM3"
|
| 191 |
+
display_info: "Khadas VIM3\nA311D\nCPU"
|
| 192 |
+
platform: "CPU"
|
| 193 |
+
|
| 194 |
+
- name: "Atlas 200 DK"
|
| 195 |
+
display_info: "Atlas 200 DK\nAscend 310\nCPU"
|
| 196 |
+
platform: "CPU"
|
| 197 |
+
|
| 198 |
+
- name: "Jetson Nano B01"
|
| 199 |
+
display_info: "Jetson Nano\nB01\nGPU"
|
| 200 |
+
platform: "GPU (CUDA-FP32)"
|
| 201 |
+
|
| 202 |
+
- name: "Khadas VIM3"
|
| 203 |
+
display_info: "Khadas VIM3\nA311D\nNPU"
|
| 204 |
+
platform: "NPU (TIMVX)"
|
| 205 |
+
|
| 206 |
+
- name: "Atlas 200 DK"
|
| 207 |
+
display_info: "Atlas 200 DK\nAscend 310\nNPU"
|
| 208 |
+
platform: "NPU"
|
| 209 |
+
|
| 210 |
+
Suffixes:
|
| 211 |
+
- model: "MobileNet-V1"
|
| 212 |
+
device: "Khadas VIM3"
|
| 213 |
+
platform: "NPU (TIMVX)"
|
| 214 |
+
str: "\\*"
|
| 215 |
+
|
| 216 |
+
- model: "MobileNet-V2"
|
| 217 |
+
device: "Khadas VIM3"
|
| 218 |
+
platform: "NPU (TIMVX)"
|
| 219 |
+
str: "\\*"
|