YOLOv8部署训练操作实录
开篇成功调用GPU训练了。
环境部署
YOLOv8
好像是23年1月出来的,当时正准备写论文就出来了,YOLOv8的部署较之前的版本是更为简单的(后来看了攻略才知道)。
pip install ultralytics
据说可以这样直接安装,但鉴于笔者当时没有看攻略,是依照之前版本上去Clone了一下库,然后通过requirements.txt安装的。
pip install -r requirements.txt
pip install -r requirements.txt -i http://pypi.douban.com/simple --trusted-host pypi.douban.com # 国内镜像加速
然后记得到这一步出现了一系列依赖冲突的问题(从来不建独立虚拟环境惹的)。
pip install 包名==版本号 -i http://pypi.douban.com/simple --trusted-host pypi.douban.com
笔者根据报错进行了一系列版本替换,成功让其跑了起来。
import ultralytics # 调用依赖库
ultralytics.checks() # 查看YOLO版本
调用GPU
因为鉴于毕设要训练模型,不调用GPU肯定不行,通过上述PIP命令安装好的默认是CPU版本。可以在Python控制台通过以下代码查看学习库是否支持调用GPU。
import torch # 调用依赖库
print(torch.__version__) # 查看pytorch版本
torch.cuda.is_available() # 查看GPU是否可用
官方文档给的是进入pytorch官网 https://pytorch.org/ 选择合适版本安装。
pip3 install torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu117 # 选择合适GPU版torch安装
这里笔者尝试官网首页好几个版本都失败了,或依赖冲突、或部署成功依然显示GPU不可用,报错好像是:
NotImplementedError: Could not run 'torchvision::nms' with arguments from the 'CUDA' backend.
23年3月注:在笔者想玩儿AI炼丹时将Python版本升级至3.10.10后,此问题不再出现。令人想起VMware,遇事不决,可以更新。
笔者这里降低到1.9.0+cu111版本也是在CSDN上翻了好多篇博主的文章才在本机尝试得到的可用版本。
pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio===0.9.0 -f https://download.pytorch.org/whl/torch_stable.html -i https://pypi.douban.com/simple
到这里如果得到的和笔者一样,应该就是部署成功啦。
模型应用
检测
文件准备: 一些需要检测的图片或视频。
yolo task=detect mode=predict model="./yolov8n.pt" conf=0.25 source="./ultralytics/assets/bus.jpg"
老面孔,这行代码是YOLO的应用,其他怎么都是加参数,调参。其中conf为置信度的门槛,常用的参数还有iou,降低可以防止对同目标的重复标记。
这里的yolov8n.pt笔者Clone来的库是没有的,是单独又下载来的,隐隐记得不上魔法下载速度感人,笔者把它放在了ultralytics根目录。在ultralytics根目录下的/ultralytics/assets/发现了经典图片,测一下,在runs目录下成功得到了结果。
训练
文件准备:
一个训练集,如图所示。
笔者model用的yolov8m.yaml文件用改的只有最上面的nc,改成你训练的类别数量,要和data.yaml里的nc保持一致。
# Ultralytics YOLO 🚀, GPL-3.0 license
# Parameters
nc: 1 # number of classes 只有这里用改,要和data.yaml里的nc保持一致
depth_multiple: 0.67 # scales module repeats
width_multiple: 0.75 # scales convolution channels
# YOLOv8.0m backbone
backbone:
# [from, repeats, module, args]
- [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
- [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
- [-1, 3, C2f, [128, True]]
- [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
- [-1, 6, C2f, [256, True]]
- [-1, 1, Conv, [512, 3, 2]] # 5-P4/16
- [-1, 6, C2f, [512, True]]
- [-1, 1, Conv, [768, 3, 2]] # 7-P5/32
- [-1, 3, C2f, [768, True]]
- [-1, 1, SPPF, [768, 5]] # 9
# YOLOv8.0m head
head:
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 3, C2f, [512]] # 13
- [-1, 1, nn.Upsample, [None, 2, 'nearest']]
- [[-1, 4], 1, Concat, [1]] # cat backbone P3
- [-1, 3, C2f, [256]] # 17 (P3/8-small)
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 12], 1, Concat, [1]] # cat head P4
- [-1, 3, C2f, [512]] # 20 (P4/16-medium)
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 9], 1, Concat, [1]] # cat head P5
- [-1, 3, C2f, [768]] # 23 (P5/32-large)
- [[15, 18, 21], 1, Detect, [nc]] # Detect(P3, P4, P5)
笔者data用到data.yaml,这个一般需要编写的多一点,注意nc和names数量一致即可。在使用时PATH试了好几回,相对路径的话他默认设置好像有些奇怪,容易像这样各种报:
Dataset 'datasets/data.yaml' not found ⚠️, missing paths ['D:\code\datasets\ultralytics\datasets\dataset\valid\images']
最后决定用绝对路径(注释的相对路径也根据尝试性报错傲娇的调通了喔)。
# Ultralytics YOLO 🚀, GPL-3.0 license
# COCO128 dataset https://www.kaggle.com/ultralytics/coco128 (first 128 images from COCO train2017) by Ultralytics
# Example usage: python train.py --data coco128.yaml
# parent
# ├── yolov5
# └── datasets
# └── coco128 ← downloads here (7 MB)
# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: D:\code\ultralytics\datasets # dataset root dir
# path: ../ultralytics/datasets
train: train/images # train images (relative to 'path') 128 images
val: valid/images # val images (relative to 'path') 128 images
test: test/images # test images (optional)
nc: 1
# Classes
names:
0: whitepoint
# 1: test
# Download script/URL (optional)
# download: https://ultralytics.com/assets/coco128.zip
然后test、train、valid就是分割测试、训练、检验数据集用的了,和v5一样,每个文件夹下一个images文件夹和一个labels文件夹,分别放图片和标注信息,对应标注信息文件名需要保持一致,如00001.jpg和00001.txt。
在这里还遇到了大概是这样的报错:
C:/w/b/windows/pytorch/aten/src/ATen/native/cuda/Loss.cu:111: block: [61,0,0], thread: [31,0,0] Assertion input_val >= zero && input_val <= one failed.
报错提示:https://pytorch.org/docs/stable/optim.html#how-to-adjust-learning-rate 来这里看原因,相关问题找了几篇博客感觉比较复杂。
笔者把images文件夹和一个labels文件夹下的文件名称修改为纯数字编码后不再报错,本来推测是原文件名太长且英语数字下划线杂糅导致的,结果想复刻这个报错时它不报了,神奇。。。
较之其他检测算法与常用的标注工具Lableme产出的json文件等,讲一下YOLO中标注信息txt文件的格式,为:
0 0.8520983333333334 0.8520983333333334 0.00146484375 0.003
分别代表: 类别编码 中心点x坐标 中心点y坐标 宽度 高度
坐标信息与宽度高度都需要进行归一化(数值控制在0-1之间)操作。
中心点x坐标:(x1 + x2) / 2 / w
中心点y坐标:(y1 + y2) / 2 / h
宽度:(x2 - x1) / w
高度:(y2 - y1) / h
(x1,y1)为左上角坐标
(x2,y2)为右下角坐标
w为图片宽度,h为图片高度
都准备好之后就可以开始训练啦:
yolo task=detect mode=train model=datasets/yolov8m.yaml data=datasets/data.yaml epochs=100 imgsz=640 device=0 resume=True
mode 较之检测时改为train,task和mode还有其他更多参数。
model 如上述,笔者是在\ultralytics\models\v8目录里扒拉到的,这里大家根据需求和配置用适合版本就行。
data 如上述,这里如果是要训练自己的模型就需要自己配置,模板去\ultralytics\yolo\data\datasets目录里抄,很多COCO数据集的配置文件。
epochs 是训练轮数,笔者大概有6000张图片,每张训练一遍在2s左右,训练100遍粗略一算要300h,达唛,这不能搞!
device 这里是调用显卡计算。
resume 大意是否支持中断继续训练的。
imgsz 输入训练的像素方块,看了一些其他攻略意思应该是越大越好,必须是32的倍数。
batch 一次处理的图片数量,为8的倍数会有更好效果。
更多参数以及默认值在\ultralytics\yolo\cfg\default.yaml文件里看。
在测试训练6000张图片十轮时遇到以下问题:
OSError: [WinError 1455]页面文件太小,无法完成操作。
这里引用的一篇网上的答案,大意给Python增配虚拟内存,成功解决,解决方案链接。
其后又遇到了Pycharm在提示:
Starting training for 10 epochs...
后闪退的问题,猜测线程炸了。增加参数workers=2,成功开始训练。
断续训
啊,随便一遍就要半个小时,正经训练起来耗时还是蛮久的,为了灵活安排,断训续训的操作少不了。可以通过 Ctrl + C 终止命令,然后再再适宜时调用以下命令进行续训。其中last.pt用自己终止结果的最后一次训练模型文件。
yolo task=detect mode=train model=runs/detect/train/weights/last.pt epochs=100 imgsz=640 device=0 resume=True workers=2
根据理解的话这里建议大家这个操作在一轮训练结束刚进入一下轮训练时使用。
Warning处理
RuntimeWarning: Glyph XXXXX missing from current font.
这个报错看了相关处理,应该是matplotlib字体不支持中文产生的。改了很多地方,单独用matplotlib没问题,但是通过YOLO调用的话还是不生效,研究了2h,到YOLOv8的confusion_matrix.png是在yolo/utils/metrics.py文件里的plot函数通过seaborn绘制的,加了参数没成功,最后所幸直接把catch出来的backend_agg.py中的函数给改了。这样应该会给性能带来较大损耗,应该研究研究怎么把字体作为参数传进YOLO,和项目原作者提出了这个问题,但是尝试未果。
def _get_agg_font(self, prop):
"""
Get the font for text instance t, caching for efficiency
"""
# fname = findfont(prop)
fname = 'D:\code\SimHei.ttf' # 强制替换字体
font = get_font(fname)
# print(fname,type(font))
font.clear()
size = prop.get_size_in_points()
font.set_size(size, self.dpi)
return font
val: WARNING D:\code\ultralytics\my_datasets\valid\images\00001.jpg: corrupt JPEG restored and saved
是因YOLO代码发现训练集中的jpg文件是被强制转换过来的,如果直接处理会有精度上的部分损失。这里比较科学的办法是,借助于PIL或者是OpenCV模块将原始格式的数据读取出来然后再存储为自己要的格式的数据就行了。
import os
import cv2
dataDir="../my_datasets/original/"
saveDir="../my_datasets/train/"
if not os.path.exists(saveDir):
os.makedirs(saveDir)
for one_pic in os.listdir(dataDir):
one_path=dataDir+one_pic
one_img=cv2.imread(one_path)
new_path=saveDir+one_pic
cv2.imwrite(new_path, one_img)