Upload 27 files
Browse files- model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/README.md +59 -0
- model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/cpp/CMakeLists.txt +30 -0
- model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/cpp/bus.jpg +3 -0
- model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/cpp/main.cpp +349 -0
- model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/models/cutoff_yolov8s_w8a8.qnn216.ctx.bin +3 -0
- model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/python/bus.jpg +3 -0
- model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/python/run_test.py +30 -0
- model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/python/utils.py +123 -0
- model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/python/yolov8s.py +86 -0
- model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/README.md +59 -0
- model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/cpp/CMakeLists.txt +30 -0
- model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/cpp/bus.jpg +3 -0
- model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/cpp/main.cpp +349 -0
- model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/models/cutoff_yolov8s_fp16.qnn216.ctx.bin +3 -0
- model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/python/bus.jpg +3 -0
- model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/python/run_test.py +30 -0
- model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/python/utils.py +123 -0
- model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/python/yolov8s.py +86 -0
- model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/README.md +59 -0
- model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/cpp/CMakeLists.txt +30 -0
- model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/cpp/bus.jpg +3 -0
- model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/cpp/main.cpp +349 -0
- model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/models/cutoff_yolov8s_w8a8.qnn216.ctx.bin +3 -0
- model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/python/bus.jpg +3 -0
- model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/python/run_test.py +30 -0
- model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/python/utils.py +123 -0
- model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/python/yolov8s.py +86 -0
model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Model Information
|
2 |
+
### Source model
|
3 |
+
- Input shape: 640x640
|
4 |
+
- Number of parameters: 10.65M
|
5 |
+
- Model size: 42.7M
|
6 |
+
- Output shape: 1x84x8400
|
7 |
+
|
8 |
+
Source model repository: [yolov8](https://github.com/ultralytics/ultralytics)
|
9 |
+
|
10 |
+
### Converted model
|
11 |
+
|
12 |
+
- Precision: INT8
|
13 |
+
- Backend: QNN2.16
|
14 |
+
- Target Device: FV01 QCS6490
|
15 |
+
|
16 |
+
## Model Conversion Reference
|
17 |
+
User can find model conversion reference at [aimo.aidlux.com](https://aimo.aidlux.com/#/public/04384e46-ee9f-4c6d-875b-daa4702aa6d0)
|
18 |
+
|
19 |
+
## Inference with AidLite SDK
|
20 |
+
|
21 |
+
### SDK installation
|
22 |
+
Model Farm uses AidLite SDK as the model inference SDK. For details, please refer to the [AidLite Developer Documentation](https://v2.docs.aidlux.com/en/sdk-api/aidlite-sdk/)
|
23 |
+
|
24 |
+
- install AidLite SDK
|
25 |
+
|
26 |
+
```bash
|
27 |
+
# Install the appropriate version of the aidlite sdk
|
28 |
+
sudo aid-pkg update
|
29 |
+
sudo aid-pkg install aidlite-sdk
|
30 |
+
# Download the qnn version that matches the above backend. Eg Install QNN2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
31 |
+
sudo aid-pkg install aidlite-{QNN VERSION}
|
32 |
+
# eg: Install QNN 2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
33 |
+
```
|
34 |
+
|
35 |
+
- Verify AidLite SDK
|
36 |
+
|
37 |
+
```bash
|
38 |
+
# aidlite sdk c++ check
|
39 |
+
python3 -c "import aidlite ; print(aidlite.get_library_version())"
|
40 |
+
|
41 |
+
# aidlite sdk python check
|
42 |
+
python3 -c "import aidlite ; print(aidlite.get_py_library_version())"
|
43 |
+
```
|
44 |
+
|
45 |
+
### Run Demo
|
46 |
+
|
47 |
+
#### python
|
48 |
+
```bash
|
49 |
+
cd model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite
|
50 |
+
python3 python/run_test.py --target_model ./models/cutoff_yolov8s_w8a8.qnn216.ctx.bin --imgs ./python/bus.jpg --invoke_nums 10
|
51 |
+
```
|
52 |
+
|
53 |
+
#### cpp
|
54 |
+
```bash
|
55 |
+
cd model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/cpp
|
56 |
+
mkdir -p build && cd build
|
57 |
+
cmake .. && make
|
58 |
+
./run_test --target_model ../../models/cutoff_yolov8s_w8a8.qnn216.ctx.bin --imgs ../bus.jpg --invoke_nums 10
|
59 |
+
```
|
model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/cpp/CMakeLists.txt
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required (VERSION 3.5)
|
2 |
+
project("run_test")
|
3 |
+
|
4 |
+
find_package(OpenCV REQUIRED)
|
5 |
+
|
6 |
+
message(STATUS "oPENCV Library status:")
|
7 |
+
message(STATUS ">version:${OpenCV_VERSION}")
|
8 |
+
message(STATUS "Include:${OpenCV_INCLUDE_DIRS}")
|
9 |
+
|
10 |
+
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations")
|
11 |
+
|
12 |
+
include_directories(
|
13 |
+
/usr/local/include
|
14 |
+
/usr/include/opencv4
|
15 |
+
)
|
16 |
+
|
17 |
+
link_directories(
|
18 |
+
/usr/local/lib/
|
19 |
+
)
|
20 |
+
|
21 |
+
file(GLOB SRC_LISTS
|
22 |
+
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
23 |
+
)
|
24 |
+
|
25 |
+
add_executable(run_test ${SRC_LISTS})
|
26 |
+
|
27 |
+
target_link_libraries(run_test
|
28 |
+
aidlite
|
29 |
+
${OpenCV_LIBS}
|
30 |
+
)
|
model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/cpp/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/cpp/main.cpp
ADDED
@@ -0,0 +1,349 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <iostream>
|
2 |
+
#include <string>
|
3 |
+
#include <algorithm>
|
4 |
+
#include <cctype>
|
5 |
+
#include <opencv2/opencv.hpp>
|
6 |
+
#include <aidlux/aidlite/aidlite.hpp>
|
7 |
+
#include <vector>
|
8 |
+
#include <numeric>
|
9 |
+
|
10 |
+
const float INPUT_WIDTH = 640.0;
|
11 |
+
const float INPUT_HEIGHT = 640.0;
|
12 |
+
const float SCORE_THRESHOLD = 0.25;
|
13 |
+
const float NMS_THRESHOLD = 0.45;
|
14 |
+
const float CONFIDENCE_THRESHOLD = 0.25;
|
15 |
+
const uint32_t size = 640;
|
16 |
+
const uint32_t out_size = 8400;
|
17 |
+
|
18 |
+
const int FONT_FACE = cv::FONT_HERSHEY_SIMPLEX;
|
19 |
+
cv::Scalar WHITE = cv::Scalar(255,255,255);
|
20 |
+
|
21 |
+
const float FONT_SCALE = 0.75;
|
22 |
+
const int THICKNESS = 1;
|
23 |
+
|
24 |
+
const std::vector<std::string> class_list = {
|
25 |
+
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
|
26 |
+
"truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter",
|
27 |
+
"bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear",
|
28 |
+
"zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase",
|
29 |
+
"frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
|
30 |
+
"baseball glove", "skateboard", "surfboard", "tennis racket", "bottle",
|
31 |
+
"wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
32 |
+
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
|
33 |
+
"cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet",
|
34 |
+
"TV", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave",
|
35 |
+
"oven", "toaster", "sink", "refrigerator", "book", "clock", "vase",
|
36 |
+
"scissors", "teddy bear", "hair drier", "toothbrush"
|
37 |
+
};
|
38 |
+
|
39 |
+
using namespace Aidlux::Aidlite;
|
40 |
+
|
41 |
+
struct Args {
|
42 |
+
std::string target_model = "../../models/cutoff_yolov8s_w8a8.qnn216.ctx.bin.aidem";
|
43 |
+
std::string imgs = "../bus.jpg";
|
44 |
+
int invoke_nums = 10;
|
45 |
+
std::string model_type = "QNN";
|
46 |
+
};
|
47 |
+
|
48 |
+
Args parse_args(int argc, char* argv[]) {
|
49 |
+
Args args;
|
50 |
+
for (int i = 1; i < argc; ++i) {
|
51 |
+
std::string arg = argv[i];
|
52 |
+
if (arg == "--target_model" && i + 1 < argc) {
|
53 |
+
args.target_model = argv[++i];
|
54 |
+
} else if (arg == "--imgs" && i + 1 < argc) {
|
55 |
+
args.imgs = argv[++i];
|
56 |
+
} else if (arg == "--invoke_nums" && i + 1 < argc) {
|
57 |
+
args.invoke_nums = std::stoi(argv[++i]);
|
58 |
+
} else if (arg == "--model_type" && i + 1 < argc) {
|
59 |
+
args.model_type = argv[++i];
|
60 |
+
}
|
61 |
+
}
|
62 |
+
return args;
|
63 |
+
}
|
64 |
+
|
65 |
+
std::string to_lower(const std::string& str) {
|
66 |
+
std::string lower_str = str;
|
67 |
+
std::transform(lower_str.begin(), lower_str.end(), lower_str.begin(), [](unsigned char c) {
|
68 |
+
return std::tolower(c);
|
69 |
+
});
|
70 |
+
return lower_str;
|
71 |
+
}
|
72 |
+
|
73 |
+
|
74 |
+
void concatenate(float* qnn_trans_data, float* qnn_mul_data, int batch, int num_elements, int trans_dim, int mul_dim, std::vector<float>& output) {
|
75 |
+
int out_dim = trans_dim + mul_dim + 1;
|
76 |
+
output.resize(batch * num_elements * out_dim);
|
77 |
+
for (int i = 0; i < batch * num_elements; ++i) {
|
78 |
+
std::memcpy(&output[i * out_dim], &qnn_mul_data[i * mul_dim], mul_dim * sizeof(float));
|
79 |
+
float max_val = *std::max_element(&qnn_trans_data[i * trans_dim], &qnn_trans_data[i * trans_dim + trans_dim]);
|
80 |
+
output[i * out_dim + 4] = max_val;
|
81 |
+
std::memcpy(&output[i * out_dim + 5], &qnn_trans_data[i * trans_dim], trans_dim * sizeof(float));
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
void transformData(const float* input, float* output, int C, int N) {
|
86 |
+
for (int c = 0; c < C; ++c) {
|
87 |
+
for (int n = 0; n < N; ++n) {
|
88 |
+
output[n * C + c] = input[c * N + n];
|
89 |
+
}
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
double img_process(cv::Mat frame, cv::Mat &img_input, int size) {
|
94 |
+
cv::Mat img_processed = frame.clone();
|
95 |
+
int height = img_processed.rows;
|
96 |
+
int width = img_processed.cols;
|
97 |
+
int length = std::max(height, width);
|
98 |
+
double scala = static_cast<double>(length) / size;
|
99 |
+
|
100 |
+
cv::Mat image = cv::Mat::zeros(cv::Size(length, length), CV_8UC3);
|
101 |
+
img_processed.copyTo(image(cv::Rect(0, 0, width, height)));
|
102 |
+
|
103 |
+
cv::cvtColor(image, img_input, cv::COLOR_BGR2RGB);
|
104 |
+
cv::resize(img_input, img_input, cv::Size(size, size));
|
105 |
+
|
106 |
+
cv::Mat mean_data = cv::Mat::zeros(img_input.size(), CV_32FC3);
|
107 |
+
cv::Mat std_data(img_input.size(), CV_32FC3, cv::Scalar(255, 255, 255));
|
108 |
+
img_input.convertTo(img_input, CV_32FC3);
|
109 |
+
img_input = (img_input - mean_data) / std_data;
|
110 |
+
return scala;
|
111 |
+
}
|
112 |
+
|
113 |
+
|
114 |
+
cv::Scalar generate_colors(int i, bool bgr = false) {
|
115 |
+
static const std::vector<std::string> hex_colors = {
|
116 |
+
"FF3838", "FF9D97", "FF701F", "FFB21D", "CFD231", "48F90A",
|
117 |
+
"92CC17", "3DDB86", "1A9334", "00D4BB", "2C99A8", "00C2FF",
|
118 |
+
"344593", "6473FF", "0018EC", "8438FF", "520085", "CB38FF",
|
119 |
+
"FF95C8", "FF37C7"
|
120 |
+
};
|
121 |
+
|
122 |
+
int num = hex_colors.size();
|
123 |
+
std::string hex = hex_colors[i % num];
|
124 |
+
|
125 |
+
int r = std::stoi(hex.substr(0, 2), nullptr, 16);
|
126 |
+
int g = std::stoi(hex.substr(2, 2), nullptr, 16);
|
127 |
+
int b = std::stoi(hex.substr(4, 2), nullptr, 16);
|
128 |
+
|
129 |
+
if (bgr)
|
130 |
+
return cv::Scalar(b, g, r);
|
131 |
+
else
|
132 |
+
return cv::Scalar(r, g, b);
|
133 |
+
}
|
134 |
+
|
135 |
+
void draw_label(cv::Mat& input_image, std::string label, int left, int top, cv::Scalar color)
|
136 |
+
{
|
137 |
+
int baseLine;
|
138 |
+
cv::Size label_size = cv::getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS, &baseLine);
|
139 |
+
int y = top - label_size.height - baseLine;
|
140 |
+
if (y < 0) {
|
141 |
+
y = top ;
|
142 |
+
}
|
143 |
+
cv::Point tlc(left, y);
|
144 |
+
cv::Point brc(left + label_size.width, y + label_size.height + baseLine);
|
145 |
+
rectangle(input_image, tlc, brc, color, cv::FILLED);
|
146 |
+
putText(input_image, label, cv::Point(left, y + label_size.height), FONT_FACE, FONT_SCALE, WHITE, THICKNESS);
|
147 |
+
}
|
148 |
+
|
149 |
+
|
150 |
+
cv::Mat post_process(cv::Mat &input_image, std::vector<float> &outputs, const std::vector<std::string> &class_name, const double ratio)
|
151 |
+
{
|
152 |
+
// Initialize vectors to hold respective outputs while unwrapping detections.
|
153 |
+
std::vector<int> class_ids;
|
154 |
+
std::vector<float> confidences;
|
155 |
+
std::vector<cv::Rect> boxes;
|
156 |
+
|
157 |
+
// Iterate through outputs for each box prediction
|
158 |
+
for (int i = 0; i < outputs.size(); i+=85)
|
159 |
+
{
|
160 |
+
float confidence = outputs[i+4];
|
161 |
+
if (confidence >= CONFIDENCE_THRESHOLD)
|
162 |
+
{
|
163 |
+
// Create a 1x80 Mat and store class scores of 80 classes.
|
164 |
+
cv::Mat scores(1, class_name.size(), CV_32FC1, outputs.data() + i + 5);
|
165 |
+
cv::Point class_id;
|
166 |
+
double max_class_score;
|
167 |
+
|
168 |
+
// For multi-label, check each class score
|
169 |
+
for (int c = 0; c < class_name.size(); c++) {
|
170 |
+
float class_score = scores.at<float>(0, c);
|
171 |
+
|
172 |
+
// If class score is above threshold, consider this class for the box
|
173 |
+
if (class_score > SCORE_THRESHOLD) {
|
174 |
+
// Store class ID and confidence in the pre-defined respective vectors.
|
175 |
+
confidences.push_back(confidence * class_score); // Multiply with confidence
|
176 |
+
class_ids.push_back(c); // class index
|
177 |
+
// Center and box dimension.
|
178 |
+
float cx = outputs[i];
|
179 |
+
float cy = outputs[i+1];
|
180 |
+
float w = outputs[i+2];
|
181 |
+
float h = outputs[i+3];
|
182 |
+
|
183 |
+
int left = int((cx - 0.5 * w) * ratio);
|
184 |
+
int top = int((cy - 0.5 * h) * ratio);
|
185 |
+
int width = int(w * ratio);
|
186 |
+
int height = int(h * ratio);
|
187 |
+
|
188 |
+
// Store good detections in the boxes vector.
|
189 |
+
boxes.push_back(cv::Rect(left, top, width, height));
|
190 |
+
}
|
191 |
+
}
|
192 |
+
}
|
193 |
+
}
|
194 |
+
|
195 |
+
// Perform Non Maximum Suppression and draw predictions.
|
196 |
+
std::vector<int> indices;
|
197 |
+
cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, indices);
|
198 |
+
printf("Detected {%ld} targets.\n", indices.size());
|
199 |
+
|
200 |
+
// Loop over NMS results and draw bounding boxes
|
201 |
+
for (int i = 0; i < indices.size(); i++)
|
202 |
+
{
|
203 |
+
int idx = indices[i];
|
204 |
+
cv::Rect box = boxes[idx];
|
205 |
+
|
206 |
+
int left = box.x;
|
207 |
+
int top = box.y;
|
208 |
+
int width = box.width;
|
209 |
+
int height = box.height;
|
210 |
+
cv::Scalar color = generate_colors(class_ids[idx]);
|
211 |
+
// Draw bounding box.
|
212 |
+
rectangle(input_image, cv::Point(left, top), cv::Point(left + width, top + height), color, 2*THICKNESS);
|
213 |
+
|
214 |
+
// Get the label for the class name and its confidence.
|
215 |
+
std::string label = cv::format("%.2f", confidences[idx]);
|
216 |
+
label = class_name[class_ids[idx]] + ":" + label;
|
217 |
+
// Draw class labels.
|
218 |
+
draw_label(input_image, label, left, top, color);
|
219 |
+
}
|
220 |
+
printf("Processing finished.\n");
|
221 |
+
return input_image;
|
222 |
+
}
|
223 |
+
|
224 |
+
int invoke(const Args& args) {
|
225 |
+
std::cout << "Start main ... ... Model Path: " << args.target_model << "\n"
|
226 |
+
<< "Image Path: " << args.imgs << "\n"
|
227 |
+
<< "Inference Nums: " << args.invoke_nums << "\n"
|
228 |
+
<< "Model Type: " << args.model_type << "\n";
|
229 |
+
Model* model = Model::create_instance(args.target_model);
|
230 |
+
if(model == nullptr){
|
231 |
+
printf("Create model failed !\n");
|
232 |
+
return EXIT_FAILURE;
|
233 |
+
}
|
234 |
+
Config* config = Config::create_instance();
|
235 |
+
if(config == nullptr){
|
236 |
+
printf("Create config failed !\n");
|
237 |
+
return EXIT_FAILURE;
|
238 |
+
}
|
239 |
+
config->implement_type = ImplementType::TYPE_LOCAL;
|
240 |
+
std::string model_type_lower = to_lower(args.model_type);
|
241 |
+
if (model_type_lower == "qnn"){
|
242 |
+
config->framework_type = FrameworkType::TYPE_QNN;
|
243 |
+
} else if (model_type_lower == "snpe2" || model_type_lower == "snpe") {
|
244 |
+
config->framework_type = FrameworkType::TYPE_SNPE2;
|
245 |
+
}
|
246 |
+
config->accelerate_type = AccelerateType::TYPE_DSP;
|
247 |
+
config->is_quantify_model = 1;
|
248 |
+
|
249 |
+
std::vector<std::vector<uint32_t>> input_shapes = {{1, size, size, 3}};
|
250 |
+
std::vector<std::vector<uint32_t>> output_shapes = {{1, 4, out_size}, {1, 80, out_size}};
|
251 |
+
model->set_model_properties(input_shapes, DataType::TYPE_FLOAT32, output_shapes, DataType::TYPE_FLOAT32);
|
252 |
+
std::unique_ptr<Interpreter> fast_interpreter = InterpreterBuilder::build_interpretper_from_model_and_config(model, config);
|
253 |
+
if(fast_interpreter == nullptr){
|
254 |
+
printf("build_interpretper_from_model_and_config failed !\n");
|
255 |
+
return EXIT_FAILURE;
|
256 |
+
}
|
257 |
+
int result = fast_interpreter->init();
|
258 |
+
if(result != EXIT_SUCCESS){
|
259 |
+
printf("interpreter->init() failed !\n");
|
260 |
+
return EXIT_FAILURE;
|
261 |
+
}
|
262 |
+
// load model
|
263 |
+
fast_interpreter->load_model();
|
264 |
+
if(result != EXIT_SUCCESS){
|
265 |
+
printf("interpreter->load_model() failed !\n");
|
266 |
+
return EXIT_FAILURE;
|
267 |
+
}
|
268 |
+
printf("detect model load success!\n");
|
269 |
+
|
270 |
+
cv::Mat frame = cv::imread(args.imgs);
|
271 |
+
if (frame.empty()) {
|
272 |
+
printf("detect image load failed!\n");
|
273 |
+
return 1;
|
274 |
+
}
|
275 |
+
printf("img_src cols: %d, img_src rows: %d\n", frame.cols, frame.rows);
|
276 |
+
cv::Mat input_img;
|
277 |
+
double scale = img_process(frame, input_img, size);
|
278 |
+
if (input_img.empty()) {
|
279 |
+
printf("detect input_img load failed!\n");
|
280 |
+
return 1;
|
281 |
+
}
|
282 |
+
|
283 |
+
float *qnn_trans_data = nullptr;
|
284 |
+
float *qnn_mul_data = nullptr;
|
285 |
+
|
286 |
+
std::vector<float> invoke_time;
|
287 |
+
for (int i = 0; i < args.invoke_nums; ++i) {
|
288 |
+
result = fast_interpreter->set_input_tensor(0, input_img.data);
|
289 |
+
if(result != EXIT_SUCCESS){
|
290 |
+
printf("interpreter->set_input_tensor() failed !\n");
|
291 |
+
return EXIT_FAILURE;
|
292 |
+
}
|
293 |
+
// 开始计时
|
294 |
+
auto t1 = std::chrono::high_resolution_clock::now();
|
295 |
+
result = fast_interpreter->invoke();
|
296 |
+
auto t2 = std::chrono::high_resolution_clock::now();
|
297 |
+
std::chrono::duration<double> cost_time = t2 - t1;
|
298 |
+
invoke_time.push_back(cost_time.count() * 1000);
|
299 |
+
if(result != EXIT_SUCCESS){
|
300 |
+
printf("interpreter->invoke() failed !\n");
|
301 |
+
return EXIT_FAILURE;
|
302 |
+
}
|
303 |
+
uint32_t out_data_1 = 0;
|
304 |
+
result = fast_interpreter->get_output_tensor(0, (void**)&qnn_trans_data, &out_data_1);
|
305 |
+
if(result != EXIT_SUCCESS){
|
306 |
+
printf("interpreter->get_output_tensor() 1 failed !\n");
|
307 |
+
return EXIT_FAILURE;
|
308 |
+
}
|
309 |
+
uint32_t out_data_2 = 0;
|
310 |
+
result = fast_interpreter->get_output_tensor(1, (void**)&qnn_mul_data, &out_data_2);
|
311 |
+
if(result != EXIT_SUCCESS){
|
312 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
313 |
+
return EXIT_FAILURE;
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
float max_invoke_time = *std::max_element(invoke_time.begin(), invoke_time.end());
|
318 |
+
float min_invoke_time = *std::min_element(invoke_time.begin(), invoke_time.end());
|
319 |
+
float mean_invoke_time = std::accumulate(invoke_time.begin(), invoke_time.end(), 0.0f) / args.invoke_nums;
|
320 |
+
float var_invoketime = 0.0f;
|
321 |
+
for (auto time : invoke_time) {
|
322 |
+
var_invoketime += (time - mean_invoke_time) * (time - mean_invoke_time);
|
323 |
+
}
|
324 |
+
var_invoketime /= args.invoke_nums;
|
325 |
+
printf("=======================================\n");
|
326 |
+
printf("QNN inference %d times :\n --mean_invoke_time is %f \n --max_invoke_time is %f \n --min_invoke_time is %f \n --var_invoketime is %f\n",
|
327 |
+
args.invoke_nums, mean_invoke_time, max_invoke_time, min_invoke_time, var_invoketime);
|
328 |
+
printf("=======================================\n");
|
329 |
+
|
330 |
+
// std::vector<std::vector<uint32_t>> output_shapes = {{1, 4, out_size}, {1, 80, out_size}};
|
331 |
+
float* pos_data = new float[4 * out_size];
|
332 |
+
float* class_data = new float[80 * out_size];
|
333 |
+
transformData(qnn_trans_data, pos_data, 4, out_size);
|
334 |
+
transformData(qnn_mul_data, class_data, 80, out_size);
|
335 |
+
|
336 |
+
// post process
|
337 |
+
std::vector<float> qnn_concat;
|
338 |
+
concatenate(class_data, pos_data , 1, out_size, 80, 4, qnn_concat);
|
339 |
+
cv::Mat img = post_process(frame, qnn_concat, class_list, scale);
|
340 |
+
cv::imwrite("./results.png", img);
|
341 |
+
fast_interpreter->destory();
|
342 |
+
return 0;
|
343 |
+
}
|
344 |
+
|
345 |
+
|
346 |
+
int main(int argc, char* argv[]) {
|
347 |
+
Args args = parse_args(argc, argv);
|
348 |
+
return invoke(args);
|
349 |
+
}
|
model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/models/cutoff_yolov8s_w8a8.qnn216.ctx.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:60eef403584262893959e5f133f4b523205a71d166750bc1e0853303536cb5ed
|
3 |
+
size 11804696
|
model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/python/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/python/run_test.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import argparse
|
3 |
+
from yolov8s import Yolov8S
|
4 |
+
from utils import draw_detect_res
|
5 |
+
|
6 |
+
def parser_args():
|
7 |
+
parser = argparse.ArgumentParser(description="Run model benchmarks")
|
8 |
+
parser.add_argument('--target_model',type=str,default='./models/cutoff_yolov8s_w8a8.qnn231.ctx.bin.aidem',help="inference model path")
|
9 |
+
parser.add_argument('--imgs',type=str,default='./python/bus.jpg',help="Predict images path")
|
10 |
+
parser.add_argument('--height',type=int,default=640,help="run backend")
|
11 |
+
parser.add_argument('--weight',type=int,default=640,help="run backend")
|
12 |
+
parser.add_argument('--cls_num',type=int,default=80,help="run backend")
|
13 |
+
parser.add_argument('--invoke_nums',type=int,default=10,help="Inference nums")
|
14 |
+
parser.add_argument('--model_type',type=str,default='QNN',help="run backend")
|
15 |
+
args = parser.parse_args()
|
16 |
+
return args
|
17 |
+
|
18 |
+
if __name__ == "__main__":
|
19 |
+
args = parser_args()
|
20 |
+
height = args.height
|
21 |
+
weight = args.weight
|
22 |
+
|
23 |
+
|
24 |
+
model = Yolov8S(args.target_model, args.weight, args.height, args.cls_num)
|
25 |
+
frame = cv2.imread(args.imgs)
|
26 |
+
|
27 |
+
out_boxes= model(frame, args.invoke_nums)
|
28 |
+
print(f"=================== \n Detect {len(out_boxes)} targets.")
|
29 |
+
result = draw_detect_res(frame, out_boxes)
|
30 |
+
cv2.imwrite("./python/result.jpg", result)
|
model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/python/utils.py
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
|
4 |
+
CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light",
|
5 |
+
"fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant",
|
6 |
+
"bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
|
7 |
+
"baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ",
|
8 |
+
"spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa",
|
9 |
+
"pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop ", "mouse ", "remote ", "keyboard ", "cell phone", "microwave ",
|
10 |
+
"oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ")
|
11 |
+
|
12 |
+
def eqprocess(image, size1, size2):
|
13 |
+
h,w,_ = image.shape
|
14 |
+
mask = np.zeros((size1,size2,3),dtype=np.float32)
|
15 |
+
scale1 = h /size1
|
16 |
+
scale2 = w / size2
|
17 |
+
if scale1 > scale2:
|
18 |
+
scale = scale1
|
19 |
+
else:
|
20 |
+
scale = scale2
|
21 |
+
img = cv2.resize(image,(int(w / scale),int(h / scale)))
|
22 |
+
mask[:int(h / scale),:int(w / scale),:] = img
|
23 |
+
return mask, scale
|
24 |
+
|
25 |
+
def xywh2xyxy(x):
|
26 |
+
'''
|
27 |
+
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
28 |
+
'''
|
29 |
+
y = np.copy(x)
|
30 |
+
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
31 |
+
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
32 |
+
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
33 |
+
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
34 |
+
return y
|
35 |
+
|
36 |
+
def xyxy2xywh(box):
|
37 |
+
'''
|
38 |
+
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
39 |
+
'''
|
40 |
+
box[:, 2:] = box[:, 2:] - box[:, :2]
|
41 |
+
return box
|
42 |
+
|
43 |
+
def NMS(dets, scores, thresh):
|
44 |
+
'''
|
45 |
+
单类NMS算法
|
46 |
+
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
47 |
+
'''
|
48 |
+
x1 = dets[:,0]
|
49 |
+
y1 = dets[:,1]
|
50 |
+
x2 = dets[:,2]
|
51 |
+
y2 = dets[:,3]
|
52 |
+
areas = (y2-y1+1) * (x2-x1+1)
|
53 |
+
keep = []
|
54 |
+
index = scores.argsort()[::-1]
|
55 |
+
while index.size >0:
|
56 |
+
i = index[0] # every time the first is the biggst, and add it directly
|
57 |
+
keep.append(i)
|
58 |
+
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
59 |
+
y11 = np.maximum(y1[i], y1[index[1:]])
|
60 |
+
x22 = np.minimum(x2[i], x2[index[1:]])
|
61 |
+
y22 = np.minimum(y2[i], y2[index[1:]])
|
62 |
+
w = np.maximum(0, x22-x11+1) # the weights of overlap
|
63 |
+
h = np.maximum(0, y22-y11+1) # the height of overlap
|
64 |
+
overlaps = w*h
|
65 |
+
ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
|
66 |
+
idx = np.where(ious<=thresh)[0]
|
67 |
+
index = index[idx+1] # because index start from 1
|
68 |
+
|
69 |
+
return keep
|
70 |
+
|
71 |
+
|
72 |
+
def draw_detect_res(img, det_pred):
|
73 |
+
'''
|
74 |
+
检测结果绘制
|
75 |
+
'''
|
76 |
+
if det_pred is None:
|
77 |
+
return img
|
78 |
+
|
79 |
+
img = img.astype(np.uint8)
|
80 |
+
im_canvas = img.copy()
|
81 |
+
color_step = int(255/len(CLASSES))
|
82 |
+
for i in range(len(det_pred)):
|
83 |
+
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
84 |
+
cls_id = int(det_pred[i][5])
|
85 |
+
print(i+1,[x1,y1,x2,y2],det_pred[i][4], f'{CLASSES[cls_id]}')
|
86 |
+
cv2.putText(img, f'{CLASSES[cls_id]}', (x1, y1-6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
87 |
+
cv2.rectangle(img, (x1, y1), (x2, y2), (0, int(cls_id*color_step), int(255-cls_id*color_step)),thickness = 2)
|
88 |
+
img = cv2.addWeighted(im_canvas, 0.3, img, 0.7, 0)
|
89 |
+
return img
|
90 |
+
|
91 |
+
def scale_mask(masks, im0_shape):
|
92 |
+
masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]),
|
93 |
+
interpolation=cv2.INTER_LINEAR)
|
94 |
+
if len(masks.shape) == 2:
|
95 |
+
masks = masks[:, :, None]
|
96 |
+
return masks
|
97 |
+
|
98 |
+
def crop_mask(masks, boxes):
|
99 |
+
n, h, w = masks.shape
|
100 |
+
x1, y1, x2, y2 = np.split(boxes[:, :, None], 4, 1)
|
101 |
+
r = np.arange(w, dtype=x1.dtype)[None, None, :]
|
102 |
+
c = np.arange(h, dtype=x1.dtype)[None, :, None]
|
103 |
+
return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))
|
104 |
+
|
105 |
+
def process_mask(protos, masks_in, bboxes, im0_shape):
|
106 |
+
c, mh, mw = protos.shape
|
107 |
+
masks = np.matmul(masks_in, protos.reshape((c, -1))).reshape((-1, mh, mw)).transpose(1, 2, 0) # HWN
|
108 |
+
masks = np.ascontiguousarray(masks)
|
109 |
+
masks = scale_mask(masks, im0_shape) # re-scale mask from P3 shape to original input image shape
|
110 |
+
masks = np.einsum('HWN -> NHW', masks) # HWN -> NHW
|
111 |
+
masks = crop_mask(masks, bboxes)
|
112 |
+
return np.greater(masks, 0.5)
|
113 |
+
|
114 |
+
def masks2segments(masks):
|
115 |
+
segments = []
|
116 |
+
for x in masks.astype('uint8'):
|
117 |
+
c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # CHAIN_APPROX_SIMPLE
|
118 |
+
if c:
|
119 |
+
c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)
|
120 |
+
else:
|
121 |
+
c = np.zeros((0, 2)) # no segments found
|
122 |
+
segments.append(c.astype('float32'))
|
123 |
+
return segments
|
model_farm_yolov8s_qcs6490_qnn2.16_int8_aidlite/python/yolov8s.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
import aidlite
|
4 |
+
from utils import eqprocess, xywh2xyxy, NMS
|
5 |
+
import time
|
6 |
+
|
7 |
+
OBJ_THRESH = 0.45
|
8 |
+
NMS_THRESH = 0.45
|
9 |
+
|
10 |
+
class Yolov8S(object):
|
11 |
+
def __init__(self, model_path, width, height, class_num):
|
12 |
+
self.class_num = class_num
|
13 |
+
self.width = width
|
14 |
+
self.height = height
|
15 |
+
input_shape = [[1,height,width,3]]
|
16 |
+
self.blocks = int(height * width * ( 1 / 64 + 1 / 256 + 1 / 1024))
|
17 |
+
self.maskw = int(width / 4)
|
18 |
+
self.maskh = int(height / 4)
|
19 |
+
self.output_shape = [[1,4,self.blocks],[1,class_num,self.blocks]]
|
20 |
+
|
21 |
+
self.model = aidlite.Model.create_instance(model_path)
|
22 |
+
if self.model is None:
|
23 |
+
print("Create model failed !")
|
24 |
+
return
|
25 |
+
self.model.set_model_properties(input_shape, aidlite.DataType.TYPE_FLOAT32, self.output_shape, aidlite.DataType.TYPE_FLOAT32)
|
26 |
+
|
27 |
+
self.config = aidlite.Config.create_instance()
|
28 |
+
if self.config is None:
|
29 |
+
print("build_interpretper_from_model_and_config failed !")
|
30 |
+
return
|
31 |
+
|
32 |
+
self.config.framework_type = aidlite.FrameworkType.TYPE_QNN216
|
33 |
+
self.config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
34 |
+
self.config.is_quantify_model = 1
|
35 |
+
|
36 |
+
self.interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(self.model, self.config)
|
37 |
+
if self.interpreter is None:
|
38 |
+
print("build_interpretper_from_model_and_config failed !")
|
39 |
+
return
|
40 |
+
|
41 |
+
self.interpreter.init()
|
42 |
+
self.interpreter.load_model()
|
43 |
+
|
44 |
+
def __call__(self, frame,invoke_nums):
|
45 |
+
img, scale = eqprocess(frame, self.height, self.width)
|
46 |
+
img = img / 255
|
47 |
+
img = img.astype(np.float32)
|
48 |
+
self.interpreter.set_input_tensor(0,img.data)
|
49 |
+
|
50 |
+
invoke_time=[]
|
51 |
+
for i in range(invoke_nums):
|
52 |
+
t1=time.time()
|
53 |
+
self.interpreter.invoke()
|
54 |
+
cost_time = (time.time()-t1)*1000
|
55 |
+
invoke_time.append(cost_time)
|
56 |
+
|
57 |
+
max_invoke_time = max(invoke_time)
|
58 |
+
min_invoke_time = min(invoke_time)
|
59 |
+
mean_invoke_time = sum(invoke_time)/invoke_nums
|
60 |
+
var_invoketime=np.var(invoke_time)
|
61 |
+
print("====================================")
|
62 |
+
print(f"QNN invoke {invoke_nums} times:\n --mean_invoke_time is {mean_invoke_time} \n --max_invoke_time is {max_invoke_time} \n --min_invoke_time is {min_invoke_time} \n --var_invoketime is {var_invoketime}")
|
63 |
+
print("====================================")
|
64 |
+
|
65 |
+
qnn_1 = self.interpreter.get_output_tensor(0)
|
66 |
+
qnn_2 = self.interpreter.get_output_tensor(1)
|
67 |
+
qnn_out = sorted([qnn_1,qnn_2], key=len)
|
68 |
+
|
69 |
+
qnn_local = qnn_out[0].reshape(*self.output_shape[0])
|
70 |
+
qnn_conf = qnn_out[1].reshape(*self.output_shape[1])
|
71 |
+
|
72 |
+
|
73 |
+
x = np.concatenate([qnn_local, qnn_conf], axis = 1).transpose(0,2,1)
|
74 |
+
x = x[np.amax(x[..., 4:], axis=-1) > OBJ_THRESH]
|
75 |
+
if len(x) < 1:
|
76 |
+
return None, None
|
77 |
+
|
78 |
+
x = np.c_[x[..., :4], np.amax(x[..., 4:], axis=-1), np.argmax(x[..., 4:], axis=-1)]
|
79 |
+
|
80 |
+
x[:, :4] = xywh2xyxy(x[:, :4])
|
81 |
+
index = NMS(x[:, :4], x[:, 4], NMS_THRESH)
|
82 |
+
out_boxes = x[index]
|
83 |
+
out_boxes[..., :4] = out_boxes[..., :4] * scale
|
84 |
+
|
85 |
+
return out_boxes
|
86 |
+
|
model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Model Information
|
2 |
+
### Source model
|
3 |
+
- Input shape: 640x640
|
4 |
+
- Number of parameters: 10.65M
|
5 |
+
- Model size: 42.7M
|
6 |
+
- Output shape: 1x84x8400
|
7 |
+
|
8 |
+
Source model repository: [yolov8](https://github.com/ultralytics/ultralytics)
|
9 |
+
|
10 |
+
### Converted model
|
11 |
+
|
12 |
+
- Precision: FP16
|
13 |
+
- Backend: QNN2.16
|
14 |
+
- Target Device: SNM972 QCS8550
|
15 |
+
|
16 |
+
## Model Conversion Reference
|
17 |
+
User can find model conversion reference at [aimo.aidlux.com](https://aimo.aidlux.com/#/public/8204cbbb-e7dc-4c2b-8eb8-06e11fa82e29)
|
18 |
+
|
19 |
+
## Inference with AidLite SDK
|
20 |
+
|
21 |
+
### SDK installation
|
22 |
+
Model Farm uses AidLite SDK as the model inference SDK. For details, please refer to the [AidLite Developer Documentation](https://v2.docs.aidlux.com/en/sdk-api/aidlite-sdk/)
|
23 |
+
|
24 |
+
- install AidLite SDK
|
25 |
+
|
26 |
+
```bash
|
27 |
+
# Install the appropriate version of the aidlite sdk
|
28 |
+
sudo aid-pkg update
|
29 |
+
sudo aid-pkg install aidlite-sdk
|
30 |
+
# Download the qnn version that matches the above backend. Eg Install QNN2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
31 |
+
sudo aid-pkg install aidlite-{QNN VERSION}
|
32 |
+
```
|
33 |
+
|
34 |
+
- Verify AidLite SDK
|
35 |
+
|
36 |
+
```bash
|
37 |
+
# Install the appropriate version of the aidlite sdk
|
38 |
+
sudo aid-pkg update
|
39 |
+
sudo aid-pkg install aidlite-sdk
|
40 |
+
# Download the qnn version that matches the above backend. Eg Install QNN2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
41 |
+
sudo aid-pkg install aidlite-{QNN VERSION}
|
42 |
+
# eg: Install QNN 2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
43 |
+
```
|
44 |
+
|
45 |
+
### Run Demo
|
46 |
+
|
47 |
+
#### python
|
48 |
+
```bash
|
49 |
+
cd model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite
|
50 |
+
python3 python/run_test.py --target_model ./models/cutoff_yolov8s_fp16.qnn216.ctx.bin --imgs ./python/bus.jpg --invoke_nums 10
|
51 |
+
```
|
52 |
+
|
53 |
+
#### cpp
|
54 |
+
```bash
|
55 |
+
cd model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/cpp
|
56 |
+
mkdir -p build && cd build
|
57 |
+
cmake .. && make
|
58 |
+
./run_test --target_model ../../models/cutoff_yolov8s_fp16.qnn216.ctx.bin --imgs ../bus.jpg --invoke_nums 10
|
59 |
+
```
|
model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/cpp/CMakeLists.txt
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required (VERSION 3.5)
|
2 |
+
project("run_test")
|
3 |
+
|
4 |
+
find_package(OpenCV REQUIRED)
|
5 |
+
|
6 |
+
message(STATUS "oPENCV Library status:")
|
7 |
+
message(STATUS ">version:${OpenCV_VERSION}")
|
8 |
+
message(STATUS "Include:${OpenCV_INCLUDE_DIRS}")
|
9 |
+
|
10 |
+
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations")
|
11 |
+
|
12 |
+
include_directories(
|
13 |
+
/usr/local/include
|
14 |
+
/usr/include/opencv4
|
15 |
+
)
|
16 |
+
|
17 |
+
link_directories(
|
18 |
+
/usr/local/lib/
|
19 |
+
)
|
20 |
+
|
21 |
+
file(GLOB SRC_LISTS
|
22 |
+
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
23 |
+
)
|
24 |
+
|
25 |
+
add_executable(run_test ${SRC_LISTS})
|
26 |
+
|
27 |
+
target_link_libraries(run_test
|
28 |
+
aidlite
|
29 |
+
${OpenCV_LIBS}
|
30 |
+
)
|
model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/cpp/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/cpp/main.cpp
ADDED
@@ -0,0 +1,349 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <iostream>
|
2 |
+
#include <string>
|
3 |
+
#include <algorithm>
|
4 |
+
#include <cctype>
|
5 |
+
#include <opencv2/opencv.hpp>
|
6 |
+
#include <aidlux/aidlite/aidlite.hpp>
|
7 |
+
#include <vector>
|
8 |
+
#include <numeric>
|
9 |
+
|
10 |
+
const float INPUT_WIDTH = 640.0;
|
11 |
+
const float INPUT_HEIGHT = 640.0;
|
12 |
+
const float SCORE_THRESHOLD = 0.25;
|
13 |
+
const float NMS_THRESHOLD = 0.45;
|
14 |
+
const float CONFIDENCE_THRESHOLD = 0.25;
|
15 |
+
const uint32_t size = 640;
|
16 |
+
const uint32_t out_size = 8400;
|
17 |
+
|
18 |
+
const int FONT_FACE = cv::FONT_HERSHEY_SIMPLEX;
|
19 |
+
cv::Scalar WHITE = cv::Scalar(255,255,255);
|
20 |
+
|
21 |
+
const float FONT_SCALE = 0.75;
|
22 |
+
const int THICKNESS = 1;
|
23 |
+
|
24 |
+
const std::vector<std::string> class_list = {
|
25 |
+
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
|
26 |
+
"truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter",
|
27 |
+
"bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear",
|
28 |
+
"zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase",
|
29 |
+
"frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
|
30 |
+
"baseball glove", "skateboard", "surfboard", "tennis racket", "bottle",
|
31 |
+
"wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
32 |
+
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
|
33 |
+
"cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet",
|
34 |
+
"TV", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave",
|
35 |
+
"oven", "toaster", "sink", "refrigerator", "book", "clock", "vase",
|
36 |
+
"scissors", "teddy bear", "hair drier", "toothbrush"
|
37 |
+
};
|
38 |
+
|
39 |
+
using namespace Aidlux::Aidlite;
|
40 |
+
|
41 |
+
struct Args {
|
42 |
+
std::string target_model = "../../models/cutoff_yolov8s_fp16.qnn216.ctx.bin.aidem";
|
43 |
+
std::string imgs = "../bus.jpg";
|
44 |
+
int invoke_nums = 10;
|
45 |
+
std::string model_type = "QNN";
|
46 |
+
};
|
47 |
+
|
48 |
+
Args parse_args(int argc, char* argv[]) {
|
49 |
+
Args args;
|
50 |
+
for (int i = 1; i < argc; ++i) {
|
51 |
+
std::string arg = argv[i];
|
52 |
+
if (arg == "--target_model" && i + 1 < argc) {
|
53 |
+
args.target_model = argv[++i];
|
54 |
+
} else if (arg == "--imgs" && i + 1 < argc) {
|
55 |
+
args.imgs = argv[++i];
|
56 |
+
} else if (arg == "--invoke_nums" && i + 1 < argc) {
|
57 |
+
args.invoke_nums = std::stoi(argv[++i]);
|
58 |
+
} else if (arg == "--model_type" && i + 1 < argc) {
|
59 |
+
args.model_type = argv[++i];
|
60 |
+
}
|
61 |
+
}
|
62 |
+
return args;
|
63 |
+
}
|
64 |
+
|
65 |
+
std::string to_lower(const std::string& str) {
|
66 |
+
std::string lower_str = str;
|
67 |
+
std::transform(lower_str.begin(), lower_str.end(), lower_str.begin(), [](unsigned char c) {
|
68 |
+
return std::tolower(c);
|
69 |
+
});
|
70 |
+
return lower_str;
|
71 |
+
}
|
72 |
+
|
73 |
+
|
74 |
+
void concatenate(float* qnn_trans_data, float* qnn_mul_data, int batch, int num_elements, int trans_dim, int mul_dim, std::vector<float>& output) {
|
75 |
+
int out_dim = trans_dim + mul_dim + 1;
|
76 |
+
output.resize(batch * num_elements * out_dim);
|
77 |
+
for (int i = 0; i < batch * num_elements; ++i) {
|
78 |
+
std::memcpy(&output[i * out_dim], &qnn_mul_data[i * mul_dim], mul_dim * sizeof(float));
|
79 |
+
float max_val = *std::max_element(&qnn_trans_data[i * trans_dim], &qnn_trans_data[i * trans_dim + trans_dim]);
|
80 |
+
output[i * out_dim + 4] = max_val;
|
81 |
+
std::memcpy(&output[i * out_dim + 5], &qnn_trans_data[i * trans_dim], trans_dim * sizeof(float));
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
void transformData(const float* input, float* output, int C, int N) {
|
86 |
+
for (int c = 0; c < C; ++c) {
|
87 |
+
for (int n = 0; n < N; ++n) {
|
88 |
+
output[n * C + c] = input[c * N + n];
|
89 |
+
}
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
double img_process(cv::Mat frame, cv::Mat &img_input, int size) {
|
94 |
+
cv::Mat img_processed = frame.clone();
|
95 |
+
int height = img_processed.rows;
|
96 |
+
int width = img_processed.cols;
|
97 |
+
int length = std::max(height, width);
|
98 |
+
double scala = static_cast<double>(length) / size;
|
99 |
+
|
100 |
+
cv::Mat image = cv::Mat::zeros(cv::Size(length, length), CV_8UC3);
|
101 |
+
img_processed.copyTo(image(cv::Rect(0, 0, width, height)));
|
102 |
+
|
103 |
+
cv::cvtColor(image, img_input, cv::COLOR_BGR2RGB);
|
104 |
+
cv::resize(img_input, img_input, cv::Size(size, size));
|
105 |
+
|
106 |
+
cv::Mat mean_data = cv::Mat::zeros(img_input.size(), CV_32FC3);
|
107 |
+
cv::Mat std_data(img_input.size(), CV_32FC3, cv::Scalar(255, 255, 255));
|
108 |
+
img_input.convertTo(img_input, CV_32FC3);
|
109 |
+
img_input = (img_input - mean_data) / std_data;
|
110 |
+
return scala;
|
111 |
+
}
|
112 |
+
|
113 |
+
|
114 |
+
cv::Scalar generate_colors(int i, bool bgr = false) {
|
115 |
+
static const std::vector<std::string> hex_colors = {
|
116 |
+
"FF3838", "FF9D97", "FF701F", "FFB21D", "CFD231", "48F90A",
|
117 |
+
"92CC17", "3DDB86", "1A9334", "00D4BB", "2C99A8", "00C2FF",
|
118 |
+
"344593", "6473FF", "0018EC", "8438FF", "520085", "CB38FF",
|
119 |
+
"FF95C8", "FF37C7"
|
120 |
+
};
|
121 |
+
|
122 |
+
int num = hex_colors.size();
|
123 |
+
std::string hex = hex_colors[i % num];
|
124 |
+
|
125 |
+
int r = std::stoi(hex.substr(0, 2), nullptr, 16);
|
126 |
+
int g = std::stoi(hex.substr(2, 2), nullptr, 16);
|
127 |
+
int b = std::stoi(hex.substr(4, 2), nullptr, 16);
|
128 |
+
|
129 |
+
if (bgr)
|
130 |
+
return cv::Scalar(b, g, r);
|
131 |
+
else
|
132 |
+
return cv::Scalar(r, g, b);
|
133 |
+
}
|
134 |
+
|
135 |
+
void draw_label(cv::Mat& input_image, std::string label, int left, int top, cv::Scalar color)
|
136 |
+
{
|
137 |
+
int baseLine;
|
138 |
+
cv::Size label_size = cv::getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS, &baseLine);
|
139 |
+
int y = top - label_size.height - baseLine;
|
140 |
+
if (y < 0) {
|
141 |
+
y = top ;
|
142 |
+
}
|
143 |
+
cv::Point tlc(left, y);
|
144 |
+
cv::Point brc(left + label_size.width, y + label_size.height + baseLine);
|
145 |
+
rectangle(input_image, tlc, brc, color, cv::FILLED);
|
146 |
+
putText(input_image, label, cv::Point(left, y + label_size.height), FONT_FACE, FONT_SCALE, WHITE, THICKNESS);
|
147 |
+
}
|
148 |
+
|
149 |
+
|
150 |
+
cv::Mat post_process(cv::Mat &input_image, std::vector<float> &outputs, const std::vector<std::string> &class_name, const double ratio)
|
151 |
+
{
|
152 |
+
// Initialize vectors to hold respective outputs while unwrapping detections.
|
153 |
+
std::vector<int> class_ids;
|
154 |
+
std::vector<float> confidences;
|
155 |
+
std::vector<cv::Rect> boxes;
|
156 |
+
|
157 |
+
// Iterate through outputs for each box prediction
|
158 |
+
for (int i = 0; i < outputs.size(); i+=85)
|
159 |
+
{
|
160 |
+
float confidence = outputs[i+4];
|
161 |
+
if (confidence >= CONFIDENCE_THRESHOLD)
|
162 |
+
{
|
163 |
+
// Create a 1x80 Mat and store class scores of 80 classes.
|
164 |
+
cv::Mat scores(1, class_name.size(), CV_32FC1, outputs.data() + i + 5);
|
165 |
+
cv::Point class_id;
|
166 |
+
double max_class_score;
|
167 |
+
|
168 |
+
// For multi-label, check each class score
|
169 |
+
for (int c = 0; c < class_name.size(); c++) {
|
170 |
+
float class_score = scores.at<float>(0, c);
|
171 |
+
|
172 |
+
// If class score is above threshold, consider this class for the box
|
173 |
+
if (class_score > SCORE_THRESHOLD) {
|
174 |
+
// Store class ID and confidence in the pre-defined respective vectors.
|
175 |
+
confidences.push_back(confidence * class_score); // Multiply with confidence
|
176 |
+
class_ids.push_back(c); // class index
|
177 |
+
// Center and box dimension.
|
178 |
+
float cx = outputs[i];
|
179 |
+
float cy = outputs[i+1];
|
180 |
+
float w = outputs[i+2];
|
181 |
+
float h = outputs[i+3];
|
182 |
+
|
183 |
+
int left = int((cx - 0.5 * w) * ratio);
|
184 |
+
int top = int((cy - 0.5 * h) * ratio);
|
185 |
+
int width = int(w * ratio);
|
186 |
+
int height = int(h * ratio);
|
187 |
+
|
188 |
+
// Store good detections in the boxes vector.
|
189 |
+
boxes.push_back(cv::Rect(left, top, width, height));
|
190 |
+
}
|
191 |
+
}
|
192 |
+
}
|
193 |
+
}
|
194 |
+
|
195 |
+
// Perform Non Maximum Suppression and draw predictions.
|
196 |
+
std::vector<int> indices;
|
197 |
+
cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, indices);
|
198 |
+
printf("Detected {%ld} targets.\n", indices.size());
|
199 |
+
|
200 |
+
// Loop over NMS results and draw bounding boxes
|
201 |
+
for (int i = 0; i < indices.size(); i++)
|
202 |
+
{
|
203 |
+
int idx = indices[i];
|
204 |
+
cv::Rect box = boxes[idx];
|
205 |
+
|
206 |
+
int left = box.x;
|
207 |
+
int top = box.y;
|
208 |
+
int width = box.width;
|
209 |
+
int height = box.height;
|
210 |
+
cv::Scalar color = generate_colors(class_ids[idx]);
|
211 |
+
// Draw bounding box.
|
212 |
+
rectangle(input_image, cv::Point(left, top), cv::Point(left + width, top + height), color, 2*THICKNESS);
|
213 |
+
|
214 |
+
// Get the label for the class name and its confidence.
|
215 |
+
std::string label = cv::format("%.2f", confidences[idx]);
|
216 |
+
label = class_name[class_ids[idx]] + ":" + label;
|
217 |
+
// Draw class labels.
|
218 |
+
draw_label(input_image, label, left, top, color);
|
219 |
+
}
|
220 |
+
printf("Processing finished.\n");
|
221 |
+
return input_image;
|
222 |
+
}
|
223 |
+
|
224 |
+
int invoke(const Args& args) {
|
225 |
+
std::cout << "Start main ... ... Model Path: " << args.target_model << "\n"
|
226 |
+
<< "Image Path: " << args.imgs << "\n"
|
227 |
+
<< "Inference Nums: " << args.invoke_nums << "\n"
|
228 |
+
<< "Model Type: " << args.model_type << "\n";
|
229 |
+
Model* model = Model::create_instance(args.target_model);
|
230 |
+
if(model == nullptr){
|
231 |
+
printf("Create model failed !\n");
|
232 |
+
return EXIT_FAILURE;
|
233 |
+
}
|
234 |
+
Config* config = Config::create_instance();
|
235 |
+
if(config == nullptr){
|
236 |
+
printf("Create config failed !\n");
|
237 |
+
return EXIT_FAILURE;
|
238 |
+
}
|
239 |
+
config->implement_type = ImplementType::TYPE_LOCAL;
|
240 |
+
std::string model_type_lower = to_lower(args.model_type);
|
241 |
+
if (model_type_lower == "qnn"){
|
242 |
+
config->framework_type = FrameworkType::TYPE_QNN;
|
243 |
+
} else if (model_type_lower == "snpe2" || model_type_lower == "snpe") {
|
244 |
+
config->framework_type = FrameworkType::TYPE_SNPE2;
|
245 |
+
}
|
246 |
+
config->accelerate_type = AccelerateType::TYPE_DSP;
|
247 |
+
config->is_quantify_model = 1;
|
248 |
+
|
249 |
+
std::vector<std::vector<uint32_t>> input_shapes = {{1, size, size, 3}};
|
250 |
+
std::vector<std::vector<uint32_t>> output_shapes = {{1, 4, out_size}, {1, 80, out_size}};
|
251 |
+
model->set_model_properties(input_shapes, DataType::TYPE_FLOAT32, output_shapes, DataType::TYPE_FLOAT32);
|
252 |
+
std::unique_ptr<Interpreter> fast_interpreter = InterpreterBuilder::build_interpretper_from_model_and_config(model, config);
|
253 |
+
if(fast_interpreter == nullptr){
|
254 |
+
printf("build_interpretper_from_model_and_config failed !\n");
|
255 |
+
return EXIT_FAILURE;
|
256 |
+
}
|
257 |
+
int result = fast_interpreter->init();
|
258 |
+
if(result != EXIT_SUCCESS){
|
259 |
+
printf("interpreter->init() failed !\n");
|
260 |
+
return EXIT_FAILURE;
|
261 |
+
}
|
262 |
+
// load model
|
263 |
+
fast_interpreter->load_model();
|
264 |
+
if(result != EXIT_SUCCESS){
|
265 |
+
printf("interpreter->load_model() failed !\n");
|
266 |
+
return EXIT_FAILURE;
|
267 |
+
}
|
268 |
+
printf("detect model load success!\n");
|
269 |
+
|
270 |
+
cv::Mat frame = cv::imread(args.imgs);
|
271 |
+
if (frame.empty()) {
|
272 |
+
printf("detect image load failed!\n");
|
273 |
+
return 1;
|
274 |
+
}
|
275 |
+
printf("img_src cols: %d, img_src rows: %d\n", frame.cols, frame.rows);
|
276 |
+
cv::Mat input_img;
|
277 |
+
double scale = img_process(frame, input_img, size);
|
278 |
+
if (input_img.empty()) {
|
279 |
+
printf("detect input_img load failed!\n");
|
280 |
+
return 1;
|
281 |
+
}
|
282 |
+
|
283 |
+
float *qnn_trans_data = nullptr;
|
284 |
+
float *qnn_mul_data = nullptr;
|
285 |
+
|
286 |
+
std::vector<float> invoke_time;
|
287 |
+
for (int i = 0; i < args.invoke_nums; ++i) {
|
288 |
+
result = fast_interpreter->set_input_tensor(0, input_img.data);
|
289 |
+
if(result != EXIT_SUCCESS){
|
290 |
+
printf("interpreter->set_input_tensor() failed !\n");
|
291 |
+
return EXIT_FAILURE;
|
292 |
+
}
|
293 |
+
// 开始计时
|
294 |
+
auto t1 = std::chrono::high_resolution_clock::now();
|
295 |
+
result = fast_interpreter->invoke();
|
296 |
+
auto t2 = std::chrono::high_resolution_clock::now();
|
297 |
+
std::chrono::duration<double> cost_time = t2 - t1;
|
298 |
+
invoke_time.push_back(cost_time.count() * 1000);
|
299 |
+
if(result != EXIT_SUCCESS){
|
300 |
+
printf("interpreter->invoke() failed !\n");
|
301 |
+
return EXIT_FAILURE;
|
302 |
+
}
|
303 |
+
uint32_t out_data_1 = 0;
|
304 |
+
result = fast_interpreter->get_output_tensor(0, (void**)&qnn_trans_data, &out_data_1);
|
305 |
+
if(result != EXIT_SUCCESS){
|
306 |
+
printf("interpreter->get_output_tensor() 1 failed !\n");
|
307 |
+
return EXIT_FAILURE;
|
308 |
+
}
|
309 |
+
uint32_t out_data_2 = 0;
|
310 |
+
result = fast_interpreter->get_output_tensor(1, (void**)&qnn_mul_data, &out_data_2);
|
311 |
+
if(result != EXIT_SUCCESS){
|
312 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
313 |
+
return EXIT_FAILURE;
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
float max_invoke_time = *std::max_element(invoke_time.begin(), invoke_time.end());
|
318 |
+
float min_invoke_time = *std::min_element(invoke_time.begin(), invoke_time.end());
|
319 |
+
float mean_invoke_time = std::accumulate(invoke_time.begin(), invoke_time.end(), 0.0f) / args.invoke_nums;
|
320 |
+
float var_invoketime = 0.0f;
|
321 |
+
for (auto time : invoke_time) {
|
322 |
+
var_invoketime += (time - mean_invoke_time) * (time - mean_invoke_time);
|
323 |
+
}
|
324 |
+
var_invoketime /= args.invoke_nums;
|
325 |
+
printf("=======================================\n");
|
326 |
+
printf("QNN inference %d times :\n --mean_invoke_time is %f \n --max_invoke_time is %f \n --min_invoke_time is %f \n --var_invoketime is %f\n",
|
327 |
+
args.invoke_nums, mean_invoke_time, max_invoke_time, min_invoke_time, var_invoketime);
|
328 |
+
printf("=======================================\n");
|
329 |
+
|
330 |
+
// std::vector<std::vector<uint32_t>> output_shapes = {{1, 4, out_size}, {1, 80, out_size}};
|
331 |
+
float* pos_data = new float[4 * out_size];
|
332 |
+
float* class_data = new float[80 * out_size];
|
333 |
+
transformData(qnn_trans_data, pos_data, 4, out_size);
|
334 |
+
transformData(qnn_mul_data, class_data, 80, out_size);
|
335 |
+
|
336 |
+
// post process
|
337 |
+
std::vector<float> qnn_concat;
|
338 |
+
concatenate(class_data, pos_data , 1, out_size, 80, 4, qnn_concat);
|
339 |
+
cv::Mat img = post_process(frame, qnn_concat, class_list, scale);
|
340 |
+
cv::imwrite("./results.png", img);
|
341 |
+
fast_interpreter->destory();
|
342 |
+
return 0;
|
343 |
+
}
|
344 |
+
|
345 |
+
|
346 |
+
int main(int argc, char* argv[]) {
|
347 |
+
Args args = parse_args(argc, argv);
|
348 |
+
return invoke(args);
|
349 |
+
}
|
model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/models/cutoff_yolov8s_fp16.qnn216.ctx.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:68c451e6059b8cbbfcc732cfe83571223a7e0c4120c1437d78d32d5e4f828d8e
|
3 |
+
size 23003136
|
model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/python/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/python/run_test.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import argparse
|
3 |
+
from yolov8s import Yolov8S
|
4 |
+
from utils import draw_detect_res
|
5 |
+
|
6 |
+
def parser_args():
|
7 |
+
parser = argparse.ArgumentParser(description="Run model benchmarks")
|
8 |
+
parser.add_argument('--target_model',type=str,default='./models/cutoff_yolov8s_w8a8.qnn231.ctx.bin.aidem',help="inference model path")
|
9 |
+
parser.add_argument('--imgs',type=str,default='./python/bus.jpg',help="Predict images path")
|
10 |
+
parser.add_argument('--height',type=int,default=640,help="run backend")
|
11 |
+
parser.add_argument('--weight',type=int,default=640,help="run backend")
|
12 |
+
parser.add_argument('--cls_num',type=int,default=80,help="run backend")
|
13 |
+
parser.add_argument('--invoke_nums',type=int,default=10,help="Inference nums")
|
14 |
+
parser.add_argument('--model_type',type=str,default='QNN',help="run backend")
|
15 |
+
args = parser.parse_args()
|
16 |
+
return args
|
17 |
+
|
18 |
+
if __name__ == "__main__":
|
19 |
+
args = parser_args()
|
20 |
+
height = args.height
|
21 |
+
weight = args.weight
|
22 |
+
|
23 |
+
|
24 |
+
model = Yolov8S(args.target_model, args.weight, args.height, args.cls_num)
|
25 |
+
frame = cv2.imread(args.imgs)
|
26 |
+
|
27 |
+
out_boxes= model(frame,args.invoke_nums)
|
28 |
+
print(f"=================== \n Detect {len(out_boxes)} targets.")
|
29 |
+
result = draw_detect_res(frame, out_boxes)
|
30 |
+
cv2.imwrite("./python/result.jpg", result)
|
model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/python/utils.py
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
|
4 |
+
CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light",
|
5 |
+
"fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant",
|
6 |
+
"bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
|
7 |
+
"baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ",
|
8 |
+
"spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa",
|
9 |
+
"pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop ", "mouse ", "remote ", "keyboard ", "cell phone", "microwave ",
|
10 |
+
"oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ")
|
11 |
+
|
12 |
+
def eqprocess(image, size1, size2):
|
13 |
+
h,w,_ = image.shape
|
14 |
+
mask = np.zeros((size1,size2,3),dtype=np.float32)
|
15 |
+
scale1 = h /size1
|
16 |
+
scale2 = w / size2
|
17 |
+
if scale1 > scale2:
|
18 |
+
scale = scale1
|
19 |
+
else:
|
20 |
+
scale = scale2
|
21 |
+
img = cv2.resize(image,(int(w / scale),int(h / scale)))
|
22 |
+
mask[:int(h / scale),:int(w / scale),:] = img
|
23 |
+
return mask, scale
|
24 |
+
|
25 |
+
def xywh2xyxy(x):
|
26 |
+
'''
|
27 |
+
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
28 |
+
'''
|
29 |
+
y = np.copy(x)
|
30 |
+
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
31 |
+
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
32 |
+
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
33 |
+
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
34 |
+
return y
|
35 |
+
|
36 |
+
def xyxy2xywh(box):
|
37 |
+
'''
|
38 |
+
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
39 |
+
'''
|
40 |
+
box[:, 2:] = box[:, 2:] - box[:, :2]
|
41 |
+
return box
|
42 |
+
|
43 |
+
def NMS(dets, scores, thresh):
|
44 |
+
'''
|
45 |
+
单类NMS算法
|
46 |
+
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
47 |
+
'''
|
48 |
+
x1 = dets[:,0]
|
49 |
+
y1 = dets[:,1]
|
50 |
+
x2 = dets[:,2]
|
51 |
+
y2 = dets[:,3]
|
52 |
+
areas = (y2-y1+1) * (x2-x1+1)
|
53 |
+
keep = []
|
54 |
+
index = scores.argsort()[::-1]
|
55 |
+
while index.size >0:
|
56 |
+
i = index[0] # every time the first is the biggst, and add it directly
|
57 |
+
keep.append(i)
|
58 |
+
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
59 |
+
y11 = np.maximum(y1[i], y1[index[1:]])
|
60 |
+
x22 = np.minimum(x2[i], x2[index[1:]])
|
61 |
+
y22 = np.minimum(y2[i], y2[index[1:]])
|
62 |
+
w = np.maximum(0, x22-x11+1) # the weights of overlap
|
63 |
+
h = np.maximum(0, y22-y11+1) # the height of overlap
|
64 |
+
overlaps = w*h
|
65 |
+
ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
|
66 |
+
idx = np.where(ious<=thresh)[0]
|
67 |
+
index = index[idx+1] # because index start from 1
|
68 |
+
|
69 |
+
return keep
|
70 |
+
|
71 |
+
|
72 |
+
def draw_detect_res(img, det_pred):
|
73 |
+
'''
|
74 |
+
检测结果绘制
|
75 |
+
'''
|
76 |
+
if det_pred is None:
|
77 |
+
return img
|
78 |
+
|
79 |
+
img = img.astype(np.uint8)
|
80 |
+
im_canvas = img.copy()
|
81 |
+
color_step = int(255/len(CLASSES))
|
82 |
+
for i in range(len(det_pred)):
|
83 |
+
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
84 |
+
cls_id = int(det_pred[i][5])
|
85 |
+
print(i+1,[x1,y1,x2,y2],det_pred[i][4], f'{CLASSES[cls_id]}')
|
86 |
+
cv2.putText(img, f'{CLASSES[cls_id]}', (x1, y1-6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
87 |
+
cv2.rectangle(img, (x1, y1), (x2, y2), (0, int(cls_id*color_step), int(255-cls_id*color_step)),thickness = 2)
|
88 |
+
img = cv2.addWeighted(im_canvas, 0.3, img, 0.7, 0)
|
89 |
+
return img
|
90 |
+
|
91 |
+
def scale_mask(masks, im0_shape):
|
92 |
+
masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]),
|
93 |
+
interpolation=cv2.INTER_LINEAR)
|
94 |
+
if len(masks.shape) == 2:
|
95 |
+
masks = masks[:, :, None]
|
96 |
+
return masks
|
97 |
+
|
98 |
+
def crop_mask(masks, boxes):
|
99 |
+
n, h, w = masks.shape
|
100 |
+
x1, y1, x2, y2 = np.split(boxes[:, :, None], 4, 1)
|
101 |
+
r = np.arange(w, dtype=x1.dtype)[None, None, :]
|
102 |
+
c = np.arange(h, dtype=x1.dtype)[None, :, None]
|
103 |
+
return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))
|
104 |
+
|
105 |
+
def process_mask(protos, masks_in, bboxes, im0_shape):
|
106 |
+
c, mh, mw = protos.shape
|
107 |
+
masks = np.matmul(masks_in, protos.reshape((c, -1))).reshape((-1, mh, mw)).transpose(1, 2, 0) # HWN
|
108 |
+
masks = np.ascontiguousarray(masks)
|
109 |
+
masks = scale_mask(masks, im0_shape) # re-scale mask from P3 shape to original input image shape
|
110 |
+
masks = np.einsum('HWN -> NHW', masks) # HWN -> NHW
|
111 |
+
masks = crop_mask(masks, bboxes)
|
112 |
+
return np.greater(masks, 0.5)
|
113 |
+
|
114 |
+
def masks2segments(masks):
|
115 |
+
segments = []
|
116 |
+
for x in masks.astype('uint8'):
|
117 |
+
c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # CHAIN_APPROX_SIMPLE
|
118 |
+
if c:
|
119 |
+
c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)
|
120 |
+
else:
|
121 |
+
c = np.zeros((0, 2)) # no segments found
|
122 |
+
segments.append(c.astype('float32'))
|
123 |
+
return segments
|
model_farm_yolov8s_qcs8550_qnn2.16_fp16_aidlite/python/yolov8s.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
import aidlite
|
4 |
+
from utils import eqprocess, xywh2xyxy, NMS
|
5 |
+
import time
|
6 |
+
|
7 |
+
OBJ_THRESH = 0.45
|
8 |
+
NMS_THRESH = 0.45
|
9 |
+
|
10 |
+
class Yolov8S(object):
|
11 |
+
def __init__(self, model_path, width, height, class_num):
|
12 |
+
self.class_num = class_num
|
13 |
+
self.width = width
|
14 |
+
self.height = height
|
15 |
+
input_shape = [[1,height,width,3]]
|
16 |
+
self.blocks = int(height * width * ( 1 / 64 + 1 / 256 + 1 / 1024))
|
17 |
+
self.maskw = int(width / 4)
|
18 |
+
self.maskh = int(height / 4)
|
19 |
+
self.output_shape = [[1,4,self.blocks],[1,class_num,self.blocks]]
|
20 |
+
|
21 |
+
self.model = aidlite.Model.create_instance(model_path)
|
22 |
+
if self.model is None:
|
23 |
+
print("Create model failed !")
|
24 |
+
return
|
25 |
+
self.model.set_model_properties(input_shape, aidlite.DataType.TYPE_FLOAT32, self.output_shape, aidlite.DataType.TYPE_FLOAT32)
|
26 |
+
|
27 |
+
self.config = aidlite.Config.create_instance()
|
28 |
+
if self.config is None:
|
29 |
+
print("build_interpretper_from_model_and_config failed !")
|
30 |
+
return
|
31 |
+
|
32 |
+
self.config.framework_type = aidlite.FrameworkType.TYPE_QNN
|
33 |
+
self.config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
34 |
+
self.config.is_quantify_model = 1
|
35 |
+
|
36 |
+
self.interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(self.model, self.config)
|
37 |
+
if self.interpreter is None:
|
38 |
+
print("build_interpretper_from_model_and_config failed !")
|
39 |
+
return
|
40 |
+
|
41 |
+
self.interpreter.init()
|
42 |
+
self.interpreter.load_model()
|
43 |
+
|
44 |
+
def __call__(self, frame,invoke_nums):
|
45 |
+
img, scale = eqprocess(frame, self.height, self.width)
|
46 |
+
img = img / 255
|
47 |
+
img = img.astype(np.float32)
|
48 |
+
self.interpreter.set_input_tensor(0,img.data)
|
49 |
+
|
50 |
+
invoke_time=[]
|
51 |
+
for i in range(invoke_nums):
|
52 |
+
t1=time.time()
|
53 |
+
self.interpreter.invoke()
|
54 |
+
cost_time = (time.time()-t1)*1000
|
55 |
+
invoke_time.append(cost_time)
|
56 |
+
|
57 |
+
max_invoke_time = max(invoke_time)
|
58 |
+
min_invoke_time = min(invoke_time)
|
59 |
+
mean_invoke_time = sum(invoke_time)/invoke_nums
|
60 |
+
var_invoketime=np.var(invoke_time)
|
61 |
+
print("====================================")
|
62 |
+
print(f"QNN invoke {invoke_nums} times:\n --mean_invoke_time is {mean_invoke_time} \n --max_invoke_time is {max_invoke_time} \n --min_invoke_time is {min_invoke_time} \n --var_invoketime is {var_invoketime}")
|
63 |
+
print("====================================")
|
64 |
+
|
65 |
+
qnn_1 = self.interpreter.get_output_tensor(0)
|
66 |
+
qnn_2 = self.interpreter.get_output_tensor(1)
|
67 |
+
qnn_out = sorted([qnn_1,qnn_2], key=len)
|
68 |
+
|
69 |
+
qnn_local = qnn_out[0].reshape(*self.output_shape[0])
|
70 |
+
qnn_conf = qnn_out[1].reshape(*self.output_shape[1])
|
71 |
+
|
72 |
+
|
73 |
+
x = np.concatenate([qnn_local, qnn_conf], axis = 1).transpose(0,2,1)
|
74 |
+
x = x[np.amax(x[..., 4:], axis=-1) > OBJ_THRESH]
|
75 |
+
if len(x) < 1:
|
76 |
+
return None, None
|
77 |
+
|
78 |
+
x = np.c_[x[..., :4], np.amax(x[..., 4:], axis=-1), np.argmax(x[..., 4:], axis=-1)]
|
79 |
+
|
80 |
+
x[:, :4] = xywh2xyxy(x[:, :4])
|
81 |
+
index = NMS(x[:, :4], x[:, 4], NMS_THRESH)
|
82 |
+
out_boxes = x[index]
|
83 |
+
out_boxes[..., :4] = out_boxes[..., :4] * scale
|
84 |
+
|
85 |
+
return out_boxes
|
86 |
+
|
model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
## Model Information
|
2 |
+
### Source model
|
3 |
+
- Input shape: 640x640
|
4 |
+
- Number of parameters: 10.65M
|
5 |
+
- Model size: 42.7M
|
6 |
+
- Output shape: 1x84x8400
|
7 |
+
|
8 |
+
Source model repository: [yolov8](https://github.com/ultralytics/ultralytics)
|
9 |
+
|
10 |
+
### Converted model
|
11 |
+
|
12 |
+
- Precision: INT8
|
13 |
+
- Backend: QNN2.16
|
14 |
+
- Target Device: SNM972 QCS8550
|
15 |
+
|
16 |
+
## Model Conversion Reference
|
17 |
+
User can find model conversion reference at [aimo.aidlux.com](https://aimo.aidlux.com/#/public/34252a53-87e0-4fe2-b1bb-87c153fc21b7)
|
18 |
+
|
19 |
+
## Inference with AidLite SDK
|
20 |
+
|
21 |
+
### SDK installation
|
22 |
+
Model Farm uses AidLite SDK as the model inference SDK. For details, please refer to the [AidLite Developer Documentation](https://v2.docs.aidlux.com/en/sdk-api/aidlite-sdk/)
|
23 |
+
|
24 |
+
- install AidLite SDK
|
25 |
+
|
26 |
+
```bash
|
27 |
+
# Install the appropriate version of the aidlite sdk
|
28 |
+
sudo aid-pkg update
|
29 |
+
sudo aid-pkg install aidlite-sdk
|
30 |
+
# Download the qnn version that matches the above backend. Eg Install QNN2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
31 |
+
sudo aid-pkg install aidlite-{QNN VERSION}
|
32 |
+
# eg: Install QNN 2.23 Aidlite: sudo aid-pkg install aidlite-qnn223
|
33 |
+
```
|
34 |
+
|
35 |
+
- Verify AidLite SDK
|
36 |
+
|
37 |
+
```bash
|
38 |
+
# aidlite sdk c++ check
|
39 |
+
python3 -c "import aidlite ; print(aidlite.get_library_version())"
|
40 |
+
|
41 |
+
# aidlite sdk python check
|
42 |
+
python3 -c "import aidlite ; print(aidlite.get_py_library_version())"
|
43 |
+
```
|
44 |
+
|
45 |
+
### Run Demo
|
46 |
+
|
47 |
+
#### python
|
48 |
+
```bash
|
49 |
+
cd model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite
|
50 |
+
python3 python/run_test.py --target_model ./models/cutoff_yolov8s_w8a8.qnn216.ctx.bin --imgs ./python/bus.jpg --invoke_nums 10
|
51 |
+
```
|
52 |
+
|
53 |
+
#### cpp
|
54 |
+
```bash
|
55 |
+
cd model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/cpp
|
56 |
+
mkdir -p build && cd build
|
57 |
+
cmake .. && make
|
58 |
+
./run_test --target_model ../../models/cutoff_yolov8s_w8a8.qnn216.ctx.bin --imgs ../bus.jpg --invoke_nums 10
|
59 |
+
```
|
model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/cpp/CMakeLists.txt
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
cmake_minimum_required (VERSION 3.5)
|
2 |
+
project("run_test")
|
3 |
+
|
4 |
+
find_package(OpenCV REQUIRED)
|
5 |
+
|
6 |
+
message(STATUS "oPENCV Library status:")
|
7 |
+
message(STATUS ">version:${OpenCV_VERSION}")
|
8 |
+
message(STATUS "Include:${OpenCV_INCLUDE_DIRS}")
|
9 |
+
|
10 |
+
set(CMAKE_CXX_FLAGS "-Wno-error=deprecated-declarations -Wno-deprecated-declarations")
|
11 |
+
|
12 |
+
include_directories(
|
13 |
+
/usr/local/include
|
14 |
+
/usr/include/opencv4
|
15 |
+
)
|
16 |
+
|
17 |
+
link_directories(
|
18 |
+
/usr/local/lib/
|
19 |
+
)
|
20 |
+
|
21 |
+
file(GLOB SRC_LISTS
|
22 |
+
${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
|
23 |
+
)
|
24 |
+
|
25 |
+
add_executable(run_test ${SRC_LISTS})
|
26 |
+
|
27 |
+
target_link_libraries(run_test
|
28 |
+
aidlite
|
29 |
+
${OpenCV_LIBS}
|
30 |
+
)
|
model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/cpp/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/cpp/main.cpp
ADDED
@@ -0,0 +1,349 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
#include <iostream>
|
2 |
+
#include <string>
|
3 |
+
#include <algorithm>
|
4 |
+
#include <cctype>
|
5 |
+
#include <opencv2/opencv.hpp>
|
6 |
+
#include <aidlux/aidlite/aidlite.hpp>
|
7 |
+
#include <vector>
|
8 |
+
#include <numeric>
|
9 |
+
|
10 |
+
const float INPUT_WIDTH = 640.0;
|
11 |
+
const float INPUT_HEIGHT = 640.0;
|
12 |
+
const float SCORE_THRESHOLD = 0.25;
|
13 |
+
const float NMS_THRESHOLD = 0.45;
|
14 |
+
const float CONFIDENCE_THRESHOLD = 0.25;
|
15 |
+
const uint32_t size = 640;
|
16 |
+
const uint32_t out_size = 8400;
|
17 |
+
|
18 |
+
const int FONT_FACE = cv::FONT_HERSHEY_SIMPLEX;
|
19 |
+
cv::Scalar WHITE = cv::Scalar(255,255,255);
|
20 |
+
|
21 |
+
const float FONT_SCALE = 0.75;
|
22 |
+
const int THICKNESS = 1;
|
23 |
+
|
24 |
+
const std::vector<std::string> class_list = {
|
25 |
+
"person", "bicycle", "car", "motorcycle", "airplane", "bus", "train",
|
26 |
+
"truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter",
|
27 |
+
"bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear",
|
28 |
+
"zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase",
|
29 |
+
"frisbee", "skis", "snowboard", "sports ball", "kite", "baseball bat",
|
30 |
+
"baseball glove", "skateboard", "surfboard", "tennis racket", "bottle",
|
31 |
+
"wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
|
32 |
+
"sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut",
|
33 |
+
"cake", "chair", "couch", "potted plant", "bed", "dining table", "toilet",
|
34 |
+
"TV", "laptop", "mouse", "remote", "keyboard", "cell phone", "microwave",
|
35 |
+
"oven", "toaster", "sink", "refrigerator", "book", "clock", "vase",
|
36 |
+
"scissors", "teddy bear", "hair drier", "toothbrush"
|
37 |
+
};
|
38 |
+
|
39 |
+
using namespace Aidlux::Aidlite;
|
40 |
+
|
41 |
+
struct Args {
|
42 |
+
std::string target_model = "../../models/cutoff_yolov8s_w8a8.qnn216.ctx.bin.aidem";
|
43 |
+
std::string imgs = "../bus.jpg";
|
44 |
+
int invoke_nums = 10;
|
45 |
+
std::string model_type = "QNN";
|
46 |
+
};
|
47 |
+
|
48 |
+
Args parse_args(int argc, char* argv[]) {
|
49 |
+
Args args;
|
50 |
+
for (int i = 1; i < argc; ++i) {
|
51 |
+
std::string arg = argv[i];
|
52 |
+
if (arg == "--target_model" && i + 1 < argc) {
|
53 |
+
args.target_model = argv[++i];
|
54 |
+
} else if (arg == "--imgs" && i + 1 < argc) {
|
55 |
+
args.imgs = argv[++i];
|
56 |
+
} else if (arg == "--invoke_nums" && i + 1 < argc) {
|
57 |
+
args.invoke_nums = std::stoi(argv[++i]);
|
58 |
+
} else if (arg == "--model_type" && i + 1 < argc) {
|
59 |
+
args.model_type = argv[++i];
|
60 |
+
}
|
61 |
+
}
|
62 |
+
return args;
|
63 |
+
}
|
64 |
+
|
65 |
+
std::string to_lower(const std::string& str) {
|
66 |
+
std::string lower_str = str;
|
67 |
+
std::transform(lower_str.begin(), lower_str.end(), lower_str.begin(), [](unsigned char c) {
|
68 |
+
return std::tolower(c);
|
69 |
+
});
|
70 |
+
return lower_str;
|
71 |
+
}
|
72 |
+
|
73 |
+
|
74 |
+
void concatenate(float* qnn_trans_data, float* qnn_mul_data, int batch, int num_elements, int trans_dim, int mul_dim, std::vector<float>& output) {
|
75 |
+
int out_dim = trans_dim + mul_dim + 1;
|
76 |
+
output.resize(batch * num_elements * out_dim);
|
77 |
+
for (int i = 0; i < batch * num_elements; ++i) {
|
78 |
+
std::memcpy(&output[i * out_dim], &qnn_mul_data[i * mul_dim], mul_dim * sizeof(float));
|
79 |
+
float max_val = *std::max_element(&qnn_trans_data[i * trans_dim], &qnn_trans_data[i * trans_dim + trans_dim]);
|
80 |
+
output[i * out_dim + 4] = max_val;
|
81 |
+
std::memcpy(&output[i * out_dim + 5], &qnn_trans_data[i * trans_dim], trans_dim * sizeof(float));
|
82 |
+
}
|
83 |
+
}
|
84 |
+
|
85 |
+
void transformData(const float* input, float* output, int C, int N) {
|
86 |
+
for (int c = 0; c < C; ++c) {
|
87 |
+
for (int n = 0; n < N; ++n) {
|
88 |
+
output[n * C + c] = input[c * N + n];
|
89 |
+
}
|
90 |
+
}
|
91 |
+
}
|
92 |
+
|
93 |
+
double img_process(cv::Mat frame, cv::Mat &img_input, int size) {
|
94 |
+
cv::Mat img_processed = frame.clone();
|
95 |
+
int height = img_processed.rows;
|
96 |
+
int width = img_processed.cols;
|
97 |
+
int length = std::max(height, width);
|
98 |
+
double scala = static_cast<double>(length) / size;
|
99 |
+
|
100 |
+
cv::Mat image = cv::Mat::zeros(cv::Size(length, length), CV_8UC3);
|
101 |
+
img_processed.copyTo(image(cv::Rect(0, 0, width, height)));
|
102 |
+
|
103 |
+
cv::cvtColor(image, img_input, cv::COLOR_BGR2RGB);
|
104 |
+
cv::resize(img_input, img_input, cv::Size(size, size));
|
105 |
+
|
106 |
+
cv::Mat mean_data = cv::Mat::zeros(img_input.size(), CV_32FC3);
|
107 |
+
cv::Mat std_data(img_input.size(), CV_32FC3, cv::Scalar(255, 255, 255));
|
108 |
+
img_input.convertTo(img_input, CV_32FC3);
|
109 |
+
img_input = (img_input - mean_data) / std_data;
|
110 |
+
return scala;
|
111 |
+
}
|
112 |
+
|
113 |
+
|
114 |
+
cv::Scalar generate_colors(int i, bool bgr = false) {
|
115 |
+
static const std::vector<std::string> hex_colors = {
|
116 |
+
"FF3838", "FF9D97", "FF701F", "FFB21D", "CFD231", "48F90A",
|
117 |
+
"92CC17", "3DDB86", "1A9334", "00D4BB", "2C99A8", "00C2FF",
|
118 |
+
"344593", "6473FF", "0018EC", "8438FF", "520085", "CB38FF",
|
119 |
+
"FF95C8", "FF37C7"
|
120 |
+
};
|
121 |
+
|
122 |
+
int num = hex_colors.size();
|
123 |
+
std::string hex = hex_colors[i % num];
|
124 |
+
|
125 |
+
int r = std::stoi(hex.substr(0, 2), nullptr, 16);
|
126 |
+
int g = std::stoi(hex.substr(2, 2), nullptr, 16);
|
127 |
+
int b = std::stoi(hex.substr(4, 2), nullptr, 16);
|
128 |
+
|
129 |
+
if (bgr)
|
130 |
+
return cv::Scalar(b, g, r);
|
131 |
+
else
|
132 |
+
return cv::Scalar(r, g, b);
|
133 |
+
}
|
134 |
+
|
135 |
+
void draw_label(cv::Mat& input_image, std::string label, int left, int top, cv::Scalar color)
|
136 |
+
{
|
137 |
+
int baseLine;
|
138 |
+
cv::Size label_size = cv::getTextSize(label, FONT_FACE, FONT_SCALE, THICKNESS, &baseLine);
|
139 |
+
int y = top - label_size.height - baseLine;
|
140 |
+
if (y < 0) {
|
141 |
+
y = top ;
|
142 |
+
}
|
143 |
+
cv::Point tlc(left, y);
|
144 |
+
cv::Point brc(left + label_size.width, y + label_size.height + baseLine);
|
145 |
+
rectangle(input_image, tlc, brc, color, cv::FILLED);
|
146 |
+
putText(input_image, label, cv::Point(left, y + label_size.height), FONT_FACE, FONT_SCALE, WHITE, THICKNESS);
|
147 |
+
}
|
148 |
+
|
149 |
+
|
150 |
+
cv::Mat post_process(cv::Mat &input_image, std::vector<float> &outputs, const std::vector<std::string> &class_name, const double ratio)
|
151 |
+
{
|
152 |
+
// Initialize vectors to hold respective outputs while unwrapping detections.
|
153 |
+
std::vector<int> class_ids;
|
154 |
+
std::vector<float> confidences;
|
155 |
+
std::vector<cv::Rect> boxes;
|
156 |
+
|
157 |
+
// Iterate through outputs for each box prediction
|
158 |
+
for (int i = 0; i < outputs.size(); i+=85)
|
159 |
+
{
|
160 |
+
float confidence = outputs[i+4];
|
161 |
+
if (confidence >= CONFIDENCE_THRESHOLD)
|
162 |
+
{
|
163 |
+
// Create a 1x80 Mat and store class scores of 80 classes.
|
164 |
+
cv::Mat scores(1, class_name.size(), CV_32FC1, outputs.data() + i + 5);
|
165 |
+
cv::Point class_id;
|
166 |
+
double max_class_score;
|
167 |
+
|
168 |
+
// For multi-label, check each class score
|
169 |
+
for (int c = 0; c < class_name.size(); c++) {
|
170 |
+
float class_score = scores.at<float>(0, c);
|
171 |
+
|
172 |
+
// If class score is above threshold, consider this class for the box
|
173 |
+
if (class_score > SCORE_THRESHOLD) {
|
174 |
+
// Store class ID and confidence in the pre-defined respective vectors.
|
175 |
+
confidences.push_back(confidence * class_score); // Multiply with confidence
|
176 |
+
class_ids.push_back(c); // class index
|
177 |
+
// Center and box dimension.
|
178 |
+
float cx = outputs[i];
|
179 |
+
float cy = outputs[i+1];
|
180 |
+
float w = outputs[i+2];
|
181 |
+
float h = outputs[i+3];
|
182 |
+
|
183 |
+
int left = int((cx - 0.5 * w) * ratio);
|
184 |
+
int top = int((cy - 0.5 * h) * ratio);
|
185 |
+
int width = int(w * ratio);
|
186 |
+
int height = int(h * ratio);
|
187 |
+
|
188 |
+
// Store good detections in the boxes vector.
|
189 |
+
boxes.push_back(cv::Rect(left, top, width, height));
|
190 |
+
}
|
191 |
+
}
|
192 |
+
}
|
193 |
+
}
|
194 |
+
|
195 |
+
// Perform Non Maximum Suppression and draw predictions.
|
196 |
+
std::vector<int> indices;
|
197 |
+
cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, indices);
|
198 |
+
printf("Detected {%ld} targets.\n", indices.size());
|
199 |
+
|
200 |
+
// Loop over NMS results and draw bounding boxes
|
201 |
+
for (int i = 0; i < indices.size(); i++)
|
202 |
+
{
|
203 |
+
int idx = indices[i];
|
204 |
+
cv::Rect box = boxes[idx];
|
205 |
+
|
206 |
+
int left = box.x;
|
207 |
+
int top = box.y;
|
208 |
+
int width = box.width;
|
209 |
+
int height = box.height;
|
210 |
+
cv::Scalar color = generate_colors(class_ids[idx]);
|
211 |
+
// Draw bounding box.
|
212 |
+
rectangle(input_image, cv::Point(left, top), cv::Point(left + width, top + height), color, 2*THICKNESS);
|
213 |
+
|
214 |
+
// Get the label for the class name and its confidence.
|
215 |
+
std::string label = cv::format("%.2f", confidences[idx]);
|
216 |
+
label = class_name[class_ids[idx]] + ":" + label;
|
217 |
+
// Draw class labels.
|
218 |
+
draw_label(input_image, label, left, top, color);
|
219 |
+
}
|
220 |
+
printf("Processing finished.\n");
|
221 |
+
return input_image;
|
222 |
+
}
|
223 |
+
|
224 |
+
int invoke(const Args& args) {
|
225 |
+
std::cout << "Start main ... ... Model Path: " << args.target_model << "\n"
|
226 |
+
<< "Image Path: " << args.imgs << "\n"
|
227 |
+
<< "Inference Nums: " << args.invoke_nums << "\n"
|
228 |
+
<< "Model Type: " << args.model_type << "\n";
|
229 |
+
Model* model = Model::create_instance(args.target_model);
|
230 |
+
if(model == nullptr){
|
231 |
+
printf("Create model failed !\n");
|
232 |
+
return EXIT_FAILURE;
|
233 |
+
}
|
234 |
+
Config* config = Config::create_instance();
|
235 |
+
if(config == nullptr){
|
236 |
+
printf("Create config failed !\n");
|
237 |
+
return EXIT_FAILURE;
|
238 |
+
}
|
239 |
+
config->implement_type = ImplementType::TYPE_LOCAL;
|
240 |
+
std::string model_type_lower = to_lower(args.model_type);
|
241 |
+
if (model_type_lower == "qnn"){
|
242 |
+
config->framework_type = FrameworkType::TYPE_QNN;
|
243 |
+
} else if (model_type_lower == "snpe2" || model_type_lower == "snpe") {
|
244 |
+
config->framework_type = FrameworkType::TYPE_SNPE2;
|
245 |
+
}
|
246 |
+
config->accelerate_type = AccelerateType::TYPE_DSP;
|
247 |
+
config->is_quantify_model = 1;
|
248 |
+
|
249 |
+
std::vector<std::vector<uint32_t>> input_shapes = {{1, size, size, 3}};
|
250 |
+
std::vector<std::vector<uint32_t>> output_shapes = {{1, 4, out_size}, {1, 80, out_size}};
|
251 |
+
model->set_model_properties(input_shapes, DataType::TYPE_FLOAT32, output_shapes, DataType::TYPE_FLOAT32);
|
252 |
+
std::unique_ptr<Interpreter> fast_interpreter = InterpreterBuilder::build_interpretper_from_model_and_config(model, config);
|
253 |
+
if(fast_interpreter == nullptr){
|
254 |
+
printf("build_interpretper_from_model_and_config failed !\n");
|
255 |
+
return EXIT_FAILURE;
|
256 |
+
}
|
257 |
+
int result = fast_interpreter->init();
|
258 |
+
if(result != EXIT_SUCCESS){
|
259 |
+
printf("interpreter->init() failed !\n");
|
260 |
+
return EXIT_FAILURE;
|
261 |
+
}
|
262 |
+
// load model
|
263 |
+
fast_interpreter->load_model();
|
264 |
+
if(result != EXIT_SUCCESS){
|
265 |
+
printf("interpreter->load_model() failed !\n");
|
266 |
+
return EXIT_FAILURE;
|
267 |
+
}
|
268 |
+
printf("detect model load success!\n");
|
269 |
+
|
270 |
+
cv::Mat frame = cv::imread(args.imgs);
|
271 |
+
if (frame.empty()) {
|
272 |
+
printf("detect image load failed!\n");
|
273 |
+
return 1;
|
274 |
+
}
|
275 |
+
printf("img_src cols: %d, img_src rows: %d\n", frame.cols, frame.rows);
|
276 |
+
cv::Mat input_img;
|
277 |
+
double scale = img_process(frame, input_img, size);
|
278 |
+
if (input_img.empty()) {
|
279 |
+
printf("detect input_img load failed!\n");
|
280 |
+
return 1;
|
281 |
+
}
|
282 |
+
|
283 |
+
float *qnn_trans_data = nullptr;
|
284 |
+
float *qnn_mul_data = nullptr;
|
285 |
+
|
286 |
+
std::vector<float> invoke_time;
|
287 |
+
for (int i = 0; i < args.invoke_nums; ++i) {
|
288 |
+
result = fast_interpreter->set_input_tensor(0, input_img.data);
|
289 |
+
if(result != EXIT_SUCCESS){
|
290 |
+
printf("interpreter->set_input_tensor() failed !\n");
|
291 |
+
return EXIT_FAILURE;
|
292 |
+
}
|
293 |
+
// 开始计时
|
294 |
+
auto t1 = std::chrono::high_resolution_clock::now();
|
295 |
+
result = fast_interpreter->invoke();
|
296 |
+
auto t2 = std::chrono::high_resolution_clock::now();
|
297 |
+
std::chrono::duration<double> cost_time = t2 - t1;
|
298 |
+
invoke_time.push_back(cost_time.count() * 1000);
|
299 |
+
if(result != EXIT_SUCCESS){
|
300 |
+
printf("interpreter->invoke() failed !\n");
|
301 |
+
return EXIT_FAILURE;
|
302 |
+
}
|
303 |
+
uint32_t out_data_1 = 0;
|
304 |
+
result = fast_interpreter->get_output_tensor(0, (void**)&qnn_trans_data, &out_data_1);
|
305 |
+
if(result != EXIT_SUCCESS){
|
306 |
+
printf("interpreter->get_output_tensor() 1 failed !\n");
|
307 |
+
return EXIT_FAILURE;
|
308 |
+
}
|
309 |
+
uint32_t out_data_2 = 0;
|
310 |
+
result = fast_interpreter->get_output_tensor(1, (void**)&qnn_mul_data, &out_data_2);
|
311 |
+
if(result != EXIT_SUCCESS){
|
312 |
+
printf("interpreter->get_output_tensor() 2 failed !\n");
|
313 |
+
return EXIT_FAILURE;
|
314 |
+
}
|
315 |
+
}
|
316 |
+
|
317 |
+
float max_invoke_time = *std::max_element(invoke_time.begin(), invoke_time.end());
|
318 |
+
float min_invoke_time = *std::min_element(invoke_time.begin(), invoke_time.end());
|
319 |
+
float mean_invoke_time = std::accumulate(invoke_time.begin(), invoke_time.end(), 0.0f) / args.invoke_nums;
|
320 |
+
float var_invoketime = 0.0f;
|
321 |
+
for (auto time : invoke_time) {
|
322 |
+
var_invoketime += (time - mean_invoke_time) * (time - mean_invoke_time);
|
323 |
+
}
|
324 |
+
var_invoketime /= args.invoke_nums;
|
325 |
+
printf("=======================================\n");
|
326 |
+
printf("QNN inference %d times :\n --mean_invoke_time is %f \n --max_invoke_time is %f \n --min_invoke_time is %f \n --var_invoketime is %f\n",
|
327 |
+
args.invoke_nums, mean_invoke_time, max_invoke_time, min_invoke_time, var_invoketime);
|
328 |
+
printf("=======================================\n");
|
329 |
+
|
330 |
+
// std::vector<std::vector<uint32_t>> output_shapes = {{1, 4, out_size}, {1, 80, out_size}};
|
331 |
+
float* pos_data = new float[4 * out_size];
|
332 |
+
float* class_data = new float[80 * out_size];
|
333 |
+
transformData(qnn_trans_data, pos_data, 4, out_size);
|
334 |
+
transformData(qnn_mul_data, class_data, 80, out_size);
|
335 |
+
|
336 |
+
// post process
|
337 |
+
std::vector<float> qnn_concat;
|
338 |
+
concatenate(class_data, pos_data , 1, out_size, 80, 4, qnn_concat);
|
339 |
+
cv::Mat img = post_process(frame, qnn_concat, class_list, scale);
|
340 |
+
cv::imwrite("./results.png", img);
|
341 |
+
fast_interpreter->destory();
|
342 |
+
return 0;
|
343 |
+
}
|
344 |
+
|
345 |
+
|
346 |
+
int main(int argc, char* argv[]) {
|
347 |
+
Args args = parse_args(argc, argv);
|
348 |
+
return invoke(args);
|
349 |
+
}
|
model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/models/cutoff_yolov8s_w8a8.qnn216.ctx.bin
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:25255e85b913a3d079c9a975049b192ae05b77232cb78c0b5077f339c38129e6
|
3 |
+
size 11690008
|
model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/python/bus.jpg
ADDED
![]() |
Git LFS Details
|
model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/python/run_test.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import cv2
|
2 |
+
import argparse
|
3 |
+
from yolov8s import Yolov8S
|
4 |
+
from utils import draw_detect_res
|
5 |
+
|
6 |
+
def parser_args():
|
7 |
+
parser = argparse.ArgumentParser(description="Run model benchmarks")
|
8 |
+
parser.add_argument('--target_model',type=str,default='./models/cutoff_yolov8s_w8a8.qnn231.ctx.bin.aidem',help="inference model path")
|
9 |
+
parser.add_argument('--imgs',type=str,default='./python/bus.jpg',help="Predict images path")
|
10 |
+
parser.add_argument('--height',type=int,default=640,help="run backend")
|
11 |
+
parser.add_argument('--weight',type=int,default=640,help="run backend")
|
12 |
+
parser.add_argument('--cls_num',type=int,default=80,help="run backend")
|
13 |
+
parser.add_argument('--invoke_nums',type=int,default=10,help="Inference nums")
|
14 |
+
parser.add_argument('--model_type',type=str,default='QNN',help="run backend")
|
15 |
+
args = parser.parse_args()
|
16 |
+
return args
|
17 |
+
|
18 |
+
if __name__ == "__main__":
|
19 |
+
args = parser_args()
|
20 |
+
height = args.height
|
21 |
+
weight = args.weight
|
22 |
+
|
23 |
+
|
24 |
+
model = Yolov8S(args.target_model, args.weight, args.height, args.cls_num)
|
25 |
+
frame = cv2.imread(args.imgs)
|
26 |
+
|
27 |
+
out_boxes= model(frame, args.invoke_nums)
|
28 |
+
print(f"=================== \n Detect {len(out_boxes)} targets.")
|
29 |
+
result = draw_detect_res(frame, out_boxes)
|
30 |
+
cv2.imwrite("./python/result.jpg", result)
|
model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/python/utils.py
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
|
4 |
+
CLASSES = ("person", "bicycle", "car", "motorbike ", "aeroplane ", "bus ", "train", "truck ", "boat", "traffic light",
|
5 |
+
"fire hydrant", "stop sign ", "parking meter", "bench", "bird", "cat", "dog ", "horse ", "sheep", "cow", "elephant",
|
6 |
+
"bear", "zebra ", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball", "kite",
|
7 |
+
"baseball bat", "baseball glove", "skateboard", "surfboard", "tennis racket", "bottle", "wine glass", "cup", "fork", "knife ",
|
8 |
+
"spoon", "bowl", "banana", "apple", "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza ", "donut", "cake", "chair", "sofa",
|
9 |
+
"pottedplant", "bed", "diningtable", "toilet ", "tvmonitor", "laptop ", "mouse ", "remote ", "keyboard ", "cell phone", "microwave ",
|
10 |
+
"oven ", "toaster", "sink", "refrigerator ", "book", "clock", "vase", "scissors ", "teddy bear ", "hair drier", "toothbrush ")
|
11 |
+
|
12 |
+
def eqprocess(image, size1, size2):
|
13 |
+
h,w,_ = image.shape
|
14 |
+
mask = np.zeros((size1,size2,3),dtype=np.float32)
|
15 |
+
scale1 = h /size1
|
16 |
+
scale2 = w / size2
|
17 |
+
if scale1 > scale2:
|
18 |
+
scale = scale1
|
19 |
+
else:
|
20 |
+
scale = scale2
|
21 |
+
img = cv2.resize(image,(int(w / scale),int(h / scale)))
|
22 |
+
mask[:int(h / scale),:int(w / scale),:] = img
|
23 |
+
return mask, scale
|
24 |
+
|
25 |
+
def xywh2xyxy(x):
|
26 |
+
'''
|
27 |
+
Box (center x, center y, width, height) to (x1, y1, x2, y2)
|
28 |
+
'''
|
29 |
+
y = np.copy(x)
|
30 |
+
y[:, 0] = x[:, 0] - x[:, 2] / 2 # top left x
|
31 |
+
y[:, 1] = x[:, 1] - x[:, 3] / 2 # top left y
|
32 |
+
y[:, 2] = x[:, 0] + x[:, 2] / 2 # bottom right x
|
33 |
+
y[:, 3] = x[:, 1] + x[:, 3] / 2 # bottom right y
|
34 |
+
return y
|
35 |
+
|
36 |
+
def xyxy2xywh(box):
|
37 |
+
'''
|
38 |
+
Box (left_top x, left_top y, right_bottom x, right_bottom y) to (left_top x, left_top y, width, height)
|
39 |
+
'''
|
40 |
+
box[:, 2:] = box[:, 2:] - box[:, :2]
|
41 |
+
return box
|
42 |
+
|
43 |
+
def NMS(dets, scores, thresh):
|
44 |
+
'''
|
45 |
+
单类NMS算法
|
46 |
+
dets.shape = (N, 5), (left_top x, left_top y, right_bottom x, right_bottom y, Scores)
|
47 |
+
'''
|
48 |
+
x1 = dets[:,0]
|
49 |
+
y1 = dets[:,1]
|
50 |
+
x2 = dets[:,2]
|
51 |
+
y2 = dets[:,3]
|
52 |
+
areas = (y2-y1+1) * (x2-x1+1)
|
53 |
+
keep = []
|
54 |
+
index = scores.argsort()[::-1]
|
55 |
+
while index.size >0:
|
56 |
+
i = index[0] # every time the first is the biggst, and add it directly
|
57 |
+
keep.append(i)
|
58 |
+
x11 = np.maximum(x1[i], x1[index[1:]]) # calculate the points of overlap
|
59 |
+
y11 = np.maximum(y1[i], y1[index[1:]])
|
60 |
+
x22 = np.minimum(x2[i], x2[index[1:]])
|
61 |
+
y22 = np.minimum(y2[i], y2[index[1:]])
|
62 |
+
w = np.maximum(0, x22-x11+1) # the weights of overlap
|
63 |
+
h = np.maximum(0, y22-y11+1) # the height of overlap
|
64 |
+
overlaps = w*h
|
65 |
+
ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
|
66 |
+
idx = np.where(ious<=thresh)[0]
|
67 |
+
index = index[idx+1] # because index start from 1
|
68 |
+
|
69 |
+
return keep
|
70 |
+
|
71 |
+
|
72 |
+
def draw_detect_res(img, det_pred):
|
73 |
+
'''
|
74 |
+
检测结果绘制
|
75 |
+
'''
|
76 |
+
if det_pred is None:
|
77 |
+
return img
|
78 |
+
|
79 |
+
img = img.astype(np.uint8)
|
80 |
+
im_canvas = img.copy()
|
81 |
+
color_step = int(255/len(CLASSES))
|
82 |
+
for i in range(len(det_pred)):
|
83 |
+
x1, y1, x2, y2 = [int(t) for t in det_pred[i][:4]]
|
84 |
+
cls_id = int(det_pred[i][5])
|
85 |
+
print(i+1,[x1,y1,x2,y2],det_pred[i][4], f'{CLASSES[cls_id]}')
|
86 |
+
cv2.putText(img, f'{CLASSES[cls_id]}', (x1, y1-6), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1)
|
87 |
+
cv2.rectangle(img, (x1, y1), (x2, y2), (0, int(cls_id*color_step), int(255-cls_id*color_step)),thickness = 2)
|
88 |
+
img = cv2.addWeighted(im_canvas, 0.3, img, 0.7, 0)
|
89 |
+
return img
|
90 |
+
|
91 |
+
def scale_mask(masks, im0_shape):
|
92 |
+
masks = cv2.resize(masks, (im0_shape[1], im0_shape[0]),
|
93 |
+
interpolation=cv2.INTER_LINEAR)
|
94 |
+
if len(masks.shape) == 2:
|
95 |
+
masks = masks[:, :, None]
|
96 |
+
return masks
|
97 |
+
|
98 |
+
def crop_mask(masks, boxes):
|
99 |
+
n, h, w = masks.shape
|
100 |
+
x1, y1, x2, y2 = np.split(boxes[:, :, None], 4, 1)
|
101 |
+
r = np.arange(w, dtype=x1.dtype)[None, None, :]
|
102 |
+
c = np.arange(h, dtype=x1.dtype)[None, :, None]
|
103 |
+
return masks * ((r >= x1) * (r < x2) * (c >= y1) * (c < y2))
|
104 |
+
|
105 |
+
def process_mask(protos, masks_in, bboxes, im0_shape):
|
106 |
+
c, mh, mw = protos.shape
|
107 |
+
masks = np.matmul(masks_in, protos.reshape((c, -1))).reshape((-1, mh, mw)).transpose(1, 2, 0) # HWN
|
108 |
+
masks = np.ascontiguousarray(masks)
|
109 |
+
masks = scale_mask(masks, im0_shape) # re-scale mask from P3 shape to original input image shape
|
110 |
+
masks = np.einsum('HWN -> NHW', masks) # HWN -> NHW
|
111 |
+
masks = crop_mask(masks, bboxes)
|
112 |
+
return np.greater(masks, 0.5)
|
113 |
+
|
114 |
+
def masks2segments(masks):
|
115 |
+
segments = []
|
116 |
+
for x in masks.astype('uint8'):
|
117 |
+
c = cv2.findContours(x, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[0] # CHAIN_APPROX_SIMPLE
|
118 |
+
if c:
|
119 |
+
c = np.array(c[np.array([len(x) for x in c]).argmax()]).reshape(-1, 2)
|
120 |
+
else:
|
121 |
+
c = np.zeros((0, 2)) # no segments found
|
122 |
+
segments.append(c.astype('float32'))
|
123 |
+
return segments
|
model_farm_yolov8s_qcs8550_qnn2.16_int8_aidlite/python/yolov8s.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2
|
3 |
+
import aidlite
|
4 |
+
from utils import eqprocess, xywh2xyxy, NMS
|
5 |
+
import time
|
6 |
+
|
7 |
+
OBJ_THRESH = 0.45
|
8 |
+
NMS_THRESH = 0.45
|
9 |
+
|
10 |
+
class Yolov8S(object):
|
11 |
+
def __init__(self, model_path, width, height, class_num):
|
12 |
+
self.class_num = class_num
|
13 |
+
self.width = width
|
14 |
+
self.height = height
|
15 |
+
input_shape = [[1,height,width,3]]
|
16 |
+
self.blocks = int(height * width * ( 1 / 64 + 1 / 256 + 1 / 1024))
|
17 |
+
self.maskw = int(width / 4)
|
18 |
+
self.maskh = int(height / 4)
|
19 |
+
self.output_shape = [[1,4,self.blocks],[1,class_num,self.blocks]]
|
20 |
+
|
21 |
+
self.model = aidlite.Model.create_instance(model_path)
|
22 |
+
if self.model is None:
|
23 |
+
print("Create model failed !")
|
24 |
+
return
|
25 |
+
self.model.set_model_properties(input_shape, aidlite.DataType.TYPE_FLOAT32, self.output_shape, aidlite.DataType.TYPE_FLOAT32)
|
26 |
+
|
27 |
+
self.config = aidlite.Config.create_instance()
|
28 |
+
if self.config is None:
|
29 |
+
print("build_interpretper_from_model_and_config failed !")
|
30 |
+
return
|
31 |
+
|
32 |
+
self.config.framework_type = aidlite.FrameworkType.TYPE_QNN216
|
33 |
+
self.config.accelerate_type = aidlite.AccelerateType.TYPE_DSP
|
34 |
+
self.config.is_quantify_model = 1
|
35 |
+
|
36 |
+
self.interpreter = aidlite.InterpreterBuilder.build_interpretper_from_model_and_config(self.model, self.config)
|
37 |
+
if self.interpreter is None:
|
38 |
+
print("build_interpretper_from_model_and_config failed !")
|
39 |
+
return
|
40 |
+
|
41 |
+
self.interpreter.init()
|
42 |
+
self.interpreter.load_model()
|
43 |
+
|
44 |
+
def __call__(self, frame,invoke_nums):
|
45 |
+
img, scale = eqprocess(frame, self.height, self.width)
|
46 |
+
img = img / 255
|
47 |
+
img = img.astype(np.float32)
|
48 |
+
self.interpreter.set_input_tensor(0,img.data)
|
49 |
+
|
50 |
+
invoke_time=[]
|
51 |
+
for i in range(invoke_nums):
|
52 |
+
t1=time.time()
|
53 |
+
self.interpreter.invoke()
|
54 |
+
cost_time = (time.time()-t1)*1000
|
55 |
+
invoke_time.append(cost_time)
|
56 |
+
|
57 |
+
max_invoke_time = max(invoke_time)
|
58 |
+
min_invoke_time = min(invoke_time)
|
59 |
+
mean_invoke_time = sum(invoke_time)/invoke_nums
|
60 |
+
var_invoketime=np.var(invoke_time)
|
61 |
+
print("====================================")
|
62 |
+
print(f"QNN invoke {invoke_nums} times:\n --mean_invoke_time is {mean_invoke_time} \n --max_invoke_time is {max_invoke_time} \n --min_invoke_time is {min_invoke_time} \n --var_invoketime is {var_invoketime}")
|
63 |
+
print("====================================")
|
64 |
+
|
65 |
+
qnn_1 = self.interpreter.get_output_tensor(0)
|
66 |
+
qnn_2 = self.interpreter.get_output_tensor(1)
|
67 |
+
qnn_out = sorted([qnn_1,qnn_2], key=len)
|
68 |
+
|
69 |
+
qnn_local = qnn_out[0].reshape(*self.output_shape[0])
|
70 |
+
qnn_conf = qnn_out[1].reshape(*self.output_shape[1])
|
71 |
+
|
72 |
+
|
73 |
+
x = np.concatenate([qnn_local, qnn_conf], axis = 1).transpose(0,2,1)
|
74 |
+
x = x[np.amax(x[..., 4:], axis=-1) > OBJ_THRESH]
|
75 |
+
if len(x) < 1:
|
76 |
+
return None, None
|
77 |
+
|
78 |
+
x = np.c_[x[..., :4], np.amax(x[..., 4:], axis=-1), np.argmax(x[..., 4:], axis=-1)]
|
79 |
+
|
80 |
+
x[:, :4] = xywh2xyxy(x[:, :4])
|
81 |
+
index = NMS(x[:, :4], x[:, 4], NMS_THRESH)
|
82 |
+
out_boxes = x[index]
|
83 |
+
out_boxes[..., :4] = out_boxes[..., :4] * scale
|
84 |
+
|
85 |
+
return out_boxes
|
86 |
+
|