UNeedCryDear / yolov8-opencv-onnxruntime-cpp

yolov8 hub,cpp with onnxruntime and opencv
Apache License 2.0
319 stars 56 forks source link

obb模型,onnxruntime-gpu,半精度模型推理失败 #43

Closed ZJDATY closed 8 months ago

ZJDATY commented 8 months ago

使用自己训练的模型 , yolo export model=runs/obb/train7/weights/best.pt format=onnx imgsz=(416,512) opset=12 dynamic=False simplify=true

这个导出的模型没有问题,正常使用onnx gpu 推理。

但是如果使用 yolo export model=runs/obb/train7/weights/best.pt format=onnx imgsz=(416,512) opset=12 dynamic=False simplify=true half=true device=0 导出half 模型 。就会 image 运行到程序124行,会跳到136行,return false。在使用 全精度和半精度的模型时,代码没有进行任何修改。 是不是哪边要改成float16啊。但是float16在程序里不支持。

UNeedCryDear commented 8 months ago

全FP16也不是不可以,但是由于c++基本数据类型没有半精度的概念,所以你需要自己去弄下ORT的Float_16 比较建议混合精度,也就是输入输出是FP32,其他为FP16. 具体转换可以看下这个,我之前给别人弄过了https://github.com/UNeedCryDear/yolov8-opencv-onnxruntime-cpp/issues/38#issuecomment-1853753437

ZJDATY commented 8 months ago

全FP16也不是不可以,但是由于c++基本数据类型没有半精度的概念,所以你需要自己去弄下ORT的Float_16 比较建议混合精度,也就是输入输出是FP32,其他为FP16. 具体转换可以看下这个,我之前给别人弄过了#38 (comment)

好的 我先学习一下 不会再来请教大佬。

ZJDATY commented 8 months ago

@UNeedCryDear 可以了 ,大佬 。但是令人悲伤的是 混合精度的 推理比 fp32 还慢。我用tensorrt的时候 ,fp16 会比 fp32 快接近1倍。 这难道是onnxruntime-gpu的问题吗,明天我再排查下。

UNeedCryDear commented 8 months ago

需要多次运行才行,前两三次都会慢,后面应该就会快,但是无法达到trt快一倍的速度,快一点点吧,不至于会慢。 另外还有一些显卡的问题,20系以前的显卡好像不支持fp16,我不知道是不是TRT特殊优化让这些显卡能够支持了。

ZJDATY commented 8 months ago

需要多次运行才行,前两三次都会慢,后面应该就会快,但是无法达到trt快一倍的速度,快一点点吧,不至于会慢。 另外还有一些显卡的问题,20系以前的显卡好像不支持fp16,我不知道是不是TRT特殊优化让这些显卡能够支持了。

真的是 fp16比 fp32 慢 。 链接: https://pan.baidu.com/s/1LdaWC-vrhQCU-lv1wg6tuQ?pwd=aqzu 提取码: aqzu 这个是混合精度的 image 这个是全精度的

image

很离谱的 ,不是吗?

UNeedCryDear commented 8 months ago

你给的模型我测试了下,我3060的显卡是FP16快一些,大概两三毫秒的样子。如果你确定你的显卡支持FP16的话,你可以试试将onnx的后端设置为tensorRT。 具体请自行找下

#include <tensorrt_provider_factory.h> 
这个头文件中的OrtTensorRTProviderOptionsV2模块。
ZJDATY commented 8 months ago

@UNeedCryDear 显卡确实是支持FP16的,且性能是FP32 的两倍 。之前别的模型用过 trt ,FP16 确实会快很多。明天我用另外一台3060的显卡再测试一下。我现在用的是opencv4.7+onnxruntime-gpu 1.13.1 。会不会是onnx版本的问题。 image

ZJDATY commented 8 months ago

你给的模型我测试了下,我3060的显卡是FP16快一些,大概两三毫秒的样子。如果你确定你的显卡支持FP16的话,你可以试试将onnx的后端设置为tensorRT。 具体请自行找下

#include <tensorrt_provider_factory.h> 
这个头文件中的OrtTensorRTProviderOptionsV2模块。

你给的模型我测试了下,我3060的显卡是FP16快一些,大概两三毫秒的样子。如果你确定你的显卡支持FP16的话,你可以试试将onnx的后端设置为tensorRT。 具体请自行找下

#include <tensorrt_provider_factory.h> 
这个头文件中的OrtTensorRTProviderOptionsV2模块。

我找到了一篇文章提到 OrtTensorRTProviderOptionsV2 。大佬有 关于使用 OrtTensorRTProviderOptionsV2 的示例程序吗?

UNeedCryDear commented 8 months ago

其实很简单,就是加上头文件,然后这里的set cuda这里换成tensort相关就可以了。 https://github.com/UNeedCryDear/yolov8-opencv-onnxruntime-cpp/blob/6bccffea393f019038b8c91b14f3e4fb8829e7f1/yolov8_obb_onnx.cpp#L29-L33

ZJDATY commented 8 months ago

@UNeedCryDear 好的 我再接着研究 。 但是我今天换了3060 的显卡 去跑 ,依然是混合精度 耗时长 。体积小的是混合精度,大佬你测试我的模型时有没有搞错了。

UNeedCryDear commented 8 months ago
头文件前面加上

#include <tensorrt_provider_factory.h>  //if use OrtTensorRTProviderOptionsV2
#include <onnxruntime_c_api.h>

然后set cuda这里面换成下面的语句就能切换trt的后端了。第一次生成engine模型会很慢

            OrtTensorRTProviderOptionsV2 *tensorrt_options;
            GetApi().CreateTensorRTProviderOptions(&tensorrt_options);
            const char* engine_cache_path = "./trt_engine_folder";
            std::vector<const char*> keys{ "device_id", "trt_fp16_enable", "trt_int8_enable", "trt_engine_cache_enable", "trt_engine_cache_path" };
            std::vector<const char*> values{ "0", "1", "0", "1", engine_cache_path };
            GetApi().UpdateTensorRTProviderOptions(tensorrt_options, keys.data(), values.data(), values.size()) == nullptr;

            GetApi().SessionOptionsAppendExecutionProvider_TensorRT_V2(_OrtSessionOptions, tensorrt_options);

设置trt参数啥的话,具体可以看下文档: https://onnxruntime.ai/docs/execution-providers/TensorRT-ExecutionProvider.html 文档里面还有给出怎么使用cuda stream的demo,就是由用户来控制cuda流的情况。

UNeedCryDear commented 8 months ago

@UNeedCryDear 好的 我再接着研究 。 但是我今天换了3060 的显卡 去跑 ,依然是混合精度 耗时长 。体积小的是混合精度,大佬你测试我的模型时有没有搞错了。

这个我重新运行了下,你的模型比较小,在跑exe的时候这两个时间没啥差距的,之前用的vs的debug模式跑会有点差距,切换release编译为exe就没啥区别了,模型小看不出来。如果你真的是FP16比FP32慢的话,你得看下有没有正确调用起来显卡才行。默认代码的话我的显卡调用是false,你得修改为true才行

ZJDATY commented 8 months ago

@UNeedCryDear 感谢大佬,已经全部跑通。 但是我像官方例子中那样添加cuda stream ,会找不到定义,不知道还要添加什么头文件。