RCNN系列我是大概看过的,还写过:RCNN系列,但是这种location和classification分开的思路,要达到实时的话我的硬件条件肯定是不可能的。YOLOV3我是在TX2上跑过的:YOLOV3-TX2跑起来,而且YOLO是有简化版本的模型的,对于简单应用应该是够了。
因为以前跑过,整体的流程走下来还算比较顺利,比起SSD来说,训练时要修改的代码也比较少,可能留给犯错的概率就少一些。
我分以下几个部分:
- 1. YOLO系列简介。
- 2. 编译环境准备。
- 3. 训练配置。
1. YOLOV3系列简介。
1.1:简介。
- 作者:Joseph Redmon
- YOLO主页:YOLO
- 作者github: https://github.com/pjreddie
- 模型简介:You only look once (YOLO) is a state-of-the-art, real-time object detection system. On a Pascal Titan X it processes images at 30 FPS and has a mAP of 57.9% on COCO test-dev.
和其他模型的对比:(总结起来一句话:比它快的准确率没有它高,准确率比它高的没有他快)
Model | Train | Test | mAP | FLOPS | FPS | Cfg | Weights |
---|---|---|---|---|---|---|---|
SSD300 | COCO trainval | test-dev | 41.2 | - | 46 | link | |
SSD500 | COCO trainval | test-dev | 46.5 | - | 19 | link | |
YOLOv2 608x608 | COCO trainval | test-dev | 48.1 | 62.94 Bn | 40 | cfg | weights |
Tiny YOLO | COCO trainval | test-dev | 23.7 | 5.41 Bn | 244 | cfg | weights |
SSD321 | COCO trainval | test-dev | 45.4 | - | 16 | link | |
DSSD321 | COCO trainval | test-dev | 46.1 | - | 12 | link | |
R-FCN | COCO trainval | test-dev | 51.9 | - | 12 | link | |
SSD513 | COCO trainval | test-dev | 50.4 | - | 8 | link | |
DSSD513 | COCO trainval | test-dev | 53.3 | - | 6 | link | |
FPN FRCN | COCO trainval | test-dev | 59.1 | - | 6 | link | |
Retinanet-50-500 | COCO trainval | test-dev | 50.9 | - | 14 | link | |
Retinanet-101-500 | COCO trainval | test-dev | 53.1 | - | 11 | link | |
Retinanet-101-800 | COCO trainval | test-dev | 57.5 | - | 5 | link | |
YOLOv3-320 | COCO trainval | test-dev | 51.5 | 38.97 Bn | 45 | cfg | weights |
YOLOv3-416 | COCO trainval | test-dev | 55.3 | 65.86 Bn | 35 | cfg | weights |
YOLOv3-608 | COCO trainval | test-dev | 57.9 | 140.69 Bn | 20 | cfg | weights |
YOLOv3-tiny | COCO trainval | test-dev | 33.1 | 5.56 Bn | 220 | cfg | weights |
YOLOv3-spp | COCO trainval | test-dev | 60.6 | 141.45 Bn | 20 | cfg | weights |
1.2.YOLO原理。
论文我正在看,等我看完了再写这一部分,但是因为这个模型的训练和检测框架都是端到端的,所以即使 不了解中间的细节也是可以训练和检测的。
2. 编译环境准备。
相较于其他模型来说,darknet的编译环境是最简单的。因为他并没有用时下比较流行的深度学习框架来写,而是作者自己用C撸了一个框架:darknet。这个框架是用C和CUDA-C来写的(这代码能力就只有仰望的份了),所以装了ubuntu系统装好以后就可以用了,非常简单。
如果需要(一般肯定是需要的)GPU加速的话,那么需要安装NVIIDA的那一套东西(驱动,CUDA,CUDNN),如果需要测试视频和显示视频或者照片的话,那么需要安装opencv。
所以是不是很简单?
我自己的电脑是win10+ubuntu的双系统。win10下darknet也是可以配置的,但是为了简单和适应linux系统我这次还是选择了ubuntu系统,中间安装opencv的时候空间不够了,我手贱想从win10下面分出来一点空间来给ubuntu的时候,出了岔子,ubunut系统崩掉了,一气之下我把C盘清空了,两个系统都重装了。
装系统的话就不多说了,win10下装ubuntu的话大概以下几个步骤:
- ①从win的系统盘右键压缩出来50G(有的话可以再多点)的未分配的空间。(可能是绿色或者黑色的,不是很影响)
- ②制作ubuntu的u盘启动盘,用软碟通就可以,这个很简单。
- ③重启,进bios,从u盘启动,顺便把电脑的网断了(拔掉网线或者关闭wifi),然后安装,不要选择安装更新,并且自己分配空间,就从刚才从win10上压缩的未分配空间来分配。
然后基本就可以了,如果遇到什么问题,勤百度,这写坑基本上都有。
至于安装NVIDIA的那一套,网上也是有很多教程,我也是踩了很多坑,现在也无法截图写教程了,就不说了,这一套更新挺快的,并不是越新越好(越适合自己的项目),注意各个版本需要匹配。
opencv的编译写一下,因为我正在弄。
- ①安装一些依赖环境:
sudo apt-get install build-essential
sudo apt-get install cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev
sudo apt-get install python-dev python-numpy libtbb2 libtbb-dev libjpeg-dev libpng-dev libtiff-dev libjasper-dev libdc1394-22-dev
sudo apt-get install –assume-yes libopencv-dev libdc1394-22 libdc1394-22-dev libjpeg-dev libpng12-dev libtiff5-dev libjasper-dev libavcodec-dev libavformat-dev libswscale-dev libxine2-dev libgstreamer0.10-dev libgstreamer-plugins-base0.10-dev libv4l-dev libtbb-dev libqt4-dev libfaac-dev libmp3lame-dev libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev libxvidcore-dev x264 v4l-utils unzip
sudo apt-get install ffmpeg libopencv-dev libgtk-3-dev python-numpy python3-numpy libdc1394-22 libdc1394-22-dev libjpeg-dev libpng12-dev libtiff5-dev libjasper-dev libavcodec-dev libavformat-dev libswscale-dev libxine2-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev libv4l-dev libtbb-dev qtbase5-dev libfaac-dev libmp3lame-dev libopencore-amrnb-dev
选择的地方全部选择yes,然后等待安装完成就可以了。
- ② 下载opencv源码,这个自己想办法吧,网络好的话还是比较快的。然后解压。
- ③ 配置cmake编译。
cd opencv-3.4.1 #解压的文件
mkdir build #创建build文件夹
cd build #进入build文件夹
cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_TBB=ON -D WITH_V4L=ON -D WITH_QT=ON -D WITH_OPENGL=ON -D WITH_GTK=ON -D WITH_GTK_2_X=ON -D CUDA_NVCC_FLAGS="-D_FORCE_INLINES" ..
#配置cmake
sudo make #编译
编译还是挺慢的,我跑了步回来还没好,耐心等着就可以了。
然后
sudo make install #这个sudo是必须的,要不会因为权限问题产生错误
这样就可以了,有的教程写这里需要添加动态连接什么的,我倒没有这么做,就直接可以用了。
- ④测试。
mkdir opencv_cpp #建立一个文件夹:
gedit lena.cpp #建立测试文件
gedit CMakelist.txt #建立CMakeLists文件
cmake . #编译头文件和源文件
make #生成可执行文件
CMakelist.txt 里面写的是:
cmake_minimum_required(VERSION 2.8)
project( DisplayImage )
find_package( OpenCV REQUIRED )
add_executable( LENA lena.cpp )
target_link_libraries( LENA ${OpenCV_LIBS} )
cpp文件里写的是:
#include <stdio.h>
#include <opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char** argv )
{ if ( argc != 2 )
{ printf("usage: DisplayImage.out <Image_Path>\n");
return -1; }
Mat image;
image = imread( argv[1], 1 );
if ( !image.data )
{ printf("No image data \n"); return -1; }
namedWindow("Display Image", WINDOW_AUTOSIZE );
imshow("Display Image", image);
waitKey(0);
return 0;
}
然后找一张照片命名lena.jpg
,放到lena.cpp
的同级目录下。
最后执行:
./LENA lena.jpg
看到显示照片的话就说明没有问题了。
c++版本的opencv这里就可以用了,但是没有好用的编辑器,还是不如win下面VS写起来好用。
3.训练配置。
这里训练使用VOC2007的数据格式,这个数据格式在前面的文章中已经做了介绍:VOC制作数据集
其中
Annotations
中存的是打好的标签,xml格式。一个典型的标签长这样:
里面包含了文件名,路径,尺寸,通道以及标注的目标以及目标的位置和尺寸。
在JPEGImages文件夹里面是所有的原始照片。
imageSets文件夹里面是我们分配的训练集和验证集的个数:这个我们可以用代码来生成,代码给在下面,改的别人的。这个代码的主要作用就是生成main文件夹下的TXT文件。
import os
import random
trainval_percent = 1 # trainval数据集占所有数据的比例
train_percent = 0.9 # train数据集占trainval数据的比例
xmlfilepath = 'Annotations'
txtsavepath = 'ImageSets\Main'
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('ImageSets/Main/trainval.txt', 'w')
ftest = open('ImageSets/Main/test.txt', 'w')
ftrain = open('ImageSets/Main/train.txt', 'w')
fval = open('ImageSets/Main/val.txt', 'w')
for i in list:
name=total_xml[i][:-4]+'\n'
if i in trainval:
ftrainval.write(name)
if i in train:
ftrain.write(name)
else:
fval.write(name)
else:
ftest.write(name)
ftrainval.close()
ftrain.close()
fval.close()
ftest .close()
好了,下面有几个步骤:
3.1. 生成labels标签和train文件地址索引。
VOC的格式就差不多是上面那些了,但是YOLO要求的标签需要是归一化以后的坐标以及尺寸,所以需要生成这样的训练标签,以及,用哪些照片来训练是需要把它们的目录索引写在文本文件中的。
参考代码如下:
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join
#sets=[('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test')]
sets=[('2007','train')]
#修改成自己的训练文件,我们只用了2007的train,所以这里这么改
#classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]
classes = ["DJI"]
#修改成自己的类别,我这里只有一类,所以这样写。
#classes=[str(i) for i in range(1)]
#这个函数就是为了获得归一化坐标的。
def convert(size, box):
#print(size[0])
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(year, image_id):
in_file = open('VOCdevkit/VOC%s/Annotations/%s.xml'%(year, image_id))
out_file = open('VOCdevkit/VOC%s/labels/%s.txt'%(year, 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()
for year, image_set in sets:
print(year)
print(image_set)
if not os.path.exists('VOCdevkit/VOC%s/labels/'%(year)):
os.makedirs('VOCdevkit/VOC%s/labels/'%(year))
image_ids = open('VOCdevkit/VOC%s/ImageSets/Main/%s.txt'%(year, image_set)).read().strip().split()
list_file = open('%s_%s.txt'%(year, image_set), 'w')
for image_id in image_ids:
list_file.write('%s/VOCdevkit/VOC%s/JPEGImages/%s.jpg\n'%(wd, year, image_id))
convert_annotation(year, image_id)
list_file.close()
这样会在labels文件夹下面生成每个图像的标注信息,我随表找了一个,如下:
darknet根文件夹下面会生成2007_train.txt
文件,这个文件里面写的就是所有待训练图片的目录信息,如图:
3.2. 下载预训练权重。
这个主要是卷积部分的预训练权重,使用这个权重可以节省训练时间,直接输入这个命令下载,或者去darknet官网上下载都是可以的。
wget https://pjreddie.com/media/files/darknet53.conv.74
3.3. 修改cfg/voc.data
这个主要是使用VOC格式的数据进行训练的时候的一些路径设置:
classes= 1 #类别
train =/home/zhxing/darknet/2007_train.txt #训练图片路径存储的txt
valid = /home/zhxing/darknet/2007_test.txt #测试图片路径存储的txt
names = data/voc.names #voc.names,这个里面存的是名称,下面修改
backup = backup #存放训练好的模型的位置,这个文件夹在darknet下自己新建一个就可以了
3.4. 新建backup文件夹。
3.5. 修改data/voc.names
就是把对应的名称来修改,我是只有用一类,所以就这样了,这里写的其实和标注的时候那个data文件夹下的txt里面写的是一样的内容。
3.6. 修改cfg/yolov3-voc.cfg
最后是来修改这个文件,这个文件存的就是yolov3的网络结构,darknet这个框架中cfg里面不同的配置文件对应着不同的网络结构,用来训练和检测都是在cfg文件里进行定义的,所以这里我们是要做一些修改的。主要修改的部分是与类别相关的,还挺长的,我把需要修改的用中文注释一下。
[net]
# Testing
#batch=1
#subdivisions=1
# 改成训练模式,batch和subdivisions修改一下,这个关系到GPU内存是否够用。
Training #训练模式打开
batch=32
subdivisions=16
# 每次前向的图片数目=batch/subdivisons
width=416
height=416
channels=3
momentum=0.9
decay=0.0005
angle=0
saturation = 1.5
exposure = 1.5
hue=.1
learning_rate=0.001
burn_in=1000
max_batches = 50200
policy=steps
steps=40000,45000
scales=.1,.1
[convolutional]
batch_normalize=1
filters=32
size=3
stride=1
pad=1
activation=leaky
# Downsample
[convolutional]
batch_normalize=1
filters=64
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=32
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=64
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
# Downsample
[convolutional]
batch_normalize=1
filters=128
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=64
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=64
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
# Downsample
[convolutional]
batch_normalize=1
filters=256
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=128
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
# Downsample
[convolutional]
batch_normalize=1
filters=512
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=256
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
# Downsample
[convolutional]
batch_normalize=1
filters=1024
size=3
stride=2
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
filters=1024
size=3
stride=1
pad=1
activation=leaky
[shortcut]
from=-3
activation=linear
######################
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
size=3
stride=1
pad=1
filters=1024
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
size=3
stride=1
pad=1
filters=1024
activation=leaky
[convolutional]
batch_normalize=1
filters=512
size=1
stride=1
pad=1
activation=leaky
[convolutional]
batch_normalize=1
size=3
stride=1
pad=1
filters=1024
activation=leaky
[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 = .5
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 # 这里改成3×(类别+4+1),这个看文章就是到是怎么回事了,是每个grid生成的向量的维数
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 = .5
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 #修改,3×(类别+4+1)
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 = .5 #阈值
truth_thresh = 1
random=1 #是否进行多尺度训练
需要注意,修改cfg文件是不需要重新编译源码的,所以非常方便,可以根据自己的需求进行修改,需要修改的地方基本都在命名未[yolo]的结构下面,对照着改一下就可以了,下面就可以开始训练了。
3.7. 开始训练。
输入以下命令,开始训练。
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74
会进行权重加载然后训练:
参数意义:
Region xx: cfg文件中yolo-layer的索引.
AVE IOU: 当前迭代中,预测的box和标注的box的平均交并比,越大越好,最大是1.
class: 标注物体的分类准确率,越大越好,期望值是1.
obj: 越大越好,期望值为1.
no obj:越小越好,期望值为0.
.5R: IOU=0.5时的召回率,召回率=检测出的正样本/实际的正样本
0.75R: 和上面的一样,阈值为0.75
count: 正样本数目.
每一个batch结束之后,会显示当前batch的损失和平均损失:
开头为数字的那一行,意义分别是:
batch 总损失 平均损失 学习率 rate 消耗时间 使用图片
默认的是每小于1000的时候每100个batch保存一次模型,大于1000的时候每10000个batch保存一次模型,这个可以根据自己的需求修改,代码在examples/detector.c line 138
:
save_weights(net, buff);
}
if(i%1000==0 || (i < 1000 && i%100 == 0)){
//需要修改保存模型的batch的话修改这里,我已经改过了,大于1000的话每1000个batch存一次模型.
#ifdef GPU
if(ngpus != 1) sync_nets(nets, ngpus, 0);
#endif
char buff[256];
sprintf(buff, "%s/%s_%d.weights", backup_directory, base, i);
save_weights(net, buff);
}
free_data(train);
}
#ifdef GPU
基本上就是这些了,训练需要结束的话关掉终端就可以了(一般看损失降到差不多或者召回率比较高的时候),然后可以加载训练好的模型来检测。
3.8. 检测.
./darknet detector test cfg/voc.data cfg/yolov3-voc.cfg backup/yolov3-voc_final.weights 01.jpg
把weights文件和jpg文件换成自己的就可以了。
4. 其他。
基本的训练流程就是这样了,还有些其他的:比如如何批量测试保存图片,测试保存视频,保存loss信息等一些列问题,有的我已经解决了,有的还没有,这一篇太庞杂了,打算新开一篇了。
我自己做的无人机检测,第一次搞的数据量感觉有点少,最后的结果也非常一般,这一次数据量扩充了5倍,刚刚标注完,所以重新走了一遍训练的流程,顺便记录下来,希望一切顺利!这一篇就到此结束了。