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

 

 

平头哥pentougu 2020-03-19 00:06:52  11280  已收藏 44

分类专栏: 目标检测

版权

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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 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()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

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

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

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

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

在这里插入图片描述
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209

提一下,主要修改的是三个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
  • 1

其中,–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
  • 1

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

4. 结果检测:

在Terminal下输入以下命令:

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

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

5. 模型评估与测试

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值