前沿科技探索家 · 2021年07月22日

如何在Jetson nano上同时编译TensorRT与Paddle Lite框架

我从上学期开始逐渐接触飞桨深度学习框架,当时的飞桨逐步为广大开发者熟知。半年过去,生态不完善不再是扣在飞桨框架上的一顶帽子。如果你仍怀偏见,那么建议从现在开始深入地了解和使用它。

由于参加的百度人工智能创意赛的算法组要求了EasyDL的使用,所以我需要在嵌入式硬件上搭建Paddle框架,才能部署队友训练好的模型。目前可以实现加速模型推理的方式多种多样,但从通用性和部署简易性上讲,我认为使用低功耗GPU进行加速的Jetson系列相对更好。同时,飞桨对该系列的硬件支持较好:一方面可以通过百度针对终端发布的轻量化推理引擎PaddleLite进行部署,同时使用模型量化等操作加速推理;另一方面可以使用飞桨原生推理库Paddle Inference,通过调用Paddle-TensorRT接口,充分地利用Nvidia的软硬件资源。

考虑到比赛中模型改进的可能,需要建立一个更有普适性的部署环境,因此选择了第二种方案。

最终,在搜集了相关文档后,决定通过源码编译的方式在Jetson nano上安装Paddle框架。因为已有的教程都没有提及TensorRT的功能如何配置,我也在尝试中找到了一种合理的配置方法。本教程就在不断的失败和尝试中诞生,希望可以为各位开发者扫清配置Paddle环境的障碍。

第一部分:编译时的环境

首先确认Jetson nano环境,这里建议初学者尽量不选择最新的Jetpack。略低的版本受支持情况更好,同时有更多针对Bug的解决方案。我使用的版本如下(镜像来自Nvidia官网):

JetPack4.3  
Found Paddle host system: ubuntu, version: 18.04.3  
-- Found Paddle host system's CPU: 4 cores  
-- CXX compiler: /usr/bin/c++, version: GNU 7.5.0  
-- C compiler: /usr/bin/cc, version: GNU 7.5.0  
第二部分:编译前的准备工作

这部分包括依赖的安装、以及对系统的设置来保证编译过程的顺利进行。同时修改和打包TensorRT的库文件,为后续编译做准备。

安装所需的依赖:

sudo pip install virtualenv  #虚拟环境的依赖  
sudo apt-get install python3.6-dev liblapack-dev gfortran libfreetype6-dev libpng-dev libjpeg-dev zlib1g-dev patchelf python3-opencv  

对nano的设置:

打开性能模式加快编译速度;受制于nano硬件资源,需要增加swap空间防止编译中内存不足的情况发生;同时,需要修改Linux系统对同时打开文件的数量限制。

#打开性能模式  
sudo nvpmodel -m 0 && sudo jetson_clocks   

#增加swap空间,防止爆内存  
swapoff -a  
sudo fallocate -l 15G /swapfile  
sudo chmod 600 /var/swapfile  
sudo mkswap /swapfile  
sudo swapon /swapfile  
swapon -a  
sudo swapon –show #用来修改结果  

#最大的文件打开数量  
ulimit -n 2048   

上方对Jetson nano的设置务必要进行,swap空间的大小可以根据自己存储卡的大小设置,建议设置8G及以上的swap空间。

更改TensorRT相关库文件:在NvInferRuntime.h中class IPluginFactory和class IGpuAllocator里分别添加虚析构函数。

virtual ~IPluginFactory() {};  
virtual ~IGpuAllocator() {};  

修改protected: ~IOptimizationProfile() noexcept = default为:

virtual ~IOptimizationProfile() noexcept = default;  

之后的编译过程中,如果仍报没有虚析构函数的问题时,改法都是找到缺少的位置添加类的虚构函数。

整理TensorRT库文件:

我从官方文档以及提的issue找出的一种方法,即通过模仿x86_64上的TensorRT环境,来适应cmake文件的编译命令。Nvidia官方的TensorRT库呈现以下结构:

─include  
│      NvCaffeParser.h  
│      NvInfer.h  
│      NvInferPlugin.h  
│      NvOnnxConfig.h  
│      NvOnnxParser.h  
│      NvUffParser.h  
│      NvUtils.h  
│  
└─lib  
        libnvcaffe_parser.a  
        libnvcaffe_parser.so  
        libnvcaffe_parser.so.4  
        libnvcaffe_parser.so.4.1.0  
        libnvinfer.a  
        libnvinfer.so  
        libnvinfer.so.4  
        libnvinfer.so.4.1.0  
        libnvinfer_plugin.a  
        libnvinfer_plugin.so  
        libnvinfer_plugin.so.4  
        libnvinfer_plugin.so.4.1.0  
        libnvparsers.a  
        libnvparsers.so  
        libnvparsers.so.4  
        libnvparsers.so.4.1.0  

因为编译命令通过指定TensorRT_ROOT的方式找到include和lib中的相关文件。因此需要手动在nano的usr/文件夹中找到上述文件并整理成这种形式。个人的Jetpack 4.3 中库文件分别在在/usr/lib/aarch64-linux-gnu 和 /usr/include/aarch64-linux-gnu。由于镜像中TensorRT的库文件的位置分散在两个不同路径,不建议修改cmake文件来找相应库文件。

第三部分:编译流程
第一步:建立安装Paddle的虚拟python环境

因为JetPack4.3的nano自带相应的cv2模块,不需要再安装,只需链接即可。因此我使用的是方便找到文件夹的venv工具去创建虚拟环境,方便后续链接cv2库。创建虚拟python环境:

python3 -m venv name-of-env #在一个你可以记住的文件夹创建  

链接cv2模块:这部分内容需要根据个人的配置修改。链接的前半部分是本机cv2,后面是要链接到的虚拟环境cv2。

ln -s /usr/lib/python3.6/dist-packages/cv2/python-3.6/cv2.cpython-36m-aarch64-linux-gnu.so path-to-venv/name-of-venv/lib/python3.6/site-packages/cv2.so  

使TensorRT对虚拟环境python可见。如果初次使用,需要配置CUDA环境变量。

# 添加CUDA环境变量  
export CUDA_HOME=/usr/local/cuda  
export PATH=$CUDA_HOME/bin:$PATH  
export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH  
source ~/.bashrc  

测试cuda是否可见:

nvcc –version  

如果是如下提示,那么可以继续接下来的步骤。

nvcc: NVIDIA (R) Cuda compiler driver  
Copyright (c) 2005-2018 NVIDIA Corporation  
Built on ...  
Cuda compilation tools, release 10.0, Vxxxxx  

为了使Jetpack中的TensorRT对虚拟环境的python可见,需要在命令行中运行:

export PYTHONPATH=/usr/lib/python3.6/dist-packages:$PYTHONPATH  
source ~/.bashrc

进入虚拟环境并测试cv2,paddle_env为虚拟python环境的文件夹名。用下方命令进入虚拟环境,成功后会在终端中出现(paddle) root@ubuntu:*的提示。

source paddle_env/bin/activate

测试cv2和tensorrt

#测试cv2和tensorrt  
python   
import cv2  
import tensorrt  

以上没有报错方可继续。

第二步:安装必要的包

首先需要在虚拟环境中安装不包括在requirements.txt但又是必要的依赖:(依赖版本没有要求,测试中没有遇到不兼容的情况)

pip install cython wheel numpy

然后克隆Paddle的Github

git clone https://github.com/paddlepaddle/paddle

进入克隆的Paddle文件夹,安装其他依赖:

cd Paddle
pip install -r python/requirements.txt
第三步:选择版本以及编译安装NCCL

查看可用的版本:

git tag

切换版本:我使用的是2.0.0,不是稳定的版本。不选择1.8.x版本的原因是在尝试中发现该系列版本都会出现报缺少cpuid.h文件的错误,该问题已经在Paddle最新版本修复。

git checkout v2.0.0-alpha0

安装NCCL依赖,此过程可能持续近1h。

git clone https://github.com/NVIDIA/nccl.git  
make -j4  
make install  
第四步:配置cmake并开始编译Paddle

首先创建并进入build文件夹

mkdir build  
cd build/  

Cmake设置:

之前的准备步骤中我们已经将Paddle编译需要的TensorRT库整理成了适应cmake文件的形式,之后只需要指定TensorRT库的位置即可。接下来的cmake命令指定了编译结果所支持的功能。其他配置可以参考Paddle Inference文档中源码编译的部分。

-DWITH_PYTHON=ON使编译结果内嵌python解释器并编译whl,-DTENSORRT_ROOT指定TensorRT库的路径,-DCUDA_ARCH_NAME=Auto指定编译结果只适应当前的GPU架构,可以节省编译时间。

cmake .. \  
          -DWITH_CONTRIB=OFF \  
          -DWITH_MKL=OFF  \  
          -DWITH_MKLDNN=OFF \  
          -DWITH_TESTING=OFF \  
          -DCMAKE_BUILD_TYPE=Release \  
          -DON_INFER=ON \  
          -DWITH_PYTHON=ON \   
          -DWITH_XBYAK=OFF  \  
          -DWITH_NV_JETSON=ON \    
          -DPY_VERSION=3.6 \  
          -DTENSORRT_ROOT=/home/dlinano/Paddle/TensorRT \   
          -DCUDA_ARCH_NAME=Auto   

开始编译(过程很漫长):

#使用全部核心
make -j4  
# 生成预测lib
make inference_lib_dist   


#安装编译好的paddlepaddle-gpu的whl  
pip install -U python/dist/*.whl #还是在build文件夹  

第五步:使用python预测接口运行Paddle-Inference-Demo中的yolov3例子

克隆并进入目标文件夹:

git clone https://github.com/PaddlePaddle/Paddle-Inference-Demo.git  
cd Paddle-Inference-Demo/python/yolov3 

运行demo前,需要下载GitHub中提供的测试图片,放入yolov3文件夹。同时也需要下载提供的训练好的模型,放入创建的yolov3_infer文件夹。最终文件结构如下:

yolov3  
    │  infer_yolov3.py  
    │  kite.jpg  
    │  README.md  
    │  utils.py  
    │  
    └─yolo3_infer  
            __model__  
            __params__  

根据官方文档的介绍,预测过程主要分为以下几个步骤。

配置推理选项
创建Predictor
准备模型输入
模型推理
获取模型输出
在jetson nano上推理,需要修改推理配置的部分代码:推理配置对应AnalysisConfig类,建立其对象时需要指定模型路径。所有可选配置可以参考飞桨官方文档中的python预测API介绍。使用 TensorRT加速时,需要调用Paddle提供的接口,即AnalysisConfig类的enable_tensorrt_engine()方法。之后用以上配置创建predictor。

#对infer_yolov3.py中的推理配置进行修改:  
def create_predictor(args):  
    if args.model_dir is not "":  
        config = AnalysisConfig(args.model_dir)  
    else:  
        config = AnalysisConfig(args.model_file, args.params_file)  

    config.switch_use_feed_fetch_ops(False)  
    config.enable_memory_optim()  
    if args.use_gpu:  
        config.enable_use_gpu(1000, 0)  
        config.enable_tensorrt_engine(  
            precision_mode=AnalysisConfig.Precision.Half,  
            use_static=False,  
            use_calib_mode=False)  #tensorrt_engine with FP16 accuracy  
    else:  
        # If not specific mkldnn, you can set the blas thread.  
        # The thread num should not be greater than the number of cores in the CPU.  
        config.set_cpu_math_library_num_threads(4)  
        #config.enable_mkldnn()  

    predictor = create_paddle_predictor(config)  
    return predictor  

其余代码可以不做修改,再用下方的命令开始预测。该命令运行了infer_yolov3.py文件,同时指定了模型和参数的位置,以及GPU的使用情况。

python infer_yolov3.py --model_file=./yolov3_infer/__model__ params_file=./yolov3_infer/__params__ --use_gpu=1  
第四部分:效果展示

打印提示使用到了TensorRT的模型优化。看到Paddle-TRT字样就可以确定我们成功使用Paddle框架调用了TensorRT进行加速。模型的优化会占用大量GPU资源,耗时也较长。

1.jpg

预测输出的图片:

1.jpg

速度测试:

比较了在6c12t的i7-8750H、4核Arm A53以及Jetson nano GPU推理单张图片的耗时。结果如下:

1 (2).jpg

奉上遇到问题的解决方法
  1. 缺少虚析构函数的问题

解决方法为第二部分“编译前的准备工作”中对TensorRT库文件的修改。

  1. 编译中没有错误提示,但是编译失败

例如报错为:

paddle/fluid/operators/CMakeFiles/edit_distance_op.dir/edit_distance_op_generated_edit_distance_op.cu.o
nvcc error : 'cicc' died due to signal 9 (Kill signal)

问题在于swap区不够。解决方案参考第二部分“编译前的准备工作”中对Jetson nano设置。

  1. *:Too many files

需要修改系统打开文件最大数量的限制。解决方案参考第二部分“编译前的准备工作”中对Jetson nano设置。

参考资料:

https://www.jianshu.com/p/a35...
https://paddle-inference.read...
https://www.paddlepaddle.org....
https://paddle-inference.read...
https://github.com/PaddlePadd...
最后感谢飞桨技术人员在Github及时回答问题。

测试Paddle-Inference-Demo其他例子,欢迎访问项目地址:

Github:https://github.com/PaddlePadd...

Paddle Inference官方文档:https://paddle-inference.read...

如在使用过程中有问题,可加入飞桨官方QQ群进行交流:1108045677或飞桨推理部署QQ群:959308808。

如果您想详细了解更多飞桨的相关内容,请参阅以下文档。

官网地址:https://www.paddlepaddle.org.cn

飞桨开源框架项目地址:

GitHub: https://github.com/PaddlePadd...

Gitee: https://gitee.com/paddlepaddle/

推荐阅读
关注数
12971
内容数
325
带你捕获最前沿的科技信息,了解最新鲜的科技资讯
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息