1配置darknet环境
参考官网 darknet
git clone https://github.com/pjreddie/darknet
cd darknet
更改Makefile, 令GPU=1,CUDNN=1,OPENCV=1
ARCH= -gencode arch=compute_30,code=sm_30 \
-gencode arch=compute_35,code=sm_35 \
-gencode arch=compute_50,code=[sm_50,compute_50] \
-gencode arch=compute_52,code=[sm_52,compute_52] \
-gencode arch=compute_61,code=[sm_61,compute_61]
make
2制作特定格式的数据集
1.cfg/**.data
classes = 9 # 你的数据集类别数
train = /home/ktjiang/animal/data/list/train.txt #训练集路径,图片和标签要在同一个文件夹下,一个图片img对应一个标签txt
valid = /home/ktjiang/animal/data/list/test.txt #验证集路径, 图片和标签要在同一个文件夹下,一个图片img对应一个标签txt
names = data/animal.names #数据集类别名称
backup = backup #训练权重保存路径
2.data/**.names
类别从0开始,为方便,添加一个unknown类别,实际类别只有8类
unknown # 0
AmurLeopard # 1
AmurTiger # 2
Car # 3
Cow # 4
Dog # 5
RacoonDog # 6
Red_Fox # 7
WildBoar # 8
3.train.txt, test.txt
训练集和测试集图片的路径信息,其中/home/ktjiang/animal/data/train/
和/home/ktjiang/animal/data/val/
文件夹下还包含对应的*.txt(标签信息)
train.txt
/home/ktjiang/animal/data/train/2000001.jpg
/home/ktjiang/animal/data/train/1000011.jpg
/home/ktjiang/animal/data/train/3000084.jpg
test.txt
/home/ktjiang/animal/data/val/2000068.jpg
/home/ktjiang/animal/data/val/8000043.jpg
/home/ktjiang/animal/data/val/5000117.jpg
4.label格式(归一化)
class_id | x_center | y_center | w | h |
---|---|---|---|---|
1 | 0.66 | 0.29 | 0.19 | 0.39 |
假设一个标注的boundingbox的左下角和右上角坐标分别为(x1,y1)(x2,y2)
,图像的宽和高分别为w,h
归一化的中心点x坐标x_center计算公式:((x2+x1) / 2.0)/ w
归一化的中心点y_center坐标计算公式:((y2+y1) / 2.0)/ h
归一化的目标框宽度w的计算公式: (x2-x1) / w
归一化的目标框高度h计算公式:((y2-y1)/ h
如果图片的高度、宽度未知,可以通过cv2读取
imginfo = cv2.imread(img_dir + img_name + '.jpg').shape
imginfo里存的是图像的[h, w,通道数]
,这一需要注意imginfo结果里的顺序
5.新建一个cfg/yolov3_**.cfg配置文件
Testing # 测试模式,此模式下,下面的两行要放出来,训练模式下面的两行要注释掉
batch=1
subdivisions=1
#Training # 训练模式,此模式下,下面的两行要放出来,测试模式下面的两行要注释掉
#batch=64
#subdivisions=16 #每个batch分为16组,每组为batch/subdivision=4张图片
width=608 #网络输入的宽,高,通道数
height=608
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 #学习率变动因子,也即batch=40000时,learning_rate=0.0001, batch=45000时,learning_rate=0.00001
每一个yolo层的上一层卷积层的filter需要改变,random根据自己的显存决定(需要改变3个地方,3个yolo层)
[convolutional]
size=1
stride=1
pad=1
filters=42 # 3*(num_class + 5(注:4bbox+1confidence)) 这里num_class=9
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=9
num=9
jitter=.3
ignore_thresh = .7
truth_thresh = 1
random=1 # 多尺度训练打开,0为关闭
6.开始训练
./darknet detector train cfg/animal.data cfg/yolov3_animals.cfg darknet53.conv.74 -gpus 0,1,2,3 >log.txt
7.训练问题汇总
CUDA: out of memory 以及 resizing 问题
显存不够,调小batch,关闭多尺度训练:random = 0。
在迭代前期,loss很大,正常吗?
经过几个数据集的测试,前期loss偏大是正常的,后面就很快收敛了
训练出现nan的问题?
训练的时候若数据集小目标较少,106层会大概率输出nan,这是数据集的问题。如果数据集没有问题,可以通过调大batch或者调小learning_rate来解决.regin 82, regin 94, regin 106分别负责检测大,中,小物体,对应的feature map 大小为1313, 2626,52*52.对于大小为 416 x 416 的图像,YOLO 预测 ((52 x 52) + (26 x 26) + 13 x 13)) x 3 = 10647 个边界框
检测不到目标、计算recall为0,验证没有产生结果文件?
运行test,recall,vaild命令时,<test_cfg>文件中batch和subdivisions两项必须为1。官方cfg中两者值分别为64和16。
测试标签上如何添加置信值
由于官方代码测试只标注了类别,标签文字较大。使用过程中希望减小标签,并加上检测的置信值。
修改src/image.c
文件draw_detections
函数,前面部分代码修改如下:
void draw_detections(image im, detection *dets, int num, float thresh, char **names, image **alphabet, int classes)
{
int i,j;
for(i = 0; i < num; ++i){
char labelstr[4096] = {0};
int class = -1;
for(j = 0; j < classes; ++j){
if (dets[i].prob[j] > thresh){
if (class < 0) {
char a[20];
sprintf(a,"%g", dets[i].prob[j]);
strcat(labelstr, names[j]);
strcat(labelstr,":");
strcat(labelstr,a);
class = j;
} else {
char a[20];
sprintf(a,"%g",dets[i].prob[j]);
strcat(labelstr, ", ");
strcat(labelstr,names[j]);
strcat(labelstr,":");
strcat(labelstr,a);
}
printf("%s: %.0f%%\n", names[j], dets[i].prob[j]*100);
}
}
修改src/image.c
文件draw_detections
函数中get_label
函数调用的参数
if (alphabet) {
image label = get_label(alphabet, labelstr, (im.h*.03));
draw_label(im, top + width, left, label, rgb);
free_image(label);
}
image label = get_label(alphabet, labelstr, (im.h*.02));
源码中为0.03,修改为0.02后,标签文字减小,可以根据需要调整。
修改代码后需要使用make clean,make重新编译。
使用多GPU训练时,由于并行处理,训练迭代次数会一次跳过几轮,导致某些整数次迭代的模型没有保存。
修改example/detector.c文件中的第148行
源代码为:if(i%10000==0 || (i<1000 && i%100==0))
//迭代小于1000次,每100次保存模型,大于1000次,每10000次保存模型。
可以根据需要修改训练多少轮保存一个模型,if(i%1000==0 || (i<1000 && i%100==0))
,大于1000次,每1000次保存模型。
8.测试问题
./darknet detector test cfg/animal.data cfg/yolov3_animals.cfg backup/yolov3_final.weights -thresh 0.2 -gpus 0,1,2,3
验证
计算MAP和RECALL