UNeedCryDear / yolov8-opencv-onnxruntime-cpp

yolov8 hub,cpp with onnxruntime and opencv
Apache License 2.0
341 stars 60 forks source link

关于GPU推理比CPU慢 #32

Closed pcycccccc closed 1 year ago

pcycccccc commented 1 year ago

您好,很感谢您提供的推理代码帮助我完成了推理部署任务,YOLOv8的目标检测和图像分割算法我都有试过在CPU跑过,我最近在使用配置好的Opencv-CUDA版进行yolov8-seg推理的时候出现了GPU推理达到300多ms,而CPU推理仅90ms左右(仅测试一张图片的情况下,为了避免第一次测试加载造成的时间太长,我在release上测试了多遍都差不多是这个数值)。 我的GPU使用的是英伟达的GeForce RTX 3080,显卡性能不算差,推理的时候,确实是在显卡上跑(从任务管理器的性能上也能看出来),但是不明白为啥GPU怎么跑都没有CPU快,不知道哪里出了问题,希望大佬能给我点意见。

补充一下:我使用的是yolov8seg-opencv-dnn的代码

pcycccccc commented 1 year ago

大佬,我试了一下你的yolov8seg-onnxruntime-cpp的代码来跑,在推理一张图片(416*416)的情况下,GPU还是跑的比CPU慢,每次推理都需要加载一次模型,如何做到下次不用加载模型也能够推理呢?

UNeedCryDear commented 1 year ago

关于第一个问题,GPU比CPU慢,一般来说这个会是第一次推理的时候会有这个问题(有些是前两三张都会),所以一般统计GPU速度的时候是不计算前几张的速度的,后面就会正常比CPU快很多。

第二,你为什么会是跑一次加载一次模型呢?你只要正常read一次model就可以了啊,dnn的话是会将Net返回的,你下次需要在哪里推理,就在哪里传入Net就可以了啊,我不知道你修改是怎么用的,我给你个demo你看下就明白了。

Yolov8 task_detect;
Net net;
task_detect.ReadModel(net, model_path, false); //只读一次,这里就可以拿到net
for(int i=0;i<imgs.size();++i){
    task_detect.Detect(imgs[i], net, result); //这里在for循环中使用net,不需要每次去读取
}
pcycccccc commented 1 year ago

n的话是会将Net返回的,你下次需要在哪里推理,就在哪里传入Net就可以了啊,我不知道你修改是怎么用的,我给你个demo你看下就明白了

我没有修改什么比较重要的代码,只是去掉了没有用到的函数,主函数上

关于第一个问题,GPU比CPU慢,一般来说这个会是第一次推理的时候会有这个问题(有些是前两三张都会),所以一般统计GPU速度的时候是不计算前几张的速度的,后面就会正常比CPU快很多。

第二,你为什么会是跑一次加载一次模型呢?你只要正常read一次model就可以了啊,dnn的话是会将Net返回的,你下次需要在哪里推理,就在哪里传入Net就可以了啊,我不知道你修改是怎么用的,我给你个demo你看下就明白了。

Yolov8 task_detect;
Net net;
task_detect.ReadModel(net, model_path, false); //只读一次,这里就可以拿到net
for(int i=0;i<imgs.size();++i){
    task_detect.Detect(imgs[i], net, result); //这里在for循环中使用net,不需要每次去读取
}

大佬,我试着修改了一下(仅整合有用到的代码),图像分割的main函数里试着添加了你提到的这个for循环,用GPU经测试第一张图的推理速度很慢,后面速度在10ms一张图。(yolov8seg-opencv-dnn)main函数的代码如下图所示 image 而我之前每次运行代码都只是检测了一张图(只检测一次,没有些for循环),应该是包含了加载模型的时间,所以推理的时间会很慢。 总之,谢谢,我终于搞懂这个问题了!

UNeedCryDear commented 1 year ago

main函数只是我给你们的一个调用的demo,并不是说你们自己用的时候就一定要按这个方式去用,具体怎么使用是要看具体的需求的。