LightTrack复现

参考链接:

本文配置(笔记本):

  • 系统版本:Windows 10 企业版 1903
  • 显卡:GT940M
  • CPU:I5-4210M
  • 内存:12G
  • Anaconda版本:4.8.3
  • python版本:3.6.10
  • nvcc版本(cuda):10.0
  • torch版本:1.1.0
  • torchversion版本:0.3.0
  • TensorFlow版本:1.8.0
  • 其余软件版本详见项目源码下environment.yml文件

前置条件:本文默认已经安装AnacondaNVIDIA CUDA Toolkit

一、环境搭建

首先从GitHub上下载项目源码,根据项目的README,创建一个anaconda的虚拟环境(注意python选择3.6):

1
conda env create lighttrack

再根据项目源码下environment.yml文件在anaconda和python中手动添加各种包(尝试过直接使用conda env create -f environment.yml命令一键添加各种包,但是失败了,故改为手动)

  • 其中难免有失效的包,不用管。注意上述本文配置中的包即版本即可

  • TensorFlow现在可以直接在Anaconda NAVIGATOR中安装

  • Pytorch采用pip的方式安装,不推荐直接pip install torch

    • 官网找到torchtorchvision对应的版本

      • cu100:cuda10.0
      • torch-1.1.0 : torch 版本 1.1.0
      • cp36 : python 版本 3.6
      • win: Windows 系统
    • 用pip本地安装:

      1
      2
      pip install .\torch\torch-1.1.0-cp36-cp36m-win_amd64.whl
      pip install .\torch\torchvision-0.3.0-cp36-cp36m-win_amd64.whl

二、修改源码

环境搭建好后,安装README指示需要编译几个python库:

1
2
cd lighttrack/lib
python setup.py build_ext --inplace

此时会报各种错,这里提供我修改好的lighttrack/lib/setup.py文件,直接替换即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
# -*- coding: UTF-8 -*-
# --------------------------------------------------------
# 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.exe')
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')
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 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(
"utils.cython_nms",
["utils/nms.pyx"],
extra_compile_args={'gcc': ["-Wno-cpp", "-Wno-unused-function"]},
include_dirs = [numpy_include]
),
Extension(
"nms.cpu_nms",
["nms/cpu_nms.pyx"],
extra_compile_args={'gcc': ["-Wno-cpp", "-Wno-unused-function"]},
include_dirs = [numpy_include]
),
Extension('nms.gpu_nms',
['nms/nms_kernel.cu', 'nms/gpu_nms.cpp'],
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_35',
'--ptxas-options=-v',
'-c',
'--compiler-options',
'-fPIC']},
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},
)
  • 如果仍然报错,且是在CUDA = locate_cuda()该句报错,是因为没有设置好系统环境变量,推荐新增一个CUDAHOME变量,我这里是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.0,根据实际路径来即可。

接着下载权重文件并解压到lighttrack/lib处:

下载测试视频lighttrack/data/demo

最后,如果调用demo即可:

1
2
3
4
# 调用摄像头 按q退出
python demo_camera_mobile.py
# 直接读取刚刚的视频文件
python demo_video_mobile.py
  • 如果lighttrack\HPE\config.py文件创建文件make_dir(cfg.output_dir)报错,需要修改14行为:this_dir_name = cur_dir.split('\\')[-1]

  • 此时可能会遇到lighttrack\lib\nms\gpu_nms.cpp文件报错:__pyx_t_5numpy_int32_t*不能转成int*,修改该文件报错的哪一行(1616)为:

    1
    _nms((&(*__Pyx_BufPtrStrided1d(int *, __pyx_pybuffernd_keep.rcbuffer->pybuffer.buf, __pyx_t_10, __pyx_pybuffernd_keep.diminfo[0].strides))), (&__pyx_v_num_out), (&(*__Pyx_BufPtrStrided2d(__pyx_t_5numpy_float32_t *, __pyx_pybuffernd_sorted_dets.rcbuffer->pybuffer.buf, __pyx_t_12, __pyx_pybuffernd_sorted_dets.diminfo[0].strides, __pyx_t_13, __pyx_pybuffernd_sorted_dets.diminfo[1].strides))), __pyx_v_boxes_num, __pyx_v_boxes_dim, __pyx_t_14, __pyx_v_device_id);
  • 接着会报错找不到str2bool,只需修改lighttrack\graph\gcn_utils\io.pylighttrack\graph\gcn_utils\processor_siamese_gcn.pylighttrack\graph\gcn_utils\processor_base.py

    1
    2
    3
    4
    import torchlight
    from torchlight import str2bool
    from torchlight import DictAction
    from torchlight import import_class

    为:

    1
    2
    3
    4
    from torchlight.torchlight.io import str2bool
    from torchlight.torchlight.io import DictAction
    from torchlight.torchlight.io import import_class
    import torchlight.torchlight as torchlight

    即可

最后,整个修改后的工程放到了我的GitHub