opencv - 动态图像大小调整的 GPU 与 CPU 端到端延迟

标签 opencv imagemagick gpu cpu throughput

我目前使用 OpenCV 和 ImageMagick 进行一些吞吐量基准测试,但我没有发现使用 GPU 比 CPU 快得多。我们在现场的用例是根据服务调用动态调整到从主副本请求的大小,并尝试评估是否有 GPU 可以动态调整每个服务调用的大小。

分享我为 OpenCV 编写的代码。我正在为存储在一个文件夹中的所有图像连续运行以下函数,最终我正在运行 N 个这样的进程以实现 X 次图像大小调整。我想了解我的方法是否不正确,或者用例是否不正确适合典型的 GPU 用例。究竟是什么限制了 GPU 性能。我什至没有将利用率最大化到接近 100%

resizeGPU.cpp: {

    cv::Mat::setDefaultAllocator(cv::cuda::HostMem::getAllocator (cv::cuda::HostMem::AllocType::PAGE_LOCKED));

    auto t_start = std::chrono::high_resolution_clock::now();
    Mat src = imread(input_file,CV_LOAD_IMAGE_COLOR);
    auto t_end_read = std::chrono::high_resolution_clock::now();
    if(!src.data){
            std::cout<<"Image Not Found: "<< input_file << std::endl;
            return;
    }

    cuda::GpuMat d_src;
    d_src.upload(src,stream);
    auto t_end_h2d = std::chrono::high_resolution_clock::now();
    cuda::GpuMat d_dst;

    cuda::resize(d_src, d_dst, Size(400, 400),0,0, CV_INTER_AREA,stream);
    auto t_end_resize = std::chrono::high_resolution_clock::now();

    Mat dst;
    d_dst.download(dst,stream);
    auto t_end_d2h = std::chrono::high_resolution_clock::now();
    std::cout<<"read,"<<std::chrono::duration<double, std::milli>(t_end_read-t_start).count()<<",host2device,"<<std::chrono::duration<double, std::milli>(t_end_h2d-t_end_read).count()
                            <<",resize,"<<std::chrono::duration<double, std::milli>(t_end_resize-t_end_h2d).count()
                            <<",device2host,"<<std::chrono::duration<double, std::milli>(t_end_d2h-t_end_resize).count()
            <<",total,"<<std::chrono::duration<double, std::milli>(t_end_d2h-t_start).count()<<endl;


}

resizeCPU.cpp:

    auto t_start = std::chrono::high_resolution_clock::now();
    Mat src = imread(input_file,CV_LOAD_IMAGE_COLOR);
    auto t_end_read = std::chrono::high_resolution_clock::now();
    if(!src.data){
            std::cout<<"Image Not Found: "<< input_file << std::endl;
            return;
    }

    Mat dst;
    resize(src, dst, Size(400, 400),0,0, CV_INTER_AREA);
    auto t_end_resize = std::chrono::high_resolution_clock::now();

    std::cout<<"read,"<<std::chrono::duration<double, std::milli>(t_end_read-t_start).count()<<",resize,"<<std::chrono::duration<double, std::milli>(t_end_resize-t_end_read).count()
        <<",total,"<<std::chrono::duration<double, std::milli>(t_end_resize-t_start).count()<<endl;

编译:g++ -std=c++11 resizeCPU.cpp -o resizeCPU pkg-config --cflags --libs opencv

我正在运行每个程序 N 次,由以下代码控制:runMultipleGPU.sh

#!/bin/bash
echo $1
START=1
END=$1
for (( c=$START; c<=$END; c++ ))
do
./resizeGPU "$c" &#>/dev/null #&disown;
done
wait
echo All done

运行:./runMultipleGPU.sh

周围的计时器会导致以下聚合数据

No_processes    resizeCPU   resizeGPU   memcpyGPU   totalresizeGPU
1                 1.51        0.55        2.13         2.68
10                5.67        0.37        2.43         2.80
15                6.35        2.30       12.45        14.75
20                6.30        2.05       10.56        12.61
30                8.09        4.57       23.97        28.55

每个进程运行的图像数量:267

图片的平均大小:624Kb

根据上面的数据,随着我们增加进程数量(导致同时调整大小的数量增加),调整大小执行 ance(包括实际调整大小+主机到设备和设备到主机的副本)在 GPU 和 CPU 上显着增加。

使用下面使用 OpenCL 的 ImageMagick 后结果相似

代码:

setenv("MAGICK_OCL_DEVICE","OFF",1); //Turn in ON to use GPU acceleration
Image image;
auto t_start_read = std::chrono::high_resolution_clock::now();
image.read( full_path );
auto t_end_read = std::chrono::high_resolution_clock::now();
image.resize( Geometry(400,400) );
auto t_end_resize = std::chrono::high_resolution_clock::now();

结果:

No_procs    resizeCPU   resizeGPU
1            63.23       8.54
10           76.16      31.04
15           76.56      50.79
20           76.58      71.68
30           86.29     140.17

测试机配置:

4 GPU (Tesla P100) - 但测试仅使用 1 GPU

64 个 CPU 内核(超过 Intel Xeon 2680 v4 CPU)

OpenCV 版本:3.4.0

ImageMagick 版本:6.9.9-26 Q16 x86_64 2018-01-17

Cuda 工具包:9.0

最佳答案

很可能这已经太晚了,无法帮助您。但是对于查看此答案的人来说,这是我提高性能的建议。您设置固定内存的方式并不能为您提供所需的提升。 这是:使用

//method 1
cv::Mat::setDefaultAllocator(cv::cuda::HostMem::getAllocator(cv::cuda::HostMem::AllocType::PAGE_LOCKED));

this discussion的评论中.有人建议像你那样做。接电话的人说速度比较慢。我正在安排接近 Coldvision.io Sobel 中的 sobel 导数的实现时间。主要步骤是:

  1. 读取彩色图像
  2. 彩色图像的高斯模糊使用 半径为 3,增量为 1;
  3. 灰度转换;
  4. 计算x和y梯度
  5. 将它们合并到最终输出图像中。

相反,我实现了一个交换步骤 2 和 3 顺序的版本。首先转换为灰度,然后通过传递高斯对结果进行去噪。

我在 Windows 10 中运行 openCV 3.4。Cuda 9.0。我的 CPU 是 i7-6820HQ。 GPU 是 Quadro M1200。

我试试你的方法和这个:

//Method 2
//allocate pinned memory    
cv::cuda::HostMem memory(siz.height, siz.width, CV_8U, cv::cuda::HostMem::PAGE_LOCKED);
//Read input image from the disk
Mat input = imread(input_file, CV_LOAD_IMAGE_COLOR);
if (input.empty())
{
    std::cout << "Image Not Found: " << input_file << std::endl;
    return;
}    
input.copyTo(memory);
// copy the input image from CPU to GPU memory
cuda::GpuMat gpuInput;
cv::cuda::Stream stream;
gpuInput.upload(memory, stream);

//Do your processing... 

//allocate pinned memory for output
cv::cuda::HostMem outMemory(siz.height, siz.width, CV_8U, cv::cuda::HostMem::PAGE_LOCKED);
gpuOutput.download(outMemory, stream);
cv::Mat output = outMemory.createMatHeader();

我计算增益为:(t1-t2)/t1*100。其中 t1 是正常运行代码的时间。 t2 使用固定内存运行它。负值表示方法比在非固定内存中运行慢。

image size  Gain % Method 1    Gain % Method 2
800x600     2.9                8.2
1280x1024   2.5                15.3
1600x1200   0.2                7.0
2048x1536   -2.3               14.6
4096x3072   -1.0               17.2

关于opencv - 动态图像大小调整的 GPU 与 CPU 端到端延迟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48921705/

相关文章:

r - GPU 上的 foreach doparallel

python - OpenCV 教程 - 错误 : Unsupported format or combination of formats

node.js - 在 Nodejs 中使用 gm 调整大小并合成两个或多个图像

python - TensorFlow 的 ./configure 在哪里以及如何启用 GPU 支持?

python - MoviePY 无法在 Windows 上检测 ImageMagick 二进制文件

c++ - Graphicsmagick C++ API

c++ - 识别崩溃的图形驱动程序

c# - 如何使用 opencv 均衡图像的对比度和亮度?

c++ - 从标记的姿势相机的姿势

c++ - 如何将 boost.Asio 与 MJPEG 一起使用?