我目前使用 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 导数的实现时间。主要步骤是:
- 读取彩色图像
- 彩色图像的高斯模糊使用 半径为 3,增量为 1;
- 灰度转换;
- 计算x和y梯度
- 将它们合并到最终输出图像中。
相反,我实现了一个交换步骤 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/