目录
1建立数据集
1.1图片
1.2xml文件
1.3数据集划分
2下载ImageNet数据集下预训练得到的模型
3修改prototxt配置文件
3.1修改train.prototxt
3.2修改test.prototxt
3.3修改solver.prototxt
3.4修改pascal_voc.py
3.5修改imdb.py
3.6修改train_net.py(运行train_net.py进行训练时修改)
3.7修改config.py(运行train_net.py进行训练时修改)
3.8修改faster_rcnn_end2end.sh(采用脚本训练时修改)
4.1训练准备
4.2模型训练
4.2.1通过运行脚本命令来训练模型
4.2.2通过运行py文件来训练模型
5测试模型
6Demo
6.1准备
6.2运行Demo
数据集格式应和VOC2007相同。
图片命名按照VOC2007标准格式,如“000001.jpg”形式。训练集中所有的图片重命名后放在路径py-faster-rcnn\data\VOCdevkit2007\VOC2007\JPEGImages下。
利用labelImg工具对图片自定义绘制包围框,并生成与图片对应的xml文件,如000001.xml。生成的所有的xml文件放在路径py-faster-rcnn\data\VOCdevkit2007\VOC2007\Annotations下。
利用xml文件划分数据集,生成trainval.txt、train.txt、test.txt和val.txt文件。将生成的四个txt文件放在路径py-faster-rcnn\data\VOCdevkit2007\VOC2007\ImagesSets\Main下。参考下面的python程序:py-faster-rcnn划分数据集(训练集、验证集、训练验证集、测试集)
运行命令:
$ cd py-fasyer-rcnn
$ ./data/scripts/fetch_imagenet_models.sh
下载的model保存在py-fasyer-rcnn /data/文件夹下,名称为imagenet_models。
├── caffe-fast-rcnn # caffe框架目录
├── data # 用来存放pretrained模型以及读取文件的cache缓存,还有一些下载模型的脚本
│ ├── cache
│ ├── demo
│ ├── ......
│ ├── scripts
│ ├── VOCdevkit
│ ├── imagenet_models
│ │ ├── VGG16.v2.caffemodel
│ │ ├── VGG_CNN_M_1024.v2.caffemodel
│ │ └── ZF.v2.caffemodel
│ └── ......
├── experiments # 存放配置文件以及运行的log文件
└── .....
使用基于VGG16模型的近似联合训练方法(端对端)训练和测试Faster R-CNN,需要更改以下配置文件:
文件路径py-faster-rcnn /models/pascal_voc/VGG16/faster_rcnn_end2end/train.prototxt
①修改input-data层(第11行)
将原先的num_classes的“21”改成“**”(**为实际类别数+1(背景)):
layer {
name: 'input-data'
type: 'Python'
top: 'data'
top: 'im_info'
top: 'gt_boxes'
python_param {
module: 'roi_data_layer.layer'
layer: 'RoIDataLayer'
param_str: "'num_classes': 21" //目标类别数+1
}
}
②修改roi-data层(第530行)
将原先的num_classes的“21”改成“**”(**为实际类别数+1(背景)):
layer {
name: 'roi-data'
type: 'Python'
bottom: 'rpn_rois'
bottom: 'gt_boxes'
top: 'rois'
top: 'labels'
top: 'bbox_targets'
top: 'bbox_inside_weights'
top: 'bbox_outside_weights'
python_param {
module: 'rpn.proposal_target_layer'
layer: 'ProposalTargetLayer'
param_str: "'num_classes': 21" //目标类别数+1
}
}
③修改cls_score层(第620行)
将原先的num_classes的“21”改成“**”(**为实际类别数+1(背景)):
layer {
name: "cls_score"
type: "InnerProduct"
bottom: "fc7"
top: "cls_score"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 21 //目标类别数+1
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
④修改bbox_pred层(第643行)
将原来的num_output的“84”改成“**”(**为(实际类别数+1(背景))*4):
layer {
name: "bbox_pred"
type: "InnerProduct"
bottom: "fc7"
top: "bbox_pred"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 84 //(目标类别数+1)*4
weight_filler {
type: "gaussian"
std: 0.001
}
bias_filler {
type: "constant"
value: 0
}
}
}
文件路径py-faster-rcnn /models/pascal_voc/VGG16/faster_rcnn_end2end/test.prototxt。test.prototxt中没有input-data层,只需修改cls_score层和bbox_pred层的方式即可。
①修改cls_score层(第567行)
将原先的num_classes的“21”改成“**”(**为实际类别数+1(背景)):
layer {
name: "cls_score"
type: "InnerProduct"
bottom: "fc7"
top: "cls_score"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 21 //目标类别数+1
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
②修改bbox_pred层(第592行)
将原来的num_output的“84”改成“**”(**为(实际类别数+1(背景))*4):
layer {
name: "bbox_pred"
type: "InnerProduct"
bottom: "fc7"
top: "bbox_pred"
param {
lr_mult: 1
}
param {
lr_mult: 2
}
inner_product_param {
num_output: 84 //(目标类别数+1)*4
weight_filler {
type: "gaussian"
std: 0.001
}
bias_filler {
type: "constant"
value: 0
}
}
}
文件路径py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_end2end/solver.prototxt。该文件可以修改最大迭代次数等。
文件路径py-faster-rcnn/ lib/datasets/pascal_voc.py。这里的类别以及之前的类别名称最好是全部小写,假如是大写的话,则会报keyError的错误。将其中的类别改为自己的。
self._classes = ('__background__', # always index 0
'car tail', 'car head', 'car turn', 'car crosswide',
'bus tail', 'bus head', 'bus turn', 'bus crosswide',
'truck tail','truck head', 'truck turn', 'truck crosswide',
'person','cyclist', 'cycle','tricycle','barricade','misc')
文件路径py-faster-rcnn/lib/datasets/imdb.py。
def append_flipped_images(self):
num_images = self.num_images
# widths = self._get_widths() # 修改前
widths = [PIL.Image.open(self.image_path_at(i)).size[0] # 修改后
for i in xrange(num_images)] # 修改后
for i in xrange(num_images):
boxes = self.roidb[i]['boxes'].copy()
oldx1 = boxes[:, 0].copy()
oldx2 = boxes[:, 2].copy()
boxes[:, 0] = widths[i] - oldx2 – 1
for b in range(len(boxes)): # 添加
if boxes[b][2] < boxes[b][0]: # 添加
boxes[b][0] = 0 # 添加
print boxes[:, 0] ####?
boxes[:, 2] = widths[i] - oldx1 - 1
print boxes[:, 0] ####?
assert (boxes[:, 2] >= boxes[:, 0]).all()
entry = {'boxes' : boxes,
'gt_overlaps' : self.roidb[i]['gt_overlaps'],
'gt_classes' : self.roidb[i]['gt_classes'],
'flipped' : True}
self.roidb.append(entry)
self._image_index = self._image_index * 2
文件路径py-faster-rcnn/tools/train_net.py。可以为其中的命令行参数设置默认值,这样就不用每次训练时都在命令行设置多个参数了。
文件路径py-faster-rcnn/lib/fast_rcnn/config.py。
修改:
__C.TRAIN.SNAPSHOT_ITERS=10000
该参数确定了模型每训练多少次保存一次快照,源码设置的是10000,根据自己设置的最大迭代次数来合理修改(它的值小于最大迭代次数,不然训练了半天一个模型都没保存)。
文件路径:py-faster-rcnn/experiments/scripts/faster_rcnn_end2end.sh
若调用脚本faster_rcnn_end2end.sh训练模型,则可以在文件中修改最大迭代次数。
TRAIN_IMDB="coco_2014_train"
TEST_IMDB="coco_2014_minival"
PT_DIR="coco"
ITERS=490000
4模型训练
在训练新模型时候,为防止与之前的模型搞混,需要删除以下文件:
①删除py-faster-rcnn下的output文件夹;
②删除py-faster-rcnn/data/cache中的文件;
③删除py-faster-rcnn/data/VOCdevkit2007/annotations_cache中的文件。
通过运行命令删除:
sudo rm -rf ~/py-faster-rcnn/output/*
sudo rm -rf ~/py-faster-rcnn/data/cache/*
sudo rm -rf ~/py-faster-rcnn/data/VOCdevkit2007/annotations_cache/*
sudo rm -rf ~/py-faster-rcnn/data/VOCdevkit2007/results/VOC2007/Main/*
$ cd py-faster-rcnn
$ sudo ./experiments/scripts/faster_rcnn_end2end.sh 0 VGG16 pascal_voc
其中,
$ sudo ./experiments/scripts/faster_rcnn_end2end.sh [GPU_ID] [NET] [--set ...]
(1)GPU_ID为训练所用的GPU,如果只有一块GPU,则为0;
(2)NET为使用的网络模型,可选择ZF、VGG_CNN_M_1024、VGG16;
(3)--set允许配置fast_rcnn.config文件中的各种选项。
$ cd py-faster-rcnn
$ sudo python ./tools/train_net.py --gpu 0 --solver models/pascal_voc/VGG16/faster_rcnn_end2end/solver.prototxt --weights data/imagenet_models/VGG16.v2.caffemodel --imdb voc_2007_trainval --cfg experiments/cfgs/faster_rcnn_end2end.yml
其中,
--gpu:代表机器上的GPU编号。
--solver:代表模型的配置文件,train.prototxt的文件路径已经包含在这个文件之中。
--weights:代表初始化的权重文件,这里用的是Imagenet上预训练好的模型,大型的网络我们选择用VGG_16.v2.caffemodel。
--imdb:给出的训练的数据库名字需要在factory.py的_sets中,在文件里面有_sets[‘hs’],train_net.py:这个文件会调用factory.py再生成hs这个类,来读取数据。
训练完成后生成的模型保存在路径py-faster-rcnn\output\faster_rcnn_end2end\voc_2007_trainval下。
运行命令(将vgg16_faster_rcnn_iter_10000.caffemodel修改为自己训练得到的模型):
$ cd py-faster-rcnn
$ sudo python ./tools/test_net.py --gpu 0 --def models/pascal_voc/VGG16/faster_rcnn_end2end/test.prototxt --net output/faster_rcnn_end2end/voc_2007_trainval/vgg16_faster_rcnn_iter_10000.caffemodel --imdb voc_2007_test --cfg experiments/cfgs/faster_rcnn_end2end.yml
若测试时出现报错:IndexError:too many indices for array
原因:样本量太少,某些类别在测试集中没有,路径data/VOCdevkit2007/results/VOC2007/main.下生成的对应的txt文件是空的。
解决办法:在路径py-faster-rcnn/lib/datasets/voc_eval.py中的BB=BB[sorted_ind,:]上面一行添加语句if len(BB) !=0:(注意if后要缩进)
训练完成之后,将训练得到的py-faster-rcnn\output\faster_rcnn_end2end\voc_2007_trainval中的caffemodel拷贝至py-faster-rcnn\data\faster_rcnn_models下。
修改py-faster-rcnn\tools\下demo.py的配置:
(1)修改CLASSES(第27行)
把里面的原始标签全部改为自己的标签:
CLASSES = ('__background__',
'car tail', 'car head', 'car turn', 'car crosswide',
'bus tail', 'bus head', 'bus turn', 'bus crosswide',
'truck tail','truck head', 'truck turn', 'truck crosswide',
'person','cyclist','cycle','tricycle','barricade','misc')
(2)修改NETS(第39行)
将VGG16_faster_rcnn_final.caffemodel修改为自己训练得到的模型:
NETS = {'vgg16': ('VGG16',
'VGG16_faster_rcnn_final.caffemodel'),
'zf': ('ZF',
'ZF_faster_rcnn_final.caffemodel'),
'resnet50': ('ResNet-50',
'ResNet-50_faster_rcnn_final.caffemodel')}
(3)修改prototxt(第124行)
由于prototxt默认配置为faster_rcnn_alt_opt,所以需要修改为faster_rcnn_end2end。
将:
prototxt = os.path.join(cfg.MODELS_DIR, NETS[args.demo_net][0],
'faster_rcnn_alt_opt', 'faster_rcnn_test.pt')
修改为:
prototxt = os.path.join(cfg.MODELS_DIR, NETS[args.demo_net][0],
'faster_rcnn_end2end', 'test.prototxt')
(4)修改im_names(第148行)
将内容修改为需要测试的图片名字,并把测试图片放在py-faster-rcnn\data\demo中,并按照训练图片的命名格式和大小来修改测试图片。
例如测试图片为:
将:
im_names = ['000456.jpg', '000542.jpg', '001150.jpg', '001763.jpg', '004545.jpg']
修改为:
im_names = ['000001.jpg', '000002.jpg', '000003.jpg', '000004.jpg', '000005.jpg', '000006.jpg']
(1)将默认的模型改为VGG16
在py-faster-rcnn\tools\demo.py的def parse_args()里修改默认参数:
parser.add_argument (
‘–net’,
dest=’demo_net’,
help=’Network to use [vgg16]’,
choices=NETS.keys(),
default=’vgg16’ # 修改为vgg16
)
(2)运行
运行命令:
$ cd py-faster-rcnn
$ sudo python ./tools/demo.py
若不修改默认的模型,则运行命令:
$ cd py-faster-rcnn
$ sudo python ./tools/demo.py --net vgg16