Building Jetson Nano libraries on host PC

docker Docker

こちらの記事では、Jetson Nano上でPyTorchライブラリをビルドし、こちらの記事では、Jetson Nano上でOpenCVライブラリをビルドしました。これらのビルドはすべてJetson Nano上で実行しましたが、こちらの記事で解説した方法を使用しJetson Nanoのアーキテクチャであるaarch64バイナリをホストPCで実行しPyTorchとOpenCVライブラリをビルドする方法を解説します。

docker

ビルドにはDockerを使用します。Dockerを使用することでaarch64バイナリが必要とする共有ライブラリなどの環境を構築することができます。なお以下を実行し事前にログインユーザをdockerグループに追加しsudoなしでdockerコマンドを実行できるようにします。

sudo groupadd docker sudo gpasswd -a $USER docker
Code language: PHP (php)

再起動しdockerグループへの追加を反映させます。

PyTorch

以下Dockerfileの説明です。

FROM nvcr.io/nvidia/l4t-base:r32.7.1 ENV DEBIAN_FRONTEND=noninteractive ARG MAX_JOBS=2
Code language: Dockerfile (dockerfile)

ARG MAX_JOBSdocker build時に外から--build-arg MAX_JOBS=$(nproc)などとして渡すことを可能にしています。

# https://qengineering.eu/install-pytorch-on-jetson-nano.html RUN apt-get update && apt-get install -y \ python3.8 python3.8-dev \ ninja-build git cmake clang \ libopenmpi-dev libomp-dev ccache \ libopenblas-dev libblas-dev libeigen3-dev \ python3-pip libjpeg-dev \ gnupg2 curl RUN apt-key adv --fetch-key http://repo.download.nvidia.com/jetson/jetson-ota-public.asc RUN echo 'deb https://repo.download.nvidia.com/jetson/common r32.7 main\n\ deb https://repo.download.nvidia.com/jetson/t210 r32.7 main' > /etc/apt/sources.list.d/nvidia-l4t-apt-source.list RUN apt-get update && apt-get install -y nvidia-cuda nvidia-cudnn8 RUN python3.8 -m pip install -U pip RUN python3.8 -m pip install -U setuptools RUN python3.8 -m pip install -U wheel mock pillow RUN python3.8 -m pip install scikit-build RUN python3.8 -m pip install cython Pillow
Code language: Dockerfile (dockerfile)

途中repo.download.nvidia.comをapt repositoryに追加し、その後nvidia-cuda nvidia-cudnn8をインストールしています。

以降はこちらの記事で説明したものとほぼ同じになります。

## download PyTorch v1.11.0 with all its libraries RUN git clone -b v1.11.0 --depth 1 --recursive --recurse-submodules --shallow-submodules https://github.com/pytorch/pytorch.git WORKDIR pytorch RUN python3.8 -m pip install -r requirements.txt COPY pytorch-1.11-jetson.patch . RUN patch -p1 < pytorch-1.11-jetson.patch RUN apt-get install -y software-properties-common lsb-release RUN wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null RUN apt-add-repository "deb https://apt.kitware.com/ubuntu/ $(lsb_release -cs) main" RUN apt-get update && apt-get install -y cmake ENV BUILD_CAFFE2_OPS=OFF ENV USE_FBGEMM=OFF ENV USE_FAKELOWP=OFF ENV BUILD_TEST=OFF ENV USE_MKLDNN=OFF ENV USE_NNPACK=OFF ENV USE_XNNPACK=OFF ENV USE_QNNPACK=OFF ENV USE_PYTORCH_QNNPACK=OFF ENV USE_CUDA=ON ENV USE_CUDNN=ON ENV TORCH_CUDA_ARCH_LIST="5.3;6.2;7.2" ENV USE_NCCL=OFF ENV USE_SYSTEM_NCCL=OFF ENV USE_OPENCV=OFF ENV MAX_JOBS=$MAX_JOBS # set path to ccache ENV PATH=/usr/lib/ccache:$PATH # set clang compiler ENV CC=clang ENV CXX=clang++ # create symlink to cublas # ln -s /usr/lib/aarch64-linux-gnu/libcublas.so /usr/local/cuda/lib64/libcublas.so # start the build RUN python3.8 setup.py bdist_wheel RUN find /pytorch/dist/ -type f|xargs python3.8 -m pip install # torch vision RUN git clone --depth=1 https://github.com/pytorch/vision torchvision -b v0.12.0 RUN cd torchvision && \ TORCH_CUDA_ARCH_LIST='5.3;6.2;7.2' \ FORCE_CUDA=1 \ python3.8 setup.py bdist_wheel
Code language: Dockerfile (dockerfile)

上記Dockerfileをビルドします。

docker build -t pytorch-build . --build-arg MAX_JOBS=$(nproc)
Code language: Bash (bash)

Jetson Nanoでビルドする際はメモリが少ない為MAX_JOBS=2を指定しましたが、ホストPCではこの制限は緩やかです。

ビルドが終わったら、ビルドされたバイナリを取り出します。

$ id=$(docker run -it --rm -d pytorch-build bash) $ pytorch=$(docker exec -it ${id} find /pytorch/dist -type f | sed -e "s/[\r\n]\+//g") $ vision=$(docker exec -it ${id} find /pytorch/torchvision/dist -type f | sed -e "s/[\r\n]\+//g") $ docker cp ${id}:${pytorch} . $ docker cp ${id}:${vision} . $ docker stop ${id} $ ls Dockerfile *whl Dockerfile torch-1.11.0a0+gitbc2c6ed-cp38-cp38-linux_aarch64.whl torchvision-0.12.0a0+9b5a3fe-cp38-cp38-linux_aarch64.whl
Code language: Bash (bash)

手元にtorch-1.11.0a0+gitbc2c6ed-cp38-cp38-linux_aarch64.whltorchvision-0.12.0a0+9b5a3fe-cp38-cp38-linux_aarch64.whlの2つができました。

これら2つをJetson Nanoにコピーしインストールします。以下はJetson Nanoで実行します。

sudo apt update sudo apt install -y \ python3.8 python3.8-dev python3-pip \ libopenmpi-dev libomp-dev libopenblas-dev libblas-dev libeigen3-dev \ nvidia-cuda nvidia-cudnn8 python3.8 -m pip install -U pip python3.8 -m pip install torch-*.whl torchvision-*.whl
Code language: Bash (bash)

OpenCV

以下Dockerfileの説明です。

FROM nvcr.io/nvidia/l4t-base:r32.6.1 ENV DEBIAN_FRONTEND=noninteractive ARG VER="4.6.0" ARG PREFIX=/usr/local ARG MAX_JOBS
Code language: Dockerfile (dockerfile)

こちらも、いくつかの変数をdocker build時に--build-argで渡せるようにしています。以降はこちらの記事で説明したものとほぼ同じになります。

# setup RUN cd tmp && mkdir build_opencv WORKDIR /tmp/build_opencv # install_dependencies RUN apt-get update && \ apt-get install -y \ build-essential \ cmake \ git \ gfortran \ libatlas-base-dev \ libavcodec-dev \ libavformat-dev \ libavresample-dev \ libcanberra-gtk3-module \ libdc1394-22-dev \ libeigen3-dev \ libglew-dev \ libgstreamer-plugins-base1.0-dev \ libgstreamer-plugins-good1.0-dev \ libgstreamer1.0-dev \ libgtk-3-dev \ libjpeg-dev \ libjpeg8-dev \ libjpeg-turbo8-dev \ liblapack-dev \ liblapacke-dev \ libopenblas-dev \ libpng-dev \ libpostproc-dev \ libswscale-dev \ libtbb-dev \ libtbb2 \ libtesseract-dev \ libtiff-dev \ libv4l-dev \ libxine2-dev \ libxvidcore-dev \ libx264-dev \ pkg-config \ python3.8-dev \ python3.8-dev \ python3-numpy \ python3-matplotlib \ python3-pip \ qv4l2 \ v4l-utils \ v4l2ucp \ zlib1g-dev # git_source ${VER} RUN git clone --depth 1 --branch ${VER} https://github.com/opencv/opencv.git RUN git clone --depth 1 --branch ${VER} https://github.com/opencv/opencv_contrib.git RUN python3 -m pip install -U pip RUN python3 -m pip uninstall -y numpy RUN python3.8 -m pip install -U pip RUN python3.8 -m pip install setuptools RUN python3.8 -m pip install numpy RUN apt-key adv --fetch-key http://repo.download.nvidia.com/jetson/jetson-ota-public.asc RUN echo 'deb https://repo.download.nvidia.com/jetson/common r32.6 main\n\ deb https://repo.download.nvidia.com/jetson/t210 r32.6 main' > /etc/apt/sources.list.d/nvidia-l4t-apt-source.list RUN apt-get update && apt-get install -y nvidia-cuda nvidia-cudnn8 RUN cd opencv && \ mkdir build && \ cd build && \ cmake \ -D BUILD_EXAMPLES=OFF \ -D BUILD_opencv_python2=OFF \ -D BUILD_opencv_python3=ON \ -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=${PREFIX} \ -D CUDA_ARCH_BIN=5.3,6.2,7.2 \ -D CUDA_ARCH_PTX= \ -D CUDA_FAST_MATH=ON \ -D CUDNN_VERSION='8.0' \ -D EIGEN_INCLUDE_PATH=/usr/include/eigen3 \ -D ENABLE_NEON=ON \ -D OPENCV_DNN_CUDA=ON \ -D OPENCV_ENABLE_NONFREE=ON \ -D OPENCV_EXTRA_MODULES_PATH=/tmp/build_opencv/opencv_contrib/modules \ -D OPENCV_GENERATE_PKGCONFIG=ON \ -D WITH_CUBLAS=ON \ -D WITH_CUDA=ON \ -D WITH_CUDNN=ON \ -D WITH_GSTREAMER=ON \ -D WITH_LIBV4L=ON \ -D WITH_OPENGL=ON \ -D BUILD_PERF_TESTS=OFF \ -D BUILD_TESTS=OFF \ -D PYTHON3_EXECUTABLE=python3.8 \ -D PYTHON3_INCLUDE_PATH=$(python3.8 -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \ -D PYTHON3_PACKAGES_PATH=$(python3.8 -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())") \ -D PYTHON3_LIBRARY=/usr/lib/aarch64-linux-gnu/libpython3.8.so \ -D CPACK_BINARY_DEB=ON \ -D CPACK_PACKAGING_INSTALL_PREFIX=${PREFIX} \ .. WORKDIR /tmp/build_opencv/opencv/build RUN make -j${MAX_JOBS} RUN make install RUN cpack -G DEB
Code language: Dockerfile (dockerfile)

debパッケージを作成するために、cmakeのオプションに、-D CPACK_BINARY_DEB=ON-D CPACK_PACKAGING_INSTALL_PREFIX=${PREFIX}を追加しています。最後に、cpack -G DEBでdebパッケージを作成します。

上記Dockerfileをビルドします。

docker build -t opencv-build . --build-arg MAX_JOBS=$(nproc)
Code language: Bash (bash)

ビルドが終わったら、ビルドされたバイナリを取り出します。

$ id=$(docker run -it --rm -d opencv-build bash) $ debs=$(docker exec -it ${id} find /tmp/build_opencv/opencv/build/ -maxdepth 1 -name "*.deb" | sed -e "s/[\r\n]\+//g") $ for deb in $debs; do docker cp ${id}:$deb . done $ docker stop ${id} $ ls Dockerfile *deb Dockerfile OpenCV-4.6.0-aarch64-dev.deb OpenCV-4.6.0-aarch64-libs.deb OpenCV-4.6.0-aarch64-licenses.deb OpenCV-4.6.0-aarch64-main.deb OpenCV-4.6.0-aarch64-python.deb OpenCV-4.6.0-aarch64-scripts.deb
Code language: Bash (bash)

これらのdebパッケージをJetson Nanoにコピーしインストールします。以下はJetson Nanoで実行します。

sudo apt update apt list --installed *opencv*|awk -F/ '/opencv/ {print $1}'|sudo xargs apt remove -y sudo apt install -y ./OpenCV*.deb
Code language: Bash (bash)

既存のopencvパッケージを削除してからビルドしたOpenCVパッケージをインストールします。

パフォーマンス

PytorchのDockerビルド、OpenCVのDockerビルドをそれぞれJetson NanoとホストPC上で実行した時間を掲載します。

Jetson
Nano
Host PC
i9-12900K, 32GB
faster
PyTorchMAX_JOBS=2
real 832m39.333s
user 0m7.352s
sys 0m4.268s
MAX_JOBS=24
real 176m48.354s
user 0m0.852s
sys 0m0.904s
x4.7
OpenCVMAX_JOBS=4
real 161m34.754s
user 0m2.240s
sys 0m1.660s
MAX_JOBS=24
real 117m28.657s
user 0m0.648s
sys 0m0.517s
x1.3

ホストPCでのビルドはPyTorchで4.7倍、OpenCVで1.3倍、高速にビルドすることが可能です。またホストPCでのビルドは機材に依存しないためCI/CDなどのビルドサーバに導入することが可能です。

上記のコードは https://github.com/otamajakusi/build_jetson_nano_libraries にまとめてあります。

以上です。

参照