win10+torch+yolov3训练自己数据集

1. 前情说明:

穷苦学生一枚,恰好最近在学习object detection,用到了yolov3模型,捣鼓了好几天,看了各大论坛、贴吧、CSDN,知乎,博客园等好多大佬前辈们写的文章(吐血.jpg),在这里将自己的过程和结果写出来,希望大家能少走点弯路。

2. 环境:

这个很重要!!!!!

  1. window 10
  2. pytorch 1.4.0
  3. opencv-python
  4. tqdm
  5. matplotlib
  6. pycocotools(这个很难装!!,原作者压根没有考虑window环境下的coco tools,真的吐血,具体安装教程可以参考我的博客:https://blog.csdn.net/weixin_45829462/article/details/104787103

本次使用的是ultralytics-yolov3
为什么使用这个版本,因为这个版本工业应用的比较多,检测速度也比较快,最重要的是,目前这个版本原作者一直在优化之中。
在这里插入图片描述

3. 步骤:

3.1 制作数据集:
在制作数据集需要用到一款标注工具,labellmge,安装地址:github:https://github.com/tzutalin/labelImg,使用方法:
https://www.cnblogs.com/Terrypython/p/9577657.html
3.2 数据集:
博主使用的数据集是Voc行人数据集,是已经标注好的数据集,下载地址:
大家先将数据集下载到桌面,解压,等待使用,数据中有两个文件夹,分别是:
在这里插入图片描述
Annotations文件打开后如下:
在这里插入图片描述
JPEGImages打开后如下:
在这里插入图片描述
3.3 下载模型:
请大家将模型下载下来,地址:https://github.com/ultralytics/yolov3
因为博主准备训练关于检测行人的模型,故命名为yolov3-person,下载下来重要的源文件包都有:

在这里插入图片描述
3.4 装载数据:
将数据集Annotations、JPEGImages复制到yolov3-person工程目录下的data文件下;同时新建两个文件夹,分别命名为ImageSetslabels,最后我们将JPEGImages文件夹复制粘贴一下,并将文件夹重命名为images,具体如下注:(data下加上原先的sample文件夹,一共是6个子文件夹):
在这里插入图片描述
3.5 建立标签文件:

在根目录下新建两个文件夹,makeTxt.pyvoc_label.py,将以下代码拷贝进py文件中,如下:

  • makeTxt.py:
import os
import random

trainval_percent = 0.1
train_percent = 0.9
xmlfilepath = 'data/Annotations'
txtsavepath = 'data/ImageSets'
total_xml = os.listdir(xmlfilepath)

num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)

ftrainval = open('data/ImageSets/trainval.txt', 'w')
ftest = open('data/ImageSets/test.txt', 'w')
ftrain = open('data/ImageSets/train.txt', 'w')
fval = open('data/ImageSets/val.txt', 'w')

for i in list:
    name = total_xml[i][:-4] + '\n'
    if i in trainval:
        ftrainval.write(name)
        if i in train:
            ftest.write(name)
        else:
            fval.write(name)
    else:
        ftrain.write(name)

ftrainval.close()
ftrain.close()
fval.close()
ftest.close()
  • voc_label.py:
import xml.etree.ElementTree as ET
import os
from os import listdir, getcwd

sets = ['train', 'test', 'val']

classes = ["person"]  # 我们只检测person这个类别


def convert(size, box):#对图片进行归一化处理
    dw = 1. / size[0]
    dh = 1. / size[1]
    x = (box[0] + box[1]) / 2.0
    y = (box[2] + box[3]) / 2.0
    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_id):
    in_file = open('data/Annotations/%s.xml' % (image_id))
    out_file = open('data/labels/%s.txt' % (image_id), '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
        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))
        bb = convert((w, h), b)
        out_file.write(str(cls_id) + " " + " ".join([str(a) for a in bb]) + '\n')


wd = getcwd()
print(wd)
for image_set in sets:
    if not os.path.exists('data/labels/'):
        os.makedirs('data/labels/')
    image_ids = open('data/ImageSets/%s.txt' % (image_set)).read().strip().split()
    list_file = open('data/%s.txt' % (image_set), 'w')
    for image_id in image_ids:
        list_file.write('data/images/%s.jpg\n' % (image_id))
        convert_annotation(image_id)
    list_file.close()

注:classes=【‘person’】里面的标签并不是我们定的,请大家打开自己数据集的xml文件,类目头标签是是啥填啥:
在这里插入图片描述
3.6 运行标签文件:

  • 运行makeTxt.py后,在ImagesSets文件夹里面生成4个文件:
    在这里插入图片描述
  • 运行makeTxt.py后,在Iabels文件夹里面生成文件名以及image中目标的位置信息:
    在这里插入图片描述
    3.7 配置文件:
    data文件下新建person.names文件,内容如下:
person

data文件下新建person.data文件,内容如下:

classes=1#只检测一个类,原为80个
train=data/train.txt
valid=data/test.txt
names=data/person.names#读取类目信息
backup=backup/
eval=coco#配置标准与coco数据集一致

在这里插入图片描述
3.8 修改参数文件:
修改原yolov3-spp.cfg文件为(可直接拷贝):

[net]
# Testing
# batch=1
# subdivisions=1
# Training
batch=64
subdivisions=16
width=608
height=608
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1



[convolutional]
size=1
stride=1
pad=1
filters=18
activation=linear


[yolo]
mask = 6,7,8
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=1
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1


[route]
layers = -4

[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky

[upsample]
stride=2

[route]
layers = -1, 61



[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky

[convolutional]
batch_normalize=1
size=3
stride=1
pad=1
filters=512
activation=leaky

[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky

[convolutional]
batch_normalize=1
size=3
stride=1
pad=1
filters=512
activation=leaky

[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky

[convolutional]
batch_normalize=1
size=3
stride=1
pad=1
filters=512
activation=leaky

[convolutional]
size=1
stride=1
pad=1
filters=18
activation=linear


[yolo]
mask = 3,4,5
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=1
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1



[route]
layers = -4

[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky

[upsample]
stride=2

[route]
layers = -1, 36



[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky

[convolutional]
batch_normalize=1
size=3
stride=1
pad=1
filters=256
activation=leaky

[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky

[convolutional]
batch_normalize=1
size=3
stride=1
pad=1
filters=256
activation=leaky

[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky

[convolutional]
batch_normalize=1
size=3
stride=1
pad=1
filters=256
activation=leaky

[convolutional]
size=1
stride=1
pad=1
filters=18
activation=linear


[yolo]
mask = 0,1,2
anchors = 10,13,  16,30,  33,23,  30,61,  62,45,  59,119,  116,90,  156,198,  373,326
classes=1
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1

提一下,主要修改的是三个yolo层附近的参数,一共六处地方:

修改如下:
①filters=255改为18:即3*(classes+5),单类的话classes=1
②classes=80改为1,只检测person一类
其他参数根据自己需要进行修改:
①如果想修改anchor的值,需要根据kmeans聚类跑自己的数据集得出结果,代码地址:https://github.com/lars76/kmeans-anchor-boxes
②如果GPU显存较小,可以设置将random=1设置为0
③当单类是cls为0

3.10 配置预权重:

预权重需要哪个根据自己修改的cfg文件进行选择,以下附一张图。但要提一点,如果不想在作者训练好的权重再加以训练,想要从头开始训练,选择darknet53.conv.74
在这里插入图片描述
3.11 训练模型:

使用pycharm中的Terminal,输入如下命令:

python train.py --data data/person.data --cfg cfg/yolov3-spp.cfg --weights weights/darknet53.conv.74 --epochs 100 --batch-size 32

其中,–epochs 10指迭代了10次,batch-size 32指每次处理32张图片。
①如果GPU显存不够的,会报出错误:
②batch-size 最好在32以上,并且为2的指数倍,不然会不定时出现nan问题:
在这里插入图片描述
③数据集不要包括黑白图片,请保持RBG通道一致,不然会报错:
在这里插入图片描述
④,有条件的,请开启多尺度训练,提高模型精度,具体命令如下:

python train.py --data data/person.data --cfg cfg/yolov3-spp.cfg --weights weights/darknet53.conv.74 --epochs 100 --batch-size 32 --multi-scale

正常运行如下:
在这里插入图片描述
在这里插入图片描述(自己笔记本显存不够,通过Google Colab训练)
训练结束后得到模型best.ptlast.pt
在这里插入图片描述

4. 结果检测:

在Terminal下输入以下命令:

python detect.py --names data/person.names --cfg cfg/yolov3-spp.cfg --weights weights/best.pt

结果如下:
在这里插入图片描述
在这里插入图片描述
结果倒是出乎自己的预期

5. 模型评估与测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
模型仍有待优化,近期不定时更新该博文!

原创文章 42 获赞 62 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_45829462/article/details/104810031
今日推荐