4. 通用yolov6模型部署

4.1. 引言

本文档介绍了如何将yolov6架构的模型部署在cv181x开发板的操作流程,主要的操作步骤包括:

  • yolov6模型pytorch版本转换为onnx模型

  • onnx模型转换为cvimodel格式

  • 最后编写调用接口获取推理结果

4.2. pt模型转换为onnx

下载yolov6官方仓库 [meituan/YOLOv6](https://github.com/meituan/YOLOv6),下载yolov6权重文件,在yolov6文件夹下新建一个目录weights,并将下载的权重文件放在目录yolov6-main/weights/下

然后将yolo_export/yolov6_eport.py复制到yolov6-main/deploy/onnx目录下

yolo_export中的脚本可以通过SFTP获取:下载站台:sftp://218.17.249.213 帐号:cvitek_mlir_2023 密码:7&2Wd%cu5k

通过SFTP找到下图对应的文件夹:

/home/公版深度学习SDK/yolo_export.zip

通过以下命令导出onnx模型

python ./deploy/ONNX/yolov6_export.py \
  --weights ./weights/yolov6n.pt \
  --img-size 640 640
  • weights 为pytorch模型文件的路径

  • img-size 为模型输入尺寸

然后得到onnx模型

小技巧

如果输入为1080p的视频流,建议将模型输入尺寸改为384x640,可以减少冗余计算,提高推理速度,如下所示

python yolov6_export.py --weights path/to/pt/weights --img-size 384 640

4.3. onnx模型转换cvimodel

cvimodel转换操作可以参考yolo-v5移植章节的onnx模型转换cvimodel部分。

4.4. yolov6接口说明

提供预处理参数以及算法参数设置,其中参数设置:

  • YoloPreParam 输入预处理设置

    $y=(x-mean)times factor$

    • factor 预处理方差的倒数

    • mean 预处理均值

    • use_quantize_scale 预处理图片尺寸

    • format 图片格式

  • YoloAlgParam

    • cls 设置yolov6模型的分类

> yolov6是anchor-free的目标检测网络,不需要传入anchor

另外是yolov6的两个参数设置:

  • CVI_TDL_SetModelThreshold 设置置信度阈值,默认为0.5

  • CVI_TDL_SetModelNmsThreshold 设置nms阈值,默认为0.5

// set preprocess and algorithm param for yolov6 detection
// if use official model, no need to change param
CVI_S32 init_param(const cvitdl_handle_t tdl_handle) {
  // setup preprocess
  YoloPreParam preprocess_cfg =
      CVI_TDL_Get_YOLO_Preparam(tdl_handle, CVI_TDL_SUPPORTED_MODEL_YOLOV6);

  for (int i = 0; i < 3; i++) {
    printf("asign val %d \n", i);
    preprocess_cfg.factor[i] = 0.003922;
    preprocess_cfg.mean[i] = 0.0;
  }
  preprocess_cfg.format = PIXEL_FORMAT_RGB_888_PLANAR;

  printf("setup yolov6 param \n");
  CVI_S32 ret =
      CVI_TDL_Set_YOLO_Preparam(tdl_handle, CVI_TDL_SUPPORTED_MODEL_YOLOV6, preprocess_cfg);
  if (ret != CVI_SUCCESS) {
    printf("Can not set yolov6 preprocess parameters %#x\n", ret);
    return ret;
  }

  // setup yolo algorithm preprocess
  YoloAlgParam yolov6_param = CVI_TDL_Get_YOLO_Algparam(tdl_handle, CVI_TDL_SUPPORTED_MODEL_YOLOV6);
  yolov6_param.cls = 80;

  printf("setup yolov6 algorithm param \n");
  ret = CVI_TDL_Set_YOLO_Algparam(tdl_handle, CVI_TDL_SUPPORTED_MODEL_YOLOV6, yolov6_param);
  if (ret != CVI_SUCCESS) {
    printf("Can not set yolov6 algorithm parameters %#x\n", ret);
    return ret;
  }

  // set thershold
  CVI_TDL_SetModelThreshold(tdl_handle, CVI_TDL_SUPPORTED_MODEL_YOLOV6, 0.5);
  CVI_TDL_SetModelNmsThreshold(tdl_handle, CVI_TDL_SUPPORTED_MODEL_YOLOV6, 0.5);

  printf("yolov6 algorithm parameters setup success!\n");
  return ret;
}

推理代码如下:

推理代码如下:

通过本地或者流获取图片,并通过CVI_TDL_ReadImage函数读取图片,然后调用Yolov6推理接口CVI_TDL_Yolov6。推理的结果存放在obj_meta结构体中,遍历获取边界框bbox的左上角以及右下角坐标点以及object score(x1, y1, x2, y2, score),另外还有分类classes

ret = CVI_TDL_OpenModel(tdl_handle, CVI_TDL_SUPPORTED_MODEL_YOLOV6, model_path.c_str());
if (ret != CVI_SUCCESS) {
  printf("open model failed %#x!\n", ret);
  return ret;
}
printf("cvimodel open success!\n");

std::cout << "model opened:" << model_path << std::endl;

VIDEO_FRAME_INFO_S fdFrame;
ret = CVI_TDL_ReadImage(str_src_dir.c_str(), &fdFrame, PIXEL_FORMAT_RGB_888);
std::cout << "CVI_TDL_ReadImage done!\n";

if (ret != CVI_SUCCESS) {
  std::cout << "Convert out video frame failed with :" << ret << ".file:" << str_src_dir
            << std::endl;
}

cvtdl_object_t obj_meta = {0};

CVI_TDL_Yolov6(tdl_handle, &fdFrame, &obj_meta);

printf("detect number: %d\n", obj_meta.size);

for (uint32_t i = 0; i < obj_meta.size; i++) {
  printf("detect res: %f %f %f %f %f %d\n", obj_meta.info[i].bbox.x1, obj_meta.info[i].bbox.y1,
         obj_meta.info[i].bbox.x2, obj_meta.info[i].bbox.y2, obj_meta.info[i].bbox.score,
         obj_meta.info[i].classes);
}

4.5. 测试结果

转换了yolov6官方仓库给出的yolov6n以及yolov6s,测试数据集为COCO2017

其中阈值参数设置为:

  • conf_threshold: 0.03

  • nms_threshold: 0.65

分辨率均为640x640

yolov6n模型的官方导出方式性能:

测试平台

推理耗时 (ms)

带宽 (MB)

ION(MB)

MAP 0.5

MAP 0.5-0.95

pytorch

N/A

N/A

N/A

53.1

37.5

cv180x

ion分配失败

ion分配失败

15.59

量化失败

量化失败

cv181x

ion分配失败

ion分配失败

11.58

量化失败

量化失败

cv182x

39.17

47.08

11.56

量化失败

量化失败

cv183x

量化失败

量化失败

量化失败

量化失败

量化失败

cv186x

4.74

51.28

14.04

量化失败

量化失败

yolov6n模型的TDL_SDK导出方式性能:

测试平台

推理耗时 (ms)

带宽 (MB)

ION(MB)

MAP 0.5

MAP 0.5-0.95

onnx

N/A

N/A

N/A

51.6373

36.4384

cv180x

ion分配失败

ion分配失败

14.74

ion分配失败

ion分配失败

cv181x

49.11

31.35

8.46

49.8226

34.284

cv182x

34.14

30.53

8.45

49.8226

34.284

cv183x

10.89

21.22

8.49

49.8226

34.284

cv186x

4.02

36.26

12.67

41.53

27.63

yolov6s模型的官方导出方式性能:

测试平台

推理耗时 (ms)

带宽 (MB)

ION(MB)

MAP 0.5

MAP 0.5-0.95

pytorch

N/A

N/A

N/A

61.8

45

cv180x

模型转换失败

模型转换失败

模型转换失败

模型转换失败

模型转换失败

cv181x

ion分配失败

ion分配失败

27.56

量化失败

量化失败

cv182x

131.1

115.81

27.56

量化失败

量化失败

cv183x

量化失败

量化失败

量化失败

量化失败

量化失败

cv186x

14.67

100.02

29.66

量化失败

量化失败

yolov6s模型的TDL_SDK导出方式性能:

测试平台

推理耗时 (ms)

带宽 (MB)

ION(MB)

MAP 0.5

MAP 0.5-0.95

onnx

N/A

N/A

N/A

60.1657

43.5878

cv180x

ion分配失败

ion分配失败

45.27

ion分配失败

ion分配失败

cv181x

ion分配失败

ion分配失败

25.33

ion分配失败

ion分配失败

cv182x

126.04

99.16

25.32

56.2774

40.0781

cv183x

38.55

57.26

23.59

56.2774

40.0781

cv186x

13.89

85.96

29.57

46.02

31.61