上期我们已经完成了环境的搭建,以及环境的检测。我们接着在上期的基础上进行训练模型。
点击这个链接,先下载数据集(提取码: 485q)。
这里取的是猫猫图片前121张,名字是cat.0.jpg到cat.120.jpg。
复制到项目文件夹yolov5-master\own_datas\images\train文件夹下作为训练集。
另外再新建出来yolov5-master\own_datas\labels这些文件夹。(有用)
我们在终端下面先输入以下代码。
pip install pyqt5 labelme
pip install pyqt5 labelme
很遗憾,我这里报错了。如果你的报错跟我一样可以在下面接着输入。
pip install --upgrade setuptools
pip3 install wheel
pip3 install pyinstaller
pip install --upgrade setuptools
pip3 install wheel
pip3 install pyinstaller
运行完是这些效果。
接着再运行一遍下面这个代码。
pip install pyqt5 labelme
pip install pyqt5 labelme
神奇的没有报错。
接着输入。
labelme
labelme
接着在屏幕上弹出来了这个。
准备工作结束!
点击左上角的Open Dir,选择yolov5-master\own_datas\images\train文件夹,就会出现训练集里的图片。右键选择Create Rectangle,框出图片里的猫猫。
框选结束后,输入标签名cat,点击ok,这个标签就保存下来了。如果有多只猫猫,就继续框选。整张图片框选完毕后,点击左侧的Next Image,根据提示把标注文件保存到路径yolov5-master\own_datas\labels\json中,文件的格式是.json。大概40分钟左右就能标注完成。
接着我们需要把json文件转换成txt文件,在此之前先在labels文件夹下面新建txt的文件夹,方便将数据保存。
接着我们在项目文件夹里面新建一个py文件。
在下面写入以下代码
import json
import os
name2id = {'cat': 0} # 标签名称
def convert(img_size, box):
dw = 1. / (img_size[0])
dh = 1. / (img_size[1])
x = (box[0] + box[2]) / 2.0 - 1
y = (box[1] + box[3]) / 2.0 - 1
w = box[2] - box[0]
h = box[3] - box[1]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
def decode_json(json_floder_path, json_name):
txt_name = 'C:/Users/华硕/Desktop/yolov5-master/own_datas/labels/txt/' + json_name[0:-5] + '.txt'
# txt文件夹的绝对路径
txt_file = open(txt_name, 'w')
json_path = os.path.join(json_floder_path, json_name)
data = json.load(open(json_path, 'r', encoding='gb2312', errors='ignore'))
img_w = data['imageWidth']
img_h = data['imageHeight']
for i in data['shapes']:
label_name = i['label']
if (i['shape_type'] == 'rectangle'):
x1 = int(i['points'][0][0])
y1 = int(i['points'][0][1])
x2 = int(i['points'][1][0])
y2 = int(i['points'][1][1])
bb = (x1, y1, x2, y2)
bbox = convert((img_w, img_h), bb)
txt_file.write(str(name2id[label_name]) + " " + " ".join([str(a) for a in bbox]) + '\n')
if __name__ == "__main__":
json_floder_path = 'C:/Users/华硕/Desktop/yolov5-master/own_datas/labels/json/'
# json文件夹的绝对路径
json_names = os.listdir(json_floder_path)
for json_name in json_names:
decode_json(json_floder_path, json_name)
import json
import os
name2id = {'cat': 0} # 标签名称
def convert(img_size, box):
dw = 1. / (img_size[0])
dh = 1. / (img_size[1])
x = (box[0] + box[2]) / 2.0 - 1
y = (box[1] + box[3]) / 2.0 - 1
w = box[2] - box[0]
h = box[3] - box[1]
x = x * dw
w = w * dw
y = y * dh
h = h * dh
return (x, y, w, h)
def decode_json(json_floder_path, json_name):
txt_name = 'C:/Users/华硕/Desktop/yolov5-master/own_datas/labels/txt/' + json_name[0:-5] + '.txt'
# txt文件夹的绝对路径
txt_file = open(txt_name, 'w')
json_path = os.path.join(json_floder_path, json_name)
data = json.load(open(json_path, 'r', encoding='gb2312', errors='ignore'))
img_w = data['imageWidth']
img_h = data['imageHeight']
for i in data['shapes']:
label_name = i['label']
if (i['shape_type'] == 'rectangle'):
x1 = int(i['points'][0][0])
y1 = int(i['points'][0][1])
x2 = int(i['points'][1][0])
y2 = int(i['points'][1][1])
bb = (x1, y1, x2, y2)
bbox = convert((img_w, img_h), bb)
txt_file.write(str(name2id[label_name]) + " " + " ".join([str(a) for a in bbox]) + '\n')
if __name__ == "__main__":
json_floder_path = 'C:/Users/华硕/Desktop/yolov5-master/own_datas/labels/json/'
# json文件夹的绝对路径
json_names = os.listdir(json_floder_path)
for json_name in json_names:
decode_json(json_floder_path, json_name)
大家别忘记把文件地址改一下。这是我的电脑文件夹地址。
运行一下py文件,你会得到转换后的数据。
最后一步,把txt文件夹中的文件全部复制到yolov5-master\own_datas\labels\train文件夹中。
首先先复制两个文件
在yolov5-master\data路径下找到coco128.yaml文件,复制到yolov5-master\own_datas路径下,改名为cat.yaml
在yolov5-master\models路径下找到yolov5s.yaml文件,同样复制到yolov5-master\own_datas路径下。选择yolov5s是因为,虽然它效果不太好,但是速度比较快。
打开cat.yaml文件,首先需要修改的是这三行:
# path: ../datasets/coco128 # dataset root dir
train: own_datas/images/train # train images (relative to 'path') 128 images
val: own_datas/images/train # val images (relative to 'path') 128 images
# path: ../datasets/coco128 # dataset root dir
train: own_datas/images/train # train images (relative to 'path') 128 images
val: own_datas/images/train # val images (relative to 'path') 128 images
第一行注释掉,第二行和第三行的相对路径,如果是一模一样跟着我做下来的,按我这个来就可以了
然后修改这两行:
nc: 1 # number of classes
names: ['cat'] # class names
nc: 1 # number of classes
names: ['cat'] # class names
最后把这一行给注释掉
打开yolov5s.yaml文件,需要修改的是这一行:
nc: 1 # number of classes
nc: 1 # number of classes
打开train.py文件找到这几行。
parser.add_argument('--weights', type=str, default='yolov5s.pt', help='initial weights path')
parser.add_argument('--cfg', type=str, default='own_datas/yolov5s.yaml', help='model.yaml path')
parser.add_argument('--data', type=str, default='own_datas/cat.yaml', help='dataset.yaml path')
parser.add_argument('--epochs', type=int, default=150)
parser.add_argument('--workers', type=int, default=0, help='maximum number of dataloader workers')
parser.add_argument('--weights', type=str, default='yolov5s.pt', help='initial weights path')
parser.add_argument('--cfg', type=str, default='own_datas/yolov5s.yaml', help='model.yaml path')
parser.add_argument('--data', type=str, default='own_datas/cat.yaml', help='dataset.yaml path')
parser.add_argument('--epochs', type=int, default=150)
parser.add_argument('--workers', type=int, default=0, help='maximum number of dataloader workers')
修改成这个样子。
运行train.py,然后静静等待
报错了!!!!!
解决方法:找到5.0版报错的loss.py中最后那段for函数,将其整体替换为yolov5-master版中loss.py最后一段for函数即可正常运行。
for i in range(self.nl):
anchors, shape = self.anchors[i], p[i].shape
gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain
# Match targets to anchors
t = targets * gain # shape(3,n,7)
if nt:
# Matches
r = t[..., 4:6] / anchors[:, None] # wh ratio
j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare
# j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2))
t = t[j] # filter
# Offsets
gxy = t[:, 2:4] # grid xy
gxi = gain[[2, 3]] - gxy # inverse
j, k = ((gxy % 1 < g) & (gxy > 1)).T
l, m = ((gxi % 1 < g) & (gxi > 1)).T
j = torch.stack((torch.ones_like(j), j, k, l, m))
t = t.repeat((5, 1, 1))[j]
offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j]
else:
t = targets[0]
offsets = 0
# Define
bc, gxy, gwh, a = t.chunk(4, 1) # (image, class), grid xy, grid wh, anchors
a, (b, c) = a.long().view(-1), bc.long().T # anchors, image, class
gij = (gxy - offsets).long()
gi, gj = gij.T # grid indices
# Append
indices.append((b, a, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, anchor, grid
tbox.append(torch.cat((gxy - gij, gwh), 1)) # box
anch.append(anchors[a]) # anchors
tcls.append(c) # class
for i in range(self.nl):
anchors, shape = self.anchors[i], p[i].shape
gain[2:6] = torch.tensor(shape)[[3, 2, 3, 2]] # xyxy gain
# Match targets to anchors
t = targets * gain # shape(3,n,7)
if nt:
# Matches
r = t[..., 4:6] / anchors[:, None] # wh ratio
j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare
# j = wh_iou(anchors, t[:, 4:6]) > model.hyp['iou_t'] # iou(3,n)=wh_iou(anchors(3,2), gwh(n,2))
t = t[j] # filter
# Offsets
gxy = t[:, 2:4] # grid xy
gxi = gain[[2, 3]] - gxy # inverse
j, k = ((gxy % 1 < g) & (gxy > 1)).T
l, m = ((gxi % 1 < g) & (gxi > 1)).T
j = torch.stack((torch.ones_like(j), j, k, l, m))
t = t.repeat((5, 1, 1))[j]
offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j]
else:
t = targets[0]
offsets = 0
# Define
bc, gxy, gwh, a = t.chunk(4, 1) # (image, class), grid xy, grid wh, anchors
a, (b, c) = a.long().view(-1), bc.long().T # anchors, image, class
gij = (gxy - offsets).long()
gi, gj = gij.T # grid indices
# Append
indices.append((b, a, gj.clamp_(0, shape[2] - 1), gi.clamp_(0, shape[3] - 1))) # image, anchor, grid
tbox.append(torch.cat((gxy - gij, gwh), 1)) # box
anch.append(anchors[a]) # anchors
tcls.append(c) # class
点运行train.py
大概跑了2个多小时,跑完是这个样子
打开训练好的结果查看一下,没毛病
我的输出是exp3文件夹的原因是我前两次因为bug,失败了两次。如果你是一次就成功的那么输出文件会直接是exp。
weights文件夹里面的best.pt文件是训练好的模型,测试的时候用
我在训练集中随便选了一张,以为当时训练的时候用了前100多张,后面的图片我就可以随便抽一张,进行测试。
打开detect.py文件
改两行代码(第一行代码要看一下模型的具体位置,我这里因为前面失败了两次,第三次才炼制成功了)
parser.add_argument('--weights', nargs='+', type=str, default='runs/train/exp3/weights/best.pt', help='model path(s)')
parser.add_argument('--source', type=str, default='own_datas/images/test', help='file/dir/URL/glob, 0 for webcam')
parser.add_argument('--weights', nargs='+', type=str, default='runs/train/exp3/weights/best.pt', help='model path(s)')
parser.add_argument('--source', type=str, default='own_datas/images/test', help='file/dir/URL/glob, 0 for webcam')
第一个default就是之前说过的训练出来的模型文件的相对路径
第二个default就是存放测试文件的文件夹的相对路径
运行一下detect.py
看一下效果
这里我又选取了一段有猫猫的视频(我是随便下载了一段,不建议下载太长,因为测试起来会消耗很长的时间),我又进行了测试。
这是一段47秒的视频,大概跑了3分钟左右。
这里我截图一张,看看效果。
效果差强人意,毕竟只训练了121张图片,还用了比较差的yolov5s网络,下次再增加一下训练集的数量。要是用GPU跑应该会好一点吧。