基于Jetson Xavier构建mmdeploy部署镜像流程

1 目标

  • 构建mmdeploy在Jetson Xavier的转换转换环境,方便直接将模型转换成tensort并执行推理;
  • 转换后的模型能够在triton-serve加载并使用
  • 支持图片分类、目标检测和实例分隔三种模型的转换;

2 环境

3 基本问题

问:什么是JetPack?
答:Nvidia制作的Jetson上的系统包,需要下载再烧录到SD卡上

问:如何更新JetPack?
答:4.4之后的可以直接在线升级,之前的仍然需要烧录

问:如何烧录JetPack?
答:

问:什么是L4T
答:L4T是Linux for Tegra的缩写,因为jetson系列用的是Tegra架构,因此L4T可以理解为jetson定制的Linux操作系统,具体的来说就是ubuntu定制款。

4 制作Jetson上的MMDeploy镜像

构建Jetson上的镜像探索了两种思路,

  • 思路1:在x86架构的机器上交叉编译,然后制作成镜像。可以参考交叉编译,我尝试该方法后发现,在x86机器上的编译速度并不是很快,同时编译后不方便测试GPU是否能够使用起来,因此该方案没有进行深入探索。
  • 思路2:直接在aarch64的机器上构建容器环境,一些包的编译相对较慢,但是只需编译一次就可以了。

本实验探索在nvcr.io/nvidia/l4t-ml:r32.6.1-py3镜像的基础上构建容器,所以需要先手动执行一遍,最后形成构建容器的Dockerfile。下面先介绍探索的过程以及探索过程中遇到的一些坑。

4.1 准备容器环境

注意:后续的操作都是在启动的容器中进行操作的。

docker run -d -it --runtime nvidia --name jetson-ml -v /opt/data/code/software:/software --network host nvcr.io/nvidia/l4t-ml:r32.6.1-py3  /bin/bash   # 启动容器
docker exec -it jetson-ml /bin/bash  # 进入容器
docker stop jetson-ml && docker rm jetson-ml  # 停止并删除容器

注意启动参数中添加了--runtime nvidia,否则cuda相关的库会用无法使用。

nvcr.io/nvidia/l4t-ml:r32.6.1-py3镜像中已经自带了下列包,因此不需要安装。

  • TensorFlow 1.15.5
  • PyTorch v1.9.0
  • torchvision v0.10.0
  • torchaudio v0.9.0
  • onnx 1.8.0
  • CuPy 9.2.0
  • numpy 1.19.5
  • numba 0.53.1
  • OpenCV 4.5.0 (with CUDA)
  • pandas 1.1.5
  • scipy 1.5.4
  • scikit-learn 0.23.2
  • JupyterLab 2.2.9

安装必要的包

apt update
apt install python3-tk unzip  -y
pip3 install tkinter

4.2 升级cmake

cmake升级有两种方案,① 直接下载cmake源码,然后进行编译,编译时间大概1个小时左右。② 下载预编译好的cmake,直接下载cmake-3.21.6-linux-aarch64.sh

方案1:下载源码并编译

apt-get remove cmake  # 卸载系统自带的cmake
wget https://github.com/Kitware/CMake/archive/refs/tags/v3.22.1.tar.gz
tar zxvf v3.22.1.tar.gz
cd v3.22.1
./bootstrap && make && make install

方案2:下载预编译包

wget https://github.com/Kitware/CMake/releases/download/v3.21.6/cmake-3.21.6-linux-aarch64.sh
sh cmake-3.21.6-linux-aarch64.sh
export PATH=$PATH:/INSTALL_PATH/cmake-3.21.6-linux-aarch64/bin  # 注意必须要导出安装路径

4.3 编译安装spdlog

spdlog一个开源的C++日志库,后续mmdeploy编译时需要。编译前需要在Cmakelists.txt中添加add_compile_options(-fPIC),否则后续mmdeploy编译会报错。

cd spdlog-1.9.2 && mkdir build && cd build && cmake .. && make -j$(nproc) && make install

4.4 编译安装ppl.cv

ppl.cv是openPPL的高性能图像处理库,后续mmdeploy编译时需要。

unzip ppl.cv-0.6.1.zip && mv ppl.cv-0.6.1 ppl.cv && cd ppl.cv && ./build.sh cuda

4.5 安装onnxruntime

onnxruntime在1.10.0版本之后,直接发布了aarch64的预编译版本onnxruntime-linux-aarch64-1.10.0.tgz,直接下载使用即可。

下载后执行解压、并导出对应的环境变量

tar zxvf onnxruntime-linux-aarch64-1.10.0.tgz  -C /workspace
export ONNXRUNTIME_DIR=/workspace

安装onnxruntime-gpu

pip3 install onnxruntime-gpu==1.10.0

4.6 安装mmcv-full

pip3 install mmcv-full==1.4.5 -f https://download.openmmlab.com/mmcv/dist/cu102/torch1.9.0/index.html

首次使用的系统会自动编译,编译完成后可以从缓存中把编译的whl包保存下来,下次就不用编译了,首次编译时间大概也需要1个小时左右。获取到编译的包之后,直接pip3 install mmcv_full-1.4.5-cp36-cp36m-linux_aarch64.whl即可。

4.7 安装mmdet/mmseg/mmcls

上述环境准备好之后,这三个包直接pip安装即可,命令如下:

pip3 install mmdet==2.21.0 mmcls==0.20.1 mmsegmentation==0.18.0

4.8 编译安装mmdeploy

下载mmdeploy,处理mmdeploy,还需要下载对应子模块的代码。

git clone https://github.com/open-mmlab/mmdeploy.git
cd mmdeploy
export MMDEPLOY_DIR=$(pwd)  # 注意要导出MMDEPLOY_DIR后续编译需要用到。
git submodule update --init --recursive

编译onnruntime和tensorrt支持库

cd mmdeploy &&\
    rm -rf build &&\
    mkdir build &&\
    cd build &&\
    cmake -DMMDEPLOY_TARGET_BACKENDS=ort .. &&\
    make -j$(nproc) &&\
    cmake -DMMDEPLOY_TARGET_BACKENDS=trt .. &&\
    make -j$(nproc) &&\
    cd .. &&\
    pip3 install -e .

编译sdk支持

cd mmdeploy &&\
    rm -rf build/CM* &&\
    mkdir -p build && cd build &&\
    cmake .. \
        -DMMDEPLOY_BUILD_SDK=ON \
        -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \
        -Dpplcv_DIR=/software/ppl.cv/cuda-build/install/lib/cmake/ppl \
        -DMMDEPLOY_BUILD_SDK_PYTHON_API=ON \
        -DMMDEPLOY_TARGET_DEVICES="cuda;cpu" \
        -DMMDEPLOY_TARGET_BACKENDS="trt" \
        -DMMDEPLOY_CODEBASES=all &&\
    cmake --build . -- -j$(nproc) && cmake --install . &&\
    cd install/example  && mkdir -p build && cd build &&\
    cmake -DMMDeploy_DIR=/software/mmdeploy/build/install/lib/cmake/MMDeploy .. 

编译完成后导出mmdeploy的库:

export LD_LIBRARY_PATH="DIR/mmdeploy/build/lib:${LD_LIBRARY_PATH}"

5 Dockerfile

FROM nvcr.io/nvidia/l4t-ml:r32.6.1-py3 

ARG CUDA=10.2.460
ARG PYTHON_VERSION=3.6.9
ARG TORCH_VERSION=1.9.0
ARG TORCHVISION_VERSION=0.10.0
ARG ONNXRUNTIME_VERSION=1.10.0
ARG MMCV_VERSION=1.4.5

ENV WORK_DIR=/root/workspace
ENV DEBIAN_FRONTEND=noninteractive
ENV PATH="${PATH}:${WORK_DIR}/cmake-3.21.6-linux-aarch64/bin"
ENV LD_LIBRARY_PATH="${WORK_DIR}/mmdeploy/build/lib:${LD_LIBRARY_PATH}"
ENV ONNXRUNTIME_DIR="${WORK_DIR}/onnxruntime-linux-aarch64-1.10.0"

WORKDIR /root/workspace

### copy files
copy files $WORK_DIR

RUN cd $WORK_DIR && apt update && apt-get remove cmake -y && apt install python3-tk unzip -y &&\
    sh -c '/bin/echo -e "\ny\ny" | sh cmake-3.21.6-linux-aarch64.sh'
    
RUN cd $WORK_DIR &&\
    pip3 install onnxruntime_gpu-1.10.0-cp36-cp36m-linux_aarch64.whl &&\
    pip3 install mmcv_full-1.4.5-cp36-cp36m-linux_aarch64.whl &&\
    pip3 install mmdet==2.21.0 mmcls==0.20.1 mmsegmentation==0.18.0 &&\
    tar zxvf onnxruntime-linux-aarch64-1.10.0.tgz
    
RUN cd $WORK_DIR/spdlog-1.9.2 && mkdir build && cd build && cmake .. && make -j$(nproc) && make install

RUN cd $WORK_DIR && unzip ppl.cv-0.6.1.zip && mv ppl.cv-0.6.1 ppl.cv &&\
    cd ppl.cv && ./build.sh cuda

ENV MMDEPLOY_DIR="${WORK_DIR}/mmdeploy"
RUN cd $WORK_DIR/mmdeploy &&\
    rm -rf build &&\
    mkdir build &&\
    cd build &&\
    cmake -DMMDEPLOY_TARGET_BACKENDS=ort .. &&\
    make -j$(nproc) &&\
    cmake -DMMDEPLOY_TARGET_BACKENDS=trt .. &&\
    make -j$(nproc) &&\
    cd .. &&\
    pip3 install -e .
    
RUN cd $WORK_DIR/mmdeploy &&\
    rm -rf build/CM* &&\
    mkdir -p build && cd build &&\
    cmake .. \
        -DMMDEPLOY_BUILD_SDK=ON \
        -DCMAKE_CXX_COMPILER=aarch64-linux-gnu-g++ \
        -Dpplcv_DIR=${WORK_DIR}/ppl.cv/cuda-build/install/lib/cmake/ppl \
        -DMMDEPLOY_BUILD_SDK_PYTHON_API=ON \
        -DMMDEPLOY_TARGET_DEVICES="cuda;cpu" \
        -DMMDEPLOY_TARGET_BACKENDS="trt" \
        -DMMDEPLOY_CODEBASES=all &&\
    cmake --build . -- -j$(nproc) && cmake --install . &&\
    cd install/example  && mkdir -p build && cd build &&\
    cmake -DMMDeploy_DIR=${WORK_DIR}/mmdeploy/build/install/lib/cmake/MMDeploy ..
    
RUN rm -f ${WORK_DIR}/*.gz && rm -f ${WORK_DIR}/*.tgz && rm -f ${WORK_DIR}/*.zip

适配Xavier JetPack4.6的Dockerfile以及对应的文件链接:https://pan.baidu.com/s/14WXskPdrS7BI_HcrXUY0LQ
提取码:r9z0

6 测试模型转换以及tritonserver的部署

用到的测试模型以及配置文件下载地址:
链接:https://pan.baidu.com/s/1uZ7pi2KszHkC2vkZ8UPi1A
提取码:cp1r

模型转换测试

docker run -it --rm -w /root/workspace/mmdeploy \
    -v /root/software:/software --network host 172.18.18.222:5000/schinper/ai-train:schiper_deploy_xavier_v1.0  python3 tools/deploy.py /software/model/cls_139_1182/model_deploy_config.py \
    /software/model/cls_139_1182/mmcls_model_config.py /software/model/cls_139_1182/latest.pth /software/model/cls_139_1182/demo.jpg \
    --test-img /software/model/cls_139_1182/demo.jpg \
    --work-dir /software/model/cls_139_1182/convert \
    --device cuda:0 --log-level INFO --dump-info

tritonserver的配置文件
路径格式

- tritonserver
  - 139_1182_resnet18_cls_tensorrt
    - 1
      - model.plan
    - config.pbtxt

config.pbtxt配置

name: "139_1182_resnet18_cls_tensorrt"
platform: "tensorrt_plan"
max_batch_size : 0
input [
  {
    name: "input"
    data_type: TYPE_FP32
    format: FORMAT_NCHW
    dims: [3, 224, 224]
    reshape { shape: [1, 3, 224, 224] }
  }
]
output [
  {
    name: "output"
    data_type: TYPE_FP32
    dims: [1000]
    reshape { shape: [ 1, 1000] }
  }
]

启动tritonserver【JetPack4.6中已经预装tritonserver2.19.0,直接使用即可】,需要指定与加载的TensorRT算子,具体操作参考下面的问题3。tritonserver启动效果。


image.png

7 遇到的坑

问题1:构建镜像时出现如下错误 CUDA_cublas_LIBRARY

CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
CUDA_cublas_LIBRARY (ADVANCED)
    linked by target "mmdeploy_tensorrt_ops_obj" in directory /root/workspace/mmdeploy/csrc/backend_ops/tensorrt

-- Generating done
CMake Generate step failed.  Build files cannot be regenerated correctly.

解决方法:需要将docker的runtime 默认设置为"default-runtime": "nvidia" ,在docker的daemon.json
中添加"default-runtime": "nvidia"。示例如下:

{
    "runtimes": {
        "nvidia": {
            "path": "nvidia-container-runtime",
            "runtimeArgs": []
        }
    },
    "insecure-registries": ["172.18.18.222:5000"],
    "default-runtime": "nvidia"
}

问题2:mmdeploy在编译的时出现dangerous relocation: unsupported relocation错误
解决方法:出现这个问题主要是由于编译spdlog时,需要在spdlog的Cmakelists.txt中添加add_compile_options(-fPIC),否则会出现上述的链接定位错误。

问题3:加载模型是出现下面的错误

E0311 04:18:11.717970 28535 logging.cc:43] 1: [pluginV2Runner.cpp::load::290] Error Code 1: Serialization (Serialization assertion creator failed.Cannot deserialize plugin since corresponding IPluginCreator not found in Plugin Registry)
E0311 04:18:11.718220 28535 logging.cc:43] 4: [runtime.cpp::deserializeCudaEngine::50] Error Code 4: Internal Error (Engine deserialization failed.)
I0311 04:18:11.799840 28535 tensorrt.cc:5345] TRITONBACKEND_ModelInstanceFinalize: delete instance state
I0311 04:18:11.800085 28535 tensorrt.cc:5283] TRITONBACKEND_ModelFinalize: delete model state
E0311 04:18:11.801115 28535 model_repository_manager.cc:1152] failed to load '147_1297_retinanet_det_tensorrt' version 1: Internal: unable to create TensorRT engine

解决方法:出现该问题的原因是因为tensorrt中没有mmdeploy新增的算子,因此需要将构建镜像时编译生成的库,拷贝到tritonserver可以使用的地方。

# 启动一个容器
docker run -it --rm --name temp 172.18.18.222:5000/schinper/ai-train:schiper_deploy_xavier_v1.0 /bin/bash
# 在另外一个console下执行拷贝
docker cp /root/workspace/mmdeploy/build/install/lib /root/mmdeploy_lib
# 指定预加载库,并启动tritonserver
LD_PRELOAD=/root/mmdeploy_lib/libmmdeploy_tensorrt_ops.so ./tritonserver --model-repository=/root/models
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容