Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ModelZoo
yolov5_migraphx
Commits
28602b9a
Commit
28602b9a
authored
Jun 19, 2023
by
shizhm
Browse files
重构yolov5推理示例
parent
b306b620
Changes
11
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
401 additions
and
194 deletions
+401
-194
CMakeLists.txt
CMakeLists.txt
+0
-3
Doc/Tutorial_Cpp.md
Doc/Tutorial_Cpp.md
+73
-65
Doc/Tutorial_Python.md
Doc/Tutorial_Python.md
+23
-17
Python/YoloV5_infer_migraphx.py
Python/YoloV5_infer_migraphx.py
+62
-32
README.md
README.md
+50
-33
Resource/Configuration.xml
Resource/Configuration.xml
+2
-1
Resource/Images/Result.jpg
Resource/Images/Result.jpg
+0
-0
Resource/Models/yolov5s.onnx
Resource/Models/yolov5s.onnx
+0
-0
Src/YOLOV5.cpp
Src/YOLOV5.cpp
+88
-35
Src/YOLOV5.h
Src/YOLOV5.h
+3
-2
Src/main.cpp
Src/main.cpp
+100
-6
No files found.
CMakeLists.txt
View file @
28602b9a
...
...
@@ -26,10 +26,7 @@ set(LIBRARY opencv_core
opencv_imgproc
opencv_imgcodecs
opencv_dnn
migraphx_ref
migraphx
migraphx_c
migraphx_device
migraphx_gpu
migraphx_onnx
)
link_libraries
(
${
LIBRARY
}
)
...
...
Doc/Tutorial_Cpp.md
View file @
28602b9a
# YOLOV5检测器
YOLOV5模型是目前工业界使用较多的算法,官方提供了多个不同版本的预训练模型,本份文档主要介绍了如何基于migraphx构建YOLOV5动态shape推理,该示例推理流程对YOLOV5其他版本的模型同样适用。
YOLOV5模型是目前工业界使用较多的算法,官方提供了多个不同版本的预训练模型,本份文档主要介绍了如何基于migraphx构建YOLOV5
推理,包括:静态推理、
动态shape推理,该示例推理流程对YOLOV5其他版本的模型同样适用。
## 模型简介
...
...
@@ -12,7 +12,8 @@ YOLOV5是一种单阶段目标检测算法,该算法在YOLOV4的基础上添
samples工程中的Resource/Configuration.xml文件的DetectorYOLOV5节点表示YOLOV5检测器的参数,相关参数主要依据官方推理示例进行设置。各个参数含义如下:
-
ModelPath:yolov5模型存放路径
-
ModelPathDynamic:yolov5动态模型存放路径
-
ModelPathStatic:yolov5静态模型存放路径
-
ClassNameFile:coco数据集类别文件存放路径
-
UseFP16:是否使用FP16推理模式
-
NumberOfClasses:检测类别数量
...
...
@@ -21,7 +22,8 @@ samples工程中的Resource/Configuration.xml文件的DetectorYOLOV5节点表示
-
ObjectThreshold:用于判断anchor内部是否有物体
```
<ModelPath>"../Resource/Models/yolov5s_Nx3xNxN.onnx"</ModelPath>
<ModelPathDynamic>"../Resource/Models/yolov5s_Nx3xNxN.onnx"</ModelPathDynamic>
<ModelPathStatic>"../Resource/Models/yolov5s.onnx"</ModelPathStatic>
<ClassNameFile>"../Resource/Models/coco.names"</ClassNameFile>
<UseFP16>0</UseFP16><!--是否使用FP16-->
<NumberOfClasses>80</NumberOfClasses><!--类别数(不包括背景类),COCO:80,VOC:20-->
...
...
@@ -32,45 +34,34 @@ samples工程中的Resource/Configuration.xml文件的DetectorYOLOV5节点表示
## 模型初始化
模型初始化首先通过parse_onnx()函数加载YOLOV5的onnx模型,本示例构建YOLOV5动态shape推理,所以需要设置模型输入的最大shape,本示例设为{1,3,800,800},并可以通过program的get_parameter_shapes()函数获取网络的输入属性。完成模型加载之后需要使用compile()方法编译模型,编译模式使用migraphx::gpu::target{}设为GPU模式,编译过程主要基于MIGraphX IR完成各种优化。同时如果需要使用低精度量化进行推理,可以使用quantize_fp16()函数实现。
模型初始化首先通过parse_onnx()函数加载YOLOV5的onnx模型。
-
静态推理:调用parse_onnx函数对静态模型进行解析
```
ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializationParameterOfDetector)
ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializationParameterOfDetector
, bool dynamic
)
{
...
migraphx::onnx_options onnx_options;
onnx_options.map_input_dims["images"]={1,3,800,800};
net = migraphx::parse_onnx(modelPath, onnx_options);
LOG_INFO(stdout,"succeed to load model: %s\n",GetFileName(modelPath).c_str());
// 获取模型输入属性
std::unordered_map<std::string, migraphx::shape> inputMap=net.get_parameter_shapes();
inputName=inputMap.begin()->first;
inputShape=inputMap.begin()->second;
int N=inputShape.lens()[0];
int C=inputShape.lens()[1];
int H=inputShape.lens()[2];
int W=inputShape.lens()[3];
inputSize=cv::Size(W,H);
// 设置模型为GPU模式
migraphx::target gpuTarget = migraphx::gpu::target{};
// 量化
if(useFP16)
{
migraphx::quantize_fp16(net);
}
// 编译模型
migraphx::compile_options options;
options.device_id=0;
options.offload_copy=true;
net.compile(gpuTarget,options);
LOG_INFO(stdout,"succeed to compile model: %s\n",GetFileName(modelPath).c_str());
// 加载模型
net = migraphx::parse_onnx(modelPath);
LOG_INFO(stdout,"succeed to load model: %s\n",GetFileName(modelPath).c_str());
...
}
```
-
动态shape推理:需要设置模型输入的最大shape,本示例设为{1,3,800,800}
```
ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializationParameterOfDetector, bool dynamic)
{
...
migraphx::onnx_options onnx_options;
onnx_options.map_input_dims["images"]={1,3,800,800};//
net = migraphx::parse_onnx(modelPath, onnx_options);
...
}
```
...
...
@@ -79,25 +70,44 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
在将数据输入到模型之前,需要对图像做如下预处理操作:
1.
转换数据排布为NCHW
2.
归一化[0.0, 1.0]
3.
将输入数据的尺寸变换到YOLOV5动态输入大小,relInputShape为每次实际inputshape
-
转换数据排布为NCHW
-
归一化[0.0, 1.0]
-
输入数据的尺寸变换:静态推理将输入大小变换为[1,3,608,608],动态推理对输入图像尺寸不做变换。
```
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection)
{
...
inputSize = cv::Size(relInputShape[3], relInputShape[2]);
// 预处理并转换为NCHW
// 数据预处理
cv::Mat inputBlob;
blobFromImage(srcImage, // 输入数据
inputBlob, // 输出数据
1 / 255.0, //归一化
inputSize, //YOLOV5输入尺寸
Scalar(0, 0, 0), //未减去均值
true, //转换RB通道
std::vector<std::size_t> relInputShape;
int height, width;
if(dynamic)
{
width = srcImage.rows;
height = srcImage.cols;
relInputShape = {1,3,height,width};
cv::dnn::blobFromImage(srcImage,
inputBlob,
1 / 255.0,
cv::Size(width, height),
cv::Scalar(0, 0, 0),
true,
false);
}
else
{
cv::dnn::blobFromImage(srcImage,
inputBlob,
1 / 255.0,
inputSize,
cv::Scalar(0, 0, 0),
true,
false);
}
...
}
...
...
@@ -105,32 +115,30 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_
## 推理
完成图像预处理以及YOLOV5目标检测相关参数设置之后开始执行推理,利用migraphx推理计算得到YOLOV5模型的输出。
完成图像预处理以及YOLOV5目标检测相关参数设置之后开始执行推理,利用migraphx推理计算得到YOLOV5模型的输出。
其中静态推理输入数据inputData的shape大小为模型的固定输入尺寸,动态推理则为实际输入的尺寸。
```
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection)
{
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection, bool dynamic)
{
...
// 创建输入数据
// 创建输入数据
migraphx::parameter_map inputData;
inputData[inputName]= migraphx::argument{migraphx::shape(inputShape.type(), relInputShape), (float*)inputBlob.data};
if(dynamic)
{
inputData[inputName]= migraphx::argument{migraphx::shape(inputShape.type(), relInputShape), (float*)inputBlob.data};
}
else
{
inputData[inputName]= migraphx::argument{inputShape, (float*)inputBlob.data};
}
// 推理
std::vector<migraphx::argument> inferenceResults = net.eval(inputData);
// 获取推理结果
std::vector<cv::Mat> outs;
migraphx::argument result = inferenceResults[0];
// 转换为cv::Mat
migraphx::shape outputShape = result.get_shape();
int shape[]={outputShape.lens()[0],outputShape.lens()[1],outputShape.lens()[2]};
cv::Mat out(3,shape,CV_32F);
memcpy(out.data,result.data(),sizeof(float)*outputShape.elements());
outs.push_back(out);
...
}
```
...
...
@@ -140,7 +148,7 @@ YOLOV5的MIGraphX推理结果inferenceResults是一个std::vector< migraphx::arg
-
第二步根据confidenceThreshold阈值进行筛选,当满足第一步阈值anchor的最大置信度得分maxClassScore大于该阈值,则进一步获取当前anchor的坐标信息和预测物体类别信息,小于该阈值则不做处理。
```
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage,
std::vector<std::size_t> &relInputShape,
std::vector<ResultOfDetection> &resultsOfDetection)
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDetection> &resultsOfDetection
, bool dynamic
)
{
...
...
...
@@ -196,7 +204,7 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_
为了消除重叠锚框,输出最终的YOLOV5目标检测结果,执行非极大值抑制对筛选之后的anchor进行处理,最后保存检测结果到resultsOfDetection中。
```
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage,
std::vector<std::size_t> &relInputShape,
std::vector<ResultOfDetection> &resultsOfDetection)
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDetection> &resultsOfDetection
, bool dynamic
)
{
...
...
...
Doc/Tutorial_Python.md
View file @
28602b9a
...
...
@@ -34,32 +34,37 @@ def prepare_input(self, image):
return input_img
```
其中模型输入的inputWidth、inputHeight为每次动态输入shape。
## 推理
执行YOLOV5
动态输入
推理,首先需要对YOLOV5
的动态
模型进行解析、编译,与静态推理不同的是,动态shape推理需要设置模型输入的最大shape,本示例设为[1,3,800,800]。
执行YOLOV5
模型
推理,首先需要对YOLOV5模型进行解析、编译,
静态推理过程中直接调用parse_onnx函数对静态模型进行解析,获取静态模型的输入shape信息;
与静态推理不同的是,动态shape推理需要设置模型输入的最大shape,本示例设为[1,3,800,800]。
```
class YOLOv5:
def __init__(self, path, obj_thres=0.5, conf_thres=0.25, iou_thres=0.5):
def __init__(self, path,
dynamic=False,
obj_thres=0.5, conf_thres=0.25, iou_thres=0.5):
self.objectThreshold = obj_thres
self.confThreshold = conf_thres
self.nmsThreshold = iou_thres
self.isDynamic = dynamic
# 获取模型检测的类别信息
self.classNames = list(map(lambda x: x.strip(), open('../Resource/Models/coco.names', 'r').readlines()))
# 解析推理模型
maxInput={"images":[1,3,800,800]}
self.model = migraphx.parse_onnx(path, map_input_dims=maxInput)
# 获取模型的输入name
self.inputName = self.model.get_parameter_names()[0]
# 获取模型的输入尺寸
inputShape = self.model.get_parameter_shapes()[self.inputName].lens()
print("inputName:{0} \ninputMaxShape:{1}".format(self.inputName, inputShape))
if self.isDynamic:
maxInput={"images":[1,3,800,800]}
self.model = migraphx.parse_onnx(path, map_input_dims=maxInput)
self.inputName = self.model.get_parameter_names()[0]
inputShape = self.model.get_parameter_shapes()[self.inputName].lens()
print("inputName:{0} \ninputMaxShape:{1}".format(self.inputName, inputShape))
else:
self.model = migraphx.parse_onnx(path)
self.inputName = self.model.get_parameter_names()[0]
inputShape = self.model.get_parameter_shapes()[self.inputName].lens()
print("inputName:{0} \ninputShape:{1}".format(self.inputName, inputShape))
# 静态推理尺寸
self.inputWidth = inputShape[3]
self.inputHeight = inputShape[2]
# 模型编译
self.model.compile(t=migraphx.get_target("gpu"), device_id=0) # device_id: 设置GPU设备,默认为0号设备
...
...
@@ -71,9 +76,10 @@ class YOLOv5:
模型初始化完成之后开始进行推理,对输入数据进行前向计算得到模型的输出result,在detect函数中调用定义的process_output函数对result进行后处理,得到图像中含有物体的anchor坐标信息、类别置信度、类别ID。
```
def detect(self, image, input_shape):
self.inputWidth = input_shape[3]
self.inputHeight = input_shape[2]
def detect(self, image, input_shape=None):
if(self.isDynamic):
self.inputWidth = input_shape[3]
self.inputHeight = input_shape[2]
# 输入图片预处理
input_img = self.prepare_input(image)
...
...
Python/YoloV5_infer_migraphx.py
View file @
28602b9a
...
...
@@ -8,32 +8,40 @@ import migraphx
class
YOLOv5
:
def
__init__
(
self
,
path
,
obj_thres
=
0.5
,
conf_thres
=
0.25
,
iou_thres
=
0.5
):
def
__init__
(
self
,
path
,
dynamic
=
False
,
obj_thres
=
0.5
,
conf_thres
=
0.25
,
iou_thres
=
0.5
):
self
.
objectThreshold
=
obj_thres
self
.
confThreshold
=
conf_thres
self
.
nmsThreshold
=
iou_thres
self
.
isDynamic
=
dynamic
# 获取模型检测的类别信息
self
.
classNames
=
list
(
map
(
lambda
x
:
x
.
strip
(),
open
(
'../Resource/Models/coco.names'
,
'r'
).
readlines
()))
# 解析推理模型
maxInput
=
{
"images"
:[
1
,
3
,
800
,
800
]}
self
.
model
=
migraphx
.
parse_onnx
(
path
,
map_input_dims
=
maxInput
)
# 获取模型的输入name
self
.
inputName
=
self
.
model
.
get_parameter_names
()[
0
]
# 获取模型的输入尺寸
inputShape
=
self
.
model
.
get_parameter_shapes
()[
self
.
inputName
].
lens
()
print
(
"inputName:{0}
\n
inputMaxShape:{1}"
.
format
(
self
.
inputName
,
inputShape
))
if
self
.
isDynamic
:
maxInput
=
{
"images"
:[
1
,
3
,
800
,
800
]}
self
.
model
=
migraphx
.
parse_onnx
(
path
,
map_input_dims
=
maxInput
)
self
.
inputName
=
self
.
model
.
get_parameter_names
()[
0
]
inputShape
=
self
.
model
.
get_parameter_shapes
()[
self
.
inputName
].
lens
()
print
(
"inputName:{0}
\n
inputMaxShape:{1}"
.
format
(
self
.
inputName
,
inputShape
))
else
:
self
.
model
=
migraphx
.
parse_onnx
(
path
)
self
.
inputName
=
self
.
model
.
get_parameter_names
()[
0
]
inputShape
=
self
.
model
.
get_parameter_shapes
()[
self
.
inputName
].
lens
()
print
(
"inputName:{0}
\n
inputShape:{1}"
.
format
(
self
.
inputName
,
inputShape
))
# 静态推理尺寸
self
.
inputWidth
=
inputShape
[
3
]
self
.
inputHeight
=
inputShape
[
2
]
# 模型编译
self
.
model
.
compile
(
t
=
migraphx
.
get_target
(
"gpu"
),
device_id
=
0
)
# device_id: 设置GPU设备,默认为0号设备
print
(
"Success to compile"
)
def
detect
(
self
,
image
,
input_shape
):
self
.
inputWidth
=
input_shape
[
3
]
self
.
inputHeight
=
input_shape
[
2
]
def
detect
(
self
,
image
,
input_shape
=
None
):
if
(
self
.
isDynamic
):
self
.
inputWidth
=
input_shape
[
3
]
self
.
inputHeight
=
input_shape
[
2
]
# 输入图片预处理
input_img
=
self
.
prepare_input
(
image
)
...
...
@@ -85,13 +93,8 @@ class YOLOv5:
return
boxes
[
indices
],
scores
[
indices
],
class_ids
[
indices
]
def
extract_boxes
(
self
,
predictions
):
# 获取anchor的坐标信息
boxes
=
predictions
[:,
:
4
]
# 将anchor的坐标信息映射到输入image
boxes
=
self
.
rescale_boxes
(
boxes
)
# 格式转换
boxes_
=
np
.
copy
(
boxes
)
boxes_
[...,
0
]
=
boxes
[...,
0
]
-
boxes
[...,
2
]
*
0.5
boxes_
[...,
1
]
=
boxes
[...,
1
]
-
boxes
[...,
3
]
*
0.5
...
...
@@ -124,28 +127,33 @@ def read_images(image_path):
image_lists
.
append
(
image
)
return
image_lists
if
__name__
==
'__main__'
:
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'--imgpath'
,
type
=
str
,
default
=
'../Resource/Images/DynamicPics'
,
help
=
"image path"
)
parser
.
add_argument
(
'--modelpath'
,
type
=
str
,
default
=
'../Resource/Models/yolov5s_Nx3xNxN.onnx'
,
help
=
"onnx filepath"
)
parser
.
add_argument
(
'--objectThreshold'
,
default
=
0.5
,
type
=
float
,
help
=
'class confidence'
)
parser
.
add_argument
(
'--confThreshold'
,
default
=
0.25
,
type
=
float
,
help
=
'class confidence'
)
parser
.
add_argument
(
'--nmsThreshold'
,
default
=
0.5
,
type
=
float
,
help
=
'nms iou thresh'
)
args
=
parser
.
parse_args
()
def
yolov5_Static
(
imgpath
,
modelpath
,
objectThreshold
,
confThreshold
,
nmsThreshold
):
yolov5_detector
=
YOLOv5
(
modelpath
,
False
,
obj_thres
=
objectThreshold
,
conf_thres
=
confThreshold
,
iou_thres
=
nmsThreshold
)
srcimg
=
cv2
.
imread
(
imgpath
,
1
)
boxes
,
scores
,
class_ids
=
yolov5_detector
.
detect
(
srcimg
)
dstimg
=
yolov5_detector
.
draw_detections
(
srcimg
,
boxes
,
scores
,
class_ids
)
# 保存检测结果
cv2
.
imwrite
(
"./Result.jpg"
,
dstimg
)
print
(
"Success to save result"
)
def
yolov5_dynamic
(
imgpath
,
modelpath
,
objectThreshold
,
confThreshold
,
nmsThreshold
):
# 设置动态输入shape
input_shapes
=
[]
input_shapes
.
append
([
1
,
3
,
416
,
416
])
input_shapes
.
append
([
1
,
3
,
608
,
608
])
# 读取测试图像
image_lists
=
read_images
(
args
.
imgpath
)
image_lists
=
read_images
(
imgpath
)
# 推理
yolov5_detector
=
YOLOv5
(
args
.
modelpath
,
obj_thres
=
args
.
objectThreshold
,
conf_thres
=
args
.
confThreshold
,
iou_thres
=
args
.
nmsThreshold
)
yolov5_detector
=
YOLOv5
(
modelpath
,
True
,
obj_thres
=
objectThreshold
,
conf_thres
=
confThreshold
,
iou_thres
=
nmsThreshold
)
for
i
,
image
in
enumerate
(
image_lists
):
print
(
"Start to inference image{}"
.
format
(
i
))
boxes
,
scores
,
class_ids
=
yolov5_detector
.
detect
(
image
,
input_shapes
[
i
])
...
...
@@ -156,6 +164,28 @@ if __name__ == '__main__':
cv2
.
imwrite
(
result_name
,
dstimg
)
print
(
"Success to save results"
)
if
__name__
==
'__main__'
:
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
'--imgPath'
,
type
=
str
,
default
=
'../Resource/Images/DynamicPics/image1.jpg'
,
help
=
"image path"
)
parser
.
add_argument
(
'--imgFolderPath'
,
type
=
str
,
default
=
'../Resource/Images/DynamicPics'
,
help
=
"image folder path"
)
parser
.
add_argument
(
'--staticModelPath'
,
type
=
str
,
default
=
'../Resource/Models/yolov5s.onnx'
,
help
=
"static onnx filepath"
)
parser
.
add_argument
(
'--dynamicModelPath'
,
type
=
str
,
default
=
'../Resource/Models/yolov5s_Nx3xNxN.onnx'
,
help
=
"static onnx filepath"
)
parser
.
add_argument
(
'--objectThreshold'
,
default
=
0.5
,
type
=
float
,
help
=
'class confidence'
)
parser
.
add_argument
(
'--confThreshold'
,
default
=
0.25
,
type
=
float
,
help
=
'class confidence'
)
parser
.
add_argument
(
'--nmsThreshold'
,
default
=
0.5
,
type
=
float
,
help
=
'nms iou thresh'
)
parser
.
add_argument
(
"--staticInfer"
,
action
=
"store_true"
,
default
=
False
,
help
=
"Performing static inference"
)
parser
.
add_argument
(
"--dynamicInfer"
,
action
=
"store_true"
,
default
=
False
,
help
=
"Performing static inference"
)
args
=
parser
.
parse_args
()
# 静态推理
if
args
.
staticInfer
:
yolov5_Static
(
args
.
imgPath
,
args
.
staticModelPath
,
args
.
objectThreshold
,
args
.
confThreshold
,
args
.
nmsThreshold
)
# 动态推理
if
args
.
dynamicInfer
:
yolov5_dynamic
(
args
.
imgFolderPath
,
args
.
dynamicModelPath
,
args
.
objectThreshold
,
args
.
confThreshold
,
args
.
nmsThreshold
)
...
...
README.md
View file @
28602b9a
...
...
@@ -43,7 +43,32 @@ pip install -r requirements.txt
### 运行示例
YoloV5模型的推理示例程序是YoloV5_infer_migraphx.py,本示例执行YOLOV5动态shape推理,在Python目录下使用如下命令运行该推理示例:
YoloV5模型的推理示例程序是YoloV5_infer_migraphx.py,使用如下命令运行该推理示例:
```
# 进入python目录
cd <path_to_yolov5_migraphx>
# 进入Python目录
cd Python/
```
1.
静态推理
```
python YoloV5_infer_migraphx.py \
--imgPath 测试图像路径 \
--staticModelPath onnx模型路径 \
--objectThreshold 判断是否有物体阈值,默认0.5 \
--confThreshold 置信度阈值,默认0.25 \
--nmsThreshold nms阈值,默认0.5 \
```
程序运行结束后,在当前目录生成YOLOV5静态推理检测结果可视化图像Result.jpg
<img
src=
"./Resource/Images/Result.jpg"
alt=
"Result"
style=
"zoom: 50%;"
/>
2.
动态推理
```
# 开启环境变量
...
...
@@ -51,14 +76,14 @@ export MIGRAPHX_DYNAMIC_SHAPE=1
# 运行示例
python YoloV5_infer_migraphx.py \
--img
p
ath 测试图像路径 \
--
m
odel
p
ath onnx模型路径 \
--img
FolderP
ath 测试图像
文件夹
路径 \
--
dynamicM
odel
P
ath onnx模型路径 \
--objectThreshold 判断是否有物体阈值,默认0.5 \
--confThreshold 置信度阈值,默认0.25 \
--nmsThreshold nms阈值,默认0.5 \
```
程序运行结束会在当前目录生成YoloV5
检测结果图像
。
程序运行结束会在当前目录生成YoloV5
动态推理检测结果可视化图像Result0.jpg、Result1.jpg
。
<img
src=
"./Resource/Images/Result0.jpg"
alt=
"Result_2"
style=
"zoom: 50%;"
/>
...
...
@@ -76,22 +101,8 @@ python YoloV5_infer_migraphx.py \
docker pull image.sourcefind.cn:5000/dcu/admin/base/custom:ort1.14.0_migraphx3.0.0-dtk22.10.1
```
### 安装Opencv依赖
```
python
cd
<
path_to_migraphx_samples
>
sh
.
/
3
rdParty
/
InstallOpenCVDependences
.
sh
```
### 修改CMakeLists.txt
-
如果使用ubuntu系统,需要修改CMakeLists.txt中依赖库路径:
将"${CMAKE_CURRENT_SOURCE_DIR}/depend/lib64/"修改为"${CMAKE_CURRENT_SOURCE_DIR}/depend/lib/"
-
**MIGraphX2.3.0及以上版本需要c++17**
### 安装OpenCV并构建工程
### 构建工程
```
rbuild build -d depend
...
...
@@ -101,18 +112,10 @@ rbuild build -d depend
将依赖库依赖加入环境变量LD_LIBRARY_PATH,在~/.bashrc中添加如下语句:
**Centos**
:
```
export LD_LIBRARY_PATH=<path_to_yolov5_migraphx>/depend/lib64/:$LD_LIBRARY_PATH
```
**Ubuntu**
:
```
export LD_LIBRARY_PATH=<path_to_yolov5_migraphx>/depend/lib/:$LD_LIBRARY_PATH
```
然后执行:
```
...
...
@@ -121,23 +124,37 @@ source ~/.bashrc
### 运行示例
成功编译
YoloV5
工程
后,执行如下
命
令运行
动态shape推理
该示例:
YoloV5
示例程序编译成功
后,执行如下
指
令运行该示例:
```
# 进入yolov5 migraphx工程根目录
cd <path_to_yolov5_migraphx>
cd <path_to_yolov5_migraphx>
# 进入build目录
cd ./build/
cd build/
```
1.
静态推理
```
./YOLOV5 0
```
程序运行结束后,会在当前目录生成YOLOV5静态推理检测结果可视化图像Result.jpg
<img
src=
"./Resource/Images/Result.jpg"
alt=
"Result"
style=
"zoom:50%;"
/>
2.
动态推理
```
# 开启环境变量
export MIGRAPHX_DYNAMIC_SHAPE=1
# 执行示例程序
./YOLOV5
# 执行
动态推理
示例程序
./YOLOV5
1
```
程序运行结束会在build目录生成YoloV5动态shape推理检测结果
图像
。
程序运行结束会在build目录生成YoloV5动态shape推理检测结果
可视化图像Result0.jpg、Result1.jpg
。
<img
src=
"./Resource/Images/Result0.jpg"
alt=
"Result"
style=
"zoom:50%;"
/>
...
...
Resource/Configuration.xml
View file @
28602b9a
...
...
@@ -3,7 +3,8 @@
<!--YOLOV5检测器 -->
<DetectorYOLOV5>
<ModelPath>
"../Resource/Models/yolov5s_Nx3xNxN.onnx"
</ModelPath>
<ModelPathDynamic>
"../Resource/Models/yolov5s_Nx3xNxN.onnx"
</ModelPathDynamic>
<ModelPathStatic>
"../Resource/Models/yolov5s.onnx"
</ModelPathStatic>
<ClassNameFile>
"../Resource/Models/coco.names"
</ClassNameFile>
<UseFP16>
0
</UseFP16>
<!--是否使用FP16-->
<NumberOfClasses>
80
</NumberOfClasses>
<!--类别数(不包括背景类),COCO:80,VOC:20-->
...
...
Resource/Images/Result.jpg
0 → 100644
View file @
28602b9a
487 KB
Resource/Models/yolov5s.onnx
0 → 100644
View file @
28602b9a
File added
Src/YOLOV5.cpp
View file @
28602b9a
...
...
@@ -21,7 +21,7 @@ DetectorYOLOV5::~DetectorYOLOV5()
}
ErrorCode
DetectorYOLOV5
::
Initialize
(
InitializationParameterOfDetector
initializationParameterOfDetector
)
ErrorCode
DetectorYOLOV5
::
Initialize
(
InitializationParameterOfDetector
initializationParameterOfDetector
,
bool
dynamic
)
{
// 读取配置文件
std
::
string
configFilePath
=
initializationParameterOfDetector
.
configFilePath
;
...
...
@@ -39,7 +39,14 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
// 获取配置文件参数
cv
::
FileNode
netNode
=
configurationFile
[
"DetectorYOLOV5"
];
std
::
string
modelPath
=
(
std
::
string
)
netNode
[
"ModelPath"
];
if
(
dynamic
)
{
modelPath
=
(
std
::
string
)
netNode
[
"ModelPathDynamic"
];
}
else
{
modelPath
=
(
std
::
string
)
netNode
[
"ModelPathStatic"
];
}
std
::
string
pathOfClassNameFile
=
(
std
::
string
)
netNode
[
"ClassNameFile"
];
yolov5Parameter
.
confidenceThreshold
=
(
float
)
netNode
[
"ConfidenceThreshold"
];
yolov5Parameter
.
nmsThreshold
=
(
float
)
netNode
[
"NMSThreshold"
];
...
...
@@ -47,27 +54,63 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
yolov5Parameter
.
numberOfClasses
=
(
int
)
netNode
[
"NumberOfClasses"
];
useFP16
=
(
bool
)(
int
)
netNode
[
"UseFP16"
];
// 加载模型
if
(
Exists
(
modelPath
)
==
false
)
if
(
dynamic
)
{
LOG_ERROR
(
stdout
,
"%s not exist!
\n
"
,
modelPath
.
c_str
());
return
MODEL_NOT_EXIST
;
// 加载模型
if
(
Exists
(
modelPath
)
==
false
)
{
LOG_ERROR
(
stdout
,
"%s not exist!
\n
"
,
modelPath
.
c_str
());
return
MODEL_NOT_EXIST
;
}
migraphx
::
onnx_options
onnx_options
;
onnx_options
.
map_input_dims
[
"images"
]
=
{
1
,
3
,
800
,
800
};
//
net
=
migraphx
::
parse_onnx
(
modelPath
,
onnx_options
);
LOG_INFO
(
stdout
,
"succeed to load model: %s
\n
"
,
GetFileName
(
modelPath
).
c_str
());
// 获取模型输入属性
std
::
unordered_map
<
std
::
string
,
migraphx
::
shape
>
inputMap
=
net
.
get_parameter_shapes
();
inputName
=
inputMap
.
begin
()
->
first
;
inputShape
=
inputMap
.
begin
()
->
second
;
int
N
=
inputShape
.
lens
()[
0
];
int
C
=
inputShape
.
lens
()[
1
];
int
H
=
inputShape
.
lens
()[
2
];
int
W
=
inputShape
.
lens
()[
3
];
inputSize
=
cv
::
Size
(
W
,
H
);
// log
LOG_INFO
(
stdout
,
"InputMaxSize:%dx%d
\n
"
,
inputSize
.
width
,
inputSize
.
height
);
}
migraphx
::
onnx_options
onnx_options
;
onnx_options
.
map_input_dims
[
"images"
]
=
{
1
,
3
,
800
,
800
};
net
=
migraphx
::
parse_onnx
(
modelPath
,
onnx_options
);
LOG_INFO
(
stdout
,
"succeed to load model: %s
\n
"
,
GetFileName
(
modelPath
).
c_str
());
// 获取模型输入属性
std
::
unordered_map
<
std
::
string
,
migraphx
::
shape
>
inputMap
=
net
.
get_parameter_shapes
();
inputName
=
inputMap
.
begin
()
->
first
;
inputShape
=
inputMap
.
begin
()
->
second
;
int
N
=
inputShape
.
lens
()[
0
];
int
C
=
inputShape
.
lens
()[
1
];
int
H
=
inputShape
.
lens
()[
2
];
int
W
=
inputShape
.
lens
()[
3
];
inputSize
=
cv
::
Size
(
W
,
H
);
else
{
// 加载模型
if
(
Exists
(
modelPath
)
==
false
)
{
LOG_ERROR
(
stdout
,
"%s not exist!
\n
"
,
modelPath
.
c_str
());
return
MODEL_NOT_EXIST
;
}
net
=
migraphx
::
parse_onnx
(
modelPath
);
LOG_INFO
(
stdout
,
"succeed to load model: %s
\n
"
,
GetFileName
(
modelPath
).
c_str
());
// 获取模型输入属性
std
::
unordered_map
<
std
::
string
,
migraphx
::
shape
>
inputMap
=
net
.
get_parameter_shapes
();
inputName
=
inputMap
.
begin
()
->
first
;
inputShape
=
inputMap
.
begin
()
->
second
;
int
N
=
inputShape
.
lens
()[
0
];
int
C
=
inputShape
.
lens
()[
1
];
int
H
=
inputShape
.
lens
()[
2
];
int
W
=
inputShape
.
lens
()[
3
];
inputSize
=
cv
::
Size
(
W
,
H
);
// log
LOG_INFO
(
stdout
,
"InputSize:%dx%d
\n
"
,
inputSize
.
width
,
inputSize
.
height
);
}
LOG_INFO
(
stdout
,
"InputName:%s
\n
"
,
inputName
.
c_str
());
LOG_INFO
(
stdout
,
"ConfidenceThreshold:%f
\n
"
,
yolov5Parameter
.
confidenceThreshold
);
LOG_INFO
(
stdout
,
"NMSThreshold:%f
\n
"
,
yolov5Parameter
.
nmsThreshold
);
LOG_INFO
(
stdout
,
"objectThreshold:%f
\n
"
,
yolov5Parameter
.
objectThreshold
);
LOG_INFO
(
stdout
,
"NumberOfClasses:%d
\n
"
,
yolov5Parameter
.
numberOfClasses
);
// 设置模型为GPU模式
migraphx
::
target
gpuTarget
=
migraphx
::
gpu
::
target
{};
...
...
@@ -105,19 +148,11 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
classNames
.
resize
(
yolov5Parameter
.
numberOfClasses
);
}
// log
LOG_INFO
(
stdout
,
"InputMaxSize:%dx%d
\n
"
,
inputSize
.
width
,
inputSize
.
height
);
LOG_INFO
(
stdout
,
"InputName:%s
\n
"
,
inputName
.
c_str
());
LOG_INFO
(
stdout
,
"ConfidenceThreshold:%f
\n
"
,
yolov5Parameter
.
confidenceThreshold
);
LOG_INFO
(
stdout
,
"NMSThreshold:%f
\n
"
,
yolov5Parameter
.
nmsThreshold
);
LOG_INFO
(
stdout
,
"objectThreshold:%f
\n
"
,
yolov5Parameter
.
objectThreshold
);
LOG_INFO
(
stdout
,
"NumberOfClasses:%d
\n
"
,
yolov5Parameter
.
numberOfClasses
);
return
SUCCESS
;
}
ErrorCode
DetectorYOLOV5
::
Detect
(
const
cv
::
Mat
&
srcImage
,
std
::
vector
<
std
::
size_t
>
&
relInputShape
,
std
::
vector
<
ResultOfDetection
>
&
resultsOfDetection
)
ErrorCode
DetectorYOLOV5
::
Detect
(
const
cv
::
Mat
&
srcImage
,
std
::
vector
<
ResultOfDetection
>
&
resultsOfDetection
,
bool
dynamic
)
{
if
(
srcImage
.
empty
()
||
srcImage
.
type
()
!=
CV_8UC3
)
{
...
...
@@ -125,21 +160,39 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_
return
IMAGE_ERROR
;
}
inputSize
=
cv
::
Size
(
relInputShape
[
3
],
relInputShape
[
2
]);
// 数据预处理并转换为NCHW格式
// 数据预处理
cv
::
Mat
inputBlob
;
cv
::
dnn
::
blobFromImage
(
srcImage
,
std
::
vector
<
std
::
size_t
>
relInputShape
;
int
height
,
width
;
if
(
dynamic
)
{
width
=
srcImage
.
rows
;
height
=
srcImage
.
cols
;
relInputShape
=
{
1
,
3
,
height
,
width
};
inputBlob
=
cv
::
dnn
::
blobFromImage
(
srcImage
);
}
else
{
cv
::
dnn
::
blobFromImage
(
srcImage
,
inputBlob
,
1
/
255.0
,
inputSize
,
cv
::
Scalar
(
0
,
0
,
0
),
true
,
false
);
}
// 创建输入数据
migraphx
::
parameter_map
inputData
;
inputData
[
inputName
]
=
migraphx
::
argument
{
migraphx
::
shape
(
inputShape
.
type
(),
relInputShape
),
(
float
*
)
inputBlob
.
data
};
if
(
dynamic
)
{
inputData
[
inputName
]
=
migraphx
::
argument
{
migraphx
::
shape
(
inputShape
.
type
(),
relInputShape
),
(
float
*
)
inputBlob
.
data
};
}
else
{
inputData
[
inputName
]
=
migraphx
::
argument
{
inputShape
,
(
float
*
)
inputBlob
.
data
};
}
// 推理
std
::
vector
<
migraphx
::
argument
>
inferenceResults
=
net
.
eval
(
inputData
);
...
...
Src/YOLOV5.h
View file @
28602b9a
...
...
@@ -23,9 +23,9 @@ public:
~
DetectorYOLOV5
();
ErrorCode
Initialize
(
InitializationParameterOfDetector
initializationParameterOfDetector
);
ErrorCode
Initialize
(
InitializationParameterOfDetector
initializationParameterOfDetector
,
bool
dynamic
);
ErrorCode
Detect
(
const
cv
::
Mat
&
srcImage
,
std
::
vector
<
std
::
size_t
>
&
relInputShape
,
std
::
vector
<
ResultOfDetection
>
&
resultsOfDetection
);
ErrorCode
Detect
(
const
cv
::
Mat
&
srcImage
,
std
::
vector
<
ResultOfDetection
>
&
resultsOfDetection
,
bool
dynamic
);
private:
cv
::
FileStorage
configurationFile
;
...
...
@@ -33,6 +33,7 @@ private:
migraphx
::
program
net
;
cv
::
Size
inputSize
;
std
::
string
inputName
;
std
::
string
modelPath
;
migraphx
::
shape
inputShape
;
bool
useFP16
;
...
...
Src/main.cpp
View file @
28602b9a
...
...
@@ -5,13 +5,106 @@
#include <Filesystem.h>
#include <YOLOV5.h>
int
main
()
void
MIGraphXSamplesUsage
(
char
*
programName
)
{
printf
(
"Usage : %s <index>
\n
"
,
programName
);
printf
(
"index:
\n
"
);
printf
(
"
\t
0) YOLOV5 sample.
\n
"
);
printf
(
"
\t
1) YOLOV5 Dynamic sample.
\n
"
);
}
void
Sample_YOLOV5
();
void
Sample_YOLOV5_Dynamic
();
int
main
(
int
argc
,
char
*
argv
[])
{
if
(
argc
<
2
||
argc
>
2
)
{
MIGraphXSamplesUsage
(
argv
[
0
]);
return
-
1
;
}
if
(
!
strncmp
(
argv
[
1
],
"-h"
,
2
))
{
MIGraphXSamplesUsage
(
argv
[
0
]);
return
0
;
}
switch
(
*
argv
[
1
])
{
case
'0'
:
{
Sample_YOLOV5
();
break
;
}
case
'1'
:
{
Sample_YOLOV5_Dynamic
();
break
;
}
default
:
{
MIGraphXSamplesUsage
(
argv
[
0
]);
break
;
}
}
return
0
;
}
void
Sample_YOLOV5
()
{
// 创建YOLOV5检测器
migraphxSamples
::
DetectorYOLOV5
detector
;
migraphxSamples
::
InitializationParameterOfDetector
initParamOfDetectorYOLOV5
;
initParamOfDetectorYOLOV5
.
configFilePath
=
CONFIG_FILE
;
migraphxSamples
::
ErrorCode
errorCode
=
detector
.
Initialize
(
initParamOfDetectorYOLOV5
);
migraphxSamples
::
ErrorCode
errorCode
=
detector
.
Initialize
(
initParamOfDetectorYOLOV5
,
false
);
if
(
errorCode
!=
migraphxSamples
::
SUCCESS
)
{
LOG_ERROR
(
stdout
,
"fail to initialize detector!
\n
"
);
exit
(
-
1
);
}
LOG_INFO
(
stdout
,
"succeed to initialize detector
\n
"
);
// 读取测试图片
cv
::
Mat
srcImage
=
cv
::
imread
(
"../Resource/Images/DynamicPics/image1.jpg"
,
1
);
// 推理
std
::
vector
<
migraphxSamples
::
ResultOfDetection
>
predictions
;
double
time1
=
cv
::
getTickCount
();
detector
.
Detect
(
srcImage
,
predictions
,
false
);
double
time2
=
cv
::
getTickCount
();
double
elapsedTime
=
(
time2
-
time1
)
*
1000
/
cv
::
getTickFrequency
();
LOG_INFO
(
stdout
,
"inference time:%f ms
\n
"
,
elapsedTime
);
// 获取推理结果
LOG_INFO
(
stdout
,
"========== Detection Results ==========
\n
"
);
for
(
int
i
=
0
;
i
<
predictions
.
size
();
++
i
)
{
migraphxSamples
::
ResultOfDetection
result
=
predictions
[
i
];
cv
::
rectangle
(
srcImage
,
result
.
boundingBox
,
cv
::
Scalar
(
0
,
255
,
255
),
2
);
std
::
string
label
=
cv
::
format
(
"%.2f"
,
result
.
confidence
);
label
=
result
.
className
+
" "
+
label
;
int
left
=
predictions
[
i
].
boundingBox
.
x
;
int
top
=
predictions
[
i
].
boundingBox
.
y
;
int
baseLine
;
cv
::
Size
labelSize
=
cv
::
getTextSize
(
label
,
cv
::
FONT_HERSHEY_SIMPLEX
,
0.5
,
1
,
&
baseLine
);
top
=
max
(
top
,
labelSize
.
height
);
cv
::
putText
(
srcImage
,
label
,
cv
::
Point
(
left
,
top
-
10
),
cv
::
FONT_HERSHEY_SIMPLEX
,
1
,
cv
::
Scalar
(
0
,
255
,
255
),
2
);
LOG_INFO
(
stdout
,
"box:%d %d %d %d,label:%d,confidence:%f
\n
"
,
predictions
[
i
].
boundingBox
.
x
,
predictions
[
i
].
boundingBox
.
y
,
predictions
[
i
].
boundingBox
.
width
,
predictions
[
i
].
boundingBox
.
height
,
predictions
[
i
].
classID
,
predictions
[
i
].
confidence
);
}
cv
::
imwrite
(
"Result.jpg"
,
srcImage
);
LOG_INFO
(
stdout
,
"Detection results have been saved to ./Result.jpg
\n
"
);
}
void
Sample_YOLOV5_Dynamic
()
{
// 创建YOLOV5检测器
migraphxSamples
::
DetectorYOLOV5
detector
;
migraphxSamples
::
InitializationParameterOfDetector
initParamOfDetectorYOLOV5
;
initParamOfDetectorYOLOV5
.
configFilePath
=
CONFIG_FILE
;
migraphxSamples
::
ErrorCode
errorCode
=
detector
.
Initialize
(
initParamOfDetectorYOLOV5
,
true
);
if
(
errorCode
!=
migraphxSamples
::
SUCCESS
)
{
LOG_ERROR
(
stdout
,
"fail to initialize detector!
\n
"
);
...
...
@@ -26,7 +119,7 @@ int main()
cv
::
glob
(
folder
,
imagePathList
);
for
(
int
i
=
0
;
i
<
imagePathList
.
size
();
++
i
)
{
cv
::
Mat
srcImage
=
cv
::
imread
(
imagePathList
[
i
],
1
);
cv
::
Mat
srcImage
=
cv
::
imread
(
imagePathList
[
i
],
1
);
srcImages
.
push_back
(
srcImage
);
}
...
...
@@ -37,10 +130,13 @@ int main()
for
(
int
i
=
0
;
i
<
srcImages
.
size
();
++
i
)
{
// 生成不同尺寸的图像
cv
::
resize
(
srcImages
[
i
],
srcImages
[
i
],
cv
::
Size
(
inputShapes
[
i
][
3
],
inputShapes
[
i
][
2
]));
// 推理
std
::
vector
<
migraphxSamples
::
ResultOfDetection
>
predictions
;
double
time1
=
cv
::
getTickCount
();
detector
.
Detect
(
srcImages
[
i
],
inputShapes
[
i
],
predictions
);
detector
.
Detect
(
srcImages
[
i
],
predictions
,
true
);
double
time2
=
cv
::
getTickCount
();
double
elapsedTime
=
(
time2
-
time1
)
*
1000
/
cv
::
getTickFrequency
();
LOG_INFO
(
stdout
,
"inference image%d time:%f ms
\n
"
,
i
,
elapsedTime
);
...
...
@@ -68,6 +164,4 @@ int main()
cv
::
imwrite
(
imgName
,
srcImages
[
i
]);
LOG_INFO
(
stdout
,
"Detection results have been saved to ./Result%d.jpg
\n
"
,
i
);
}
return
0
;
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment