Jetson Mediapipe GPU/CUDA Python 包构建

发布时间 2023-11-09 18:47:16作者: ZeddBao

使用 CPU 版本的 Mediapipe 延迟真的很高,所以试着构建了 GPU 版本的 Mediapipe。

GPU Support  |  MediaPipe  |  Google for Developers

然而 Google 官方的教程非常过时且并不是针对 Python 包的教程,参考价值非常非常小。因此搜集各路社区论坛,折腾了一个星期终于构建成功。

image

这个是我构建的环境配置,主要看 CUDA、cuDNN 这两个库还有 Python 的版本(OpenCV 我用 CUDA 编译了 4.8.1 版本不知道有没有啥影响,版本不一样应该可以先不管)。

1 安装一些依赖

sudo apt-get install mesa-common-dev libegl1-mesa-dev libgles2-mesa-dev mesa-utils pkg-config zip g++ zlib1g-dev unzip python3
sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt install openjdk-11-jdk

2 安装 Bazel

Bazel 是 Google 官方的构建工具,可以在 GitHub 下载。

Releases · bazelbuild/bazel

我下的是 6.4.0 版本的,最新的出了 7.0.0 不知道能不能用。

可以直接命令行下载:

wget https://github.com/bazelbuild/bazel/releases/download/6.4.0/bazel-6.4.0-linux-arm64
sudo mv bazel-6.4.0-linux-arm64 /usr/local/bin
chmod +x /usr/local/bin

需要放到 /usr/local/bin 可以全局使用 bazel 命令。

3 下载 Mediapipe 源码

Releases · google/mediapipe

wget https://github.com/google/mediapipe/archive/refs/tags/v0.10.7.tar.gz
tar -xzvf v0.10.7.tar.gz
cd mediapipe-0.10.7

我这里下的是 v0.10.7 版本的。

4 修改一些源码

参考链接:

【精选】零基础入门Jetson Nano——MediaPipe双版本(CPU+GPU)的安装与使用_mediapipe gpu加速 如何交叉编译通多的-CSDN博客

How to compile the gpu version of the python interface · Issue #1042 · google/mediapipe

  1. ./setup.py

    1. 注释掉下面的语句(注意有两处):

      if not self.link_opencv and not IS_WINDOWS:
      	bazel_command.append('--define=OPENCV=source')
      

      如果不注释会有如下报错:

      Error in depset: at index 0 of transitive, got element of type NoneType, want depset
      
    2. 替换

      binary_graphs = [
        'face_detection/face_detection_short_range_cpu',
        'face_detection/face_detection_full_range_cpu',
        'face_landmark/face_landmark_front_cpu',
        'hand_landmark/hand_landmark_tracking_cpu',
        'holistic_landmark/holistic_landmark_cpu', 'objectron/objectron_cpu',
        'pose_landmark/pose_landmark_cpu',
        'selfie_segmentation/selfie_segmentation_cpu'
      ]
      

      binary_graphs = [
        'face_detection/face_detection_short_range_gpu',
        'face_detection/face_detection_full_range_gpu',
        'face_landmark/face_landmark_front_gpu',
        'hand_landmark/hand_landmark_tracking_gpu',
        'holistic_landmark/holistic_landmark_gpu', 'objectron/objectron_gpu',
        'pose_landmark/pose_landmark_gpu',
        'selfie_segmentation/selfie_segmentation_gpu'
      ]
      

      修改这个是为了构建 gpu 版本的计算图。

    3. 把 **version** = 'dev' 改成 **version** = '0.10.7'

  2. ./mediapipe/python/solutions

    可以用 vscode 的搜索替换功能把这个目录下所有文件的的所有 _cpu. 替换成 _gpu.,例如 ./mediapipe/python/solutions/hands

    _BINARYPB_FILE_PATH = 'mediapipe/modules/hand_landmark/hand_landmark_tracking_cpu.binarypb'
    

    改为

    _BINARYPB_FILE_PATH = 'mediapipe/modules/hand_landmark/hand_landmark_tracking_gpu.binarypb'
    

    其它文件的 _BINARYPB_FILE_PATH 变量同理。

  3. ./mediapipe/modules/

    这里的 gpu 计算图都需要改,但我只用 hands.py,所以我只改了hand_landmark_tracking_gpu.pbtxt 文件,具体如何修改可以参考:

    How to compile the gpu version of the python interface · Issue #1042 · google/mediapipe

    其它文件的修改也可以参考上面的链接。

  4. ./mediapipe/framework/tool/BUILD

    cc_binary(
        name = "encode_as_c_string",
        srcs = ["encode_as_c_string.cc"],
        visibility = ["//visibility:public"],
        deps = [
            "@com_google_absl//absl/strings",
        ],
    )
    

    替换为

    cc_binary(
        name = "encode_as_c_string",
        srcs = ["encode_as_c_string.cc"],
        visibility = ["//visibility:public"],
        deps = [
            "@com_google_absl//absl/strings",
        ],
        linkopts = ["-lm"],
    )
    

    linkopts = ["-lm"],表示在链接阶段将使用 -lm 选项,这个选项告诉链接器链接数学库(libm)。

  5. ./mediapipe/framework/gpu/gl_context.cc./mediapipe/framework/gpu/gl_context_egl.cc

    注释掉下面的代码:

    ABSL_LOG(INFO) << "Successfully initialized EGL. Major : " << major
                   << " Minor: " << minor;
    
    ABSL_LOG(INFO) << "GL version: " << gl_major_version_ << "."
                   << gl_minor_version_ << " (" << version_string
                   << "), renderer: " << glGetString(GL_RENDERER);
    

    为了运行的时候不会打印日志消息。

  6. (如果安装了 opencv4)./third_party/opencv_linux.BUILD

    cc_library(
        name = "opencv",
        hdrs = glob([
            # For OpenCV 4.x
            #"include/aarch64-linux-gnu/opencv4/opencv2/cvconfig.h",
            #"include/arm-linux-gnueabihf/opencv4/opencv2/cvconfig.h",
            #"include/x86_64-linux-gnu/opencv4/opencv2/cvconfig.h",
            #"include/opencv4/opencv2/**/*.h*",
        ]),
        includes = [
            # For OpenCV 4.x
            #"include/aarch64-linux-gnu/opencv4/",
            #"include/arm-linux-gnueabihf/opencv4/",
            #"include/x86_64-linux-gnu/opencv4/",
            #"include/opencv4/",
        ],
        linkopts = [
            "-l:libopencv_core.so",
            "-l:libopencv_calib3d.so",
            "-l:libopencv_features2d.so",
            "-l:libopencv_highgui.so",
            "-l:libopencv_imgcodecs.so",
            "-l:libopencv_imgproc.so",
            "-l:libopencv_video.so",
            "-l:libopencv_videoio.so",
        ],
        visibility = ["//visibility:public"],
    )
    

    "include/aarch64-linux-gnu/opencv4/opencv2/cvconfig.h",

    "include/aarch64-linux-gnu/opencv4/",

    取消注释这两行。

    此外,保险起见可以输入下面的命令:

    sudo ln -s /usr/include/opencv4/opencv2 /usr/include/
    

    以防动态链接库找不到 opencv2。

5 一个和使用虚拟环境有关的问题

参考链接:

Conda虚拟环境下libp11-kit.so.0: undefined symbol: ffi_type_pointer...问题解决_Destinycjk的博客-CSDN博客

编译时可能会报错:

ImportError: /lib/aarch64-linux-gnu/libp11-kit.so.0: undefined symbol: ffi_type_pointer, version LIBFFI_BASE_7.0

可以看一下虚拟环境 lib 中的链接情况

ls -l ~/miniconda/envs/xxx/lib
# 上面的路径换成你自己的虚拟环境的路径

image

修正链接:

sudo ln -s /lib/aarch64-linux-gnu/libffi.so.7.1.0 libffi.so.7
sudo ln -s /lib/aarch64-linux-gnu/libffi.so.7.1.0 libffi.7.so
sudo ldconfig

6 最后配置一下环境变量开始编译

export http_proxy=http://127.0.0.1:7890
export https_proxy=http://127.0.0.1:7890
# 编译的时候会下载一些第三方库需要开梯子
export TF_CUDA_PATHS=/usr/local/cuda-11.x:/usr/lib/aarch64-linux-gnu:/usr/include
# 上面的 cuda-11.x 需要换成你自己的版本
export MEDIAPIPE_DISABLE_GPU=0
python3 setup.py gen_protos && python3 setup.py bdist_wheel

编译完成以后会在 ./dist 目录下生成 whl 文件,pip 一下即可。

⚠️ 注意如果中途编译失败可能会导致虚拟环境中 ./envs/xxx/lib/python3.x/site-packages/mediapipe-0.10.7/__init__.py 出现错误,如下:

from mediapipe.python import *
import mediapipe.python.solutions as solutions 
import mediapipe.tasks.python as tasks

del framework
del gpu
del modules
del python
del mediapipe
del util
__version__ = '0.10.7'

from mediapipe.python import *
import mediapipe.python.solutions as solutions 
import mediapipe.tasks.python as tasks

del framework
del gpu
del modules
del python
del mediapipe
del util
__version__ = '0.10.7'

# ...

失败几次就会重复几遍,删去重复内容即可。

7 安装完成

⚠️ 注意,需要先 import cv2import mediapipe as mp 不然会报错,原因不明 …

image

可以看到 GPU 版本的 Mediapipe 已经跑起来了,GPU 负荷确实上去了,并且画面延迟和帧率都有不小改善,几乎和没有直接 Capture 的画面一样了。