目录
一、简介
最近为了应付毕业论文,学习了目标检测,目的是检测车辆和行人,使用了yolov5,想到了是否可以在mac 上跑yolov5 ,因为是m1芯片,以及系统的更新,踩了不少坑,总结了几个博主的经验,顺利的在mac上实现了yolov5的训练和检测。
踩坑点:pyqt5安装、labelimg安装(需前置pyqt5)、yolov5训练时隐藏文件文件.DS_store无法识别
配置
电脑型号:2021 mbp m1 pro
系统版本:ventura 13.0 (22A380)
环境准备
anaconda individual 最新版
python 3.9.13
pytorch 2.0 (后面有教程)
TensorFlow 2.11.0(后面有教程)
Pyqt5 5.15.7(后面有教程)
labelimg 1.8.6
pycharm 2022.3
yolov5
二、环境配置
1.安装anaconda
(1)进入官网
官网链接:Anaconda | The World's Most Popular Data Science Platform
直接在这里下载并安装anaconda就可以
(2)点击安装包进行安装
直接无脑点下一步
在这一步时选择仅为我安装。
安装好之后再应用程序里就可以看见。
(3)打开终端之后
发现前面有个(base)就是安装成功了。
2.安装TensorFlow
(1)创建一个新的anaconda环境
conda create -n tf python=3.9.13
(2)切换到tf环境(再打开终端时要记得切到这个环境)
conda activate tf
前面有(tf)则是转换成功
(3)安装macos版本的TensorFlow。
如果显示404等错误,可以尝试挂个梯子。
conda install -c apple tensorflow-deps
python3 -m pip install tensorflow-macos
(如果不确定使用python3还是python,可以使用which python查看路径,使用虚拟环境下的python才有效)
python3 -m pip install tensorflow-metal
(4)然后在终端输入
python3
import tensorflow
如果出现
则是成功
exit()
可以退出python命令行
报错——>提示numpy版本不兼容(numpy版本过低要重新装)
conda uninstall numpy
pip install numpy
再次尝试导入tensorflow重复(4)中
成功
3.安装pytorch
进入pytorch官网
点击install 出现
选择相应的配置
在终端运行
pip3 install torch torchvision torchaudio
等待安装完成即可。
4.pyqt5安装
因为labelimg需要Pyqt5,但高版本macos 的pyqt安装会出错。
可以先运行一下
pip install pyqt5
如果成功则这步省略
出错则需要进行安装homebrew 再用brew去安装pyqt5
(1)安装homebrew
Homebrew — The Missing Package Manager for macOS (or Linux)
首页就是安装方法
终端运行
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
安装完成之后 使用brew 安装pyqt5
brew install pyqt5
如果你的brew 长时间没更新
会报404找不到资源的错误,那就先要更新brew,csdn搜索即可。
安装完成之后进入homebrew的cellar文件夹
我的在
/opt/homebrew/Cellar
找到pyqt@5文件夹点进去
目录如下所示
/opt/homebrew/Cellar/pyqt@5/5.15.7_2/lib/python3.9/site-packages
把下列文件全部放到anaconda环境中
首先找到conda的环境
conda env list
我的tf环境在
/Users/qishuocheng/anaconda3/envs/tf
使用前往文件夹就可以
点进去找到lib文件夹
/Users/qishuocheng/anaconda3/envs/tf/lib/python3.9/site-packages
把上面pyqt5的文件放进来
python
import PyQt5
不报错就算成功
5.安装labelimg
上述完成后进行
pip install labelimg
安装完成之后
输入
labelimg
出现这个即可。
6.下载yolov5
GitHub - ultralytics/yolov5 at v6.1
直接下载zip
或者git clone到本地
git clone https://github.com/ultralytics/yolov5.git (加本地文件地址)
没有git 的要先
pip install git
7.pycharm安装
PyCharm: the Python IDE for Professional Developers by JetBrains
进入官网
下载之后配置
切到你的conda环境
如果没有就添加本地解释器
选择你的环境点击确定就可以切换环境啦。
三、使用labelimg标记图片
1.准备工作
在yolov5目录下新建一个名为VOCData的文件夹
在VOCData文件夹下创建 Annotations 和 images 文件夹
images放要训练的图片
(【🎯易错】:images的文件名不建议修改,否则之后训练时容易出现No labels found的错误,原因见下)
[说明]:
Annotations 文件夹用于存放使用labelimg标记后的图片(XML格式)
images 文件夹用于存放用于标记的图片
(【🎯易错】:images 文件夹下直接放图片,内部不要嵌套有文件夹,否则之后训练可能会出现 No label found 的错误,具体原因见下文中 xml_to_yolo.py文件的第67行)
2.标记图片
在cmd窗口下输入 labelimg 或者运行 labelimg.py 文件进入labelimg的可执行程序(注:如果是在虚拟环境下安装的labelimg,记得先激活虚拟环境)
conda activate tf(你自己的虚拟环境名)
分别设置需要标注图片的文件夹和存放标记结果的文件夹的地址
图像放在之前设置好的images里
更改存放目录改为Annotions文件夹里
推荐设置自动保存
标记图片快捷键:w:标记 a:上一张图片 d:下一张图片
标注的时候尽可能贴近物体轮廓
四、 划分数据集以及配置文件修改
1. 划分训练集、验证集、测试集
在VOCData目录下创建程序 split_train_val.py 并运行以下代码。代码可以不做任何修改
注意注意:在macos下,文件夹内会生成.Ds_store隐藏文件要先删除 不然会读取错误
打开images文件夹(之前创建的文件)
这是我的文件夹 根据自己路径找
cd /Users/qishuocheng/Desktop/yolov5/VOCData/images
ls -a
删除这个文件后
rm .DS_Store
运行下面的代码(images下存放你的图片)
# coding:utf-8import osimport randomimport argparseparser = argparse.ArgumentParser()#xml文件的地址,根据自己的数据进行修改 xml一般存放在Annotations下parser.add_argument('--xml_path', default='Annotations', type=str, help='input xml label path')#数据集的划分,地址选择自己数据下的ImageSets/Mainparser.add_argument('--txt_path', default='ImageSets/Main', type=str, help='output txt label path')opt = parser.parse_args()trainval_percent = 1.0 # 训练集和验证集所占比例。 这里没有划分测试集train_percent = 0.9 # 训练集所占比例,可自己进行调整xmlfilepath = opt.xml_pathtxtsavepath = opt.txt_pathtotal_xml = os.listdir(xmlfilepath)if not os.path.exists(txtsavepath): os.makedirs(txtsavepath)num = len(total_xml)list_index = range(num)tv = int(num * trainval_percent)tr = int(tv * train_percent)trainval = random.sample(list_index, tv)train = random.sample(trainval, tr)file_trainval = open(txtsavepath + '/trainval.txt', 'w')file_test = open(txtsavepath + '/test.txt', 'w')file_train = open(txtsavepath + '/train.txt', 'w')file_val = open(txtsavepath + '/val.txt', 'w')for i in list_index: name = total_xml[i][:-4] + '\n' if i in trainval: file_trainval.write(name) if i in train: file_train.write(name) else: file_val.write(name) else: file_test.write(name)file_trainval.close()file_train.close()file_val.close()file_test.close()
运行结束后会在生成一个名为 ImageSets 的文件夹:
测试集里的内容为空,因为在划分数据的时候,将90%的数据划分到训练集,将10%的数据划分到训练集。如果要分配,则调整上面14,15行代码中trainval和train的所占的比例
[说明]:
训练集是用来训练模型的,通过尝试不同的方法和思路使用训练集来训练不同的模型
验证集使用交叉验证来挑选最优的模型,通过不断的迭代来改善模型在验证集上的性能
测试集用来评估模型的性能
2.XML格式转yolo_txt格式
在VOCData目录下创建程序 xml_to_yolo.py 并运行以下代码,注意:
将classes改为自己标注时设置的类名(我这里叫"car")
将各个绝对路径修改为自己的
# -*- coding: utf-8 -*-import xml.etree.ElementTree as ETimport osfrom os import getcwdsets = ['train', 'val', 'test']classes = ["car"] # 改成自己的类别abs_path = os.getcwd()print(abs_path)def convert(size, box): dw = 1. / (size[0]) dh = 1. / (size[1]) x = (box[0] + box[1]) / 2.0 - 1 y = (box[2] + box[3]) / 2.0 - 1 w = box[1] - box[0] h = box[3] - box[2] x = x * dw w = w * dw y = y * dh h = h * dh return x, y, w, hdef convert_annotation(image): in_file = open('/Users/qishuocheng/Desktop/yolov5/VOCData/Annotations/%s.xml' % image,encoding='utf-8') out_file = open('/Users/qishuocheng/Desktop/yolov5/VOCData/labels/%s.txt' % image, 'w') tree = ET.parse(in_file) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) for obj in root.iter('object'): difficult = obj.find('difficult').text # difficult = obj.find('Difficult').text cls = obj.find('name').text if cls not in classes or int(difficult) == 1: continue cls_id = classes.index(cls) xmlbox = obj.find('bndbox') b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) b1, b2, b3, b4 = b # 标注越界修正 if b2 > w: b2 = w if b4 > h: b4 = h b = (b1, b2, b3, b4) bb = convert((w, h), b) out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')wd = getcwd()for image_set in sets: if not os.path.exists('/Users/qishuocheng/Desktop/yolov5/VOCData/labels/'): os.makedirs('/Users/qishuocheng/Desktop/yolov5/VOCData/labels/') image_ids = open( '/Users/qishuocheng/Desktop/yolov5/VOCData/ImageSets/Main/%s.txt' % image_set).read().strip().split() if not os.path.exists('/Users/qishuocheng/Desktop/yolov5/VOCData/dataSet_path/'): os.makedirs('/Users/qishuocheng/Desktop/yolov5/VOCData/dataSet_path/') list_file = open('dataSet_path/%s.txt' % image_set, 'w') # 这行路径不需更改,这是相对路径 for image_id in image_ids: list_file.write('/Users/qishuocheng/Desktop/yolov5/VOCData/images/%s.jpeg\n' % image_id) convert_annotation(image_id) list_file.close()
运行后会生成如下图所示的 dataSet_path 和 labels 文件夹。dataSet_path下会有三个数据集的txt文件,labels下存放各个图像的标注文件
3.配置文件
在 yolov5 的 data 文件夹下创建一个名为 myvoc.yaml,模板如下,改成自己的路径,根据自己实际情况填写:
(【🎯易错】:注意冒号后面是有空格的)
train: /Users/qishuocheng/Desktop/yolov5/VOCData/dataSet_path/train.txt
val: /Users/qishuocheng/Desktop/yolov5/VOCData/dataSet_path/val.txt
# number of classes
nc: 1
# class names
names: ["car"]
4.聚类获得先验框
在 models 文件夹下找到 yolov5s.yaml(如果使用这个权重模型训练的话),将其中的 nc 改为实际上标注类的数量,和 myvoc.yaml 一样(记得保存)。
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license# Parametersnc: 1 # 只改这里 改成自己的类的数量depth_multiple: 0.33 # model depth multiplewidth_multiple: 0.50 # layer channel multipleanchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32# YOLOv5 v6.0 backbonebackbone: # [from, number, module, args] [[-1, 1, Conv, [64, 6, 2, 2]], # 0-P1/2 [-1, 1, Conv, [128, 3, 2]], # 1-P2/4 [-1, 3, C3, [128]], [-1, 1, Conv, [256, 3, 2]], # 3-P3/8 [-1, 6, C3, [256]], [-1, 1, Conv, [512, 3, 2]], # 5-P4/16 [-1, 9, C3, [512]], [-1, 1, Conv, [1024, 3, 2]], # 7-P5/32 [-1, 3, C3, [1024]], [-1, 1, SPPF, [1024, 5]], # 9 ]# YOLOv5 v6.0 headhead: [[-1, 1, Conv, [512, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 6], 1, Concat, [1]], # cat backbone P4 [-1, 3, C3, [512, False]], # 13 [-1, 1, Conv, [256, 1, 1]], [-1, 1, nn.Upsample, [None, 2, 'nearest']], [[-1, 4], 1, Concat, [1]], # cat backbone P3 [-1, 3, C3, [256, False]], # 17 (P3/8-small) [-1, 1, Conv, [256, 3, 2]], [[-1, 14], 1, Concat, [1]], # cat head P4 [-1, 3, C3, [512, False]], # 20 (P4/16-medium) [-1, 1, Conv, [512, 3, 2]], [[-1, 10], 1, Concat, [1]], # cat head P5 [-1, 3, C3, [1024, False]], # 23 (P5/32-large) [[17, 20, 23], 1, Detect, [nc, anchors]], # Detect(P3, P4, P5) ]
五、使用CPU训练
在cmd窗口下激活相应虚拟环境后 cd 到 yolov5 文件夹后,输入下列指令即可开始训练
mac也可以调用mps加速,听说有bug 不如用cpu训练的快,所以建议用cpu
python train.py --weights yolov5s.pt --cfg models/yolov5s.yaml --data data/myvoc.yaml --epoch 200 --batch-size 8 --img 640 --device cpu
[参数说明]:
--weights :权重文件所在的相对路径
--cfg:存储模型结构配置文件的相对路径
--data:存储训练、测试数据的文件的相对路径
--epoch:训练过程中整个数据集将被迭代(训练)了多少次
--batch-size:训练完多少张图片才进行权重更新
--img:img-size
--device:选择用CPU或者GPU训练
(开始训练)
训练完成!
六、训练结果可视化
训练结果将保存在/yolov5/runs/train/exp 文件夹下,部分文件意义如下:
weights:训练生成权重。包含 best.pt (最好的权重,detect时用到它),和 last.pt(最近生成的权重模型)
confusion:混淆矩阵。混淆矩阵让我们了解分类模型所犯的错误,更重要的是可以了解哪些错误类型正在发生。
F1_curve:置信度和F1分数的关系图
P_curve:准确率和置信度的关系图
R_curve:召回率和置信度之间的关系
PR_curve:PR曲线中的P代表的是precision(精准率),R代表的是recall(召回率),其代表的是精准率与召回率的关系
labels:左上图表示个类别的数据量;右上图表示标签;左下图表示 center 的 xy 坐标;右下图表示各个标签的长和宽
训练时或者训练后,输入tensorboard --logdir=runs,即可利用 tensorboard 实现训练结果可视化
tensorboard --logdir=runs
在高版本的tensorboard中 有个很恶心的点需要更改 = 为 "" 不然识别不出来。
tensorboard --logdir "runs"
访问网页 http://localhost:6006/即可看到各种训练结果(注:localhost指的是你所在的计算机本身)
使用刚刚训练好的 best.pt模型来检测:
python detect.py --weights runs/train/exp/weights/best.pt --source ../source/test.png
[说明]:
--weights:表示我们选择的权重模型
--source:表示待检测的图片的路径 (…/表示上级路径)
成功实现了恶劣环境下的DM码的定位
识别成功
来源地址:https://blog.csdn.net/Xcz1220/article/details/129837000