R-FCN Python版本实现

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%。

Github:https://github.com/Orpine/py-R-FCN
Paper:https://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)

效果图如下:

R-FCN Python版本实现_第1张图片
Demo

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

R-FCN Python版本实现_第2张图片
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版本实现)