引用地址:
https://pjreddie.com/darknet/yolo/
https://blog.csdn.net/ch_liu23/article/details/53558549
https://blog.csdn.net/lengconglin/article/details/77367246
由于上一章修改Makefile中的OPENCV=1重新make却一直报错,因此一直在网上查找解决方案。最后重装了opencv,并且尝试了这个网站给出的解决方案,依然不能重新得到darknet的文件(因为只有得到了这个文件才算是make成功)。其中还把电脑搞崩了一次。。。然后只能放弃!O…O
我们可以直接在这里下载数据集,也可以使用如下命令行下载和解压。
(在Yolo官网上,是在darknet文件夹下新建一个名为VOCdevkit的文件夹,然后在这个文件夹下下载和解压的,我们暂时也这样操作。解压后又会在VOCdevkit生成一个名为VOCdevkit的文件夹,其中包含解压后的VOC2007和VOC2012,这两个文件夹中包含了Annotations/ImageSets/JPEGImages/SegmentationClass/SegmentationObject五个文件夹。具体里面都代表什么,等用到再讲吧)
wget https://pjreddie.com/media/files/VOCtrainval_11-May-2012.tar
wget https://pjreddie.com/media/files/VOCtrainval_06-Nov-2007.tar
wget https://pjreddie.com/media/files/VOCtest_06-Nov-2007.tar
tar xf VOCtrainval_11-May-2012.tar
tar xf VOCtrainval_06-Nov-2007.tar
tar xf VOCtest_06-Nov-2007.tar
Darknet需要读取.txt文件,每一张图片就要一个.txt文件来表示真实目标的位置。当然,一张图中可能存在多个目标,一个目标的位置写一行。如下格式:
其中x,y,width,height分别代表真实目标在原图中的左上角的横坐标、纵坐标、以及目标的宽和高。
为了生成这些文件,我们需要在Darknet文件夹下的scripts目录下运行voc_label.py。下载voc_label.py可用如下命令:(Darknet官网也是很调皮–>原话说:Let’s just download it again because we are lazy. 相信大家都看得懂,我就不解释了哈!)
wget https://pjreddie.com/media/files/voc_label.py
然后只需运行voc_label.py即可生成.txt文件。
python voc_label.py
打开生成的labels文件夹,可以看到很多.txt文件。如下图所示:
打开000001.txt,可以看到如下图所示结果。其中一共包含两行数据,这表明这个图中包含两个目标。
**需要注意的一点:**Darknet官网给出的voc_label.py已经写好了读取文件路径,但是这个路径又跟原来我们一步步按照它的步骤来做的不一样,从而我运行的时候会报错。说找不到VOCdevkit/VOC2007/ImageSets/Main/train.txt这个文件。后来在这里找到了解决方法。也就是说,我们还要将解压后的VOCdevkit文件夹拷贝到scripts中。当然你也可以去修改voc_label.py中的路径,但是我修改了一下,感觉有点乱(因为路径中加了%s字符串怕搞混了),就还是拷贝了。最后我们就可以生成好几个.txt文件啦!(笔者只拷贝了VOC2007,所以只生成了3个)
**还有一点:**voc_label.py其中不但需要真实标签的路径,还可以设置想要生成.txt的集合和要检测哪些类别。这些都可以在第七行和第八、九行进行修改。
如:我只想训练和测试VOC2007,那么我就可以只拷贝解压后的VOC2007的数据到scripts文件夹。然后修改
sets=[('2012', 'train'), ('2012', 'val'), ('2007', 'train'), ('2007', 'val'), ('2007', 'test')]
为
sets=[('2007', 'train'), ('2007', 'val'), ('2007', 'test')]
(笔者这里就只拷了VOC2007到这个文件夹,所以修改了这个地方,其余没动)
如果你只想检测鸟这一类,则可以将
classes = ["aeroplane", "bicycle", "bird", "boat", "bottle", "bus", "car", "cat", "chair", "cow", "diningtable", "dog", "horse", "motorbike", "person", "pottedplant", "sheep", "sofa", "train", "tvmonitor"]
修改为
class = ["bird"]
**PS:**如果你修改了这里,那还有一个地方需要修改——voc.data(后面会讲到)
由于用于训练的样本包含train和val(其中train是指训练集,是用于真正训练的;val是指验证集,是作为验证训练的样本是否已经训练的足够好。)test则只用于测试阶段。因此需要将2007_train.txt和2007_val.txt进行合并。我们可以用下列指令合并之:
cat 2007_train.txt 2007_val.txt 2012_*.txt > train.txt
当然,笔者没有用到VOC2012,就不用写后面那个啦~
进入Darknet文件夹,更改cfg/voc.data配置文件:
classes= 20
train = /train.txt
valid = 2007_test.txt
names = data/voc.names
backup = backup
我们要用自己生成的train.txt和2007_test.txt的路径替换。如果你修改了voc_label.py中的class信息,那么这里的classes=20也要改变为相应的类别数量;voc.names也是一样,如果增加或减少了类别名称,也要在这里修改。backup是用来存放训练后的权重的,一开始backup是空的,训练过程中,会不断出现新的后缀为.weights的权重文件。每循环100,保存一次权重文件。但只会保存前10个权重,最后保存最后一个权重文件。
为了获的更好的训练效果,我们可以在这里下载预训练权重,也可以使用下列指令获得:(可直接在darknet文件夹下运行)
wget https://pjreddie.com/media/files/darknet53.conv.74
执行代码:
./darknet detector train cfg/voc.data cfg/yolov3-voc.cfg darknet53.conv.74
当然,我们总是不可能一帆风顺,作为程序员,总是要和bug作斗争!
虽然有时候没有报错,但是看到运行后,全是nan,就猜到错了。。。然后查看了yolov3-voc.cfg,训练时应当将前几行改为如下:
# Testing
# batch=1
# subdivisions=1
# Training
batch=64
subdivisions=16
然后运行了好久,也没有一直出现nan了。结果最后报错说out of memory,然后我又修改了yolov3-voc.cfg中的max_batches和steps。
max_batches = 5000 #50200
steps=1000,3000 #40000,45000
还不知道会不会报错,但是可以看到还是有一些地方总是nan =_=。又运行了几个小时还没跑完。。。跑完后下次继续写!
---------------------- 这是一天后的分割线 ---------------------
今天打开电脑后发现程序竟然还在运行!如下图,已经运行了1w多个epoch了。可我明明改了max_batches啊!
实在等不了了,就停下来看看哪里出了问题。结果看了一下自己运行的命令,竟然是
./darknet detector train cfg/voc.data cfg/yolov3.cfg darknet53.conv.74
而我修改的网络配置文件确实yolov3-voc.cfg,分分钟奔溃!然后修改后重新运行,结果报错
yolov3-voc
Segmentation fault (core dumped)
可是我只修改了几个地方,怎么会报错呢?尝试了好几个yolov2.cfg和yolov2-voc.cfg等,在我修改过后都会报同样的错误!然后我把我下面修改的两处:max_batches和steps后注释的地方都删掉了(因为我担心破坏原来的数据,就每次都加了注释。)结果就能跑通了!现在我正在跑的是yolov2-voc.cfg,这些网络配置文件其实都是可以用的,只是yolov2的网络层没有yolov3的复杂。现在我的yolov2-voc.cfg中的数据是这样的:
[net]
# Testing
# batch=1
# subdivisions=1
# Training
batch=64
subdivisions=8
height=416
width=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 = 4000
policy=steps
steps=1000,3000
scales=.1,.1
其他的都没变。我也很好奇,为什么上面有注释的,下面我在max_batches和steps后注释就会报错。希望有明白的童鞋看到能解释一番~
----------------------- 又过了一天 ----------------------
训练完成后,进行测试,使用命令:
./darknet detector test cfg/voc.data cfg/yolov2-voc.cfg backup/yolov2-voc_final.weights data/eagle.jog
没有报错,但是检测没有出框。感觉原因可能是因为训练次数太少,max_batches只有4000,而图片数量却很大,从而训练的不够好。于是又重新修改,重新训练。后来发现还有一个地方需要修改。yolov2-voc.cfg中的filters,filters=num×(classes + coords + 1),yolov2和yolov3能够检测的类别不一样,前者是20类,后者是80类。num通常为5,coords=4,故将其修改为filters=5*(20+4+1)=125。
对了,还有一处,examples中的darknet.c文件的437行(如果没找到,在这附近找)中的"cfg/coco.data"改为"cfg/voc.data",如下:
test_detector("cfg/voc.data", argv[2], argv[3], filename, thresh, .5, outfile, fullscreen);
因为我们修改的是voc.data,而不是coco.data,所以需要修改成自己用的文件。
最后,我们终于可以再次重新训练,max_batches依然设为4000,因为我们想尽快看到结果。但是发现一开始学习率一直为0,这时候可以修改burn_in这个值从1000改为100。
最后的最后,再再次重新训练。训练完后进行测试终于出了结果,如下:
由于我们的max_batches=4000,迭代次数较少。所以训练出的东西还是不够的。可以看出图片的框不是很准确,第二张图的狗没有检测出来,且旁边的马被误检为羊。如果按照原始的数据,max_batches=80200+, steps=40000,60000。最后检测出来的效果应该会跟原始提供的权重检测的结果相似,不会有太大区别。