10.YOLO系列及如何训练自己的数据。

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制作数据集

VOC数据文件夹

其中Annotations中存的是打好的标签,xml格式。一个典型的标签长这样:

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倍,刚刚标注完,所以重新走了一遍训练的流程,顺便记录下来,希望一切顺利!这一篇就到此结束了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,658评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,482评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,213评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,395评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,487评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,523评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,525评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,300评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,753评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,048评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,223评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,905评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,541评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,168评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,417评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,094评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,088评论 2 352

推荐阅读更多精彩内容