tensorflow版本的faster rcnn在windows系统下用cpu训练

源码地址:https://github.com/endernewton/tf-faster-rcnn

代码运行路径运行在没有中文的路径中,环境要求:win10+vs2015+python3.4+tensorflow

python所需第三方包:cythonopencv-pythoneasydict(版本最好为1.6)、scipy、pillow

所需环境(其中有关GPU环境所需的cuda和cudann可不用下载)、源码、第三方包下载链接:https://pan.baidu.com/s/1pcqHL4iNC1kVG3go1DSjHQ

一、训练模型

首先在cpu下完成训练就要把程序中用gpu的部分注释掉,具体需要注释的部分如下:

(1)tf-faster-rcnn-master/lib/model/config.py路径下USE_GPU_NMS 改为false:

(2)lib/model/nms_wrapper.py路径下,注释掉以下部分:

(3)lib/setup.py整个文件重新写一份,其中相应的gpu部分已经注释:

# --------------------------------------------------------
# Fast R-CNN
# Copyright (c) 2015 Microsoft
# Licensed under The MIT License [see LICENSE for details]
# Written by Ross Girshick
# --------------------------------------------------------

import os
from os.path import join as pjoin
import numpy as np
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext

def find_in_path(name, path):
    "Find a file in a search path"
    #adapted fom http://code.activestate.com/recipes/52224-find-a-file-given-a-search-path/
    for dir in path.split(os.pathsep):
        binpath = pjoin(dir, name)
        if os.path.exists(binpath):
            return os.path.abspath(binpath)
    return None

def locate_cuda():
    """Locate the CUDA environment on the system

    Returns a dict with keys 'home', 'nvcc', 'include', and 'lib64'
    and values giving the absolute path to each directory.

    Starts by looking for the CUDAHOME env variable. If not found, everything
    is based on finding 'nvcc' in the PATH.
    """

    # first check if the CUDAHOME env variable is in use
    if 'CUDAHOME' in os.environ:
        home = os.environ['CUDAHOME']
        nvcc = pjoin(home, 'bin', 'nvcc')
    else:
        # otherwise, search the PATH for NVCC
        nvcc = find_in_path('nvcc.exe', os.environ['PATH'])
        if nvcc is None:
            # raise EnvironmentError('The nvcc binary could not be '
            #     'located in your $PATH. Either add it to your path, or set $CUDAHOME')
            return None

        home = os.path.dirname(os.path.dirname(nvcc))

    cudaconfig = {'home':home, 'nvcc':nvcc,
                  'include': pjoin(home, 'include'),
                  'lib64': pjoin(home, 'lib', 'x64')}
    for k, v in iter(cudaconfig.items()):
        if not os.path.exists(v):
            # raise EnvironmentError('The CUDA %s path could not be located in %s' % (k, v))
            return None
    return cudaconfig
CUDA = locate_cuda()

# Obtain the numpy include directory.  This logic works across numpy versions.
try:
    numpy_include = np.get_include()
except AttributeError:
    numpy_include = np.get_numpy_include()

def customize_compiler_for_nvcc(self):
    # _msvccompiler.py imports:
    import os
    import shutil
    import stat
    import subprocess
    import winreg

    from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
                                 CompileError, LibError, LinkError
    from distutils.ccompiler import CCompiler, gen_lib_options
    from distutils import log
    from distutils.util import get_platform

    from itertools import count

    super = self.compile
    self.src_extensions.append('.cu')
    # find python include
    import sys
    py_dir = sys.executable.replace('\\', '/').split('/')[:-1]
    py_include = pjoin('/'.join(py_dir), 'include')

    # override method in _msvccompiler.py, starts from line 340
    def compile(sources,
                output_dir=None, macros=None, include_dirs=None, debug=0,
                extra_preargs=None, extra_postargs=None, depends=None):

        if not self.initialized:
            self.initialize()
        compile_info = self._setup_compile(output_dir, macros, include_dirs,
                                           sources, depends, extra_postargs)
        macros, objects, extra_postargs, pp_opts, build = compile_info

        compile_opts = extra_preargs or []
        compile_opts.append('/c')
        if debug:
            compile_opts.extend(self.compile_options_debug)
        else:
            compile_opts.extend(self.compile_options)

        add_cpp_opts = False

        for obj in objects:
            try:
                src, ext = build[obj]
            except KeyError:
                continue
            if debug:
                # pass the full pathname to MSVC in debug mode,
                # this allows the debugger to find the source file
                # without asking the user to browse for it
                src = os.path.abspath(src)

            if ext in self._c_extensions:
                input_opt = "/Tc" + src
            elif ext in self._cpp_extensions:
                input_opt = "/Tp" + src
                add_cpp_opts = True
            elif ext in self._rc_extensions:
                # compile .RC to .RES file
                input_opt = src
                output_opt = "/fo" + obj
                try:
                    self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
                except DistutilsExecError as msg:
                    raise CompileError(msg)
                continue
            elif ext in self._mc_extensions:
                # Compile .MC to .RC file to .RES file.
                #   * '-h dir' specifies the directory for the
                #     generated include file
                #   * '-r dir' specifies the target directory of the
                #     generated RC file and the binary message resource
                #     it includes
                #
                # For now (since there are no options to change this),
                # we use the source-directory for the include file and
                # the build directory for the RC file and message
                # resources. This works at least for win32all.
                h_dir = os.path.dirname(src)
                rc_dir = os.path.dirname(obj)
                try:
                    # first compile .MC to .RC and .H file
                    self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
                    base, _ = os.path.splitext(os.path.basename(src))
                    rc_file = os.path.join(rc_dir, base + '.rc')
                    # then compile .RC to .RES file
                    self.spawn([self.rc, "/fo" + obj, rc_file])

                except DistutilsExecError as msg:
                    raise CompileError(msg)
                continue
            elif ext == '.cu':
                # a trigger for cu compile
                try:
                    # use the cuda for .cu files
                    # self.set_executable('compiler_so', CUDA['nvcc'])
                    # use only a subset of the extra_postargs, which are 1-1 translated
                    # from the extra_compile_args in the Extension class
                    postargs = extra_postargs['nvcc']
                    arg = [CUDA['nvcc']] + sources + ['-odir', pjoin(output_dir, 'nms')]
                    for include_dir in include_dirs:
                        arg.append('-I')
                        arg.append(include_dir)
                    arg += ['-I', py_include]
                    # arg += ['-lib', CUDA['lib64']]
                    arg += ['-Xcompiler', '/EHsc,/W3,/nologo,/Ox,/MD']
                    arg += postargs
                    self.spawn(arg)
                    continue
                except DistutilsExecError as msg:
                    # raise CompileError(msg)
                    continue
            else:
                # how to handle this file?
                raise CompileError("Don't know how to compile {} to {}"
                                   .format(src, obj))

            args = [self.cc] + compile_opts + pp_opts
            if add_cpp_opts:
                args.append('/EHsc')
            args.append(input_opt)
            args.append("/Fo" + obj)
            args.extend(extra_postargs)

            try:
                self.spawn(args)
            except DistutilsExecError as msg:
                raise CompileError(msg)

        return objects

    self.compile = compile

# run the customize_compiler
class custom_build_ext(build_ext):
    def build_extensions(self):
        customize_compiler_for_nvcc(self.compiler)
        build_ext.build_extensions(self)

ext_modules = [
    Extension(
        "utils.cython_bbox",
        ["utils/bbox.pyx"],
        extra_compile_args={'gcc': ["-Wno-cpp", "-Wno-unused-function"]},
        include_dirs = [numpy_include]
    ),
    Extension(
        "nms.cpu_nms",
        ["nms/cpu_nms.pyx"],
        include_dirs = [numpy_include]
    ),
    # Extension('nms.gpu_nms',
    #     ['nms/nms_kernel.cu', 'nms/gpu_nms.pyx'],
    #     library_dirs=[CUDA['lib64']],
    #     libraries=['cudart'],
    #     language='c++',
    #     # this syntax is specific to this build system
    #     # we're only going to use certain compiler args with nvcc and not with gcc
    #     # the implementation of this trick is in customize_compiler() below
    #     extra_compile_args={'gcc': ["-Wno-unused-function"],
    #                         'nvcc': ['-arch=sm_52',
    #                                  '--ptxas-options=-v',
    #                                  '-c']},
    #     include_dirs = [numpy_include, CUDA['include']]
    # )
]

setup(
    name='tf_faster_rcnn',
    ext_modules=ext_modules,
    # inject our custom trigger
    cmdclass={'build_ext': custom_build_ext},
)

(4)

(a)文件lib/nms/cpu_nms.pyx:
改变第25行:cdef np.ndarray[np.int_t, ndim=1] order = scores.argsort()[::-1]

为:cdef np.ndarray[np.int64_t, ndim=1] order = scores.argsort()[::-1]

(b)文件lib/nms/gpu_nms.pyx:
改变25行: cdef np.ndarray[np.int_t, ndim=1] \

为:cdef np.ndarray[np.int64_t, ndim=1] \

(c)文件lib/datasets/pascal_voc.py:

改变226行:'{:s}.xml')

为: '{0:s}.xml')

(d)文件 lib/datasets/voc_eval.py:

改变121行:with open(cachefile, 'w') as f:

为:with open(cachefile, 'wb') as f:

(5)转到 lib 目录下, 终端运行 python setup.py build_ext

这一步如果遇到一些错误,建议删除所有的.c和.cpp文件,(lib/nms/cpu_nms.c, lib/nms/gpu_nms.cpp, lib/utils/bbox.c)

注:如果用gpu训练的话,可能会出现错误:

这种情况下,就前往nms/gpu_nms.cpp文件的2152行下,将:

_nms((&(*__Pyx_BufPtrStrided1d(__pyx_t_5numpy_int32_t *, __pyx_pybuffernd_keep.rcbuffer->......

中的__pyx_t_5numpy_int32_t *”转换成 int *,即:

_nms((&(*__Pyx_BufPtrStrided1d(int *, __pyx_pybuffernd_keep.rcbuffer->

修改之后,在运行一次 python setup.py build_ext. 就OK了

(6)训练模型:

python setup.py build_ext命令执行完后会在lib/build目录下生成如下文件,将nms文件夹里面的两个文件移动到lib/nms文件夹中,utils文件夹中的一个文件移动到lib/utils文件夹下

至此,就可以正式开始训练模型。因为GitHub原作者是在ubuntu系统下进行训练的,所以用./experiments/scripts/train_faster_rcnn.sh 0 pascal_voc vgg16就可以进行,而.sh文件不能用在windows平台上(本人对ubuntu一概不知,所以也不会弄),但是训练的过程它是调用的trainval_net.py开始训练的,所以我就把trainval_net.py进行修改,代码如下:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import _init_paths
from model.train_val import get_training_roidb, train_net
from model.config import cfg, cfg_from_file, cfg_from_list, get_output_dir, get_output_tb_dir
from datasets.factory import get_imdb
import datasets.imdb
import argparse
import pprint
import numpy as np
import sys

import tensorflow as tf
from nets.vgg16 import vgg16
from nets.resnet_v1 import resnetv1


class args:
    """
    Parse input arguments
    """
    cfg_file = '../experiments/cfgs/vgg16.yml'
    weight = '../data/imagenet_weights/vgg16.ckpt'
    imdb_name = 'voc_2007_trainval'
    imdbval_name = 'voc_2007_test'
    max_iters = 100000
    tag = None
    net = 'vgg16'
    set_cfgs = ['ANCHOR_SCALES', '[8,16,32]', 'ANCHOR_RATIOS', '[0.5,1,2]', 'TRAIN.STEPSIZE', '[50000]']


def combined_roidb(imdb_names):
    """
    Combine multiple roidbs
    """

    def get_roidb(imdb_name):
        imdb = get_imdb(imdb_name)
        print('Loaded dataset `{:s}` for training'.format(imdb.name))
        imdb.set_proposal_method(cfg.TRAIN.PROPOSAL_METHOD)
        print('Set proposal method: {:s}'.format(cfg.TRAIN.PROPOSAL_METHOD))
        roidb = get_training_roidb(imdb)
        return roidb

    roidbs = [get_roidb(s) for s in imdb_names.split('+')]
    roidb = roidbs[0]
    if len(roidbs) > 1:
        for r in roidbs[1:]:
            roidb.extend(r)
        tmp = get_imdb(imdb_names.split('+')[1])
        imdb = datasets.imdb.imdb(imdb_names, tmp.classes)
    else:
        imdb = get_imdb(imdb_names)
    return imdb, roidb


if __name__ == '__main__':
    #  args = parse_args()
    print('Called with args:')
    if args.cfg_file is not None:
        cfg_from_file(args.cfg_file)
    if args.set_cfgs is not None:
        cfg_from_list(args.set_cfgs)
    print('Using config:')
    pprint.pprint(cfg)
    np.random.seed(cfg.RNG_SEED)
    # train set
    imdb, roidb = combined_roidb(args.imdb_name)
    print('{:d} roidb entries'.format(len(roidb)))
    # output directory where the models are saved
    output_dir = get_output_dir(imdb, args.tag)
    print('Output will be saved to `{:s}`'.format(output_dir))

    # tensorboard directory where the summaries are saved during training
    tb_dir = get_output_tb_dir(imdb, args.tag)
    print('TensorFlow summaries will be saved to `{:s}`'.format(tb_dir))

    # also add the validation set, but with no flipping images
    orgflip = cfg.TRAIN.USE_FLIPPED
    cfg.TRAIN.USE_FLIPPED = False
    _, valroidb = combined_roidb(args.imdbval_name)
    print('{:d} validation roidb entries'.format(len(valroidb)))
    cfg.TRAIN.USE_FLIPPED = orgflip

    # load network
    if args.net == 'vgg16':
        net = vgg16()
    elif args.net == 'res50':
        net = resnetv1(num_layers=50)
    elif args.net == 'res101':
        net = resnetv1(num_layers=101)
    elif args.net == 'res152':
        net = resnetv1(num_layers=152)
    elif args.net == 'mobile':
        net = mobilenetv1()
    else:
        raise NotImplementedError
    train_net(net, imdb, roidb, valroidb, output_dir, tb_dir,
              pretrained_model=args.weight,
              max_iters=args.max_iters)

原来的trainval_net.py文件中的args是通过命令行来传参的,这里我设置了一个args类对所需的变量进行赋值。

之后运行trainval_net.py就可以训练网络模型~~~

二、测试模型

对./tools/test_net.py进行修改,类似于在trainval_net.py文件中的修改,将原本需要通过命令行传递的参数写一个args类对所需的变量进行赋值

class args:
    """
    Parse input arguments
    """
    cfg_file = '../experiments/cfgs/vgg16.yml
    //模型存放的路径
    model = 'E:\workspace\python\zj/tf-faster-rcnn-master(endernewton)__gpu_v6\output(64,128)/vgg16/vgg16_faster_rcnn_iter_15000.ckpt'
    # net = 'res101'
    net = 'vgg16'
    imdb_name = 'voc_2007_test'
    comp_mode =True
    TRAIN_IMDB="voc_2007_trainval"
    TEST_IMDB="voc_2007_test"
    ITERS=7000
    max_per_image = 100
    tag = None
    set_cfgs = ['ANCHOR_SCALES', '[8,16,32]', 'ANCHOR_RATIOS', '[0.5,1,2]']

修改完之后,直接运行test_net.py对训练好的模型进行测试

三、demo测试

同样写一个args类进行传参,

class args:
    cfg_file = '../experiments/cfgs/vgg16.yml'
    model = 'E:\\workspace\\python\zj/tf-faster-rcnn-master(endernewton)__gpu_v6\\tf-faster-rcnn-master\\output\\vgg16\\voc_2007_trainval\\default\\vgg16_faster_rcnn_iter_65000.ckpt'
    imdb_name = 'voc_2007_test'
    comp_mode =True
    TRAIN_IMDB="voc_2007_trainval"
    TEST_IMDB="voc_2007_test"
    ITERS=7000
    max_per_image = 100
    tag = None
    # net = 'res101'
    net = 'vgg16'
    set_cfgs = ['ANCHOR_SCALES',  '[8,16,32]', 'ANCHOR_RATIOS', '[0.5,1,2]']

demo.py默认从data/demo路径下读取图片进行检测,并将检测的结果可视化出来

发布了72 篇原创文章 · 获赞 23 · 访问量 4万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览