为什么opencv用GPU实现比用CPU实现的慢?

2023-11-03

问题


打算通过OpenCV的GPU模块优化现有代码的运行效率,怀抱着美好愿望开始了代码的改写工作。改写的过程并不顺利,遇到了不少问题。例如,gpu模块提供的接口非常坑爹,相当一部分不支持浮点类型(像histogram、integral这类常用的都不支持);又如,遇到阈值判断的地方,就必须传回cpu处理,因为gpu函数都是并行处理的,每改写完一个算法模块,就测试一下运行效率,有的时候是振奋人心,有的时候则是当头棒喝——比CPU还慢?


经过一系列的google,终于找到原因:

http://stackoverflow.com/questions/12074281/why-opencv-gpu-codes-is-slower-than-cpu

http://answers.opencv.org/question/1670/huge-time-to-upload-data-to-gpu/#1676

The first gpu function call is always takes more time, because CUDA initialize context for device. The following calls will be faster.

Programming Guide的CUDA C Runtime-Initialization一节有对此说明


整段代码的第一条与GpuMa有关的语句就是所谓的first gpu function,这里CUDA需要初始化设备上下文,而该操作是非常耗费时间的!

在代码开头,或者类的构造函数,加入:

Mat src1; src1 = Mat::zeros(cvSize(5,5),CV_16UC1);
GpuMat src2(src1);
src1随便赋一个初值,关键是调用一次涉及GpuMat的操作(其它gpu函数也行),那么段代码就实现了CUDA的初始化。

经过实测,这里需要耗费400ms!尽管是像上面那么简单的两个语句,只要是整段代码的第一次调用gpu相关操作,默认执行CUDA的初始化!在其它机器上不一定是400ms,应该跟具体的PC硬件有关。

往后的gpu的操作都不会那么慢,但一旦涉及upload、download(显存与内存的数据传递),时间成本都达到ms级别!


总结一句,GPU的并行处理的确很快,但数据传入GPU的开销实在太大,往往影响了代码的整体效率。


现在的项目是,C++写的算法,做成dll供C#调用;理所当然的,gpu的操作都放在C++的接口I函数里;那问题就来了,每次C#调用C++的函数,都要执行CUDA的初始化,都要耗费400ms在无意义的操作上,对于算法的实时性要求简直不能忍受!除非,在C#里面先初始化CUDA,但这样可行吗?又合理吗?

现在总算搞明白,为什么网上没多少opencv gpu的资源,用的人不多嘛,实在坑爹啊!这么大的弊端,真的用过就怕了,害我浪费了那么多时间去优化,算法主体部分是快了不少,原本200ms,现在到了100ms的水平,但就这坑爹的CUDA初始化400ms就够抵消所有的成果!

以后在引入gpu之前,真的要好好审视本算法的当前运行效率,只有当前运行时间远大于CUDA初始化的耗时,才有引入的必要!的确,我是没有做好运算量的评估,现在的算法的运算量根本用不到gpu!


解决措施


问题1、CUDA初始化设备上下文非常耗时。

可以通过在程序开头进行任意一项与CUDA相关的操作,如定义一个GpuMat:

GpuMat a(10,10,CV_8U); //第一条CUDA语句,初始化设备上下文
第一条CUDA语句将会非常耗时,但之后都会恢复正常。


问题2、访存时间(latency)影响程序的整体效率。

两个途径:减少数据在CPU和GPU之间的传递次数;运算量非常小的部分不要用GPU,数据量非常大、循环次数非常多的时候才使用GPU。

前者是最直接的手段,后者则是GPU的使用原则,可见以下例子:


分别用CPU和GPU实现高斯滤波

cv::GaussianBlur(img, img, Size(11, 11), 1.5, 1.0, cv::BORDER_REFLECT); 
以上是CPU的代码

	cv::cuda::registerPageLocked(img);		//锁页内存
	gimg.upload(img);						//上传数据至GPU
	cv::Ptr<cv::cuda::Filter> gauss = cv::cuda::createGaussianFilter(CV_32F, CV_32F, Size(11, 11), 1.5, 0, cv::BORDER_DEFAULT,-1);	//创建高斯滤波器
	gauss->apply(gimg, gimg);			//高斯滤波
	gimg.download(img);						//下载数据至CPU
	cv::cuda::unregisterPageLocked(img);	//解除锁页
以上是GPU的代码,锁页能够加速数据在CPU和GPU之间的传递

运行结果:只计算高斯滤波函数的耗时,GPU是CPU的1/3~1/2,然而考虑上访存时间,GPU甚至比CPU还慢!


但如果进行10次高斯滤波,GPU的优势就能够得以体现:

	cv::cuda::registerPageLocked(img);		//锁页内存
	gimg.upload(img);						//上传数据至GPU
	cv::Ptr<cv::cuda::Filter> gauss = cv::cuda::createGaussianFilter(CV_32F, CV_32F, Size(11, 11), 1.5, 0, cv::BORDER_DEFAULT,-1);	//创建高斯滤波器
	for(int i=0;i<10;i++)
		gauss->apply(gimg, gimg);			//高斯滤波
	gimg.download(img);						//下载数据至CPU
	cv::cuda::unregisterPageLocked(img);	//解除锁页
以上是进行10次滤波的GPU代码,同时,CPU代码也执行10次滤波


运行结果:算上方寸时间,GPU的总耗时是CPU的1/5,如果执行100次滤波,则为1/10


但需要注意的是,运算量不仅跟执行次数有关,还跟数据量有关。按道理说,GPU对数据量越大的情况越有利,但在opencv的CUDA模块中,矩阵较大的数据(行列数较多)将大大增加数据传递的耗时,因为GpuMat本身对矩阵大小是有限制的,所以这又制约了CUDA并行的效率,除非使用CUDA编程合理分配数据和线程,opencv本身对大矩阵是无能为力的。

---------------------------------------------------------------------分割线-------------------------------------------------------------------


以下博文是更深层次的讨论CUDA代码优化:http://blog.csdn.net/gamesdev/article/details/17488237

该博文内容摘录如下:


执行单线程的做法,无疑会闲置非常多的并行计算资源,我们必须采用多线程,这样效率就会得到大幅度的提升。在GPU编程中,有一个叫“掩藏”(Hide)的概念。它的意思是指线程因为访问存储器或者阻塞等其它原因造成的延迟,但由于分配的线程足够多,导致整体上看GPU仍然处于忙碌的状态。




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么opencv用GPU实现比用CPU实现的慢? 的相关文章

  • 查找彼此接近的对象边界

    我正在研究一个计算机视觉问题 其中问题的第一步是找到物体彼此靠近的位置 例如 在下图中 我感兴趣的是找到灰色标记的区域 Input Output 我目前的方法是首先反转图像 然后通过侵蚀进行形态梯度跟随 然后删除一些不感兴趣的轮廓 脚本如下
  • 有没有一种有效的方法来优化我的序列化代码?

    这个问题缺乏细节 因此 我决定创建另一个问题而不是编辑这个问题 新问题在这里 我可以并行化我的代码吗 还是不值得 https stackoverflow com questions 17937438 can i parallelize my
  • Opencv matchTemplate 和 np.where():仅保留唯一值

    继带有马里奥硬币的 opencv 教程 https opencv python tutroals readthedocs io en latest py tutorials py imgproc py template matching p
  • cuda中内核的并行执行

    可以说我有三个全局数组 它们已使用 cudaMemcpy 复制到 GPU 中 但 c 中的这些全局数组尚未使用 cudaHostAlloc 分配 以便分配页面锁定的内存 而不是简单的全局分配 int a 100 b 100 c 100 cu
  • 如何在给定目标大小的情况下在 python 中调整图像大小,同时保留纵横比?

    首先 我觉得这是一个愚蠢的问题 对此感到抱歉 目前 我发现计算最佳缩放因子 目标像素数的最佳宽度和高度 同时保留纵横比 的最准确方法是迭代并选择最佳缩放因子 但是必须有更好的方法来做到这一点 一个例子 import cv2 numpy as
  • 无法满足显式设备规范“/device:GPU:0”,因为没有匹配的设备

    我想在我的 Ubuntu 14 04 机器上使用 TensorFlow 0 12 作为 GPU 但是 当将设备分配给节点时 我收到以下错误 InvalidArgumentError see above for traceback Canno
  • 提高 pytesseract 从图像中正确识别文本的能力

    我正在尝试使用读取验证码pytesseract模块 大多数时候它都能提供准确的文本 但并非总是如此 这是读取图像 操作图像以及从图像中提取文本的代码 import cv2 import numpy as np import pytesser
  • 如何使用 Python 将我的 GoPro Hero 4 相机直播连接到 openCV?

    我在尝试从我的新 GoPro Hero 4 相机捕获实时流并使用 openCV 对其进行一些图像处理时遇到麻烦 这是我的试用 创建的窗口上没有显示任何内容 import cv2 import argparse import time imp
  • Python中最相似的人脸识别

    如何使用Python和OpenCV来查找面部相似 我已成功使用 OpenCV 和 Python 使用 Haar Cascades 从多张照片中提取人脸 我现在有一个图像目录 所有这些都是不同人的面孔 我想做的是拍摄一张样本图像 然后看看它最
  • OpenCV 错误:使用 COLOR_BGR2GRAY 函数时断言失败

    我在使用 opencv 时遇到了一个奇怪的问题 我在 jupyter 笔记本中工作时没有任何问题 但在尝试运行此 Sublime 时却出现问题 错误是 OpenCV错误 cvtColor中断言失败 深度 CV 8U 深度 CV 16U 深度
  • 我可以使用 openCV 比较两张不同图像上的两张脸吗?

    我对 openCV 很陌生 我看到它可以计算出脸部并返回一个矩形来指示脸部 我想知道 openCV 是否可以访问两张包含一张脸的图像 并且我希望 openCV 返回这两个人是否相同的可能性 Thanks OpenCV 不提供完整的人脸识别引
  • 如何使用 CUDA/Thrust 对两个数组/向量根据其中一个数组中的值进行排序

    这是一个关于编程的概念问题 总而言之 我有两个数组 向量 我需要对一个数组 向量进行排序 并将更改传播到另一个数组 向量中 这样 如果我对 arrayOne 进行排序 则对于排序中的每个交换 arrayTwo 也会发生同样的情况 现在 我知
  • 如何读取 GPU 负载?

    我正在编写一个程序 用于监控计算机的各种资源 例如CPU使用率等 我还想监控 GPU 使用情况 GPU 负载 而不是温度 using System using System Collections Generic using System
  • 当我将鼠标移到 Mat 关键字上时,Visual Studio 2017 冻结(OpenCv 3.4.1)

    我想在 Visual Studio 2017 中开发 openCv 项目 我下载了 opencv 预构建库并进行了必要的设置 那是 1 我添加了系统路径 build x64 vc14 bin 2 在 Visual Studio 中的项目属性
  • OpenCV Visual Studio ntdll.dll

    我尝试在 Visual Studio 2013 上使用 OpenCV 2 4 10 创建一个项目 但由于以下异常 到目前为止我运气不佳 请建议帮助 TIA letstryitonemoretime exe Win32 Loaded C Us
  • OpenCV C++ 如何知道每行的轮廓数进行排序?

    我有一个二值图像 https i stack imgur com NRLVv jpg在这张图片中 我可以使用重载的函数轻松地对从上到下 从左到右找到的轮廓进行排序std sort 我首先通过以下方式从上到下排序 sort contours
  • ffmpeg AVFrame 到 opencv Mat 转换

    我目前正在开发一个使用 ffmpeg 解码接收到的帧的项目 解码后 我想将 AVFrame 转换为 opencv Mat 帧 以便我可以在 imShow 函数上播放它 我拥有的是字节流 我将其读入缓冲区 解码为 AVFrame f fope
  • OpenCV IP 相机应用程序崩溃 [h264 @ 0xxxxx] 访问单元中缺少图片

    我在 cpp 中有一个 opencv 应用程序 它使用 opencv 的简单结构捕获视频流并将其保存到视频文件中 它与我的网络摄像头完美配合 但是 当我运行它从 IP 摄像机捕获流时 它可能会在大约十秒后崩溃 我的编译命令是 g O3 IP
  • 使用 OpenCV 和/或 Numpy 对两个图像进行 Alpha 混合 [重复]

    这个问题在这里已经有答案了 我想将一个填充纯色的半透明矩形添加到已加载的半透明 PNG 中 这是我正在使用的输入图像示例 该图像加载了标准cv2 IMREAD UNCHANGED标志 以便完美保留 alpha 通道 该输入图像存储在imag
  • 使用 OpenCV 改进特征点匹配

    我想匹配立体图像中的特征点 我已经用不同的算法找到并提取了特征点 现在我需要一个良好的匹配 在本例中 我使用 FAST 算法进行检测和提取 BruteForceMatcher用于匹配特征点 匹配代码 vector lt vector

随机推荐

  • 【LSTM分类】基于注意力机制的卷积神经网络结合长短记忆神经网络CNN-LSTM-attention实现数据分类附matlab代码

    作者简介 热爱科研的Matlab仿真开发者 修心和技术同步精进 matlab项目合作可私信 个人主页 Matlab科研工作室 个人信条 格物致知 更多Matlab仿真内容点击 智能优化算法 神经网络预测 雷达通信 无线传感器 电力系统 信号
  • 爬虫手册04 Splash的使用

    Splash的使用 目标 作为Selenium的备选方案 加载js渲染后的浏览器数据 安装方法 https blog csdn net weixin 40743639 article details 122833394 spm 1001 2
  • 《英语(二)》作文案例

    翻译文章 1 More than twenty years ago my hometown was just a small old and poor town Most of people were farmers There were
  • GLES3.0中文API-glGetQueryObjectuiv

    名称 glGetQueryObjectuiv 返回查询对象的参数 C规格 void glGetQueryObjectuiv GLuint id GLenum pname GLuint params 参数 id 指定查询对象的名称 pname
  • js逆向解析,js爬虫

    废话不多说 直接开干 吸取了百度精华 来写文章了 难度系数 两颗星 大概逻辑 1 请求url 2 找到请求参数 3 分析参数产生过程 4 整合参数 1 请求url http fanyi youdao com 2 找到请求参数 3 分析参数产
  • SQL中的循环、for循环、游标

    SQL中的循环 for循环 游标 1 利用游标循环更新 删除MemberAccount表中的数据 DECLARE My Cursor CURSOR 定义游标 FOR SELECT FROM dbo MemberAccount 查出需要的集合
  • K8S的概念和基本应用

    学习视频 Kubernetes基本概念和应用 哔哩哔哩 bilibili 零 架构概览 master节点 管理调度集群资源 一般为多节点构成 可以是物理机 也可以是虚拟机 worker节点 资源的提供者 一般为多节点构成 可以是物理机 也可
  • 在vue项目当中实现对某个数据的复制vue-clipboard2

    在vue项目当中实现对某个数据的复制 运用插件是十分方便快捷的vue clipboard2 安装 npm install save vue clipboard2 main js import Vue from vue import VueC
  • 推荐-社交推荐相关

    总结 近时间矩阵分解 社交信息的融合模型 2018 模型性能 不同社交推荐方法在不同数据集中不同用户社交强度下的性能对比 研究难点与热点 数据稀疏性 社交关系的有效挖掘 社交噪声 可解释性社交推荐 可扩展型社交推荐模型与多源信息的融合 社交
  • Linux 面试常见(55题)

    TOC删除线格式 一 文件管理 目录操作 创建目录 mkdir mkdir命令可以创建一个新的目录 例如 在当前目录下创建一个名为 test 的目录 mkdir test 2 删除目录 rmdir rmdir命令可以删除一个空目录 例如 要
  • 结构体输入输出(c语言)

    include
  • 实现Echarts词云和随机颜色(vue2)

    1 首先需要安装echarts和echarts wordcloud插件 2 echarts的版本和echarts wordcloud版本有对应要求才能实现 否则会报错 经过查询如果是用的是echarts4那么需要对应着echarts wor
  • python自动化课程笔记(十一)封装、继承、多态

    class Dog object good dog 说明文档 def init self new name color age 5 self name new name self color color self age age def s
  • Tomcat安装及部署

    Aphorism 安装 忽略下载过程 1 解压文件 把 tomcat 安装包解压到 D Program Files 下 2 启动 tomcat 在 tomcat 文件包的 bin 文件夹中 双击 startup bat 文件启动tomcat
  • 给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。(C++实现)

    题目介绍 给定一个链表 删除链表的倒数第 n 个节点 并且返回链表的头结点 示例 给定一个链表 1 gt 2 gt 3 gt 4 gt 5 和 n 2 当删除了倒数第二个节点后 链表变为 1 gt 2 gt 3 gt 5 说明 给定的 n
  • Oil Deposits

    http poj org problem id 1562 Oil Deposits Description The GeoSurvComp geologic survey company is responsible for detecti
  • 10个超炫超有用的js库/插件

    原文地址 http blog csdn net shyy123 article details 7471782 1 CodeMirror CodeMirror 是一款 Online Source Editor 基于 Javascript 短
  • MyEclipse集成PMD代码检测插件自定义规则配置文件

    把我今天最新更新的MyEclipse2014集成PMD代码检测插件自定义规则配置文件JAVA版发布出来吧 方便自己以后回顾的同时 也看看能不能帮到有这方面需求的小伙伴们 文件名 cplatform pmd5 2 3 rules xml
  • Android.bp文件简介

    Android bp Android bp的出现就是为了替换Android mk文件 bp跟mk文件不同 它是纯粹的配置 没有分支 循环等流程控制 不能做算数逻辑运算 如果需要控制逻辑 那么只能通过Go语言编写 语法 根据设计 Androi
  • 为什么opencv用GPU实现比用CPU实现的慢?

    问题 打算通过OpenCV的GPU模块优化现有代码的运行效率 怀抱着美好愿望开始了代码的改写工作 改写的过程并不顺利 遇到了不少问题 例如 gpu模块提供的接口非常坑爹 相当一部分不支持浮点类型 像histogram integral这类常