![](https://img-blog.csdnimg.cn/20190918140158853.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
CV视觉算法入门与调优
文章平均质量分 76
作者董董灿,公众号《董董灿是个攻城狮》主理人,全网科普AI算法,已帮助很多小伙伴入门AI。
该专栏面向的对象:想入门计算机视觉同学,已有一些基础但是想提高自己的同学,想学习神经网络性能优化的同学。
董董灿是个攻城狮
阿里云社区专家博主,AI算法工程师
展开
-
00、计算机视觉入门与调优简介
每天更新1篇文章,共更新100篇以上相关代码会放在gitee上中间会按进度和反馈安排视频讲解预计2023-11-11开始推送文章,持续3个月左右本专栏带你从头开始入门计算机视觉。内容会比之前写的文章更专业更全面,并且你可以深度链接作者,确保你能完全学会。我所理解的计算机视觉基础背景知识图片和像素灰度图彩色 RGB以及通道在计算机视觉中的含义彩色YUVOpenCV 介绍、环境搭建及一个实战完成YUV的分量提取小册内容丰富,从原理入门到算法解析到实战,全部包含。原创 2023-11-18 20:05:44 · 520 阅读 · 0 评论 -
快手面试,什么是矩阵乘法?
你可以这么理解,矩阵乘法的本质,是资源的整合和再创。我非常喜欢用下面的例子来说明这个问题。你是一个鸡尾酒调酒师,家里储存了很多鸡尾酒的原料,有金酒、利口酒、柠檬汁和可乐等等。今天家里来了 3 位客人,他们分别喜欢喝“自由古巴”、“长岛冰茶”以及“龙舌兰日出”这 3 款鸡尾酒,并向你下了单。希望你给他们调配出来各自喜欢的鸡尾酒。巧的是,这 3 款鸡尾酒的原料都是金酒、利口酒、柠檬汁和可乐。你作为一个调酒师,分分钟就把客人的爱好的鸡尾酒给调出来了。怎么做的呢?原创 2024-06-19 10:20:13 · 120 阅读 · 0 评论 -
99、仓库代码使用说明
另外,如果你想运行 python/model 目录下的文件,需要 cd 到 model 目录,安装解析模型相关的依赖库(可以不运行,我已经运行完并且将解析好的文件放在了 model 目录下,可直接用)。此外在仓库主目录下,还增加了一个 new_version_with_notes 目录: 这是本仓库的一个新版本,包含上述所有代码,里面的目录结构复刻了上述结构。6 个目录相互独立,可以独立运行任意目录中的代码,对比查看在迭代过程中,由于代码的优化带来的性能提升效果。原创 2024-04-07 22:34:52 · 46 阅读 · 0 评论 -
98、小册内容总结
本项目旨在完成对 AI 计算机视觉的入门学习。首先通过对一些经典的传统计算机视觉算法进行实操,理解计算机视觉的含义;随后以 resnet50 神经网络为例子,系统的讲解一个 AI 模型的基础算法原理和相关背景知识。最后通过本仓库中的代码实战,从零手写 resnet50 神经网络,完成任意一张图片的识别,以及神经网络模型的性能优化。传统计算机视觉部分,会有灰度图、RGB、均值/高斯滤波器、利用 Canny 算子对图像进行边缘检测、利用大津算法对图像进行分割等小的实操项目。原创 2024-03-07 22:40:22 · 111 阅读 · 0 评论 -
97、我对 AI 模型调优的经验和认识
做 AI 算法调优一些年了,这些年中接触了不少模型,也做过不少在 ASIC 芯片进行模型加速的案例。在接触的模型中,有一些模型有着非常奇怪的分支结构,有的还有奇怪的 tensor shape,还有的有这奇怪的自定义算法。但在模型优化时,为了将一个 AI 模型性能调到最优,也是无所不用其极,能用到的办法几乎都会尝试一遍。但是,有方法不代表有效。很多时候,在一个 AI 平台上有效的优化手段,换到了另一个平台上就失效了。原创 2024-03-07 22:39:01 · 150 阅读 · 0 评论 -
96、C++ 性能优化一览
在对 C++ 版本的 resnet50 经过大约 5 个版本的优化之后,性能也基本达到了预期。至少利用手写的 resnet50 在 CPU 上推理一张图片感觉不到卡顿了。下面对这几个版本的性能优化做一个总结。原创 2024-03-06 21:51:14 · 215 阅读 · 0 评论 -
94、利用多线程优化卷积运算
上一节简单介绍了多线程的概念,同时也介绍了在使用多线程编程时,对于数据在线程间的切分,应该遵循的一个原则:那就是切分独立的数据快,而不切分有数据依赖的数据块。最后还抛出了一个问题:对于卷积算法而言,你觉的切分哪个维度最合适呢?原创 2024-03-04 21:54:45 · 165 阅读 · 0 评论 -
93、多线程概念简介
多线程是一种并发编程技术,它允许程序同时执行多个线程,从而提高程序运行速度。在开始多线程优化之前,先看两个概念:进程和线程。进程我们可以简单粗暴的理解为一个应用进程,比如你在电脑上开一个QQ聊天,那么一个QQ应用就是一个进程,但如果你用一个QQ和多人同时聊天,可以认为每个人聊天都是一个线程,你此时在多线程工作。对应到 C++ 的 resnet50 示例中,当你在 linux 上执行 ./resnet 时,就开启了一个进程,在没有进行多线程编程的情况下,resnet 默认使用一个线程。原创 2024-03-04 21:53:36 · 52 阅读 · 0 评论 -
91、在推理流程中加载动态库中的Infer函数
注:建议在 new_version_with_notes 目录下尝试本节内容,有更为丰富的细节输出。在将生成的代码编译成一个动态链接库之后,接下来需要加载动态链接库中写好的推理入口函数,完成推理。在生成的代码中,在 codegen 目录下,有一个文件,里面是一个 Infer 函数,该函数由 5th_codegen/resnet_中的 CodeGen 函数生成。Infer 函数也就是推理的主入口函数。翻回 4th_no_malloc/原创 2024-02-29 21:15:33 · 46 阅读 · 0 评论 -
89、对 resnet50 的c++实现进行代码生成
简单介绍了代码生成的逻辑,并且通过一个例子来进行了代码生成的演示。resnet50 的代码生成思路为:1. 先预先运行一遍模型,在核心计算函数的地方,通过输出字符串的形式,将关键信息(如内存地址、一些层的参数)作为确定值固定下来,然后构造相关算法逻辑的字符串流,输出到文本文件中。2. 生成的所有代码存放在 5th_codegen/ 下的 codegen 目录下。3. 程序运行(执行 ./resnet) 时会进行 jit 编译,调用相关编译命令对生成的代码文本进行编译,编译成动态库。原创 2024-02-28 22:21:33 · 331 阅读 · 0 评论 -
88、代码生成初探
先看个例子,假设要实现如下功能:对两个等长的数组,将第一个数组中数值为偶数的数与第二个数组中对应位置的数相加,得到一个新的数组,其余位置设为0。i < 5;i++) {if (v1[i] % 2 == 0) { // 判断是否是偶数// 如果为偶数则相加这样写没问题,但是深入分析就可以看到,数组中 index 为0 和 3 的位置为奇数,只有1,2,4的位置为偶数,相加操作仅计算 index = 1,2,4 的位置即可。这种写法和上面的写法区别在于:没有了循环的使用。原创 2024-02-28 09:25:36 · 154 阅读 · 0 评论 -
85、字符串操作的优化
介绍了在模型的推理优化过程中,动态内存申请会带来额外的性能损失。Python 语言在性能上之所以没有c++高效,有一部分原因就在于Python语言将内存的动态管理过程给封装起来了,我们作为 Python 语言的使用者是看不到这个过程的。这一点有点类似于 c++ 标准库中的一些操作, c++的标准库中提供了很多容器,常见的有vector,也就是数组,可类比于python中的列表,还有字符串string。原创 2024-02-23 23:00:17 · 71 阅读 · 0 评论 -
84、介绍:操作系统中内存申请的性能
本节简单的介绍一下在操作系统中的内存申请机制。有些同学看到这可能会有疑惑,我们不是在学习 AI吗,为什么要介绍内存申请的知识呢?因为无论是 AI,还是其他的计算学科,都离不开以下几个方面的内容:算法 + 操作系统 + 芯片 + 数据。AI 作为这几年爆火的学科,不是突然之间横空出世的,它是在已有的计算科学框架下,厚积薄发的一门学科。AI 与其他传统的学科相比,变化最大的地方应该是算法和芯片,但即使是这两方面,也离不开传统算法和传统芯片的加持。原创 2024-01-30 23:01:37 · 128 阅读 · 0 评论 -
81、计算机基础:数据流加载以及为什么要做权值预加载
本节我们开启对手写的 resnet50 模型的第二个优化,对应到仓库中的优化代码为本次优化内容为模型的权值预加载。将模型的权值进行预加载,可以减少甚至消除模型推理过程中冗余的内存操作,降低推理延迟,大幅提高模型性能。所以,接下来的几节内容,会围绕这个优化来展开。在开始这个优化之前,先介绍一下计算机的基础知识,以及为什么要做这个优化。大家可能听说过冯诺依曼架构,事实上,现在很多的计算机(芯片)都是基于冯诺依曼架构来进行的设计。冯诺依曼架构的特点,总结下来可以这么理解:计算部件和存储部件的分离。原创 2024-01-22 22:24:44 · 101 阅读 · 0 评论 -
79、avx2 向量指令集优化卷积运算
介绍了 avx2 向量指令集中的 load/store 操作,本节介绍如何使用 avx2 的向量指令集来实现乘累加运算。因为我们实战中用到的 resnet50 神经网络中,卷积运算在整个模型中的比例占据是相当高,而卷积运算的核心计算就是乘累加计算。因此,只要将最核心的乘累加计算效率提高,那么整个模型的性能就会有大幅度的提高。在介绍向量寄存器的时候,举了一个例子来说明向量加法的计算,向量乘法和向量加法一样,下面我们就用实际的代码来展示,如何完成向量乘法的计算。原创 2024-01-21 22:09:23 · 147 阅读 · 0 评论 -
78、avx2 数据 load/store 向量化操作介绍
向量寄存器和一个最简单的寄存器-内存的存储器模型,查看。本节基于整个内存模型,介绍一下如何使用 avx2 向量指令集,来完成数据从内存到寄存器中的交互的。原创 2024-01-17 21:21:33 · 78 阅读 · 0 评论 -
76、avx2 向量指令集介绍
我们介绍了计算向量化的概念,简单来说,计算向量化就是把对数据的计算,从循环计算的方式,优化为使用一条指令来完成,起到性能优化的目的。接下来简单介绍一个在绝大部分电脑 CPU 上都有的向量指令集,后面我们也会用这个指令集来优化卷积运算,那就是 avx2 指令集。原创 2024-01-16 22:43:09 · 970 阅读 · 0 评论 -
74、C++ - 开始进行一次基于 C++ 的推理吧
在经过了前面几节环境搭建和仓库介绍之后,下面开始进行一次 C++ 的全流程代码推理吧。原创 2024-01-16 00:03:00 · 51 阅读 · 0 评论 -
73、C++ 编译,运行介绍
在使用 C++ 仓库前,介绍一下 C++ 代码的执行流程:先编译后运行。这一点和python不一样,下面简单解释一下:静态类型语言和动态类型语言C++ 是一种静态类型语言,代码中所使用的变量的类型(如整型int,字符串 string)需要在编译期就确定,并且在编译器进行类型检查,确保没有问题,一旦失败就会编译报错。Python 是一种动态类型语言,它的变量类型在运行时动态确定。原创 2024-01-16 00:02:20 · 224 阅读 · 0 评论 -
72、C++ 代码格式规范的一个工具使用:clang-format
本节与小册内容无关,仅仅是介绍一个C++代码格式规范化的工具,用来将写的杂乱无章,格式不规范的C++代码来统一调整为规范的格式,包括空格、对齐等,使得C++代码美观大方。因为 C++ 仓库中用到了这个工具,所以介绍下,有平时用C++做开发的同学也可以使用一下。原创 2024-01-13 11:38:10 · 123 阅读 · 0 评论 -
71、C++ 环境搭建:10分钟快速在 windows 上安装一个 Linux 系统
这一节带大家搭建一个统一的 C++ 环境。因为不少人用的 C++ 环境都不一样,用的编译器、编辑器也都不一致,很难统一。我在准备写这篇的时候,思考了很久,最终决定搭建一个统一的环境,希望大家后面在运行和调试C++代码时,可以参考这个环境来进行。如果你是 linux 老用户,可以不采用这个方法,因为仓库代码中的环境本身就是基于 linux 环境做的,你只需要往后看,安装自己需要的 c++ 依赖包即可。原创 2024-01-13 11:36:10 · 215 阅读 · 0 评论 -
70、C++ - 仓库目录结构介绍
后面的优化基本都是基于 C++ 版本的代码来进行的,如果没有 C++ 的编程经验,可以顺便依托这个小的 C++ 项目来学一些 C++ 的基础知识。后面涉及 C++ 部分的内容,我也会尽可能写的详细一些。在进行 C++ 部分之前,先介绍一下 C++ 的代码仓库。只不过 C++ 部分在目录下。原创 2024-01-12 23:07:22 · 168 阅读 · 0 评论 -
69、python - 利用向量内积来优化卷积运算
上一节介绍了利用 python 实现的原始卷积版本性能很差的原因,不知道各位同学有尝试的么?这一节介绍下如何对卷积的乘累加进行一次优化:我们利用 np.dot 来进行优化。原创 2024-01-12 23:06:02 · 167 阅读 · 0 评论 -
68、python - 第一版手写代码性能评估
上一节介绍了这两个评价神经网络模型性能的指标。这一节利用这两个参数,来实际评测一下我们自己手写的模型的性能到底如何?注:因为代码是跑在自己的电脑上,大家基本也都是CPU环境,即使是相同的代码,在不同的电脑上运行得出的性能指标也会有较大差异。差异主要来源于电脑配置以及运行负载。建议自己测试性能时,将其他无关程序都关闭,最大程度上保证自己性能测试的环境一致性。原创 2024-01-11 19:11:59 · 82 阅读 · 0 评论 -
67、AI 模型性能评估指标:吞吐和延时
吞吐量是1/60个人每秒,也就是说,如果存在 1/60个人去取钱的话,那么ATM机每秒能接待的客户是1/60个。举个例子,如果说一条数据通路的吞吐量是 40Gbps,那么意味着,如果你往这个数据通路中注入40Gb 的数据量,那么它可以在1秒内流过这条数据通路。和只有一台ATM机的时候相比,延时没有变,一个客户取一次钱,都是需要花费1分钟,但是整个ATM机的吞吐量却增加了一倍。这就意味着,如果我排着队轮到我使用这台ATM机取钱,我可以预见的是,1分钟的时间,我就可以拿到钱并且离开ATM机。原创 2024-01-11 19:11:13 · 284 阅读 · 0 评论 -
66、python - 代码仓库介绍
整个仓库目录如上,后面估计不会大改,可能会有持续更新,但会保持目录结构的一致。红色框标注的是在介绍传统计算机视觉时用到的一些实操代码。大家可以点击下方链接来回顾一下。0_gray: 灰度图1_RGB: 彩色图2_mean_blur: 均值滤波3_gussian_blur: 高斯滤波4_canny: canny 算法5_dajin: 大津算法完成图像分割6_mnist: 手写数字识别项目练手以上几部分互相独立,目录间没有任何关系,可以独立使用。原创 2024-01-10 22:01:52 · 645 阅读 · 0 评论 -
65、python - 利用手写的网络,成功预测一张图片
上面两节通过介绍了几种预处理方法,分别是和在完成图像预处理之后,加上之前手动搭建的神经网络,其实我们就可以对图形进行推理识别了。这一节我们使用自己手写的算法、自己搭建的神经网络,来第一次完成一张图像的识别。下面对一些重要代码做一下说明。上面代码逻辑是完成推理的主要逻辑,包含了加载图像、推理以及结果验证。下面一点点说明。原创 2024-01-10 22:00:26 · 304 阅读 · 0 评论 -
64、图片预处理:Normalize
介绍了图像预处理中 resize 和 crop 的概念,在仓库的 python 预处理函数中,在 resize 和 crop之后,还有几个预处理的过程:一个是归一化,另外就是transpose 和reshape。这一节就介绍一下,为什么在推理之前还需要对图像进行归一化。原创 2024-01-09 22:39:18 · 823 阅读 · 0 评论 -
63、图片预处理:Resize and Crop
resize 一般指的是图像在长和宽方向上的尺寸缩放。目前有很多算法可以完成图像的 resize 操作。最常见的就是插值算法,插值算法很多同学可能接触过,大概就是通过已有的像素点来推测未知位置上的像素点的值,从而完成图像像素的填充,重建或者平滑。原创 2024-01-09 22:37:54 · 1083 阅读 · 0 评论 -
62、python - 全手写搭建 resnet50 神经网络
每一层命名为 Computexxx,比如第一层 ComputeConvLayer 说明这一层是一个卷积运算,ComputeAvgPoolLayer 说明这一层是一个平均池化运算,ComputeBottleNeck 说明这一层是一个BoottleNeck 结构,该结构包含了残差链接,查看上一节和前面一些。除了第一层的 ComputeConvLayer 第一个参数是 img 之外,后面所有层的第一个输入均为上一层的输出 out, 体现了神经网络逐层连接,数据从前往后流动的特点。的章节中,下载的模型。原创 2024-01-07 20:29:15 · 1256 阅读 · 1 评论 -
61、python - 手写卷积、bn、池化、全连接、激活、ResBlock
给出的示例是用 python 语法来实现的,也是实现的最基础的版本,这也是我们手写算法的初衷:不调用其他的三方库,从最基础的手写算法开始,一步步完成算法实现和性能优化,这样可以更加深刻的理解算法。下面整理一下之前手写的算法连接,大家可以参考或者复习一下,当然也可以根据自己的理解,来写一个你认为更好的算法实现出来。这篇算是一个总结,之前的原理部分在介绍各个算法时候,已经加入了每个算法的代码编写介绍。建议把以上连接中的代码都看一下,或者尝试自己重新写一个更好的版本。原创 2024-01-07 20:28:20 · 450 阅读 · 0 评论 -
60、resnet50 权值和参数加载
上一节我们将 resnet50 中需要下载的权值,以及每层卷积的参数,都下载并且保存到了 仓库 resnet50_weight 目录,在。在将权值保存好之后,接下来就是要看如何使用这些权值,也就是如何加载。本节就介绍下我们实战过程中,如何加载这些权值。原创 2024-01-07 20:27:02 · 1228 阅读 · 0 评论 -
59、resnet50 权值和参数保存
上一节我们下载好了模型,这一节开始将模型中存在权值的层的权值参数抽取出来,以文件(txt后缀的文本文件)的形式保存在本地电脑上,方便后续推理使用。按照之前介绍算法时所说的,在 resnet50 中,存在权值的层有卷积层(权值为卷积核)、bn层(权值为gamma 和 bias),全连接层(权值为矩阵)同时,我们把所有卷积层中的参数(padding,stride,kernel_size等)同样保存下来,也是为了方便在推理到这一层时直接使用。原创 2024-01-07 20:25:35 · 1063 阅读 · 0 评论 -
58、resnet50 模型下载
上图是我截取的打印的模型结构的一部分,红框中标注的就是之前我们介绍过的残差结构中下采样的部分。是 PyTorch 库中的一个函数,用于从 PyTorch Hub 中加载预训练的模型,示例中通过这个接口,下载了 resnet50 这个模型。推理模式和训练模式在某一些算法上是不一样的,还记得在介绍 BN 算法的时候是如何区分推理模式还是训练模式的吗?在这个接口中,pretrained = True 说明下载的模型是已经预训练好的,也就是模型中包含有训练好的参数。可以先看前 7 行,其余的暂时不需要看。原创 2024-01-07 10:07:11 · 1668 阅读 · 0 评论 -
57、python 环境搭建[for 计算机视觉从入门到调优项目]
从本节开始,进入到代码实战部分,在开始之前,先简单进行一下说明。代码实战部分,我会默认大家有一定的编程基础,不需要对编程很精通,但是至少要会 python 的基础语法、python 环境搭建、pip 的使用;C++ 要熟悉基础知识和基础语法,会根据文章中的步骤完成 C++ 的环境搭建,以及 C++ 编译和运行。如果确实有某一部分之前没有接触过,可以借着代码实战部分的示例,多查查资料,把这部分知识丰富起来,虽然每一部分涉及的知识不会很深,但还是要有基础的概念和技能。原创 2024-01-07 10:06:19 · 655 阅读 · 0 评论 -
56、resnet中的下采样
这一节是算法原理和背景的最后一章节,下一节开始进入实战部分。如果你从第一节看到这一节,这总共56节的内容基本上都能理解的话,那么恭喜你,算法原理部分已经掌握了,也基本接近入门了。总结一下算法原理的部分,介绍了传统计算机视觉的一些算法,比如滤波算法,然后介绍了一些深度学习的基础概念,包括训练和推理,正向传播,反向传播和损失函数。随后重点介绍了resnet这一神经网络中用到的算法,包括卷积算法,批归一化算法,池化算法,激活函数,还有矩阵乘算法,以及每一个算法的原理和优势。原创 2024-01-07 10:05:01 · 586 阅读 · 0 评论 -
55、交叉熵损失函数和softmax
其实上面说的 Q1 里面的每个概率,就是softmax的输出,从这个例子里也可以看出为什么在分类网络的最后一层,需要将真实的模型输出转换为0~1之间的概率分布了。假设模型经过了改良,在完成一次推理或者一轮训练后,对第一张图得到了如下的预测,也就是说这张图有98%的概率是狗,这离标签的100%已经差的很少了。该分类表明,第一张图像越 40%的概率是狗,30%的概率是狐狸,5%的概率是马,5%的概率是老鹰,20%的概率是松鼠。此时,P(i) 和 Q(i) 服从两种不同的概率分布,交叉熵的“交叉”就体现在这。原创 2024-01-05 22:27:58 · 932 阅读 · 0 评论 -
54、Softmax 分类器以及它的底层原理
例子中猫的得分是2,狗的得分是1,人的得分是0.1,我们可以比较肯定的说,因为猫的得分最高,而且比狗和人都高很多,肯定就是猫。这就是 SoftMax 的底层原理:指数让得分大的分类最终的概率更大,得分小的分类最终的概率更小,而得分为负数的分类,几乎可以忽略。也就是说,猫得了 2 分,狗得了 1 分,人得了 0.1 分,单看这个结果,我们大概知道,因为猫的得分最高,那最终神经网络会认为这张图片是一只猫,这么理解是可以的,但是大概还是有两个地方有些问题。对于某些任务,比如进行垃圾邮件的检测是非常重要的。原创 2024-01-05 22:25:49 · 947 阅读 · 0 评论 -
53、实战 - 手写一个全连接算法
全连接算法在一定程度上和矩阵乘法算法等价,因此如果我们想实现一个全连接。的算法,只需要实现一个矩阵乘法就可以。。矩阵乘法是线性代数运算,用于将两个矩阵相乘得到一个新的矩阵。要执行矩阵乘法,需要确保第一个矩阵的列数与第二个矩阵的行数相等。比如第一个矩阵的维度为 m×k,第二个矩阵的维度为 k×n,则相乘得到的新矩阵的维度为 m×n。通过上面的描述,我们可以看到矩阵乘法的乘累加维度,实际上是 k 那一维度,他通过将k 那一维的所有数据进行逐元素相乘,并且累加成一个值来完成特征的融合。原创 2024-01-04 22:23:01 · 513 阅读 · 0 评论 -
52、全连接 - 特征与样本空间的对应关系
上一节说到经过全连接层之后,神经网络学习到的特征,会从隐层特征空间逐步映射到样本空间,这主要是由于全连接层可以融合全局的特征。在经过全连接层之后,在 ResNet50 这个神经网络中会输出1000个特征的得分值,这1000个特征的得分值,便可以对应到图像的分类。怎么对应呢?选取得分最高的那一个特征,它对应的索引下标就是图像分类的索引下标。这里简单说一下 ResNet50 模型训练时所采用的数据集。ResNet50 是在 ImageNet 数据集上进行的预训练。原创 2024-01-04 22:21:56 · 599 阅读 · 0 评论