因为要在安卓板上部署模型供安卓app调用,目前支持安卓调用这方面做得比较成熟的当然是tensorflow,将模型训练出来后转换成pb文件即可供安卓调用。
之前用于机器人上某种识别用途的模型出于jetson-nano板子的内存约束采用的是caffe版的faster-rcnn基于某backbone训练出来的小模型,才200多M大小,现在模型需要在安卓板上部署,于是改成tensorflow版的faster-rcnn基于比较小的VGG16来训练模型,选择使用的源码是https://github.com/smallcorgi/Faster-RCNN_TF,此源码有点老了,当时使用的是tensorflow1.2,于是到docker hub上拉取一个合适的tensorflow1.2-devel-gpu版的docker image(注意不要使用tensorflow1.2-gpu的docker image,因为里面安装的包和工具太少了,你会发现除了tensorflow外几乎常用的支持包和工具什么都没有!):
nohup docker pull tensorflow/tensorflow:1.2.0-devel-gpu &
如果使用无线网,不那么稳定经常中断的话,执行拉取命令时最好转入后台,因为这个下载的过程会很长。
下载完tensorflow1.2-devel-gpu的docker image,然后执行命令创建和运行容器:
sudo nvidia-docker run -it -v /home/xsrt/AI:/home --name tensorflow1.2.0-devel-gpu tensorflow/tensorflow:1.2.0-devel-gpu bash
进入容器后,先更新Ubuntu的源:
cd /etc/apt
mv sources.lsit sources.list.bak #需要时还可以把标准的Ubuntu源切换回来,有时切换一下源某些包能快速找到和下载
mv sources.list.d sources.list.d.old #很关键!!!不然卡住apt-get update,把不需要的原来有的nvidia等源不要包含在内
cp /home/sources.list . #这个sources.list里面是阿里云或者清华治之类的国内源,非必须
apt-get update
安装Fater-RCNN_TF所需的支持包(https://github.com/smallcorgi/Faster-RCNN_TF说的支持包只是其中三个核心的,但下面其他的支持包也是需要的,如果你环境中不存在运行时就会报错):
apt-get install cython
apt-get install python-opencv
pip install easydict
pip install Pillow
apt-get install python-tk
sudo apt-get install python-yaml
拉取源码:
git clone --recursive https://github.com/smallcorgi/Faster-RCNN_TF.git
编译Faster-RCNN_TF的源码:
export FRCN_ROOT=<Faster-RCNN_TF所在的路径>
cd $FRCN_ROOT/lib
make
在$FRCN_ROOT/data/下建立目录VOCdevkit2007并把VOC2007格式的数据集链接到这个目录下面(Faster-RCNN_TF/data/VOCdevkit2007/VOC2007/,下面是Annotations、ImageSets和JPEGImages),在data目录下还需建立个目录pretrain_model,从网上下载个VGG预训练模型文件VGG_imagenet.npy(方便起见,我把这个文件上传到VGG_imagenet.part1 VGG_imagenet.part2 VGG_imagenet.part3)放到这个目录下,
然后执行 mkdir -p experiment/logs,在experiment目录下手工建立目录logs,否则最后运行test_net.py时会报错:
grep: experiments/logs/faster_rcnn_end2end_VGG_.txt.2020-01-13_02-38-15: No such file or directory
并且根据你的识别类别做下列修改:
lib/datasets/pascal_voc2.py:
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'
'your_class')
lib/networks/VGGnet_test.py:
n_classes = 2 #num_of_your_classes +1
lib/networks/VGGnet_train.py:
n_classes = 2 #num_of_your_classes +1
然后训练:
cd $FRCN_ROOT
nohup ./experiments/scripts/faster_rcnn_end2end.sh gpu 1 VGG pascal_voc & #使用GPU,id为1
启动训练后会出错:
Traceback (most recent call last):
File "./tools/train_net.py", line 16, in <module>
from networks.factory import get_network
File "/root/Faster-RCNN_TF/tools/../lib/networks/__init__.py", line 8, in <module>
from .VGGnet_train import VGGnet_train
File "/root/Faster-RCNN_TF/tools/../lib/networks/VGGnet_train.py", line 2, in <module>
from networks.network import Network
File "/root/Faster-RCNN_TF/tools/../lib/networks/network.py", line 3, in <module>
import roi_pooling_layer.roi_pooling_op as roi_pool_op
File "/root/Faster-RCNN_TF/tools/../lib/roi_pooling_layer/roi_pooling_op.py", line 5, in <module>
_roi_pooling_module = tf.load_op_library(filename)
File "/usr/local/lib/python2.7/dist-packages/tensorflow/python/framework/load_library.py", line 64, in load_op_library
None, None, error_msg, error_code)
tensorflow.python.framework.errors_impl.NotFoundError: /root/Faster-RCNN_TF/tools/../lib/roi_pooling_layer/roi_pooling.so: undefined symbol: _ZN10tensorflow7strings6StrCatB5cxx11ERKNS0_8AlphaNumE
这里出错的原因是编译lib时需要加个参数,首先删除lib下已编译生成的so库文件和.o文件:
lib/roi_pooling_layer/roi_pooling.so
lib/roi_pooling_layer/roi_pooling_op.cu.o
lib/nms/cpu_nms.so
lib/nms/gpu_nms.so
lib/utils/cython_bbox.so
lib/utils/cython_nms.so
然后修改lib/make.sh:
if [ -d "$CUDA_PATH" ]; then
nvcc -std=c++11 -c -o roi_pooling_op.cu.o roi_pooling_op_gpu.cu.cc \
-I $TF_INC -D GOOGLE_CUDA=1 -x cu -Xcompiler -fPIC $CXXFLAGS \
-arch=sm_53
g++ -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0 -shared -o roi_pooling.so roi_pooling_op.cc \
roi_pooling_op.cu.o -I $TF_INC -D GOOGLE_CUDA=1 -fPIC $CXXFLAGS \
-lcudart -L $CUDA_PATH/lib64
有人说:
对于gcc/g++5.x 设置-D_GLIBCXX_USE_CXX11_ABI=1
对于gcc/g++4.x 设置-D_GLIBCXX_USE_CXX11_ABI=0
我看说反了,因为我的编译环境是g++5.4,使用-D_GLIBCXX_USE_CXX11_ABI=1编译后上面的错误继续存在,使用-D_GLIBCXX_USE_CXX11_ABI=0编译后错误就消失了。
修改make.sh时顺带把算力也改了,原来是-arch=sm_37,改成-arch=sm_53 (tensorflow1.2只支持到CUDA8,而CUDA8只支持算力到sm53,对于现在个人常用的2080卡对应的sm75不支持,会报错不认识这个architecture:
nvcc fatal : Value 'sm_75' is not defined for option 'gpu-architecture'
),另外,还需修改 lib/setup.py:
extra_compile_args={'gcc': ["-Wno-unused-function"],
'nvcc': ['-arch=sm_53', #原来是sm_35,改成sm_53
'--ptxas-options=-v',
'-c',
'--compiler-options',
"'-fPIC'"]},
做了上面的修改,然后在lib下再执行make。
然后启动训练,train_net.py执行完成在output/faster_rcnn_end2end/voc_2007_trainval/下最终生成文件VGGnet_fast_rcnn_iter_70000.ckpt.data-00000-of-00001、VGGnet_fast_rcnn_iter_70000.ckpt.index和VGGnet_fast_rcnn_iter_70000.ckpt.meta后执行test_net.py时会报错模型文件VGGnet_fast_rcnn_iter_70000.ckpt找不到,这是因为,log文件(例如Faster-RCNN_TF/experiments/logs/faster_rcnn_end2end_VGG_.txt.2019-10-13_06-41-26)里,输出的日志是:
Wrote snapshot to: /root/Faster-RCNN_TF/output/faster_rcnn_end2end/voc_2007_trainval/VGGnet_fast_rcnn_iter_70000.ckpt
而实际生成的文件却是:
/root/Faster-RCNN_TF/output/faster_rcnn_end2end/voc_2007_trainval/VGGnet_fast_rcnn_iter_70000.ckpt.data-00000-of-00001
在启动训练和测试的脚本Faster-RCNN_TF/experiments/scripts/faster_rcnn_end2end.sh里,是从log文件里找Wrote snapshot to:后面的内容作为NET_FINAL的值:
set +x
NET_FINAL=`grep -B 1 "done solving" ${LOG} | grep "Wrote snapshot" | awk '{print $4}'`
set -x
time python ./tools/test_net.py --device ${DEV} --device_id ${DEV_ID} \
--weights ${NET_FINAL} \
--imdb ${TEST_IMDB} \
--cfg experiments/cfgs/faster_rcnn_end2end.yml \
--network VGGnet_test \
${EXTRA_ARGS}
这样当然找不着模型文件,在RCNN_TF/output/faster_rcnn_end2end/voc_2007_trainval/下建个链接即可解决:
ln -s VGGnet_fast_rcnn_iter_70000.ckpt.data-00000-of-00001 VGGnet_fast_rcnn_iter_70000.ckpt
然后再运行test_net.py时,又会报错:
cudaCheckError() failed : invalid resource handle
这个错误是因为GPU卡是RTX2080TI,驱动是比较新的,和老旧的CUDA8根本不匹配,所以这个问题不好解决,不大可能为了凑合tensorflow1.2+CUDA8而把驱动安装成很老的版本,会导致服务器上其他很多模型跑不了,好在只是运行test_net时出错,因而修改了一下faster_rcnn_end2end.py,把运行test_net.py测试模型这部分注释掉,把运行test_net.p测试模型部分以及前面的初始化和参数解析部分摘出来单独存为一个test_faster_rcnn_end2end.py文件:
...
python ./tools/test_net.py --device ${DEV} --device_id ${DEV_ID} \
--weights ${NET_FINAL} \
--imdb ${TEST_IMDB} \
--cfg experiments/cfgs/faster_rcnn_end2end.yml \
--network VGGnet_test \
${EXTRA_ARGS}
然后改成cpu运行:
./experiments/scripts/test_faster_rcnn_end2end.sh cpu 0 VGG pascal_voc
运行测试可以较快完成,没有错误。