Faster R-CNN 运行、训练及测试自己的数据集

运行环境:

Ubuntu 16.04+Python3.6+TensorFlow-gpu1.2.1+CUDA8.0+cudnn5.1

前提:

已搭建好深度学习环境,没有的话可以看我的其它文章(待更)。

注意:

1.本文讲解的是基于GPU训练,Python是基于Anaconda安装;
2.Faster-R-CNN只支持Tensorflow1.2的版本,故版本不宜过高,否则报错;

降低TensorFlow版本:
conda install tensorflow-gpu==1.2.1
选择一个路径下载模型:
git clone https://github.com/endernewton/tf-faster-rcnn.git
下载后会有一个tf-faster-rcnn的文件夹,进入lib目录下:
cd tf-faster-rcnn/lib

修改tf-faster-rcnn/lib/setup.py文件翻至最后面的-arch参数,将其改为sm_61(对应1050Ti和1080Ti)具体显卡的算力参数配置可在这个网站查找https://developer.nvidia.com/cuda-gpus,算力中对应的sm_6.1即为这里的sm_61.

vim setup.py
安装easydict, cython, opencv-python等包:
pip install easydict
pip install cython
pip install opencv-python
pip install matplotlib
python -m pip install Pillow
在lib目录下编译cython:
make clean
make
cd ..
安装COCO API:
cd data
git clone https://github.com/pdollar/coco.git
cd coco/PythonAPI
make
cd ../../..
在tf-faster-rcnn目录下下载VOC2007数据集:
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
解压后会发现该目录下出现了一个VOCdevkit文件夹,这就是VOC2007数据集,将VOCdevkit文件夹重命名为VOCdevkit2007,并将其移动到data路径下:
mv VOCdevkit/ data/VOCdevkit2007
下载预训练模型,github给的链接已失效,可在百度网盘下载 密码:lzns。
下载后将其放在data目录下,并进行解压:
tar xvf voc_0712_80k-110k.tgz
然后在tf-faster-rcnn目录下建立预训练模型软链接:
NET=res101
TRAIN_IMDB=voc_2007_trainval+voc_2012_trainval
mkdir -p output/${NET}/${TRAIN_IMDB}
cd output/${NET}/${TRAIN_IMDB}
ln -s ../../../data/voc_2007_trainval+voc_2012_trainval ./default
cd ../../.
运行demo:
CUDA_VISIBLE_DEVICES=0 ./tools/demo.py

使用训练过的模型对数据进行测试:

这里需要修改tf-faster-rcnn/lib/datasets/voc_eval.py的几个数据:

gedit lib/datasets/voc_eval.py
# with open(cachefile,'w') as f   #修改前内容
with open(cachefile,'wb') as f    #修改后内容
......
# cachefile = os.path.join(cachedir, '%s_annots.pkl' % imagesetfile)  #修改前内容
cachefile = os.path.join(cachedir, '%s_annots.pkl' % imagesetfile.split("/")[-1].split(".")[0]) #修改后内容
接下来运行:
GPU_ID=0
./experiments/scripts/test_faster_rcnn.sh $GPU_ID pascal_voc_0712 res101

训练模型:

此操作是在tf-faster-rcnn目录下进行
下载VGG和resnet模型,下载后对其解压后的命名为vgg_16.ckpt和resnet_v1_101.ckpt
将其改名为vgg16.ckpt和res101.ckpt,
并在data目录下创建一个imagenet_weights文件夹,
并将解压后的文集移至该目录下:

下载vgg16模型:
mkdir -p data/imagenet_weights
cd data/imagenet_weights
wget -v http://download.tensorflow.org/models/vgg_16_2016_08_28.tar.gz
tar -xzvf vgg_16_2016_08_28.tar.gz
mv vgg_16.ckpt vgg16.ckpt
cd ../..
下载res101模型:
mkdir -p data/imagenet_weights
cd data/imagenet_weights
wget -v http://download.tensorflow.org/models/resnet_v1_101_2016_08_28.tar.gz
tar -xzvf resnet_v1_101_2016_08_28.tar.gz
mv resnet_v1_101.ckpt res101.ckpt
cd ../..

为了节省时间并排除错误,我把迭代次数只设置了20次,把./experiments/scripts/train_faster_rcnn.sh里的第22行把ITERS=70000改成ITERS=20,同时记得把./experiments/scripts/test_faster_rcnn.sh的ITERS也改成20。
执行训练:

./experiments/scripts/train_faster_rcnn.sh 0 pascal_voc vgg16
注意:因为我使用的是pascal_voc数据集,所以只需要更改对应数据集的ITERS的就行了,训练和测试的都要改,因为在train_faster_rcnn.sh的末尾会执行test_faster_rcnn.sh。

如果训练通过,不报错,则说明程序运行成功。

以上是各种配置及检验程序能否正常运行,下面将讲解训练自己的数据集

替换自己的数据集:

将前面下载的VOC2007数据集中的Annatations中的文件删去,换成自己的xml文件,将原数据集中的JPEGImages中的图片删去,换成自己的.jpg图片,但需要注意的是图片和xml文件都要为000001.jpg,000001.xml的六位数命名格式,一一对应,所有类别放在一起。

使用代码生成训练集测试集:

我用的时MATLAB代码,Python没有尝试,在此贴出作为备忘。

Python代码:
#注意修改路径,代码中的Annotations和Imagesets文件均为VOCdevkit/VOC2007/路径下的文件,自己操作时要写对自己的文件路径,否则生成的.txt文件错误会导致程序无法运行
import os 
import random 
def _main(): 
    trainval_percent = 0.5 
    train_percent = 0.5 
    xmlfilepath = 'Annotations'   #存放xml文件的路径
    total_xml = os.listdir(xmlfilepath) 
    num = len(total_xml) 
    list = range(num) 
    tv = int(num * trainval_percent) 
    tr = int(tv * train_percent) 
    trainval = random.sample(list, tv) 
    train = random.sample(trainval, tr) 
    ftrainval = open('ImageSets/Main/trainval.txt', 'w') 
    ftest = open('ImageSets/Main/test.txt', 'w') 
    ftrain = open('ImageSets/Main/train.txt', 'w') 
    fval = open('ImageSets/Main/val.txt', 'w') 
    for i in list: 
        name = total_xml[i][:-4] + '\n' 
        if i in trainval: 
            ftrainval.write(name) 
            if i in train: 
                ftest.write(name) 
            else: 
                fval.write(name) 
        else: 
        ftrain.write(name) 
    ftrainval.close() 
    ftrain.close() 
    fval.close() 
    ftest.close() 
if __name__ == '__main__':
    _main()
MATLAB代码:
%%
%该代码根据已生成的xml,制作VOC2007数据集中的trainval.txt;train.txt;test.txt和val.txt
%trainval占总数据集的50%,test占总数据集的50%;train占trainval的50%,val占trainval的50%;
%上面所占百分比可根据自己的数据集修改,如果数据集比较少,test和val可少一些
%%
%注意修改下面两个路径
xmlfilepath='Annotations';
txtsavepath='ImageSets\Main\';

xmlfile=dir(xmlfilepath);
numOfxml=length(xmlfile)-2;%减去.和..  总的数据集大小

trainval=sort(randperm(numOfxml,floor(numOfxml/2)));%trainval为数据集的50%
test=sort(setdiff(1:numOfxml,trainval));%test为剩余50%

trainvalsize=length(trainval);%trainval的大小
train=sort(trainval(randperm(trainvalsize,floor(trainvalsize/2))));
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);

将Annotations和JPEGImages文件路径设置好后运行,会生成四个.txt文件,分别是:

test.txt,train.txt,trainval.txt,val.txt

将这四个文件放到下面两个目录下:

tf-faster-rcnn/data/VOCdevkit2007/VOC2007/ImageSets/Layout
tf-faster-rcnn/data/VOCdevkit2007/VOC2007/ImageSets/Main

在tf-faster-rcnn/lib/datasets目录下的pascal_voc.py里第36行更改自己的类别,'background'切记不可删掉,把后面的原来的20个label换成自己的

self._classes = ('__background__',  'man', 'woman')
                 '#自己的类名'

在train_faster_rcnn.sh和test_faster_rcnn.sh中修改迭代次数:

ITEMS=#自己设置,本人设置为50000

在开始训练之前,还需要把之前训练产生的模型以及cache删除掉,分别在下面三个路径下:

tf-faster-rcnn/output/vgg16/voc_2007_trainval/default
tf-faster-rcnn/data/cache
tf-faster-rcnn/data/VOCdevkit2007/annotations_cache

然后就可以开始训练了:
./experiments/scripts/train_faster_rcnn.sh 0 pascal_voc vgg16

把后面的vgg16换成res101即可更改模型进行训练,训练中会将模型保存在以下目录中:

output/vgg16/voc_2007_trainval/default
output/res101/voc_2007_trainval/default

到此为止,已经成功训练了自己的数据集,但如何让它显示检测结果的图片呢?下面将进行讲解。

运行demo显示自己的数据的测试结果:

在tools文件目录下,打开demo.py文件修改参数:

修改类别:
CLASSES = ('__background__', 'man', 'woman',  '#自己的类')
修改模型:

主要是修改迭代次数,最后的70000,10000就是对应模型在训练至该迭代次数下保存的模型参数

NETS = {'vgg16': ('vgg16_faster_rcnn_iter_70000.ckpt',),'res101':('res101_faster_rcnn_iter_10000.ckpt',)}
修改类别:
net.create_architecture("TEST",3,        # 自己的类别数+1

                          tag='default',anchor_scales=[8, 16, 32])
将图片换成自己要测试的图片:
im_names = ['000033.jpg', '000062.jpg', '000279.jpg',
                '000603.jpg', '000798.jpg', '001080.jpg', 
                '001084.jpg', '001210.jpg', '001587.jpg',
                '001851.jpg', '001852.jpg', '000000.jpg']

这里需要注意的是自己要测试的图片必须放在data/demo路径下,否则需要修改demo.py中存放demo测试图片的路径,相对麻烦容易出错。

运行demo:
./tools/demo.py
注意,这里默认为res101模型做demo测试,如果想换做vgg16模型测试demo,则要进行如下操作:
在tf-faster-rcnn下建立路径:

output/vgg16/voc_2007_trainval+voc_2012_trainval/default

将训练保存在output/vgg16/voc_2007_trainval/default路径中的vgg16模型中的同一迭代次数下的4个文件复制到上面建立的路径下,然后将其中的.pkl文件重命名为.ckpt文件,即可。

然后运行代码,指定网络为vgg16:
python ./tools/demo.py --net vgg16

批量测试test.txt中的图片并将结果保存在文件夹中

前面的demo只能测试自己指定的几张图片,如果想测试大量图片会比较麻烦,这里举例批量测试test.txt中的图片,并将结果保存在文件中。

这里需要修改demo.py文件:
#!/usr/bin/env python
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import _init_paths
from model.config import cfg
from model.test import im_detect
from model.nms_wrapper import nms

from utils.timer import Timer
import tensorflow as tf
import matplotlib.pyplot as plt
import numpy as np
import os, cv2
import argparse
from nets.vgg16 import vgg16
from nets.resnet_v1 import resnetv1

CLASSES = ('__background__',
           'man', 'woman', 'car')      # 修改自己的类别

NETS = {'vgg16': ('vgg16_faster_rcnn_iter_70000.ckpt',),'res101':    ('res101_faster_rcnn_iter_50000.ckpt',)}    # 修改自己的模型名字
DATASETS= {'pascal_voc': ('voc_2007_trainval',),'pascal_voc_0712': ('voc_2007_trainval+voc_2012_trainval',)}

def vis_detections(image_name, 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()
    # 添加下面两行,注意修改路径
    plt.savefig('/home/pxt/tf-faster-rcnn/result/'+image_name)   # 保存结果的路径
    print("save image to /home/pxt/tf-faster-rcnn/result/{}".format(image_name))


def demo(image_name, sess, net):      #第一个形参
    """Detect object classes in an image using pre-computed object proposals."""

    # 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(sess, net, im)
    timer.toc()
    print('Detection took {:.3f}s for {:d} object proposals'.format(timer.total_time, boxes.shape[0]))

    # 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(image_name, im, cls, dets, thresh=CONF_THRESH)    # 添加此处调用的参数

def parse_args():
    """Parse input arguments."""
    parser = argparse.ArgumentParser(description='Tensorflow Faster R-CNN demo')
    parser.add_argument('--net', dest='demo_net', help='Network to use [vgg16 res101]',
                        choices=NETS.keys(), default='res101')
    parser.add_argument('--dataset', dest='dataset', help='Trained dataset [pascal_voc pascal_voc_0712]',
                        choices=DATASETS.keys(), default='pascal_voc_0712')
    args = parser.parse_args()

    return args

if __name__ == '__main__':
    cfg.TEST.HAS_RPN = True  # Use RPN for proposals
    args = parse_args()

    # model path
    demonet = args.demo_net
    dataset = args.dataset
    tfmodel = os.path.join('output', demonet, DATASETS[dataset][0], 'default',
                              NETS[demonet][0])


    if not os.path.isfile(tfmodel + '.meta'):
        raise IOError(('{:s} not found.\nDid you download the proper networks from '
                       'our server and place them properly?').format(tfmodel + '.meta'))

    # set config
    tfconfig = tf.ConfigProto(allow_soft_placement=True)
    tfconfig.gpu_options.allow_growth=True

    # init session
    sess = tf.Session(config=tfconfig)
    # load network
    if demonet == 'vgg16':
        net = vgg16()
    elif demonet == 'res101':
        net = resnetv1(num_layers=101)
    else:
        raise NotImplementedError
    net.create_architecture("TEST", 4,      # 类别+1
                          tag='default', anchor_scales=[8, 16, 32])
    saver = tf.train.Saver()
    saver.restore(sess, tfmodel)

    print('Loaded network {:s}'.format(tfmodel))
    # 添加下面几行
    fi=open('/home/pxt/tf-faster-rcnn/data/VOCdevkit2007/VOC2007/ImageSets/Main/test.txt')#输入要批量检测的图片名字合集,直接用训练时的test.txt就行。
 
    txt=fi.readlines()
    im_names = []
    for line in txt:
        line=line.strip('\n')
        line=(line+'.jpg')
        im_names.append(line)
    print(im_names)
    fi.close()

    # 把之前的这几行注释或删去
    #im_names = ['000033.jpg', '000062.jpg', '000279.jpg',
    #            '000603.jpg', '000798.jpg', '001080.jpg', 
    #            '001084.jpg', '001210.jpg', '001587.jpg',
    #            '001851.jpg', '001852.jpg', '000000.jpg']
    
    for im_name in im_names:
        print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
        print('Demo for data/demo/{}'.format(im_name))
        demo(im_name, sess, net)

    #plt.show()    #最好注释这一行,不然会将大量图片全部显示出来

注意:还需将test.txt中的图像全部放到data/demo目录下,为方便起见,直接将JPEGImages中的图片全部复制到data/demo目录下,然后运行demo.py即可。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341