Transformer部署难?TensorRT实战YOLOv7+Transformer的部署

作者 | 林大佬  编辑 | 汽车人

原文链接:https://zhuanlan.zhihu.com/p/487877753

点击下方卡片,关注“自动驾驶之心”公众号

ADAS巨卷干货,即可获取

点击进入→自动驾驶之心【模型部署】技术交流群

最近有大佬开源了YOLOv7, 大概看了一眼, 支持DETR等模型的ONNX导出,并且可以进行tensorrt推理。但是原作者并没有开源对应的权重,也没有开源onnx推理的脚本。本文就依托YOLOv7这个项目,将DETR导出到onnx,并教大家如何使用这个onnx进行tensorrt的部署。

首先clone一下原项目:
github.com/jinfagang/yolov7

84c2ff315f109b6072a1bec4333b6a10.png

DETR 权重推理验证

原来的项目其实也支持AnchorDETR,这个我没有测试,但是逻辑应该是一样的。首先大家可以从DETR官方repo下载官方的DETR权重:

https://github.com/facebookresearch/detr

但是官方的DETR权重不是基于detection2的。好在我们可以在YOLOv7里面找到一个脚本, tools/convert_detr_to_d2.py可以将原版的模型转到d2.

python tools/convert_detr_to_d2.py --source_model ./detr-r50-e632da11.pth --output_model weights/detr-r50.pth

我是这样转的,然后我们就可以得到一个detr 的d2模型。

同样,我们使用YOLOV7里面的demo脚本,来推理一下这个权重是否正确:

python demo.py --config-file configs/coco/detr/detr_256_6_6_torchvision.yaml --input ./images -c 0.26 --opts MODEL.WEIGHTS weights/detr-r50.pth
a5558089c1edc3514a729ed86ae7164d.png

结果正确!

看来YOLOv7诚不欺我!

接下来我在多跑几个图片看看:

74a710894e1594ac60e2d85a721476bb.png e155fd0deec0e1bcb7c6690eb8b71f0e.png

可以看到,DETR的模型有两个显著的特点:

  • 置信度非常高

  • 对于遮挡推理效果非常好!

这也是为什么Transformer based的检测模型,才是未来。你会发现他学到的东西非常合理,比从一大堆boudingbox里面选择概率的范式要好一点。

好了,接着我们可以进行下一步了。

DETR导出ONNX

接下来要导出onnx.

我们依旧采用YOLOv7里面的脚本来试一下,里面有提供一个 export_onnx.py。他的使用方式大概是这样:

python3 export_onnx.py --config-file configs/coco/yolox_s.yaml --input ./images/COCO_val2014_000000002153.jpg --opts MODEL.WEIGHTS ./output/coco_yolox_s/model_final.pth

也就是说,YOLOv7里面的脚本,也可以用来导出YOLOX的onnx?这有点牛逼了,挖个坑,有时间用YOLOv7试一下YOLOX的onnx部署看看。

我们使用这行命令:

python export_onnx.py --config configs/coco/detr/detr_256_6_6_torchvision.yaml --input ./images/COCO_val2014_000000002153.jpg --opts MODEL.WEIGHTS weights/detr-r50.pth

来导出ONNX.激动人心的是到了!

看到了这个输出!

[03/26 10:31:13 detectron2]: Model saved into: weights/detr-r50.onnx

但是好像遇到了一个报错:

return self._sess.run(output_names, input_feed, run_options)
onnxruntime.capi.onnxruntime_pybind11_state.RuntimeException: [ONNXRuntimeError] : 6 : RUNTIME_EXCEPTION : Non-zero status code returned while running Reshape node. Name:'Reshape_1682' Status Message: /onnxruntime_src/onnxruntime/core/providers/cpu/tensor/reshape_helper.h:41 onnxruntime::ReshapeHelper::ReshapeHelper(const onnxruntime::TensorShape&, std::vector<long int>&, bool) gsl::narrow_cast<int64_t>(input_shape.Size()) == size was false. The input tensor cannot be reshaped to the requested shape. Input shape:{2108,1,256}, requested shape:{2108,800,32}

应该是有个错误,好家伙,这后面还有一行输出:

[03/26 10:31:22 detectron2]: generate simplify onnx to: weights/detr-r50_sim.onnx
[INFO] onnx修改完成, 保存在weights/detr-r50_sim.onnx_changed.onnx.
[03/26 10:31:28 detectron2]: test if onnx export logic is right...
INFO 03.26 10:31:28 detr.py:152: [WARN] exporting onnx...
INFO 03.26 10:31:28 detr.py:363: [onnx export] in MaskedBackbone...
m:  tensor([[[False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         ...,
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False]]], device='cuda:0')
m:  torch.Size([1, 1080, 1960])
torch.Size([1, 270, 490])
m:  tensor([[[False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         ...,
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False]]], device='cuda:0')
m:  torch.Size([1, 1080, 1960])
torch.Size([1, 135, 245])
m:  tensor([[[False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         ...,
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False]]], device='cuda:0')
m:  torch.Size([1, 1080, 1960])
torch.Size([1, 68, 123])
m:  tensor([[[False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         ...,
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False],
         [False, False, False,  ..., False, False, False]]], device='cuda:0')
m:  torch.Size([1, 1080, 1960])
torch.Size([1, 34, 62])

还有一个修改ONNX的逻辑呢?这么看来,DETR的部署还真不太容易,坑很多呢。

不管怎么说,好像YOLOv7给了一个正确的onnx输出结果:

96bea593fcc643692c265d6dfe80187b.png

看起来至少是正常的。好了,我们接下来看看导出的onnx长什么样:

95ebf53ed4949637f3a55e9340f7a87a.png

好家伙!费了九牛二虎之力,借助YOLOv7的魔法,我们终于得到了DETR onnx的模型结构了!!

13d427efcba012a6009566bf39ea65c7.png

但是这个100x100x6的输出,令人无法理解。理论上应该是100x6才对。

但是我们可视化onnxsimplified的之后模型看看:

34fdcbb4d0dbe6238caec1ad189c2df0.png

这个结果是正常的,输出第一个维度应该是batchsize.

好了,就这个了,既然可以推理,那就转换一波tensorrt看看。

onnx2trt weights/detr-r50_sim.onnx                                                    main
----------------------------------------------------------------
Input filename:   weights/detr-r50_sim.onnx
ONNX IR version:  0.0.6
Opset version:    12
Producer name:    pytorch
Producer version: 1.8
Domain:           
Model version:    0
Doc string:       
----------------------------------------------------------------
Parsing model
[2022-03-26 02:38:54 WARNING] onnx2trt_utils.cpp:364: Your ONNX model has been generated with INT64 weights, while TensorRT does not natively support INT64. Attempting to cast down to INT32.
[2022-03-26 02:38:55 WARNING] Tensor DataType is determined at build time for tensors not marked as input or output.
All done

可以转TensorRT!!

好了,万事具备,只需东风了。我们接着下一步。

DETR TensorRT推理

这个推理其实就很容易了,大家可以直接使用我之前案例的神力工具连,直接配置好config.yaml就可以直接推理。

INPUT:
  # input only for dynamic input, otherwise automatically read from trt engine
  # INPUT_WIDTH: 800
  # INPUT_HEIGHT: 800
  # INPUT_CHANNEL: 3
  PREPROCESS_GPU: true
  # PREPROCESS_GPU: false

TENSORRT:
  ENGINE_PATH: ./models/detr.trt
  ONNX_PATH: ""
  FP16: true
  INT8: false
  CALIBRATION_PATH: ./calibration_files

TASK:
  SCORE_THRESH: 0.6
  # NMS_THRESH: 0.6
  # num queries in DETR
  OUTPUT_CANDIDATES: 100

然后命令行:

./build/examples/demo_detr configs/detr.yaml ~/data/road_demo.mp4

输出:

289f8100dbad4e720643fa02a740ac10.png

成功了!!!

终于可以实现DETR的TensorRT推理! 我大概测了一下速度,在1070 下,可以跑到30ms,速度已经很快了。根据YOLOv7作者说明,在2080上可以跑到10ms以内,如果fp16会更快,这个高精度的检测算法拿去部署他不香??

最后,本教程提到的所有代码和步骤,都可以在这些链接找到:
github.com/jinfagang/yolov7
manaai.cn/aisolution_detail.html?id=7

(一)视频课程来了!

自动驾驶之心为大家汇集了毫米波雷达视觉融合、高精地图、BEV感知、多传感器标定、传感器部署、自动驾驶协同感知、语义分割、自动驾驶仿真、L4感知、决策规划、轨迹预测等多个方向学习视频,欢迎大家自取(扫码进入学习)

9df32e00eaab04d361e0e2822c2ba292.png

(扫码学习最新视频)

视频官网:www.zdjszx.com

(二)国内首个自动驾驶学习社区

近1000人的交流社区,和20+自动驾驶技术栈学习路线,想要了解更多自动驾驶感知(分类、检测、分割、关键点、车道线、3D目标检测、Occpuancy、多传感器融合、目标跟踪、光流估计、轨迹预测)、自动驾驶定位建图(SLAM、高精地图)、自动驾驶规划控制、领域技术方案、AI模型部署落地实战、行业动态、岗位发布,欢迎扫描下方二维码,加入自动驾驶之心知识星球,这是一个真正有干货的地方,与领域大佬交流入门、学习、工作、跳槽上的各类难题,日常分享论文+代码+视频,期待交流!

d2dd407e4101f66a4012e94420074b48.jpeg

(三)自动驾驶之心】全栈技术交流群

自动驾驶之心是首个自动驾驶开发者社区,聚焦目标检测、语义分割、全景分割、实例分割、关键点检测、车道线、目标跟踪、3D目标检测、BEV感知、多传感器融合、SLAM、光流估计、深度估计、轨迹预测、高精地图、NeRF、规划控制、模型部署落地、自动驾驶仿真测试、产品经理、硬件配置、AI求职交流等方向;

5ee1cc7fd54d9c6e22eb548de9755073.jpeg

添加汽车人助理微信邀请入群

备注:学校/公司+方向+昵称

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值