前言
前面已经介绍了如何准备数据集,以及如何修改数据集读写接口来操作数据集,接下来我来说明一下怎么来训练网络和之后的检测过程。
修改模型文件
faster rcnn有两种各种训练方式:
- Alternative training(alt-opt)
- Approximate joint training(end-to-end)
两种方法有什么不同,可以参考我这篇博客,推荐使用第二种,因为第二种使用的显存更小,而且训练会更快,同时准确率差不多,两种方式需要修改的代码是不一样的,同时faster rcnn提供了三种训练模型,小型的ZF model,中型的VGG_CNN_M_1024和大型的VGG16,论文中说VGG16效果比其他两个好,但是同时占用更大的GPU显存(~11GB)
我使用的是VGG model + alternative training,需要检测的类别只有一类,加上背景所以总共是两类(background + person)。
下面修改模型文件:
py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_alt_opt/stage1_fast_rcnn_train.pt
123456789101112131415layer {name: 'data'type: 'Python'top: 'data'top: 'rois'top: 'labels'top: 'bbox_targets'top: 'bbox_inside_weights'top: 'bbox_outside_weights'python_param {module: 'roi_data_layer.layer'layer: 'RoIDataLayer'param_str: "'num_classes': 2" #按训练集类别改,该值为类别数+1}}1234567891011121314151617181920212223layer {name: "cls_score"type: "InnerProduct"bottom: "fc7"top: "cls_score"param {lr_mult: 1.0}param {lr_mult: 2.0}inner_product_param {num_output: 2 #按训练集类别改,该值为类别数+1weight_filler {type: "gaussian"std: 0.01}bias_filler {type: "constant"value: 0}}}1234567891011121314151617181920212223layer {name: "bbox_pred"type: "InnerProduct"bottom: "fc7"top: "bbox_pred"param {lr_mult: 1.0}param {lr_mult: 2.0}inner_product_param {num_output: 8 #按训练集类别改,该值为(类别数+1)*4,四个顶点坐标weight_filler {type: "gaussian"std: 0.001}bias_filler {type: "constant"value: 0}}}py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_alt_opt/stage1_rpn_train.pt
123456789101112layer {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': 2" #按训练集类别改,该值为类别数+1}}py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_alt_opt/stage2_fast_rcnn_train.pt
123456789101112131415layer {name: 'data'type: 'Python'top: 'data'top: 'rois'top: 'labels'top: 'bbox_targets'top: 'bbox_inside_weights'top: 'bbox_outside_weights'python_param {module: 'roi_data_layer.layer'layer: 'RoIDataLayer'param_str: "'num_classes': 2" #按训练集类别改,该值为类别数+1}}1234567891011121314151617181920212223layer {name: "cls_score"type: "InnerProduct"bottom: "fc7"top: "cls_score"param {lr_mult: 1.0}param {lr_mult: 2.0}inner_product_param {num_output: 2 #按训练集类别改,该值为类别数+1weight_filler {type: "gaussian"std: 0.01}bias_filler {type: "constant"value: 0}}}1234567891011121314151617181920212223layer {name: "bbox_pred"type: "InnerProduct"bottom: "fc7"top: "bbox_pred"param {lr_mult: 1.0}param {lr_mult: 2.0}inner_product_param {num_output: 8 #按训练集类别改,该值为(类别数+1)*4,四个顶点坐标weight_filler {type: "gaussian"std: 0.001}bias_filler {type: "constant"value: 0}}}py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_alt_opt/stage2_rpn_train.pt
123456789101112layer {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': 2" #按训练集类别改,该值为类别数+1}}py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_alt_opt/faster_rcnn_test.pt
12345678910111213141516171819layer {name: "cls_score"type: "InnerProduct"bottom: "fc7"top: "cls_score"inner_product_param {num_output: 2 #按训练集类别改,该值为类别数+1}}layer {name: "bbox_pred"type: "InnerProduct"bottom: "fc7"top: "bbox_pred"inner_product_param {num_output: 84 #按训练集类别改,该值为(类别数+1)*4,四个顶点坐标}}
训练测试
训练前还需要注意几个地方:
cache问题:
假如你之前训练了官方的VOC2007的数据集或其他的数据集,是会产生cache的问题的,建议在重新训练新的数据之前将其删除。
py-faster-rcnn/output
py-faster-rcnn/data/cache
训练参数
参数放在如下文件:
py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_alt_opt/stage_fast_rcnn_solver*.pt
12345base_lr: 0.001lr_policy: 'step'step_size: 30000display: 20....迭代次数在文件py-faster-rcnn/tools/train_faster_rcnn_alt_opt.py中进行修改:
1max_iters = [80000, 40000, 80000, 40000]分别对应rpn第1阶段,fast rcnn第1阶段,rpn第2阶段,fast rcnn第2阶段的迭代次数,自己修改即可,不过注意这里的值不要小于上面的solver里面的step_size的大小,大家自己修改吧
开始训练
首先修改experiments/scripts/faster_rcnn_alt_opt.sh
成如下,修改地方已标注:
|
|
调用如下命令进行训练及测试,从上面代码可以看出,该shell文件在训练完后会接着进行测试,但是我的测试集没有标注,所以测试的时候会报错,但是由于Caltech数据集的测试结果有专门的评估代码,所以我不用faster r-cnn提供的代码进行测试,而是直接进行检测生成坐标,用专门的评估代码进行检测。
|
|
- 参数1:指定gpu_id。
- 参数2:指定网络模型参数。
- 参数3:数据集名称,目前只能为
pascal_voc
。
在训练过程中,会调用py_faster_rcnn/tools/train_faster_rcnn_alt_opt.py
文件开始训练网络。
可能会出现的Bugs
AssertionError: assert (boxes[:, 2] >= boxes[:, 0]).all()
问题重现
在训练过程中可能会出现如下报错:
|
|
问题分析
检查自己数据发现,左上角坐标 (x, y) 可能为0,或标定区域溢出图片(即坐标为负数),而faster rcnn会对Xmin,Ymin,Xmax,Ymax进行减一操作,如果Xmin为0,减一后变为65535,从而在左右翻转图片时导致如上错误发生。
问题解决
修改
lib/datasets/imdb.py
中的append_flipped_images()
函数:数据整理,在一行代码为
boxes[:, 2] = widths[i] - oldx1 - 1
下加入代码:123for b in range(len(boxes)):if boxes[b][2]< boxes[b][0]:boxes[b][0] = 0修改
lib/datasets/caltech.py
,_load_pascal_annotation()
函数,将对Xmin,Ymin,Xmax,Ymax减一去掉,变为:1234567891011121314# Load object bounding boxes into a data frame.for ix, obj in enumerate(objs):bbox = obj.find('bndbox')# Make pixel indexes 0-based# 这里我把‘-1’全部删除掉了,防止有的数据是0开始,然后‘-1’导致变为负数,产生AssertError错误x1 = float(bbox.find('xmin').text)y1 = float(bbox.find('ymin').text)x2 = float(bbox.find('xmax').text)y2 = float(bbox.find('ymax').text)cls = self._class_to_ind[obj.find('name').text.lower().strip()]boxes[ix, :] = [x1, y1, x2, y2]gt_classes[ix] = clsoverlaps[ix, cls] = 1.0seg_areas[ix] = (x2 - x1 + 1) * (y2 - y1 + 1)(可选)如果1和2可以解决问题,就没必要用方法3。修改
lib/fast_rcnn/config.py
,不使图片实现翻转,如下改为:12# Use horizontally-flipped images during training?__C.TRAIN.USE_FLIPPED = False
如果如上三种方法都无法解决该问题,那么肯定是你的数据集坐标出现小于等于0的数,你应该一一排查。
训练fast rcnn时出现loss=nan的情况。
问题重现
问题分析
这是由于模型不收敛,导致loss迅速增长。
而我出现以上现象的原因主要是因为我在出现AssertionError的时候直接使用了第三种方法导致的。也就是禁用图片翻转。
问题解决
启用图片翻转。
训练结果
训练后的模型放在output/faster_rcnn_alt_opt/train/VGG16_faster_rcnn_final.caffemodel
,该模型可以用于之后的检测。
检测
检测步骤
经过以上训练后,就可以用得到的模型来进行检测了。检测所参考的代码是tools/demo.py
,具体步骤如下:
- 将
output/faster_rcnn_alt_opt/train/VGG16_faster_rcnn_final.caffemodel
,拷贝到data/faster_rcnn_models
下,命名为VGG16_Caltech_faster_rcnn__final.caffemodel
- 进入
tools/
文件夹中,拷贝demo.py
为demo_caltech.py
。 - 修改demo_caltech.py代码如下:
|
|
在命令行中输入一下命令进行检测:
|
|
检测结果
放几张检测后的结果图,感觉检测效果并不是很好,很多把背景当成行人的错误: