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)
效果图如下:
如果编译CPU版本会出现下图的问题,可能是这一层需要nvcc进行编译,cpu版本无法生成该层。
在测试的过程中,出现过放弃核心存储,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