はじめに
タイトルのとおり、ハマってしまったので記事に残すことにしました。
ハマったこと
Raspberry Pi Zero(armv6l)用のPython Wheelパッケージが提供されていないので、公式ドキュメントの通りにやってみたら、ビルドに失敗してしまう…
試してみたこと-1
こちらの記事を参考にして、Dockerコンテナ上で試してみても、ビルドに失敗してしまう(汗)
失敗したときの実行環境・実行したコマンドは、以下の通りです。
実行環境
- OS: Ubuntu 20.04.2 LTS (ConoHa VPS)
- CPU: 2Core
- Mem: 1GB
- SSD: 100GB
実行したコマンド
# Dockerのインストール(環境:ローカル)
# apt update && apt upgrade
# apt install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# apt update
# apt install docker-ce docker-ce-cli containerd.io
# cmakeのインストール(環境:ローカル)
# apt install cmake
# TensorFlowリポジトリのクローンを作成
# cd ~
# git clone https://github.com/tensorflow/tensorflow.git tensorflow_src
# Dockerコンテナの作成・起動
# docker pull tensorflow/tensorflow:devel
# docker run -it -v /var/run/docker.sock:/var/run/docker.sock \
-v $PWD/tensorflow_src:/root/tensorflow_src -w /root/tensorflow_src \
tensorflow/tensorflow:devel bash
# Dockerのインストール(環境:Dockerコンテナ)
# apt update && apt upgrade
# apt install \
apt-transport-https \
ca-certificates \
curl \
gnupg \
lsb-release
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# echo \
"deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# apt update
# apt install docker-ce docker-ce-cli containerd.io
# cmakeのインストール(環境:Dockerコンテナ)
# apt install cmake
# Wheelのビルド(環境:Dockerコンテナ)
# tensorflow/tools/ci_build/ci_build.sh PI-PYTHON37 \
tensorflow/lite/tools/pip_package/build_pip_package_with_cmake.sh rpi0
ちなみに、ビルドに失敗すると、このようなメッセージが表示されます。
/workspace/tensorflow/lite/tools/cmake/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/8.3.0/bits/deque.tcc:585:7: note: parameter passing for argument of type '__gnu_cxx::__normal_iterator<const double*, std::vector<double> >' changed in GCC 7.1
/workspace/tensorflow/lite/tools/cmake/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/8.3.0/bits/deque.tcc:585:7: note: parameter passing for argument of type '__gnu_cxx::__normal_iterator<const double*, std::vector<double> >' changed in GCC 7.1
/workspace/tensorflow/lite/tools/cmake/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/8.3.0/bits/deque.tcc:625:11: note: parameter passing for argument of type '__gnu_cxx::__normal_iterator<const double*, std::vector<double> >' changed in GCC 7.1
_M_insert_aux(__pos, __first, __last, __n);
^~~~~~~~~~~~~
In file included from /workspace/tensorflow/lite/tools/cmake/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/8.3.0/deque:64,
from /workspace/tensorflow/lite/kernels/internal/spectrogram.h:35,
from /workspace/tensorflow/lite/kernels/internal/spectrogram.cc:16:
/workspace/tensorflow/lite/tools/cmake/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/8.3.0/bits/stl_deque.h: In member function 'bool tflite::internal::Spectrogram::GetNextWindowOfSamples(const std::vector<InputSample>&, int*) [with InputSample = double]':
/workspace/tensorflow/lite/tools/cmake/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/8.3.0/bits/stl_deque.h:2021:4: note: parameter passing for argument of type '__gnu_cxx::__normal_iterator<const double*, std::vector<double> >' changed in GCC 7.1
_M_range_insert_aux(__pos, __first, __last,
^~~~~~~~~~~~~~~~~~~
/workspace/tensorflow/lite/tools/cmake/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/arm-linux-gnueabihf/include/c++/8.3.0/bits/stl_deque.h:2021:4: note: parameter passing for argument of type '__gnu_cxx::__normal_iterator<const double*, std::vector<double> >' changed in GCC 7.1
_M_range_insert_aux(__pos, __first, __last,
^~~~~~~~~~~~~~~~~~~
make[3]: Leaving directory '/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.7/cmake_build'
make[2]: *** [CMakeFiles/tensorflow-lite.dir/all] Error 2
CMakeFiles/Makefile2:1145: recipe for target 'CMakeFiles/tensorflow-lite.dir/all' failed
make[2]: Leaving directory '/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.7/cmake_build'
CMakeFiles/Makefile2:1253: recipe for target 'CMakeFiles/_pywrap_tensorflow_interpreter_wrapper.dir/rule' failed
make[1]: *** [CMakeFiles/_pywrap_tensorflow_interpreter_wrapper.dir/rule] Error 2
make[1]: Leaving directory '/workspace/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.7/cmake_build'
make: *** [_pywrap_tensorflow_interpreter_wrapper] Error 2
Makefile:215: recipe for target '_pywrap_tensorflow_interpreter_wrapper' failed
root@06a2eea49469:~/tensorflow_src#
試してみたこと-2
結論から言うと、こちらの方法でWheelのビルドに成功しました。
コンテナではなくRaspberry Pi Zero上で普通にビルドした方が良いのでは?、と思いbuild_pip_package_with_cmake.sh
の中身を解読して、一行ずつ端末から実行してみました。
成功したときの実行環境・実行したコマンドは、以下の通りです。
実行環境
- Raspberry Pi Zero WH
- OS: Raspberry Pi OS Lite (Release data: May 7th 2021)
- SDカード: 64GB
実行したコマンド
$ sudo apt update && sudo apt upgrade -y
$ sudo apt install cmake
$ cd ~
$ git clone https://github.com/tensorflow/tensorflow.git tensorflow_src
$ mkdir tflite_build
$ cd tflite_build
$ sudo cmake ../tensorflow_src/tensorflow/lite \
-DCMAKE_C_FLAGS="-I/usr/include/python3.7m -I/home/pi/.local/lib/python3.7/site-packages/pybind11/include" \
-DCMAKE_CXX_FLAGS="-I/usr/include/python3.7m -I/home/pi/.local/lib/python3.7/site-packages/pybind11/include" \
-DCMAKE_SHARED_LINKER_FLAGS='-latomic'
-DCMAKE_SYSTEM_NAME=Linux \
-DCMAKE_SYSTEM_PROCESSOR=armv6 \
-DTFLITE_ENABLE_XNNPACK=OFF
$ sudo cmake --build . --verbose -j 1 -t _pywrap_tensorflow_interpreter_wrapper
$ cd ~/tensorflow_src/tensorflow/lite/tools/pip_package/
$ sudo mkdir gen
$ sudo mkdir gen/tflite_pip
$ sudo mkdir gen/tflite_pip/python3.7
$ sudo mkdir gen/tflite_pip/python3.7/tflite_runtime
$ cd gen/tflite_pip/python3.7
$ sudo cp -r ~/tensorflow_src/tensorflow/lite/tools/pip_package/debian/ ./
$ sudo cp -r ~/tensorflow_src/tensorflow/lite/tools/pip_package/MANIFEST.in ./
$ sudo cp -r ~/tensorflow_src/tensorflow/lite/python/interpreter_wrapper/ ./
$ sudo cp ~/tensorflow_src/tensorflow/lite/tools/pip_package/setup_with_binary.py ./setup.py
$ sudo cp ~/tensorflow_src/tensorflow/lite/python/interpreter.py ./tflite_runtime/
$ sudo cp ~/tensorflow_src/tensorflow/lite/python/metrics_interface.py ./tflite_runtime/
$ sudo cp ~/tensorflow_src/tensorflow/lite/python/metrics_portable.py ./tflite_runtime/
$ sudo cp ~/tflite_build/_pywrap_tensorflow_interpreter_wrapper.so ./tflite_runtime/
$ sudo chmod u+w ./tflite_runtime/_pywrap_tensorflow_interpreter_wrapper.so
$ sudo touch ./tflite_runtime/__init__.py
$ sudo echo "__version__ = '2.7.0'" >> ./tflite_runtime/__init__.py
$ sudo echo "__git_version__ = '$(git -C ~/tensorflow_src describe)'" >> ./tflite_runtime/__init__.py
$ sudo python3 setup.py bdist --plat-name=linux_armv6l bdist_wheel --plat-name=linux-armv6l
ビルドに成功すると、tensorflow_src/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.7/dist
に
Wheelが出力されます。ちなみに、ビルド完了するまで、4時間くらいかかりました。
pi@raspberrypi:~/tensorflow_src/tensorflow/lite/tools/pip_package/gen/tflite_pip/python3.7/dist $ ls
tflite_runtime-2.7.0-cp37-cp37m-linux_armv6l.whl
tflite-runtime-2.7.0.linux_armv6l.tar.gz
動作確認
動作確認のため、学習済みモデル(test.tflite
)を読み込み、get_input_details()
とget_output_details()
を実行してみました。結果、エラーは発生せず、入力層と出力層の情報を表示することができました。
pi@raspberrypi:~ $ python3
Python 3.7.3 (default, Jan 22 2021, 20:04:44)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import tflite_runtime.interpreter as tflite
>>> interpreter = tflite.Interpreter(model_path='./test.tflite')
>>> interpreter.get_input_details()
[{'name': 'serving_default_flatten_input:0', 'index': 0, 'shape': array([ 1, 28, 28]), 'shape_signature': array([-1, 28, 28]), 'dtype': <class 'numpy.float32'>, 'quantization': (0.0, 0), 'quantization_parameters': {'scales': array([], dtype=float32), 'zero_points': array([], dtype=int32), 'quantized_dimension': 0}, 'sparsity_parameters': {}}]
>>> interpreter.get_output_details()
[{'name': 'StatefulPartitionedCall:0', 'index': 9, 'shape': array([ 1, 10]), 'shape_signature': array([-1, 10]), 'dtype': <class 'numpy.float32'>, 'quantization': (0.0, 0), 'quantization_parameters': {'scales': array([], dtype=float32), 'zero_points': array([], dtype=int32), 'quantized_dimension': 0}, 'sparsity_parameters': {}}]
>>>
おわりに
あまり需要のない内容かと思いますが、誰かの参考になれば幸いです。