Yolo v5学习笔记
Yolo v5学习笔记
小游Yolo v5学习笔记
安装环境
下载miniconda
Index of /anaconda/miniconda/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror
打开Anaconda Prompt
conda create -n yolov5 python=3.8 |
配置PYPI 镜像
打开https://mirrors.tuna.tsinghua.edu.cn/help/pypi/
复制下面这句
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple |
安装pytorch
这里选择的是 v1.8.2版本,我直接下载的cpu的嘻嘻~
pip install torch==1.8.2 torchvision==0.9.2 torchaudio==0.8.2 --extra-index-url https://download.pytorch.org/whl/lts/1.8/cpu |
安装yolov5
解压文件,将文件中的requirements.txt打开,将
然后打开yolo文件夹所在位置,运行
pip install -r requirements.txt |
运行测试
运行两次
python detect.py |
成功
关于yolov5安装的补充
实战!Yolov5模型检测
一、关键参数
1.weights 参数
2.source参数
例如,对某个目录下的某张图片进行检测,
python detect.py --weights weights/yolov5x.pt --source data/images/bus.jpg |
哈哈哈哈笑死我啦,运行上一行代码让我把Pillow降级或者numpy升级,我把Pillow降级为了8.4.0,现在又让我升级啦,如何呢??嘻嘻
Ultralytics(YOLOv5 的维护者)要求安装一个特定版本或更高版本的 Pillow(至少为 10.3.0),在运行代码时,会将pillow自动升级,所以我们选择升级numpy~
下边是对屏幕进行检测
python detect.py --weights weights/yolov5x.pt --source screen |
3.conf-thres 置信度阈值
置信度阈值,越低框越多,越高框越少(当检测到的目标的轮廓小于置信度阈值的时候,这个框不显示)
python detect.py --weights weights/yolov5s.pt --conf 0.25 |
4.iou-thres IOU阈值
IOU阈值,越低框越少,越高框越多(与上一个相反)
5.其他参数(其他参数在detect.py文件里可以看到)
- imgsz 输入图片的默认大小
- max-det 在一个图片中最大的检测数量
- device 设备,如果过不指定的话,系统会自己匹配一个合适的设备
- view-img 会把检测结果弹出一个框来
- classes 指定检测哪几类
二、基于torch.hub的检测方法
提供更为简单的检测途径,特别是放到一个可视化界面中
这里我们用jupyter进行编写
如果没有的话可以先安装:
pip install jupyterlab |
import torch |
ok了,又说我numpy版本不行了,笑一下好了Successfully installed numpy-1.24.4~
还是不对,Successfully installed numpy-1.20.3~
都不行,怎么回事老弟,我学不学了?
Successfully installed numpy-1.23.0 解决问题
三、数据集构建
数据收集
import cv2 |
# 打开视频文件 |
plt.imshow(frame) |
这里读取图片不是按RGB通道读取的,是用的BGR通道,所以我们下边转换一下通道
plt.imshow(cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)) |
这里是读取视频,将截取的图片存到文件夹里
video = cv2.VideoCapture("./BVN.mp4") |
标注工具
下载标注工具
pip install labelimg |
在终端运行这个,然后打开新页面
labelimg |
第一步,将模式设置为yolo
第二步,点击view,点击Auto Save mode,设置为自动保存
第三步,点击左侧菜单中的Open Dir,第一次选择的文件夹是标注的图片位置(images),第二次我们创建一个和images同级的labels文件夹,用于存放标注图片
第四步,点击右侧打开图片,右击图片选择第一个选项开始标注(或者按W)
按D是下一张,A是上一张
标注完成后,我们labels文件里就有东西了
里边的classes.txt文件存放的是我们是别的标签
四、yolo模型训练
数据调整
像这样分好
关键参数
第一步,把datasets文件移进来
第二步,把下边这个yaml文件复制并且改名
第三步,配置这个刚复制过来的yaml文件
第四步,打开train.py文件,改一个参数
第五步,运行!点击右上角的运行标志
然后我又报错了,AttributeError: module ‘numpy.typing’ has no attribute ‘NDArray’
还是numpy,如何呢老弟?
报错是因为之前的requirements.txt文件中写了numpy的版本,运行之后会自动匹配文件里的版本,这样才会报错。改一下就好了
运行了一下,电脑黑屏了(嗯…..)
常见问题
训练结果
我没训出来,半个小时进度8/99太慢了,学完再慢慢训吧,别把我训没了
我是笨蛋,因为路径打错了,所以人家自动下载了别的数据集,所以下载慢
训好的东西存在run/train/exp里边
训练集:
验证:
运行tensorboard --logdir runs
可以看到很多表
检测视频
python detect.py --weights |
五、Pyside6可视化界面
环境安装
在终端运行where python
查看python路径·
按路径找到pydesigner.exe后,创建快捷方式到桌面
需要把Qt生成的UI文件转换为python文件,需要一个插件,我们在vscode里搜索下载
接下来打开Qt开始设计
第一步,将元素拖拽组合
第二步,设置属性
为了调整图片自适应大小,把下边这个也勾选上
我们再对各个元素进行一个命名
到这里我们的界面就设计完成啦,ctrl+s保存。
把这个ui文件放在yolov5文件夹里,然后右键
点击之后我们就获得了一个main_window_ui.py文件
接着我们创建一个base_ui.py
文件,把下边的代码复制进去
import sys |
在这里运行自己的模型的时候,出来的图片没有被检测到,不知道为什么捏
是因为我的训练太少啦!改一下训练轮次
有convert2QImage是因为模型预测得到的 list数据要转化为 QImage类型后,才能继续转化为QPixmap类型,进而才能显示出来
import sys |
现在图像的检测就搞定了(视频里在这里卸载了pywin32)
下边我们对视频进行检测
当我们写完进行检测时发现,页面很卡,这是因为Qt的事件阻塞(connect+while true),我们可以启用计时器来解决这个问题(QTime),也就相当于把while true这里的逻辑替换成了QTimer
import cv2 |
但是我们在检测视频的时候打开图片,图片会一闪然后消失,这是因为计时器还在干活
,我们优化一下逻辑。
效果展示
六、Yolov5 Gradio搭建Web GUI
相比于pyside6,少了很多代码,可以在web上显示
在终端输入pip install gradio,新建文件夹gradio_demo.py
import torch |
这是结果展示
Yolov5拓展进阶
一、模型结构与构建原理
我们打开models文件夹,里边有很多模型的yaml文件,我们点开yolov5s.yaml来看一下
- nc 是类别数量
- 中间的表示图片的大小
- anchors 对应了三组模框
backbone解释:
- from:输入来自那一层,-1代表上一次,1代表第1层,3代表第3层
- number:模块的数量,最终数量需要乘 depth_multiple,然后四舍五入取整,如果小于1,取1(看上图,除了C3模块不为1,其他都是等于1的)。
- module:子模块 (用的啥模块)
- args:模块参数,channel,kernel_size,stride,padding,bias等
二、使用Tensorboard可视化
在终端输入命令下载:
pip install tensorboard==2.12.0 |
输入命令打开可视化界面
tensorboard --logdir runs |
我打不开,报错:
找了解决办法,但是还是不行。
所以下边的图是用的何老师的
进入浏览器后,点击“graphs”,然后双击detection Model,进入了模型得内部细节
三、数据流动过程(二刷明白基础流程逻辑了,但还是感觉不太透彻)
向上采样(*2)(Upsampling):
向上采样是指增加图像的分辨率,通常通过插值方法在图像中插入新的像素来实现。常见的插值方法包括最近邻插值、双线性插值和双三次插值等。通过向上采样,可以增加图像的细节和清晰度,但同时也增加了图像的计算量和存储空间。向下采样(/2)(Downsampling):
向下采样是指降低图像的分辨率,通常通过从图像中删除一些像素来实现。这些被删除的像素通常是通过取样的方式进行选择。向下采样可以减少图像的计算量和存储空间,但也可能导致信息丢失和图像质量下降。
下面从input的图片开始,整个走一遍
input输入的图片是 1×3×640×640
经过Conv[0] 之后,变成了 1 × 32 × 320 × 320
1×3×640×640 变成了 1 × 32 × 320 × 320,图片缩小了1/2,参考yolov5s。yaml中的代码,如下图(#0 表示第0层,#1表示第一层)
到了#2,C3的输出是 1 × 64 × 160 × 160
到了#3 Conv的输出是 1×128×80×80
到了#5,又经过一次卷积,1 × 256 × 40 × 40 ,也就是 640 / 16= 40,缩小了16倍。到了#7, 又经过一次卷积,输出是 1 × 512 × 20 × 20
到了#9,其实是第10层了(SPPF),输出还是 1 × 512 × 20 ×20,如下图
下面是head部分
head的第一层是Conv[10],输出是 1 × 256 × 20 × 20
由于在#11做了上采样,输出是 1 × 256 × 40 × 40
那么在#12,进行拼接,一个来自#6层(1 × 256 × 40 × 40),
一个来自#11(上采样后 1 × 256 × 40 × 40)
最后一层,来自#17,#20和#23的特征图
[[17, 20, 23], 1, Detect, [nc, anchors]], #Detect(P3, P4, P5) |
head里的[-1,3,c3,[256,False]],#17(P3/8-small)
是八倍下采样,是用来检测小目标的
[-1,3,C3,[512,False]],#20(P4/16-medium)
是十六倍下采样(40*40),是用来检测中等大小的目标的
[-1,3,C3,[1024,False]],#23(P5/32-large)
是32倍下采样,是用来检测比较大的物体的
接着我们看,代码是怎么实现这个文件的
我们打开train.py文件
cfg就是config文件,就是我们的yolov5s.yaml文件,ch=3就是通道数是3,nc是我们要识别的东西(我们传过去之后会自动更新)
可以在这里创建新的模型common.py
可以在这里引入模型,进入模型解析,并传入需要的参数
有关深度和宽度的控制,如下:
上图中,args里的第一个为定义通道数,实际的通道数要 乘以width_multiple
四、修改网络结构–以C2f为例
v8希望框架以命令行的形式去执行,做了很多额外的东西,所以跟v5长得不太一样
如果要看源码的话,咱们就去ultralytics文件里找
打开ultralytics-nn-moudles.py.(moudles.py在新版本里是没有的,我们这里用的是8.0.90)
这个文件其实就相当于yolov5中的common.py文件
然后我们看这个c2f,把这个模块复制到yolov5的common文件里去
我们放在了c3模块的前边
因为模块c2f的Bottleneck里有参数k,是yolov5中不包含的,所以我们把Bottleneck相应的部分也复制过去。
为了避免这个会对yolov5其他的部分造成影响,我们这里将Bottleneck重命名为C2fBottleneck
通过比较可以看出,C2f和C3所需要的参数基本是一样的,所以我们打开yolov5的yolo.py文件,找C3所在的位置,把C2f也放进去就行了
先导入我们新加的C2f
主要是在parse_model这个模块里边
然后我们修改一下yaml文件,我们把yolov5s.yaml文件复制一份,命名为yolov4sC2f.yaml,将文件里的C3替换为C2f
下面我们开始训练
打开train.py文件,找到parse_opt模块
如果我们要训练自己的模型,就要更改这个cfg参数
但是weights参数对我们的影响还是有的,有参数的话,就根据这个权重继续训练,如果没有的话,就相当于完全的从头开始训练。
我们看一下这部分的相关代码:
如果pretrained识别到了这个以pt结尾的文件,就根据这个权重继续训练。
下面我们运行命令直接训练一下
python train.py |
如果报错tensorflow.python.framework.errors_impl.FailedPreconditionError: runs is not a directory
是因为文件路径里有中文,改一下就好了
训练过程中我们会发现,结果是很多零,这是因为我们Cf2生成的一些随机的坐标是很难对应上的,但是不用担心,让它多训练会儿就好了,视频中训练到25轮次的时候就出现数字了,但是我呢,您猜怎么着,41轮了还没有(爽啦)
我到第59轮才有的数字
运行完成之后,我这里有一个报错:AttributeError: module 'PIL.Image' has no attribute 'ANTIALIAS'
。
是因为在较新的版本的 Pillow(PIL 的一个分支)中,ANTIALIAS
常量已被移除。在 Pillow 10.0.0 及以后的版本中,需要使用 Image.LANCZOS
来替代 Image.ANTIALIAS
。
咱们的训练结果已经出来了,这个错误主要影响 TensorBoard 日志的生成和记录。咱们暂时不需要 TensorBoard 的可视化结果,所以忽略这个错误,训练模型的性能不会受到影响。
但是非常不幸,咱们训练的这个模型效果不太好,并没有检测到目标,可以增加训练轮次?但是他们说按理来说这是可以训练出来的,不知道我的为啥检测不到,就算我再训练一次也不见得会好(瘫)
不对啊,我这个怎么跟从头训练的一样?怎么回事
我们把train.py里的weights参数改一下,pt文件就用刚刚训练出来的(看的何老师笔记,试试肿么样)
这里更换pt文件是因为新的pt文件里训练出来的权重更适合咱们的模型
parser.add_argument("--weights", type=str, default=ROOT / "runs/train/exp17/weights/best.pt", help="initial weights path") |
结果还没出来,但是感觉能行,训练的时间好长,我的小电脑好慢(偷偷学教资)
结果出来了
对比上一次的,嗯…..怎么比的有大有小的
但是这次咱们识别到了(庆祝!)
Yolo进阶之——引入注意力机制—以SE为例
借鉴代码
https://github.com/ZhugeKongan/Attention-mechanism-implementation
一、加入新增网络结构
打开common.py,将下面这个文件的内容粘贴进去
二、新建yaml文件
复制yolov5文件,并重新命名
在backbone下边再添加一行,作为第十层,将head中大于10的层数+1
三、配置参数
然后进入yolo.py,parse_model模块
添加
为什么要设定c2,而不是直接使用c1?因为parse_model中,C2 是用来记录输出维度的,最后会将c2的值存入ch中,所以务必要对c2的值进行设定
四、开始训练
然后我们运行train.py文件进行训练
报错TypeError: init() takes 3 positional arguments but 4 were given
是因为这里我添加了SE,去掉就好了
Yolo进阶之替换主干网络——以MobileNet为例
一、加入新的网络结构
我们下载的包里有,所以咱们在主目录下边新建demo.ipynb文件,下边是代码
torchvision 0.13开始,加载预训练模型函数的参数从pretrained = True 改为 weights=预训练模型参数版本 。
如果你不知道哪个权重文件的版本是最新的,没关系,直接选择默认DEFAULT即可。官方会随着 torchvision 的升级而让 DEFAULT权重文件版本保持在最新。
progress=True 是显示一个进度条,如果下载过了,就不显示进度条了
import torchvision.models as models |
model = models.mobilenet_v3_small(weights=models.MobileNet_V3_Small_Weights.DEFAULT,progress=True) |
然后我们通过model就可以看到这个模型了
为了更好地查看这个库,我们`pip install torchinfo,并导入这个包.
summary(model, input_size=(1, 3, 640, 640)) |
如果在你觉得无比正确的某一步报错了,不要怀疑自己,切换一下环境,再换回来,就好了。这个编辑器喜欢发癫,适应了就好了。(思考)
运行后的输出:
可以点击text editor
查看更详细的部分
因为MobileNet本来是用于分类的,但是咱们现在只需要特征提取那一部分,所以咱们就只看 features部分就好了
所以我们修改一下代码,运行下边的部分,看一下 features部分
summary(model.features, input_size=(1, 3, 640, 640)) |
运行结果
=============================================================================================== |
一个重要的值得关注的问题
如果要替换backbone,由于YOLO采用的是金字塔结构,具有一定的对称性,体现在之后可以将输入拼起来(这里的拼起来指的是,前几层的输出,可以在后几层,跟别的层一起拼起来:就比如说,一般某一层的输入是上一层的输出,但是head里边,某些层的输入=是上一层+前边某一层的输出,是一个列表,不是单个的前一层的输入)这个不理解的话可以看咱们yolov5给的图(Tensorboard可视化)
我们以yolov5s.yaml文件解释一下这个问题:
backbone的八倍采样、十六倍采样和三十二倍采样都很重要,因为head里边是要用的。
然后来看mobileNet的结构,正好有我们需要的这个几个下采样
所以我们可以把1-4层作为第一个模块
把这个作为16倍下采样
从第10层开始,对应32倍下采样
另外,查看 model.features 的类型可知,如下图
其特性在于可以通过切片来取模型结构
例如,参考下图,取前四个模块,如下图
就可以使用 如下命令,如下图
了解了原理,我们下边开始写代码
二、修改common.py文件
代码如下
import torchvision.models as models |
然后我们开始写yaml文件,还是跟原来一样,复制一份yolov5s.yaml并进行重命名
输出通道数看最后一层的输出通道数,第一层的输出通道是24
这里是yaml文件修改完成之后的代码
# Ultralytics YOLOv5 🚀, AGPL-3.0 license |
三、修改yolo文件
在yolo中注册
四、修改train文件
首先我们先把这个参数改为空
运行查看一下它的参数量
然后我们将参数改为我们刚刚创建好的mobilenet的yaml文件,下图是mobilenet的参数量
好!本节结束
Yolov5 项目部署
一、TensorRt环境安装与配置
TensorRt可以用来实现推理加速
安装好第二个之后,将里边的文件剪切到cuda的c盘的文件里边
路径是这样的
移动好之后,我们打开cmd测试是否安装成功
下载好第三个之后解压,我们进入conda环境,查看python版本,我这里是3.8.19.
然后我们打开刚刚解压的文件
我们在终端进入这个文件夹,并且安装相应python版本,这里安装的是cp38版本的
pip install tensorrt-8.5.3.1-cp38-none-win_amd64.whl |
接下来我们把lib中的文件复制到CUDA中,我的路径是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.6\bin
,如果复制过来的话,编译的时候会报错找不到。
我没有下载第四个。
我们打开vscode 打开yolov5里的export.py文件
可以看到,我们需要下载很多东西
其中有一个onnx,它是一个中间状态的东西,我们可以把模型转为onnx,然后再用onnx转出去。
我们需要安装一下onnx,直接在环境中pip就可以 pip install onnx
这里说了导出的用法
咱们现在导出的是TensorRT,所以咱们是用engine
先把Usage里的这段复制下来python export.py --weights yolov5s.pt --include
在后边加上engine,再加上--device 0
,这样就可以了,下边是命令
python export.py --weights yolov5s.pt --include engine --device 0 |
但是–device 0是说用的GPU,但是我没有GPU!
最终我选择了不导出 TensorRT,而是导出ONNX。
导出之后,视频用detect对视频进行了检测python detect.py --weights yolov5s.engine
二、正确使用TensorRT推理加速
我们先来对比一下,咱们导出的TensorRT模型,对比于pythorch模型,他们的处理速度之间会有怎样的差异
我们先来跑一下,看他们平均每一帧需要多长时间来做一个对比
首先是pythorch检测python detect.py --weights yolov5s.pt
接着是TensorRT:python detect.py --weights yolov5s.engine
但是我们发现TensorRT的时间竟然比之前还要长了,这是为什么捏?
其实他们两个输入数据的维度不太一样,pythorch是384x640,TensorRT是640x640,所以TensorRT才会慢
但是为什么他们的数据不一样呢?
TensorRT要求输入维度和输出维度是一样的,我们可以通过这样写命令来python detect.py --weights yolov5s.engine --imgsz 384 640
更改输入维度,但是报错了,那么这个输入输出唯独是怎么来的呢?
其实是在我们导出的时候,在这里定义的。
如果说我们需要它检测384x640维度的,要在这里进行修改,因为TensorRT会根据你的输入维度对模型进行一个加速,这个维度是定死的
所以我们重新导出一下
python export.py --weights yolov5s.pt --include engine --device 0 img 384 640 |
视频重新运行了
python detect.py --weights yolov5s-fp32.engine --imgsz 384 640 |
我们现在可以看到,推理时间只有10ms
我们在导出的时候,还可以加一个half参数,用半精度推理实现,加速深度学习训练
导出命令是这样的
python export.py --weights yolov5s.pt --include engine --device 0 img 384 640 --half |
然后我们看一下半精度模型的训练速度怎么样
python detect.py --weights yolov5s-fp16.engine --imgsz 384 640 --half |
这个速度还可以提升!!
如果我们不考虑精度的损失的话,我们还可以进一步缩小这个图像的维度,但是我们不要缩小的太小,只要能满足32倍、16倍、8倍下采样的话,这个是可以缩到192x320的(这个没听太懂,笔记也没做太好)
视频又导出了一版,是192x320精度的
python detect.py --weights yolov5s-halfsize.engine --imgsz 192 320 |
只花了5.7ms
在导出模型的时候。一定要记得把输入维度跟最终预测的这些图像的维度对齐,只有这样的话才能保证咱们的加速是有效的。
三、Torchhub模型预测使用进阶
我们来看一下load这个方法,第一个参数是路径,第二个参数是model在这里就是custom
然后我们看一下里边的内容
首先是source,他只接受GitHub和local两个参数,并调用相应的方法-
然后下边是load_local方法,里边第一个参数是路径,这里有一个非常值得注意的点,就是我们本地加载的模型要在yolov5-master目录下,不然会报错
我们看一下hubconf.py
我们第二个参数custom方法对应的就是这个,它会根据我们后边的path路径,最终create,然后把模型返回
如果我们不用自己训练的模型,而是用官方训练好的模型,我们可以去修改这个custom参数
咱们下边再看一下预测
之前的预测咱们是直接给图片的路径
现在咱们优化一下
imgs = [ |
那我们有个问题,该怎么去找这个模型的预测方法呢
其实创建了我们autoship类型的模型之后,在这个文件下可以看到能用的方法
我们可以看这里的源码,来判断用哪个,怎么拿到我们需要的东西
如果我们要拿到每一个类别的检测结果。可以用这个
如果我们希望把每一个识别到的实体(也就是那个框)裁剪出来,可以用crop方法
但是我们可以看到,调取crop方法出来的是这个
我们可以根据这些信息去选择将哪一部分去做一个可视化
from IPython.display import display |
这样就可以可视化了
如果想要得到检测结果中文本的那一部分
我们可以
str(results) |
但是我们将模型换为TensorRT的模型的时候,框起来的的值不是person、tie这样的
我们要设置一下
model.names = {0:"person",27:"tie"} |
这样就好了
四、基于Flask的Yolov5项目部署
官方写的在这里
example_request.py里边是连接方式
restapi.py里边的东西可以直接拿来用,改一下里边的模型参数就行
接下来我们把这两个文件复制到主目录下
修改一下
restapi:
example_request:
基于图像的预测方式代码:
restapi.py里加入:
example_request:
到这里我们实现了往Flask服务器发图片,下边实现返回图片
example_request:
# Ultralytics YOLOv5 🚀, AGPL-3.0 license |
restapi.py
if request.data: |
到这里就完成了,结课!