Commit cfaa9eb1 authored by shizhm's avatar shizhm
Browse files

修改yolov5示例为动态shape推理

parent ca5fdd93
# YOLOV5检测器 # YOLOV5检测器
YOLOV5模型是目前工业界使用较多的算法,官方提供了多个不同版本的预训练模型,本份文档主要介绍了如何将MIGraphX推理结果进行模型初始化、预处理以及后处理,该示例推理流程对YOLOV5其他版本的模型同样适用。 YOLOV5模型是目前工业界使用较多的算法,官方提供了多个不同版本的预训练模型,本份文档主要介绍了如何基于migraphx构建YOLOV5动态shape推理,该示例推理流程对YOLOV5其他版本的模型同样适用。
## 模型简介 ## 模型简介
...@@ -21,7 +21,7 @@ samples工程中的Resource/Configuration.xml文件的DetectorYOLOV5节点表示 ...@@ -21,7 +21,7 @@ samples工程中的Resource/Configuration.xml文件的DetectorYOLOV5节点表示
- ObjectThreshold:用于判断anchor内部是否有物体 - ObjectThreshold:用于判断anchor内部是否有物体
``` ```
<ModelPath>"../Resource/Models/YOLOV5s.onnx"</ModelPath> <ModelPath>"../Resource/Models/YOLOV5s_Nx3xNxN.onnx"</ModelPath>
<ClassNameFile>"../Resource/Models/coco.names"</ClassNameFile> <ClassNameFile>"../Resource/Models/coco.names"</ClassNameFile>
<UseFP16>0</UseFP16><!--是否使用FP16--> <UseFP16>0</UseFP16><!--是否使用FP16-->
<NumberOfClasses>80</NumberOfClasses><!--类别数(不包括背景类),COCO:80,VOC:20--> <NumberOfClasses>80</NumberOfClasses><!--类别数(不包括背景类),COCO:80,VOC:20-->
...@@ -32,21 +32,22 @@ samples工程中的Resource/Configuration.xml文件的DetectorYOLOV5节点表示 ...@@ -32,21 +32,22 @@ samples工程中的Resource/Configuration.xml文件的DetectorYOLOV5节点表示
## 模型初始化 ## 模型初始化
模型初始化首先通过parse_onnx()函数加载YOLOV5的onnx模型,并可以通过program的get_parameter_shapes()函数获取网络的输入属性。完成模型加载之后需要使用compile()方法编译模型,编译模式使用migraphx::gpu::target{}设为GPU模式,编译过程主要基于MIGraphX IR完成各种优化。同时如果需要使用低精度量化进行推理,可以使用quantize_fp16()函数实现。 模型初始化首先通过parse_onnx()函数加载YOLOV5的onnx模型,本示例构建YOLOV5动态shape推理,所以需要设置模型输入的最大shape,本示例设为{1,3,800,800},并可以通过program的get_parameter_shapes()函数获取网络的输入属性。完成模型加载之后需要使用compile()方法编译模型,编译模式使用migraphx::gpu::target{}设为GPU模式,编译过程主要基于MIGraphX IR完成各种优化。同时如果需要使用低精度量化进行推理,可以使用quantize_fp16()函数实现。
``` ```
ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializationParameterOfDetector) ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializationParameterOfDetector)
{ {
... ...
//模型加载 migraphx::onnx_options onnx_options;
net = migraphx::parse_onnx(modelPath); 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()); LOG_INFO(stdout,"succeed to load model: %s\n",GetFileName(modelPath).c_str());
// 获取模型输入属性 // 获取模型输入属性
std::pair<std::string, migraphx::shape> inputAttribute=*(net.get_parameter_shapes().begin()); std::unordered_map<std::string, migraphx::shape> inputMap=net.get_parameter_shapes();
inputName=inputAttribute.first; inputName=inputMap.begin()->first;
inputShape=inputAttribute.second; inputShape=inputMap.begin()->second;
int N=inputShape.lens()[0]; int N=inputShape.lens()[0];
int C=inputShape.lens()[1]; int C=inputShape.lens()[1];
int H=inputShape.lens()[2]; int H=inputShape.lens()[2];
...@@ -64,11 +65,12 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ ...@@ -64,11 +65,12 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
// 编译模型 // 编译模型
migraphx::compile_options options; migraphx::compile_options options;
options.device_id=0; // 设置GPU设备,默认为0号设备 options.device_id=0;
options.offload_copy=true; // 设置offload_copy options.offload_copy=true;
net.compile(gpuTarget,options); net.compile(gpuTarget,options);
LOG_INFO(stdout,"succeed to compile model: %s\n",GetFileName(modelPath).c_str()); LOG_INFO(stdout,"succeed to compile model: %s\n",GetFileName(modelPath).c_str());
... ...
} }
``` ```
...@@ -79,19 +81,20 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ ...@@ -79,19 +81,20 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
1. 转换数据排布为NCHW 1. 转换数据排布为NCHW
2. 归一化[0.0, 1.0] 2. 归一化[0.0, 1.0]
3. 将输入数据的尺寸变换到YOLOV5输入大小(1,3,608,608) 3. 将输入数据的尺寸变换到YOLOV5动态输入大小,relInputShape为每次实际inputshape
``` ```
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDetection> &resultsOfDetection) 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 // 预处理并转换为NCHW
cv::Mat inputBlob; cv::Mat inputBlob;
blobFromImage(srcImage, // 输入数据 blobFromImage(srcImage, // 输入数据
inputBlob, // 输出数据 inputBlob, // 输出数据
1 / 255.0, //归一化 1 / 255.0, //归一化
inputSize, //YOLOV5输入尺寸,本示例为608x608 inputSize, //YOLOV5输入尺寸
Scalar(0, 0, 0), //未减去均值 Scalar(0, 0, 0), //未减去均值
true, //转换RB通道 true, //转换RB通道
false); false);
...@@ -105,13 +108,13 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe ...@@ -105,13 +108,13 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe
完成图像预处理以及YOLOV5目标检测相关参数设置之后开始执行推理,利用migraphx推理计算得到YOLOV5模型的输出。 完成图像预处理以及YOLOV5目标检测相关参数设置之后开始执行推理,利用migraphx推理计算得到YOLOV5模型的输出。
``` ```
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDetection> &resultsOfDetection) ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection)
{ {
... ...
// 创建输入数据 // 创建输入数据
std::unordered_map<std::string, migraphx::shape> inputData; migraphx::parameter_map inputData;
inputData[inputName]= migraphx::argument{inputShape, (float*)inputBlob.data}; inputData[inputName]= migraphx::argument{migraphx::shape(inputShape.type(), relInputShape), (float*)inputBlob.data};
// 推理 // 推理
std::vector<migraphx::argument> inferenceResults = net.eval(inputData); std::vector<migraphx::argument> inferenceResults = net.eval(inputData);
...@@ -137,20 +140,20 @@ YOLOV5的MIGraphX推理结果inferenceResults是一个std::vector< migraphx::arg ...@@ -137,20 +140,20 @@ YOLOV5的MIGraphX推理结果inferenceResults是一个std::vector< migraphx::arg
- 第二步根据confidenceThreshold阈值进行筛选,当满足第一步阈值anchor的最大置信度得分maxClassScore大于该阈值,则进一步获取当前anchor的坐标信息和预测物体类别信息,小于该阈值则不做处理。 - 第二步根据confidenceThreshold阈值进行筛选,当满足第一步阈值anchor的最大置信度得分maxClassScore大于该阈值,则进一步获取当前anchor的坐标信息和预测物体类别信息,小于该阈值则不做处理。
``` ```
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDetection> &resultsOfDetection) ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection)
{ {
... ...
//获取先验框的个数numProposal=22743 //获取先验框的个数
numProposal = outs[0].size[1]; int numProposal = outs[0].size[1];
//每个anchor的预测信息数量numOut=85 int numOut = outs[0].size[2];
numOut = outs[0].size[2]; //变换输出的维度
outs[0] = outs[0].reshape(0, numProposal); outs[0] = outs[0].reshape(0, numProposal);
//生成先验框
std::vector<float> confidences; std::vector<float> confidences;
std::vector<cv::Rect> boxes; std::vector<cv::Rect> boxes;
std::vector<int> classIds; std::vector<int> classIds;
//原图尺寸与模型输入尺寸的缩放比例
float ratioh = (float)srcImage.rows / inputSize.height, ratiow = (float)srcImage.cols / inputSize.width; float ratioh = (float)srcImage.rows / inputSize.height, ratiow = (float)srcImage.cols / inputSize.width;
//计算cx,cy,w,h,box_sore,class_sore //计算cx,cy,w,h,box_sore,class_sore
...@@ -158,32 +161,22 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe ...@@ -158,32 +161,22 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe
float* pdata = (float*)outs[0].data; float* pdata = (float*)outs[0].data;
for (n = 0; n < numProposal; n++) for (n = 0; n < numProposal; n++)
{ {
//获取当前anchor是否包含物体的概率值
float boxScores = pdata[4]; float boxScores = pdata[4];
//第一次筛选,判断anchor内是否包含物体
if (boxScores > yolov5Parameter.objectThreshold) if (boxScores > yolov5Parameter.objectThreshold)
{ {
//获取每个anchor内部预测的80个类别概率信息
cv::Mat scores = outs[0].row(rowInd).colRange(5, numOut); cv::Mat scores = outs[0].row(rowInd).colRange(5, numOut);
cv::Point classIdPoint; cv::Point classIdPoint;
double maxClassScore; double maxClassScore;
//获取80个类别中最大概率值和对应的类别ID
cv::minMaxLoc(scores, 0, &maxClassScore, 0, &classIdPoint); cv::minMaxLoc(scores, 0, &maxClassScore, 0, &classIdPoint);
maxClassScore *= boxScores; maxClassScore *= boxScores;
//第二次筛选,判断当前anchor的最大置信度得分是否满足阈值
if (maxClassScore > yolov5Parameter.confidenceThreshold) if (maxClassScore > yolov5Parameter.confidenceThreshold)
{ {
const int classIdx = classIdPoint.x; const int classIdx = classIdPoint.x;
//将每个anchor坐标按缩放比例映射到原图
float cx = pdata[0] * ratiow; float cx = pdata[0] * ratiow;
float cy = pdata[1] * ratioh; float cy = pdata[1] * ratioh;
float w = pdata[2] * ratiow; float w = pdata[2] * ratiow;
float h = pdata[3] * ratioh; float h = pdata[3] * ratioh;
//获取anchor的左上角坐标
int left = int(cx - 0.5 * w); int left = int(cx - 0.5 * w);
int top = int(cy - 0.5 * h); int top = int(cy - 0.5 * h);
...@@ -203,7 +196,7 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe ...@@ -203,7 +196,7 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe
为了消除重叠锚框,输出最终的YOLOV5目标检测结果,执行非极大值抑制对筛选之后的anchor进行处理,最后保存检测结果到resultsOfDetection中。 为了消除重叠锚框,输出最终的YOLOV5目标检测结果,执行非极大值抑制对筛选之后的anchor进行处理,最后保存检测结果到resultsOfDetection中。
``` ```
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDetection> &resultsOfDetection) ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection)
{ {
... ...
......
# YOLOV5检测器 # YOLOV5检测器
本份文档主要介绍如何基于MIGraphX构建YOLOV5的Python推理示例,根据文档描述可以了解怎样运行该Python示例得到YOLOV5的目标检测结果。 本份文档主要介绍如何基于MIGraphX构建YOLOV5的动态shape推理Python示例,根据文档描述可以了解怎样运行该Python示例得到YOLOV5的目标检测结果。
## 模型简介 ## 模型简介
...@@ -14,7 +14,7 @@ YOLOV5是一种单阶段目标检测算法,该算法在YOLOV4的基础上添 ...@@ -14,7 +14,7 @@ YOLOV5是一种单阶段目标检测算法,该算法在YOLOV4的基础上添
1. 转换数据排布为NCHW 1. 转换数据排布为NCHW
2. 归一化[0.0, 1.0] 2. 归一化[0.0, 1.0]
3. 调整输入数据的尺寸为(1,3,608,608) 3. 调整输入数据的尺寸
``` ```
def prepare_input(self, image): def prepare_input(self, image):
...@@ -34,7 +34,11 @@ def prepare_input(self, image): ...@@ -34,7 +34,11 @@ def prepare_input(self, image):
return input_img return input_img
``` ```
其中模型输入的inputWidth、inputHeight通过migraphx对输入模型进行解析获取,代码位置见YOLOV5类初始化位置。 其中模型输入的inputWidth、inputHeight为每次动态输入shape。
## 推理
执行YOLOV5动态输入推理,首先需要对YOLOV5的动态模型进行解析、编译,与静态推理不同的是,动态shape推理需要设置模型输入的最大shape,本示例设为[1,3,800,800]。
``` ```
class YOLOv5: class YOLOv5:
...@@ -47,31 +51,33 @@ class YOLOv5: ...@@ -47,31 +51,33 @@ class YOLOv5:
self.classNames = list(map(lambda x: x.strip(), open('../Resource/Models/coco.names', 'r').readlines())) self.classNames = list(map(lambda x: x.strip(), open('../Resource/Models/coco.names', 'r').readlines()))
# 解析推理模型 # 解析推理模型
self.model = migraphx.parse_onnx(path) maxInput={"images":[1,3,800,800]}
self.model = migraphx.parse_onnx(path, map_input_dims=maxInput)
# 获取模型的输入name # 获取模型的输入name
self.inputName = self.model.get_parameter_names()[0] self.inputName = self.model.get_parameter_names()[0]
# 获取模型的输入尺寸 # 获取模型的输入尺寸
inputShape = self.model.get_parameter_shapes()[self.inputName].lens() inputShape = self.model.get_parameter_shapes()[self.inputName].lens()
self.inputHeight = int(inputShape[2]) print("inputName:{0} \ninputMaxShape:{1}".format(self.inputName, inputShape))
self.inputWidth = int(inputShape[3])
# 模型编译
self.model.compile(t=migraphx.get_target("gpu"), device_id=0) # device_id: 设置GPU设备,默认为0号设备
print("Success to compile")
...
``` ```
## 推理 模型初始化完成之后开始进行推理,对输入数据进行前向计算得到模型的输出result,在detect函数中调用定义的process_output函数对result进行后处理,得到图像中含有物体的anchor坐标信息、类别置信度、类别ID。
输入图像预处理完成之后开始进行推理,首先需要利用migraphx进行编译,然后对输入数据进行前向计算得到模型的输出result,在detect函数中调用定义的process_output函数对result进行后处理,得到图像中含有物体的anchor坐标信息、类别置信度、类别ID。
``` ```
def detect(self, image): def detect(self, image, input_shape):
# 输入图像预处理 self.inputWidth = input_shape[3]
self.inputHeight = input_shape[2]
# 输入图片预处理
input_img = self.prepare_input(image) input_img = self.prepare_input(image)
# 模型编译
self.model.compile(t=migraphx.get_target("gpu"), device_id=0) # device_id: 设置GPU设备,默认为0号设备
print("Success to compile")
# 执行推理 # 执行推理
print("Start to inference")
start = time.time() start = time.time()
result = self.model.run({self.model.get_parameter_names()[0]: input_img}) result = self.model.run({self.model.get_parameter_names()[0]: input_img})
print('net forward time: {:.4f}'.format(time.time() - start)) print('net forward time: {:.4f}'.format(time.time() - start))
...@@ -110,6 +116,19 @@ def process_output(self, output): ...@@ -110,6 +116,19 @@ def process_output(self, output):
return boxes[indices], scores[indices], class_ids[indices] 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
return boxes_
def rescale_boxes(self, boxes): def rescale_boxes(self, boxes):
# 对anchor尺寸进行变换 # 对anchor尺寸进行变换
input_shape = np.array([self.inputWidth, self.inputHeight, self.inputWidth, self.inputHeight]) input_shape = np.array([self.inputWidth, self.inputHeight, self.inputWidth, self.inputHeight])
......
...@@ -17,26 +17,27 @@ class YOLOv5: ...@@ -17,26 +17,27 @@ class YOLOv5:
self.classNames = list(map(lambda x: x.strip(), open('../Resource/Models/coco.names', 'r').readlines())) self.classNames = list(map(lambda x: x.strip(), open('../Resource/Models/coco.names', 'r').readlines()))
# 解析推理模型 # 解析推理模型
self.model = migraphx.parse_onnx(path) maxInput={"images":[1,3,800,800]}
self.model = migraphx.parse_onnx(path, map_input_dims=maxInput)
# 获取模型的输入name # 获取模型的输入name
self.inputName = self.model.get_parameter_names()[0] self.inputName = self.model.get_parameter_names()[0]
# 获取模型的输入尺寸 # 获取模型的输入尺寸
inputShape = self.model.get_parameter_shapes()[self.inputName].lens() inputShape = self.model.get_parameter_shapes()[self.inputName].lens()
self.inputHeight = int(inputShape[2]) print("inputName:{0} \ninputMaxShape:{1}".format(self.inputName, inputShape))
self.inputWidth = int(inputShape[3])
print("inputName:{0} \ninputShape:{1}".format(self.inputName, inputShape)) # 模型编译
self.model.compile(t=migraphx.get_target("gpu"), device_id=0) # device_id: 设置GPU设备,默认为0号设备
print("Success to compile")
def detect(self, image): def detect(self, image, input_shape):
self.inputWidth = input_shape[3]
self.inputHeight = input_shape[2]
# 输入图片预处理 # 输入图片预处理
input_img = self.prepare_input(image) input_img = self.prepare_input(image)
# 模型编译
self.model.compile(t=migraphx.get_target("gpu"), device_id=0) # device_id: 设置GPU设备,默认为0号设备
print("Success to compile")
# 执行推理 # 执行推理
print("Start to inference")
start = time.time() start = time.time()
result = self.model.run({self.model.get_parameter_names()[0]: input_img}) result = self.model.run({self.model.get_parameter_names()[0]: input_img})
print('net forward time: {:.4f}'.format(time.time() - start)) print('net forward time: {:.4f}'.format(time.time() - start))
...@@ -114,28 +115,50 @@ class YOLOv5: ...@@ -114,28 +115,50 @@ class YOLOv5:
labelSize, baseLine = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1) labelSize, baseLine = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.5, 1)
cv2.putText(image, label, (cx, cy - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), thickness=2) cv2.putText(image, label, (cx, cy - 10), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), thickness=2)
return image return image
def read_images(image_path):
image_lists = []
for image_name in os.listdir(image_path):
image = cv2.imread(image_path +"/" + image_name, 1)
image_lists.append(image)
image_lists.reverse()
return image_lists
if __name__ == '__main__': if __name__ == '__main__':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--imgpath', type=str, default='../Resource/Images/bus.jpg', help="image path") parser.add_argument('--imgpath', type=str, default='../Resource/Images/DynamicPics', help="image path")
parser.add_argument('--modelpath', type=str, default='../Resource/Models/yolov5s.onnx', help="onnx filepath") 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('--objectThreshold', default=0.5, type=float, help='class confidence')
parser.add_argument('--confThreshold', default=0.25, 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('--nmsThreshold', default=0.5, type=float, help='nms iou thresh')
args = parser.parse_args() args = parser.parse_args()
yolov5_detector = YOLOv5(args.modelpath, obj_thres=args.objectThreshold, conf_thres=args.confThreshold, # 设置动态输入shape
iou_thres=args.nmsThreshold) input_shapes = []
srcimg = cv2.imread(args.imgpath, 1) input_shapes.append([1,3,416,416])
input_shapes.append([1,3,608,608])
boxes, scores, class_ids = yolov5_detector.detect(srcimg)
# 读取测试图像
dstimg = yolov5_detector.draw_detections(srcimg, boxes, scores, class_ids) image_lists = read_images(args.imgpath)
# 保存检测结果 # 推理
cv2.imwrite("./Result.jpg", dstimg) yolov5_detector = YOLOv5(args.modelpath, obj_thres=args.objectThreshold,
print("Success to save result") conf_thres=args.confThreshold, iou_thres=args.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])
dstimg = yolov5_detector.draw_detections(image, boxes, scores, class_ids)
# 保存检测结果
result_name = "Result{}.jpg".format(i)
cv2.imwrite(result_name, dstimg)
print("Success to save results")
......
...@@ -43,9 +43,13 @@ pip install -r requirements.txt ...@@ -43,9 +43,13 @@ pip install -r requirements.txt
### 运行示例 ### 运行示例
YoloV5模型的推理示例程序是YoloV5_infer_migraphx.py,在Python目录下使用如下命令运行该推理示例: YoloV5模型的推理示例程序是YoloV5_infer_migraphx.py,本示例执行YOLOV5动态shape推理,在Python目录下使用如下命令运行该推理示例:
``` ```
# 开启环境变量
export MIGRAPHX_DYNAMIC_SHAPE=1
# 运行示例
python YoloV5_infer_migraphx.py \ python YoloV5_infer_migraphx.py \
--imgpath 测试图像路径 \ --imgpath 测试图像路径 \
--modelpath onnx模型路径 \ --modelpath onnx模型路径 \
...@@ -56,7 +60,9 @@ python YoloV5_infer_migraphx.py \ ...@@ -56,7 +60,9 @@ python YoloV5_infer_migraphx.py \
程序运行结束会在当前目录生成YoloV5检测结果图像。 程序运行结束会在当前目录生成YoloV5检测结果图像。
<img src="./Resource/Images/Result.jpg" alt="Result_2" style="zoom: 50%;" /> <img src="./Resource/Images/Result0.jpg" alt="Result_2" style="zoom: 50%;" />
<img src="./Resource/Images/Result1.jpg" alt="Result1" style="zoom: 50%;" />
## C++版本推理 ## C++版本推理
...@@ -115,7 +121,7 @@ source ~/.bashrc ...@@ -115,7 +121,7 @@ source ~/.bashrc
### 运行示例 ### 运行示例
成功编译YoloV5工程后,执行如下命令运行该示例: 成功编译YoloV5工程后,执行如下命令运行动态shape推理该示例:
``` ```
# 进入yolov5 migraphx工程根目录 # 进入yolov5 migraphx工程根目录
...@@ -124,13 +130,18 @@ cd <path_to_yolov5_migraphx> ...@@ -124,13 +130,18 @@ cd <path_to_yolov5_migraphx>
# 进入build目录 # 进入build目录
cd ./build/ cd ./build/
# 开启环境变量
export MIGRAPHX_DYNAMIC_SHAPE=1
# 执行示例程序 # 执行示例程序
./YOLOV5 ./YOLOV5
``` ```
程序运行结束会在build目录生成YoloV5检测结果图像。 程序运行结束会在build目录生成YoloV5动态shape推理检测结果图像。
<img src="./Resource/Images/Result0.jpg" alt="Result" style="zoom:50%;" />
<img src="./Resource/Images/Result.jpg" alt="Result" style="zoom:50%;" /> <img src="./Resource/Images/Result1.jpg" alt="Result" style="zoom:50%;" />
## 源码仓库及问题反馈 ## 源码仓库及问题反馈
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<!--YOLOV5检测器 --> <!--YOLOV5检测器 -->
<DetectorYOLOV5> <DetectorYOLOV5>
<ModelPath>"../Resource/Models/yolov5s.onnx"</ModelPath> <ModelPath>"../Resource/Models/yolov5s_Nx3xNxN.onnx"</ModelPath>
<ClassNameFile>"../Resource/Models/coco.names"</ClassNameFile> <ClassNameFile>"../Resource/Models/coco.names"</ClassNameFile>
<UseFP16>0</UseFP16><!--是否使用FP16--> <UseFP16>0</UseFP16><!--是否使用FP16-->
<NumberOfClasses>80</NumberOfClasses><!--类别数(不包括背景类),COCO:80,VOC:20--> <NumberOfClasses>80</NumberOfClasses><!--类别数(不包括背景类),COCO:80,VOC:20-->
......
...@@ -53,7 +53,10 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ ...@@ -53,7 +53,10 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
LOG_ERROR(stdout,"%s not exist!\n",modelPath.c_str()); LOG_ERROR(stdout,"%s not exist!\n",modelPath.c_str());
return MODEL_NOT_EXIST; return MODEL_NOT_EXIST;
} }
net = migraphx::parse_onnx(modelPath);
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()); LOG_INFO(stdout,"succeed to load model: %s\n",GetFileName(modelPath).c_str());
// 获取模型输入属性 // 获取模型输入属性
...@@ -77,7 +80,7 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ ...@@ -77,7 +80,7 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
// 编译模型 // 编译模型
migraphx::compile_options options; migraphx::compile_options options;
options.device_id=0; // 设置GPU设备,默认为0号设备 options.device_id=0;
options.offload_copy=true; options.offload_copy=true;
net.compile(gpuTarget,options); net.compile(gpuTarget,options);
LOG_INFO(stdout,"succeed to compile model: %s\n",GetFileName(modelPath).c_str()); LOG_INFO(stdout,"succeed to compile model: %s\n",GetFileName(modelPath).c_str());
...@@ -103,7 +106,7 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ ...@@ -103,7 +106,7 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
} }
// log // log
LOG_INFO(stdout,"InputSize:%dx%d\n",inputSize.width,inputSize.height); LOG_INFO(stdout,"InputMaxSize:%dx%d\n",inputSize.width,inputSize.height);
LOG_INFO(stdout,"InputName:%s\n",inputName.c_str()); LOG_INFO(stdout,"InputName:%s\n",inputName.c_str());
LOG_INFO(stdout,"ConfidenceThreshold:%f\n",yolov5Parameter.confidenceThreshold); LOG_INFO(stdout,"ConfidenceThreshold:%f\n",yolov5Parameter.confidenceThreshold);
LOG_INFO(stdout,"NMSThreshold:%f\n",yolov5Parameter.nmsThreshold); LOG_INFO(stdout,"NMSThreshold:%f\n",yolov5Parameter.nmsThreshold);
...@@ -114,7 +117,7 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ ...@@ -114,7 +117,7 @@ ErrorCode DetectorYOLOV5::Initialize(InitializationParameterOfDetector initializ
} }
ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDetection> &resultsOfDetection) ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection)
{ {
if(srcImage.empty()||srcImage.type()!=CV_8UC3) if(srcImage.empty()||srcImage.type()!=CV_8UC3)
{ {
...@@ -122,6 +125,8 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe ...@@ -122,6 +125,8 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe
return IMAGE_ERROR; return IMAGE_ERROR;
} }
inputSize = cv::Size(relInputShape[3], relInputShape[2]);
// 数据预处理并转换为NCHW格式 // 数据预处理并转换为NCHW格式
cv::Mat inputBlob; cv::Mat inputBlob;
cv::dnn::blobFromImage(srcImage, cv::dnn::blobFromImage(srcImage,
...@@ -133,8 +138,8 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe ...@@ -133,8 +138,8 @@ ErrorCode DetectorYOLOV5::Detect(const cv::Mat &srcImage, std::vector<ResultOfDe
false); false);
// 创建输入数据 // 创建输入数据
std::unordered_map<std::string, migraphx::argument> inputData; migraphx::parameter_map inputData;
inputData[inputName]= migraphx::argument{inputShape, (float*)inputBlob.data}; inputData[inputName]= migraphx::argument{migraphx::shape(inputShape.type(), relInputShape), (float*)inputBlob.data};
// 推理 // 推理
std::vector<migraphx::argument> inferenceResults = net.eval(inputData); std::vector<migraphx::argument> inferenceResults = net.eval(inputData);
......
...@@ -25,7 +25,7 @@ public: ...@@ -25,7 +25,7 @@ public:
ErrorCode Initialize(InitializationParameterOfDetector initializationParameterOfDetector); ErrorCode Initialize(InitializationParameterOfDetector initializationParameterOfDetector);
ErrorCode Detect(const cv::Mat &srcImage, std::vector<ResultOfDetection> &resultsOfDetection); ErrorCode Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection);
private: private:
cv::FileStorage configurationFile; cv::FileStorage configurationFile;
......
...@@ -19,38 +19,55 @@ int main() ...@@ -19,38 +19,55 @@ int main()
} }
LOG_INFO(stdout, "succeed to initialize detector\n"); LOG_INFO(stdout, "succeed to initialize detector\n");
// 读取测试图片 // 读取测试图像
cv::Mat srcImage = cv::imread("../Resource/Images/bus.jpg",1); std::vector<cv::Mat> srcImages;
cv::String folder = "../Resource/Images/DynamicPics";
// 推理 std::vector<cv::String> imagePathList;
std::vector<migraphxSamples::ResultOfDetection> predictions; cv::glob(folder,imagePathList);
double time1 = cv::getTickCount(); for (int i = 0; i < imagePathList.size(); ++i)
detector.Detect(srcImage,predictions);
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:: Mat srcImage=cv::imread(imagePathList[i], 1);
cv::rectangle(srcImage,result.boundingBox,cv::Scalar(0,255,255),2); srcImages.push_back(srcImage);
}
std::string label = cv::format("%.2f", result.confidence);
label = result.className + " " + label; // 设置动态推理shape
int left = predictions[i].boundingBox.x; std::vector<std::vector<std::size_t>> inputShapes;
int top = predictions[i].boundingBox.y; inputShapes.push_back({1,3,416,416});
int baseLine; inputShapes.push_back({1,3,608,608});
cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
top = max(top, labelSize.height); for (int i = 0; i < srcImages.size(); ++i)
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, std::vector<migraphxSamples::ResultOfDetection> predictions;
predictions[i].boundingBox.y,predictions[i].boundingBox.width,predictions[i].boundingBox.height,predictions[i].classID,predictions[i].confidence); double time1 = cv::getTickCount();
detector.Detect(srcImages[i], inputShapes[i], predictions);
double time2 = cv::getTickCount();
double elapsedTime = (time2 - time1)*1000 / cv::getTickFrequency();
LOG_INFO(stdout, "inference image%d time:%f ms\n", i, elapsedTime);
// 获取推理结果
LOG_INFO(stdout,"========== Detection Image%d Results ==========\n", i);
for(int j=0;j<predictions.size();++j)
{
migraphxSamples::ResultOfDetection result=predictions[j];
cv::rectangle(srcImages[i],result.boundingBox,cv::Scalar(0,255,255),2);
std::string label = cv::format("%.2f", result.confidence);
label = result.className + " " + label;
int left = predictions[j].boundingBox.x;
int top = predictions[j].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(srcImages[i], 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[j].boundingBox.x,
predictions[j].boundingBox.y,predictions[j].boundingBox.width,predictions[j].boundingBox.height,predictions[j].classID,predictions[j].confidence);
}
std::string imgName = cv::format("Result%d.jpg", i);
cv::imwrite(imgName, srcImages[i]);
LOG_INFO(stdout,"Detection results have been saved to ./Result%d.jpg\n", i);
} }
cv::imwrite("Result.jpg",srcImage);
LOG_INFO(stdout,"Detection results have been saved to ./Result.jpg\n");
return 0; return 0;
} }
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment