OpenCV算法加速的一些学习总结

一、概述

算法加速在实际软件层面应用来说 大数据和复杂计算的过程中

算法优化,指降低算法计算复杂度,设计新算法快速求解,比如Hungarian匹配算法。或牺牲一些内存,预计算一些重复计算的过程,减少程序层面的复杂度。

语言更换,指将自己算法迁移到更加底层的算法,越是低级的算法,执行速度越快。常见地,将Matlab、Python等解释性代码移植到C++平台,往往有5-20倍的加速效果。

算法并行,指将自己算法的独立计算部分,分成几块,利用CPU指令集、多核或GPU的特性实现加速。多核并行和CUDA并行最为常见。

汇编加速,将自己的一片代码指定为自己设计的汇编语言。多种C++编译器实际上也是将语言转换为汇编代码,对汇编进行加速在嵌入式中常见。(该方法对平台有需求,并不常见)

硬件加速,利用特殊硬件处理特殊算法,降低CPU架构的复杂度。常见的就是FPGA。
https://blog.csdn.net/ljsant/article/details/12707525https://blog.csdn.net/ljsant/article/details/12707525

本文主要介绍算法并行进行加速

 其中,3、算法并行

**并行思想从小到大可以总结为:**指令集开发->多核并行->CUDA**并行,**

3.1 指令集加速

指令集加速,一般是针对CPU架构进行的底层优化,常见于OpenCV和Tensorflow的CPU版本。之所以OpenCV是个经典的开源图像框架,很大原因是因为其在多个平台上执行效率很高,其中底层的优化,比如指令集优化,起到了关键作用。

数据并行的两种实现在计算机体系中,数据并行有两种实现路径:

  • MIMD(Multiple Instruction Multiple Data,多指令流多数据流)。MIMD的表现形式主要有多发射、多线程、多核心,在当代设计的以处理能力为目标驱动的处理器中,均能看到它们的身影。
  • SIMD(Single Instruction Multiple Data,单指令流多数据流)。随着多媒体、大数据、人工智能等应用的兴起,为处理器赋予SIMD处理能力变得愈发重要,因为这些应用存在大量细粒度、同质、独立的数据操作,而SIMD天生就适合处理这些操作。SIMD本身并不是一种指令集,而是一种处理思想,现在的一些指令集都支持SIMD。(简单来说,计算1000维向量的点积,乘法是独立的,多核心不值得,这时候就可以利用指令集一次性计算4次或8次乘法,同样的,之后的加法也同样可以用指令集计算)CPU指令集的发展(针对Intel的x86指令集系列):
  • MMX指令集 (Multi Media eXtension, 多媒体扩展指令集)。MMX指令集率先在Pentium处理器中使用,MMX指令集支持算数、比较、移位等运算,MMX指令集的向量寄存器是64bit。
  • SSE指令集(Streaming SIMD Extensions,单指令多数据流扩展),所有的SSE系列指令的向量寄存器都是128bit,也就是一次性可以计算4个int。SSE最早出现在1999年,在之后的近10年内,推出了SSE,SSE2,SSE3,SSE4.1,SSE4.2。AVX指令集(Advanced Vector Extensions,高级向量扩展)。AVX指令集是在之前的SSE128位扩展到和256位的单指令多数据流。AVX出现在2008年,之后出了AVX2,2014年,AVX-512将数据bit由256bit扩展到了512bit。AVX是目前比较常用的指令集,256位的类型可以一次计算4个double,有效的提升性能。

利用CPU-Z软件可以查看电脑的CPU信息,查看电脑支持哪些指令集。

现代编译器有三种方式来支持 SIMD:

(1)编译器能够在没有用户干预的情况下生成 SIMD 代码,称之为自动矢量化。

(2)用户可以插入 Intrinsics 函数实现 SIMD。

(3)用户可以使用矢量 C++ 类 (仅限ICC编译器) 来实现 SIMD。

在C++中使用SIMD指令集需要包含头文件<xmmintrin.h>,在QT中需要包含头文件<immintrin.h>

3.2 多核编程

多核编程可以理解为就是多线程编程,总体上可以分为三个部分:OpenMP并行,opencv并行和多线程并行。在设计相关代码时候,切记变量可以被多个线程访问,但同一时间只能被一个线程修改,如果多个线程想修改同一个变量,可使用原子操作或加锁。 当然,多核编程不止这些,还有tbb,mkl等等。

  1. OpenMP 并行。这种并行办法是最简单的一种并行方法,直接在for循环前面添加#pragma omp parallel for即可,程序会自动将for循环分解。值得注意的是,该方法是在for循环前开始创建线程,结束后并销毁,这个过程会产生一些时间消耗,大约在3-5ms之间,做实时性应用开发的时候需要注意这个问题。(如果用到opencv,内部也有并行)
  2. 多线程并行。上述的两种方法是针对一个for循环来解决的,但是整个算法不可能就由一个for循环构成,如果每个for循环都这么做的话,创建线程的开销巨大,因此,多线程并行主要就是解决这类问题的。初始化时候创建好线程,之后主线程串联算法,子线程解决for循环问题,线程可能会使用同步,加锁等手段逐步执行,最终获得输出结果。创建多线程时候,系统本身就会将不同线程分到不同核心上,有自己的调度手段,所以该方法加速效果很明显,就是过于面向过程,不方便后续的改进。

1、利用x86转为x64提速,可以提高1倍的速度

2、多线程的openmp或Intel TBB提速,将cpu的利用率从20%多提高到100%

3、利用GPU提速,至少可以提高5~10倍的运算速度

OpenCV访问像素的三种方法

访问图像中像素的三种方法:1. 指针访问_雪易的博客-CSDN博客

访问图像中像素的三种方法:2. 迭代器访问_迭代器访问像素_雪易的博客-CSDN博客

访问图像中像素的三种方法:3. 动态地址计算配合at方法_雪易的博客-CSDN博客

二、加速方式

1、OpenMP

算法加速的一些方法思路_疯狂的挖掘机的博客-CSDN博客

OpenCV算法加速(1)OpenMP/PPL/TTB基础知识_利白的博客-CSDN博客_opencv加速

VS中启用OpenMP

在项目上右键->属性->配置属性->C/C++->语言->OpenMP支持,选择“是”即可。

提供指向 OpenMP API 中使用的构造的链接。

循环代码

openMP的一点使用经验_weixin_30449453的博客-CSDN博客

#pragma omp parallel for
     for (int i=0;i<10;i++)
         std::cout<<i<<std::endl;

2、TBB

TBB——使用lambda进行并行加速_tbb加速_windxgz的博客-CSDN博客

C++ 实现soble算子_qt sobel算子c++实现_酷小川的博客-CSDN博客

sobel算子实现原理和c++实现sobel()检测边缘函数_共觞的博客-CSDN博客

TBB_lambda表达式

tbb::parallel_for(tbb::blocked_range<size_t>(0, n), [](const tbb::blocked_range<size_t>& r)

指令集 SIMD指令集(MMX、SSE、AVX)和MIPP


Intel® Intrinsics Guide    用法参考官网

SIMD(Single Instruction Multiple Data ),顾名思义,就是单条指令处理多个数据

        SIMD(Single Instruction Multiple Data)指令集,从第一代开始算起,也快有近20年的历史了,从最开始的MMX技术,到SSE,以及后来的SSE2、SSE3、SSE4、AVX以及11年以后的AVX2,逐渐的成熟和丰富,不过目前考虑通用性方面,AVX的辐射范围还是有限,大部分在优化时还是考虑使用128位的SSE指令集。

3、SSE指令级加速

 
Intel® Intrinsics Guide    用法参考官网

了解这一类用于进行初始化加载数据以及将暂存器的数据保存到内存相关的指令

使用的xmm0到xmm8的暂存器

其使用方法可以归纳为:“接-化-发”

__m128i p1 = _mm_cvtepu8_epi16(_mm_loadu_si128((__m128i*) (smoothImg + ((i - 1) * src.step + j - 1))));
  1. 使用SSE专门的LOAD指令从内存加载一个向量到寄存器。
  2. 使用SSE专门的OP指令对两个向量进行某种计算。
  3. 使用SSE专门的STORE指令把计算结果从寄存机写回到内存。

1. load系列,用于加载数据,从内存到暂存器

__m128 _mm_load_ss (float *p)  
__m128 _mm_load_ps (float *p)  
__m128 _mm_load1_ps (float *p)  
__m128 _mm_loadh_pi (__m128 a, __m64 *p)  
__m128 _mm_loadl_pi (__m128 a, __m64 *p)  
__m128 _mm_loadr_ps (float *p)  
__m128 _mm_loadu_ps (float *p)

MIPP

        MIPP 是用 C++11 编写的向量内在函数 (SIMD) 的可移植和开源包装器(MIT 许可)。 它适用于 SSE、AVX、AVX-512 和 ARM NEON(32 位和 64 位)指令。 MIPP 包装器支持简单/双精度浮点数以及有符号整数运算(64 位、32 位、16 位和 8 位)。
 

OpenMP+SSE  TTB+SSE   AVX加速

tbb+openMP 无法结合,因为他们都是多线程的 多耗时25倍


总结

加速时会消耗内存提高速度 , 消耗内存就是空间换时间

        算法分为空间复杂度和时间复杂度,一般在工作中时间要求更高,可以改变算法逻辑,必要情况下,哪怕提高空间复杂度也要降低时间复杂度

        并发算法都是压榨设备的性能,特别是现在的多核处理器。但是如果设备性能不够高,即使很高的并发也实现不了,而且将串行修改成并行或者并发,都是要额外付出时间的,所以leader说没必要用二维度的range,就是因为公司电脑性能带不动二维,强行使用带不来较一维明显的效果,还压榨设备性能,也会造成硬件的加速老化。

        实际项目中往往牺牲内存提升速度通过开辟更大的内存,即扩大空间复杂度。来降低算法实现的时间复杂度 所以同样的效果其实可以有很多实现方式,而且优劣分明。

加速算法主要就是在空间复杂度时间复杂度上下文章。

电脑提速从而减少浪费内存

1、tbb和OpenMP都是多线程的无法结合进行加速,尝试结合后,时间迸发;

2、tbb加速比较实用的还是lambda表达式的形式;

3、OpenMP使用需要配置VS属性:

在项目上右键->属性->配置属性->C/C++->语言->OpenMP支持,选择“是”即可。提供指向 OpenMP API 中使用的构造的链接。

4、SSE支持的数据类型是4个32位(共计128位)浮点数集合,就是C、C++语言中的float[4],并且必须是以16位字节边界对齐的。因此这也给输入和输出带来了不少的麻烦,实际上主要影响SSE发挥性能的就是不停地对数据进行复制以适用应它的数据格式。

5、用AVX指令集必须做好合适的IDE配置。

在C/C++ ->代码生成的启用增强指令集里


参考文献

https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.htmlIntel® Intrinsics Guide

1、利白老师总结的超详细

OpenCV算法加速(1)OpenMP/PPL/TTB基础知识   

OpenCV算法加速(2)使用SIMD指令集(MMX、SSE、AVX)和MIPP实现视觉算法优化/2、

2、下面博客也很nice

【AI PC端算法优化】四,一步步将Sobel边缘检测加速22倍

[边缘检测算法] Sobel算子及其PC端优化提速20几倍

单线程、SSE、AVX运行效率对比——加法运算

3、sobel算子

sobel算子原理与实现_五仁月饼哭了的博客-CSDN博客

OpenCV图像处理专栏十八 | 手动构造Sobel算子完成边缘检测_just_sort的博客-CSDN博客

Sobel算子及C++实现_chuifuhuo6864的博客-CSDN博客

【学习opencv】Sobel算子原理及其实现_opencv sobel实现_zhulinzhulinlin的博客-CSDN博客

4、TBB入门资料

TBB入门_tbb使用教程_阿尔贝斯的博客-CSDN博客

Intel Thread Building Blocks (TBB) 入门篇_Belial_2010的博客-CSDN博客

VS2010+OpenCV2.3.1环境下使用tbb加速示例_配置tbb加速_小卡36的博客-CSDN博客

Intel Threading Building Blocks :基本算法参考及使用__saga的博客-CSDN博客

Intel TBB 开发指南 2 Parallelizing Simple Loops_sunny_98_98的博客-CSDN博客

C++高性能编程笔记(第6讲 intelTBB入门) - 知乎

Lambda表达式从用到底层原理_恒者走天下的博客-CSDN博客

5、OpenMP学习

OpenMP的配置及简单使用_openmp安装_小白的进阶的博客-CSDN博客

OpenMP并行编程_openmp编程_伴君的博客-CSDN博客

6、SSE学习

SSE指令集学习__mm_srai_epi16_林小鱼的猫的博客-CSDN博客

使用SSE指令集来优化程序_sse2指令集优化_百里杨的博客-CSDN博客

一文读懂SIMD指令集 目前最全SSE/AVX介绍_Axurq的博客-CSDN博客

关于simd:如何选择AVX比较谓词变体 | 码农家园

SSE指令集加速运算_nick_wong的博客-CSDN博客

经典图像二值分割的SSE加速实现_HAOJUN_HAN的博客-CSDN博客

SSE图像算法优化系列1-RGB转灰度图_just_sort的博客-CSDN博客

机器学习中的高性能计算(二)SSE优化 - 知乎

在C/C++代码中使用SSE等指令集的指令(5)SSE进行加法运算简单的性能测试_c++ sse_百里杨的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/13101.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

微软文字转语音不能试用了,分享三个方法给大家!

最近很多小伙伴告诉我&#xff0c;微软文字转语音不能在线试用了&#xff0c;这是因为微软关闭了官方的使用页面&#xff0c;所以现在不能直接使用微软的网页版进行文字转语音了。 那么我们还有没有更好的方法去“白嫖”微软的文字转语音呢&#xff1f; 答案是肯定的&#xf…

MTU 网卡bond 简介

MTU 最大传输单元MTU&#xff08;Maximum Transmission Unit&#xff0c;MTU&#xff09;&#xff0c;是指网络能够传输的最大数据包大小&#xff0c;以字节为单位。MTU的大小决定了发送端一次能够发送报文的最大字节数。如果MTU超过了接收端所能够承受的最大值&#xff0c;或者…

被裁后找不到工作,本质上是因为原来的能力就配不上高薪,如果技术好,根本不怕被裁,相当于白送n+1!...

被裁员后&#xff0c;能要求公司补缴公积金吗&#xff1f; 一位网友问&#xff1a; 被裁员了&#xff0c;要求公司把历史公积金全部足额缴纳&#xff0c;现在月薪2.3万&#xff0c;但公司每个月只给自己缴纳300元公积金&#xff0c;结果一次补了二十多万&#xff0c;一次性取出…

Linux工具——yum和vim

目录 &#x1f34f;Linux软件包管理器-yum&#x1f34e;yum简介&#x1f34e;rzsz工具&#x1f34e;注意事项&#x1f34e;软件包查看&#x1f34e;如何安装和卸载软件 &#x1f34f;Linux编辑器-vim&#x1f34e;vim的基本概念&#x1f34e;vim的基本操作&#x1f34e;vim正常…

Linux基础——FTP原理与配置

Linux基础——FTP原理与配置 一、文件传输协议——FTP服务二、ftp配置文件解析三、FTP服务器搭建 一、文件传输协议——FTP服务 FTP是典型的C/S结构的应用层协议&#xff0c;需要由服务器软件、客户端软件两个部分共同实现文件传输功能 FTP 连接模式 FTP服务器默认使用TCP协议…

盖子的c++小课堂——第十七讲:递归

前言 通知一下&#xff0c;以后每周不定期更新&#xff0c;有可能是周六更新&#xff0c;也可能是周日吧&#xff0c;反正会更新的~~还有我新出的专栏《跟着盖子读论语》&#xff0c;记得订阅一下啊跟着盖子学《论语》_我叫盖子的盖鸭的博客-CSDN博客 三元表达式 三元表达式…

中国版ChatGPT来了!快跟我一起申请文心一言吧

随着ChatGPT的快速进化吸引了全球网友的眼球 国内厂商也纷纷推出了相似的产品 其中百度推出的“文心一言”已经正式开始的相关的测试 很多人都在问 文心一言入口在哪&#xff1f; 文心一言邀请码在哪可以领&#xff1f; 文心一言怎么申请内测&#xff1f; 自从文心一言发…

计算机视觉——yolov5回归与跨网格预测、训练技巧(下篇)

yolov5 1. yolov5网络架构与组件1.1 网络可视化工具 netron1.2 不同模型的配置1.3 Focus 模块1.4 CSPNet 跨阶段局部网络1.5 SPP 空间金字塔池化1.6 PANet 路径聚合网络 2. 损失函数2.1 类别预测2.2 边界框回归2.3 回顾IoU2.4 IoU推广——GIoU loss2.5 IoU推广——DIoU loss2.6…

大四的告诫

&#x1f442; LOCK OUT - $atori Zoom/KALONO - 单曲 - 网易云音乐 &#x1f442; 喝了一口星光酒&#xff08;我只想爱爱爱爱你一万年&#xff09; - 木小雅 - 单曲 - 网易云音乐 其实不是很希望这篇文章火&#xff0c;不然就更卷了。。 从大一开始&#xff0c;每天10小时…

腾讯云轻量4核8G12M应用服务器带宽、月流量详细性能评测

腾讯云轻量4核8G12M应用服务器带宽&#xff0c;12M公网带宽下载速度峰值可达1536KB/秒&#xff0c;折合1.5M/s&#xff0c;每月2000GB月流量&#xff0c;折合每天66GB&#xff0c;系统盘为180GB SSD盘&#xff0c;地域节点可选上海、广州或北京&#xff0c;4核8G服务器网来详细…

Praat脚本-037 | 批量把标注TextGrid生成韵律文本

目录 引题方案一方案二方案三获取脚本关注版权说明 引题 Praat是一种非常出色、轻便、开源免费的标注工具&#xff0c;它的最主要用途是标注&#xff0c;即对语音信号中的一些特征、信息进行标注&#xff0c;保存为TextGrid文件&#xff0c;这个TextGrid文件实质 上就是一种文…

Harmony OS 开发指南——源码下载和编译

本文介绍了如何下载鸿蒙系统源码&#xff0c;如何一次性配置可以编译三个目标平台&#xff08;Hi3516&#xff0c;Hi3518和Hi3861&#xff09;的编译环境&#xff0c;以及如何将源码编译为三个目标平台的二进制文件。 坑点总结&#xff1a; 下载源码基本上没有太多坑&#xf…

Web前端-Vue2.0框架学习

Web前端-Vue框架学习 1. 前端工程化与Webpack1.1 隔行变色的demo实现1.2 webpack的基本使用1.3 webpac插件1.3.1 webpack-dev-server插件1.3.2 html-webpack-plugin 1.4 webpack中的loader&#xff08;加载器&#xff09;1.4.1 css-loader1.4.2 less-loader1.4.3 url-loader &a…

Node【Global全局对象】之【URL】

文章目录 &#x1f31f;前言&#x1f31f;URL&#x1f31f;URL组成部分&#x1f31f;URL 类&#x1f31f;url.href&#x1f31f;url.pathname&#x1f31f;url.port&#x1f31f;url.protocol&#x1f31f;url.search&#x1f31f;url.searchParams&#x1f31f;url.hash&#…

C语言模拟银行排队叫号(链队)

一.队列 队列是一种具有先进先出&#xff08;FIFO&#xff09;特性的线性数据结构&#xff0c;它只允许在队列的两端进行插入和删除操作。队列的一端称为队尾&#xff08;rear&#xff09;&#xff0c;另一端称为队头&#xff08;front&#xff09;。新元素总是插入在队列的队…

C++进阶——二叉搜索树BST

C进阶——二叉搜索树BST 其实应该是二叉树内容的进阶版本&#xff1a; 二叉树在前面C数据结构阶段已经讲过&#xff0c;本节取名二叉树进阶是因为&#xff1a; map和set特性需要先铺垫二叉搜索树&#xff0c;而二叉搜索树也是一种树形结构二叉搜索树的特性了解&#xff0c;有…

【路径规划】基于前向动态规划算法在地形上找到最佳路径(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

自然语言处理:词嵌入简介

动动发财的小手&#xff0c;点个赞吧&#xff01; Word Embeddings 机器学习模型“查看”数据的方式与我们&#xff08;人类&#xff09;的方式不同。例如&#xff0c;我们可以轻松理解“我看到一只猫”这一文本&#xff0c;但我们的模型却不能——它们需要特征向量。此类向量或…

C/C++每日一练(20230417)

目录 1. 字母异位词分组 &#x1f31f;&#x1f31f; 2. 计算右侧小于当前元素的个数 &#x1f31f;&#x1f31f;&#x1f31f; 3. 加一 &#x1f31f; &#x1f31f; 每日一练刷题专栏 &#x1f31f; Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 J…

通过简单demo让你秒懂Python的编译和执行全过程

基本说明 python 是一种解释型的编程语言&#xff0c;所以不像编译型语言那样需要显式的编译过程。然而&#xff0c;在 Python 代码执行之前&#xff0c;它需要被解释器转换成字节码&#xff0c;这个过程就是 Python 的编译过程。 DEMO演示讲解 假设我们有以下 Python 代码&…
最新文章