Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

为什么c++推理时间比python中的推理时间更长? #17

Closed
1404561326521 opened this issue Oct 17, 2023 · 12 comments
Closed

为什么c++推理时间比python中的推理时间更长? #17

1404561326521 opened this issue Oct 17, 2023 · 12 comments

Comments

@1404561326521
Copy link

yolov5分割任务,图像分辨率1440×1080,python的predict.py脚本推理时间一张图在30ms左右,但是在c++中推理时间一张图在200ms左右,我尝试在c++推理之前将分辨率下采样,但是时间并没有什么变化,大佬帮忙看下,main.cpp如下:
#include
#include <opencv2/opencv.hpp>
#include
#include "yolo_seg.h"
#include "yolov5_seg_onnx.h"
#include <time.h>

#include <boost/filesystem.hpp>

using namespace std;
using namespace cv;
using namespace dnn;
namespace fs = boost::filesystem;

std::set uniqueClassIDs;

string results_folder = "./test_results_time"; // 结果图像保存文件夹路径

// 函数用于将绘制后的图像保存到结果文件夹
void SaveResultImage(const Mat& img, const string& img_path) {
// 确保图像为单通道图像
Mat singleChannelImg;
cvtColor(img, singleChannelImg, COLOR_GRAY2BGR);

string result_img_path = results_folder + "/" + fs::path(img_path).filename().string();
imwrite(result_img_path, singleChannelImg);

}

// 用于生成掩码图像的函数
Mat GenerateMaskImage(const vector& result, const Mat& inputImage) {
// 创建一个与原始图像相同大小的单通道掩码图像,初始化为全零
Mat maskImage = Mat::ones(inputImage.size(), CV_8UC1) * 255;

// 遍历检测到的对象
for (const OutputSeg& obj : result) {
    int classID = obj.id; // 获取类别 ID
    Rect bbox = obj.box;  // 获取对象的边界框

    obj.boxMask.forEach<uchar>([=](uchar& pixel, const int* position) -> void {
        if (pixel == uchar()) {
            pixel = 255;
        }
        else if (pixel == 255)
            pixel = static_cast<uchar>(classID);
        });

    // 从 boxMask 复制像素值到 inputImage
    obj.boxMask.copyTo(maskImage(bbox));
}
return maskImage;

}

// 批量推理所有图片
int yolov5_seg_onnx() {
string images_folder = "./images";
string model_path = "./models/best.onnx";
YoloSegOnnx test;

if (!test.ReadModel(model_path, true, 0, true)) {
    cout << "Failed to read model." << endl;
    return -1;
}

// 创建颜色映射表,根据类别ID为每个类别分配颜色
vector<Scalar> colorMap;
colorMap.push_back(Scalar(255, 0, 0));
colorMap.push_back(Scalar(0, 255, 0));

// 遍历 images 文件夹下的所有图片文件
for (const auto& entry : fs::directory_iterator(images_folder)) {
    if (fs::is_regular_file(entry) && entry.path().extension() == ".png") {
        string img_path = entry.path().string();
        cout << "Processing image: " << img_path << endl;

        vector<OutputSeg> result;
        Mat img = imread(img_path);

        // 下采样到 480x640
        Mat resized_img;
        resize(img, resized_img, Size(480, 640));

        // 启动计时器
        auto start = chrono::high_resolution_clock::now();

        if (test.OnnxDetect(resized_img, result)) {
            // 在这里添加生成掩码图像的代码
            Mat maskImage = GenerateMaskImage(result, resized_img);

            // 将掩码图像恢复至原始分辨率
            Mat final_maskImage;
            resize(maskImage, final_maskImage, img.size());

            // 将掩码图像保存到文件
            SaveResultImage(final_maskImage, img_path);
        }
        else {
            cout << "Failed to detect objects in image: " << img_path << endl;
        }

        // 结束计时器
        auto end = chrono::high_resolution_clock::now();

        // 计算处理时间(毫秒)
        auto elapsed_ms = chrono::duration_cast<chrono::milliseconds>(end - start);
        cout << "Image processed in " << elapsed_ms.count() << " milliseconds." << endl;
    }
}

return 0;

}

int main() {
if (!fs::exists(results_folder)) {
fs::create_directory(results_folder);
}

yolov5_seg_onnx(); // OnnxRuntime, support dynamic!
return 0;

}

@UNeedCryDear
Copy link
Owner

确认下你的ORT有无调用到GPU,你这个速度是没有调用到GPU的速度。
另外ORT调用GPU,第一次运行会比较慢,所以需要启用warm up,另外有一点是,如果你输入每次都是不一样大小的话,那warm up对这种动态效果就不是很好,反而可能更慢,这点python下面会好一些。

@1404561326521
Copy link
Author

我的输入图像尺寸固定为1440×1080,这个具体要怎么调用GPU啊,大佬可以指点一下不

@UNeedCryDear
Copy link
Owner

image

@LYHTZHANGJIANG
Copy link

image

我测试就推理的时间,要接近100多ms, 跟cpu没什么区别,但是是按照你这样的设置了呀? 请问是什么问题呀?

@1404561326521
Copy link
Author

我在读模型时确实启用了cuda,但是速度还是200多毫秒
image

@UNeedCryDear
Copy link
Owner

UNeedCryDear commented Oct 18, 2023

@LYHTZHANGJIANG @1404561326521

代码这里设置为true并不代表一定能调用成功,我的策略就是如果启用cuda失败回退带CPU推理。这就是为什么即使你设置了cuda为true,但是仍然和cpu速度一样。

首先请确认下自己的cuda和cudnn是否安装成功,和onnx的版本是否可以匹配,和显卡是否匹配,特别是30系之后的显卡,至少要cuda11.x的版本才行,低于这个版本无法使用cuda。

其次如果会debug,你可以打断点在read模型的时候,看下是否跳转到了 cpu上面去了。如果不会跟代码,就开任务管理器,看下对应的显卡显存有无上涨,引擎修改为cuda看下有无增长。另外,z这里的显卡说的是英伟达的显卡,而非核显或者AMD的显卡

image

@1404561326521
Copy link
Author

我就是在任务管理器观察的,运行时cpu占用率提高了很多,gpu的占用率基本没变化

@UNeedCryDear
Copy link
Owner

另外有一点,我再次测试了下我的最新代码,可以成功跑在ort1.9~ort1.16.x,所以请检查一下你自己的环境之类的有无问题,onnxruntime是否下载的gpu版本

@LYHTZHANGJIANG
Copy link

另外有一点,我再次测试了下我的最新代码,可以成功跑在ort1.9~ort1.16.x,所以请检查一下你自己的环境之类的有无问题,onnxruntime是否下载的gpu版本

我的环境是4090 cuda12,ort12.0 是gpu版本,我debug打印看了,是走的cuda,cpu和gpu耗时都是80ms左右,我想问问您那边推理单张图像耗时是多少?

@UNeedCryDear
Copy link
Owner

@LYHTZHANGJIANG

我的环境是4090 cuda12,ort12.0 是gpu版本,我debug打印看了,是走的cuda,cpu和gpu耗时都是80ms左右,我想问问您那边推理单张图像耗时是多少?

默认640x640的突破的话,前两三张会慢,后面可以达到18-30ms之间(3060,不进行结果绘制,只计算输入图片开始到拿到结果,没有绘制结果),取决于原图大小和上面目标的数量,毕竟计算mask的时候耗时还是比较高的。推理速度的话很快,基本上2-7ms之间,具体没有很详细的计算,大概就是这么个速度。
另外有一点,这个速度是release下面测试的,如果你是debug模式,速度慢是正常的。

@LYHTZHANGJIANG
Copy link

@LYHTZHANGJIANG

我的环境是4090 cuda12,ort12.0 是gpu版本,我debug打印看了,是走的cuda,cpu和gpu耗时都是80ms左右,我想问问您那边推理单张图像耗时是多少?

默认640x640的突破的话,前两三张会慢,后面可以达到18-30ms之间(3060,不进行结果绘制,只计算输入图片开始到拿到结果,没有绘制结果),取决于原图大小和上面目标的数量,毕竟计算mask的时候耗时还是比较高的。推理速度的话很快,基本上2-7ms之间,具体没有很详细的计算,大概就是这么个速度。 另外有一点,这个速度是release下面测试的,如果你是debug模式,速度慢是正常的。

我的问题解决了,我是环境版本不对应就没能加速,cuda11.6和11.1 ort12是可以的,单跑推理7ms。但是我跑transformer CPU和GPU的耗时还是一样,我观察了显存是变化了的,请问您这边有遇到过吗?

@UNeedCryDear
Copy link
Owner

模型小,或者GPU前面几次推理速度慢,多跑几次取个均值看下

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants