R-FCN Python版本实现

作者: Daisy丶 | 来源:发表于2017-03-17 15:45 被阅读5640次

    R-FCN(Region-based Fully Convolutional Networks),是一个准确和高效的基于区域的对象检测框架。 与先前的基于区域的检测器(诸如Fast/Faster R-CNN)在每个区域子网络几百次的高成本计算相反,R-FCN的基于区域的检测器是利用深度完全卷积网络,几乎所有计算在整个图像上共享。 R-FCN可以采用强大的完全卷积图像网络结构,例如ResNets等。

    相关代码提供了Matlab和Python版本的实现,两者均是基于Caffe框架的实现。因为个人需要,本文记录了我在Ubuntu Linux下运行Python版本R-FCN的步骤,由于使用了Python Layer,该版本的速度相对于Matlab版本降低了10%。

    Githubhttps://github.com/Orpine/py-R-FCN
    Paperhttps://arxiv.org/abs/1605.06409

    环境

    • Ubuntu Linux 14.04
    • Python 2.7
    • rfcn-caffe
    • CUDA Toolkit 7.5与 cuDNN v3 or cuDNN

    PS:
    由于R-FCN对Roi Layer有了修改,因此需用使用作者版本的Caffe而不是BLVC版本。该版本Caffe要求使用CUDA Toolkit 7.5与** cuDNN v3 or cuDNN v4**。
    因为cuda 7.5不支持gcc 4.9以上的编译器,而Ubuntu 16.04默认的编译器是gcc 5,即使是进行了降级处理,其apt-get仓库的各种依赖包依旧是使用gcc 5编译的,这样在编译caffe gpu的时候会出现冲突导致失败,因此最好选择Ubuntu 14.04。
    个人体验,如果完全按照官方的步骤与版本要求来做,很少出现大的错误,之前因为自己替换各种不同版本,导致了一个星期的时间出现各种错误,真的是教训啊。

    如果你需要在Windows下安装Caffe与R-FCN,可以参考下面这两篇文章:
    http://blog.csdn.net/evan_feng/article/details/51612843
    http://blog.csdn.net/chenzhi1992/article/details/53374265

    安装

    按照下面的顺序进行安装

    一般依赖库安装

    sudo apt-get install libprotobuf-dev libleveldb-dev libsnappy-dev libopencv-dev libhdf5-serial-dev protobuf-compiler
    sudo apt-get install --no-install-recommends libboost-all-dev
    

    Cuda 安装

    有两种方式可以安装cuba,分别是apt-get与run文件安装,单显卡用户推荐前一种,双显卡推荐后一种。

    第一种:
    先把自带的显卡驱动清理干净
    sudo apt-get --purge remove nvidia-*
    自动安装cuda 7.5,选择安装cuda toolkit与驱动
    sudo apt-get install nvidia-cuda-toolkit

    第二种:
    下载run文件,比如cuda_7.5.18_linux.run

    打开黑名单文件,将blacklist nouveau添加到末尾。
    sudo vim /etc/modprobe.d/blacklist.conf

    执行下列命名删除自带的驱动

    sudo reboot
    sudo apt-get remove --purge nvidia*
    

    重启后进入终端环境,进入run文件所在的目录,执行下列命令安装cuda

    sudo service lightdm stop
    chmod +x cuda_7.5.18_linux.run
    sudo ./cuda_7.5.18_linux.run
    

    如果出现错误

    If you're sure that X is not running, but are getting this error, please delete any X lock files in /tmp.

    可以通过通过直接删除X-lock文件解决问题
    sudo rm /tmp/.X0-lock

    配置cuda环境变量

    打开用户配置文件
    sudo vim ~/.bashrc

    在文件末尾添加路径,这里根据自己的安装目录格式进行修改

    PATH=/usr/local/cuda/bin:$PATH
    export PATH
    

    使路径生效
    source ~/.bashrc

    cudnn 安装

    下载cudnn文件并解压,执行下列命令安装cudnn,注意根据自己的路径进行修改。

    sudo tar xvf cudnn-7.0-linux-x64-v4.0-prod.tgz
    cd cuda/include
    sudo cp *.h /usr/local/include/
    cd ../lib64
    sudo cp lib* /usr/local/lib/
    cd /usr/local/lib
    sudo chmod +r libcudnn.so.4.0.4
    sudo ln -sf libcudnn.so.4.0.4 libcudnn.so.4
    sudo ln -sf libcudnn.so.4 libcudnn.so
    sudo ldconfig
    

    BLAS安装

    安装 ATLAS,如果追求更好的性能,可以自行安装OpenBLAS或者MKL,这样的话需要自行修改caffe的配置文件。
    sudo apt-get install libatlas-base-dev

    Python相关安装

    本文中使用了Ubuntu默认的python 2.7,如果使用了Anaconda2,那么可以省略某些包的安装。

    sudo apt-get install python-dev
    pip install cython  
    pip install easydict 
    apt-get install python-opencv 
    pip install matplotlib
    

    其余依赖库

    sudo apt-get install libgflags-dev libgoogle-glog-dev liblmdb-dev

    Caffe 安装

    作者提供的Caffe版本
    git clone https://github.com/daijifeng001/caffe-rfcn.git

    复制配置文件

    cd caffe-rfcn
    cp Makefile.config.example  Makefile.config
    

    修改配置文件,GPU版本删掉use_cudnn前的注释符号,CPU版本反之。

    # cuDNN acceleration switch (uncomment to build with cuDNN).
    USE_CUDNN := 1
    
    # CPU-only switch (uncomment to build without GPU support).
    # CPU_ONLY := 1
    

    支持Python layer

    # Uncomment to support layers written in Python (will link against Python libs)
    WITH_PYTHON_LAYER := 1
    

    如果使用了Python3、Anaconda等,可以自行修改其他属性。

    安装Caffe
    make -j8 && make pycaffe

    配置pycaffe的环境变量,注意根据自己的路径进行修改。

    vim ~/.bashrc 
    export PYTHONPATH=/home/xiaochu/caffe-rfcn/python:$PYTHONPATH # 添加到文件末尾
    source ~/.bashrc # 执行使更改生效。 
    

    R-FCN安装

    Python版本的R-FCN源码
    git clone https://github.com/Orpine/py-R-FCN.git

    编译lib目录下的Cython源码,将编译好的文件根据文件名,复制到nms、pycocotools、utils文件夹中去

    cd ~/py-R-FCN/lib
    python setup.py install
    

    下载 ResNet Caffemodel : rfcn_models
    解压到data目录下,解压后的目录结构如下:

    data/rfcn_models/resnet50_rfcn_final.caffemodel
    data/rfcn_models/resnet101_rfcn_final.caffemodel
    

    执行Demo

    cd ~/py-R-FCN/tools
    python demo_rfcn.py --net ResNet-50  
    

    由于R-FCN的demo源码是每张图片的每个物体在一个新的窗口中框出来,因此我修改了一下源码,使得一张图片中的所有物体能够在一个窗口中规被全部框出来。

    demo_rfcn.py

    #!/usr/bin/env python
    
    # --------------------------------------------------------
    # R-FCN
    # Copyright (c) 2016 Yuwen Xiong
    # Licensed under The MIT License [see LICENSE for details]
    # Written by Yuwen Xiong
    # --------------------------------------------------------
    
    """
    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__',
               'aeroplane', 'bicycle', 'bird', 'boat',
               'bottle', 'bus', 'car', 'cat', 'chair',
               'cow', 'diningtable', 'dog', 'horse',
               'motorbike', 'person', 'pottedplant',
               'sheep', 'sofa', 'train', 'tvmonitor')
    
    NETS = {'ResNet-101': ('ResNet-101',
                      'resnet101_rfcn_final.caffemodel'),
            'ResNet-50': ('ResNet-50',
                      'resnet50_rfcn_final.caffemodel')}
    
    
    def vis_detections(im, items):
        """Draw detected bounding boxes."""
        rects = []
        cas = []
        for item in items:
            class_name = item[0]
            dets = item[1]
            thresh = item[2]
    
            inds = np.where(dets[:, -1] >= thresh)[0]
            if len(inds) == 0:
                continue
    
            for i in inds:
                bbox = dets[i, :4]
                score = dets[i, -1]
    
                rect = [bbox[0], bbox[1], bbox[2] - bbox[0], bbox[3] - bbox[1]]
                rects.append(rect)
                cs = [class_name, score]
                cas.append(cs)
        return rects, cas
    
    
    def demo(net, image_name):
        """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(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
        cand = []
        for cls_ind, cls in enumerate(CLASSES[1:]):
            cls_ind += 1 # because we skipped background
            cls_boxes = boxes[:, 4:8]
            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, :]
    
            one = [cls, dets, CONF_THRESH]
            cand.append(one)
        rects, cas = vis_detections(im, cand)
    
        fig, ax = plt.subplots(figsize=(12, 12))
        im = im[:, :, (2, 1, 0)]
        ax.imshow(im, aspect='equal')
        for i in range(len(rects)):
            r = rects[i]
            ax.add_patch(
                plt.Rectangle((r[0], r[1]), r[2], r[3] ,
                    fill=False, edgecolor='red', linewidth=3.5))
            c = cas[i]
            ax.text(r[0], r[1] - 2,
                    '{:s} {:.3f}'.format(c[0], c[1]),
                    bbox=dict(facecolor='blue', alpha=0.5),
                    fontsize=14, color='white')
        plt.axis('off')
        plt.tight_layout()
        plt.draw()
        plt.show()
    
    
    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 [ResNet-101]',
                            choices=NETS.keys(), default='ResNet-101')
    
        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],
                                'rfcn_end2end', 'test_agnostic.prototxt')
        caffemodel = os.path.join(cfg.DATA_DIR, 'rfcn_models',
                                  NETS[args.demo_net][1])
    
        if not os.path.isfile(caffemodel):
            raise IOError(('{:s} not found.\n').format(caffemodel))
    
        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)
    
        im_names = ['000456.jpg', '000542.jpg', '001150.jpg',
                    '001763.jpg', '004545.jpg']
        for im_name in im_names:
            print '~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'
            print 'Demo for data/demo/{}'.format(im_name)
            demo(net, im_name)
    
    

    效果图如下:

    Demo

    如果编译CPU版本会出现下图的问题,可能是这一层需要nvcc进行编译,cpu版本无法生成该层。

    Error

    在测试的过程中,出现过放弃核心存储,out of memory的错误,这是因为显存不够修改下面的文件,将Test size从1000修改到600即可。

    /iib/fast_rcnn/config.py
    
    # Max pixel size of the longest side of a scaled input image
    __C.TEST.MAX_SIZE = 1000
    

    相关文章

      网友评论

        本文标题:R-FCN Python版本实现

        本文链接:https://www.haomeiwen.com/subject/nksenttx.html