目录
一、简介
最近为了应付毕业论文,学习了目标检测,目的是检测车辆和行人,使用了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官网
官网链接: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-8
import os
import random
import argparse
parser = argparse.ArgumentParser()
#xml文件的地址,根据自己的数据进行修改 xml一般存放在Annotations下
parser.add_argument('--xml_path', default='Annotations', type=str, help='input xml label path')
#数据集的划分,地址选择自己数据下的ImageSets/Main
parser.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_path
txtsavepath = opt.txt_path
total_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 ET
import os
from os import getcwd
sets = ['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, h
def 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
# Parameters
nc: 1 # 只改这里 改成自己的类的数量
depth_multiple: 0.33 # model depth multiple
width_multiple: 0.50 # layer channel multiple
anchors:
- [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 backbone
backbone:
# [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 head
head:
[[-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码的定位
识别成功
文章出处登录后可见!