上一篇:【DL (1)】Linux16.04.2 1080ti cuda8.0 cudnn5 caffe py-faster-rcnn
配置好py-faster-rcnn,运行demo成功后(https://blog.csdn.net/foreverhehe716/article/details/80408522),尝试用自己的数据进行训练和识别测试。为了取得较好的效果以及容易上手,以VOC的数据集和训练好的model入手,然后加入自己的数据完成训练和测试。
1、VOC数据集训练和识别
(1)下载训练、验证以及测试集和VOCdevkit
这里博客里有个百度云地址:https://blog.csdn.net/sinat_30071459/article/details/51332084
其实可以直接用下面命令下载,速度也还可以,在py-faster-rcnn/data下开启terminal输入下面命令:
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtest_06-Nov-2007.tar
wget http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCdevkit_08-Jun-2007.tar
下载之后解压:
tar xvf VOCtrainval_06-Nov-2007.tar
tar xvf VOCtest_06-Nov-2007.tar
tar xvf VOCdevkit_08-Jun-2007.tar
PS:解压后这几个自动合并成一个文件夹为“VOCdevkit”,该文件夹位于py-faster-rcnn/data文件夹下。将VOCdevkit改为“VOCdevkit2007”,否则后面运行时会报错。
解压后的文件夹里面长这样:
$VOCdevkit/ # 开发工具包
$VOCdevkit/VOCcode/ # VOC实用代码
$VOCdevkit/VOC2007# 图片集, 注释, 等等
# 一些其他的目录
(2)下载预训练的imageNet model
本来可以运行如下代码自动下载:
./data/scripts/fetch_imagenet_models.sh
但是基本会被墙或者没有速度,要么从这里下:http://pan.baidu.com/s/1hsxx8OW
(from https://blog.csdn.net/sinat_30071459/article/details/51332084 )
(3)训练和测试
训练方式有两种,对应不同的代码,详见https://blog.csdn.net/CV_adventurer/article/details/72805852#3-%E8%AE%AD%E7%BB%83PASCAL-VOC-2007%E7%9A%84%E6%95%B0%E6%8D%AE%E9%9B%86
用近似联合训练简单测试一下,用下面代码:
./experiments/scripts/faster_rcnn_end2end.sh [GPU_ID] [NET] [--set ...]
后面为设置,比如:
./experiments/scripts/faster_rcnn_end2end.sh 0 VGG_CNN_M_1024 pascal_voc
上面表面GPU编号是0,用的特征提取网络是VGG_CNN_M_1024, 用的数据集为pascal_voc。开始训练了,首先是各个参数、设置的显示,然后是网络结构的自检,然后开始训练。
根据faster_rcnn_end2end.sh中的路径等设置,可以找到LOG位置信息。里面Line30设置数据集pascal_voc情况下训练的迭代次数ITERS. 训练得到的model在py-faster-rcnn/output/faster_rcnn_end2end/voc_2007_trainval文件夹下面。
2、用自己的数据训练和测试
依托VOC2007的结构,用自己的数据进行训练和测试。
因为demo.py是基于voc2007的,因此为了最快应用自己数据的训练测试,采用了voc的文件夹布置结构。
(1)制作数据
将voc2007原来JPEGImages文件夹下的影像删除,替换成自己的影像:
制作标签,我用的是labelImg这个工具,非常好用,手动画了boundingbox后自动生成可直接使用的标签xml文件。
xml文件放在annotations文件夹下:
(2)划分数据集
然后需要生成四个txt文件,告诉程序哪些图片是用来train,哪些用来val,哪些用来test:
可以用如下matlab代码实现(from https://blog.csdn.net/CV_adventurer/article/details/72805852#3-%E8%AE%AD%E7%BB%83PASCAL-VOC-2007%E7%9A%84%E6%95%B0%E6%8D%AE%E9%9B%86):
%%
%该代码根据已生成的xml,制作VOC2007数据集中的trainval.txt;train.txt;test.txt和val.txt
%trainval占总数据集的70%,test占总数据集的30%;train占trainval的70%,val占trainval的30%;
%上面所占百分比可根据自己的数据集修改
%注意修改下面两个路径
xmlfilepath='/home/linbiyuan/py-faster-rcnn/data/VOCdevkit2007/VOC2007/Annotations';
txtsavepath='/home/linbiyuan/py-faster-rcnn/data/VOCdevkit2007/VOC2007/ImageSets/Main/';
xmlfile=dir(xmlfilepath);
numOfxml=length(xmlfile)-2;%减去.和.. 总的数据集大小
trainval=sort(randperm(numOfxml,floor(numOfxml*0.7)));%trainval为数据集的50%
test=sort(setdiff(1:numOfxml,trainval));%test为剩余50%
trainvalsize=length(trainval);%trainval的大小
train=sort(trainval(randperm(trainvalsize,floor(trainvalsize*0.7))));
val=sort(setdiff(trainval,train));
ftrainval=fopen([txtsavepath 'trainval.txt'],'w');
ftest=fopen([txtsavepath 'test.txt'],'w');
ftrain=fopen([txtsavepath 'train.txt'],'w');
fval=fopen([txtsavepath 'val.txt'],'w');
for i=1:numOfxml
if ismember(i,trainval)
fprintf(ftrainval,'%s\n',xmlfile(i+2).name(1:end-4));
if ismember(i,train)
fprintf(ftrain,'%s\n',xmlfile(i+2).name(1:end-4));
else
fprintf(fval,'%s\n',xmlfile(i+2).name(1:end-4));
end
else
fprintf(ftest,'%s\n',xmlfile(i+2).name(1:end-4));
end
end
fclose(ftrainval);
fclose(ftrain);
fclose(fval);
fclose(ftest);
xml,制作VOC2007数据集中的trainval.txt;train.txt;test.txt和val.txt
%trainval占总数据集的70%,test占总数据集的30%;train占trainval的70%,val占trainval的30%;
%上面所占百分比可根据自己的数据集修改
%注意修改下面两个路径
xmlfilepath='/home/linbiyuan/py-faster-rcnn/data/VOCdevkit2007/VOC2007/Annotations';
txtsavepath='/home/linbiyuan/py-faster-rcnn/data/VOCdevkit2007/VOC2007/ImageSets/Main/';
xmlfile=dir(xmlfilepath);
numOfxml=length(xmlfile)-2;%减去.和.. 总的数据集大小
trainval=sort(randperm(numOfxml,floor(numOfxml*0.7)));%trainval为数据集的50%
test=sort(setdiff(1:numOfxml,trainval));%test为剩余50%
trainvalsize=length(trainval);%trainval的大小
train=sort(trainval(randperm(trainvalsize,floor(trainvalsize*0.7))));
val=sort(setdiff(trainval,train));
ftrainval=fopen([txtsavepath 'trainval.txt'],'w');
ftest=fopen([txtsavepath 'test.txt'],'w');
ftrain=fopen([txtsavepath 'train.txt'],'w');
fval=fopen([txtsavepath 'val.txt'],'w');
for i=1:numOfxml
if ismember(i,trainval)
fprintf(ftrainval,'%s\n',xmlfile(i+2).name(1:end-4));
if ismember(i,train)
fprintf(ftrain,'%s\n',xmlfile(i+2).name(1:end-4));
else
fprintf(fval,'%s\n',xmlfile(i+2).name(1:end-4));
end
else
fprintf(ftest,'%s\n',xmlfile(i+2).name(1:end-4));
end
end
fclose(ftrainval);
fclose(ftrain);
fclose(fval);
fclose(ftest);
生成好后如下。打开看,可以发现是图像名称列表。
(3)修改文件:
因为我要识别的为船和背景,因此是两类。需要修改的地方如下:
在/py-faster-rcnn/models/pascal_voc/VGG_CNN_M_1024/faster_rcnn_end2end/train.prototxt文件中,需要将类别的地方修改为2类(需要修改三处),bbox_pred层中的output数目修改为类数×4=2*4=8,具体如下:
注意下图修改的都是train。prototxt中的内容:
在同文件夹下的text.prototxt中也要类似修改,其中为cls_score层的num_output修改为2,bbox_pred层的num_output修改为8,原因同上。
另外,进入到py-faster-rcnn/lib/datasets文件夹下,对下面的文件进行修改。首先需要对lmdb.py中加入如下语句,避免bug。
(4)需要注意的设置
有时候数据集很小,可能会报错说index过大,同时你想先把迭代次数设置小一些,看程序是否能够正常运行。设置之间都有联系,不能任意修改数值。
需要修改的地方如下:
/py-faster-rcnn/tools/train_faster_rcnn_alt_opt.py
上面的值改小了,就可以测试数据量较少的情况也不会报错。
另外,如果将/py-faster-rcnn/experiments/scripts/faster_rcnn_end2end.sh里面的ITER数值设的很小,那么在/py-faster-rcnn/models/pascal_voc?VGG_CNN_M_1024/faster_rcnn_end2end/solver.prototxt文件里,stepsize值要小于这个ITER值。
(5)训练和测试
训练:和上面VOC的数据集训练一样。
识别新数据:修改/py-faster-rcnn/tools/demo.py中的内容,主要是设置test.prototxt和caffemodel的路径,我这里直接写死了:
并替换成你要检测的影像名称:
将测试影像放置在/py-faster-rcnn/data/demo文件夹下即可。
运行demo.py即可:
yexin@yexin-Precision-Tower-7910:~/py-faster-rcnn$ ./tools/demo.py
3. 对视频流实时处理
改动demo.py如下:(主要是vis_detections_video函数加入,demo函数改造,以及main函数调用的地方修改),因为太懒,所以直接把整个demo.py贴上来。
#!/usr/bin/env python
# --------------------------------------------------------
# Faster R-CNN
# Copyright (c) 2015 Microsoft
# Licensed under The MIT License [see LICENSE for details]
# Written by Ross Girshick
# --------------------------------------------------------
"""
Demo script showing detections in sample images.
See README.md for installation instructions before running.
"""
import _init_paths
from fast_rcnn.config import cfg
from fast_rcnn.test import im_detect
from fast_rcnn.nms_wrapper import nms
from utils.timer import Timer
import matplotlib.pyplot as plt
import numpy as np
import scipy.io as sio
import caffe, os, sys, cv2
import argparse
CLASSES = ('__background__',
'ship')
NETS = {'vgg16': ('VGG16',
'VGG16_faster_rcnn_final.caffemodel'),
'zf': ('ZF',
'ZF_faster_rcnn_final.caffemodel'),
'wyx': ('wyx','vgg_cnn_m_1024_faster_rcnn_iter_1000.caffemodel')}
def vis_detections(im, class_name, dets, thresh=0.5):
"""Draw detected bounding boxes."""
inds = np.where(dets[:, -1] >= thresh)[0]
if len(inds) == 0:
return
im = im[:, :, (2, 1, 0)]
fig, ax = plt.subplots(figsize=(12, 12))
ax.imshow(im, aspect='equal')
for i in inds:
bbox = dets[i, :4]
score = dets[i, -1]
ax.add_patch(
plt.Rectangle((bbox[0], bbox[1]),
bbox[2] - bbox[0],
bbox[3] - bbox[1], fill=False,
edgecolor='red', linewidth=3.5)
)
ax.text(bbox[0], bbox[1] - 2,
'{:s} {:.3f}'.format(class_name, score),
bbox=dict(facecolor='blue', alpha=0.5),
fontsize=14, color='white')
ax.set_title(('{} detections with '
'p({} | box) >= {:.1f}').format(class_name, class_name,
thresh),
fontsize=14)
plt.axis('off')
plt.tight_layout()
plt.draw()
def vis_detections_video(im, class_name, dets, thresh=0.5):
"""Draw detected bounding boxes."""
global lastColor,frameRate
inds = np.where(dets[:, -1] >= thresh)[0]
if len(inds) == 0:
return im
for i in inds:
bbox = dets[i, :4]
score = dets[i, -1]
cv2.rectangle(im,(bbox[0],bbox[1]),(bbox[2],bbox[3]),(0,0,255),2)
cv2.rectangle(im,(int(bbox[0]),int(bbox[1]-20)),(int(bbox[0]+200),int(bbox[1])),(10,10,10),-1)
cv2.putText(im,'{:s} {:.3f}'.format(class_name, score),(int(bbox[0]),int(bbox[1]-2)),cv2.FONT_HERSHEY_SIMPLEX,.75,(255,255,255))#,cv2.CV_AA)
return im
def demo(net, im):
"""Detect object classes in an image using pre-computed object proposals."""
global frameRate
# Load the demo image
#im_file = os.path.join(cfg.DATA_DIR, 'demo', image_name)
#im = cv2.imread(im_file)
# Detect all object classes and regress object bounds
timer = Timer()
timer.tic()
scores, boxes = im_detect(net, im)
timer.toc()
print ('Detection took {:.3f}s for '
'{:d} object proposals').format(timer.total_time, boxes.shape[0])
frameRate = 1.0/timer.total_time
print "fps: " + str(frameRate)
# Visualize detections for each class
CONF_THRESH = 0.8
NMS_THRESH = 0.3
for cls_ind, cls in enumerate(CLASSES[1:]):
cls_ind += 1 # because we skipped background
cls_boxes = boxes[:, 4*cls_ind:4*(cls_ind + 1)]
cls_scores = scores[:, cls_ind]
dets = np.hstack((cls_boxes,
cls_scores[:, np.newaxis])).astype(np.float32)
keep = nms(dets, NMS_THRESH)
dets = dets[keep, :]
vis_detections_video(im, cls, dets, thresh=CONF_THRESH)
cv2.putText(im,'{:s} {:.2f}'.format("FPS:", frameRate),(1750,50),cv2.FONT_HERSHEY_SIMPLEX,1,(0,0,255))
cv2.imshow(videoFilePath.split('/')[len(videoFilePath.split('/'))-1],im)
cv2.waitKey(20)
def parse_args():
"""Parse input arguments."""
parser = argparse.ArgumentParser(description='Faster R-CNN demo')
parser.add_argument('--gpu', dest='gpu_id', help='GPU device id to use [0]',
default=0, type=int)
parser.add_argument('--cpu', dest='cpu_mode',
help='Use CPU mode (overrides --gpu)',
action='store_true')
parser.add_argument('--net', dest='demo_net', help='Network to use [vgg16]',
choices=NETS.keys(), default='vgg16')
args = parser.parse_args()
return args
if __name__ == '__main__':
cfg.TEST.HAS_RPN = True # Use RPN for proposals
args = parse_args()
# prototxt = os.path.join(cfg.MODELS_DIR, NETS[args.demo_net][0],
# 'faster_rcnn_alt_opt', 'faster_rcnn_test.pt')
prototxt = '/home/yexin/py-faster-rcnn/models/pascal_voc/VGG_CNN_M_1024/faster_rcnn_end2end/test.prototxt'
# print 'see prototxt path{}'.format(prototxt)
# caffemodel = os.path.join(cfg.DATA_DIR, 'faster_rcnn_models',
# NETS[args.demo_net][1])
caffemodel = '/home/yexin/py-faster-rcnn/output/faster_rcnn_end2end/voc_2007_trainval/vgg_cnn_m_1024_faster_rcnn_iter_100.caffemodel'
# print '\n\nok'
if not os.path.isfile(caffemodel):
raise IOError(('{:s} not found.\nDid you run ./data/script/'
'fetch_faster_rcnn_models.sh?').format(caffemodel))
print '\n\nok'
if args.cpu_mode:
caffe.set_mode_cpu()
else:
caffe.set_mode_gpu()
caffe.set_device(args.gpu_id)
cfg.GPU_ID = args.gpu_id
net = caffe.Net(prototxt, caffemodel, caffe.TEST)
print '\n\nLoaded network {:s}'.format(caffemodel)
# Warmup on a dummy image
im = 128 * np.ones((300, 500, 3), dtype=np.uint8)
for i in xrange(2):
_, _= im_detect(net, im)
videoFilePath = '/home/yexin/py-faster-rcnn/data/demo/test_1-3.mp4'
videoCapture = cv2.VideoCapture(videoFilePath)
#success, im = videoCapture.read()
while True :
success, im = videoCapture.read()
demo(net, im)
if cv2.waitKey(10) & 0xFF == ord('q'):
break
videoCapture.release()
cv2.destroyAllWindows()
4. 参数设置及其意义
(1)solver.prototxt
#网络结构设置文件train.prototxt的路径
train_net: "models/pascal_voc/VGG_CNN_M_1024/faster_rcnn_end2end/train.prototxt"
#基础(初始)学习速率,即一开始用的就是这个学习速率,当采用lr_policy: "step"策略时,直到训练迭代到stepsize设置的70000次后,速率变成了base_lr*gamma,即0.0001,然后再70000次后变成了0.00001,以此类推。
base_lr: 0.001
lr_policy: "step"
gamma: 0.1
stepsize: 70000
#屏幕打印设置,每迭代100次,输出学习速率lr,loss等信息
display: 100
# 显示loss为之前average_loss个loss的平均值
average_loss: 100
#momentum是上一次梯度更新的权重,一般取值在0.5--0.99之间。通常设为0.9,momentum可以让使用SGD的深度学习方法更加稳定以及快速。(不太懂。。。)
momentum: 0.9
#权重衰减项,防止过拟合的一个参数。weight decay(权值衰减)使用的目的是防止过拟合。在损失函数中,weight decay是放在正则项(regularization)(这是what?)前面的一个系数,正则项一般指示模型的复杂度,所以weight decay的作用是调节模型复杂度对损失函数的影响,若weight decay很大,则复杂的模型损失函数的值也就大。。
weight_decay: 0.005
# We disable standard caffe solver snapshotting and implement our own snapshot
# function
#每迭代10000次就保存一个版本的model和solverstate
snapshot: 10000
# We still use the snapshot prefix, though
# 保存的名称前缀
snapshot_prefix: "vgg_cnn_m_1024_faster_rcnn"
更多参数解释可参考博客https://blog.csdn.net/zhanghenan123/article/details/80703607
https://blog.csdn.net/u012746763/article/details/51549184
关于学习速率,见这篇博客:https://blog.csdn.net/R1uNW1W/article/details/79251530
5. trouble shootting
(1) 14582
在solver.prototxt中,将基础学习速率设为:base_lr: 0.01,发现会报错:
14582 Floating point exception(core dumped)
我的解决方案:
base_lr: 0.001
网上有说在跑识别新图像的demo出现了此错误,然后解决方法是将min_size设为1. https://github.com/rbgirshick/py-faster-rcnn/issues/786
另:发现在我的train.prototxt与test.prototxt中,设置的conv1中的lr_mult都为0,感觉不对,查了下大家都设的如下,因此改为: