参考

自分でビルドするのはめんどくさい人向け

ビルド済みバイナリ(mediapipe-0.10.1)を用意しました。 Ubuntu用はバージョンがdevになっていますが、中身は0.10.1です。

bazeliskの導入

とりあえず~/apps/binに入れておく。PATHも通しておいたほうがよい。

1
2
3
4
5
% mkdir -p ~/apps/bin
% curl -L -o ~/apps/bin/bazelisk https://github.com/bazelbuild/bazelisk/releases/download/v1.11.0/bazelisk-linux-arm64
% (cd ~/apps/bin; ln -sf bazelisk bazel)
% chmod +x ~/apps/bin/bazelisk
% PATH="${HOME}/apps/bin:${PATH}"

ビルドに必要なものの用意

1
2
3
4
% sudo apt install build-essential python3-dev python3-setuptools cmake protobuf-compiler python3-numpy
% git clone https://github.com/google/mediapipe
% cd mediapipe
% git checkout v0.10.1

setup.pyのバージョン情報を更新する。

1
% sed -i "s/__version__ = 'dev'/__version__ = '0.10.1'/" setup.py

third_party/BUILDを編集し、不要な機能を除外する。 同様に不要なライブラリのリンクをしないようにする。 また、carotene_o4tを無効化する。

1
2
3
% sed -i -e "/\"imgcodecs\"/d;/\"calib3d\"/d;/\"features2d\"/d;/\"highgui\"/d;/\"video\"/d;/\"videoio\"/d" \
         -e "/-ljpeg/d;/-lpng/d;/-ltiff/d;/-lImath/d;/-lIlmImf/d;/-lHalf/d;/-lIex/d;/-lIlmThread/d;/-lrt/d;/-ldc1394/d;/-lavcodec/d;/-lavformat/d;/-lavutil/d;/-lswscale/d;/-lavresample/d" \
         -e 's/"WITH_WEBP": "OFF",/"WITH_WEBP": "OFF",\n        "ENABLE_NEON": "OFF",\n        "WITH_TENGINE": "OFF",/' third_party/BUILD

編集したthird_party/BUILDのdiffは下記の通り。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
% git diff third_party/BUILD
diff --git a/third_party/BUILD b/third_party/BUILD
index e2044cf..0100547 100644
--- a/third_party/BUILD
+++ b/third_party/BUILD
@@ -76,12 +76,6 @@ load("@rules_foreign_cc//tools/build_defs:cmake.bzl", "cmake_external")
 # linker, so if library A depends on library B, library B must come _after_.
 # Hence core is at the bottom.
 OPENCV_MODULES = [
-    "calib3d",
-    "features2d",
-    "highgui",
-    "video",
-    "videoio",
-    "imgcodecs",
     "imgproc",
     "core",
 ]
@@ -113,6 +107,8 @@ cmake_external(
         "WITH_PNG": "ON",
         "WITH_TIFF": "ON",
         "WITH_WEBP": "OFF",
+       "ENABLE_NEON": "OFF",
+       "WITH_TENGINE": "OFF",
         # Optimization flags
         "CV_ENABLE_INTRINSICS": "ON",
         "WITH_EIGEN": "ON",
@@ -149,25 +145,10 @@ cmake_external(
         # the build, and so depends on what is installed on the local system.
         # After building, the linkopts for the current setup can be extracted
         # from lib/pkgconfig/opencv.pc in bazel-out
-        "-ljpeg",
-        "-lpng",
         "-lz",
-        "-ltiff",
-        "-lImath",
-        "-lIlmImf",
-        "-lIex",
-        "-lHalf",
-        "-lIlmThread",
-        "-ldc1394",
-        "-lavcodec",
-        "-lavformat",
-        "-lavutil",
-        "-lswscale",
-        "-lavresample",
         "-ldl",
         "-lm",
         "-lpthread",
-        "-lrt",
     ],
     shared_libraries = select({
         "@bazel_tools//src/conditions:darwin": ["libopencv_%s.%s.dylib" % (module, OPENCV_SO_VERSION) for module in OPENCV_MODULES],

編集が完了したら、早速ビルドを開始する。

1
2
3
% PATH="${HOME}/apps/bin:${PATH}"
% python3 setup.py gen_protos
% time python3 setup.py bdist_wheel

/usr/bin/pythonが存在しないと下記のようなエラーが発生する。 どうやらどこかのスクリプトのShebangで#!/usr/bin/env pythonが用いられている模様。 とりあえずsudo ln -s /usr/bin/python3.9 /usr/bin/pythonしておけば通った。

1
2
3
4
5
6
7
8
9
10
11
12
13
ERROR: /home/gloria/.cache/bazel/_bazel_gloria/c703987e42a2b396bbfb309c04bccc16/external/org_tensorflow/tensorflow/core/util/BUILD:379:24: 
Action external/org_tensorflow/tensorflow/core/util/version_info.cc failed: (Exit 127): bash failed: error executing command 
/bin/bash -c 'bazel-out/aarch64-opt-ST-e0f78fafe98f/bin/external/org_tensorflow/tensorflow/tools/git/gen_git_source 
--generate "$@" --git_tag_override=${GIT_TAG_OVERRIDE:-}' '' ... (remaining 4 argument(s) skipped)

Use --sandbox_debug to see verbose messages from the sandbox
/usr/bin/env: 'python': No such file or directory
Target //mediapipe/modules/face_detection:face_detection_short_range_cpu failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 4961.073s, Critical Path: 3555.34s
INFO: 2026 processes: 265 internal, 1761 linux-sandbox.
FAILED: Build did NOT complete successfully
python3 setup.py bdist_wheel  2.09s user 3.12s system 0% cpu 1:22:43.05 total

Raspberry Pi 4(modelB 8GB)では、合計3時間程度でビルドできた。 メモリは常に2GB以上必要となるようなので、最低でも4GBモデルが必要となりそう。(2023/04/24追記: 4GBでは足りなかった)

1
python3 setup.py bdist_wheel  19.92s user 19.28s system 0% cpu 2:44:46.69 total

インストール

ビルドしたmediapipeライブラリと、mediapipeの利用に必要なライブラリ群をインストールしておく。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
% sudo apt install cython3 python3-opencv
% pip3 install pillow
% pip3 install ./dist/mediapipe-dev-cp310-cp310-linux_aarch64.whl
Defaulting to user installation because normal site-packages is not writeable
Processing /home/gloria/src/mediapipe/dist/mediapipe-dev-cp310-cp310-linux_aarch64.whl
Collecting absl-py
  Downloading absl_py-1.4.0-py3-none-any.whl (126 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 126.5/126.5 KB 1.3 MB/s eta 0:00:00
Collecting flatbuffers>=2.0
  Downloading flatbuffers-23.5.26-py2.py3-none-any.whl (26 kB)
Collecting opencv-contrib-python
  Downloading opencv_contrib_python-4.7.0.72-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (45.0 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 45.0/45.0 MB 6.1 MB/s eta 0:00:00
Requirement already satisfied: numpy in /usr/lib/python3/dist-packages (from mediapipe==dev) (1.21.5)
Collecting sounddevice>=0.4.4
  Downloading sounddevice-0.4.6-py3-none-any.whl (31 kB)
Requirement already satisfied: attrs>=19.1.0 in /usr/lib/python3/dist-packages (from mediapipe==dev) (21.2.0)
Collecting protobuf<4,>=3.11
  Downloading protobuf-3.20.3-cp310-cp310-manylinux2014_aarch64.whl (918 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 918.4/918.4 KB 8.7 MB/s eta 0:00:00
Collecting matplotlib
  Downloading matplotlib-3.7.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (11.3 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 11.3/11.3 MB 9.5 MB/s eta 0:00:00
Collecting CFFI>=1.0
  Using cached cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (449 kB)
Collecting pillow>=6.2.0
  Downloading Pillow-9.5.0-cp310-cp310-manylinux_2_28_aarch64.whl (3.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.2/3.2 MB 10.1 MB/s eta 0:00:00
Requirement already satisfied: pyparsing>=2.3.1 in /usr/lib/python3/dist-packages (from matplotlib->mediapipe==dev) (2.4.7)
Collecting kiwisolver>=1.0.1
  Downloading kiwisolver-1.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (1.4 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.4/1.4 MB 4.3 MB/s eta 0:00:00
Collecting packaging>=20.0
  Downloading packaging-23.1-py3-none-any.whl (48 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 48.9/48.9 KB 185.7 kB/s eta 0:00:00
Collecting python-dateutil>=2.7
  Using cached python_dateutil-2.8.2-py2.py3-none-any.whl (247 kB)
Collecting fonttools>=4.22.0
  Downloading fonttools-4.40.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (4.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.2/4.2 MB 10.3 MB/s eta 0:00:00
Collecting contourpy>=1.0.1
  Downloading contourpy-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (283 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 283.9/283.9 KB 10.6 MB/s eta 0:00:00
Collecting cycler>=0.10
  Using cached cycler-0.11.0-py3-none-any.whl (6.4 kB)
Collecting pycparser
  Using cached pycparser-2.21-py2.py3-none-any.whl (118 kB)
Requirement already satisfied: six>=1.5 in /usr/lib/python3/dist-packages (from python-dateutil>=2.7->matplotlib->mediapipe==dev) (1.16.0)
Installing collected packages: flatbuffers, python-dateutil, pycparser, protobuf, pillow, packaging, opencv-contrib-python, kiwisolver,
 fonttools, cycler, contourpy, absl-py, matplotlib, CFFI, sounddevice, mediapipe
Successfully installed CFFI-1.15.1 absl-py-1.4.0 contourpy-1.1.0 cycler-0.11.0 flatbuffers-23.5.26 fonttools-4.40.0 kiwisolver-1.4.4 
matplotlib-3.7.1 mediapipe-dev opencv-contrib-python-4.7.0.72 packaging-23.1 pillow-9.5.0 protobuf-3.20.3 pycparser-2.21 python-dateutil-2.8.2 sounddevice-0.4.6

コケた場合の対処法

コケる可能性は無限大。

swap領域を追加する

メモリが不足しコケる場合は、下記のようにswapfileなどを用意して回避する手法もある。 ただし、少なくともUSB-SSDを用いるなどの対策を行わないとSDカードがあっという間に壊れる可能性が高いので注意。 (そもそもビルドのようなストレージに負荷が掛かる作業は、SDカード上では行わない方がよい。)

1
2
3
4
5
6
% sudo dd if=/dev/zero of=/swapfile bs=1M count=4096
% sudo mkswap /swapfile
% sudo swapon /swapfile
% swapon
NAME      TYPE SIZE USED PRIO
/swapfile file   4G 1.5M   -2

setuptoolsとwheelを最新にする

setup.pyが速攻でコケた時は、mediapipeに限らずだいたいこれ。毎度おなじみ。

1
% python3 -m pip install -U setuptools wheel

下手にディストリパッケージのpipをインストールするとバージョンやら依存関係やらがぐちゃぐちゃになりがちなので、 get-pip.pyあたりを使った方がよいかもしれない。 (その上でpipenvなどを使うとなおよいかもしれない。)

protobuf-compiler(protoc)を最新にする

ubuntu-22.04では大丈夫なようだが、Raspberry Pi OSなどで動かしたい場合は protocが古すぎてpython3 setup.py gen_protosがエラーとなる場合がある。

1
2
3
4
% python3 setup.py gen_protos
...
generating proto file: build/lib.linux-aarch64-cpython-39/mediapipe/tasks/cc/components/processors/proto/detection_postprocessing_graph_options_pb2.py
mediapipe/tasks/cc/components/processors/proto/detection_postprocessing_graph_options.proto: This file contains proto3 optional fields, but --experimental_allow_proto3_optional was not set.

このような場合は、bazel同様~/appsprotocの新しいバイナリを入れておく。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
% curl -L -O https://github.com/protocolbuffers/protobuf/releases/download/v23.3/protoc-23.3-linux-aarch_64.zip
% unzip protoc-23.3-linux-aarch_64.zip -d ~/apps/bin
Archive:  protoc-23.3-linux-aarch_64.zip
  inflating: apps/bin/protoc
  inflating: apps/include/google/protobuf/any.proto
  inflating: apps/include/google/protobuf/api.proto
  inflating: apps/include/google/protobuf/compiler/plugin.proto
  inflating: apps/include/google/protobuf/descriptor.proto
  inflating: apps/include/google/protobuf/duration.proto
  inflating: apps/include/google/protobuf/empty.proto
  inflating: apps/include/google/protobuf/field_mask.proto
  inflating: apps/include/google/protobuf/source_context.proto
  inflating: apps/include/google/protobuf/struct.proto
  inflating: apps/include/google/protobuf/timestamp.proto
  inflating: apps/include/google/protobuf/type.proto
  inflating: apps/include/google/protobuf/wrappers.proto
  inflating: apps/readme.txt

古いバージョンは削除しておきましょう。

1
% sudo apt purge protobuf-compiler

clang-13を用いる

Raspberry Pi OS(bullseye)のgcc(10.2.1 20210110 (Debian 10.2.1-6))だと、ビルド中に下記のようにSegmentation faultによるinternal compiler errorが発生する。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
ERROR: /home/gloria/src/mediapipe-0.10.1/mediapipe/framework/stream_handler/BUILD:84:11: Compiling mediapipe/framework/stream_handler/fixed_size_input_stream_handler.cc failed: (Exit 1): gcc failed: error executing command (from target //mediapipe/framework/stream_handler:fixed_size_input_stream_handler) /usr/bin/gcc -U_FORTIFY_SOURCE -fstack-protector -Wall -Wunused-but-set-parameter -Wno-free-nonheap-object -fno-omit-frame-pointer -g0 -O2 '-D_FORTIFY_SOURCE=1' -DNDEBUG -ffunction-sections ... (remaining 56 arguments skipped)

Use --sandbox_debug to see verbose messages from the sandbox and retain the sandbox build root for debugging
In file included from <command-line>:
/usr/include/stdc-predef.h: In substitution of 'template<class _Functor, class, class> std::function<std::unique_ptr<mediapipe::InputStreamHandler>(std::shared_ptr<mediapipe::tool::TagMap>, mediapipe::CalculatorContextManager*, const mediapipe::MediaPipeOptions&, bool)>::function(_Functor) [with _Functor = <missing>; <template-parameter-1-2> = <missing>; <template-parameter-1-3> = <missing>]':
mediapipe/framework/stream_handler/fixed_size_input_stream_handler.cc:228:1:   required from here
/usr/include/stdc-predef.h:32:94: internal compiler error: Segmentation fault
   32 |    whether the overall intent is to support these features; otherwise,
      |                                                                                              ^
0x7f8c5fbe17 __libc_start_main
        ../csu/libc-start.c:308
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <file:///usr/share/doc/gcc-10/README.Bugs> for instructions.
Target //mediapipe/modules/face_detection:face_detection_short_range_cpu failed to build
Use --verbose_failures to see the command lines of failed build steps.
INFO: Elapsed time: 1608.472s, Critical Path: 1323.53s
INFO: 1122 processes: 321 internal, 801 linux-sandbox.
FAILED: Build did NOT complete successfully

clang-13であれば問題なくビルドできるようだった。

1
2
3
4
5
6
7
% sudo apt install clang-13
% CC=clang
% CXX=clang
% export CC
% export CXX
% python3 setup.py gen_protos
% time python3 setup.py bdist_wheel

ソースコードを展開しなおす

複数回ビルド作業を行ったソースコードから作成したwhlファイルをインストールすると、下記のようなエラーが出る。

1
2
3
4
5
6
7
8
Python 3.10.12 (main, Jul  3 2023, 14:40:47) [GCC 10.2.1 20210110] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import mediapipe as mp
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/python3.10/lib/python3.10/site-packages/mediapipe/__init__.py", line 30, in <module>
    import mediapipe.tasks.python as tasks
ImportError: cannot import name 'python' from 'mediapipe.tasks.python' (/usr/python3.10/lib/python3.10/site-packages/mediapipe/tasks/python/__init__.py)

これは、ソースのmediapipe/__init__.pyを動的に変更するビルドスクリプトにバグがあるらしく、 下記のように何度も再定義されるようになってしまっている。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Copyright 2019 - 2022 The MediaPipe Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

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__ = 'dev'

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__ = 'dev'
...

どうやらsetup.py_add_mp_init_files()があやしい。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def _add_mp_init_files():
  """Add __init__.py to mediapipe root directories to make the subdirectories indexable."""
  open(MP_ROOT_INIT_PY, 'w').close()
  # Save the original mediapipe/__init__.py file.
  shutil.copyfile(MP_DIR_INIT_PY, _get_backup_file(MP_DIR_INIT_PY))
  mp_dir_init_file = open(MP_DIR_INIT_PY, 'a')
  mp_dir_init_file.writelines([
      '\n', 'from mediapipe.python import *\n',
      'import mediapipe.python.solutions as solutions \n',
      'import mediapipe.tasks.python as tasks\n', '\n\n', 'del framework\n',
      'del gpu\n', 'del modules\n', 'del python\n', 'del mediapipe\n',
      'del util\n', '__version__ = \'{}\''.format(__version__), '\n'
  ])
  mp_dir_init_file.close()
  1. BuildPyのrun()_add_mp_init_files()が呼ばれ、mediapipe/__init__.pyのバックアップを用意した上で編集される
  2. BuildPyのrun()内の他のビルド作業を実行
  3. ビルドが終了したらRestoreのrun()で編集されたmediapipe/__init__.pyを消去した上で、バックアップを元に戻す

と処理しているようだが、当然2のビルド中に失敗したり強制中断したりすることもあるわけで、 それが残ったまま異常終了してしまっているのが原因の模様。

更新履歴

  • 2021-12-19: 初期バージョン。
  • 2023-04-24: 22.04で検証。
  • 2023-06-21: mediapipe-0.10.1で検証。
  • 2023-07-04: ビルド時・ビルド後の不具合について追記。
  • 2023-07-05: Raspberry Pi OS用バイナリを追加