本文記錄了在ubuntu16.04下使用py-faster-rcnn來訓(xùn)練自己的數(shù)據(jù)集的大致過程。
在此之前,已經(jīng)成功配置過了caffe-gpu,使用的顯卡是GTX1080ti,安裝的cuda8.0.61+cudnn v5.1,caffe-gpu的配置過程可以參考:Ubuntu16.04配置caffe-GPU環(huán)境。
第一步:制作自己的數(shù)據(jù)集
首先,為了方便,可以將自己的訓(xùn)練圖像名稱改成PASCAL VOC格式,比如我自己的數(shù)據(jù)集共有1150張訓(xùn)練圖像,寫一個簡單的python腳本將其重命名為00001.jpg~001150.jpg。
數(shù)據(jù)集的制作工具:labelImg。安裝和使用方法都很簡單,這里不再贅述。
第二步:clone py-faster-rcnn源代碼
在bash中執(zhí)行
git clone --recursive https://github.com/rbgirshick/py-faster-rcnn.git
將得到一個py-faster-rcnn文件夾。
下載后按照py-faster-rcnn中README.md中的指導(dǎo),依次編譯/py-faster-rcnn/lib/文件夾和/py-faster-rcnn/caffe-fast-rcnn/文件夾。
在編譯/py-faster-rcnn/caffe-fast-rcnn/文件夾時出現(xiàn)了以下錯誤:
ys@ysubuntu:~/pycaffe/py-faster-rcnn/caffe-fast-rcnn$ make -j8 && make pycaffe
PROTOC src/caffe/proto/caffe.proto
CXX src/caffe/parallel.cpp
CXX src/caffe/internal_thread.cpp
...
In file included from ./include/caffe/util/device_alternate.hpp:40:0,
from ./include/caffe/common.hpp:19,
from ./include/caffe/blob.hpp:8,
from ./include/caffe/net.hpp:10,
from ./include/caffe/solver.hpp:7,
from ./include/caffe/sgd_solvers.hpp:7,
from src/caffe/solvers/nesterov_solver.cpp:3:
./include/caffe/util/cudnn.hpp: In function ‘void caffe::cudnn::createPoolingDesc(cudnnPoolingStruct**, caffe::PoolingParameter_PoolMethod, cudnnPoolingMode_t*, int, int, int, int, int, int)’:
./include/caffe/util/cudnn.hpp:127:41: error: too few arguments to function ‘cudnnStatus_t cudnnSetPooling2dDescriptor(cudnnPoolingDescriptor_t, cudnnPoolingMode_t, cudnnNanPropagation_t, int, int, int, int, int, int)’
pad_h, pad_w, stride_h, stride_w));
^
./include/caffe/util/cudnn.hpp:15:28: note: in definition of macro ‘CUDNN_CHECK’
cudnnStatus_t status = condition; \
^
In file included from ./include/caffe/util/cudnn.hpp:5:0,
from ./include/caffe/util/device_alternate.hpp:40,
from ./include/caffe/common.hpp:19,
from ./include/caffe/blob.hpp:8,
from ./include/caffe/net.hpp:10,
from ./include/caffe/solver.hpp:7,
from ./include/caffe/sgd_solvers.hpp:7,
from src/caffe/solvers/nesterov_solver.cpp:3:
/usr/local/cuda/include/cudnn.h:803:27: note: declared here
cudnnStatus_t CUDNNWINAPI cudnnSetPooling2dDescriptor(
^
Makefile:563: recipe for target '.build_release/src/caffe/solvers/nesterov_solver.o' failed
make: *** [.build_release/src/caffe/solvers/nesterov_solver.o] Error 1
make: *** Waiting for unfinished jobs....
...
make: *** [.build_release/src/caffe/parallel.o] Error 1
ys@ysubuntu:~/pycaffe/py-faster-rcnn/caffe-fast-rcnn$ make clean
ys@ysubuntu:~/pycaffe/py-faster-rcnn/caffe-fast-rcnn$
錯誤的原因應(yīng)該是py-faster-rcnn中自帶的cudnn相關(guān)文件版本太老。
解決辦法參考:py-faster-rcnn安裝問題總結(jié)。也就是用最新下載的caffe源代碼中/caffe/include/和/caffe/src/下面所有和cudnn相關(guān)的.hpp文件和.cpp文件復(fù)制到/py-faster-rcnn/caffe-fast-rcnn/文件夾下,替換掉老版本的cudnn文件。
這樣就能順利編譯/py-faster-rcnn/caffe-fast-rcnn/文件夾了。
自己的數(shù)據(jù)集放在哪兒
為了盡量少改動代碼,最方便的方式是按照源代碼中的PASCAL VOC數(shù)據(jù)集的放置格式,即在.../py-faster-rcnn/data/文件夾下,新建一個名為VOCdevkit2007,然后,其子文件夾的目錄樹如下圖:

也就是在VOCdevkit2007下再建一個名為VOC2007的文件夾;然后在VOC2007下面分別建立3個文件夾:Annotations、ImageSets和JPEGImages。其中JPEGImages下面放的是訓(xùn)練集圖片:

Annotations下面放的是自己制作的訓(xùn)練集圖片對應(yīng)的.xml標簽文件:

ImageSets下面的目錄如下:

其下再建一個Main文件夾,在Main文件夾下面放trainval.txt文件,trainval.txt文件內(nèi)容是每張訓(xùn)練圖片名:

下載訓(xùn)練好的VGG16模型
參照py-faster-rcnn的使用說明,要訓(xùn)練模型需要下載一個訓(xùn)練好的VGG16模型用于遷移學(xué)習(xí)。在py-faster-rcnn/目錄下打開bash,執(zhí)行:
./data/scripts/fetch_imagenet_models.sh
或者直接在進入網(wǎng)址:https://dl.dropbox.com/s/gstw7122padlf0l/imagenet_models.tgz?dl=0下載預(yù)訓(xùn)練好的VGG16模型。
下載下來后,在/py-faster-rcnn/data/文件夾下新建一個imagenet_models文件夾,將VGG16模型放進去:

修改幾個地方來訓(xùn)練自己的數(shù)據(jù)集
修改train.prototxt和solver.prototxt
打開/py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_end2end/train.prototxt,使用編輯器的查找替換功能,將其中的數(shù)字21替換成你自己的數(shù)據(jù)集類別數(shù)+1,將數(shù)字84替換成你自己的(數(shù)據(jù)集類別數(shù)+1)*4,這個文件中共有3處21,一處84需要替換;
在/py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_end2end/solver.prototxt中,根據(jù)自己的實際情況修改,比如我只是的總訓(xùn)練迭代次數(shù)只設(shè)置了10000次,所以solver文件中,stepsize值我改成了6000。
修改pascal_voc.py
將/py-faster-rcnn/lib/datasets/pascal_voc.py中的約33行處的:
self._classes = ('__background__', # always index 0
'aeroplane', 'bicycle', 'bird', 'boat',
'bottle', 'bus', 'car', 'cat', 'chair',
'cow', 'diningtable', 'dog', 'horse',
'motorbike', 'person', 'pottedplant',
'sheep', 'sofa', 'train', 'tvmonitor')
改成自己的類別名稱。
修改train_net.py
在/py-faster-rcnn/tools/train_net.py中,可以為其中的命令行參數(shù)設(shè)置默認值,這樣就不用每次訓(xùn)練時都在命令行設(shè)置多個參數(shù)了,下面是我設(shè)置的默認值:
def parse_args():
"""
Parse input arguments
"""
parser = argparse.ArgumentParser(description='Train a Fast R-CNN network')
parser.add_argument('--gpu', dest='gpu_id',
help='GPU device id to use [0]',
default=0, type=int)
parser.add_argument('--solver', dest='solver',
help='solver prototxt',
default='models/pascal_voc/VGG16/faster_rcnn_end2end/solver.prototxt', type=str)
parser.add_argument('--iters', dest='max_iters',
help='number of iterations to train',
default=10000, type=int)
parser.add_argument('--weights', dest='pretrained_model',
help='initialize with pretrained model weights',
default='data/imagenet_models/VGG16.v2.caffemodel', type=str)
parser.add_argument('--cfg', dest='cfg_file',
help='optional config file',
default='experiments/cfgs/faster_rcnn_end2end.yml', type=str)
parser.add_argument('--imdb', dest='imdb_name',
help='dataset to train on',
default='voc_2007_trainval', type=str)
parser.add_argument('--rand', dest='randomize',
help='randomize (do not use a fixed seed)',
action='store_true')
parser.add_argument('--set', dest='set_cfgs',
help='set config keys', default=None,
nargs=argparse.REMAINDER)
if len(sys.argv) == 1:
parser.print_help()
sys.exit(1)
args = parser.parse_args()
return args
另外可能需要修改的是/py-faster-rcnn/lib/fast_rcnn/config.py中的__C.TRAIN.SNAPSHOT_ITERS參數(shù),它確定了你的模型每訓(xùn)練多少次保存一次快照,源碼設(shè)置的是10000,根據(jù)自己設(shè)置的最大迭代次數(shù)來合理修改(它的值當(dāng)然不能大于最大迭代次數(shù),不然訓(xùn)練了半天一個模型都沒保存)。
訓(xùn)練模型
以上準備工作完成后,在/py-faster-rcnn/目錄下打開bash,執(zhí)行:
python ./tools/train_net.py --gpu 0
開始模型訓(xùn)練。
可能會遇到這個問題:
Traceback (most recent call last):
File "./tools/train_net.py", line 112, in <module>
max_iters=args.max_iters)
File "/home/ys/pycaffe/py-faster-rcnn/tools/../lib/fast_rcnn/train.py", line 157, in train_net
pretrained_model=pretrained_model)
File "/home/ys/pycaffe/py-faster-rcnn/tools/../lib/fast_rcnn/train.py", line 51, in __init__
pb2.text_format.Merge(f.read(), self.solver_param)
AttributeError: 'module' object has no attribute 'text_format'
解決辦法參考:py-faster-rcnn安裝問題總結(jié)。
還可能會遇到這個問題:
Traceback (most recent call last):
File "./tools/train_net.py", line 112, in <module>
max_iters=args.max_iters)
File "/home/ys/pycaffe/py-faster-rcnn/tools/../lib/fast_rcnn/train.py", line 161, in train_net
model_paths = sw.train_model(max_iters)
File "/home/ys/pycaffe/py-faster-rcnn/tools/../lib/fast_rcnn/train.py", line 102, in train_model
self.solver.step(1)
File "/home/ys/pycaffe/py-faster-rcnn/tools/../lib/rpn/proposal_target_layer.py", line 66, in forward
rois_per_image, self._num_classes)
File "/home/ys/pycaffe/py-faster-rcnn/tools/../lib/rpn/proposal_target_layer.py", line 191, in _sample_rois
_get_bbox_regression_labels(bbox_target_data, num_classes)
File "/home/ys/pycaffe/py-faster-rcnn/tools/../lib/rpn/proposal_target_layer.py", line 127, in _get_bbox_regression_labels
bbox_targets[ind, start:end] = bbox_target_data[ind, 1:]
TypeError: slice indices must be integers or None or have an __index__ method
解決辦法參考這里。
出錯原因:

可能是源代碼發(fā)布的時候,numpy 是支持浮點數(shù)作為索引的,但是在 numpy1.12.0 之后,numpy 只能用整數(shù)作為索引。所以,解決辦法有兩種:
第一種是卸載當(dāng)前的 numpy,安裝回以前的 1.11.2 版本,但是同時安裝的 opencv 版本也得退回老版本,因為新版本的 opencv3.1 依賴于新版本的 numpy,相同的依賴問題還有matplotlib。因此的重裝回 openCV2.4.13, matplotlib1.5.1,當(dāng)然這種辦法比較麻煩;
第二種辦法是找到使用浮點數(shù)作為 numpy 索引的相關(guān)代碼,將其強制轉(zhuǎn)換為 int 型:

再次運行,模型就能順利訓(xùn)練了。
測試模型
修改test.prototxt
打開/py-faster-rcnn/models/pascal_voc/VGG16/faster_rcnn_end2end/test.prototxt,使用編輯器的查找替換功能,將其中的數(shù)字21替換成你自己的數(shù)據(jù)集類別數(shù)+1,將數(shù)字84替換成你自己的(數(shù)據(jù)集類別數(shù)+1)*4,這個文件中共有1處21,一處84需要替換;
修改demo.py
訓(xùn)練得到的模型在這里:

將其復(fù)制到/py-faster-rcnn/data/faster_rcnn_models/目錄下。
然后打開demo.py,將
CLASSES = ('__background__',
'aeroplane', 'bicycle', 'bird', 'boat',
'bottle', 'bus', 'car', 'cat', 'chair',
'cow', 'diningtable', 'dog', 'horse',
'motorbike', 'person', 'pottedplant',
'sheep', 'sofa', 'train', 'tvmonitor')
改成自己的標簽,將
NETS = {'vgg16': ('VGG16',
'VGG16_faster_rcnn_final.caffemodel'),
中的模型改成自己訓(xùn)練保存的模型。比如我修改的內(nèi)容:
CLASSES = ('__background__', 'type1', 'type2', 'type3', 'type4', 'type5')
NETS = {'vgg16': ('VGG16',
'vgg16_faster_rcnn_iter_10000.caffemodel'),
將
prototxt = os.path.join(cfg.MODELS_DIR, NETS[args.demo_net][0],
'faster_rcnn_alt_opt', 'faster_rcnn_test.pt')
改成
prototxt = os.path.join(cfg.MODELS_DIR, NETS[args.demo_net][0],
'faster_rcnn_end2end', 'test.prototxt')
將
im_names = ['000456.jpg', '000542.jpg', '001150.jpg',
'001763.jpg', '004545.jpg']
列表中的圖片名改成自己要測試的圖片名稱,當(dāng)然首先需要將相應(yīng)的圖片復(fù)制到/py-faster-rcnn/data/demo/目錄下。
修改完成,在/py-faster-rcnn/目錄下打開bash,執(zhí)行
python ./tools/demo.py
沒問題的話,就能順利看到測試結(jié)果。