【DL (2)】 py-faster-rcnn 运行VOC2007例子 加入自己的新数据新类别重新训练 识别图片 视频

上一篇:【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,感觉不对,查了下大家都设的如下,因此改为:

上一篇:Linux16.04.2 1080ti cuda8.0 cudnn5 caffe py-faster-rcnn

猜你喜欢

转载自blog.csdn.net/foreverhehe716/article/details/80504424