
CV视觉算法入门与调优
文章平均质量分 76
作者董董灿,公众号《董董灿是个攻城狮》主理人,全网科普AI算法,已帮助很多小伙伴入门AI。
该专栏面向的对象:想入门计算机视觉同学,已有一些基础但是想提高自己的同学,想学习神经网络性能优化的同学。
董董灿是个攻城狮
阿里云社区专家博主,AI算法工程师
展开
-
00、计算机视觉入门与调优简介
每天更新1篇文章,共更新100篇以上相关代码会放在gitee上中间会按进度和反馈安排视频讲解预计2023-11-11开始推送文章,持续3个月左右本专栏带你从头开始入门计算机视觉。内容会比之前写的文章更专业更全面,并且你可以深度链接作者,确保你能完全学会。我所理解的计算机视觉基础背景知识图片和像素灰度图彩色 RGB以及通道在计算机视觉中的含义彩色YUVOpenCV 介绍、环境搭建及一个实战完成YUV的分量提取小册内容丰富,从原理入门到算法解析到实战,全部包含。原创 2023-11-18 20:05:44 · 572 阅读 · 0 评论 -
快手面试,什么是矩阵乘法?
你可以这么理解,矩阵乘法的本质,是资源的整合和再创。我非常喜欢用下面的例子来说明这个问题。你是一个鸡尾酒调酒师,家里储存了很多鸡尾酒的原料,有金酒、利口酒、柠檬汁和可乐等等。今天家里来了 3 位客人,他们分别喜欢喝“自由古巴”、“长岛冰茶”以及“龙舌兰日出”这 3 款鸡尾酒,并向你下了单。希望你给他们调配出来各自喜欢的鸡尾酒。巧的是,这 3 款鸡尾酒的原料都是金酒、利口酒、柠檬汁和可乐。你作为一个调酒师,分分钟就把客人的爱好的鸡尾酒给调出来了。怎么做的呢?原创 2024-06-19 10:20:13 · 193 阅读 · 0 评论 -
我入门AI的学习感想
今天回答一个朋友问的问题。“我在入门深度学习的过程中,从配环境到 debug 全是坑,解决问题的时间远超跑模型的时间。这个问题真的问到我的心坎里了,多年前,我从机械硕士毕业转码搞软件开发,然后转行做深度学习算法,已有不少年了。转行的过程,就是从零开始的过程。无论是自学C++、Python这种编程技能,还是学习AI算法,还是钻研计算机体系结构,每一部分都有很多的感悟。这里重点说一下学习AI算法的经历和感受。记得第一次参加与深度学习算法的面试时,是一个小公司,面试官问我什么是权值?原创 2024-06-05 09:53:35 · 220 阅读 · 0 评论 -
99、仓库代码使用说明
另外,如果你想运行 python/model 目录下的文件,需要 cd 到 model 目录,安装解析模型相关的依赖库(可以不运行,我已经运行完并且将解析好的文件放在了 model 目录下,可直接用)。此外在仓库主目录下,还增加了一个 new_version_with_notes 目录: 这是本仓库的一个新版本,包含上述所有代码,里面的目录结构复刻了上述结构。6 个目录相互独立,可以独立运行任意目录中的代码,对比查看在迭代过程中,由于代码的优化带来的性能提升效果。原创 2024-04-07 22:34:52 · 83 阅读 · 0 评论 -
98、小册内容总结
本项目旨在完成对 AI 计算机视觉的入门学习。首先通过对一些经典的传统计算机视觉算法进行实操,理解计算机视觉的含义;随后以 resnet50 神经网络为例子,系统的讲解一个 AI 模型的基础算法原理和相关背景知识。最后通过本仓库中的代码实战,从零手写 resnet50 神经网络,完成任意一张图片的识别,以及神经网络模型的性能优化。传统计算机视觉部分,会有灰度图、RGB、均值/高斯滤波器、利用 Canny 算子对图像进行边缘检测、利用大津算法对图像进行分割等小的实操项目。原创 2024-03-07 22:40:22 · 155 阅读 · 0 评论 -
97、我对 AI 模型调优的经验和认识
做 AI 算法调优一些年了,这些年中接触了不少模型,也做过不少在 ASIC 芯片进行模型加速的案例。在接触的模型中,有一些模型有着非常奇怪的分支结构,有的还有奇怪的 tensor shape,还有的有这奇怪的自定义算法。但在模型优化时,为了将一个 AI 模型性能调到最优,也是无所不用其极,能用到的办法几乎都会尝试一遍。但是,有方法不代表有效。很多时候,在一个 AI 平台上有效的优化手段,换到了另一个平台上就失效了。原创 2024-03-07 22:39:01 · 303 阅读 · 0 评论 -
96、C++ 性能优化一览
在对 C++ 版本的 resnet50 经过大约 5 个版本的优化之后,性能也基本达到了预期。至少利用手写的 resnet50 在 CPU 上推理一张图片感觉不到卡顿了。下面对这几个版本的性能优化做一个总结。原创 2024-03-06 21:51:14 · 271 阅读 · 0 评论 -
95、评估使用多线程优化带来的性能提升
在相同的环境下,分别运行 5th_codegen 和 6th_multi_thread 下的 compile.sh 脚本进行代码编译,然后运行编译后生成的可执行文件 ./resnet。可以看到性能提升非常明显:优化前平均推理延时为 772 ms,优化后为 291 ms,性能提升了大概 260%,效果很好,而且推理结果也是正确的。注意:不同电脑机器不同环境下测出来的性能会有差异,大家只需要比对性能提升的相对值即可。本节评估一下,通过对卷积的 co 维度进行多线程切分之后,对于模型的性能提升。原创 2024-03-06 21:50:22 · 129 阅读 · 0 评论 -
94、利用多线程优化卷积运算
上一节简单介绍了多线程的概念,同时也介绍了在使用多线程编程时,对于数据在线程间的切分,应该遵循的一个原则:那就是切分独立的数据快,而不切分有数据依赖的数据块。最后还抛出了一个问题:对于卷积算法而言,你觉的切分哪个维度最合适呢?原创 2024-03-04 21:54:45 · 257 阅读 · 0 评论 -
93、多线程概念简介
多线程是一种并发编程技术,它允许程序同时执行多个线程,从而提高程序运行速度。在开始多线程优化之前,先看两个概念:进程和线程。进程我们可以简单粗暴的理解为一个应用进程,比如你在电脑上开一个QQ聊天,那么一个QQ应用就是一个进程,但如果你用一个QQ和多人同时聊天,可以认为每个人聊天都是一个线程,你此时在多线程工作。对应到 C++ 的 resnet50 示例中,当你在 linux 上执行 ./resnet 时,就开启了一个进程,在没有进行多线程编程的情况下,resnet 默认使用一个线程。原创 2024-03-04 21:53:36 · 101 阅读 · 0 评论 -
92、评估代码生成操作带来的性能提升
这是因为在目前很多主流的推理框架里,如TVM,MLIR中,都有比较完善的 codegen机制。他们大都是将一个模型中的算法,通过一些中间表示(IR)的形式表示出来,然后对这些中间表示进行优化(包括冗余计算消除,流水排布,指令调优,指令生成)。这其中,指令生成就是会将 IR 对应的计算逻辑直接生成与硬件相关的高效指令计算流。然后进行编译,运行模型。其实整体思路和我们进行的 codegen 差不太多,但是这些推理框架有十分完善的 IR 表示机制,而这个我没有办法手写来复现。原创 2024-02-29 21:16:35 · 109 阅读 · 0 评论 -
91、在推理流程中加载动态库中的Infer函数
注:建议在 new_version_with_notes 目录下尝试本节内容,有更为丰富的细节输出。在将生成的代码编译成一个动态链接库之后,接下来需要加载动态链接库中写好的推理入口函数,完成推理。在生成的代码中,在 codegen 目录下,有一个文件,里面是一个 Infer 函数,该函数由 5th_codegen/resnet_中的 CodeGen 函数生成。Infer 函数也就是推理的主入口函数。翻回 4th_no_malloc/原创 2024-02-29 21:15:33 · 112 阅读 · 0 评论 -
90、利用JIT编译技术完成对生成的代码的编译
在完成后,就需要对生成的代码进行编译,这里采用一种叫做 jit 的编译技术来进行。所谓 jit,就是just in time,可以理解为实时编译,它是在程序运行过程中对程序生成的一些中间文件进行编译,从而生成机器码的技术。对应到 codegen 场景下,由于 codegen 中生成的代码是在程序运行时生成的,因此很适合使用 jit 编译来进行。原创 2024-02-28 22:22:19 · 118 阅读 · 0 评论 -
89、对 resnet50 的c++实现进行代码生成
简单介绍了代码生成的逻辑,并且通过一个例子来进行了代码生成的演示。resnet50 的代码生成思路为:1. 先预先运行一遍模型,在核心计算函数的地方,通过输出字符串的形式,将关键信息(如内存地址、一些层的参数)作为确定值固定下来,然后构造相关算法逻辑的字符串流,输出到文本文件中。2. 生成的所有代码存放在 5th_codegen/ 下的 codegen 目录下。3. 程序运行(执行 ./resnet) 时会进行 jit 编译,调用相关编译命令对生成的代码文本进行编译,编译成动态库。原创 2024-02-28 22:21:33 · 485 阅读 · 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 · 194 阅读 · 0 评论 -
87、评估移除所有动态内存操作带来的性能提升
在相同的环境下,分别运行 3rd_preload 和 4th_no_malloc 下的 compile.sh 脚本进行代码编译,然后运行编译后生成的可执行文件 ./resnet。可以看到性能提升非常明显:优化前平均推理延时为 875ms,优化后为 742 ms,性能提升了大概 15%,还是很不错的。注意:不同电脑机器不同环境下测出来的性能会有差异,大家只需要比对性能提升的相对值即可。可以分别获取到权值预加载前后的性能指标。之后,对于模型的性能提升。原创 2024-02-25 21:13:41 · 83 阅读 · 0 评论 -
86、移除推理路径上的所有内存操作
动态申请内存的影响,前两节已经介绍过了,细心的朋友可能会发现,在使用 C++实现的 resnet50 代码中,还存在一处动态申请内存的操作。那就是对于每一层的输入或输出 feature map 数据进行内存申请,比如在文件中,卷积的计算中存在对于输出 feature map 的 malloc 行为。本节就使用一种全局内存复用的方法,来将每一层动态分配内存的操作删除掉,从而使得整个推理模型中,不存在任何动态申请内存的操作。原创 2024-02-23 23:01:24 · 93 阅读 · 0 评论 -
85、字符串操作的优化
介绍了在模型的推理优化过程中,动态内存申请会带来额外的性能损失。Python 语言在性能上之所以没有c++高效,有一部分原因就在于Python语言将内存的动态管理过程给封装起来了,我们作为 Python 语言的使用者是看不到这个过程的。这一点有点类似于 c++ 标准库中的一些操作, c++的标准库中提供了很多容器,常见的有vector,也就是数组,可类比于python中的列表,还有字符串string。原创 2024-02-23 23:00:17 · 119 阅读 · 0 评论 -
84、介绍:操作系统中内存申请的性能
本节简单的介绍一下在操作系统中的内存申请机制。有些同学看到这可能会有疑惑,我们不是在学习 AI吗,为什么要介绍内存申请的知识呢?因为无论是 AI,还是其他的计算学科,都离不开以下几个方面的内容:算法 + 操作系统 + 芯片 + 数据。AI 作为这几年爆火的学科,不是突然之间横空出世的,它是在已有的计算科学框架下,厚积薄发的一门学科。AI 与其他传统的学科相比,变化最大的地方应该是算法和芯片,但即使是这两方面,也离不开传统算法和传统芯片的加持。原创 2024-01-30 23:01:37 · 178 阅读 · 0 评论 -
83、评估权值预加载带来的性能提升
上两节介绍的权值预加载技术,在很多业务中是真实存在的。只不过限于本小册内容以及大部分同学硬件设备的局限,这里无法通过真正的推理框架(比如 tvm, pytorch) + GPU 来实现底层细节,这些推理框架中一般会将类似的优化技术封装起来。作为 tvm 或者 pytorch 的用户,你一般看不到这些实现细节,除非你是这些框架的开发者。因此,为了介绍这个优化,我通过 81、82 这两节内容来引入了一个简单的硬件-内存模型。原创 2024-01-29 20:43:18 · 322 阅读 · 0 评论 -
82、手写的模型如何模拟权值预加载
介绍了模型的权值预加载方法,以及为什么要做权值预加载。对于我们自己手写的模型,如何来完成权值预加载呢?其实大概分为以下几步:申请足够大的内存来存放模型的权值,这一步模拟的是 GPU 拥有足够的显存来存放模型权值将模型的所有权值加载到预申请的足够大的内存中,并且保持在推理过程中,这些内存中的权值数据不变,模拟的是GPU中权值驻留在显存空间中的操作。运行神经网络进行推理,运行到某一需要权值的层时,直接从已经申请的内存对应的位置中读取权值,然后进行推理计算。具体到这个项目代码中,是通过以下方式来实现的。原创 2024-01-29 20:42:37 · 85 阅读 · 0 评论 -
81、计算机基础:数据流加载以及为什么要做权值预加载
本节我们开启对手写的 resnet50 模型的第二个优化,对应到仓库中的优化代码为本次优化内容为模型的权值预加载。将模型的权值进行预加载,可以减少甚至消除模型推理过程中冗余的内存操作,降低推理延迟,大幅提高模型性能。所以,接下来的几节内容,会围绕这个优化来展开。在开始这个优化之前,先介绍一下计算机的基础知识,以及为什么要做这个优化。大家可能听说过冯诺依曼架构,事实上,现在很多的计算机(芯片)都是基于冯诺依曼架构来进行的设计。冯诺依曼架构的特点,总结下来可以这么理解:计算部件和存储部件的分离。原创 2024-01-22 22:24:44 · 154 阅读 · 0 评论 -
80、评估优化前后的性能差距
在测试的过程中,可以关注一下每次推理的结果,应该都是正确的,比如下面是我在第二版本中推理的Gou.jpg 的图像,一样会显示推理的 top1 准确度为 Samoyed。可以看到利用 avx2 优化后的第二版的延时为 5 s,吞吐为 0.2 fps。比第一版性能提升了约 3.4 倍,提升来源仅仅是做了一个卷积乘法的向量化计算。可以看到第一版的延时为 17s,吞吐为 0.06 fps。原创 2024-01-21 22:10:33 · 115 阅读 · 0 评论 -
79、avx2 向量指令集优化卷积运算
介绍了 avx2 向量指令集中的 load/store 操作,本节介绍如何使用 avx2 的向量指令集来实现乘累加运算。因为我们实战中用到的 resnet50 神经网络中,卷积运算在整个模型中的比例占据是相当高,而卷积运算的核心计算就是乘累加计算。因此,只要将最核心的乘累加计算效率提高,那么整个模型的性能就会有大幅度的提高。在介绍向量寄存器的时候,举了一个例子来说明向量加法的计算,向量乘法和向量加法一样,下面我们就用实际的代码来展示,如何完成向量乘法的计算。原创 2024-01-21 22:09:23 · 315 阅读 · 0 评论 -
78、avx2 数据 load/store 向量化操作介绍
向量寄存器和一个最简单的寄存器-内存的存储器模型,查看。本节基于整个内存模型,介绍一下如何使用 avx2 向量指令集,来完成数据从内存到寄存器中的交互的。原创 2024-01-17 21:21:33 · 247 阅读 · 0 评论 -
77、avx2 向量寄存器介绍
在现代计算机和高性能计算系统上,我们经常遇到各种术语,其中“向量寄存器”是一个重要的概念。先说一下寄存器,寄存器是 CPU 内最快速的存储设备,它直接用于参与计算,一般 CPU 中的寄存器个数不多。比如,我们电脑中常用的 Intel 芯片,寄存器是 64 位的,也就是说一个寄存器可以存放一个 int64 的数据,或者两个 int32 的数据。Intel i7 CPU 只有16个64位寄存器,因此,如果我们要实现一个 1+1等于2的运算,基本上需要占用 3 个寄存器。原创 2024-01-17 21:20:45 · 338 阅读 · 0 评论 -
76、avx2 向量指令集介绍
我们介绍了计算向量化的概念,简单来说,计算向量化就是把对数据的计算,从循环计算的方式,优化为使用一条指令来完成,起到性能优化的目的。接下来简单介绍一个在绝大部分电脑 CPU 上都有的向量指令集,后面我们也会用这个指令集来优化卷积运算,那就是 avx2 指令集。原创 2024-01-16 22:43:09 · 2352 阅读 · 0 评论 -
75、avx2 什么是计算向量化
接下来的几篇文章,会利用向量化指令来加速神经网络的计算,先学习一下什么是计算向量化。计算的向量化是一种对计算的优化方法,简单来说,就是让计算机在计算数据时,同一时间计算多个数据,而不是一个一个的循环计算,这样可以大幅提高计算的效率。计算向量化的概念,其实和线性代数中的向量运算有点类似。在线性代数中,向量运算比如向量点积,做的一整个向量的运算,映射到计算机来执行这个运算时,则依赖于计算机底层硬件对于向量指令的支持来实现的。原创 2024-01-16 22:41:58 · 173 阅读 · 0 评论 -
74、C++ - 开始进行一次基于 C++ 的推理吧
在经过了前面几节环境搭建和仓库介绍之后,下面开始进行一次 C++ 的全流程代码推理吧。原创 2024-01-16 00:03:00 · 93 阅读 · 0 评论 -
73、C++ 编译,运行介绍
在使用 C++ 仓库前,介绍一下 C++ 代码的执行流程:先编译后运行。这一点和python不一样,下面简单解释一下:静态类型语言和动态类型语言C++ 是一种静态类型语言,代码中所使用的变量的类型(如整型int,字符串 string)需要在编译期就确定,并且在编译器进行类型检查,确保没有问题,一旦失败就会编译报错。Python 是一种动态类型语言,它的变量类型在运行时动态确定。原创 2024-01-16 00:02:20 · 269 阅读 · 0 评论 -
72、C++ 代码格式规范的一个工具使用:clang-format
本节与小册内容无关,仅仅是介绍一个C++代码格式规范化的工具,用来将写的杂乱无章,格式不规范的C++代码来统一调整为规范的格式,包括空格、对齐等,使得C++代码美观大方。因为 C++ 仓库中用到了这个工具,所以介绍下,有平时用C++做开发的同学也可以使用一下。原创 2024-01-13 11:38:10 · 235 阅读 · 0 评论 -
71、C++ 环境搭建:10分钟快速在 windows 上安装一个 Linux 系统
这一节带大家搭建一个统一的 C++ 环境。因为不少人用的 C++ 环境都不一样,用的编译器、编辑器也都不一致,很难统一。我在准备写这篇的时候,思考了很久,最终决定搭建一个统一的环境,希望大家后面在运行和调试C++代码时,可以参考这个环境来进行。如果你是 linux 老用户,可以不采用这个方法,因为仓库代码中的环境本身就是基于 linux 环境做的,你只需要往后看,安装自己需要的 c++ 依赖包即可。原创 2024-01-13 11:36:10 · 296 阅读 · 0 评论 -
70、C++ - 仓库目录结构介绍
后面的优化基本都是基于 C++ 版本的代码来进行的,如果没有 C++ 的编程经验,可以顺便依托这个小的 C++ 项目来学一些 C++ 的基础知识。后面涉及 C++ 部分的内容,我也会尽可能写的详细一些。在进行 C++ 部分之前,先介绍一下 C++ 的代码仓库。只不过 C++ 部分在目录下。原创 2024-01-12 23:07:22 · 206 阅读 · 0 评论 -
69、python - 利用向量内积来优化卷积运算
上一节介绍了利用 python 实现的原始卷积版本性能很差的原因,不知道各位同学有尝试的么?这一节介绍下如何对卷积的乘累加进行一次优化:我们利用 np.dot 来进行优化。原创 2024-01-12 23:06:02 · 243 阅读 · 0 评论 -
68、python - 第一版手写代码性能评估
上一节介绍了这两个评价神经网络模型性能的指标。这一节利用这两个参数,来实际评测一下我们自己手写的模型的性能到底如何?注:因为代码是跑在自己的电脑上,大家基本也都是CPU环境,即使是相同的代码,在不同的电脑上运行得出的性能指标也会有较大差异。差异主要来源于电脑配置以及运行负载。建议自己测试性能时,将其他无关程序都关闭,最大程度上保证自己性能测试的环境一致性。原创 2024-01-11 19:11:59 · 126 阅读 · 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 · 606 阅读 · 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 · 696 阅读 · 0 评论 -
65、python - 利用手写的网络,成功预测一张图片
上面两节通过介绍了几种预处理方法,分别是和在完成图像预处理之后,加上之前手动搭建的神经网络,其实我们就可以对图形进行推理识别了。这一节我们使用自己手写的算法、自己搭建的神经网络,来第一次完成一张图像的识别。下面对一些重要代码做一下说明。上面代码逻辑是完成推理的主要逻辑,包含了加载图像、推理以及结果验证。下面一点点说明。原创 2024-01-10 22:00:26 · 353 阅读 · 0 评论 -
64、图片预处理:Normalize
介绍了图像预处理中 resize 和 crop 的概念,在仓库的 python 预处理函数中,在 resize 和 crop之后,还有几个预处理的过程:一个是归一化,另外就是transpose 和reshape。这一节就介绍一下,为什么在推理之前还需要对图像进行归一化。原创 2024-01-09 22:39:18 · 1016 阅读 · 0 评论 -
63、图片预处理:Resize and Crop
resize 一般指的是图像在长和宽方向上的尺寸缩放。目前有很多算法可以完成图像的 resize 操作。最常见的就是插值算法,插值算法很多同学可能接触过,大概就是通过已有的像素点来推测未知位置上的像素点的值,从而完成图像像素的填充,重建或者平滑。原创 2024-01-09 22:37:54 · 1461 阅读 · 0 评论