最近一些人問我怎么在BPU上部署yolov5,因?yàn)橹暗牟┛蚚BPU部署教程] 一文帶你輕松走出模型部署新手村介紹的網(wǎng)絡(luò)都是基于Caffe的,自己的網(wǎng)絡(luò)都是基于pytorch的,所以遇到了很多坑。鑒于這些需求,我自己研究了下部署的方式,把自己的過程整理下來供各位參考(看我這么好的份上,來個(gè)三連吧o( ̄▽ ̄)ブ)。

在部署之前,我先說明幾點(diǎn):
- 本教程使用的一些文件都放在百度云(提取碼:0a09 )里了,可以自行下載使用
- yolov5的代碼我用的是https://github.com/ultralytics/yolov5的master分支,目前應(yīng)該是版本6.2,后續(xù)作者更新后,可以切換到6.2分支來使用。
- 盡管本教程轉(zhuǎn)換模型用的是官方模型,但各位可以訓(xùn)練自己的模型來轉(zhuǎn)換,模型轉(zhuǎn)換幾乎沒有啥差異,可放心食用。
- 代碼版本我應(yīng)該和官方使用的不一樣,X3P給的官方測(cè)試時(shí)間是45ms左右,但我轉(zhuǎn)換模型時(shí)候,發(fā)現(xiàn)有較多的層跑在CPU,導(dǎo)致推理時(shí)間多很多。
- 很多人說了后處理過程耗時(shí)太高,后處理計(jì)算在python跑的話,確實(shí)速度會(huì)慢很多,所以我以這個(gè),順便教各位如何利用cython來包裝自己的C++代碼來加速,最后測(cè)試時(shí)候,python版的后處理耗時(shí)越450ms,用cython包裝后,后處理僅用9ms。
下面,開始我們的部署之旅。

一 環(huán)境配置
1.1 安裝依賴包
如果在當(dāng)前python環(huán)境下能利用pip install onnx
輕松安裝onnx,那就直接配置yolov5的環(huán)境就行了。
我電腦是windows,又不想安裝虛擬機(jī),所以環(huán)境的安裝有一些限制。我最開始的python環(huán)境是3.6版本,結(jié)果安裝onnx時(shí)候一堆問題。3.10有onnx的whl包,所以,建議跑模型的python環(huán)境為3.10(3.8好像也可,自己試試)。
下面給出我部署的指令流程,對(duì)于的pytorch包我也放在百度云了。
# 在指定路徑下創(chuàng)建虛擬環(huán)境,我的anaconda安裝在c盤,但我想把環(huán)境放在d盤,所以利用--prefix D:\Anaconda3\envs\yolov5指定路徑
conda create --prefix D:\Anaconda3\envs\yolov5 python=3.10
# 切換虛擬環(huán)境
conda activate D:\Anaconda3\envs\yolov5
# 安裝關(guān)鍵包ONNX
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple onnx
# 安裝yolov5依賴的pytorch
pip install "torch-1.11.0+cu113-cp310-cp310-win_amd64.whl" "torchaudio-0.11.0+cu113-cp310-cp310-win_amd64.whl" "torchvision-0.12.0+cu113-cp310-cp310-win_amd64.whl" -i https://pypi.tuna.tsinghua.edu.cn/simple
# 安裝yolov5需要的包
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple matplotlib>=3.2.2 numpy>=1.18.5 opencv-python>=4.1.1 Pillow>=7.1.2 PyYAML>=5.3.1 requests>=2.23.0 scipy>=1.4.1 tqdm>=4.64.0 tensorboard>=2.4.1 pandas>=1.1.4 seaborn>=0.11.0 ipython psutil thop>=0.1.1
1.2 運(yùn)行YoloV5
下載百度云中提供的文件,按照如下流程操作:
- 解壓
yolov5-master.zip
。 - 將
zidane.jpg
放到yolov5-master
文件夾中。 - 將
yolov5s.pt
放到yolov5-master/models
文件夾中。 - 進(jìn)入
yolov5-master
文件夾,輸入python .\detect.py --weights .\models\yolov5s.pt --source zidane.jpg
,代碼會(huì)輸出檢測(cè)結(jié)果保存路徑,比如我的就是Results saved to runs\detect\exp9
,檢測(cè)結(jié)果如下所示。
1.3 pytorch的pt模型文件轉(zhuǎn)onnx
轉(zhuǎn)換的時(shí)候,一定要清楚一點(diǎn),BPU的工具鏈沒有支持onnx的所有版本的算子,即當(dāng)前BPU支持onnx的opset版本為10和11。錯(cuò)誤的opset
在模型檢查階段就無法通過,在后面我給各位展示轉(zhuǎn)換失敗的結(jié)果。
# 錯(cuò)誤的轉(zhuǎn)換指令
python .\export.py --weights .\models\yolov5s.pt --include onnx
# 正確的轉(zhuǎn)換指令
python .\export.py --weights .\models\yolov5s.pt --include onnx --opset 11
轉(zhuǎn)換后,控制臺(tái)會(huì)輸出一些log信息,轉(zhuǎn)換后的模型文件在.\\models\\yolov5s.pt
。
export: data=D:\05 - \01 - x3\BPUCodes\yolov5\yolov5-master\data\coco128.yaml, weights=['.\\models\\yolov5s.pt'], imgsz=[640, 640], batch_size=1, device=cpu, half=False, inplace=False, train=False, keras=False, optimize=False, int8=False, dynamic=False, simplify=False, opset=12, verbose=False, workspace=4, nms=False, agnostic_nms=False, topk_per_class=100, topk_all=100, iou_thres=0.45, conf_thres=0.25, include=['onnx']
YOLOv5 2022-9-1 Python-3.10.4 torch-1.11.0+cu113 CPU
Fusing layers...
YOLOv5s summary: 213 layers, 7225885 parameters, 0 gradients
PyTorch: starting from models\yolov5s.pt with output shape (1, 25200, 85) (14.1 MB)
ONNX: starting export with onnx 1.12.0...
ONNX: export success 3.6s, saved as models\yolov5s.onnx (28.0 MB)
Export complete (4.2s)
Results saved to D:\05 - \01 - x3\BPUCodes\yolov5\yolov5-master\models
Detect: python detect.py --weights models\yolov5s.onnx
Validate: python val.py --weights models\yolov5s.onnx
PyTorch Hub: model = torch.hub.load('ultralytics/yolov5', 'custom', 'models\yolov5s.onnx')
Visualize: https://netron.app
二 ONNX模型轉(zhuǎn)換
模型轉(zhuǎn)換要在docker中轉(zhuǎn)換,怎么安裝docker,怎么進(jìn)入OE,怎么掛載硬盤,均在博客[BPU部署教程] 一文帶你輕松走出模型部署新手村中詳細(xì)介紹,任何細(xì)節(jié)不懂的,可以去這里面尋找。
新建一個(gè)文件夾,我這里叫bpucodes
,把前面轉(zhuǎn)好的yolov5s.onnx
放進(jìn)這個(gè)文件夾里,百度云里也提供了相關(guān)的代碼。
在docker中,進(jìn)入bpucodes
文件夾,開始我們的模型轉(zhuǎn)換。
2.1 模型檢查
模型檢測(cè)的目的是檢測(cè)有沒有不支持的算子,輸入指令hb_mapper checker --model-type onnx --march bernoulli2 --model yolov5s.onnx
,開始檢查模型,顯示如下內(nèi)容表示模型檢查通過。(我們可以發(fā)現(xiàn)網(wǎng)絡(luò)的后端部分存在一些層是運(yùn)行在CPU上的,這會(huì)導(dǎo)致耗時(shí)多一些)
前面提到了,在pt轉(zhuǎn)onnx時(shí),要–opset 11,而我最開始轉(zhuǎn)換的時(shí)候,是沒有指定的,下面說一下我是怎么找到問題的(這部分為題外話,想繼續(xù)下一步的話,直接跳2.2節(jié))
我最開始利用python .\export.py --weights .\models\yolov5s.pt --include onnx
來轉(zhuǎn)onnx,結(jié)果發(fā)現(xiàn)在BPU的OE工具鏈里,hb_mapper checker
檢查不通過,顯示如下錯(cuò)誤。
谷歌搜到了onnx支持的算子信息https://github.com/microsoft/onnxruntime/blob/main/docs/OperatorKernels.md
,在我這個(gè)docker里面,onnx庫的版本為1.7.0
,發(fā)現(xiàn)MaxPool實(shí)際上是支持的啊,為啥不通過,結(jié)果我發(fā)現(xiàn)后面的數(shù)字8,11,12
,才想起來這個(gè)是不是還要指定opset
呀。
然后,我在yolov5的export.py
文件里,發(fā)現(xiàn)opset默認(rèn)是12,難怪不通過,最后問了晟哥,得到支持的版本,最終在指令中增加--opset 11
,來生成onnx,這樣就通過了。
2.2 準(zhǔn)備校準(zhǔn)數(shù)據(jù)
校準(zhǔn)數(shù)據(jù)的代碼參考[BPU部署教程] 一文帶你輕松走出模型部署新手村中的yolov3的校準(zhǔn)代碼,整體沒有太多改變,主要修改了如下兩個(gè)地方(代碼我放百度云了,跟前面的博客內(nèi)容重復(fù)度太高)。
# 修改輸入圖像大小為640x640
img = imequalresize(img, (640, 640))
# 指定輸出的校準(zhǔn)圖像根目錄
dst_root = '/data/horizon_x3/codes/yolov5/bpucodes/calibration_data
輸入prepare_calibration_data.py
可以得到校準(zhǔn)數(shù)據(jù)
其實(shí)在上一節(jié)模型檢查過程中,log信息已經(jīng)輸出網(wǎng)絡(luò)輸入的圖像維度了,我也是直接用這個(gè)。
2.3 開始轉(zhuǎn)換BPU模型
轉(zhuǎn)換模型需要yaml參數(shù)文件,具體含義參考yolov3的教程,這里我直接放上我的convert_yolov5s.yaml
文件信息。
model_parameters:
onnx_model: 'yolov5s.onnx'
output_model_file_prefix: 'yolov5s'
march: 'bernoulli2'
input_parameters:
input_type_train: 'rgb'
input_layout_train: 'NCHW'
input_type_rt: 'nv12'
norm_type: 'data_scale'
scale_value: 0.003921568627451
input_layout_rt: 'NHWC'
calibration_parameters:
cal_data_dir: './calibration_data'
calibration_type: 'max'
max_percentile: 0.9999
compiler_parameters:
compile_mode: 'latency'
optimize_level: 'O3'
debug: False
core_num: 2 # x3p是雙核BPU,所以指定為2可以速度更快
輸入命令hb_mapper makertbin --config convert_yolov5s.yaml --model-type onnx
開始轉(zhuǎn)換我們的模型!校準(zhǔn)過后會(huì)輸出每一層的量化損失。
轉(zhuǎn)換成功后,得到model_output/yolov5s.bin
,這個(gè)文件拿出來,拷貝到旭日X3派上使用,它也是我們上板運(yùn)行所需要的模型文件。
三 上板運(yùn)行
有小伙伴說后處理部分耗時(shí)太高,所以我這里除了給出推理代碼,還教各位如何利用cython封裝c++來加速你的代碼。
3.1 文件準(zhǔn)備
下載百度云的文件,拷貝到旭日X3派開發(fā)板中,其中yolov5s.bin
就是我們轉(zhuǎn)換后的模型,coco_classes.names
僅用在畫框的時(shí)候,如果用自己的數(shù)據(jù)集的話,參考coco_classes.names
創(chuàng)建個(gè)新的名字文件即可。

輸入sudo apt-get install libopencv-dev
安裝opencv庫,之后進(jìn)入代碼根目錄,輸入python3 setup.py build_ext --inplace
,編譯后處理代碼,得到lib/pyyolotools.cpython-38-aarch64-linux-gnu.so
文件。
3.2 運(yùn)行推理代碼
模型推理的代碼如下所示,其中yolotools.pypostprocess_yolov5
為C++實(shí)現(xiàn)的后處理功能,推理代碼在我這里保存為inference_model_bpu.py
。
import numpy as np
import cv2
import os
from hobot_dnn import pyeasy_dnn as dnn
from bputools.format_convert import imequalresize, bgr2nv12_opencv
# lib.pyyolotools為封裝的庫
import lib.pyyolotools as yolotools
def get_hw(pro):
if pro.layout == "NCHW":
return pro.shape[2], pro.shape[3]
else:
return pro.shape[1], pro.shape[2]
def format_yolov5(frame):
row, col, _ = frame.shape
_max = max(col, row)
result = np.zeros((_max, _max, 3), np.uint8)
result[0:row, 0:col] = frame
return result
# img_path 圖像完整路徑
img_path = '20220904134315.jpg'
# model_path 量化模型完整路徑
model_path = 'yolov5s.bin'
# 類別名文件
classes_name_path = 'coco_classes.names'
# 設(shè)置參數(shù)
thre_confidence = 0.4
thre_score = 0.25
thre_nms = 0.45
# 框顏色設(shè)置
colors = [(255, 255, 0), (0, 255, 0), (0, 255, 255), (255, 0, 0)]
# 1. 加載模型,獲取所需輸出HW
models = dnn.load(model_path)
model_h, model_w = get_hw(models[0].inputs[0].properties)
print(model_h, model_w)
# 2 加載圖像,根據(jù)前面模型,轉(zhuǎn)換后的模型是以NV12作為輸入的
# 但在OE驗(yàn)證的時(shí)候,需要將圖像再由NV12轉(zhuǎn)為YUV444
imgOri = cv2.imread(img_path)
inputImage = format_yolov5(imgOri)
img = imequalresize(inputImage, (model_w, model_h))
nv12 = bgr2nv12_opencv(img)
# 3 模型推理
t1 = cv2.getTickCount()
outputs = models[0].forward(nv12)
t2 = cv2.getTickCount()
outputs = outputs[0].buffer # 25200x85x1
print('time consumption {0} ms'.format((t2-t1)*1000/cv2.getTickFrequency()))
# 4 后處理
image_width, image_height, _ = inputImage.shape
fx, fy = image_width / model_w, image_height / model_h
t1 = cv2.getTickCount()
class_ids, confidences, boxes = yolotools.pypostprocess_yolov5(outputs[0][:, :, 0], fx, fy,
thre_confidence, thre_score, thre_nms)
t2 = cv2.getTickCount()
print('post consumption {0} ms'.format((t2-t1)*1000/cv2.getTickFrequency()))
# 5 繪制檢測(cè)框
with open(classes_name_path, "r") as f:
class_list = [cname.strip() for cname in f.readlines()]
t1 = cv2.getTickCount()
for (classid, confidence, box) in zip(class_ids, confidences, boxes):
color = colors[int(classid) % len(colors)]
cv2.rectangle(imgOri, box, color, 2)
cv2.rectangle(imgOri, (box[0], box[1] - 20), (box[0] + box[2], box[1]), color, -1)
cv2.putText(imgOri, class_list[classid], (box[0], box[1] - 10), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0))
t2 = cv2.getTickCount()
print('draw rect consumption {0} ms'.format((t2-t1)*1000/cv2.getTickFrequency()))
cv2.imwrite('res.png', imgOri)
輸入sudo python3 inference_model_bpu.py
,推理結(jié)果保存為res.png
,相關(guān)結(jié)果如下所示,可以看出,后處理部分耗時(shí)為7ms,C++和Python混編有效提升了代碼的運(yùn)行速度。
3.3 利用Cython封裝后處理代碼
這部分介紹了利用Cython封裝C++的一些過程,后續(xù)各位有什么其他功能要補(bǔ)充的,按照這個(gè)流程處理即可。
3.3.1 寫后處理的C++代碼
首先,我們創(chuàng)建個(gè)頭文件yolotools.h
,用來記錄函數(shù)聲明,方便其他代碼調(diào)用。因?yàn)镃ython調(diào)用時(shí),調(diào)用C++的一些類并不方便,所以寫成C語言接口更方便調(diào)用。
后處理的函數(shù)名為postprocess_yolov5
,下面我對(duì)這個(gè)函數(shù)的輸入?yún)?shù)進(jìn)行說明:
-
float *_data, int datanum
:輸入模型推理數(shù)據(jù),BPU推理完一張640x640
的圖像后,會(huì)輸出一個(gè)25200x85x1
的矩陣,我們?nèi)サ?這一項(xiàng),得到一個(gè)25200x85
的矩陣,以它的數(shù)據(jù)起點(diǎn)指針作為輸入,datanum
為25200*85。 -
int rows, int classnum
:rows表示25200,而classnum表示數(shù)據(jù)集中的類別總數(shù),我用的這個(gè)模型是以COCO為例的,所以一共80類。值得注意的,上述的85=classnum+1(得分)+4(矩形4個(gè)參數(shù)) -
float x_factor, float y_factor
:圖像的縮放因子 -
float thre_cof, float thre_score, float thre_nms
:后處理參數(shù) -
int *_detected_num, signed int **_classids, float **_confidences, signed int **_boxes
:后處理輸出,_detected_num表示預(yù)測(cè)的矩形框個(gè)數(shù),其余的分別為對(duì)應(yīng)得數(shù)據(jù),并返回對(duì)應(yīng)的數(shù)據(jù)指針。
#ifndef YOLOV5_TOOLS_H
#define YOLOV5_TOOLS_H
void postprocess_yolov5(float *_data, int datanum,
int rows, int classnum,
float x_factor, float y_factor,
float thre_cof, float thre_score, float thre_nms,
int *_detected_num, signed int **_classids, float **_confidences, signed int **_boxes);
// 釋放由postprocess_yolov5動(dòng)態(tài)分配的內(nèi)存
void free_postprocess_yolov5(signed int **_classids, float **_confidences, signed int **_boxes);
#endif
創(chuàng)建yolov5postprocess.cpp
來對(duì)后處理函數(shù)進(jìn)行實(shí)現(xiàn)
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
#include <mutex>
#include "yolotools.h"
// 這部分的代碼參考了https://github.com/ultralytics/yolov5/issues/239
void postprocess_yolov5(float *_data, int datanum,
int rows, int classnum,
float x_factor, float y_factor,
float thre_cof, float thre_score, float thre_nms,
int *_detected_num, signed int **_classids, float **_confidences, signed int **_boxes)
{
float *data = (float*)_data;
int dimensions = classnum + 5;
CV_Assert(datanum == rows * dimensions);
std::vector<cv::Rect> boxes;
std::vector<int> class_ids;
std::vector<float> confidences;
// 這里是利用多線程,加速獲得目標(biāo)框,實(shí)際上,這部分的多線程,僅加速2-3ms。
// 可以利用cv::setNumThreads(1);指定線程數(shù)
std::mutex mtx;
cv::parallel_for_(cv::Range(0, rows), [&](const cv::Range& range)
{
for (int r = range.start; r < range.end; r++) //
{
float *usage_data = data + r * (classnum + 5);
float confidence = usage_data[4];
if (confidence >= thre_cof)
{
float *classes_scores = usage_data + 5;
cv::Mat scores(1, classnum, CV_32FC1, classes_scores);
cv::Point class_id;
double max_class_score;
cv::minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
if (max_class_score > thre_score)
{
float x = usage_data[0], y = usage_data[1], w = usage_data[2], h = usage_data[3];
int left = int((x - 0.5 * w) * x_factor);
int top = int((y - 0.5 * h) * y_factor);
int width = int(w * x_factor);
int height = int(h * y_factor);
mtx.lock();
confidences.push_back(confidence);
class_ids.push_back(class_id.x);
boxes.push_back(cv::Rect(left, top, width, height));
mtx.unlock();
}
}
}
});
std::vector<int> nms_result;
cv::dnn::NMSBoxes(boxes, confidences, thre_score, thre_nms, nms_result);
*_detected_num = nms_result.size();
*_classids = new signed int[*_detected_num];
*_confidences = new float[*_detected_num];
*_boxes = new signed int[*_detected_num * 4];
for(int i = 0; i < *_detected_num; i++)
{
int idx = nms_result[i];
(*_classids)[i] = class_ids[idx];
(*_confidences)[i] = confidences[idx];
(*_boxes)[i * 4] = boxes[idx].x;
(*_boxes)[i * 4 + 1] = boxes[idx].y;
(*_boxes)[i * 4 + 2] = boxes[idx].width;
(*_boxes)[i * 4 + 3] = boxes[idx].height;
}
}
void free_postprocess_yolov5(signed int **_classids, float **_confidences, signed int **_boxes)
{
if (*_classids)
{
delete[] *_classids;
*_classids = nullptr;
}
if (*_confidences)
{
delete[] *_confidences;
*_confidences = nullptr;
}
if (*_boxes)
{
delete[] *_boxes;
*_boxes = nullptr;
}
}
3.3.2 寫Cython所需的Pyx文件
同級(jí)目錄下創(chuàng)建pyyolotools.pyx
,切記文件名不要跟某個(gè)CPP重復(fù)了,因?yàn)閏ython會(huì)將pyyolotools.pyx
轉(zhuǎn)為pyyolotools.cpp
,如果有重復(fù)的話可能會(huì)導(dǎo)致文件被覆蓋掉。
import numpy as np
cimport numpy as np
from libc.string cimport memcpy
# 函數(shù)聲明
cdef extern from "yolotools.h":
void postprocess_yolov5(float*, int,
int, int,
float, float,
float, float, float,
int*, signed int**, float**, signed int**)
void free_postprocess_yolov5(signed int**, float**, signed int**)
# 定義Python函數(shù),主要補(bǔ)充的就是將python數(shù)據(jù)轉(zhuǎn)換為C++指針,然后利用計(jì)算出的結(jié)果再轉(zhuǎn)換回去
def pypostprocess_yolov5(np.ndarray[np.float32_t, ndim=2] yolov5output,
float fx, float fy,
float thre_cof, float thre_score, float thre_nms):
cdef int rows = yolov5output.shape[0]
cdef int dimensions = yolov5output.shape[1]
cdef int classnum = dimensions - 5
assert classnum > 5
cdef int datanum = rows * dimensions
cdef int detected_num = 0
cdef signed int *pclassids
cdef float *pconfidences
cdef signed int *pboxes
postprocess_yolov5(&yolov5output[0, 0], datanum,
rows, classnum, fx, fy,
thre_cof, thre_score, thre_nms,
&detected_num, &pclassids, &pconfidences, &pboxes)
if detected_num == 0:
return None
cdef np.ndarray[np.int32_t, ndim=1] classids = np.zeros((detected_num, ), dtype = np.int32)
cdef np.ndarray[np.float32_t, ndim=1] confidence = np.zeros((detected_num, ), dtype = np.float32)
cdef np.ndarray[np.int32_t, ndim=2] boxes = np.zeros((detected_num, 4), dtype = np.int32)
memcpy(&classids[0], pclassids, sizeof(int) * detected_num)
memcpy(&confidence[0], pconfidences, sizeof(float) * detected_num)
memcpy(&boxes[0, 0], pboxes, sizeof(int) * detected_num * 4)
free_postprocess_yolov5(&pclassids, &pconfidences, &pboxes);
return (classids, confidence, boxes)
3.3.3 寫編譯Pyx所需的python代碼
創(chuàng)建setup.py
文件,將下面代碼放進(jìn)去,配置好opencv的頭文件目錄、庫目錄、以及所需的庫文件。
在Extension
中配置封裝的函數(shù)所依賴的文件,然后在控制臺(tái)輸入python3 setup.py build_ext --inplace
即可。
from setuptools import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy as np
opencv_include = '/usr/include/opencv4/'
opencv_lib_dirs = "/usr/lib/aarch64-linux-gnu/"
opencv_libs = ['opencv_core', 'opencv_highgui', 'opencv_imgproc', 'opencv_imgcodecs', 'opencv_dnn']
print('opencv_include: ', opencv_include)
print('opencv_lib_dirs: ', opencv_lib_dirs)
print('opencv_libs: ', opencv_libs)
# python3 setup.py build_ext --inplace
class custom_build_ext(build_ext):
def build_extensions(self):
build_ext.build_extensions(self)
# Obtain the numpy include directory. This logic works across numpy versions.
try:
numpy_include = np.get_include()
except AttributeError:
numpy_include = np.get_numpy_include()
ext_modules = [
Extension(
"lib.pyyolotools",
["./yolov5postprocess.cpp",
"./pyyolotools.pyx",],
include_dirs = [numpy_include, opencv_include],
language='c++',
libraries=opencv_libs,
library_dirs=[opencv_lib_dirs]
),
]
setup(
name='pyyolotools',
ext_modules=ext_modules,
cmdclass={'build_ext': custom_build_ext},
)
print('Build done')
四 總結(jié)
上一個(gè)部署教程,主要是介紹如何利用Caffe來部署模型,這個(gè)部分,就是利用ONNX來部署。后續(xù)如果自己基于這個(gè)代碼進(jìn)行修改的話,也可以按照這個(gè)教程對(duì)自己的模型進(jìn)行量化上板。
此外,X3派作為個(gè)嵌入式板子,學(xué)會(huì)開發(fā)C++是非常重要的。但我個(gè)人認(rèn)為所有的任務(wù)都是C++是不現(xiàn)實(shí)的,我們可以利用Python高效完成項(xiàng)目開發(fā),對(duì)其中耗時(shí)較高的,封裝C++即可。文章來源:http://www.zghlxwxcb.cn/news/detail-619039.html
PS:各位千萬不要被推理耗時(shí)嚇到了,感覺耗時(shí)太高了,因?yàn)檫@個(gè)版本的模型轉(zhuǎn)換時(shí)候,后面一堆層是跑在CPU上的,各位在設(shè)計(jì)自己的網(wǎng)絡(luò)的時(shí)候也要注意下哈。文章來源地址http://www.zghlxwxcb.cn/news/detail-619039.html
到了這里,關(guān)于[BPU部署教程] 教你搞定YOLOV5部署 (版本: 6.2)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!