qc903113684
commited on
Upload 43 files
Browse files- .gitattributes +10 -0
- aimo/QCS6490/aimo_yolov5s_qnn_int16.png +0 -0
- aimo/QCS6490/aimo_yolov5s_qnn_int8.png +0 -0
- aimo/QCS6490/aimo_yolov5s_snpe_int16.png +0 -0
- aimo/QCS6490/aimo_yolov5s_snpe_int8.png +0 -0
- aimo/QCS8550/aimo_yolov5s_qnn_int16.png +0 -0
- aimo/QCS8550/aimo_yolov5s_qnn_int8.png +0 -0
- aimo/QCS8550/aimo_yolov5s_snpe_int16.png +0 -0
- aimo/QCS8550/aimo_yolov5s_snpe_int8.png +0 -0
- examples/data/bus.jpg +0 -0
- examples/python/qnn_yolov5_multi.py +350 -0
- examples/python/snpe2_yolov5_multi.py +338 -0
- models/8550/cutoff_yolov5s_int16_htp_snpe2/cutoff_yolov5s.onnx +3 -0
- models/8550/cutoff_yolov5s_int16_htp_snpe2/cutoff_yolov5s_int16_htp_snpe2.csv +0 -0
- models/8550/cutoff_yolov5s_int16_htp_snpe2/cutoff_yolov5s_int16_htp_snpe2.dlc +3 -0
- models/8550/cutoff_yolov5s_int16_htp_snpe2/cutoff_yolov5s_int16_htp_snpe2.html +0 -0
- models/8550/cutoff_yolov5s_int16_htp_snpe2/shell_info.txt +9 -0
- models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s.bin +3 -0
- models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s.cpp +0 -0
- models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s.onnx +3 -0
- models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s_int16.qnn.serialized.bin +3 -0
- models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s_net.json +0 -0
- models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.aarch64.gcc7_5.so +3 -0
- models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.aarch64.gcc9_4.so +3 -0
- models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.aarch64.ndk.so +3 -0
- models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.x86.so +3 -0
- models/8550/cutoff_yolov5s_int16_qnn/qnn_model_info.json +1 -0
- models/8550/cutoff_yolov5s_int16_qnn/shell_info.txt +9 -0
- models/8550/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s.onnx +3 -0
- models/8550/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s_int8_htp_snpe2.csv +0 -0
- models/8550/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s_int8_htp_snpe2.dlc +3 -0
- models/8550/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s_int8_htp_snpe2.html +0 -0
- models/8550/cutoff_yolov5s_int8_htp_snpe2/shell_info.txt +9 -0
- models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s.bin +3 -0
- models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s.cpp +0 -0
- models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s.onnx +3 -0
- models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s_int8.qnn.serialized.bin +3 -0
- models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s_net.json +0 -0
- models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.aarch64.gcc7_5.so +3 -0
- models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.aarch64.gcc9_4.so +3 -0
- models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.aarch64.ndk.so +3 -0
- models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.x86.so +3 -0
- models/8550/cutoff_yolov5s_int8_qnn/qnn_model_info.json +1 -0
- models/8550/cutoff_yolov5s_int8_qnn/shell_info.txt +9 -0
.gitattributes
CHANGED
@@ -41,3 +41,13 @@ Models/QCS6490/cutoff_yolov5s_int16_htp_snpe2.dlc filter=lfs diff=lfs merge=lfs
|
|
41 |
Models/QCS6490/cutoff_yolov5s_int8_htp_snpe2.dlc filter=lfs diff=lfs merge=lfs -text
|
42 |
Models/QCS8550/cutoff_yolov5s_int16_htp_snpe2.dlc filter=lfs diff=lfs merge=lfs -text
|
43 |
Models/QCS8550/cutoff_yolov5s_int8_htp_snpe2.dlc filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
Models/QCS6490/cutoff_yolov5s_int8_htp_snpe2.dlc filter=lfs diff=lfs merge=lfs -text
|
42 |
Models/QCS8550/cutoff_yolov5s_int16_htp_snpe2.dlc filter=lfs diff=lfs merge=lfs -text
|
43 |
Models/QCS8550/cutoff_yolov5s_int8_htp_snpe2.dlc filter=lfs diff=lfs merge=lfs -text
|
44 |
+
models/8550/cutoff_yolov5s_int16_htp_snpe2/cutoff_yolov5s_int16_htp_snpe2.dlc filter=lfs diff=lfs merge=lfs -text
|
45 |
+
models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.aarch64.gcc7_5.so filter=lfs diff=lfs merge=lfs -text
|
46 |
+
models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.aarch64.gcc9_4.so filter=lfs diff=lfs merge=lfs -text
|
47 |
+
models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.aarch64.ndk.so filter=lfs diff=lfs merge=lfs -text
|
48 |
+
models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.x86.so filter=lfs diff=lfs merge=lfs -text
|
49 |
+
models/8550/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s_int8_htp_snpe2.dlc filter=lfs diff=lfs merge=lfs -text
|
50 |
+
models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.aarch64.gcc7_5.so filter=lfs diff=lfs merge=lfs -text
|
51 |
+
models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.aarch64.gcc9_4.so filter=lfs diff=lfs merge=lfs -text
|
52 |
+
models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.aarch64.ndk.so filter=lfs diff=lfs merge=lfs -text
|
53 |
+
models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.x86.so filter=lfs diff=lfs merge=lfs -text
|
aimo/QCS6490/aimo_yolov5s_qnn_int16.png
ADDED
aimo/QCS6490/aimo_yolov5s_qnn_int8.png
ADDED
aimo/QCS6490/aimo_yolov5s_snpe_int16.png
ADDED
aimo/QCS6490/aimo_yolov5s_snpe_int8.png
ADDED
aimo/QCS8550/aimo_yolov5s_qnn_int16.png
ADDED
aimo/QCS8550/aimo_yolov5s_qnn_int8.png
ADDED
aimo/QCS8550/aimo_yolov5s_snpe_int16.png
ADDED
aimo/QCS8550/aimo_yolov5s_snpe_int8.png
ADDED
examples/data/bus.jpg
ADDED
examples/python/qnn_yolov5_multi.py
ADDED
@@ -0,0 +1,350 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# import sys
|
2 |
+
import os
|
3 |
+
import time
|
4 |
+
|
5 |
+
import aidlite
|
6 |
+
import cv2
|
7 |
+
import numpy as np
|
8 |
+
|
9 |
+
OBJ_CLASS_NUM = 80
|
10 |
+
NMS_THRESH = 0.45
|
11 |
+
BOX_THRESH = 0.5
|
12 |
+
MODEL_SIZE = 640
|
13 |
+
|
14 |
+
OBJ_NUMB_MAX_SIZE = 64
|
15 |
+
PROP_BOX_SIZE = (5 + OBJ_CLASS_NUM)
|
16 |
+
STRIDE8_SIZE = (MODEL_SIZE / 8)
|
17 |
+
STRIDE16_SIZE = (MODEL_SIZE / 16)
|
18 |
+
STRIDE32_SIZE = (MODEL_SIZE / 32)
|
19 |
+
|
20 |
+
anchors = [[10, 13, 16, 30, 33, 23],
|
21 |
+
[30, 61, 62, 45, 59, 119],
|
22 |
+
[116, 90, 156, 198, 373, 326]]
|
23 |
+
|
24 |
+
coco_class = [
|
25 |
+
'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
|
26 |
+
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant',
|
27 |
+
'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard',
|
28 |
+
'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle',
|
29 |
+
'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli',
|
30 |
+
'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet',
|
31 |
+
'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator',
|
32 |
+
'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']
|
33 |
+
|
34 |
+
|
35 |
+
def eqprocess(image, size1, size2):
|
36 |
+
h, w, _ = image.shape
|
37 |
+
mask = np.zeros((size1, size2, 3), dtype=np.float32)
|
38 |
+
scale1 = h / size1
|
39 |
+
scale2 = w / size2
|
40 |
+
if scale1 > scale2:
|
41 |
+
scale = scale1
|
42 |
+
else:
|
43 |
+
scale = scale2
|
44 |
+
img = cv2.resize(image, (int(w / scale), int(h / scale)))
|
45 |
+
mask[:int(h / scale), :int(w / scale), :] = img
|
46 |
+
return mask, scale
|
47 |
+
|
48 |
+
|
49 |
+
def xywh2xyxy(x):
|
50 |
+
'''
|
51 |
+
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
52 |
+
'''
|
53 |
+
y = np.copy(x)
|
54 |
+
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
55 |
+
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
56 |
+
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
57 |
+
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
58 |
+
return y
|
59 |
+
|
60 |
+
|
61 |
+
def xyxy2xywh(box):
|
62 |
+
'''
|
63 |
+
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
64 |
+
'''
|
65 |
+
box[:, 2:] = box[:, 2:] - box[:, :2]
|
66 |
+
return box
|
67 |
+
|
68 |
+
|
69 |
+
def NMS(dets, scores, thresh):
|
70 |
+
'''
|
71 |
+
单类NMS算法
|
72 |
+
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
73 |
+
'''
|
74 |
+
x1 = dets[:, 0]
|
75 |
+
y1 = dets[:, 1]
|
76 |
+
x2 = dets[:, 2]
|
77 |
+
y2 = dets[:, 3]
|
78 |
+
areas = (y2 - y1 + 1) * (x2 - x1 + 1)
|
79 |
+
keep = []
|
80 |
+
index = scores.argsort()[::-1]
|
81 |
+
while index.size > 0:
|
82 |
+
i = index[0] # every time the first is the biggst, and add it directly
|
83 |
+
keep.append(i)
|
84 |
+
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
85 |
+
y11 = np.maximum(y1[i], y1[index[1:]])
|
86 |
+
x22 = np.minimum(x2[i], x2[index[1:]])
|
87 |
+
y22 = np.minimum(y2[i], y2[index[1:]])
|
88 |
+
w = np.maximum(0, x22 - x11 + 1) # the weights of overlap
|
89 |
+
h = np.maximum(0, y22 - y11 + 1) # the height of overlap
|
90 |
+
overlaps = w * h
|
91 |
+
ious = overlaps / (areas[i] + areas[index[1:]] - overlaps)
|
92 |
+
idx = np.where(ious <= thresh)[0]
|
93 |
+
index = index[idx + 1] # because index start from 1
|
94 |
+
|
95 |
+
return keep
|
96 |
+
|
97 |
+
|
98 |
+
def clip_coords(boxes, img_shape):
|
99 |
+
# Clip bounding xyxy bounding boxes to image shape (height, width)
|
100 |
+
boxes[:, 0].clip(0, img_shape[1], out=boxes[:, 0]) # x1
|
101 |
+
boxes[:, 1].clip(0, img_shape[0], out=boxes[:, 1]) # y1
|
102 |
+
boxes[:, 2].clip(0, img_shape[1], out=boxes[:, 2]) # x2
|
103 |
+
boxes[:, 3].clip(0, img_shape[0], out=boxes[:, 3]) # y2
|
104 |
+
|
105 |
+
|
106 |
+
def detect_postprocess(prediction, img0shape, img1shape, conf_thres=0.25, iou_thres=0.45):
|
107 |
+
'''
|
108 |
+
检测输出后处理
|
109 |
+
prediction: aidlite模型预测输出
|
110 |
+
img0shape: 原始图片shape
|
111 |
+
img1shape: 输入图片shape
|
112 |
+
conf_thres: 置信度阈值
|
113 |
+
iou_thres: IOU阈值
|
114 |
+
return: list[np.ndarray(N, 5)], 对应类别的坐标框信息, xywh、conf
|
115 |
+
'''
|
116 |
+
h, w, _ = img1shape
|
117 |
+
valid_condidates = prediction[prediction[..., 4] > conf_thres]
|
118 |
+
valid_condidates[:, 5:] *= valid_condidates[:, 4:5]
|
119 |
+
valid_condidates[:, :4] = xywh2xyxy(valid_condidates[:, :4])
|
120 |
+
|
121 |
+
max_det = 300
|
122 |
+
max_wh = 7680
|
123 |
+
max_nms = 30000
|
124 |
+
valid_condidates[:, 4] = valid_condidates[:, 5:].max(1)
|
125 |
+
valid_condidates[:, 5] = valid_condidates[:, 5:].argmax(1)
|
126 |
+
sort_id = np.argsort(valid_condidates[:, 4])[::-1]
|
127 |
+
valid_condidates = valid_condidates[sort_id[:max_nms]]
|
128 |
+
boxes, scores = valid_condidates[:, :4] + valid_condidates[:, 5:6] * max_wh, valid_condidates[:, 4]
|
129 |
+
index = NMS(boxes, scores, iou_thres)[:max_det]
|
130 |
+
out_boxes = valid_condidates[index]
|
131 |
+
clip_coords(out_boxes[:, :4], img0shape)
|
132 |
+
out_boxes[:, :4] = xyxy2xywh(out_boxes[:, :4])
|
133 |
+
print("检测到{}个区域".format(len(out_boxes)))
|
134 |
+
return out_boxes
|
135 |
+
|
136 |
+
|
137 |
+
def draw_detect_res(img, det_pred):
|
138 |
+
'''
|
139 |
+
检测结果绘制
|
140 |
+
'''
|
141 |
+
img = img.astype(np.uint8)
|
142 |
+
color_step = int(255 / len(coco_class))
|
143 |
+
for i in range(len(det_pred)):
|
144 |
+
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
145 |
+
score = det_pred[i][4]
|
146 |
+
cls_id = int(det_pred[i][5])
|
147 |
+
|
148 |
+
print(i + 1, [x1, y1, x2, y2], score, coco_class[cls_id])
|
149 |
+
|
150 |
+
cv2.putText(img, f'{coco_class[cls_id]}', (x1, y1 - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
151 |
+
cv2.rectangle(img, (x1, y1), (x2 + x1, y2 + y1), (0, int(cls_id * color_step), int(255 - cls_id * color_step)),
|
152 |
+
thickness=2)
|
153 |
+
|
154 |
+
return img
|
155 |
+
|
156 |
+
|
157 |
+
class Detect():
|
158 |
+
# YOLOv5 Detect head for detection models
|
159 |
+
def __init__(self, nc=80, anchors=(), stride=[], image_size=640): # detection layer
|
160 |
+
super().__init__()
|
161 |
+
self.nc = nc # number of classes
|
162 |
+
self.no = nc + 5 # number of outputs per anchor
|
163 |
+
self.stride = stride
|
164 |
+
self.nl = len(anchors) # number of detection layers
|
165 |
+
self.na = len(anchors[0]) // 2 # number of anchors
|
166 |
+
self.grid, self.anchor_grid = [0] * self.nl, [0] * self.nl
|
167 |
+
self.anchors = np.array(anchors, dtype=np.float32).reshape(self.nl, -1, 2)
|
168 |
+
|
169 |
+
base_scale = image_size // 8
|
170 |
+
for i in range(self.nl):
|
171 |
+
self.grid[i], self.anchor_grid[i] = self._make_grid(base_scale // (2 ** i), base_scale // (2 ** i), i)
|
172 |
+
|
173 |
+
def _make_grid(self, nx=20, ny=20, i=0):
|
174 |
+
y, x = np.arange(ny, dtype=np.float32), np.arange(nx, dtype=np.float32)
|
175 |
+
yv, xv = np.meshgrid(y, x)
|
176 |
+
yv, xv = yv.T, xv.T
|
177 |
+
# add grid offset, i.e. y = 2.0 * x - 0.5
|
178 |
+
grid = np.stack((xv, yv), 2)
|
179 |
+
grid = grid[np.newaxis, np.newaxis, ...]
|
180 |
+
grid = np.repeat(grid, self.na, axis=1) - 0.5
|
181 |
+
anchor_grid = self.anchors[i].reshape((1, self.na, 1, 1, 2))
|
182 |
+
anchor_grid = np.repeat(anchor_grid, repeats=ny, axis=2)
|
183 |
+
anchor_grid = np.repeat(anchor_grid, repeats=nx, axis=3)
|
184 |
+
return grid, anchor_grid
|
185 |
+
|
186 |
+
def sigmoid(self, arr):
|
187 |
+
return 1 / (1 + np.exp(-arr))
|
188 |
+
|
189 |
+
def __call__(self, x):
|
190 |
+
z = [] # inference output
|
191 |
+
for i in range(self.nl):
|
192 |
+
bs, _, ny, nx = x[i].shape
|
193 |
+
x[i] = x[i].reshape(bs, self.na, self.no, ny, nx).transpose(0, 1, 3, 4, 2)
|
194 |
+
y = self.sigmoid(x[i])
|
195 |
+
y[..., 0:2] = (y[..., 0:2] * 2. + self.grid[i]) * self.stride[i] # xy
|
196 |
+
y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
|
197 |
+
z.append(y.reshape(bs, self.na * nx * ny, self.no))
|
198 |
+
|
199 |
+
return np.concatenate(z, 1)
|
200 |
+
|
201 |
+
|
202 |
+
def main():
|
203 |
+
# argvs = len(sys.argv)
|
204 |
+
# if argvs < 2:
|
205 |
+
# print("python3 ./qnn_yolov5_multi.py 0 for use DSP")
|
206 |
+
# print("python3 ./qnn_yolov5_multi.py 1 for use CPU")
|
207 |
+
# print("python3 ./qnn_yolov5_multi.py 2 for use GPU")
|
208 |
+
# return False
|
209 |
+
# acc_type = int(sys.argv[1])
|
210 |
+
|
211 |
+
print("Start main ... ...")
|
212 |
+
aidlite.set_log_level(aidlite.LogLevel.INFO)
|
213 |
+
aidlite.log_to_stderr()
|
214 |
+
print(f"Aidlite library version : {aidlite.get_library_version()}")
|
215 |
+
print(f"Aidlite python library version : {aidlite.get_py_library_version()}")
|
216 |
+
|
217 |
+
config = aidlite.Config.create_instance()
|
218 |
+
if config is None:
|
219 |
+
print("Create config failed !")
|
220 |
+
return False
|
221 |
+
|
222 |
+
# if acc_type == 1:
|
223 |
+
# config.accelerate_type = aidlite.AccelerateType.TYPE_CPU
|
224 |
+
# elif acc_type == 2:
|
225 |
+
# config.accelerate_type = aidlite.AccelerateType.TYPE_GPU
|
226 |
+
# config.is_quantify_model = 0
|
227 |
+
# elif acc_type == 0:
|
228 |
+
# config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
229 |
+
# config.is_quantify_model = 1
|
230 |
+
# else:
|
231 |
+
# print("python3 ./qnn_yolov5_multi.py 0 for use DSP")
|
232 |
+
# print("python3 ./qnn_yolov5_multi.py 1 for use CPU")
|
233 |
+
# print("python3 ./qnn_yolov5_multi.py 2 for use GPU")
|
234 |
+
# return False
|
235 |
+
|
236 |
+
config.implement_type = aidlite.ImplementType.TYPE_LOCAL
|
237 |
+
config.framework_type = aidlite.FrameworkType.TYPE_QNN
|
238 |
+
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
239 |
+
config.is_quantify_model = 1
|
240 |
+
|
241 |
+
model_path = "/home/aidlux/modelzoo/examples/data/cutoff_yolov5s_int8_qnn/cutoff_yolov5s_int8.qnn.serialized.bin"
|
242 |
+
model = aidlite.Model.create_instance(model_path)
|
243 |
+
if model is None:
|
244 |
+
print("Create model failed !")
|
245 |
+
return False
|
246 |
+
input_shapes = [[1, MODEL_SIZE, MODEL_SIZE, 3]]
|
247 |
+
output_shapes = [[1, 20, 20, 255], [1, 40, 40, 255], [1, 80, 80, 255]]
|
248 |
+
model.set_model_properties(input_shapes, aidlite.DataType.TYPE_FLOAT32,
|
249 |
+
output_shapes, aidlite.DataType.TYPE_FLOAT32)
|
250 |
+
|
251 |
+
interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
|
252 |
+
if interpreter is None:
|
253 |
+
print("build_interpretper_from_model_and_config failed !")
|
254 |
+
return None
|
255 |
+
result = interpreter.init()
|
256 |
+
if result != 0:
|
257 |
+
print(f"interpreter init failed !")
|
258 |
+
return False
|
259 |
+
result = interpreter.load_model()
|
260 |
+
if result != 0:
|
261 |
+
print("interpreter load model failed !")
|
262 |
+
return False
|
263 |
+
print("detect model load success!")
|
264 |
+
stride8 = stride16 = stride32 = None
|
265 |
+
|
266 |
+
image_path = os.path.join("../data/bus.jpg")
|
267 |
+
frame = cv2.imread(image_path)
|
268 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
269 |
+
img_input, scale = eqprocess(frame, MODEL_SIZE, MODEL_SIZE)
|
270 |
+
img_input = img_input / 255
|
271 |
+
img_input = img_input.astype(np.float32)
|
272 |
+
|
273 |
+
sum_time_0 = 0.0
|
274 |
+
sum_time_1 = 0.0
|
275 |
+
sum_time_2 = 0.0
|
276 |
+
_counter = 1
|
277 |
+
for idx in range(_counter):
|
278 |
+
st0 = time.time()
|
279 |
+
input_tensor_data = img_input.data
|
280 |
+
result = interpreter.set_input_tensor(0, input_tensor_data)
|
281 |
+
if result != 0:
|
282 |
+
print("interpreter set_input_tensor() failed")
|
283 |
+
return False
|
284 |
+
et0 = time.time()
|
285 |
+
dur0 = (et0 - st0) * 1000
|
286 |
+
sum_time_0 += dur0
|
287 |
+
print(f"current [{idx}] set_input_tensor cost time :{dur0} ms")
|
288 |
+
|
289 |
+
st1 = time.time()
|
290 |
+
result = interpreter.invoke()
|
291 |
+
if result != 0:
|
292 |
+
print("interpreter set_input_tensor() failed")
|
293 |
+
return False
|
294 |
+
et1 = time.time()
|
295 |
+
dur1 = (et1 - st1) * 1000
|
296 |
+
sum_time_1 += dur1
|
297 |
+
print(f"current [{idx}] invoke cost time :{dur1} ms")
|
298 |
+
|
299 |
+
st2 = time.time()
|
300 |
+
|
301 |
+
stride8 = interpreter.get_output_tensor(0)
|
302 |
+
if stride8 is None:
|
303 |
+
print("sample : interpreter->get_output_tensor() 0 failed !")
|
304 |
+
return False
|
305 |
+
print(f"len(stride8 {len(stride8)}")
|
306 |
+
|
307 |
+
stride16 = interpreter.get_output_tensor(1)
|
308 |
+
if stride16 is None:
|
309 |
+
print("sample : interpreter->get_output_tensor() 2 failed !")
|
310 |
+
return False
|
311 |
+
print(f"len(stride16 {len(stride16)}")
|
312 |
+
|
313 |
+
stride32 = interpreter.get_output_tensor(2)
|
314 |
+
if stride32 is None:
|
315 |
+
print("sample : interpreter->get_output_tensor() 1 failed !")
|
316 |
+
return False
|
317 |
+
print(f"len(stride32 {len(stride32)}")
|
318 |
+
et2 = time.time()
|
319 |
+
dur2 = (et2 - st2) * 1000
|
320 |
+
sum_time_2 += dur2
|
321 |
+
print(f"current [{idx}] get_output_tensor cost time :{dur2} ms")
|
322 |
+
|
323 |
+
print(
|
324 |
+
f"repeat [{_counter}] times , input[{sum_time_0 * 1000}]ms --- invoke[{sum_time_1 * 1000}]ms --- output[{sum_time_2 * 1000}]ms --- sum[{(sum_time_0 + sum_time_1 + sum_time_2) * 1000}]ms")
|
325 |
+
|
326 |
+
stride = [8, 16, 32]
|
327 |
+
yolo_head = Detect(OBJ_CLASS_NUM, anchors, stride, MODEL_SIZE)
|
328 |
+
# 后处理部分reshape需要知道模型的output_shapes
|
329 |
+
validCount0 = stride8.reshape(*output_shapes[2]).transpose(0, 3, 1, 2)
|
330 |
+
validCount1 = stride16.reshape(*output_shapes[1]).transpose(0, 3, 1, 2)
|
331 |
+
validCount2 = stride32.reshape(*output_shapes[0]).transpose(0, 3, 1, 2)
|
332 |
+
pred = yolo_head([validCount0, validCount1, validCount2])
|
333 |
+
det_pred = detect_postprocess(pred, frame.shape, [MODEL_SIZE, MODEL_SIZE, 3], conf_thres=0.5, iou_thres=0.45)
|
334 |
+
det_pred[np.isnan(det_pred)] = 0.0
|
335 |
+
det_pred[:, :4] = det_pred[:, :4] * scale
|
336 |
+
res_img = draw_detect_res(frame, det_pred)
|
337 |
+
|
338 |
+
result = interpreter.destory()
|
339 |
+
if result != 0:
|
340 |
+
print(f"interpreter set_input_tensor() failed")
|
341 |
+
return False
|
342 |
+
frame_bgr = cv2.cvtColor(res_img, cv2.COLOR_RGB2BGR)
|
343 |
+
result_img_path = f"{os.path.splitext(os.path.abspath(__file__))[0]}.jpg"
|
344 |
+
cv2.imwrite(result_img_path, frame_bgr)
|
345 |
+
print(f"The result image has been saved to : {result_img_path}")
|
346 |
+
return True
|
347 |
+
|
348 |
+
|
349 |
+
if __name__ == "__main__":
|
350 |
+
main()
|
examples/python/snpe2_yolov5_multi.py
ADDED
@@ -0,0 +1,338 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import struct
|
3 |
+
import sys
|
4 |
+
import time
|
5 |
+
|
6 |
+
import aidlite
|
7 |
+
import cv2
|
8 |
+
import numpy as np
|
9 |
+
|
10 |
+
FLOAT_SIZE = struct.calcsize('f')
|
11 |
+
OBJ_CLASS_NUM = 80
|
12 |
+
MODEL_SIZE = 640
|
13 |
+
anchors = [[10, 13, 16, 30, 33, 23],
|
14 |
+
[30, 61, 62, 45, 59, 119],
|
15 |
+
[116, 90, 156, 198, 373, 326]]
|
16 |
+
|
17 |
+
coco_class = [
|
18 |
+
'person', 'bicycle', 'car', 'motorcycle', 'airplane', 'bus', 'train', 'truck', 'boat', 'traffic light',
|
19 |
+
'fire hydrant', 'stop sign', 'parking meter', 'bench', 'bird', 'cat', 'dog', 'horse', 'sheep', 'cow', 'elephant',
|
20 |
+
'bear', 'zebra', 'giraffe', 'backpack', 'umbrella', 'handbag', 'tie', 'suitcase', 'frisbee', 'skis', 'snowboard',
|
21 |
+
'sports ball', 'kite', 'baseball bat', 'baseball glove', 'skateboard', 'surfboard', 'tennis racket', 'bottle',
|
22 |
+
'wine glass', 'cup', 'fork', 'knife', 'spoon', 'bowl', 'banana', 'apple', 'sandwich', 'orange', 'broccoli',
|
23 |
+
'carrot', 'hot dog', 'pizza', 'donut', 'cake', 'chair', 'couch', 'potted plant', 'bed', 'dining table', 'toilet',
|
24 |
+
'tv', 'laptop', 'mouse', 'remote', 'keyboard', 'cell phone', 'microwave', 'oven', 'toaster', 'sink', 'refrigerator',
|
25 |
+
'book', 'clock', 'vase', 'scissors', 'teddy bear', 'hair drier', 'toothbrush']
|
26 |
+
|
27 |
+
|
28 |
+
def eqprocess(image, size1, size2):
|
29 |
+
h, w, _ = image.shape
|
30 |
+
mask = np.zeros((size1, size2, 3), dtype=np.float32)
|
31 |
+
scale1 = h / size1
|
32 |
+
scale2 = w / size2
|
33 |
+
if scale1 > scale2:
|
34 |
+
scale = scale1
|
35 |
+
else:
|
36 |
+
scale = scale2
|
37 |
+
img = cv2.resize(image, (int(w / scale), int(h / scale)))
|
38 |
+
mask[:int(h / scale), :int(w / scale), :] = img
|
39 |
+
return mask, scale
|
40 |
+
|
41 |
+
|
42 |
+
def xywh2xyxy(x):
|
43 |
+
'''
|
44 |
+
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
45 |
+
'''
|
46 |
+
y = np.copy(x)
|
47 |
+
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
48 |
+
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
49 |
+
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
50 |
+
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
51 |
+
return y
|
52 |
+
|
53 |
+
|
54 |
+
def xyxy2xywh(box):
|
55 |
+
'''
|
56 |
+
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
57 |
+
'''
|
58 |
+
box[:, 2:] = box[:, 2:] - box[:, :2]
|
59 |
+
return box
|
60 |
+
|
61 |
+
|
62 |
+
def NMS(dets, scores, thresh):
|
63 |
+
'''
|
64 |
+
单类NMS算法
|
65 |
+
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
66 |
+
'''
|
67 |
+
x1 = dets[:, 0]
|
68 |
+
y1 = dets[:, 1]
|
69 |
+
x2 = dets[:, 2]
|
70 |
+
y2 = dets[:, 3]
|
71 |
+
areas = (y2 - y1 + 1) * (x2 - x1 + 1)
|
72 |
+
keep = []
|
73 |
+
index = scores.argsort()[::-1]
|
74 |
+
while index.size > 0:
|
75 |
+
i = index[0] # every time the first is the biggst, and add it directly
|
76 |
+
keep.append(i)
|
77 |
+
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
78 |
+
y11 = np.maximum(y1[i], y1[index[1:]])
|
79 |
+
x22 = np.minimum(x2[i], x2[index[1:]])
|
80 |
+
y22 = np.minimum(y2[i], y2[index[1:]])
|
81 |
+
w = np.maximum(0, x22 - x11 + 1) # the weights of overlap
|
82 |
+
h = np.maximum(0, y22 - y11 + 1) # the height of overlap
|
83 |
+
overlaps = w * h
|
84 |
+
ious = overlaps / (areas[i] + areas[index[1:]] - overlaps)
|
85 |
+
idx = np.where(ious <= thresh)[0]
|
86 |
+
index = index[idx + 1] # because index start from 1
|
87 |
+
|
88 |
+
return keep
|
89 |
+
|
90 |
+
|
91 |
+
def clip_coords(boxes, img_shape):
|
92 |
+
# Clip bounding xyxy bounding boxes to image shape (height, width)
|
93 |
+
boxes[:, 0].clip(0, img_shape[1], out=boxes[:, 0]) # x1
|
94 |
+
boxes[:, 1].clip(0, img_shape[0], out=boxes[:, 1]) # y1
|
95 |
+
boxes[:, 2].clip(0, img_shape[1], out=boxes[:, 2]) # x2
|
96 |
+
boxes[:, 3].clip(0, img_shape[0], out=boxes[:, 3]) # y2
|
97 |
+
|
98 |
+
|
99 |
+
def detect_postprocess(prediction, img0shape, img1shape, conf_thres=0.25, iou_thres=0.45):
|
100 |
+
'''
|
101 |
+
检测输出后处理
|
102 |
+
prediction: aidlite模型预测输出
|
103 |
+
img0shape: 原始图片shape
|
104 |
+
img1shape: 输入图片shape
|
105 |
+
conf_thres: 置信度阈值
|
106 |
+
iou_thres: IOU阈值
|
107 |
+
return: list[np.ndarray(N, 5)], 对应类别的坐标框信息, xywh、conf
|
108 |
+
'''
|
109 |
+
h, w, _ = img1shape
|
110 |
+
valid_condidates = prediction[prediction[..., 4] > conf_thres]
|
111 |
+
valid_condidates[:, 5:] *= valid_condidates[:, 4:5]
|
112 |
+
valid_condidates[:, :4] = xywh2xyxy(valid_condidates[:, :4])
|
113 |
+
|
114 |
+
max_det = 300
|
115 |
+
max_wh = 7680
|
116 |
+
max_nms = 30000
|
117 |
+
valid_condidates[:, 4] = valid_condidates[:, 5:].max(1)
|
118 |
+
valid_condidates[:, 5] = valid_condidates[:, 5:].argmax(1)
|
119 |
+
sort_id = np.argsort(valid_condidates[:, 4])[::-1]
|
120 |
+
valid_condidates = valid_condidates[sort_id[:max_nms]]
|
121 |
+
boxes, scores = valid_condidates[:, :4] + valid_condidates[:, 5:6] * max_wh, valid_condidates[:, 4]
|
122 |
+
index = NMS(boxes, scores, iou_thres)[:max_det]
|
123 |
+
out_boxes = valid_condidates[index]
|
124 |
+
clip_coords(out_boxes[:, :4], img0shape)
|
125 |
+
out_boxes[:, :4] = xyxy2xywh(out_boxes[:, :4])
|
126 |
+
print("检测到{}个区域".format(len(out_boxes)))
|
127 |
+
return out_boxes
|
128 |
+
|
129 |
+
|
130 |
+
def draw_detect_res(img, det_pred):
|
131 |
+
'''
|
132 |
+
检测结果绘制
|
133 |
+
'''
|
134 |
+
img = img.astype(np.uint8)
|
135 |
+
color_step = int(255 / len(coco_class))
|
136 |
+
for i in range(len(det_pred)):
|
137 |
+
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
138 |
+
score = det_pred[i][4]
|
139 |
+
cls_id = int(det_pred[i][5])
|
140 |
+
|
141 |
+
print(i + 1, [x1, y1, x2, y2], score, coco_class[cls_id])
|
142 |
+
|
143 |
+
cv2.putText(img, f'{coco_class[cls_id]}', (x1, y1 - 6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
144 |
+
cv2.rectangle(img, (x1, y1), (x2 + x1, y2 + y1), (0, int(cls_id * color_step), int(255 - cls_id * color_step)),
|
145 |
+
thickness=2)
|
146 |
+
|
147 |
+
return img
|
148 |
+
|
149 |
+
|
150 |
+
class Detect():
|
151 |
+
# YOLOv5 Detect head for detection models
|
152 |
+
def __init__(self, nc=80, anchors=(), stride=[], image_size=640): # detection layer
|
153 |
+
super().__init__()
|
154 |
+
self.nc = nc # number of classes
|
155 |
+
self.no = nc + 5 # number of outputs per anchor
|
156 |
+
self.stride = stride
|
157 |
+
self.nl = len(anchors) # number of detection layers
|
158 |
+
self.na = len(anchors[0]) // 2 # number of anchors
|
159 |
+
self.grid, self.anchor_grid = [0] * self.nl, [0] * self.nl
|
160 |
+
self.anchors = np.array(anchors, dtype=np.float32).reshape(self.nl, -1, 2)
|
161 |
+
|
162 |
+
base_scale = image_size // 8
|
163 |
+
for i in range(self.nl):
|
164 |
+
self.grid[i], self.anchor_grid[i] = self._make_grid(base_scale // (2 ** i), base_scale // (2 ** i), i)
|
165 |
+
|
166 |
+
def _make_grid(self, nx=20, ny=20, i=0):
|
167 |
+
y, x = np.arange(ny, dtype=np.float32), np.arange(nx, dtype=np.float32)
|
168 |
+
yv, xv = np.meshgrid(y, x)
|
169 |
+
yv, xv = yv.T, xv.T
|
170 |
+
# add grid offset, i.e. y = 2.0 * x - 0.5
|
171 |
+
grid = np.stack((xv, yv), 2)
|
172 |
+
grid = grid[np.newaxis, np.newaxis, ...]
|
173 |
+
grid = np.repeat(grid, self.na, axis=1) - 0.5
|
174 |
+
anchor_grid = self.anchors[i].reshape((1, self.na, 1, 1, 2))
|
175 |
+
anchor_grid = np.repeat(anchor_grid, repeats=ny, axis=2)
|
176 |
+
anchor_grid = np.repeat(anchor_grid, repeats=nx, axis=3)
|
177 |
+
return grid, anchor_grid
|
178 |
+
|
179 |
+
def sigmoid(self, arr):
|
180 |
+
return 1 / (1 + np.exp(-arr))
|
181 |
+
|
182 |
+
def __call__(self, x):
|
183 |
+
z = [] # inference output
|
184 |
+
for i in range(self.nl):
|
185 |
+
bs, _, ny, nx = x[i].shape
|
186 |
+
x[i] = x[i].reshape(bs, self.na, self.no, ny, nx).transpose(0, 1, 3, 4, 2)
|
187 |
+
y = self.sigmoid(x[i])
|
188 |
+
y[..., 0:2] = (y[..., 0:2] * 2. + self.grid[i]) * self.stride[i] # xy
|
189 |
+
y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i] # wh
|
190 |
+
z.append(y.reshape(bs, self.na * nx * ny, self.no))
|
191 |
+
|
192 |
+
return np.concatenate(z, 1)
|
193 |
+
|
194 |
+
|
195 |
+
def main():
|
196 |
+
acc_type = 0
|
197 |
+
aidlite.set_log_level(aidlite.LogLevel.INFO)
|
198 |
+
aidlite.log_to_stderr()
|
199 |
+
|
200 |
+
# image process
|
201 |
+
image_path = r"../data/bus.jpg"
|
202 |
+
frame = cv2.imread(image_path)
|
203 |
+
if frame is None:
|
204 |
+
print(f"{image_path} not exists")
|
205 |
+
return False
|
206 |
+
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
207 |
+
img_input, scale = eqprocess(frame, MODEL_SIZE, MODEL_SIZE)
|
208 |
+
img_input = img_input / 255
|
209 |
+
img_input = img_input.astype(np.float32)
|
210 |
+
|
211 |
+
config = aidlite.Config.create_instance()
|
212 |
+
if config is None:
|
213 |
+
print("build_interpretper_from_model_and_config failed !")
|
214 |
+
return False
|
215 |
+
|
216 |
+
# model init
|
217 |
+
acc_type_dsp = True
|
218 |
+
model_path = r"../data/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s_int8_htp_snpe2.dlc"
|
219 |
+
outNode_names = "/model.24/m.1/Conv,/model.24/m.2/Conv,/model.24/m.0/Conv"
|
220 |
+
config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
221 |
+
config.is_quantify_model = 1
|
222 |
+
|
223 |
+
|
224 |
+
config.implement_type = aidlite.ImplementType.TYPE_LOCAL
|
225 |
+
config.framework_type = aidlite.FrameworkType.TYPE_SNPE2
|
226 |
+
config.snpe_out_names = outNode_names.split(',')
|
227 |
+
print("---------------------------")
|
228 |
+
print(config.snpe_out_names)
|
229 |
+
|
230 |
+
model = aidlite.Model.create_instance(model_path)
|
231 |
+
if model is None:
|
232 |
+
print("Create model failed !")
|
233 |
+
return False
|
234 |
+
|
235 |
+
input_shapes = [[1, MODEL_SIZE, MODEL_SIZE, 3]]
|
236 |
+
output_shapes = [[1, 40, 40, 255], [1, 20, 20, 255], [1, 80, 80, 255]]
|
237 |
+
model.set_model_properties(input_shapes, aidlite.DataType.TYPE_FLOAT32, output_shapes,
|
238 |
+
aidlite.DataType.TYPE_FLOAT32)
|
239 |
+
|
240 |
+
snpe2_interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(model, config)
|
241 |
+
if snpe2_interpreter is None:
|
242 |
+
print("build_interpretper_from_model_and_config failed !")
|
243 |
+
return None
|
244 |
+
result = snpe2_interpreter.init()
|
245 |
+
if result != 0:
|
246 |
+
print(f"interpreter init failed !")
|
247 |
+
return False
|
248 |
+
result = snpe2_interpreter.load_model()
|
249 |
+
if result != 0:
|
250 |
+
print("interpreter load model failed !")
|
251 |
+
return False
|
252 |
+
print("detect model load success!")
|
253 |
+
|
254 |
+
stride8 = stride16 = stride32 = None
|
255 |
+
sum_time_0 = 0.0
|
256 |
+
sum_time_1 = 0.0
|
257 |
+
sum_time_2 = 0.0
|
258 |
+
_counter = 1
|
259 |
+
for idx in range(_counter):
|
260 |
+
st0 = time.time()
|
261 |
+
|
262 |
+
if acc_type_dsp:
|
263 |
+
time.sleep(0.04) # 40milliseconds
|
264 |
+
|
265 |
+
input_tensor_data = img_input.data
|
266 |
+
result = snpe2_interpreter.set_input_tensor(0, input_tensor_data)
|
267 |
+
if result != 0:
|
268 |
+
print("interpreter set_input_tensor() failed")
|
269 |
+
return False
|
270 |
+
et0 = time.time()
|
271 |
+
dur0 = (et0 - st0) * 1000
|
272 |
+
sum_time_0 += dur0
|
273 |
+
print(f"current [{idx}] set_input_tensor cost time :{dur0} ms")
|
274 |
+
|
275 |
+
st1 = time.time()
|
276 |
+
result = snpe2_interpreter.invoke()
|
277 |
+
if result != 0:
|
278 |
+
print("interpreter set_input_tensor() failed")
|
279 |
+
return False
|
280 |
+
et1 = time.time()
|
281 |
+
dur1 = (et1 - st1) * 1000
|
282 |
+
sum_time_1 += dur1
|
283 |
+
print(f"current [{idx}] invoke cost time :{dur1} ms")
|
284 |
+
|
285 |
+
st2 = time.time()
|
286 |
+
|
287 |
+
if acc_type_dsp:
|
288 |
+
time.sleep(0.02) # 40milliseconds
|
289 |
+
|
290 |
+
stride8 = snpe2_interpreter.get_output_tensor(0)
|
291 |
+
if stride8 is None:
|
292 |
+
print("sample : interpreter->get_output_tensor() 0 failed !")
|
293 |
+
return False
|
294 |
+
print(f"len(stride8 {len(stride8)}")
|
295 |
+
|
296 |
+
stride16 = snpe2_interpreter.get_output_tensor(1)
|
297 |
+
if stride16 is None:
|
298 |
+
print("sample : interpreter->get_output_tensor() 2 failed !")
|
299 |
+
return False
|
300 |
+
print(f"len(stride16 {len(stride16)}")
|
301 |
+
|
302 |
+
stride32 = snpe2_interpreter.get_output_tensor(2)
|
303 |
+
if stride32 is None:
|
304 |
+
print("sample : interpreter->get_output_tensor() 1 failed !")
|
305 |
+
return False
|
306 |
+
print(f"len(stride32 {len(stride32)}")
|
307 |
+
et2 = time.time()
|
308 |
+
dur2 = (et2 - st2) * 1000
|
309 |
+
sum_time_2 += dur2
|
310 |
+
print(f"current [{idx}] get_output_tensor cost time :{dur2} ms")
|
311 |
+
|
312 |
+
print(
|
313 |
+
f"repeat [{_counter}] time , input[{sum_time_0}]ms --- invoke[{sum_time_1}]ms --- output[{sum_time_2}]ms --- sum[{sum_time_0 + sum_time_1 + sum_time_2}]ms")
|
314 |
+
|
315 |
+
stride = [8, 16, 32]
|
316 |
+
yolo_head = Detect(OBJ_CLASS_NUM, anchors, stride, MODEL_SIZE)
|
317 |
+
validCount0 = stride8.reshape(*output_shapes[2]).transpose(0, 3, 1, 2)
|
318 |
+
validCount1 = stride16.reshape(*output_shapes[0]).transpose(0, 3, 1, 2)
|
319 |
+
validCount2 = stride32.reshape(*output_shapes[1]).transpose(0, 3, 1, 2)
|
320 |
+
pred = yolo_head([validCount0, validCount1, validCount2])
|
321 |
+
det_pred = detect_postprocess(pred, frame.shape, [MODEL_SIZE, MODEL_SIZE, 3], conf_thres=0.5, iou_thres=0.45)
|
322 |
+
det_pred[np.isnan(det_pred)] = 0.0
|
323 |
+
det_pred[:, :4] = det_pred[:, :4] * scale
|
324 |
+
res_img = draw_detect_res(frame, det_pred)
|
325 |
+
|
326 |
+
result = snpe2_interpreter.destory()
|
327 |
+
if result != 0:
|
328 |
+
print(f"interpreter set_input_tensor() failed")
|
329 |
+
return False
|
330 |
+
frame_bgr = cv2.cvtColor(res_img, cv2.COLOR_RGB2BGR)
|
331 |
+
result_img_path = f"{os.path.splitext(os.path.abspath(__file__))[0]}.jpg"
|
332 |
+
cv2.imwrite(result_img_path, frame_bgr)
|
333 |
+
print(f"The result image has been saved to : {result_img_path}")
|
334 |
+
return True
|
335 |
+
|
336 |
+
|
337 |
+
if __name__ == "__main__":
|
338 |
+
main()
|
models/8550/cutoff_yolov5s_int16_htp_snpe2/cutoff_yolov5s.onnx
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:6f3268665cee28d5932e69a42d32ea1585cd85bc2438751c2df92e66c53fbbf7
|
3 |
+
size 28953517
|
models/8550/cutoff_yolov5s_int16_htp_snpe2/cutoff_yolov5s_int16_htp_snpe2.csv
ADDED
The diff for this file is too large to render.
See raw diff
|
|
models/8550/cutoff_yolov5s_int16_htp_snpe2/cutoff_yolov5s_int16_htp_snpe2.dlc
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:d689002a3e27c63edc944f474f25e2c331c05ca6b1ab4f85a260743f18e9648f
|
3 |
+
size 15175256
|
models/8550/cutoff_yolov5s_int16_htp_snpe2/cutoff_yolov5s_int16_htp_snpe2.html
ADDED
The diff for this file is too large to render.
See raw diff
|
|
models/8550/cutoff_yolov5s_int16_htp_snpe2/shell_info.txt
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
2024-07-08 17:21:00,089 - INFO : Optimization started.
|
2 |
+
2024-07-08 17:21:00,090 - INFO : [ONNX-SIM] Clean ONNX Model input node.
|
3 |
+
2024-07-08 17:21:01,319 - INFO : [CUTOFF] Cutoff model...
|
4 |
+
2024-07-08 17:21:07,597 - INFO : [ONNX2DLC] Start converting to DLC, expected to take 9 s.
|
5 |
+
2024-07-08 17:21:10,976 - INFO : [ONNX2DLC] DLC conversion is done.
|
6 |
+
2024-07-08 17:21:10,976 - INFO : [DLC-QUAN] Start quantizing model, expected to take 70 s.
|
7 |
+
2024-07-08 17:21:17,875 - INFO : [DLC-QUAN] quantization is done.
|
8 |
+
2024-07-08 17:21:19,220 - INFO : [ONNX2DLC] DLC conversion is done.
|
9 |
+
2024-07-08 17:21:19,220 - INFO : Model optimization done.
|
models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:202ad25e2ad38b3889926aa5ecb9144d0ce10b34756d23f61a3d6e430acc269f
|
3 |
+
size 7331840
|
models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s.cpp
ADDED
The diff for this file is too large to render.
See raw diff
|
|
models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s.onnx
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:6f3268665cee28d5932e69a42d32ea1585cd85bc2438751c2df92e66c53fbbf7
|
3 |
+
size 28953517
|
models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s_int16.qnn.serialized.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:122a955a4b0bc1c3f553e6102a034601e0f8b290e79599c8ed4f9099711f8846
|
3 |
+
size 7645656
|
models/8550/cutoff_yolov5s_int16_qnn/cutoff_yolov5s_net.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.aarch64.gcc7_5.so
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:214eade70f7ed41ec4addc2fb9356b19aea0d6c1d354a83674b5f705a2ebe8d3
|
3 |
+
size 7608368
|
models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.aarch64.gcc9_4.so
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:847636599d0cc6c51e2252b97177ffd58a7355cb21d113545095391459f0329f
|
3 |
+
size 7604360
|
models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.aarch64.ndk.so
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:bb91df7035d426bbf8addc2859598d28326ddb5411018b54f66718e513e23af9
|
3 |
+
size 7870472
|
models/8550/cutoff_yolov5s_int16_qnn/libcutoff_yolov5s_int16.qnn.x86.so
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:a64c0b874c5f4330b874455320f7e63def71674c88ec7278da336b43e6388d5f
|
3 |
+
size 7660448
|
models/8550/cutoff_yolov5s_int16_qnn/qnn_model_info.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"model_name": "cutoff_yolov5s_int16.qnn.serialized.bin", "data_type": "w8a16", "inputDimensions": {"images": [1, 640, 640, 3]}, "outputDimensions": {}, "htp_socs_name": "QCS8550", "htp_socs_type": "sm8550", "qnn_sdk": "qnn_sdk_2.16.4.231110"}
|
models/8550/cutoff_yolov5s_int16_qnn/shell_info.txt
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
2024-07-08 18:22:25,075 - INFO : Optimization started.
|
2 |
+
2024-07-08 18:22:25,076 - INFO : [ONNX-SIM] Clean ONNX Model input node.
|
3 |
+
2024-07-08 18:22:26,130 - INFO : [CUTOFF] Cutoff model...
|
4 |
+
2024-07-08 18:22:28,402 - INFO : [ONNX2QNN] Start converting to QNN.
|
5 |
+
2024-07-08 18:24:11,047 - INFO : [CONVERT-QNN] Convert model is done.
|
6 |
+
2024-07-08 18:24:31,125 - INFO : [COMPILE-QNN] Compile model is done.
|
7 |
+
2024-07-08 18:24:33,089 - INFO : [CREATE-CONTEXT-BINARY] Create context binary is done.
|
8 |
+
2024-07-08 18:24:33,291 - INFO : [ONNX2QNN] QNN conversion is done.
|
9 |
+
2024-07-08 18:24:33,292 - INFO : Model optimization done.
|
models/8550/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s.onnx
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:6f3268665cee28d5932e69a42d32ea1585cd85bc2438751c2df92e66c53fbbf7
|
3 |
+
size 28953517
|
models/8550/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s_int8_htp_snpe2.csv
ADDED
The diff for this file is too large to render.
See raw diff
|
|
models/8550/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s_int8_htp_snpe2.dlc
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:934d69f4e315f4a011350072d1b0206efdb505ecae051fa5dbb3581f87907e85
|
3 |
+
size 14956262
|
models/8550/cutoff_yolov5s_int8_htp_snpe2/cutoff_yolov5s_int8_htp_snpe2.html
ADDED
The diff for this file is too large to render.
See raw diff
|
|
models/8550/cutoff_yolov5s_int8_htp_snpe2/shell_info.txt
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
2024-07-08 16:25:41,225 - INFO : Optimization started.
|
2 |
+
2024-07-08 16:25:41,225 - INFO : [ONNX-SIM] Clean ONNX Model input node.
|
3 |
+
2024-07-08 16:25:43,400 - INFO : [CUTOFF] Cutoff model...
|
4 |
+
2024-07-08 16:25:49,055 - INFO : [ONNX2DLC] Start converting to DLC, expected to take 11 s.
|
5 |
+
2024-07-08 16:25:52,205 - INFO : [ONNX2DLC] DLC conversion is done.
|
6 |
+
2024-07-08 16:25:52,205 - INFO : [DLC-QUAN] Start quantizing model, expected to take 87 s.
|
7 |
+
2024-07-08 16:25:58,803 - INFO : [DLC-QUAN] quantization is done.
|
8 |
+
2024-07-08 16:26:00,104 - INFO : [ONNX2DLC] DLC conversion is done.
|
9 |
+
2024-07-08 16:26:00,105 - INFO : Model optimization done.
|
models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:407d11ec97f758a43ee56926e755526701fc8356fb43225f8b01eaaf8f314cbe
|
3 |
+
size 7311360
|
models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s.cpp
ADDED
The diff for this file is too large to render.
See raw diff
|
|
models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s.onnx
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:6f3268665cee28d5932e69a42d32ea1585cd85bc2438751c2df92e66c53fbbf7
|
3 |
+
size 28953517
|
models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s_int8.qnn.serialized.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:603bad2305c9c2a2c9ce5678eb2919867ae5157502dbe190f370e4c0085482f0
|
3 |
+
size 7530968
|
models/8550/cutoff_yolov5s_int8_qnn/cutoff_yolov5s_net.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.aarch64.gcc7_5.so
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:1cdd4984b91d23bf7c0334dfcc0bfd3287cb847c53f848949821ac51101e6bba
|
3 |
+
size 7573464
|
models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.aarch64.gcc9_4.so
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:f3248baf6bafb88c338c628e4150f9f04b26a2efdc17e55a0962d2eeffbe0fad
|
3 |
+
size 7581744
|
models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.aarch64.ndk.so
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:7f7d40d7a95f2ef375ae034ebb6f792a7e7916b99e6315980dfda4485645dc26
|
3 |
+
size 7839680
|
models/8550/cutoff_yolov5s_int8_qnn/libcutoff_yolov5s_int8.qnn.x86.so
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:4fa4f0995efcd5d5c415775be5059a1b28ecf248d27bc81b8dd2e6533bec3e18
|
3 |
+
size 7633744
|
models/8550/cutoff_yolov5s_int8_qnn/qnn_model_info.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"model_name": "cutoff_yolov5s_int8.qnn.serialized.bin", "data_type": "w8a8", "inputDimensions": {"images": [1, 640, 640, 3]}, "outputDimensions": {}, "htp_socs_name": "QCS8550", "htp_socs_type": "sm8550", "qnn_sdk": "qnn_sdk_2.16.4.231110"}
|
models/8550/cutoff_yolov5s_int8_qnn/shell_info.txt
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
2024-07-08 18:07:31,799 - INFO : Optimization started.
|
2 |
+
2024-07-08 18:07:31,799 - INFO : [ONNX-SIM] Clean ONNX Model input node.
|
3 |
+
2024-07-08 18:07:33,343 - INFO : [CUTOFF] Cutoff model...
|
4 |
+
2024-07-08 18:07:35,697 - INFO : [ONNX2QNN] Start converting to QNN.
|
5 |
+
2024-07-08 18:09:19,450 - INFO : [CONVERT-QNN] Convert model is done.
|
6 |
+
2024-07-08 18:09:39,385 - INFO : [COMPILE-QNN] Compile model is done.
|
7 |
+
2024-07-08 18:09:41,192 - INFO : [CREATE-CONTEXT-BINARY] Create context binary is done.
|
8 |
+
2024-07-08 18:09:41,388 - INFO : [ONNX2QNN] QNN conversion is done.
|
9 |
+
2024-07-08 18:09:41,388 - INFO : Model optimization done.
|